Skip to content

Commit b509e7e

Browse files
authored
Merge pull request #622 from epage/path
refactor(path): Switch from recursive to iterative structures
2 parents fdef5c5 + 80ca240 commit b509e7e

File tree

3 files changed

+174
-202
lines changed

3 files changed

+174
-202
lines changed

src/path/mod.rs

Lines changed: 89 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@ use crate::value::{Value, ValueKind};
77
mod parser;
88

99
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
10-
pub(crate) enum Expression {
11-
Identifier(String),
12-
Child(Box<Self>, String),
13-
Subscript(Box<Self>, isize),
10+
pub(crate) struct Expression {
11+
root: String,
12+
postfix: Vec<Postfix>,
13+
}
14+
15+
impl Expression {
16+
pub(crate) fn root(root: String) -> Self {
17+
Self {
18+
root,
19+
postfix: Vec::new(),
20+
}
21+
}
1422
}
1523

1624
impl FromStr for Expression {
@@ -23,6 +31,12 @@ impl FromStr for Expression {
2331
}
2432
}
2533

34+
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
35+
enum Postfix {
36+
Key(String),
37+
Index(isize),
38+
}
39+
2640
#[derive(Debug)]
2741
struct ParseError(String);
2842

@@ -53,186 +67,97 @@ fn abs_index(index: isize, len: usize) -> Result<usize, usize> {
5367

5468
impl Expression {
5569
pub(crate) fn get(self, root: &Value) -> Option<&Value> {
56-
match self {
57-
Self::Identifier(id) => {
58-
match root.kind {
59-
// `x` access on a table is equivalent to: map[x]
60-
ValueKind::Table(ref map) => map.get(&id),
61-
62-
// all other variants return None
63-
_ => None,
70+
let ValueKind::Table(map) = &root.kind else {
71+
return None;
72+
};
73+
let mut child = map.get(&self.root)?;
74+
for postfix in &self.postfix {
75+
match postfix {
76+
Postfix::Key(key) => {
77+
let ValueKind::Table(map) = &child.kind else {
78+
return None;
79+
};
80+
child = map.get(key)?;
6481
}
65-
}
66-
67-
Self::Child(expr, key) => {
68-
match expr.get(root) {
69-
Some(value) => {
70-
match value.kind {
71-
// Access on a table is identical to Identifier, it just forwards
72-
ValueKind::Table(ref map) => map.get(&key),
73-
74-
// all other variants return None
75-
_ => None,
76-
}
77-
}
78-
79-
_ => None,
82+
Postfix::Index(rel_index) => {
83+
let ValueKind::Array(array) = &child.kind else {
84+
return None;
85+
};
86+
let index = abs_index(*rel_index, array.len()).ok()?;
87+
child = array.get(index)?;
8088
}
8189
}
82-
83-
Self::Subscript(expr, index) => match expr.get(root) {
84-
Some(value) => match value.kind {
85-
ValueKind::Array(ref array) => {
86-
let index = abs_index(index, array.len()).ok()?;
87-
array.get(index)
88-
}
89-
90-
_ => None,
91-
},
92-
93-
_ => None,
94-
},
9590
}
91+
Some(child)
9692
}
9793

98-
pub(crate) fn get_mut_forcibly<'a>(&self, root: &'a mut Value) -> Option<&'a mut Value> {
99-
match *self {
100-
Self::Identifier(ref id) => match root.kind {
101-
ValueKind::Table(ref mut map) => Some(
102-
map.entry(id.clone())
103-
.or_insert_with(|| Value::new(None, ValueKind::Nil)),
104-
),
105-
106-
_ => None,
107-
},
108-
109-
Self::Child(ref expr, ref key) => match expr.get_mut_forcibly(root) {
110-
Some(value) => {
111-
if let ValueKind::Table(ref mut map) = value.kind {
112-
Some(
113-
map.entry(key.clone())
114-
.or_insert_with(|| Value::new(None, ValueKind::Nil)),
115-
)
116-
} else {
117-
*value = Map::<String, Value>::new().into();
118-
119-
if let ValueKind::Table(ref mut map) = value.kind {
120-
Some(
121-
map.entry(key.clone())
122-
.or_insert_with(|| Value::new(None, ValueKind::Nil)),
123-
)
124-
} else {
125-
unreachable!();
126-
}
94+
pub(crate) fn get_mut_forcibly<'a>(&self, root: &'a mut Value) -> &'a mut Value {
95+
if !matches!(root.kind, ValueKind::Table(_)) {
96+
*root = Map::<String, Value>::new().into();
97+
}
98+
let ValueKind::Table(map) = &mut root.kind else {
99+
unreachable!()
100+
};
101+
let mut child = map
102+
.entry(self.root.clone())
103+
.or_insert_with(|| Value::new(None, ValueKind::Nil));
104+
for postfix in &self.postfix {
105+
match postfix {
106+
Postfix::Key(key) => {
107+
if !matches!(child.kind, ValueKind::Table(_)) {
108+
*child = Map::<String, Value>::new().into();
127109
}
128-
}
129-
130-
_ => None,
131-
},
110+
let ValueKind::Table(ref mut map) = child.kind else {
111+
unreachable!()
112+
};
132113

133-
Self::Subscript(ref expr, index) => match expr.get_mut_forcibly(root) {
134-
Some(value) => {
135-
match value.kind {
136-
ValueKind::Array(_) => (),
137-
_ => *value = Vec::<Value>::new().into(),
114+
child = map
115+
.entry(key.clone())
116+
.or_insert_with(|| Value::new(None, ValueKind::Nil));
117+
}
118+
Postfix::Index(rel_index) => {
119+
if !matches!(child.kind, ValueKind::Array(_)) {
120+
*child = Vec::<Value>::new().into();
138121
}
139-
140-
match value.kind {
141-
ValueKind::Array(ref mut array) => {
142-
let index = abs_index(index, array.len()).ok()?;
143-
144-
if index >= array.len() {
145-
array.resize(index + 1, Value::new(None, ValueKind::Nil));
122+
let ValueKind::Array(ref mut array) = child.kind else {
123+
unreachable!()
124+
};
125+
126+
let uindex = match abs_index(*rel_index, array.len()) {
127+
Ok(uindex) => {
128+
if uindex >= array.len() {
129+
array.resize(uindex + 1, Value::new(None, ValueKind::Nil));
146130
}
147-
148-
Some(&mut array[index])
131+
uindex
132+
}
133+
Err(insertion) => {
134+
array.splice(
135+
0..0,
136+
(0..insertion).map(|_| Value::new(None, ValueKind::Nil)),
137+
);
138+
0
149139
}
140+
};
150141

151-
_ => None,
152-
}
142+
child = &mut array[uindex];
153143
}
154-
_ => None,
155-
},
144+
}
156145
}
146+
child
157147
}
158148

159149
pub(crate) fn set(&self, root: &mut Value, value: Value) {
160-
match *self {
161-
Self::Identifier(ref id) => {
162-
// Ensure that root is a table
163-
match root.kind {
164-
ValueKind::Table(_) => {}
165-
166-
_ => {
167-
*root = Map::<String, Value>::new().into();
168-
}
169-
}
170-
171-
match value.kind {
172-
ValueKind::Table(ref incoming_map) => {
173-
// Pull out another table
174-
let target = if let ValueKind::Table(ref mut map) = root.kind {
175-
map.entry(id.clone())
176-
.or_insert_with(|| Map::<String, Value>::new().into())
177-
} else {
178-
unreachable!();
179-
};
180-
181-
// Continue the deep merge
182-
for (key, val) in incoming_map {
183-
Self::Identifier(key.clone()).set(target, val.clone());
184-
}
185-
}
186-
187-
_ => {
188-
if let ValueKind::Table(ref mut map) = root.kind {
189-
// Just do a simple set
190-
if let Some(existing) = map.get_mut(id) {
191-
*existing = value;
192-
} else {
193-
map.insert(id.clone(), value);
194-
}
195-
}
196-
}
197-
}
198-
}
199-
200-
Self::Child(ref expr, ref key) => {
201-
if let Some(parent) = expr.get_mut_forcibly(root) {
202-
if !matches!(parent.kind, ValueKind::Table(_)) {
203-
// Didn't find a table. Oh well. Make a table and do this anyway
204-
*parent = Map::<String, Value>::new().into();
205-
}
206-
Self::Identifier(key.clone()).set(parent, value);
150+
let parent = self.get_mut_forcibly(root);
151+
match value.kind {
152+
ValueKind::Table(ref incoming_map) => {
153+
// Continue the deep merge
154+
for (key, val) in incoming_map {
155+
Self::root(key.clone()).set(parent, val.clone());
207156
}
208157
}
209158

210-
Self::Subscript(ref expr, index) => {
211-
if let Some(parent) = expr.get_mut_forcibly(root) {
212-
if !matches!(parent.kind, ValueKind::Array(_)) {
213-
*parent = Vec::<Value>::new().into();
214-
}
215-
216-
if let ValueKind::Array(ref mut array) = parent.kind {
217-
let uindex = match abs_index(index, array.len()) {
218-
Ok(uindex) => {
219-
if uindex >= array.len() {
220-
array.resize(uindex + 1, Value::new(None, ValueKind::Nil));
221-
}
222-
uindex
223-
}
224-
Err(insertion) => {
225-
array.splice(
226-
0..0,
227-
(0..insertion).map(|_| Value::new(None, ValueKind::Nil)),
228-
);
229-
0
230-
}
231-
};
232-
233-
array[uindex] = value;
234-
}
235-
}
159+
_ => {
160+
*parent = value;
236161
}
237162
}
238163
}

0 commit comments

Comments
 (0)