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