1use std::str::FromStr;
2
3use crate::error::{ConfigError, Result};
4use crate::map::Map;
5use crate::value::{Value, ValueKind};
6
7mod parser;
8
9#[derive(Debug, Eq, PartialEq, Clone, Hash)]
10pub(crate) struct Expression {
11 root: String,
12 postfix: Vec<Postfix>,
13}
14
15impl Expression {
16 pub(crate) fn root(root: String) -> Self {
17 Self {
18 root,
19 postfix: Vec::new(),
20 }
21 }
22}
23
24impl FromStr for Expression {
25 type Err = ConfigError;
26
27 fn from_str(s: &str) -> Result<Self> {
28 parser::from_str(s).map_err(|e| ConfigError::PathParse {
29 cause: Box::new(ParseError::new(e)),
30 })
31 }
32}
33
34#[derive(Debug, Eq, PartialEq, Clone, Hash)]
35enum Postfix {
36 Key(String),
37 Index(isize),
38}
39
40#[derive(Debug)]
41struct ParseError(String);
42
43impl ParseError {
44 fn new(inner: winnow::error::ParseError<&str, winnow::error::ContextError>) -> Self {
45 Self(inner.to_string())
46 }
47}
48
49impl std::fmt::Display for ParseError {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 self.0.fmt(f)
52 }
53}
54
55impl std::error::Error for ParseError {}
56
57fn abs_index(index: isize, len: usize) -> Result<usize, usize> {
59 if index >= 0 {
60 Ok(index as usize)
61 } else if let Some(index) = len.checked_sub(index.unsigned_abs()) {
62 Ok(index)
63 } else {
64 Err((len as isize + index).unsigned_abs())
65 }
66}
67
68impl Expression {
69 pub(crate) fn get(self, root: &Value) -> Option<&Value> {
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)?;
81 }
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)?;
88 }
89 }
90 }
91 Some(child)
92 }
93
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();
109 }
110 let ValueKind::Table(ref mut map) = child.kind else {
111 unreachable!()
112 };
113
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();
121 }
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));
130 }
131 uindex
132 }
133 Err(insertion) => {
134 array.splice(
135 0..0,
136 (0..insertion).map(|_| Value::new(None, ValueKind::Nil)),
137 );
138 0
139 }
140 };
141
142 child = &mut array[uindex];
143 }
144 }
145 }
146 child
147 }
148
149 pub(crate) fn set(&self, root: &mut Value, value: Value) {
150 let parent = self.get_mut_forcibly(root);
151 match value.kind {
152 ValueKind::Table(ref incoming_map) => {
153 if !matches!(parent.kind, ValueKind::Table(_)) {
156 *parent = Map::<String, Value>::new().into();
157 }
158
159 for (key, val) in incoming_map {
161 Self::root(key.clone()).set(parent, val.clone());
162 }
163 }
164 _ => {
165 *parent = value;
166 }
167 }
168 }
169}