wirefilter/
scheme.rs

1use ast::FilterAst;
2use failure::Fail;
3use fnv::FnvBuildHasher;
4use indexmap::map::{Entry, IndexMap};
5use lex::{complete, expect, span, take_while, LexErrorKind, LexResult, LexWith};
6use serde::{Deserialize, Serialize, Serializer};
7use std::{
8    cmp::{max, min},
9    error::Error,
10    fmt::{self, Debug, Display, Formatter},
11    ptr,
12};
13use types::{GetType, Type};
14
15#[derive(PartialEq, Eq, Clone, Copy)]
16pub(crate) struct Field<'s> {
17    scheme: &'s Scheme,
18    index: usize,
19}
20
21impl<'s> Serialize for Field<'s> {
22    fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
23        self.name().serialize(ser)
24    }
25}
26
27impl<'s> Debug for Field<'s> {
28    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
29        write!(f, "{}", self.name())
30    }
31}
32
33impl<'i, 's> LexWith<'i, &'s Scheme> for Field<'s> {
34    fn lex_with(mut input: &'i str, scheme: &'s Scheme) -> LexResult<'i, Self> {
35        let initial_input = input;
36
37        loop {
38            input = take_while(input, "identifier character", |c| {
39                c.is_ascii_alphanumeric() || c == '_'
40            })?
41            .1;
42
43            match expect(input, ".") {
44                Ok(rest) => input = rest,
45                Err(_) => break,
46            };
47        }
48
49        let name = span(initial_input, input);
50
51        let field = scheme
52            .get_field_index(name)
53            .map_err(|err| (LexErrorKind::UnknownField(err), name))?;
54
55        Ok((field, input))
56    }
57}
58
59impl<'s> Field<'s> {
60    pub fn name(&self) -> &'s str {
61        self.scheme.fields.get_index(self.index).unwrap().0
62    }
63
64    pub fn index(&self) -> usize {
65        self.index
66    }
67
68    pub fn scheme(&self) -> &'s Scheme {
69        self.scheme
70    }
71}
72
73impl<'s> GetType for Field<'s> {
74    fn get_type(&self) -> Type {
75        *self.scheme.fields.get_index(self.index).unwrap().1
76    }
77}
78
79/// An error that occurs if an unregistered field name was queried from a
80/// [`Scheme`](struct@Scheme).
81#[derive(Debug, PartialEq, Fail)]
82#[fail(display = "unknown field")]
83pub struct UnknownFieldError;
84
85/// An error that occurs when previously defined field gets redefined.
86#[derive(Debug, PartialEq, Fail)]
87#[fail(display = "attempt to redefine field {}", _0)]
88pub struct FieldRedefinitionError(String);
89
90/// An opaque filter parsing error associated with the original input.
91///
92/// For now, you can just print it in a debug or a human-readable fashion.
93#[derive(Debug, PartialEq)]
94pub struct ParseError<'i> {
95    kind: LexErrorKind,
96    input: &'i str,
97    line_number: usize,
98    span_start: usize,
99    span_len: usize,
100}
101
102impl<'i> Error for ParseError<'i> {}
103
104impl<'i> ParseError<'i> {
105    pub(crate) fn new(mut input: &'i str, (kind, span): (LexErrorKind, &'i str)) -> Self {
106        let mut span_start = span.as_ptr() as usize - input.as_ptr() as usize;
107
108        let (line_number, line_start) = input[..span_start]
109            .match_indices('\n')
110            .map(|(pos, _)| pos + 1)
111            .scan(0, |line_number, line_start| {
112                *line_number += 1;
113                Some((*line_number, line_start))
114            })
115            .last()
116            .unwrap_or_default();
117
118        input = &input[line_start..];
119
120        span_start -= line_start;
121        let mut span_len = span.len();
122
123        if let Some(line_end) = input.find('\n') {
124            input = &input[..line_end];
125            span_len = min(span_len, line_end - span_start);
126        }
127
128        ParseError {
129            kind,
130            input,
131            line_number,
132            span_start,
133            span_len,
134        }
135    }
136}
137
138impl<'i> Display for ParseError<'i> {
139    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
140        writeln!(
141            f,
142            "Filter parsing error ({}:{}):",
143            self.line_number + 1,
144            self.span_start + 1
145        )?;
146
147        writeln!(f, "{}", self.input)?;
148
149        for _ in 0..self.span_start {
150            write!(f, " ")?;
151        }
152
153        for _ in 0..max(1, self.span_len) {
154            write!(f, "^")?;
155        }
156
157        writeln!(f, " {}", self.kind)?;
158
159        Ok(())
160    }
161}
162
163/// The main registry for fields and their associated types.
164///
165/// This is necessary to provide typechecking for runtime values provided
166/// to the [execution context](::ExecutionContext) and also to aid parser
167/// in ambiguous contexts.
168#[derive(Default, Deserialize)]
169#[serde(transparent)]
170pub struct Scheme {
171    fields: IndexMap<String, Type, FnvBuildHasher>,
172}
173
174impl PartialEq for Scheme {
175    fn eq(&self, other: &Self) -> bool {
176        ptr::eq(self, other)
177    }
178}
179
180impl Eq for Scheme {}
181
182impl<'s> Scheme {
183    /// Creates a new scheme.
184    pub fn new() -> Self {
185        Default::default()
186    }
187
188    /// Creates a new scheme with capacity for `n` fields.
189    pub fn with_capacity(n: usize) -> Self {
190        Scheme {
191            fields: IndexMap::with_capacity_and_hasher(n, FnvBuildHasher::default()),
192        }
193    }
194
195    /// Registers a field and its corresponding type.
196    pub fn add_field(&mut self, name: String, ty: Type) -> Result<(), FieldRedefinitionError> {
197        match self.fields.entry(name) {
198            Entry::Occupied(entry) => Err(FieldRedefinitionError(entry.key().to_string())),
199            Entry::Vacant(entry) => {
200                entry.insert(ty);
201                Ok(())
202            }
203        }
204    }
205
206    /// Registers a series of fields from an iterable, reporting any conflicts.
207    pub fn try_from_iter(
208        iter: impl IntoIterator<Item = (String, Type)>,
209    ) -> Result<Self, FieldRedefinitionError> {
210        let iter = iter.into_iter();
211        let (low, _) = iter.size_hint();
212        let mut scheme = Scheme::with_capacity(low);
213        for (name, value) in iter {
214            scheme.add_field(name, value)?;
215        }
216        Ok(scheme)
217    }
218
219    pub(crate) fn get_field_index(&'s self, name: &str) -> Result<Field<'s>, UnknownFieldError> {
220        match self.fields.get_full(name) {
221            Some((index, ..)) => Ok(Field {
222                scheme: self,
223                index,
224            }),
225            None => Err(UnknownFieldError),
226        }
227    }
228
229    pub(crate) fn get_field_count(&self) -> usize {
230        self.fields.len()
231    }
232
233    /// Parses a filter into an AST form.
234    pub fn parse<'i>(&'s self, input: &'i str) -> Result<FilterAst<'s>, ParseError<'i>> {
235        complete(FilterAst::lex_with(input.trim(), self)).map_err(|err| ParseError::new(input, err))
236    }
237}
238
239/// A convenience macro for constructing a [`Scheme`](struct@Scheme) with static
240/// contents.
241#[macro_export]
242macro_rules! Scheme {
243    ($($ns:ident $(. $field:ident)*: $ty:ident),* $(,)*) => {
244        $crate::Scheme::try_from_iter(
245            [$(
246                (
247                    concat!(stringify!($ns) $(, ".", stringify!($field))*),
248                    $crate::Type::$ty
249                )
250            ),*]
251            .iter()
252            .map(|&(k, v)| (k.to_owned(), v)),
253        )
254        // Treat duplciations in static schemes as a developer's mistake.
255        .unwrap_or_else(|err| panic!("{}", err))
256    };
257}
258
259#[test]
260fn test_parse_error() {
261    use indoc::indoc;
262
263    let scheme = &Scheme! { num: Int };
264
265    {
266        let err = scheme.parse("xyz").unwrap_err();
267        assert_eq!(
268            err,
269            ParseError {
270                kind: LexErrorKind::UnknownField(UnknownFieldError),
271                input: "xyz",
272                line_number: 0,
273                span_start: 0,
274                span_len: 3
275            }
276        );
277        assert_eq!(
278            err.to_string(),
279            indoc!(
280                r#"
281                Filter parsing error (1:1):
282                xyz
283                ^^^ unknown field
284                "#
285            )
286        );
287    }
288
289    {
290        let err = scheme.parse("xyz\n").unwrap_err();
291        assert_eq!(
292            err,
293            ParseError {
294                kind: LexErrorKind::UnknownField(UnknownFieldError),
295                input: "xyz",
296                line_number: 0,
297                span_start: 0,
298                span_len: 3
299            }
300        );
301        assert_eq!(
302            err.to_string(),
303            indoc!(
304                r#"
305                Filter parsing error (1:1):
306                xyz
307                ^^^ unknown field
308                "#
309            )
310        );
311    }
312
313    {
314        let err = scheme.parse("\n\n    xyz").unwrap_err();
315        assert_eq!(
316            err,
317            ParseError {
318                kind: LexErrorKind::UnknownField(UnknownFieldError),
319                input: "    xyz",
320                line_number: 2,
321                span_start: 4,
322                span_len: 3
323            }
324        );
325        assert_eq!(
326            err.to_string(),
327            indoc!(
328                r#"
329                Filter parsing error (3:5):
330                    xyz
331                    ^^^ unknown field
332                "#
333            )
334        );
335    }
336
337    {
338        let err = scheme
339            .parse(indoc!(
340                r#"
341                num == 10 or
342                num == true or
343                num == 20
344                "#
345            ))
346            .unwrap_err();
347        assert_eq!(
348            err,
349            ParseError {
350                kind: LexErrorKind::ExpectedName("digit"),
351                input: "num == true or",
352                line_number: 1,
353                span_start: 7,
354                span_len: 7
355            }
356        );
357        assert_eq!(
358            err.to_string(),
359            indoc!(
360                r#"
361                Filter parsing error (2:8):
362                num == true or
363                       ^^^^^^^ expected digit
364                "#
365            )
366        );
367    }
368}
369
370#[test]
371fn test_field() {
372    let scheme = &Scheme! {
373        x: Bytes,
374        x.y.z0: Int,
375        is_TCP: Bool,
376    };
377
378    assert_ok!(
379        Field::lex_with("x;", scheme),
380        scheme.get_field_index("x").unwrap(),
381        ";"
382    );
383
384    assert_ok!(
385        Field::lex_with("x.y.z0-", scheme),
386        scheme.get_field_index("x.y.z0").unwrap(),
387        "-"
388    );
389
390    assert_ok!(
391        Field::lex_with("is_TCP", scheme),
392        scheme.get_field_index("is_TCP").unwrap(),
393        ""
394    );
395
396    assert_err!(
397        Field::lex_with("x..y", scheme),
398        LexErrorKind::ExpectedName("identifier character"),
399        ".y"
400    );
401
402    assert_err!(
403        Field::lex_with("x.#", scheme),
404        LexErrorKind::ExpectedName("identifier character"),
405        "#"
406    );
407
408    assert_err!(
409        Field::lex_with("x.y.z;", scheme),
410        LexErrorKind::UnknownField(UnknownFieldError),
411        "x.y.z"
412    );
413}
414
415#[test]
416#[should_panic(expected = "attempt to redefine field foo")]
417fn test_static_field_type_override() {
418    Scheme! { foo: Int, foo: Int };
419}
420
421#[test]
422fn test_field_type_override() {
423    let mut scheme = Scheme! { foo: Int };
424
425    assert_eq!(
426        scheme.add_field("foo".into(), Type::Bytes),
427        Err(FieldRedefinitionError("foo".into()))
428    )
429}