sozu_command_lib/
parser.rs

1use nom::{
2    bytes::streaming::is_not,
3    character::complete::char,
4    combinator::map_res,
5    error::{ErrorKind, FromExternalError},
6    multi::many0,
7    sequence::terminated,
8    IResult,
9};
10
11#[derive(Debug)]
12#[allow(dead_code)]
13pub struct ParseError {
14    kind: ErrorKind,
15    serde_json_error: Option<serde_json::Error>,
16}
17
18impl FromExternalError<&[u8], serde_json::Error> for ParseError {
19    fn from_external_error(
20        _input: &[u8],
21        kind: ErrorKind,
22        serde_json_error: serde_json::Error,
23    ) -> Self {
24        // println!("input: {:?}, error kind: {:?}", input, kind);
25        Self {
26            kind,
27            serde_json_error: Some(serde_json_error),
28        }
29    }
30}
31
32impl nom::error::ParseError<&[u8]> for ParseError {
33    fn from_error_kind(_input: &[u8], kind: ErrorKind) -> Self {
34        // println!("input: {:?}, error kind: {:?}", input, kind);
35
36        Self {
37            kind,
38            serde_json_error: None,
39        }
40    }
41
42    fn append(_input: &[u8], _kind: ErrorKind, other: Self) -> Self {
43        other
44    }
45}
46
47/// this is to propagate the serde_json error
48pub fn parse_one_request<'a, T>(input: &'a [u8]) -> Result<T, ParseError>
49where
50    T: serde::de::Deserialize<'a>,
51{
52    serde_json::from_slice::<T>(input).map_err(|serde_error| {
53        ParseError::from_external_error(input, ErrorKind::MapRes, serde_error)
54    })
55}
56
57pub fn parse_several_requests<'a, T>(input: &'a [u8]) -> IResult<&[u8], Vec<T>>
58where
59    T: serde::de::Deserialize<'a>,
60{
61    // use serde_json::from_slice;
62    many0(nom::combinator::complete(terminated(
63        map_res(is_not("\0"), parse_one_request),
64        char('\0'),
65    )))(input)
66}
67
68#[cfg(test)]
69mod test {
70    use super::*;
71
72    use crate::proto::command::{request::RequestType, Status, SubscribeEvents, WorkerRequest};
73
74    #[test]
75    fn parse_one_worker_request() {
76        let worker_request = WorkerRequest::new(
77            "Some request".to_string(),
78            RequestType::Status(Status {}).into(),
79        );
80
81        let string = serde_json::ser::to_string(&worker_request).unwrap();
82
83        println!("string to parse: {string}");
84
85        let bytes = &string.as_bytes();
86
87        assert_eq!(
88            parse_one_request::<WorkerRequest>(bytes).unwrap(),
89            worker_request
90        )
91    }
92
93    #[test]
94    fn parse_several_worker_requests() {
95        let requests = vec![
96            WorkerRequest::new(
97                "Some request".to_string(),
98                RequestType::SaveState("/some/path".to_string()).into(),
99            ),
100            WorkerRequest::new(
101                "Some other request".to_string(),
102                RequestType::SubscribeEvents(SubscribeEvents {}).into(),
103            ),
104            WorkerRequest::new(
105                "Yet another request".to_string(),
106                RequestType::Status(Status {}).into(),
107            ),
108        ];
109
110        let mut serialized_requests = String::new();
111
112        for request in requests.iter() {
113            serialized_requests += &serde_json::ser::to_string(&request).unwrap();
114            serialized_requests.push('\0');
115        }
116
117        let bytes_to_parse = &serialized_requests.as_bytes();
118
119        let parsed_requests = parse_several_requests(bytes_to_parse).unwrap();
120
121        println!("parsed commands: {parsed_requests:?}");
122
123        let empty_vec: Vec<u8> = vec![];
124
125        assert_eq!(parsed_requests, (&empty_vec[..], requests))
126    }
127}