@@ -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