1
+ use std:: collections:: HashMap ;
2
+ use std:: fmt:: Debug ;
3
+ use uuid:: Uuid ;
4
+
5
+ pub trait TreeItem : Clone + Debug {
6
+ fn id ( & self ) -> Option < Uuid > ;
7
+ /*
8
+ This is the name that will be output when getting the tree nodes
9
+ */
10
+ fn short_name ( & self ) -> & str ;
11
+ /*
12
+ This is the path that the item is stored into a tree
13
+ */
14
+ fn path ( & self ) -> Vec < & str > ;
15
+ const DELIMITER : char ;
16
+ }
17
+
18
+ #[ derive( Clone , Debug ) ]
19
+ pub struct TreeIndex < T : TreeItem > {
20
+ pub id : usize , // location in the tree
21
+ pub data : T , // this will be the raw value
22
+ pub path : Vec < String >
23
+ }
24
+
25
+ impl < T : TreeItem > TreeIndex < T > {
26
+ pub fn new ( id : usize , data : T ) -> Self {
27
+ TreeIndex {
28
+ id,
29
+ data : data. clone ( ) ,
30
+ path : data. path ( ) . iter ( ) . map ( |s| s. to_string ( ) ) . collect ( ) ,
31
+ }
32
+ }
33
+ }
34
+
35
+ pub struct NodeItem < T : TreeItem > {
36
+ pub item : T ,
37
+ pub parent : Option < T > ,
38
+ pub children : Vec < T >
39
+ }
40
+
41
+ pub struct TreeNode {
42
+ pub id : usize ,
43
+ pub item_id : Uuid ,
44
+ pub parent_idx : Option < usize > ,
45
+ pub children_idx : Vec < usize > ,
46
+ pub path : Vec < String >
47
+ }
48
+
49
+ impl TreeNode {
50
+ pub fn new < T : TreeItem > ( id : usize , parent_idx : Option < usize > , children_idx : Vec < usize > , index : TreeIndex < T > ) -> Self {
51
+ TreeNode {
52
+ id,
53
+ item_id : index. data . id ( ) . unwrap ( ) ,
54
+ parent_idx,
55
+ children_idx,
56
+ path : index. path ,
57
+ }
58
+ }
59
+ }
60
+
61
+ pub struct Tree < T : TreeItem > {
62
+ pub nodes : Vec < TreeNode > ,
63
+ pub items : Vec < TreeIndex < T > > ,
64
+ path_to_node : HashMap < Vec < String > , usize >
65
+ }
66
+
67
+ impl < T : TreeItem > Tree < T > {
68
+ pub fn from_items ( items : & mut Vec < T > ) -> Self {
69
+ let mut tree = Tree {
70
+ nodes : Vec :: new ( ) ,
71
+ items : Vec :: new ( ) ,
72
+ path_to_node : HashMap :: new ( )
73
+ } ;
74
+
75
+ // sort items
76
+ items. sort_by ( |a, b| a. path ( ) . len ( ) . cmp ( & b. path ( ) . len ( ) ) ) ;
77
+
78
+ // add items
79
+ for ( index, item) in items. iter ( ) . enumerate ( ) {
80
+ let tree_index = TreeIndex :: new ( index, item. clone ( ) ) ;
81
+ tree. items . push ( tree_index. clone ( ) ) ;
82
+
83
+ tree. add_item ( tree_index) ;
84
+ }
85
+
86
+ tree
87
+ }
88
+
89
+ fn add_item ( & mut self , index : TreeIndex < T > ) {
90
+ let parent_path = index. path [ 0 ..index. path . len ( ) - 1 ] . to_vec ( ) ;
91
+
92
+ let parent_id = self . path_to_node . get ( & parent_path) . map ( |& id| {
93
+ let parent = & mut self . nodes [ id] ;
94
+ parent. children_idx . push ( index. id ) ;
95
+ parent. id
96
+ } ) ;
97
+
98
+ // add new node
99
+ let node = TreeNode :: new ( index. id , parent_id, vec ! [ ] , index) ;
100
+ self . path_to_node . insert ( node. path . clone ( ) , node. id ) ;
101
+ self . nodes . push ( node) ;
102
+
103
+ }
104
+
105
+ fn get_item_by_id ( & self , tree_item_id : Uuid ) -> Option < NodeItem < T > > {
106
+ let item = self . items . iter ( ) . find ( |i| i. data . id ( ) == Some ( tree_item_id) ) ;
107
+
108
+ if let Some ( item) = item {
109
+ let node = self . nodes . get ( item. id ) ?;
110
+
111
+ // Get the parent if it exists
112
+ let parent = node. parent_idx
113
+ . and_then ( |pid| self . nodes . get ( pid) ) ;
114
+
115
+ // Get all children nodes
116
+ let children: Vec < & TreeNode > = node. children_idx . iter ( )
117
+ . filter_map ( |& child_id| self . nodes . get ( child_id) )
118
+ . collect ( ) ;
119
+
120
+ // Get corresponding items
121
+ let parent_item = parent. and_then ( |p| self . items . get ( p. id ) ) ;
122
+ let children_items: Vec < & TreeIndex < T > > = children. iter ( )
123
+ . filter_map ( |child| self . items . get ( child. id ) )
124
+ . collect ( ) ;
125
+
126
+ return Some ( NodeItem {
127
+ item : item. data . clone ( ) ,
128
+ parent : parent_item. map ( |p| p. data . clone ( ) ) ,
129
+ children : children_items. iter ( ) . map ( |i| i. data . clone ( ) ) . collect ( )
130
+ } )
131
+ }
132
+
133
+ None
134
+ }
135
+ }
136
+
137
+ #[ cfg( test) ]
138
+ mod tests {
139
+ use super :: * ;
140
+ use uuid:: Uuid ;
141
+ use crate :: tree:: TreeItem ;
142
+
143
+ #[ derive( Clone , Debug ) ]
144
+ pub struct TestItem {
145
+ pub id : Uuid ,
146
+ pub name : String
147
+ }
148
+
149
+ impl TreeItem for TestItem {
150
+ fn id ( & self ) -> Option < Uuid > {
151
+ Some ( self . id )
152
+ }
153
+
154
+ fn short_name ( & self ) -> & str { self . path ( ) . last ( ) . unwrap ( ) }
155
+
156
+ fn path ( & self ) -> Vec < & str > {
157
+ self . name
158
+ . split ( Self :: DELIMITER )
159
+ . filter ( |s| !s. is_empty ( ) )
160
+ . collect :: < Vec < & str > > ( )
161
+ }
162
+
163
+ const DELIMITER : char = '/' ;
164
+ }
165
+
166
+ #[ test]
167
+ fn given_collection_with_one_parent_and_two_children_when_getting_parent_then_parent_is_returned_with_children_and_no_parent ( ) {
168
+ let parent_id = Uuid :: new_v4 ( ) ;
169
+ let mut items = vec ! [
170
+ TestItem {
171
+ id: Uuid :: new_v4( ) ,
172
+ name: "parent/child1" . to_string( )
173
+ } ,
174
+ TestItem {
175
+ id: parent_id,
176
+ name: "parent" . to_string( )
177
+ } ,
178
+ TestItem {
179
+ id: Uuid :: new_v4( ) ,
180
+ name: "parent/child2" . to_string( )
181
+ } ,
182
+ ] ;
183
+
184
+ let node_option = Tree :: from_items ( & mut items)
185
+ . get_item_by_id ( parent_id) ;
186
+
187
+ if let Some ( node) = node_option {
188
+ let item = node. item ;
189
+ let parent = node. parent ;
190
+ let children = node. children ;
191
+
192
+ assert_eq ! ( children. len( ) , 2 ) ;
193
+ assert_eq ! ( item. id( ) , Some ( parent_id) ) ;
194
+ assert_eq ! ( item. short_name( ) , "parent" ) ;
195
+ assert_eq ! ( item. path( ) , [ "parent" ] ) ;
196
+ assert ! ( parent. is_none( ) ) ;
197
+ } else {
198
+ panic ! ( "Node not found" ) ;
199
+ }
200
+ }
201
+
202
+ #[ test]
203
+ fn given_collection_with_one_parent_and_two_children_when_getting_child1_then_child1_is_returned_with_no_children_and_a_parent ( ) {
204
+ let child_1_id = Uuid :: new_v4 ( ) ;
205
+ let parent_id = Uuid :: new_v4 ( ) ;
206
+ let mut items = vec ! [
207
+ TestItem {
208
+ id: child_1_id,
209
+ name: "parent/child1" . to_string( )
210
+ } ,
211
+ TestItem {
212
+ id: parent_id,
213
+ name: "parent" . to_string( )
214
+ } ,
215
+ TestItem {
216
+ id: Uuid :: new_v4( ) ,
217
+ name: "parent/child2" . to_string( )
218
+ } ,
219
+ ] ;
220
+
221
+ let node_option = Tree :: from_items ( & mut items)
222
+ . get_item_by_id ( child_1_id) ;
223
+
224
+ if let Some ( node) = node_option {
225
+ let item = node. item ;
226
+ let parent = node. parent ;
227
+ let children = node. children ;
228
+
229
+ assert_eq ! ( children. len( ) , 0 ) ;
230
+ assert_eq ! ( item. id( ) , Some ( child_1_id) ) ;
231
+ assert_eq ! ( item. short_name( ) , "child1" ) ;
232
+ assert_eq ! ( item. path( ) , [ "parent" , "child1" ] ) ;
233
+ assert_eq ! ( parent. unwrap( ) . id, parent_id) ;
234
+ } else {
235
+ panic ! ( "Node not found" ) ;
236
+ }
237
+ }
238
+ }
0 commit comments