1use serde_yaml::{Mapping, Value};
2use std::borrow::{Borrow, Cow};
3use std::collections::VecDeque;
4use std::io::Read;
5
6#[derive(Debug)]
7pub enum Error {
8 IO(std::io::Error),
9 SerDe(serde_yaml::Error),
10 UTF8(std::str::Utf8Error),
11 ParseInt(std::num::ParseIntError),
12 ParseError,
13 InvalidEscapeSequence,
14 MissingArgument,
15 MissingConfigValue(String),
16}
17impl From<std::io::Error> for Error {
18 fn from(e: std::io::Error) -> Self {
19 Error::IO(e)
20 }
21}
22impl From<std::str::Utf8Error> for Error {
23 fn from(e: std::str::Utf8Error) -> Self {
24 Error::UTF8(e)
25 }
26}
27impl From<std::num::ParseIntError> for Error {
28 fn from(e: std::num::ParseIntError) -> Self {
29 Error::ParseInt(e)
30 }
31}
32impl From<serde_yaml::Error> for Error {
33 fn from(e: serde_yaml::Error) -> Self {
34 Error::SerDe(e)
35 }
36}
37impl std::fmt::Display for Error {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 write!(f, "{:?}", self)
40 }
41}
42impl std::error::Error for Error {}
43
44#[derive(Debug, Clone)]
45pub struct EscapePattern<'a>(pub Cow<'a, [u8]>, pub Cow<'a, [u8]>);
46impl Default for EscapePattern<'static> {
47 fn default() -> Self {
48 EscapePattern(b"{{"[..].into(), b"}}"[..].into())
49 }
50}
51impl<'a> std::str::FromStr for EscapePattern<'a> {
52 type Err = Error;
53
54 fn from_str(s: &str) -> Result<Self, Self::Err> {
55 let mut split = s.split("var");
56 let res = EscapePattern(
57 split
58 .next()
59 .ok_or(Error::InvalidEscapeSequence)?
60 .as_bytes()
61 .to_owned()
62 .into(),
63 split
64 .next()
65 .ok_or(Error::InvalidEscapeSequence)?
66 .as_bytes()
67 .to_owned()
68 .into(),
69 );
70 if res.0 == res.1 {
71 Err(Error::InvalidEscapeSequence)
72 } else {
73 Ok(res)
74 }
75 }
76}
77impl<'a> std::fmt::Display for EscapePattern<'a> {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 write!(
80 f,
81 "{}var{}",
82 std::str::from_utf8(self.0.borrow()).unwrap(),
83 std::str::from_utf8(self.1.borrow()).unwrap(),
84 )
85 }
86}
87
88pub fn get_val_from_config_seq(seq: &[Value], key: &str) -> Option<Value> {
89 let mut seg_iter = key.splitn(2, ".");
90 let seg = seg_iter.next()?;
91 let val = seq.get(seg.parse::<usize>().ok()?)?;
92 match (val, seg_iter.next()) {
93 (Value::Mapping(m), Some(rest)) => get_val_from_config_map(&m, rest),
94 (Value::Sequence(s), Some(rest)) => get_val_from_config_seq(s.as_slice(), rest),
95 (Value::Null, _) => None,
96 (_, None) => Some(val.clone()),
97 _ => None,
98 }
99}
100
101pub fn get_val_from_config_map(map: &Mapping, key: &str) -> Option<Value> {
102 let mut seg_iter = key.splitn(2, ".");
103 let seg = seg_iter.next()?;
104 let val = map.get(&Value::String(seg.to_owned()))?;
105 match (val, seg_iter.next()) {
106 (Value::Mapping(m), Some(rest)) => get_val_from_config_map(&m, rest),
107 (Value::Sequence(s), Some(rest)) => get_val_from_config_seq(s.as_slice(), rest),
108 (Value::Null, _) => None,
109 (_, None) => Some(val.clone()),
110 _ => None,
111 }
112}
113
114pub fn set_val_in_config_seq(seq: &mut [Value], key: &str, value: Value) -> Option<()> {
115 let mut seg_iter = key.splitn(2, ".");
116 let seg = seg_iter.next()?;
117 let val = seq.get_mut(seg.parse::<usize>().ok()?)?;
118 match (val, seg_iter.next()) {
119 (Value::Mapping(m), Some(rest)) => set_val_in_config_map(m, rest, value),
120 (Value::Sequence(s), Some(rest)) => set_val_in_config_seq(s.as_mut_slice(), rest, value),
121 (val, None) => {
122 *val = value;
123 Some(())
124 }
125 _ => None,
126 }
127}
128
129pub fn set_val_in_config_map(map: &mut Mapping, key: &str, value: Value) -> Option<()> {
130 let mut seg_iter = key.splitn(2, ".");
131 let seg = seg_iter.next()?;
132 let val = map.get_mut(&Value::String(seg.to_owned()))?;
133 match (val, seg_iter.next()) {
134 (Value::Mapping(m), Some(rest)) => set_val_in_config_map(m, rest, value),
135 (Value::Sequence(s), Some(rest)) => set_val_in_config_seq(s.as_mut_slice(), rest, value),
136 (val, None) => {
137 *val = value;
138 Some(())
139 }
140 _ => None,
141 }
142}
143
144pub fn val_to_string(val: Value) -> String {
145 match val {
146 Value::Bool(b) => format!("{}", b),
147 Value::Mapping(_) => "{map}".to_owned(),
148 Value::Null => "null".to_owned(),
149 Value::Number(n) => format!("{}", n),
150 Value::Sequence(_) => "[list]".to_owned(),
151 Value::String(s) => s,
152 }
153}
154
155pub fn val_is_truthy(val: &Value) -> bool {
156 match val {
157 Value::Bool(false) => false,
158 Value::Null => false,
159 _ => true,
160 }
161}
162
163pub fn eval(
179 map: &Mapping,
180 expr: &str,
181 escape: &EscapePattern,
182 unescape: u8,
183) -> Result<String, Error> {
184 let trimmed = expr.trim_start();
185 if trimmed.starts_with("#IF ") {
186 let mut split = trimmed[4..].splitn(2, "\n");
187 let expr = split.next().ok_or_else(|| Error::ParseError)?.trim();
188 let rest = split.next().ok_or_else(|| Error::ParseError)?;
189 if expr.contains("!=") {
190 let mut split = expr.splitn(2, "!=");
191 let if_var = split.next().ok_or_else(|| Error::ParseError)?.trim();
192 let target = split.next().ok_or_else(|| Error::ParseError)?.trim();
193 match get_val_from_config_map(map, if_var) {
194 Some(Value::String(ref s)) => {
195 if !target.starts_with("\"") || !target.ends_with("\"") {
196 eprintln!("{}", target);
197 return Err(Error::ParseError);
198 }
199 if format!("{:?}", s) != target {
200 let mut ret = String::new();
201 TemplatingReader::new(
202 std::io::Cursor::new(rest.as_bytes()),
203 map,
204 escape,
205 unescape,
206 )
207 .read_to_string(&mut ret)?;
208 Ok(ret)
209 } else {
210 Ok("".to_owned())
211 }
212 }
213 Some(Value::Number(n)) => {
214 if format!("{}", n) != target {
215 let mut ret = String::new();
216 TemplatingReader::new(
217 std::io::Cursor::new(rest.as_bytes()),
218 map,
219 escape,
220 unescape,
221 )
222 .read_to_string(&mut ret)?;
223 Ok(ret)
224 } else {
225 Ok("".to_owned())
226 }
227 }
228 _ => Ok("".to_owned()),
229 }
230 } else if expr.contains("=") {
231 let mut split = expr.splitn(2, "=");
232 let if_var = split.next().ok_or_else(|| Error::ParseError)?.trim();
233 let target = split.next().ok_or_else(|| Error::ParseError)?.trim();
234 match get_val_from_config_map(map, if_var) {
235 Some(Value::String(ref s)) => {
236 if !target.starts_with("\"") || !target.ends_with("\"") {
237 eprintln!("{}", target);
238 return Err(Error::ParseError);
239 }
240 if format!("{:?}", s) == target {
241 let mut ret = String::new();
242 TemplatingReader::new(
243 std::io::Cursor::new(rest.as_bytes()),
244 map,
245 escape,
246 unescape,
247 )
248 .read_to_string(&mut ret)?;
249 Ok(ret)
250 } else {
251 Ok("".to_owned())
252 }
253 }
254 Some(Value::Number(n)) => {
255 if format!("{}", n) == target {
256 let mut ret = String::new();
257 TemplatingReader::new(
258 std::io::Cursor::new(rest.as_bytes()),
259 map,
260 escape,
261 unescape,
262 )
263 .read_to_string(&mut ret)?;
264 Ok(ret)
265 } else {
266 Ok("".to_owned())
267 }
268 }
269 _ => Ok("".to_owned()),
270 }
271 } else if expr.starts_with("!") {
272 let if_var = &expr[1..];
273 if !get_val_from_config_map(map, if_var)
274 .map(|a| val_is_truthy(&a))
275 .unwrap_or(false)
276 {
277 let mut ret = String::new();
278 TemplatingReader::new(std::io::Cursor::new(rest.as_bytes()), map, escape, unescape)
279 .read_to_string(&mut ret)?;
280 Ok(ret)
281 } else {
282 Ok("".to_owned())
283 }
284 } else {
285 let if_var = expr;
286 if get_val_from_config_map(map, if_var)
287 .map(|a| val_is_truthy(&a))
288 .unwrap_or(false)
289 {
290 let mut ret = String::new();
291 TemplatingReader::new(std::io::Cursor::new(rest.as_bytes()), map, escape, unescape)
292 .read_to_string(&mut ret)?;
293 Ok(ret)
294 } else {
295 Ok("".to_owned())
296 }
297 }
298 } else if trimmed.starts_with("#FOREACH ") {
299 let mut split = trimmed[9..].splitn(2, "\n");
300 let for_var = split.next().ok_or_else(|| Error::ParseError)?.trim();
301 let rest = split.next().ok_or_else(|| Error::ParseError)?;
302 match get_val_from_config_map(map, for_var) {
303 Some(Value::Sequence(s)) => {
304 let mut ret = String::new();
305 let mut new_map = map.clone();
306 for item in s {
307 set_val_in_config_map(&mut new_map, for_var, item)
308 .ok_or_else(|| Error::MissingConfigValue(for_var.to_owned()))?;
309 TemplatingReader::new(
310 std::io::Cursor::new(rest.as_bytes()),
311 &new_map,
312 escape,
313 unescape,
314 )
315 .read_to_string(&mut ret)?;
316 }
317 Ok(ret)
318 }
319 Some(ref a) if val_is_truthy(a) => {
320 let mut ret = String::new();
321 TemplatingReader::new(std::io::Cursor::new(rest.as_bytes()), map, escape, unescape)
322 .read_to_string(&mut ret)?;
323 Ok(ret)
324 }
325 _ => Ok("".to_owned()),
326 }
327 } else {
328 get_val_from_config_map(map, trimmed)
329 .map(val_to_string)
330 .ok_or_else(|| Error::MissingConfigValue(trimmed.to_owned()))
331 }
332}
333
334#[derive(Debug)]
335pub struct TemplatingReader<'a, 'b, 'c, R: Read> {
336 inner: R,
337 mapping: &'a Mapping,
338 escape: &'b EscapePattern<'c>,
339 unescape: u8,
340 unescapable: bool,
341 count_start: usize,
342 count_end: usize,
343 depth: usize,
344 var: Vec<u8>,
345 buf: VecDeque<u8>,
346}
347impl<'a, 'b, 'c, R> TemplatingReader<'a, 'b, 'c, R>
348where
349 R: Read,
350{
351 pub fn new(
352 reader: R,
353 mapping: &'a Mapping,
354 escape: &'b EscapePattern<'c>,
355 unescape: u8,
356 ) -> Self {
357 TemplatingReader {
358 inner: reader,
359 mapping,
360 escape,
361 unescape,
362 unescapable: false,
363 count_start: 0,
364 count_end: 0,
365 depth: 0,
366 var: Vec::new(),
367 buf: VecDeque::new(),
368 }
369 }
370}
371
372fn to_io_error<E: std::error::Error + Send + Sync + 'static>(e: E) -> std::io::Error {
373 std::io::Error::new(std::io::ErrorKind::Other, e)
374}
375
376impl<'a, 'b, 'c, R> Read for TemplatingReader<'a, 'b, 'c, R>
377where
378 R: Read,
379{
380 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
381 let mut written = 0;
382 while written == 0 {
383 let in_bytes = self.inner.read(buf)?;
384 for byte in &buf[..in_bytes] {
385 let mut write_byte = true;
386 let byte_arr = [];
387 let mut to_extend: &[u8] = &byte_arr;
388 if self.unescapable && byte == &self.unescape {
389 self.depth -= 1;
390 self.count_start = 0;
391 to_extend = &*self.escape.0;
392 write_byte = false;
393 }
394 self.unescapable = false;
395 if byte == &self.escape.0[self.count_start] {
396 self.count_start += 1;
397 if self.depth == 0 {
398 write_byte = false;
399 }
400 } else if self.count_start != 0 {
401 to_extend = &self.escape.0[..self.count_start];
402 self.count_start = 0;
403 }
404 if self.depth > 0 && byte == &self.escape.1[self.count_end] {
405 self.count_end += 1;
406 if self.depth == 1 {
407 write_byte = false;
408 }
409 } else if self.count_end != 0 {
410 to_extend = &self.escape.1[..self.count_end];
411 self.count_end = 0;
412 }
413 if self.count_start == self.escape.0.len() {
414 self.depth += 1;
415 self.count_start = 0;
416 self.unescapable = true;
417 }
418 if self.count_end == self.escape.0.len() {
419 self.depth -= 1;
420 self.count_end = 0;
421 if self.depth == 0 {
422 self.buf.extend(
423 eval(
424 self.mapping,
425 std::str::from_utf8(&self.var).map_err(to_io_error)?,
426 self.escape,
427 self.unescape,
428 )
429 .map_err(to_io_error)?
430 .as_bytes(),
431 );
432 self.var.clear();
433 }
434 }
435 if self.depth == 0 {
436 self.buf.extend(to_extend);
437 if write_byte {
438 self.buf.push_back(*byte);
439 }
440 } else {
441 self.var.extend_from_slice(to_extend);
442 if write_byte {
443 self.var.push(*byte);
444 }
445 }
446 }
447 written = std::cmp::min(buf.len(), self.buf.len());
448 for (i, elem) in self.buf.drain(0..written).enumerate() {
449 buf[i] = elem;
450 }
451 if in_bytes == 0 {
452 break;
453 }
454 }
455 Ok(written)
456 }
457}