1 use std::str::FromStr;
2 
3 use crate::error::{ConfigError, Result};
4 use crate::map::Map;
5 use crate::value::{Value, ValueKind};
6 
7 mod parser;
8 
9 #[derive(Debug, Eq, PartialEq, Clone, Hash)]
10 pub enum Expression {
11     Identifier(String),
12     Child(Box<Self>, String),
13     Subscript(Box<Self>, isize),
14 }
15 
16 impl FromStr for Expression {
17     type Err = ConfigError;
18 
from_str(s: &str) -> Result<Self>19     fn from_str(s: &str) -> Result<Self> {
20         parser::from_str(s).map_err(ConfigError::PathParse)
21     }
22 }
23 
sindex_to_uindex(index: isize, len: usize) -> usize24 fn sindex_to_uindex(index: isize, len: usize) -> usize {
25     if index >= 0 {
26         index as usize
27     } else {
28         len - (index.abs() as usize)
29     }
30 }
31 
32 impl Expression {
get(self, root: &Value) -> Option<&Value>33     pub fn get(self, root: &Value) -> Option<&Value> {
34         match self {
35             Self::Identifier(id) => {
36                 match root.kind {
37                     // `x` access on a table is equivalent to: map[x]
38                     ValueKind::Table(ref map) => map.get(&id),
39 
40                     // all other variants return None
41                     _ => None,
42                 }
43             }
44 
45             Self::Child(expr, key) => {
46                 match expr.get(root) {
47                     Some(value) => {
48                         match value.kind {
49                             // Access on a table is identical to Identifier, it just forwards
50                             ValueKind::Table(ref map) => map.get(&key),
51 
52                             // all other variants return None
53                             _ => None,
54                         }
55                     }
56 
57                     _ => None,
58                 }
59             }
60 
61             Self::Subscript(expr, index) => match expr.get(root) {
62                 Some(value) => match value.kind {
63                     ValueKind::Array(ref array) => {
64                         let index = sindex_to_uindex(index, array.len());
65 
66                         if index >= array.len() {
67                             None
68                         } else {
69                             Some(&array[index])
70                         }
71                     }
72 
73                     _ => None,
74                 },
75 
76                 _ => None,
77             },
78         }
79     }
80 
get_mut<'a>(&self, root: &'a mut Value) -> Option<&'a mut Value>81     pub fn get_mut<'a>(&self, root: &'a mut Value) -> Option<&'a mut Value> {
82         match *self {
83             Self::Identifier(ref id) => match root.kind {
84                 ValueKind::Table(ref mut map) => map.get_mut(id),
85 
86                 _ => None,
87             },
88 
89             Self::Child(ref expr, ref key) => match expr.get_mut(root) {
90                 Some(value) => match value.kind {
91                     ValueKind::Table(ref mut map) => map.get_mut(key),
92 
93                     _ => None,
94                 },
95 
96                 _ => None,
97             },
98 
99             Self::Subscript(ref expr, index) => match expr.get_mut(root) {
100                 Some(value) => match value.kind {
101                     ValueKind::Array(ref mut array) => {
102                         let index = sindex_to_uindex(index, array.len());
103 
104                         if index >= array.len() {
105                             None
106                         } else {
107                             Some(&mut array[index])
108                         }
109                     }
110 
111                     _ => None,
112                 },
113 
114                 _ => None,
115             },
116         }
117     }
118 
get_mut_forcibly<'a>(&self, root: &'a mut Value) -> Option<&'a mut Value>119     pub fn get_mut_forcibly<'a>(&self, root: &'a mut Value) -> Option<&'a mut Value> {
120         match *self {
121             Self::Identifier(ref id) => match root.kind {
122                 ValueKind::Table(ref mut map) => Some(
123                     map.entry(id.clone())
124                         .or_insert_with(|| Value::new(None, ValueKind::Nil)),
125                 ),
126 
127                 _ => None,
128             },
129 
130             Self::Child(ref expr, ref key) => match expr.get_mut_forcibly(root) {
131                 Some(value) => {
132                     if let ValueKind::Table(ref mut map) = value.kind {
133                         Some(
134                             map.entry(key.clone())
135                                 .or_insert_with(|| Value::new(None, ValueKind::Nil)),
136                         )
137                     } else {
138                         *value = Map::<String, Value>::new().into();
139 
140                         if let ValueKind::Table(ref mut map) = value.kind {
141                             Some(
142                                 map.entry(key.clone())
143                                     .or_insert_with(|| Value::new(None, ValueKind::Nil)),
144                             )
145                         } else {
146                             unreachable!();
147                         }
148                     }
149                 }
150 
151                 _ => None,
152             },
153 
154             Self::Subscript(ref expr, index) => match expr.get_mut_forcibly(root) {
155                 Some(value) => {
156                     match value.kind {
157                         ValueKind::Array(_) => (),
158                         _ => *value = Vec::<Value>::new().into(),
159                     }
160 
161                     match value.kind {
162                         ValueKind::Array(ref mut array) => {
163                             let index = sindex_to_uindex(index, array.len());
164 
165                             if index >= array.len() {
166                                 array
167                                     .resize((index + 1) as usize, Value::new(None, ValueKind::Nil));
168                             }
169 
170                             Some(&mut array[index])
171                         }
172 
173                         _ => None,
174                     }
175                 }
176                 _ => None,
177             },
178         }
179     }
180 
set(&self, root: &mut Value, value: Value)181     pub fn set(&self, root: &mut Value, value: Value) {
182         match *self {
183             Self::Identifier(ref id) => {
184                 // Ensure that root is a table
185                 match root.kind {
186                     ValueKind::Table(_) => {}
187 
188                     _ => {
189                         *root = Map::<String, Value>::new().into();
190                     }
191                 }
192 
193                 match value.kind {
194                     ValueKind::Table(ref incoming_map) => {
195                         // Pull out another table
196                         let target = if let ValueKind::Table(ref mut map) = root.kind {
197                             map.entry(id.clone())
198                                 .or_insert_with(|| Map::<String, Value>::new().into())
199                         } else {
200                             unreachable!();
201                         };
202 
203                         // Continue the deep merge
204                         for (key, val) in incoming_map {
205                             Self::Identifier(key.clone()).set(target, val.clone());
206                         }
207                     }
208 
209                     _ => {
210                         if let ValueKind::Table(ref mut map) = root.kind {
211                             // Just do a simple set
212                             if let Some(existing) = map.get_mut(id) {
213                                 *existing = value;
214                             } else {
215                                 map.insert(id.clone(), value);
216                             }
217                         }
218                     }
219                 }
220             }
221 
222             Self::Child(ref expr, ref key) => {
223                 if let Some(parent) = expr.get_mut_forcibly(root) {
224                     if !matches!(parent.kind, ValueKind::Table(_)) {
225                         // Didn't find a table. Oh well. Make a table and do this anyway
226                         *parent = Map::<String, Value>::new().into();
227                     }
228                     Self::Identifier(key.clone()).set(parent, value);
229                 }
230             }
231 
232             Self::Subscript(ref expr, index) => {
233                 if let Some(parent) = expr.get_mut_forcibly(root) {
234                     if !matches!(parent.kind, ValueKind::Array(_)) {
235                         *parent = Vec::<Value>::new().into()
236                     }
237 
238                     if let ValueKind::Array(ref mut array) = parent.kind {
239                         let uindex = sindex_to_uindex(index, array.len());
240                         if uindex >= array.len() {
241                             array.resize((uindex + 1) as usize, Value::new(None, ValueKind::Nil));
242                         }
243 
244                         array[uindex] = value;
245                     }
246                 }
247             }
248         }
249     }
250 }
251