Skip to content

Instantly share code, notes, and snippets.

@joom
Last active August 18, 2023 02:40
Show Gist options
  • Save joom/c3f99b4b0f8c4b624bf2093d7bad8573 to your computer and use it in GitHub Desktop.
Save joom/c3f99b4b0f8c4b624bf2093d7bad8573 to your computer and use it in GitHub Desktop.
A Yew app to show a binary tree
use yew::{html, Component, Context, Html};
use gloo::console::{self};
use std::collections::VecDeque;
#[derive(Debug, Clone)]
pub struct Annot {
}
impl Default for Annot {
fn default() -> Annot { Annot { } }
}
#[derive(Debug, Clone)]
pub enum Tree {
Leaf,
Node { x: usize, l: Box<ATree>, r: Box<ATree> },
}
#[derive(Debug, Clone)]
pub struct ATree {
ann: Annot,
tree: Tree
}
#[derive(Debug, Clone)]
pub enum Direction { Left, Right }
type Path = VecDeque<Direction>;
impl ATree {
pub fn follow_path(&mut self, dir: &mut Path) -> Option<&mut Self> {
match VecDeque::pop_front(dir) {
None => { Some(self) }
Some(d) => {
match self {
ATree {ref mut ann, tree: Tree::Node {ref mut x, ref mut l, ref mut r}} => {
match d {
Direction::Left => {return l.follow_path(dir)}
Direction::Right => {return r.follow_path(dir)}
}
}
ATree {ann: _, tree: Tree::Leaf} => { None }
}
}
}
}
pub fn new() -> Self {
ATree { ann: Default::default(), tree: Tree::Leaf }
}
pub fn insert(&mut self, v : usize) -> () {
match self {
ATree {ann, tree: Tree::Leaf} => {
self.tree = Tree::Node {
x: v,
l: Box::new(ATree::new()),
r: Box::new(ATree::new()),
};
}
ATree {ann, tree: Tree::Node {x, l, r}} => {
if v < *x { l.insert(v); } else if *x < v { r.insert(v); }
}
}
}
pub fn view(&self,
ctx: &Context<App>,
dir: Path) -> Html {
match self {
ATree {ann, tree: Tree::Leaf} => {
let cls = if ann.is_selected { "selected" } else { "" };
html! {
<li>
<a class={cls}
onclick={ctx.link().callback(move |_| Msg::SelectTree(dir.clone()))}>
</a>
</li>
}
}
ATree {ann, tree: Tree::Node {x, l, r}} => {
let cls = if ann.is_selected { "selected" } else { "" };
let dirc = dir.clone();
let mut dirl = dir.clone();
dirl.push_back(Direction::Left);
let mut dirr = dir.clone();
dirr.push_back(Direction::Right);
html! {
<li>
<a class={cls}
onclick={ctx.link().callback(move |_| Msg::SelectTree(dirc.clone()))}>
{ x }
</a>
<ul>
{ l.view(ctx, dirl) }
{ r.view(ctx, dirr) }
</ul>
</li>
}
}
}
}
}
pub enum Msg {
SelectTree(Path)
}
pub struct App {
atree: ATree,
selected: Option<Path>
}
impl Component for App {
type Message = Msg;
type Properties = ();
fn create(ctx: &Context<Self>) -> Self {
let mut t = ATree::new();
for i in [5,3,7,4,2,6,8] { t.insert(i); }
Self { atree: t , selected: None }
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::SelectTree(dir) => {
console::info!("Selected!");
let mut dirc = dir.clone();
self.selected = Some(dir);
match self.atree.follow_path(&mut dirc) {
Some (ATree {ref mut ann, tree: _}) => {
console::info!("Found subtree!");
}
None => {
console::info!("Couldn't find subtree!");
}
}
true
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div class="container">
<div class="menu">
<button>
{ "Insert" }
</button>
</div>
<div class="tree">
<ul> { self.atree.view(ctx, VecDeque::new()) } </ul>
</div>
</div>
}
}
}
fn main() {
yew::start_app::<App>();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment