dapt/path/
node.rs

1use core::slice;
2use std::fmt;
3
4use crate::binary::{
5    BArray, BKeyValue, BMap, BReference, Binary, TYPE_ARRAY, TYPE_KEYVAL, TYPE_MAP,
6};
7use crate::error::DaptResult;
8use crate::{Error, Path};
9
10use super::parser::Node;
11
12// Aquireable allows you to ask for that token, and if it doesn't exist we will
13// create it. The aquire function should only ever create a sinle entity within
14// the document, since you can only return a single breference.
15pub trait Aquireable {
16    fn aquire(&self, bin: &mut Binary, b: BReference) -> DaptResult<BKeyValue>;
17}
18
19// Node is the type that a parser puts out. each
20// node should implement the trait functions below
21pub trait Discoverable {
22    fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
23    where
24        F: FnMut(BReference);
25}
26
27#[derive(Debug, PartialEq, Clone)]
28pub struct FieldLiteral {
29    name: String,
30}
31
32// FieldLiteral is an actual field name in the dapt packet. These can be
33// chained together with `.` in order to create a path. For instance
34// `log.level` would be two field literals, which point to the json structure
35// `{"log": {"level": "info"}}`. Anything that is not interpreted as a different
36// type is considered a field literal. Special characters can be escaped by wrapping
37// the field name in double quotes. For instance `"log.level"` would be a single
38// field literal that points to the json structure `{"log.level": "info"}`.
39impl FieldLiteral {
40    pub fn new(name: &str) -> FieldLiteral {
41        FieldLiteral {
42            name: name.to_string(),
43        }
44    }
45
46    pub fn from_escaped(name: &str) -> FieldLiteral {
47        // name is a string which optionally is wrapped in double quotes.
48        // here we remove the double quotes if they exist and remove any
49        // escape characters.
50        let mut c = name.chars().peekable();
51        let mut name = String::with_capacity(name.len());
52
53        while let Some(character) = c.next() {
54            match character {
55                '\\' => {
56                    // whatever comes after the escape should be...
57                    // escaped.
58                    if let Some(next) = c.next() {
59                        name.push(next);
60                    }
61                }
62                // consume any ", at this point we must believe we have a
63                // valid string since the lexer gave it to us
64                '"' => (),
65                _ => name.push(character),
66            }
67        }
68
69        FieldLiteral { name }
70    }
71}
72
73impl Discoverable for FieldLiteral {
74    // find returns a list of pointers to the
75    // child that matches the specified name.
76    fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
77    where
78        F: FnMut(BReference),
79    {
80        let n = match b.val_at(bin) {
81            Some(n) => n,
82            None => return,
83        };
84
85        match n.get_type(bin) {
86            TYPE_MAP => {
87                let bcoll = BMap::from(n);
88                if let Some(child_location) = bcoll.child_key(&self.name, bin) {
89                    f(child_location);
90                }
91            }
92            _ => (),
93        };
94    }
95}
96
97impl Aquireable for FieldLiteral {
98    fn aquire(&self, bin: &mut Binary, b: BReference) -> DaptResult<BKeyValue> {
99        let mut reg = None;
100        self.find(bin, b, &mut |x| reg = Some(x));
101
102        if reg.is_some() {
103            return Ok(reg
104                .unwrap()
105                .key_at(bin)
106                .ok_or_else(|| Error::CanNotAquire(format!("could not aquire {}", self)))?);
107        }
108
109        match b.token_at(bin) {
110            // in the event the breference is empty. This can happen on an empty
111            // dapt packet build, so we will set it to a map.
112            None => {
113                let (key_bref, bkv) = BKeyValue::new(None, BReference::from(0), &self.name, bin);
114                // create new map
115                let (map_bref, _) = BMap::new(Some(b), slice::from_ref(&key_bref), bin);
116                // set the index of the breference to the map
117                b.set_index(bin, *map_bref);
118                Ok(bkv)
119            }
120            // we have a token which is a map, we can add another keyvalue to it and move on
121            Some(tok) if tok.get_type(bin) == TYPE_MAP => {
122                let (key_bref, bkv) = BKeyValue::new(
123                    Some(tok.get_reference(bin)),
124                    BReference::from(0),
125                    &self.name,
126                    bin,
127                );
128
129                // get existing map and extend it
130                let bcoll = BMap::from(tok);
131                bcoll.add_child(key_bref, bin);
132
133                // return key value
134                Ok(bkv)
135            }
136            // we have found a keyValue, in which case we should check if it has
137            // a child and go deeper, or we should set the child value
138            Some(tok) if tok.get_type(bin) == TYPE_KEYVAL => {
139                let orig_bkv = BKeyValue::from(tok);
140                let child = orig_bkv.child(bin);
141
142                // the key has a value, so we should grab the child value and try to aquire that
143                if child.is_some() {
144                    return self.aquire(bin, child.unwrap());
145                }
146
147                let (key_bref, bkv) = BKeyValue::new(None, BReference::from(0), &self.name, bin);
148                // create new map
149                let (map_bref, _) = BMap::new(Some(b), slice::from_ref(&key_bref), bin);
150                // set the index of the breference to the map
151                orig_bkv.set_child(map_bref, bin);
152                Ok(bkv)
153            }
154            // this is a case we do not handle
155            Some(_) => Err("Cannot add a field to a non map type".into()),
156        }
157    }
158}
159
160impl fmt::Display for FieldLiteral {
161    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162        // if there is a . or a " in the name we need to wrap
163        // it in double quotes. We will wrap spaces in double
164        // quotes too, even though we don't have to.
165        if self.name.contains('.') || self.name.contains('"') || self.name.contains(' ') {
166            write!(f, "\"")?;
167            let c = self.name.chars();
168            for character in c {
169                match character {
170                    '"' => {
171                        write!(f, "\\\"")?;
172                    }
173                    _ => write!(f, "{}", character)?,
174                }
175            }
176            write!(f, "\"")
177        } else {
178            write!(f, "{}", self.name)
179        }
180    }
181}
182
183// The Array operator `[]` allows you to traverse arrays. When you
184// supply an index, like so `[1]`, it will select the specifie element
185// at the provided index. Dapt packets can point to multiple locations
186// in a document at once, which means supplying no index `[]` will point
187// to all elements in the array.
188#[derive(Debug, PartialEq, Clone)]
189pub struct Array {
190    index: Option<usize>,
191}
192
193impl Array {
194    pub fn new(index: Option<usize>) -> Array {
195        Array { index }
196    }
197}
198
199impl Discoverable for Array {
200    // find returns a list of pointers to the
201    // child that matches the specified name.
202    fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
203    where
204        F: FnMut(BReference),
205    {
206        let n = match b.val_at(bin) {
207            Some(n) => n,
208            None => return,
209        };
210
211        match n.get_type(bin) {
212            TYPE_ARRAY => {
213                let bcoll = BArray::from(n);
214                if let None = self.index {
215                    for i in 0..bcoll.length(bin) {
216                        // we know the child is there because we call for length
217                        // in the for loop
218                        f(bcoll.child_index(bin, i).unwrap());
219                    }
220                } else {
221                    if let Some(child_location) = bcoll.child_index(bin, self.index.unwrap()) {
222                        f(child_location);
223                    }
224                }
225            }
226            _ => (),
227        };
228    }
229}
230
231impl fmt::Display for Array {
232    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
233        match self.index {
234            Some(i) => write!(f, "[{}]", i),
235            None => write!(f, "[]"),
236        }
237    }
238}
239
240// Wildcard will select all the children within the map we are currently
241// in.
242#[derive(Debug, PartialEq, Clone)]
243pub struct Wildcard;
244
245impl Discoverable for Wildcard {
246    // find returns a list of pointers to the
247    // child that matches the specified name.
248    fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
249    where
250        F: FnMut(BReference),
251    {
252        let n = match b.val_at(bin) {
253            Some(n) => n,
254            None => return,
255        };
256
257        match n.get_type(bin) {
258            TYPE_MAP => {
259                let bcoll = BMap::from(n);
260                for i in 0..bcoll.length(bin) {
261                    // we know the child is there because we call for length
262                    // in the for loop
263                    f(bcoll.child_index(bin, i).unwrap());
264                }
265            }
266            _ => (),
267        };
268    }
269}
270
271impl fmt::Display for Wildcard {
272    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
273        write!(f, "*")
274    }
275}
276
277// recursive will traverse the tree until it finds the node that matches.
278// `~.message` would match the `message` field in the json structure
279// `{"something":{ "something-else": { "message": "hello" }}}`.
280#[derive(Debug, PartialEq, Clone)]
281pub struct Recursive {
282    child: Box<Node>,
283}
284
285impl Recursive {
286    pub fn new(child: Node) -> Recursive {
287        Recursive {
288            child: Box::new(child),
289        }
290    }
291}
292
293impl Discoverable for Recursive {
294    // find returns a list of pointers to the
295    // child that matches the specified name.
296    fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
297    where
298        F: FnMut(BReference),
299    {
300        b.walk(bin, &mut |childref| {
301            self.child.find(bin, childref, f);
302            true
303        });
304    }
305}
306
307impl fmt::Display for Recursive {
308    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
309        write!(f, "~.{}", self.child)
310    }
311}
312
313// First will find the first non empty value and return that.
314// `{~.message|~.error}` would match the `message` field in the json
315// structure `{"message": "hello"}` and the `error` field in the json
316// structure `{"error": "something went wrong"}`.
317#[derive(Debug, PartialEq, Clone)]
318pub struct First {
319    paths: Vec<Path>,
320}
321
322impl First {
323    pub fn new(paths: Vec<Path>) -> First {
324        First { paths }
325    }
326}
327
328impl Discoverable for First {
329    // find returns a list of pointers to the
330    // child that matches the specified name.
331    fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
332    where
333        F: FnMut(BReference),
334    {
335        for path in &self.paths {
336            let ptrs = path.find_simple(bin, b);
337            match ptrs.get(0) {
338                Some(p) => {
339                    f(*p);
340                    return;
341                }
342                None => (),
343            }
344        }
345    }
346}
347
348impl fmt::Display for First {
349    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
350        write!(f, "{{")?;
351
352        for (x, path) in self.paths.iter().enumerate() {
353            if x > 0 {
354                write!(f, ",")?;
355            }
356            write!(f, "{}", path)?;
357        }
358
359        write!(f, "}}")?;
360        Ok(())
361    }
362}
363
364// Multi works much like first, but will match on all the values
365// that are not empty. example `(~.message,~.error)` would match
366// both fields in the json structure:
367// `{"message": "hello", "error": "something went wrong"}`.
368#[derive(Debug, PartialEq, Clone)]
369pub struct Multi {
370    paths: Vec<Path>,
371}
372
373impl Multi {
374    pub fn new(paths: Vec<Path>) -> Multi {
375        Multi { paths }
376    }
377}
378
379impl Discoverable for Multi {
380    // find returns a list of pointers to the
381    // child that matches the specified name.
382    fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
383    where
384        F: FnMut(BReference),
385    {
386        for path in &self.paths {
387            path.find_simple(bin, b).iter().for_each(|p| f(*p));
388        }
389    }
390}
391
392impl fmt::Display for Multi {
393    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394        write!(f, "(")?;
395
396        for (x, path) in self.paths.iter().enumerate() {
397            if x > 0 {
398                write!(f, "|")?;
399            }
400            write!(f, "{}", path)?;
401        }
402
403        write!(f, ")")?;
404        Ok(())
405    }
406}
407
408#[derive(Debug, Clone)]
409pub struct Regexp {
410    name: regex::Regex,
411}
412
413impl Regexp {
414    pub fn new(name: &str) -> Regexp {
415        // name is a string which optionally is wrapped in double quotes.
416        // here we remove the double quotes if they exist and remove any
417        // escape characters.
418        Regexp {
419            name: regex::Regex::new(name).unwrap(),
420        }
421    }
422}
423
424impl PartialEq for Regexp {
425    fn eq(&self, other: &Self) -> bool {
426        self.name.as_str() == other.name.as_str()
427    }
428}
429
430impl Discoverable for Regexp {
431    // find returns a list of pointers to the
432    // child that matches the specified name.
433    fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
434    where
435        F: FnMut(BReference),
436    {
437        let n = match b.val_at(bin) {
438            Some(n) => n,
439            None => return,
440        };
441
442        match n.get_type(bin) {
443            TYPE_MAP => {
444                let bcoll = BMap::from(n);
445                for i in 0..bcoll.length(bin) {
446                    // we know we can unwrap because of the length in the for
447                    // loop and because a valid bMap will only have key children
448                    let child = bcoll.child_index(bin, i).unwrap();
449                    if self.name.is_match(child.key_at(bin).unwrap().key(bin)) {
450                        f(child);
451                    }
452                }
453            }
454            _ => (),
455        };
456    }
457}
458
459impl fmt::Display for Regexp {
460    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
461        // if there is a . or a " in the name we need to wrap
462        // it in double quotes. We will wrap spaces in double
463        // quotes too, even though we don't have to.
464        write!(f, "/{}/", self.name)
465    }
466}