treeflection/
node.rs

1use std::collections::HashMap;
2
3use serde::Serialize;
4use serde::de::DeserializeOwned;
5use serde_json;
6
7use crate::node_runner::NodeRunner;
8use crate::node_token::NodeToken;
9
10pub trait Node {
11    fn node_step(&mut self, runner: NodeRunner) -> String;
12}
13
14impl<T> Node for Vec<T> where T: Node + Serialize + DeserializeOwned + Default {
15    fn node_step(&mut self, mut runner: NodeRunner) -> String {
16        match runner.step() {
17            NodeToken::ChainIndex (index) => {
18                let length = self.len();
19                match self.get_mut(index) {
20                    Some (item) => item.node_step(runner),
21                    None => {
22                        return match length {
23                             0 => format!("Used index {} on an empty vector", index),
24                             1 => format!("Used index {} on a vector of size 1 (try 0)", index),
25                             _ => format!("Used index {} on a vector of size {} (try a value between 0-{})", index, length, length-1)
26                        }
27                    }
28                }
29            }
30            NodeToken::ChainAll => {
31                let mut combined = String::from("|");
32                for item in self {
33                    combined.push_str(item.node_step(runner.clone()).as_ref());
34                    combined.push('|');
35                }
36                combined
37            }
38            NodeToken::ChainProperty (ref s) if s == "length" => { self.len().node_step(runner) } // TODO: yeah this should really be a command not a property
39            NodeToken::Get => {
40                serde_json::to_string_pretty(self).unwrap()
41            }
42            NodeToken::Set (value) => {
43                match serde_json::from_str(&value) {
44                    Ok(result) => {
45                        *self = result;
46                        String::from("")
47                    }
48                    Err(err) => {
49                        format!("vector set error: {}", err)
50                    }
51                }
52            }
53            NodeToken::InsertIndex (index) => {
54                let max_index = self.len();
55                if index > max_index {
56                    format!("Tried to insert at index {} on a vector of size {} (try a value between 0-{})", index, max_index, max_index)
57                }
58                else {
59                    self.insert(index, T::default());
60                    String::new()
61                }
62            }
63            NodeToken::RemoveIndex (index) => {
64                let max_index = self.len() - 1;
65                if index > max_index {
66                    format!("Tried to remove the value at index {} on a vector of size {} (try a value between 0-{})", index, self.len(), max_index)
67                }
68                else {
69                    self.remove(index);
70                    String::new()
71                }
72            }
73            NodeToken::SetDefault => {
74                *self = vec!();
75                String::new()
76            }
77            NodeToken::Help => {
78                String::from(r#"
79Vector Help
80
81Commands:
82*   help    - display this help
83*   get     - display JSON
84*   set     - set to JSON
85*   insert  - create a new element
86*   remove  - remove an element
87*   reset   - reset to empty vector
88
89Accessors:
90*   [index] - access item at index
91*   .length - display number of items"#)
92            }
93            action => { format!("vector cannot '{:?}'", action) }
94        }
95    }
96}
97
98impl<T> Node for HashMap<String, T> where T: Node + Serialize + DeserializeOwned + Default {
99    fn node_step(&mut self, mut runner: NodeRunner) -> String {
100        match runner.step() {
101            NodeToken::ChainKey (key) => {
102                let length = self.len();
103                match self.get_mut(&key) {
104                    Some (item) => { return item.node_step(runner) }
105                    None        => { }
106                }
107                match length {
108                     0 => {
109                        format!("Used key '{}' on an empty map.", key)
110                     }
111                     _ => {
112                        format!("Used key '{}' on a map that does not contain it. Try one of: {}", key, format_keys(self))
113                    }
114                }
115            }
116            NodeToken::ChainAll => {
117                let mut combined = String::from("|");
118                let mut pairs: Vec<_> = self.iter_mut().collect();
119                pairs.sort_by_key(|x| x.0);
120                for (_, item) in pairs {
121                    combined.push_str(item.node_step(runner.clone()).as_ref());
122                    combined.push('|');
123                }
124                combined
125            }
126            NodeToken::GetKeys => {
127                format_keys(self)
128            }
129            NodeToken::ChainProperty (ref s) if s == "length" => { self.len().node_step(runner) } // TODO: yeah this should really be a command not a property
130            NodeToken::Get => {
131                serde_json::to_string_pretty(self).unwrap()
132            }
133            NodeToken::Set (value) => {
134                match serde_json::from_str(&value) {
135                    Ok(result) => {
136                        *self = result;
137                        String::from("")
138                    }
139                    Err(err) => {
140                        format!("map set error: {}", err)
141                    }
142                }
143            }
144            NodeToken::InsertKey (key) => {
145                if self.contains_key(&key) {
146                    format!("Tried to insert key '{}' on a map that already contains it. Current keys: {}", key, format_keys(self))
147                }
148                else {
149                    self.insert(key, T::default());
150                    String::new()
151                }
152            }
153            NodeToken::RemoveKey (key) => {
154                if let None = self.remove(&key) {
155                    format!("Tried to remove key '{}' on a map that doesnt contain it. Current keys: {}", key, format_keys(self))
156                }
157                else {
158                    String::new()
159                }
160            }
161            NodeToken::SetDefault => {
162                *self = HashMap::new();
163                String::new()
164            }
165            NodeToken::Help => {
166                String::from(r#"
167Map Help
168
169Commands:
170*   help    - display this help
171*   get     - display JSON
172*   getkeys - display keys
173*   set     - set to JSON
174*   insert  - create a new element
175*   remove  - remove an element
176*   reset   - reset to empty map
177
178Accessors:
179*   [key]   - access item at the string key
180*   .length - display number of items"#)
181            }
182            action => { format!("map cannot '{:?}'", action) }
183        }
184    }
185}
186
187fn format_keys<T>(map: &HashMap<String, T>) -> String {
188    let mut key_list: Vec<String> = map.keys().map(|x| format!("'{}'", x)).collect();
189    key_list.sort();
190    key_list.join(", ")
191}
192
193macro_rules! tuple_node {
194    ( $( $indexes:tt $types:ident ),* ) => {
195        impl <$( $types ),*> Node for ($( $types, )*) where $( $types: Node + Serialize + DeserializeOwned),* {
196            fn node_step(&mut self, mut runner: NodeRunner) -> String {
197                let name = stringify!{ ($( $types, )*) };
198                match runner.step() {
199                    NodeToken::ChainIndex (index) => {
200                        match index {
201                            $(
202                                $indexes => self.$indexes.node_step(runner),
203                            )*
204                            _ => format!("Used index {} on a {}", index, name)
205                        }
206                    }
207                    NodeToken::ChainAll => {
208                        let mut combined = String::from("|");
209                        $(
210                            combined.push_str(self.$indexes.node_step(runner.clone()).as_ref());
211                            combined.push('|');
212                        )*
213                        combined
214                    }
215                    NodeToken::Get => {
216                        serde_json::to_string_pretty(self).unwrap()
217                    }
218                    NodeToken::Set (value) => {
219                        match serde_json::from_str(&value) {
220                            Ok (result) => {
221                                *self = result;
222                                String::from("")
223                            }
224                            Err (err) => {
225                                format!("{} set error: {}", name, err)
226                            }
227                        }
228                    }
229                    NodeToken::Help => {
230                        String::from(r#"
231Tuple Help
232
233Commands:
234*   help - display this help
235*   get  - display JSON
236*   set  - set to JSON
237
238Accessors:
239*   [index] - access item at index"#)
240                    }
241                    action => { format!("{} cannot '{:?}'", name, action) }
242                }
243            }
244        }
245    }
246}
247
248tuple_node!(0 T0);
249tuple_node!(0 T0, 1 T1);
250tuple_node!(0 T0, 1 T1, 2 T2);
251tuple_node!(0 T0, 1 T1, 2 T2, 3 T3);
252tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4);
253tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5);
254tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6);
255tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7);
256tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7, 8 T8);
257tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7, 8 T8, 9 T9);
258tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7, 8 T8, 9 T9, 10 T10);
259tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7, 8 T8, 9 T9, 10 T10, 11 T11);
260tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7, 8 T8, 9 T9, 10 T10, 11 T11, 12 T12);
261tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7, 8 T8, 9 T9, 10 T10, 11 T11, 12 T12, 13 T13);
262tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7, 8 T8, 9 T9, 10 T10, 11 T11, 12 T12, 13 T13, 14 T14);
263tuple_node!(0 T0, 1 T1, 2 T2, 3 T3, 4 T4, 5 T5, 6 T6, 7 T7, 8 T8, 9 T9, 10 T10, 11 T11, 12 T12, 13 T13, 14 T14, 15 T15);
264
265macro_rules! array_node {
266    ( $length:expr ) => {
267        impl<T> Node for [T; $length] where T: Node + Serialize + DeserializeOwned {
268            fn node_step(&mut self, mut runner: NodeRunner) -> String {
269                let length = stringify!{ $length };
270                match runner.step() {
271                    NodeToken::ChainIndex (index) => {
272                        #[allow(unused_comparisons)] // comparison becomes useless on array of size 0
273                        if index < $length {
274                            self[index].node_step(runner)
275                        } else {
276                            format!("Used index {} on an array of length {}", index, length)
277                        }
278                    }
279                    NodeToken::ChainAll => {
280                        let mut combined = String::from("|");
281                        for i in 0..$length {
282                            combined.push_str(self[i].node_step(runner.clone()).as_ref());
283                            combined.push('|');
284                        }
285                        combined
286                    }
287                    NodeToken::Get => {
288                        serde_json::to_string_pretty(self).unwrap()
289                    }
290                    NodeToken::Set (value) => {
291                        match serde_json::from_str(&value) {
292                            Ok (result) => {
293                                *self = result;
294                                String::from("")
295                            }
296                            Err (err) => {
297                                format!("array set error: {}", err)
298                            }
299                        }
300                    }
301                    NodeToken::Help => {
302                        String::from(r#"
303Array Help
304
305Commands:
306*   help - display this help
307*   get  - display JSON
308*   set  - set to JSON
309
310Accessors:
311*   [index] - access item at index"#)
312                    }
313                    action => { format!("array cannot '{:?}'", action) }
314                }
315            }
316        }
317    }
318}
319
320array_node!(0);
321array_node!(1);
322array_node!(2);
323array_node!(3);
324array_node!(4);
325array_node!(5);
326array_node!(6);
327array_node!(7);
328array_node!(8);
329array_node!(9);
330array_node!(10);
331array_node!(11);
332array_node!(12);
333array_node!(13);
334array_node!(14);
335array_node!(15);
336array_node!(16);
337
338impl Node for bool {
339    fn node_step(&mut self, mut runner: NodeRunner) -> String {
340        match runner.step() {
341            NodeToken::Get         => { if *self { String::from("true") } else { String::from("false") } }
342            NodeToken::Set (value) => { *self = value.as_str() == "true"; String::from("") }
343            NodeToken::Help        => {
344                String::from(r#"
345Bool Help
346
347Valid values: true or false
348
349Commands:
350*   help - display this help
351*   get  - display value
352*   set  - set to value"#)
353            }
354            action => { format!("bool cannot '{:?}'", action) }
355        }
356    }
357}
358
359impl Node for String {
360    fn node_step(&mut self, mut runner: NodeRunner) -> String {
361        match runner.step() {
362            NodeToken::Get => { (*self).clone() }
363            NodeToken::Set (value) => { *self = value; String::from("") }
364            NodeToken::CopyFrom => {
365                let copy = Some (self.clone());
366                unsafe {
367                    STRING_COPY = copy;
368                }
369                String::new()
370            }
371            NodeToken::PasteTo => {
372                let paste = unsafe { STRING_COPY.clone() };
373                match paste {
374                    Some (value) => {
375                        *self = value;
376                        String::new()
377                    }
378                    None => {
379                        String::from("String has not been copied")
380                    }
381                }
382            }
383            NodeToken::Help => {
384                String::from(r#"
385String Help
386
387Valid values: Anything
388
389Commands:
390*   help  - display this help
391*   copy  - copy this value
392*   paste - paste the copied value here
393*   get   - display value
394*   set   - set to value"#)
395            }
396            action => { format!("String cannot '{:?}'", action) }
397        }
398    }
399}
400
401static mut STRING_COPY: Option<String> = None;
402
403impl<T> Node for Option<T> where T: Node + Serialize + DeserializeOwned + Default {
404    fn node_step(&mut self, mut runner: NodeRunner) -> String {
405        match runner.step() {
406            NodeToken::ChainProperty (ref s) if s == "value" => {
407                if let &mut Some(ref mut value) = self {
408                    value.node_step(runner)
409                }
410                else {
411                    String::from("Option contains no value")
412                }
413            }
414            NodeToken::Get => {
415                serde_json::to_string_pretty(self).unwrap()
416            }
417            NodeToken::Set (value) => {
418                match serde_json::from_str(&value) {
419                    Ok(result) => {
420                        *self = result;
421                        String::from("")
422                    }
423                    Err(err) => {
424                        format!("Option set error: {}", err)
425                    }
426                }
427            }
428            NodeToken::Insert => {
429                *self = Some(T::default());
430                String::new()
431            }
432            NodeToken::Remove => {
433                *self = None;
434                String::new()
435            }
436            NodeToken::SetDefault => {
437                *self = None;
438                String::new()
439            }
440            NodeToken::Help => {
441                String::from(r#"
442Option Help
443
444Commands:
445*   help    - display this help
446*   get     - display JSON
447*   set     - set to JSON
448*   insert  - set to a value
449*   remove  - remove value
450*   reset   - remove value
451
452Accessors:
453*   .value - the stored value"#)
454            }
455            action => { format!("Option cannot '{:?}'", action) }
456        }
457    }
458}
459
460macro_rules! int_node {
461    ($e:ty, $valid_values:tt) => {
462        impl Node for $e {
463            fn node_step(&mut self, mut runner: NodeRunner) -> String {
464                match runner.step() {
465                    NodeToken::Get => { (*self).to_string() }
466                    NodeToken::Set (value) => {
467                        match value.parse() {
468                            Ok (value) => {
469                                *self = value;
470                                String::from("")
471                            }
472                            Err(_) => {
473                                format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
474                            }
475                        }
476                    }
477                    NodeToken::Help => {
478                        format!(r#"
479{} Help
480
481Valid values: {}
482
483Commands:
484*   help             - display this help
485*   copy             - copy this value
486*   paste            - paste the copied value here
487*   get              - display value
488*   set      $NUMBER - set to $NUMBER
489*   add      $NUMBER - adds $NUMBER to this number
490*   subtract $NUMBER - subtracts $NUMBER from this number
491*   multiply $NUMBER - multiply this number with $NUMBER
492*   divide   $NUMBER - divide this number by $NUMBER"#,
493                            stringify! { $e },
494                            $valid_values
495                        )
496                    }
497                    NodeToken::CopyFrom => {
498                        let num_copy = match stringify! { $e } {
499                            "f32" | "f64" => NumStore::Float (*self as f64),
500                            _             => NumStore::Int   (*self as u64)
501                        };
502                        unsafe {
503                            NUM_COPY = num_copy;
504                        }
505                        String::from("")
506                    }
507                    NodeToken::PasteTo => {
508                        let num_copy = unsafe { NUM_COPY.clone() };
509                        match num_copy {
510                            NumStore::Int (value) => {
511                                *self = value as $e;
512                                String::from("")
513                            }
514                            NumStore::Float (value) => {
515                                *self = value as $e;
516                                String::from("")
517                            }
518                            NumStore::None => {
519                                String::from("A number has not been copied")
520                            }
521                        }
522                    }
523                    NodeToken::Custom (action, args) => {
524                        match action.as_ref() {
525                            "add" => {
526                                if let Some(arg0) = args.get(0) {
527                                    if let Ok(number) = arg0.parse() {
528                                        *self = (*self).saturating_add(number);
529                                        String::from("")
530                                    } else {
531                                        format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
532                                    }
533                                } else {
534                                    format!("No value for {} (needs to be: {})", stringify! { $e }, $valid_values)
535                                }
536                            }
537                            "subtract" => {
538                                if let Some(arg0) = args.get(0) {
539                                    if let Ok(number) = arg0.parse() {
540                                        *self = (*self).saturating_sub(number);
541                                        String::from("")
542                                    } else {
543                                        format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
544                                    }
545                                } else {
546                                    format!("No value for {} (needs to be: {})", stringify! { $e }, $valid_values)
547                                }
548                            }
549                            "multiply" => {
550                                if let Some(arg0) = args.get(0) {
551                                    if let Ok(number) = arg0.parse() {
552                                        *self = (*self).saturating_mul(number);
553                                        String::from("")
554                                    } else {
555                                        format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
556                                    }
557                                } else {
558                                    format!("No value for {} (needs to be: {})", stringify! { $e }, $valid_values)
559                                }
560                            }
561                            "divide" => {
562                                if let Some(arg0) = args.get(0) {
563                                    if let Ok(number) = arg0.parse() {
564                                        if let Some(number) = (*self).checked_div(number) {
565                                            *self = number;
566                                            String::from("")
567                                        } else {
568                                            format!("Invalid value for {} (needs to be: {}, excluding 0)", stringify! { $e }, $valid_values)
569                                        }
570                                    } else {
571                                        format!("Invalid value for {} (needs to be: {}, excluding 0)", stringify! { $e }, $valid_values)
572                                    }
573                                } else {
574                                    format!("No value for {} (needs to be: {})", stringify! { $e }, $valid_values)
575                                }
576                            }
577                            _ => {
578                                format!("{} cannot '{}'", stringify! { $e }, action)
579                            }
580                        }
581                    }
582                    action => { format!("{} cannot '{:?}'", stringify! { $e }, action) }
583                }
584            }
585        }
586    }
587}
588
589macro_rules! float_node {
590    ($e:ty, $valid_values:tt) => {
591        impl Node for $e {
592            fn node_step(&mut self, mut runner: NodeRunner) -> String {
593                match runner.step() {
594                    NodeToken::Get => { (*self).to_string() }
595                    NodeToken::Set (value) => {
596                        match value.parse() {
597                            Ok (value) => {
598                                *self = value;
599                                String::from("")
600                            }
601                            Err(_) => {
602                                format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
603                            }
604                        }
605                    }
606                    NodeToken::Help => {
607                        format!(r#"
608{} Help
609
610Valid values: {}
611
612Commands:
613*   help             - display this help
614*   copy             - copy this value
615*   paste            - paste the copied value here
616*   get              - display value
617*   set      $NUMBER - set to $NUMBER
618*   add      $NUMBER - adds $NUMBER to this number
619*   subtract $NUMBER - subtracts $NUMBER from this number
620*   multiply $NUMBER - multiply this number with $NUMBER
621*   divide   $NUMBER - divide this number by $NUMBER"#,
622                            stringify! { $e },
623                            $valid_values
624                        )
625                    }
626                    NodeToken::CopyFrom => {
627                        let num_copy = match stringify! { $e } {
628                            "f32" | "f64" => NumStore::Float (*self as f64),
629                            _             => NumStore::Int   (*self as u64)
630                        };
631                        unsafe {
632                            NUM_COPY = num_copy;
633                        }
634                        String::from("")
635                    }
636                    NodeToken::PasteTo => {
637                        let num_copy = unsafe { NUM_COPY.clone() };
638                        match num_copy {
639                            NumStore::Int (value) => {
640                                *self = value as $e;
641                                String::from("")
642                            }
643                            NumStore::Float (value) => {
644                                *self = value as $e;
645                                String::from("")
646                            }
647                            NumStore::None => {
648                                String::from("A number has not been copied")
649                            }
650                        }
651                    }
652                    NodeToken::Custom (action, args) => {
653                        match action.as_ref() {
654                            "add" => {
655                                if let Some(arg0) = args.get(0) {
656                                    if let Ok(number) = arg0.parse::<$e>() {
657                                        *self += number;
658                                        String::from("")
659                                    } else {
660                                        format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
661                                    }
662                                } else {
663                                    format!("No value for {} (needs to be: {})", stringify! { $e }, $valid_values)
664                                }
665                            }
666                            "subtract" => {
667                                if let Some(arg0) = args.get(0) {
668                                    if let Ok(number) = arg0.parse::<$e>() {
669                                        *self -= number;
670                                        String::from("")
671                                    } else {
672                                        format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
673                                    }
674                                } else {
675                                    format!("No value for {} (needs to be: {})", stringify! { $e }, $valid_values)
676                                }
677                            }
678                            "multiply" => {
679                                if let Some(arg0) = args.get(0) {
680                                    if let Ok(number) = arg0.parse::<$e>() {
681                                        *self *= number;
682                                        String::from("")
683                                    } else {
684                                        format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
685                                    }
686                                } else {
687                                    format!("No value for {} (needs to be: {})", stringify! { $e }, $valid_values)
688                                }
689                            }
690                            "divide" => {
691                                if let Some(arg0) = args.get(0) {
692                                    if let Ok(number) = arg0.parse::<$e>() {
693                                        *self /= number;
694                                        String::from("")
695                                    } else {
696                                        format!("Invalid value for {} (needs to be: {})", stringify! { $e }, $valid_values)
697                                    }
698                                } else {
699                                    format!("No value for {} (needs to be: {})", stringify! { $e }, $valid_values)
700                                }
701                            }
702                            _ => {
703                                format!("{} cannot '{}'", stringify! { $e }, action)
704                            }
705                        }
706                    }
707                    action => { format!("{} cannot '{:?}'", stringify! { $e }, action) }
708                }
709            }
710        }
711    }
712}
713
714#[derive(Clone)]
715enum NumStore {
716    Int   (u64),
717    Float (f64),
718    None,
719}
720
721static mut NUM_COPY: NumStore = NumStore::None;
722
723int_node!(i64, "A number from –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807");
724int_node!(u64, "A number from 0 to 18,446,744,073,709,551,615");
725int_node!(i32, "A number from –2,147,483,648 to 2,147,483,647");
726int_node!(u32, "A number from 0 to 4,294,967,295");
727int_node!(i16, "A number from –32,768 to –32,767");
728int_node!(u16, "A number from 0 to 65,535");
729int_node!(i8, "A number from -128 to 127");
730int_node!(u8, "A number from 0 to 255");
731int_node!(isize, "A number from –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807");
732int_node!(usize, "A number from 0 to 18,446,744,073,709,551,615");
733
734// TODO: Not sure how to best present possible values for the floats
735float_node!(f32, "A number with a decimal point");
736float_node!(f64, "A higher precision number with a decimal point");