Pauan / rust-signals

Zero-cost functional reactive Signals for Rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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)
commented

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?

commented

@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!