sise/tree.rs
1use alloc::string::String;
2use alloc::vec::Vec;
3
4/// A SISE tree node.
5#[derive(Clone, Debug, PartialEq, Eq, Hash)]
6pub enum TreeNode {
7 /// An atom, that matches the following regular expression:
8 ///
9 /// > `"([:atomchar:]|\"(\\([:stringchar:]|\\|\")|[:stringchar:])+\")+"`
10 ///
11 /// Where `:atomchar:` is one of:
12 ///
13 /// > `!`, `#`, `$`, `%`, `&`, `*`, `+`, `-`, `.`, `/`, `:`, `<`, `=`,
14 /// `>`, `?`, `@`, `_`, `~`
15 ///
16 /// And `:stringchar:` is any character between ASCII space and `~`,
17 /// except `\` and `"`.
18 ///
19 /// Atoms are not interpreted in any way, the crate `sise_atom` provides
20 /// functions to encode and decode atoms as strings, numbers, booleans...
21 Atom(String),
22
23 /// A list of nodes
24 List(Vec<TreeNode>),
25}
26
27impl TreeNode {
28 /// Return whether the node is an `Atom`.
29 #[inline]
30 pub fn is_atom(&self) -> bool {
31 matches!(self, Self::Atom(_))
32 }
33
34 /// Return whether the node is a `List`.
35 #[inline]
36 pub fn is_list(&self) -> bool {
37 matches!(self, Self::List(_))
38 }
39
40 /// Consumes the node and returns the atom value if it is an
41 /// `Atom`.
42 #[inline]
43 pub fn into_atom(self) -> Option<String> {
44 match self {
45 Self::Atom(s) => Some(s),
46 _ => None,
47 }
48 }
49
50 /// Consumes the node and returns the list if it is a
51 /// `List`.
52 #[inline]
53 pub fn into_list(self) -> Option<Vec<Self>> {
54 match self {
55 Self::List(l) => Some(l),
56 _ => None,
57 }
58 }
59
60 /// Returns a reference to the atom value if the node is
61 /// an `Atom`.
62 #[inline]
63 pub fn as_atom(&self) -> Option<&String> {
64 match *self {
65 Self::Atom(ref s) => Some(s),
66 _ => None,
67 }
68 }
69
70 /// Returns a reference to the list if the node is
71 /// a `List`.
72 #[inline]
73 pub fn as_list(&self) -> Option<&Vec<Self>> {
74 match *self {
75 Self::List(ref l) => Some(l),
76 _ => None,
77 }
78 }
79
80 /// Returns a mutable reference to the atom value if the node is
81 /// an `Atom`.
82 #[inline]
83 pub fn as_mut_atom(&mut self) -> Option<&mut String> {
84 match *self {
85 Self::Atom(ref mut s) => Some(s),
86 _ => None,
87 }
88 }
89
90 /// Returns mutable a reference to the list if the node is
91 /// a `List`.
92 #[inline]
93 pub fn as_mut_list(&mut self) -> Option<&mut Vec<Self>> {
94 match *self {
95 Self::List(ref mut l) => Some(l),
96 _ => None,
97 }
98 }
99
100 /// Traverses a tree with indices from `path`.
101 ///
102 /// # Example
103 ///
104 /// ```
105 /// use sise::sise_tree;
106 ///
107 /// // (example (1 2 3) (a b c))
108 /// let tree = sise_tree!(["example", ["1", "2", "3"], ["a", "b", "c"]]);
109 /// assert_eq!(*tree.index_path(&[]).unwrap(), tree);
110 /// assert_eq!(*tree.index_path(&[0]).unwrap(), "example");
111 /// assert_eq!(*tree.index_path(&[1]).unwrap(), sise_tree!(["1", "2", "3"]));
112 /// assert_eq!(tree.index_path(&[1, 0]).unwrap(), "1");
113 /// assert_eq!(tree.index_path(&[2, 0]).unwrap(), "a");
114 /// assert!(tree.index_path(&[3]).is_none());
115 /// assert!(tree.index_path(&[0, 1]).is_none());
116 /// ```
117 pub fn index_path(&self, path: &[usize]) -> Option<&Self> {
118 let mut current_node = self;
119 for &index in path {
120 match current_node {
121 Self::Atom(_) => return None,
122 Self::List(ref list) => current_node = list.get(index)?,
123 }
124 }
125 Some(current_node)
126 }
127}
128
129impl PartialEq<str> for TreeNode {
130 fn eq(&self, other: &str) -> bool {
131 match *self {
132 Self::Atom(ref atom) => atom == other,
133 _ => false,
134 }
135 }
136}
137
138impl PartialEq<&str> for TreeNode {
139 fn eq(&self, other: &&str) -> bool {
140 match *self {
141 Self::Atom(ref atom) => atom == *other,
142 _ => false,
143 }
144 }
145}
146
147impl PartialEq<String> for TreeNode {
148 fn eq(&self, other: &String) -> bool {
149 match *self {
150 Self::Atom(ref atom) => atom == other,
151 _ => false,
152 }
153 }
154}
155
156impl<'a> From<&'a str> for TreeNode {
157 #[inline]
158 fn from(atom: &'a str) -> Self {
159 Self::Atom(String::from(atom))
160 }
161}
162
163impl From<String> for TreeNode {
164 #[inline]
165 fn from(atom: String) -> Self {
166 Self::Atom(atom)
167 }
168}
169
170impl From<Vec<TreeNode>> for TreeNode {
171 #[inline]
172 fn from(list: Vec<Self>) -> Self {
173 Self::List(list)
174 }
175}