use std::{
cell::{Ref, RefCell, RefMut},
rc::Rc,
};
use crate::{Uniplate, zipper::Zipper};
struct TagNode<D> {
data: D,
parent: Option<Rc<RefCell<TagNode<D>>>>,
children: Vec<Rc<RefCell<TagNode<D>>>>,
}
#[derive(Clone)]
pub struct TaggedZipper<T, D, F>
where
T: Uniplate,
D: Clone,
F: FnMut(&T) -> D,
{
zipper: Zipper<T>,
tag_node: Rc<RefCell<TagNode<D>>>,
construct_tag: F,
}
impl<T, D, F> TaggedZipper<T, D, F>
where
T: Uniplate,
D: Clone,
F: FnMut(&T) -> D,
{
pub fn new(root: T, mut constructor: F) -> Self {
let tag_node = TagNode {
data: constructor(&root),
parent: None,
children: Vec::new(),
};
TaggedZipper {
tag_node: Rc::new(RefCell::new(tag_node)),
construct_tag: constructor,
zipper: Zipper::new(root),
}
}
pub fn zipper(&self) -> &Zipper<T> {
&self.zipper
}
pub fn focus(&self) -> &T {
self.zipper.focus()
}
pub fn replace_focus(&mut self, new_focus: T) -> T {
let old_focus = self.zipper.replace_focus(new_focus);
self.invalidate_subtree();
old_focus
}
pub fn rebuild_root(self) -> T {
self.zipper.rebuild_root()
}
pub fn tag(&self) -> Ref<'_, D> {
Ref::map(self.tag_node.borrow(), |node| &node.data)
}
pub fn tag_mut(&mut self) -> RefMut<'_, D> {
RefMut::map(self.tag_node.borrow_mut(), |node| &mut node.data)
}
pub fn replace_tag(&mut self, new_tag: D) -> D {
std::mem::replace(&mut self.tag_node.borrow_mut().data, new_tag)
}
pub fn reset_tag(&mut self) -> D {
let new_tag = (self.construct_tag)(self.zipper.focus());
self.replace_tag(new_tag)
}
pub fn invalidate_subtree(&mut self) {
let parent_node = self.tag_node.borrow().parent.clone();
let new_tag = Rc::new(RefCell::new(TagNode {
data: (self.construct_tag)(self.zipper.focus()),
parent: parent_node,
children: Vec::new(),
}));
let _ = std::mem::replace(&mut self.tag_node, new_tag);
}
pub fn go_up(&mut self) -> Option<()> {
self.zipper.go_up()?;
let parent_tag = self.tag_node.borrow().parent.clone().unwrap();
self.tag_node = parent_tag;
Some(())
}
pub fn go_down(&mut self) -> Option<()> {
self.zipper.go_down()?;
let child_tag = self.tag_node.borrow().children.first().cloned();
self.tag_node = match child_tag {
Some(tag) => tag.clone(),
None => {
let new_tag = Rc::new(RefCell::new(TagNode {
data: (self.construct_tag)(self.zipper.focus()),
parent: Some(self.tag_node.clone()),
children: Vec::new(),
}));
self.tag_node.borrow_mut().children.push(new_tag.clone());
new_tag
}
};
Some(())
}
pub fn go_left(&mut self) -> Option<()> {
self.zipper.go_left()?;
let parent_node = self.tag_node.borrow().parent.clone().unwrap();
let siblings_i = self.zipper.siblings_index().unwrap();
self.tag_node = parent_node.borrow().children[siblings_i].clone();
Some(())
}
pub fn go_right(&mut self) -> Option<()> {
self.zipper.go_right()?;
let parent_tag_node = self.tag_node.borrow().parent.clone().unwrap();
let sibling_idx = self.zipper.siblings_index().unwrap();
let sibling_tag_node = parent_tag_node.borrow().children.get(sibling_idx).cloned();
self.tag_node = match sibling_tag_node {
Some(tag) => tag.clone(),
None => {
let new_tag = Rc::new(RefCell::new(TagNode {
data: (self.construct_tag)(self.zipper.focus()),
parent: Some(parent_tag_node.clone()),
children: Vec::new(),
}));
parent_tag_node.borrow_mut().children.push(new_tag.clone());
new_tag
}
};
Some(())
}
}