I want impl a event-loop app base on FuturesUnordered
use futures::{self, stream::FuturesUnordered, StreamExt};
type Async = Pin<Box< /** ? */>>;
struct RuntimeState {
pub pending_ops: FuturesUnordered<Async>
}
fn main () {
let state = RuntimeState {
pending_ops: FuturesUnordered::new()
}
loop { // here start loop op in pending_ops
poll_fn((cx)=>{
let task = state.pending_ops.take(1)
task(state).poll_next_unpin(cx);
})
}
}
fn some_async_fn(state){
// I want push an item into pending_ops like this
state.pending_ops.push(Box::pin(async move |state: &mut RuntimeState| -> anyhow::Result<()> {
// some async ops
}))
}
The structure of the rest of the program suggests that the type Async you want is:
type Async = Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'static>>;
This is such a common type to want that futures has a type alias for it which lets you avoid writing those four nested <>:
use futures::future::BoxFuture;
type Async = BoxFuture<'static, anyhow::Result<()>>;
These are not quite the same, because BoxFuture also requires the future implement Send, for use in multithreaded executors. If that's undesired, use futures::future::LocalBoxFuture instead.
but you cannot actually use that. If the RuntimeState owns the tasks, then the tasks cannot have an &mut RuntimeState — that would be a self-referential borrow, and also even if that were possible, only one task could exist at a time since the &mut RuntimeState is unique.
You need to avoid both &mut and use interior mutability, and probably Arc too — like how tokio has the Handle type which is cloneable and lets you spawn tasks in a Runtime. That way, each task can have its own handle to whatever state you want them to share.
If I understand correctly, you're hoping that while the task is not using the RuntimeState then you can have the task be not currently borrowing it. That is not possible, because the task might yield while in the middle of using the &mut RuntimeState. The closest you can get is to use interior mutability: let the task have access to something that contains a Mutex<RuntimeState> or similar, so that the task can temporarily get the &mut. But it will be better if you never give the task a &mut RuntimeState at all because that is very powerful, allowing totally replacing the state; instead, offer it a handle with only the operations that make sense for individual tasks to do. Then with that narrower interface, you might find some even better strategy for state management than a Mutex.
sorry, this is very simplified code, It may not be accurately stated.
in fact,I‘m trying to build a JsRuntime base rusty_v8. now, it's still a demo
Before I successful impl the event loop by borrow javascript code to record a callback, and pass the index to rust code. I‘m not sure this is a correct behavior or not.
Now, I want impl the event loop by pure ruct code base the future, then I trigger the issue , I don't no how to fix it. can you help me to resolve it