-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fully working examples of how Mutable can be used to notify observers when changed. #57
Comments
There are many different ways of running Futures. You chose to use use futures::executor::LocalPool;
use futures::task::LocalSpawnExt;
let spawner = LocalPool::new().spawner();
spawner.spawn_local(async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
}); use futures::executor::ThreadPool;
let pool = ThreadPool::new().unwrap();
pool.spawn_ok(async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
}); use futures::executor::block_on;
block_on(async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
}); smoll::block_on(async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
}); wasm_bindgen_futures::spawn_local(async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
}); use async_std::task;
task::spawn(async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
}); smol::spawn(async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
}); tokio::spawn(async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
}); #[wasm_bindgen(start)]
pub async main_js() -> Result<(), JsValue> {
some_signal.for_each(|value| {
// ...
async {}
}).await;
Ok(())
} #[async_std::main]
async fn main() {
some_signal.for_each(|value| {
// ...
async {}
}).await;
} #[tokio::main]
async fn main() {
some_signal.for_each(|value| {
// ...
async {}
}).await;
} futures-signals doesn't handle Future spawning at all, instead that's handled by other crates (futures, tokio, async-std, smol, wasm-bindgen-futures, etc.) Because there are so many different ways to spawn, it's difficult to cover all of them.
|
I see. It's impressive how flexible this crate is. I still think it may be useful to have a few examples with common runtimes to demonstrate to new comers like me how to run the futures. I understand that "how to run a future" is a topic outside of the scope of this project. The Rust Book or the tutorials for the crates you demonstrated above would be a better place to find that. But the slight nuances of using this library within an executor could be demonstrated somewhere. For example, I didn't know that all references to the mutable had to be dropped before the future it created is marked as complete. But maybe not. Before trying out this crate I have never used rust futures (but I have in C++ and Python). If you disagree with the need for examples, please close this issue :) |
I agree that examples are good, I'm just saying that it's hard to do, because of how complex the Rust Futures ecosystem is.
That's quite normal for any sort of push-based stream. For example, mpsc Streams also behave like that. As long as you have a reference to the But when all references to the What if you don't want to wait for the let (future, handle) = abortable(some_signal.for_each(|value| {
// ...
async {}
}));
spawn_future_somehow(future); Now you can call You can also use something like spawn_future_somehow(async move {
let result = select(
async move {
some_signal.for_each(|value| {
// ...
async {}
}).await;
},
async move {
sleep(1000.0).await;
},
).await;
}); This will run the This is essentially a timeout: it will listen for values on And just like Also, Signals support a spawn_future_somehow(async move {
some_signal.wait_for(5).await;
// Now we know that some_signal is 5
}); In the above code, the Of course you can combine these in various ways... for example you can do something like this: let running = Mutable::new(true);
let my_state = Mutable::new(...);
spawn_future_somehow({
let running = running.clone();
let my_state = my_state.clone();
async move {
let _ = select(
async move {
my_state.signal_cloned().for_each(...).await;
},
async move {
running.signal().wait_for(false).await;
},
).await;
}
}); This will listen to changes to This happens because After you set |
How can I group the signals so I can update mutable values with the methods of a struct?, the examples have helped me a lot, thanks! async fn render(state: Self) {.
// do I have to clone the entire struct?, How to do it? , isn't it inefficient?
// let state_clone_1 = state.clone(); //error!
let state_clone_2 = state.is_running.clone();
let state_clone_3 = state.game.score.clone();
let obs_if_is_running = state_clone_2.signal().for_each(move |value| {
println!("Observer A {}", value);
state.start(true);
async {}
});
let obs_game_score = state_clone_3.signal().for_each(move |value| { //<- error, used of moved value 'state'
println!("Observer B {}", value);
state.set_game_score(222);
async {}
});
tokio::spawn(async move {
obs_if_is_running.await;
});
tokio::spawn(async move {
obs_game_score.await;
});
} |
@nothingIsSomething Generally you will have a struct which contains all of your struct Foo {
is_running: Mutable<bool>,
score: Mutable<usize>,
}
impl Foo {
fn new() -> Arc<Self> {
Arc::new(Self {
is_running: Mutable::new(true),
score: Mutable::new(0),
})
}
fn start(&self, value: bool) {
// ...
}
fn set_game_score(&self, value: usize) {
// ...
}
fn render(state: Arc<Self>) {
let state = state.clone();
// ...
}
} Cloning an |
The tutorial explains the concept of
Mutable
, but not how to actually run the code so the callbacks get called. After some trial and error, and a bit of stack overflow, I have come up with the following. Feel free to put this in anexamples
ortest
folder if this is how it is actually intended to be used.The text was updated successfully, but these errors were encountered: