Skip to content

Commit d8aa991

Browse files
committed
add map method
1 parent 6d0e5f2 commit d8aa991

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

src/tree.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,77 @@ impl<T> Tree<T> {
14841484
Ok(LevelOrderTraversalIds::new(self, node_id.clone()))
14851485
}
14861486

1487+
/// Returns a new `Tree` which nodes' values are mapped using the provided function.
1488+
///
1489+
/// If the mapping function returns an error it is returned immediately
1490+
/// and the process is aborted.
1491+
///
1492+
/// ```
1493+
/// # use id_tree::*;
1494+
/// # use id_tree::InsertBehavior::*;
1495+
///
1496+
/// let mut tree = Tree::new();
1497+
/// tree.insert(Node::new(1), AsRoot).unwrap();
1498+
///
1499+
/// fn map(x: i32) -> Result<i32, ()> {
1500+
/// Ok(x * 10)
1501+
/// }
1502+
/// let tree = tree.map(map).unwrap();
1503+
/// assert_eq!(10, *tree.get(&tree.root_node_id().unwrap()).unwrap().data());
1504+
/// ```
1505+
///
1506+
pub fn map<V, F, E>(mut self, mut map: F) -> Result<Tree<V>, E>
1507+
where
1508+
F: FnMut(T) -> Result<V, E>,
1509+
{
1510+
let tree_id = ProcessUniqueId::new();
1511+
1512+
Ok(Tree {
1513+
id: tree_id,
1514+
root: self.root.as_ref().map(|x| NodeId {
1515+
tree_id,
1516+
index: x.index,
1517+
}),
1518+
nodes: self
1519+
.nodes
1520+
.drain(..)
1521+
.map(|mut x| {
1522+
match x.as_mut().map(|y| {
1523+
Ok(Node {
1524+
data: map(unsafe {
1525+
std::mem::replace(&mut y.data, std::mem::zeroed())
1526+
})?,
1527+
parent: y.parent.as_ref().map(|z| NodeId {
1528+
tree_id,
1529+
index: z.index,
1530+
}),
1531+
children: y
1532+
.children
1533+
.iter()
1534+
.map(|z| NodeId {
1535+
tree_id,
1536+
index: z.index,
1537+
})
1538+
.collect(),
1539+
})
1540+
}) {
1541+
None => Ok(None),
1542+
Some(Ok(y)) => Ok(Some(y)),
1543+
Some(Err(y)) => Err(y),
1544+
}
1545+
})
1546+
.collect::<Result<_, E>>()?,
1547+
free_ids: self
1548+
.free_ids
1549+
.iter()
1550+
.map(|x| NodeId {
1551+
tree_id,
1552+
index: x.index,
1553+
})
1554+
.collect(),
1555+
})
1556+
}
1557+
14871558
// Nothing should make it past this function.
14881559
// If there is a way for a NodeId to be invalid, it should be caught here.
14891560
fn is_valid_node_id(&self, node_id: &NodeId) -> (bool, Option<NodeIdError>) {
@@ -2990,4 +3061,69 @@ mod tree_tests {
29903061
// ensure the tree and the cloned tree are equal
29913062
assert_eq!(tree, cloned);
29923063
}
3064+
3065+
#[test]
3066+
fn test_map() {
3067+
use InsertBehavior::*;
3068+
3069+
let mut tree = Tree::new();
3070+
let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
3071+
let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
3072+
let node_2_id = tree.insert(Node::new(2), UnderNode(&root_id)).unwrap();
3073+
let _node_3_id = tree.insert(Node::new(3), UnderNode(&node_1_id)).unwrap();
3074+
let node_4_id = tree.insert(Node::new(4), UnderNode(&node_2_id)).unwrap();
3075+
tree.take_node(node_4_id);
3076+
3077+
let tree_id = tree.id;
3078+
3079+
// ensure errors from the mapping function are propagated
3080+
assert_eq!(Err(()), tree.clone().map(|_| Err(()) as Result<(), ()>));
3081+
3082+
let mapped = tree
3083+
.map(|x| Ok(x.to_string()) as Result<String, ()>)
3084+
.unwrap();
3085+
assert!(mapped.root.is_some());
3086+
3087+
// ensure mapped tree has a new id
3088+
assert_ne!(tree_id, mapped.id);
3089+
3090+
// ensure mapped tree's root is using the new tree id
3091+
assert_eq!(mapped.root.as_ref().map(|x| x.tree_id), Some(mapped.id));
3092+
3093+
// ensure mapped tree's free_ids is using the new tree id
3094+
assert_eq!(mapped.free_ids[0].tree_id, mapped.id);
3095+
3096+
// ensure nodes' parent are using the new tree id
3097+
assert_eq!(
3098+
mapped.nodes[1]
3099+
.as_ref()
3100+
.map(|x| x.parent.as_ref().map(|x| x.tree_id)),
3101+
Some(Some(mapped.id))
3102+
);
3103+
3104+
// ensure nodes' children are using the new tree id
3105+
assert_eq!(
3106+
mapped
3107+
.children(mapped.root.as_ref().unwrap())
3108+
.unwrap()
3109+
.next()
3110+
.map(|x| x.parent.as_ref().map(|x| x.tree_id)),
3111+
Some(Some(mapped.id))
3112+
);
3113+
3114+
// ensure the mapping is correct
3115+
assert_eq!(
3116+
mapped
3117+
.traverse_level_order(mapped.root.as_ref().unwrap())
3118+
.unwrap()
3119+
.map(Node::data)
3120+
.collect::<Vec<_>>(),
3121+
vec![
3122+
&0.to_string(),
3123+
&1.to_string(),
3124+
&2.to_string(),
3125+
&3.to_string()
3126+
]
3127+
);
3128+
}
29933129
}

0 commit comments

Comments
 (0)