How can I signal by reference?
NeverGivinUp opened this issue · comments
The signal
and the signal_cloned
functions are defined only for types that implement Copy
or Clone
respectively. For types that do not implement these I guess this leaves signaling by reference. That must be the use of the signal_ref
function.
I have a data structure struct NonCopyableTestStruct(u32);
that does not implement Copy
or Clone
. Say it is held by in the test_value
field of my state: state.test_value == Mutable::new(NonCopyableTestStruct(0))
.
I tried to create a mapped signal let text_signal = state.test_value.signal_ref(|x|x).map(|test_value| format!("{}", test_value.0));
. But I get the below error, which confuses me.
How do I use the function correctly? Can I use it at all without cloning? (That would be bad, because the real struct that I'm simulating here with NonCopyableTestStruct might be huge, I do need all of its data, and cloning would be slow.)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src\lib.rs:119:62
|
119 | let text_signal = state.test_value.signal_ref(|x|x).map(|test_value| format!("{}", test_value.0));
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 119:59...
--> src\lib.rs:119:59
|
119 | let text_signal = state.test_value.signal_ref(|x|x).map(|test_value| format!("{}", test_value.0));
| ^^^^
note: ...so that the expression is assignable
--> src\lib.rs:119:62
|
119 | let text_signal = state.test_value.signal_ref(|x|x).map(|test_value| format!("{}", test_value.0));
| ^
= note: expected `&NonCopyableTestStruct`
found `&NonCopyableTestStruct`
note: but, the lifetime must be valid for the expression at 3:5...
--> src\lib.rs:119:82
|
119 | let text_signal = state.test_value.signal_ref(|x|x).map(|test_value| format!("{}", test_value.0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that the type `&NonCopyableTestStruct` will meet its required lifetime bounds
--> src\lib.rs:119:70
|
119 | let text_signal = state.test_value.signal_ref(|x|x).map(|test_value| format!("{}", test_value.0));
| ^^^^^^^^^^
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
You use it like this:
let text_signal = state.test_value.signal_ref(|test_value| format!("{}", test_value.0));
The test_value
is a reference to the object, but you can't return a reference, so in this case it's using format!
to return a String
(which is not a reference, so it's fine).
Thanks for the quick reply @Pauan :)
A followup question, if I may:
I want to use a Mutable
to loop an iterative numerical method. If I have value that implements Copy
-- say state.test_value is Mutable<u32>
-- I can do
state.test_value.signal().to_stream().take(888).for_each(|test_value| {
state.test_value.lock_mut().0 = test_value.0 + 1;
ready(())
}).await;
I am converting the Signal
to a Stream
here, to be able to limit the computation with take
or take_while
.
How can I do that by reference?
Also, is using a Mutable
as a loop state a correct use of mutables and signals?
@NeverGivinUp That definitely doesn't seem like a good use of Mutable
. If you just want to limit the value, I recommend just putting that into a method or function:
fn increment(&self) {
let mut test_value = self.test_value.lock_mut();
if *test_value < 888 {
*test_value += 1;
}
}
It's not good to treat Signals as Streams, because they aren't Streams. They're variables. Treat them like an ordinary variable. If you want Streams, then use Streams, not Mutable.
@Pauan I went through so much pain creating my own version of a loop over a stream and the result worked but was so convoluted. Your work makes solving my problems practically effortless.
I don't know how to express my gratitude. Thank you so much for creating futures-signal and rust-dominator!