Open dlight opened 1 year ago
I've been asking myself the same question all last week. And the short answer is: NO
, it isn't possible for pecs
to implement Future
.
There is a little bit longer answer:
pecs
is all about (bevy) ecs
at first point: it is important to be able to fetch Bevy's system params at any promise call (send events/query entites/modify resources, etc). This doesn't fit Future
at all.
But.
But. What can be done is to expand the functionality of asyn!
macro so it will parse the function body and expand it into multiple .then
calls. It is not the same as implementing the Future
, but it could look pretty close to classic async functions while keep the same perfect interop with Bevy's ecs (this approach is my personal goal for this project).
I'll try to demonstrate what I mean by code. Let's try to write asyn function that makes http request and logs the error or response status code and time spent using that super-cool-extended async!
macro:
commands.add(asyn!(time: Res<Time> => {
let started = time.elapsed_time();
// when macro find this await it will split the body into promise chain
let resp = await asyn::http::get("https://bevyengine.org");
let delta = time.elapsed_time() - started;
match resp {
Ok(r) => info!("Bevy respond with {} in {delta:0.2}s", r.status),
Err(e) => info!("`Got error in {delta:02}s: {e}");
}
}))
This asyn!
function looks like common async function, but it can access all Bevy's ecs features. In fact, the content of macro has any required data to expand itself into (already implemented) chain of promises:
commands.add(
Promise::start(asyn!(_, time: Res<Time> => {
asyn::http::get("https://bevyengine.org")
.with(ime.elapsed_time())
}))
.then(asyn!(state, resp, time: Res<Time> => {
let started = state.value;
let delta = time.elapsed_time() - started;
match resp {
Ok(r) => info!("Bevy respond with {} in {delta:0.2}s", r.status),
Err(e) => info!("`Got error in {delta:02}s: {e}");
}
Promise::resolve(())
}))
)
I rethought my answer. There are two parts, actually:
promise.await
)It is possible to implement both of them. But turning promises into future requires to register it within the world first, so there is only possible api I see:
// it is possible to turn any Promise or AsynFunct into future
let future = commands.promise(asyn!(...)).future()
The second part looks much more usable:
async fn my_asyn_func() -> String {
"".to_string()
}
fn setup(mut commands: Commands) {
commands.add(
Promise::start(asyn!(_ => {
// promise may return Future
my_asyn_func()
})
.then(asyn!(_, result => {
info!("Custom future result: {result}");
Promise::pass()
})
)
}
Hi, I just saw this project and I have a question, could pecs's promises implement Future so that it can be used with async/await? Not a feature request, just curious.