use crate::op_set2::OpSet;
use crate::types::{ObjId, ObjType};
use crate::{clock::Clock, exid::ExId, Prop};
#[derive(Debug, Clone)]
pub struct Parents<'a> {
pub(crate) obj: ObjId,
pub(crate) ops: &'a OpSet,
pub(crate) clock: Option<Clock>,
}
impl Parents<'_> {
pub fn path(self) -> Vec<(ExId, Prop)> {
let mut path = self
.map(|Parent { obj, prop, .. }| (obj, prop))
.collect::<Vec<_>>();
path.reverse();
path
}
pub fn visible_path(self) -> Option<Vec<(ExId, Prop)>> {
let mut path = Vec::new();
for Parent {
obj, prop, visible, ..
} in self
{
if !visible {
return None;
}
path.push((obj, prop))
}
path.reverse();
Some(path)
}
}
impl Iterator for Parents<'_> {
type Item = Parent;
fn next(&mut self) -> Option<Self::Item> {
if self.obj.is_root() {
return None;
}
let super::op_set::Parent {
obj,
typ,
prop,
visible,
..
} = self
.ops
.parent_object(&self.obj, self.clock.as_ref())
.unwrap();
self.obj = obj;
let obj = self.ops.id_to_exid(self.obj.0);
Some(Parent {
obj,
typ,
prop,
visible,
})
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Parent {
pub obj: ExId,
pub typ: ObjType,
pub prop: Prop,
pub visible: bool,
}
#[cfg(test)]
mod tests {
use super::Parent;
use crate::{transaction::Transactable, ObjType, Prop, ReadDoc};
#[test]
fn test_invisible_parents() {
let mut doc = crate::AutoCommit::new();
let list = doc
.put_object(crate::ROOT, "list", crate::ObjType::List)
.unwrap();
let obj1 = doc.insert_object(&list, 0, crate::ObjType::Map).unwrap();
let _obj2 = doc.insert_object(&list, 1, crate::ObjType::Map).unwrap();
doc.put(&obj1, "key", "value").unwrap();
doc.delete(&list, 0).unwrap();
let mut parents = doc.parents(&obj1).unwrap().collect::<Vec<_>>();
parents.reverse();
assert_eq!(
parents,
vec![
Parent {
obj: crate::ROOT,
prop: Prop::Map("list".to_string()),
visible: true,
typ: ObjType::Map,
},
Parent {
obj: list,
prop: Prop::Seq(0),
visible: false,
typ: ObjType::List,
},
]
);
}
}