1use crate::{
2 automaton::Automaton,
3 engine::{main::MainEngine, Compiler},
4};
5use serde::{
6 de::{self, Visitor},
7 ser::SerializeTuple,
8 Deserialize, Serialize,
9};
10
11#[derive(Debug, Serialize, Deserialize)]
12enum BinaryVersion {
13 Past,
15 V1,
17}
18
19impl de::Expected for BinaryVersion {
20 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
21 match *self {
22 Self::Past => write!(formatter, "Past"),
23 Self::V1 => write!(formatter, "v0.9.4"),
24 }
25 }
26}
27
28impl Serialize for MainEngine {
29 #[inline]
30 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
31 where
32 S: serde::Serializer,
33 {
34 let mut tuple_ser = serializer.serialize_tuple(2)?;
35 tuple_ser.serialize_element(&BinaryVersion::V1)?;
36 tuple_ser.serialize_element(&self.automaton())?;
37 tuple_ser.end()
38 }
39}
40
41impl<'de> Deserialize<'de> for MainEngine {
42 #[inline]
43 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
44 where
45 D: serde::Deserializer<'de>,
46 {
47 let automaton = deserializer.deserialize_tuple(2, EngineVisitor)?;
48 Ok(Self::from_compiled_query(automaton))
49 }
50}
51
52struct EngineVisitor;
53
54impl<'de> Visitor<'de> for EngineVisitor {
55 type Value = Automaton;
56
57 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
58 write!(formatter, "the binary version and the Automaton")
59 }
60
61 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
62 where
63 A: serde::de::SeqAccess<'de>,
64 {
65 let version = seq.next_element::<BinaryVersion>()?;
66 match version {
67 Some(BinaryVersion::V1) => (),
68 Some(v) => return Err(de::Error::custom(format!("binary version {:?} is incompatible", v))),
69 None => return Err(de::Error::missing_field("version")),
70 }
71 let automaton = seq.next_element::<Automaton>()?;
72 match automaton {
73 Some(a) => Ok(a),
74 None => Err(de::Error::missing_field("automaton")),
75 }
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::{
83 automaton::Automaton,
84 engine::{Compiler, RsonpathEngine},
85 };
86 use serde::{ser::SerializeTuple, Serialize, Serializer};
87 use std::error::Error;
88
89 #[test]
90 fn automaton_round_trip() -> Result<(), Box<dyn Error>> {
91 let query_str = "$..phoneNumbers[*].number";
92 let query = rsonpath_syntax::parse(query_str)?;
93 let automaton = Automaton::new(&query)?;
94 let engine = RsonpathEngine::from_compiled_query(automaton.clone());
95
96 let json_string = serde_json::to_string(&engine)?;
97
98 let round_trip: RsonpathEngine = serde_json::from_str(&json_string)?;
99
100 assert_eq!(&automaton, round_trip.automaton());
101
102 Ok(())
103 }
104
105 #[test]
106 fn deserializing_from_older_version() -> Result<(), Box<dyn Error>> {
107 struct OldEngine {
108 automaton: Automaton,
109 }
110 impl Serialize for OldEngine {
111 #[inline]
112 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
113 where
114 S: Serializer,
115 {
116 let mut tuple_ser = serializer.serialize_tuple(2)?;
117 tuple_ser.serialize_element(&BinaryVersion::Past)?;
118 tuple_ser.serialize_element(&self.automaton)?;
119 tuple_ser.end()
120 }
121 }
122
123 let query_str = "$..phoneNumbers[*].number";
124 let query = rsonpath_syntax::parse(query_str)?;
125 let automaton = Automaton::new(&query)?;
126 let engine = OldEngine { automaton };
127
128 let json_string = serde_json::to_string(&engine)?;
129
130 match serde_json::from_str::<RsonpathEngine>(&json_string) {
131 Ok(_) => panic!("expected error"),
132 Err(e) => assert!(e.to_string().contains("binary version Past is incompatible")),
133 }
134
135 Ok(())
136 }
137
138 mod proptests {
139 use super::{Automaton, Compiler, RsonpathEngine};
140 use pretty_assertions::assert_eq;
141 use proptest::prelude::*;
142 use rsonpath_syntax_proptest::{ArbitraryJsonPathQuery, ArbitraryJsonPathQueryParams};
143
144 proptest! {
145 #[test]
146 fn main_engine_cbor_roundtrips(ArbitraryJsonPathQuery { parsed, .. } in prop::arbitrary::any_with::<ArbitraryJsonPathQuery>(
147 ArbitraryJsonPathQueryParams {
148 only_rsonpath_supported_subset: true,
149 ..Default::default()
150 }
151 )) {
152 use std::io;
153 struct ReadBuf<'a> {
154 buf: &'a [u8],
155 idx: usize,
156 }
157 impl<'a> io::Read for &mut ReadBuf<'a> {
158 fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
159 let len = std::cmp::min(self.buf.len() - self.idx, buf.len());
160 buf.copy_from_slice(&self.buf[self.idx..self.idx + len]);
161 self.idx += len;
162 Ok(len)
163 }
164 }
165
166 let automaton = Automaton::new(&parsed)?;
167 let engine = RsonpathEngine::from_compiled_query(automaton.clone());
168
169 let mut buf = vec![];
170 ciborium::into_writer(&engine, &mut buf)?;
171
172 let mut read = ReadBuf { buf: &buf, idx: 0 };
173 let engine_deser = ciborium::from_reader::<RsonpathEngine, _>(&mut read)?;
174
175 assert_eq!(&automaton, engine_deser.automaton());
176 }
177
178 #[test]
179 fn main_engine_json_roundtrips(ArbitraryJsonPathQuery { parsed, .. } in prop::arbitrary::any_with::<ArbitraryJsonPathQuery>(
180 ArbitraryJsonPathQueryParams {
181 only_rsonpath_supported_subset: true,
182 ..Default::default()
183 }
184 )) {
185 let automaton = Automaton::new(&parsed)?;
186 let engine = RsonpathEngine::from_compiled_query(automaton.clone());
187
188 let json_str = serde_json::to_string(&engine)?;
189 let engine_deser = serde_json::from_str::<RsonpathEngine>(&json_str)?;
190
191 assert_eq!(&automaton, engine_deser.automaton());
192 }
193
194 #[test]
195 fn main_engine_message_pack_roundtrips(ArbitraryJsonPathQuery { parsed, .. } in prop::arbitrary::any_with::<ArbitraryJsonPathQuery>(
196 ArbitraryJsonPathQueryParams {
197 only_rsonpath_supported_subset: true,
198 ..Default::default()
199 }
200 )) {
201 let automaton = Automaton::new(&parsed)?;
202 let engine = RsonpathEngine::from_compiled_query(automaton.clone());
203
204 let buf = rmp_serde::to_vec(&engine)?;
205 let engine_deser = rmp_serde::from_slice::<RsonpathEngine>(&buf)?;
206
207 assert_eq!(&automaton, engine_deser.automaton());
208 }
209 }
210 }
211}