use std::{collections::VecDeque, sync::Arc};
use crate::{Biplate, Tree, Uniplate};
#[derive(Clone)]
pub struct Zipper<T: Uniplate> {
focus: T,
path: Vec<PathSegment<T>>,
}
#[derive(Clone)]
struct PathSegment<T: Uniplate> {
left: VecDeque<T>,
right: VecDeque<T>,
rebuild_tree: Arc<dyn Fn(VecDeque<T>) -> Tree<T>>,
ctx: Arc<dyn Fn(Tree<T>) -> T>,
}
impl<T: Uniplate> Zipper<T> {
pub fn new(root: T) -> Self {
Zipper {
focus: root,
path: Vec::new(),
}
}
pub fn focus(&self) -> &T {
&self.focus
}
pub fn focus_mut(&mut self) -> &mut T {
&mut self.focus
}
pub fn replace_focus(&mut self, new_focus: T) -> T {
std::mem::replace(&mut self.focus, new_focus)
}
pub fn rebuild_root(mut self) -> T {
while self.go_up().is_some() {}
self.focus
}
pub fn depth(&self) -> usize {
self.path.len()
}
pub(crate) fn siblings_index(&self) -> Option<usize> {
let path_segment = self.path.last()?;
Some(path_segment.left.len())
}
pub fn go_up(&mut self) -> Option<()> {
let mut path_seg = self.path.pop()?;
path_seg.left.push_back(self.focus.clone());
path_seg.left.append(&mut path_seg.right);
let tree = (path_seg.rebuild_tree)(path_seg.left);
self.focus = (path_seg.ctx)(tree);
Some(())
}
pub fn has_up(&self) -> bool {
!self.path.is_empty()
}
pub fn go_down(&mut self) -> Option<()> {
let (children, ctx) = self.focus.uniplate();
let (mut siblings, rebuild_tree) = children.list();
let new_focus = siblings.pop_front()?;
let new_segment = PathSegment {
left: VecDeque::new(),
right: siblings,
rebuild_tree: rebuild_tree.into(),
ctx: ctx.into(),
};
self.path.push(new_segment);
self.focus = new_focus;
Some(())
}
pub fn has_down(&self) -> bool {
let (children, _) = self.focus.uniplate();
!children.is_empty()
}
pub fn go_left(&mut self) -> Option<()> {
let path_segment = self.path.last_mut()?;
let new_focus = path_segment.left.pop_front()?;
let old_focus = std::mem::replace(&mut self.focus, new_focus);
path_segment.right.push_back(old_focus);
Some(())
}
pub fn has_left(&self) -> bool {
let Some(path_segment) = self.path.last() else {
return false;
};
!path_segment.left.is_empty()
}
pub fn go_right(&mut self) -> Option<()> {
let path_segment = self.path.last_mut()?;
let new_focus = path_segment.right.pop_front()?;
let old_focus = std::mem::replace(&mut self.focus, new_focus);
path_segment.left.push_back(old_focus);
Some(())
}
pub fn has_right(&self) -> bool {
let Some(path_segment) = self.path.last() else {
return false;
};
!path_segment.right.is_empty()
}
pub fn iter_left_siblings(&self) -> impl Iterator<Item = &T> {
self.path
.last()
.map(|seg| seg.left.iter())
.into_iter()
.flatten()
}
pub fn iter_right_siblings(&self) -> impl Iterator<Item = &T> {
self.path
.last()
.map(|seg| seg.right.iter())
.into_iter()
.flatten()
}
pub fn iter_siblings(&self) -> impl Iterator<Item = &T> {
self.iter_left_siblings()
.chain(std::iter::once(self.focus()))
.chain(self.iter_right_siblings())
}
pub fn iter_ancestors<'a>(&'a self) -> impl Iterator<Item = T> + 'a {
AncestorsIter {
zipper: self.clone(),
}
}
}
struct AncestorsIter<T: Uniplate> {
zipper: Zipper<T>,
}
impl<T: Uniplate> Iterator for AncestorsIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.zipper.go_up().map(|_| self.zipper.focus.clone())
}
}
#[derive(Clone)]
pub struct ZipperBi<To: Uniplate, From: Biplate<To>> {
focus: To,
path: Vec<PathSegmentBi<To, From>>,
}
#[derive(Clone)]
enum PathSegmentBi<To: Uniplate, From: Biplate<To>> {
Top {
left: VecDeque<To>,
right: VecDeque<To>,
rebuild_tree: Arc<dyn Fn(VecDeque<To>) -> Tree<To>>,
ctx: Arc<dyn Fn(Tree<To>) -> From>,
},
Node {
left: VecDeque<To>,
right: VecDeque<To>,
rebuild_tree: Arc<dyn Fn(VecDeque<To>) -> Tree<To>>,
ctx: Arc<dyn Fn(Tree<To>) -> To>,
},
}
impl<To: Uniplate, From: Biplate<To>> ZipperBi<To, From> {
pub fn new(top: From) -> Option<Self> {
let (children, ctx) = top.biplate();
let (mut siblings, rebuild_tree) = children.list();
let focus = siblings.pop_front()?;
let segment = PathSegmentBi::Top {
left: VecDeque::new(),
right: siblings,
rebuild_tree: rebuild_tree.into(),
ctx: ctx.into(),
};
Some(ZipperBi {
focus,
path: vec![segment],
})
}
pub fn focus(&self) -> &To {
&self.focus
}
pub fn focus_mut(&mut self) -> &mut To {
&mut self.focus
}
pub fn replace_focus(&mut self, new_focus: To) -> To {
std::mem::replace(&mut self.focus, new_focus)
}
pub fn rebuild_root(mut self) -> From {
while self.go_up().is_some() {}
let Some(PathSegmentBi::Top {
mut left,
mut right,
rebuild_tree,
ctx,
}) = self.path.pop()
else {
unreachable!();
};
left.push_back(self.focus.clone());
left.append(&mut right);
let tree = (rebuild_tree)(left);
(ctx)(tree)
}
pub fn depth(&self) -> usize {
self.path.len()
}
pub fn go_up(&mut self) -> Option<()> {
let Some(PathSegmentBi::Node {
left: _,
right: _,
rebuild_tree: _,
ctx: _,
}) = self.path.last()
else {
return None;
};
let Some(PathSegmentBi::Node {
mut left,
mut right,
rebuild_tree,
ctx,
}) = self.path.pop()
else {
unreachable!();
};
left.push_back(self.focus.clone());
left.append(&mut right);
let tree = (rebuild_tree)(left);
self.focus = (ctx)(tree);
Some(())
}
pub fn go_down(&mut self) -> Option<()> {
let (children, ctx) = self.focus.uniplate();
let (mut siblings, rebuild_tree) = children.list();
let new_focus = siblings.pop_front()?;
let new_segment = PathSegmentBi::Node {
left: VecDeque::new(),
right: siblings,
rebuild_tree: rebuild_tree.into(),
ctx: ctx.into(),
};
self.path.push(new_segment);
self.focus = new_focus;
Some(())
}
pub fn go_left(&mut self) -> Option<()> {
let (left, right) = match self.path.last_mut()? {
PathSegmentBi::Top {
left,
right,
rebuild_tree: _,
ctx: _,
} => (left, right),
PathSegmentBi::Node {
left,
right,
rebuild_tree: _,
ctx: _,
} => (left, right),
};
let new_focus = left.pop_front()?;
let old_focus = std::mem::replace(&mut self.focus, new_focus);
right.push_back(old_focus);
Some(())
}
pub fn go_right(&mut self) -> Option<()> {
let (left, right) = match self.path.last_mut()? {
PathSegmentBi::Top {
left,
right,
rebuild_tree: _,
ctx: _,
} => (left, right),
PathSegmentBi::Node {
left,
right,
rebuild_tree: _,
ctx: _,
} => (left, right),
};
let new_focus = right.pop_front()?;
let old_focus = std::mem::replace(&mut self.focus, new_focus);
left.push_back(old_focus);
Some(())
}
}