sawp_json/
lib.rs

1//! SAWP JSON Parser
2
3#![allow(clippy::unneeded_field_pattern)]
4
5use sawp::error::{Error, ErrorKind, Result};
6use sawp::parser::{Direction, Parse};
7use sawp::probe::Probe;
8use sawp::protocol::Protocol;
9use serde_json::{Deserializer, Value};
10
11#[derive(Debug)]
12pub struct Json {}
13
14#[derive(Debug, PartialEq, Eq)]
15pub struct Message {
16    pub value: Value,
17}
18
19impl Message {
20    pub fn new(value: Value) -> Self {
21        Self { value }
22    }
23}
24
25impl Protocol<'_> for Json {
26    type Message = Message;
27
28    fn name() -> &'static str {
29        "json"
30    }
31}
32
33impl<'a> Parse<'a> for Json {
34    fn parse(
35        &self,
36        input: &'a [u8],
37        _direction: Direction,
38    ) -> Result<(&'a [u8], Option<Self::Message>)> {
39        let mut stream = Deserializer::from_slice(input).into_iter::<Value>();
40
41        match stream.next() {
42            Some(Ok(value)) => Ok((&input[stream.byte_offset()..], Some(Message::new(value)))),
43            _ => Err(Error::new(ErrorKind::InvalidData)),
44        }
45    }
46}
47
48impl<'a> Probe<'a> for Json {}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use rstest::rstest;
54    use sawp::error::{Error, ErrorKind, Result};
55    use sawp::probe::Status;
56    use serde_json::json;
57
58    #[rstest(
59        input,
60        expected,
61        case::empty(b"", Err(Error::new(ErrorKind::InvalidData))),
62        case::singlequote(b"''", Err(Error::new(ErrorKind::InvalidData))),
63        case::incomplete(b"{\"a\":", Err(Error::new(ErrorKind::InvalidData))),
64
65        // Smoke tests
66        case::number(b"1234", Ok((0, Some(Message::new(json!(1234)))))),
67        case::null(b"null", Ok((0, Some(Message::new(json!(null)))))),
68        case::bool_true(b"true", Ok((0, Some(Message::new(json!(true)))))),
69        case::bool_false(b"false", Ok((0, Some(Message::new(json!(false)))))),
70        case::empty_obj(b"{}", Ok((0, Some(Message::new(json!({})))))),
71        case::empty_list(b"[]", Ok((0, Some(Message::new(json!([])))))),
72        case::empty_string(b"\"\"", Ok((0, Some(Message::new(json!("")))))),
73        case::object(b"{\"a\":\"b\"}", Ok((0, Some(Message::new(json!({"a": "b"})))))),
74        case::list(b"[\"a\", \"b\"]", Ok((0, Some(Message::new(json!(["a", "b"])))))),
75        case::whitespace(b"\n\t{\n\r\n\"a\":    \t\"b\"\n}", Ok((0, Some(Message::new(json!({"a": "b"})))))),
76        case::multi(b"{}[1]", Ok((3, Some(Message::new(json!({})))))),
77    )]
78    fn test_parse(input: &[u8], expected: Result<(usize, Option<<Json as Protocol>::Message>)>) {
79        let json = Json {};
80        assert_eq!(
81            expected,
82            json.parse(input, Direction::Unknown)
83                .map(|(left, msg)| (left.len(), msg)),
84        );
85    }
86
87    #[rstest(
88        input,
89        expected,
90        case::empty(b"", Status::Unrecognized),
91        case::incomplete(b"{\"a\":", Status::Unrecognized),
92        case::number(b"1234", Status::Recognized)
93    )]
94    fn test_probe(input: &[u8], expected: Status) {
95        let json = Json {};
96        assert_eq!(expected, json.probe(input, Direction::Unknown));
97    }
98}