Skip to content
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

can we nest states using only references? #26

Open
wtholliday opened this issue Jul 6, 2022 · 1 comment
Open

can we nest states using only references? #26

wtholliday opened this issue Jul 6, 2022 · 1 comment

Comments

@wtholliday
Copy link
Contributor

I was looking into using references instead of passing around a context, and it seems tricky. Just wanted to record somewhere how far I got.

This is close, but doesn't quite work:

    struct State<F, V> {
        f: F,
        state: String,
        phantom: std::marker::PhantomData<V>,
    }

    impl<'a, V: View + 'a, F: Fn(&'a String) -> V + 'a> View for State<F, V> {
        fn draw(&self) {
            (self.f)(&self.state).draw();
        }
    }

The problem is in F: Fn(&'a String) -> V + 'a. This says the entire closure cannot outlive the String passed in. That's not quite what we want. It's ok if the closure lives longer. What we want is for the return type (V) to live as long as the String passed in.

What we want is something like F: for<'a> Fn(&'a String) -> V<'a> where V is a higher-kinded-type, but rust doesn't (yet) have this feature.

@wtholliday
Copy link
Contributor Author

wtholliday commented Jul 7, 2022

This works, at the cost of boxing views, and process has to return a new value because it can't get a mutable reference:

    trait View {
        fn draw(&self);
        fn process(&self, data: &String) -> Option<String>;
    }

    struct State<F> {
        f: F,
    }

    impl<F> View for State<F>
    where
        F: for<'a> Fn(&'a String) -> Box<dyn View + 'a>,
    {
        fn draw(&self) {
            // Get the state from somewhere.
            let s = "hello world".to_string();
            (self.f)(&s).draw();
        }

        fn process(&self, _data: &String) -> Option<String> {
            let mut s = "hello world".to_string();
            let r = {
                let v = (self.f)(&s);
                v.process(&s)
            };

            if let Some(n) = r {
                s = n;
            }
            None
        }
    }

    struct Empty {}

    impl View for Empty {
        fn draw(&self) {}
        fn process(&self, _data: &String) -> Option<String> {
            None
        }
    }

    fn state<'b, F: 'b + for<'a> Fn(&'a String) -> Box<dyn View + 'a>>(f: F) -> Box<dyn View + 'b> {
        Box::new(State { f })
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant