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}