I have a simple Yew app in which I draw a binary tree and render it in HTML. I want to make it so that I save in the model (the App
type) which Node
or Leaf
is currently selected. (I will then color that one differently)
I added an Annot
struct, and added that as a field in both Node
and Leaf
. Now, I have a SelectTree
variant in the Msg
type. I want to add an argument to this, something like SelectTree(&Tree)
but this gives me an "expected named lifetime parameter" error.
I checked the examples but they all had data representable in arrays/vectors so passing an index was enough, so I didn't learn much from them. What can I do to pass a reference in the message? Is this even possible? If it is not possible, can I do this using unsafe
, and how?
Here is the code I have right now:
use yew::{html, Component, Context, Html};
use gloo::console::{self};
#[derive(Debug, Clone)]
pub struct Annot {
is_selected: bool
}
impl Default for Annot {
fn default() -> Annot { Annot { is_selected: false } }
}
#[derive(Debug, Clone)]
pub enum Tree {
Leaf { ann: Annot },
Node { ann: Annot, x: usize, l: Box<Tree>, r: Box<Tree> },
}
impl Tree {
pub fn new() -> Tree {
Tree::Leaf { ann: Default::default() }
}
pub fn insert(&mut self, v : usize) -> () {
match self {
Tree::Leaf {ann} => {
*self = Tree::Node {
ann: Default::default(),
x: v,
l: Box::new(Tree::Leaf { ann: Default::default() }),
r: Box::new(Tree::Leaf { ann: Default::default() })
};
}
Tree::Node {ann, x, l, r} => {
if v < *x { l.insert(v); } else if *x < v { r.insert(v); }
}
}
}
pub fn view(&self, ctx: &Context<App>) -> Html {
match self {
Tree::Leaf {ann} => {
let cls = if ann.is_selected { "selected" } else { "" };
html! {
<li>
<a class={cls}
onclick={ctx.link().callback(|_| Msg::SelectTree)}>
</a>
</li>
}
}
Tree::Node {ann, x, l, r} => {
let cls = if ann.is_selected { "selected" } else { "" };
html! {
<li>
<a class={cls}
onclick={ctx.link().callback(|_| Msg::SelectTree)}>
{ x }
</a>
<ul>
{ l.view(ctx) }
{ r.view(ctx) }
</ul>
</li>
}
}
}
}
}
pub enum Msg {
SelectTree
}
pub struct App {
tree: Tree
}
impl Component for App {
type Message = Msg;
type Properties = ();
fn create(ctx: &Context<Self>) -> Self {
let mut t = Tree::new();
for i in [5,3,7,4,2,6,8] { t.insert(i); }
Self { tree: t }
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::SelectTree => {
console::info!("Selected!");
true
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div class="tree">
<ul> { self.tree.view(ctx) } </ul>
</div>
}
}
}
fn main() {
yew::start_app::<App>();
}
PS: I come from a JavaScript and functional programming background, and I'm relatively a beginner at Rust. I've been trying to solve this for a few days already so I think I need things to be explained more explicitly.