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