use std::{collections::HashMap, hash::Hash, marker::PhantomData, mem};
use tracing::{debug, error, trace, trace_span};
use crate::{path::Path, tree::entry::Entry, tree::iter::depth::Traversal};
use super::{
entry::{TreeRefEntry, TREEBOUND},
iter::depth::TreeIterTarget,
node::TreeNode,
NodeIDX, Tree,
};
pub type DiffNode<N> = (Option<N>, Option<N>);
pub type DiffTree<N, B> = Tree<DiffNode<N>, B>;
pub struct Before<N>(PhantomData<N>);
pub struct Now<N>(PhantomData<N>);
impl<'a, N, B> TreeIterTarget<'a, DiffNode<N>, B> for Now<&'a N> {
type Target = &'a Option<N>;
fn target(tree: &'a Tree<DiffNode<N>, B>, idx: NodeIDX) -> Self::Target {
&tree.nodes[idx].value.1
}
}
impl<'a, N, B> TreeIterTarget<'a, DiffNode<N>, B> for Before<&'a N> {
type Target = &'a Option<N>;
fn target(tree: &'a Tree<DiffNode<N>, B>, idx: NodeIDX) -> Self::Target {
&tree.nodes[idx].value.0
}
}
impl<N, B> DiffTree<N, B>
where
B: Clone,
{
pub fn rev(&mut self) {
for node in self.nodes.iter_mut() {
mem::swap(&mut node.value.0, &mut node.value.1);
}
}
pub fn validate(&self) -> Result<(), Path<B>> {
let mut ph = Path::new();
for diff in self.iter_on::<&TreeNode<DiffNode<N>, B>>() {
ph.apply(&diff);
let d: &TreeNode<_, _> = diff.take();
if let (Some(_), None) = d.value {
if !d.children.is_empty() {
return Err(ph.branches_to_owned());
}
}
}
Ok(())
}
}
impl<N, B> DiffTree<N, B>
where
N: Clone,
B: Clone + Eq + Hash,
{
pub(super) fn mirror_subtree_at(
&mut self,
tree: &Tree<N, B>,
idx_s: NodeIDX,
idx_t: NodeIDX,
now: bool,
) {
if now {
self.nodes[idx_s].value.1 = Some(tree.nodes[idx_t].value.clone());
} else {
self.nodes[idx_s].value.0 = Some(tree.nodes[idx_t].value.clone());
}
self.mirror_subtree_rec(tree, idx_s, idx_t, now);
}
pub fn mirror_subtree_rec(
&mut self,
tree: &Tree<N, B>,
idx_s: NodeIDX,
idx_t: NodeIDX,
now: bool,
) {
for (branch, &c_idx_t) in &tree.nodes[idx_t].children {
let c_idx_s = if let Some(&c_idx_s) = self.nodes[idx_s].children.get(branch) {
if now {
self.nodes[c_idx_s].value.1 = Some(tree.nodes[c_idx_t].value.clone());
} else {
self.nodes[c_idx_s].value.0 = Some(tree.nodes[c_idx_t].value.clone());
}
c_idx_s
} else {
self.insert_at(
idx_s,
branch.clone(),
if now {
(None, Some(tree.nodes[c_idx_t].value.clone()))
} else {
(Some(tree.nodes[c_idx_t].value.clone()), None)
},
);
self.nodes[idx_s].children[branch]
};
self.mirror_subtree_rec(tree, c_idx_s, c_idx_t, now);
}
}
}
impl<N, B> DiffTree<N, B>
where
N: Clone + Default,
B: Clone + Eq + Hash + Default,
{
pub fn mirror_subtree(&mut self, tree: &Tree<N, B>, path: &Path<B>, now: bool) {
let root_t = tree.get_idx(path, None).unwrap();
let root_s = if let Ok(root_s) = self.get_idx(path, None) {
root_s
} else {
*self.extend(path, None).last().unwrap()
};
self.mirror_subtree_at(tree, root_s, root_t, now)
}
}
impl<N, B> DiffTree<N, B>
where
N: Default + Eq,
B: Default + Eq + Hash + Clone,
{
pub fn is_applicable_extend(&self, tree: &Tree<N, B>) -> Result<(), DiffApplyError<B>> {
self.is_applicable_with(tree, |entry, new| {
new.unwrap().1 = entry.path().len();
Ok(())
})
}
}
type Insertable<N, B> = fn(
&mut TreeRefEntry<N, B, TREEBOUND>,
&mut Option<(usize, usize)>,
) -> Result<(), DiffApplyError<B>>;
impl<N, B> DiffTree<N, B>
where
N: Eq,
B: Eq + Hash + Clone,
{
pub fn is_applicable(&self, tree: &Tree<N, B>) -> Result<(), DiffApplyError<B>> {
self.is_applicable_with(tree, |entry, new| {
if entry.is_node() {
return Ok(());
}
let detached = entry.detached().unwrap();
let detached_dist =
detached.iter_detached_path().len() - new.map(|(s, e)| e - s).unwrap_or(0);
debug_assert!(
detached_dist > 0,
"Expected detached entry, got attached entry"
);
if detached_dist == 1 {
if new.is_some() {
new.unwrap().1 += 1;
} else {
let l = entry.path().len();
*new = Some((l - 1, l));
}
Ok(())
} else {
Err(DiffApplyError::Other("Expected Parent".to_string()))
}
})
}
fn is_applicable_with(
&self,
tree: &Tree<N, B>,
insertable: Insertable<N, B>,
) -> Result<(), DiffApplyError<B>> {
use DiffApplyError::*;
let mut diff_i = self.iter_on::<&DiffNode<N>>();
let mut entry = tree.entry(&Path::new());
let mut deleted = None;
let mut new = None;
match diff_i.next() {
Some(Traversal::Start((b, n))) => {
if let Some(before) = &b {
let _s1 = trace_span!("Node existed");
let _s1_ = _s1.enter();
if let Some(node) = entry.node_mut() {
if **node != *before {
return Err(DifferentValue(Path::new()));
}
} else {
return Err(Expected(Path::new()));
}
if n.is_none() {
trace!("node will be deleted");
deleted = Some(0);
} else {
trace!("node will change");
}
} else if n.is_some() {
let _s1 = trace_span!("New node");
let _s1_ = _s1.enter();
if entry.is_detached() {
trace!("node will be created");
insertable(&mut entry, &mut new)?;
} else {
return Err(Unexpected(Path::new()));
}
} else {
trace!("node will remain unchanged");
}
}
None => {
debug!("diff is empty");
return Ok(());
}
Some(_) => {
unreachable!("Tree iteration should always start with a Root node");
}
};
for d in diff_i {
entry.apply_move_deref(&d);
if let Some(idx) = deleted {
if entry.path().len() <= idx {
deleted = None;
}
}
if let Some(n) = &mut new.as_mut() {
let l = entry.path().len();
if l <= n.0
{
new = None;
} else if l < n.1
{
n.1 = l;
}
}
let _s1 = trace_span!("next node");
let _s1_ = _s1.enter();
let (b, n) = d.take();
if let Some(before) = &b {
let _s2 = trace_span!("Node existed");
let _s2_ = _s2.enter();
if let Some(node) = entry.node_mut() {
if **node != *before {
return Err(DifferentValue(node.path().clone()));
}
} else {
return Err(Expected(entry.path().clone()));
}
if n.is_some() {
trace!("node will change");
if deleted.is_some() {
return Err(BelowDeletion(entry.path().clone()));
}
} else {
trace!("node will be deleted");
if deleted.is_none() {
deleted = Some(entry.path().len());
}
}
} else if n.is_some() {
let _s2 = trace_span!("New node");
let _s2_ = _s2.enter();
if deleted.is_some() {
return Err(BelowDeletion(entry.path().clone()));
}
if let Entry::Node(node) = entry {
return Err(Unexpected(node.path().clone()));
}
insertable(&mut entry, &mut new)?;
} else {
trace!("node will remain unchanged");
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DiffApplyError<B> {
Expected(Path<B>),
Unexpected(Path<B>),
DifferentValue(Path<B>),
BelowDeletion(Path<B>),
Other(String),
}
impl<B, T> From<DiffApplyError<B>> for Result<T, DiffApplyError<B>> {
fn from(value: DiffApplyError<B>) -> Self {
Err(value)
}
}
pub struct DiffMap<N, B> {
diffs: HashMap<Path<B>, DiffNode<N>>,
}
impl<N, B> IntoIterator for DiffMap<N, B> {
type Item = (Path<B>, DiffNode<N>);
type IntoIter = std::collections::hash_map::IntoIter<Path<B>, DiffNode<N>>;
fn into_iter(self) -> Self::IntoIter {
self.diffs.into_iter()
}
}
impl<N, B> From<HashMap<Path<B>, DiffNode<N>>> for DiffMap<N, B> {
fn from(value: HashMap<Path<B>, DiffNode<N>>) -> Self {
Self { diffs: value }
}
}
impl<N, B> From<DiffMap<N, B>> for DiffTree<N, B>
where
N: Ord,
B: Ord + Default + Hash + Clone,
{
fn from(value: DiffMap<N, B>) -> Self {
value
.diffs
.into_iter()
.fold(DiffTree::new(), |mut tree, (ph, v)| {
tree.insert_extend(&ph, v);
tree
})
}
}