diff --git a/crates/loro-internal/src/container/list/list_container.rs b/crates/loro-internal/src/container/list/list_container.rs index c4c3d506..e3935bee 100644 --- a/crates/loro-internal/src/container/list/list_container.rs +++ b/crates/loro-internal/src/container/list/list_container.rs @@ -684,12 +684,9 @@ impl List { self.with_container(|list| list.iter().enumerate().for_each(f)) } - // pub fn map R, R>( - // &self, - // f: F, - // ) -> Map, F> { - // self.with_container(|list| list.iter().map(f)) - // } + pub fn map R, R>(&self, f: F) -> Vec { + self.with_container(|list| list.iter().enumerate().map(f).collect()) + } #[must_use] pub fn is_empty(&self) -> bool { @@ -735,7 +732,7 @@ impl ContainerWrapper for List { #[cfg(test)] mod test { - use crate::LoroCore; + use crate::{LoroCore, LoroValue, PrelimContainer}; #[test] fn test_list_get() { @@ -787,4 +784,16 @@ mod test { assert_eq!(format!("\"{c}\""), v.to_json()) }) } + + #[test] + fn map() { + let mut loro = LoroCore::default(); + let mut list = loro.get_list("list"); + list.insert(&loro, 0, "a").unwrap(); + list.insert(&loro, 1, "b").unwrap(); + list.insert(&loro, 2, "c").unwrap(); + // list.insert(&loro, 3, PrelimContainer::from("hello".to_string())) + // .unwrap(); + assert_eq!(list.map(|(_, v)| v.to_json()),vec!["\"a\"", "\"b\"", "\"c\""]); + } } diff --git a/crates/loro-internal/src/error.rs b/crates/loro-internal/src/error.rs index b8379083..547ba2ef 100644 --- a/crates/loro-internal/src/error.rs +++ b/crates/loro-internal/src/error.rs @@ -16,6 +16,8 @@ pub enum LoroError { LockError, #[error("LoroValue::Unresolved cannot be converted to PrelimValue")] PrelimError, + #[error("Cannot find ({0}) ")] + NotFoundError(Box), // #[error("the data for key `{0}` is not available")] // Redaction(String), // #[error("invalid header (expected {expected:?}, found {found:?})")] diff --git a/crates/loro-internal/src/hierarchy.rs b/crates/loro-internal/src/hierarchy.rs index e2b49667..306b9f6b 100644 --- a/crates/loro-internal/src/hierarchy.rs +++ b/crates/loro-internal/src/hierarchy.rs @@ -8,6 +8,7 @@ use fxhash::{FxHashMap, FxHashSet}; use crate::{ container::{registry::ContainerRegistry, ContainerID}, event::{Event, EventDispatch, Index, Observer, Path, PathAndTarget, RawEvent, SubscriptionID}, + LoroError, }; /// [`Hierarchy`] stores the hierarchical relationship between containers @@ -78,6 +79,20 @@ impl Hierarchy { .unwrap_or(false) } + pub fn children(&self, id: &ContainerID) -> Result, LoroError> { + self.nodes + .get(id) + .ok_or(LoroError::NotFoundError(format!("{:?}", id).into())) + .map(|node| node.children.clone()) + } + + pub fn parent(&self, id: &ContainerID) -> Result, LoroError> { + self.nodes + .get(id) + .ok_or(LoroError::NotFoundError(format!("{:?}", id).into())) + .map(|node| node.parent.clone()) + } + #[inline(always)] pub fn contains(&self, id: &ContainerID) -> bool { self.nodes.get(id).is_some() || id.is_root() @@ -429,3 +444,32 @@ impl Hierarchy { } } } + +#[cfg(test)] +mod test { + use fxhash::FxHashMap; + + use crate::{LoroCore, PrelimContainer}; + + #[test] + fn children_parent() { + let mut loro = LoroCore::default(); + let mut list = loro.get_list("list"); + let map_container_id = list + .push(&loro, PrelimContainer::from(FxHashMap::default())) + .unwrap() + .unwrap(); + let list_container_id = list.id(); + assert_eq!( + loro.children(&list_container_id) + .unwrap() + .into_iter() + .collect::>(), + vec![map_container_id.clone()] + ); + assert_eq!( + loro.parent(&map_container_id).unwrap().unwrap(), + list_container_id + ) + } +} diff --git a/crates/loro-internal/src/loro.rs b/crates/loro-internal/src/loro.rs index eeca1422..cc29dfda 100644 --- a/crates/loro-internal/src/loro.rs +++ b/crates/loro-internal/src/loro.rs @@ -7,7 +7,7 @@ use crate::{ log_store::{EncodeConfig, LoroEncoder}, LoroError, LoroValue, }; -use fxhash::FxHashMap; +use fxhash::{FxHashMap, FxHashSet}; use tracing::instrument; use crate::{ @@ -79,6 +79,16 @@ impl LoroCore { store.contains_container(id) } + pub fn children(&self, id: &ContainerID) -> Result, LoroError> { + let hierarchy = self.hierarchy.try_lock().unwrap(); + hierarchy.children(id) + } + + pub fn parent(&self, id: &ContainerID) -> Result, LoroError> { + let hierarchy = self.hierarchy.try_lock().unwrap(); + hierarchy.parent(id) + } + // TODO: make it private pub fn export(&self, remote_vv: VersionVector) -> FxHashMap>> { let store = self.log_store.read().unwrap();