1use rquickjs::{Ctx, Value};
2use serde::Serialize;
3use serde::de::DeserializeOwned;
4
5#[doc(inline)]
6pub use crate::de::Deserializer;
7#[doc(inline)]
8pub use crate::err::{Error, Result};
9#[doc(inline)]
10pub use crate::ser::Serializer;
11
12pub mod de;
13pub mod err;
14pub mod ser;
15#[cfg(test)]
16mod test;
17mod utils;
18
19pub const MAX_SAFE_INTEGER: i64 = 2_i64.pow(53) - 1;
21
22pub const MIN_SAFE_INTEGER: i64 = -MAX_SAFE_INTEGER;
24
25#[inline]
67pub fn to_value<T>(context: Ctx<'_>, value: T) -> Result<Value<'_>>
68where
69 T: Serialize,
70{
71 let mut serializer = Serializer::from_context(context)?;
72 value.serialize(&mut serializer)?;
73 Ok(serializer.value)
74}
75
76#[inline]
122pub fn from_value<T>(value: Value) -> Result<T>
123where
124 T: DeserializeOwned,
125{
126 let mut deserializer = Deserializer::from(value);
127 T::deserialize(&mut deserializer)
128}
129
130#[cfg(test)]
131mod tests {
132 use std::collections::BTreeMap;
133
134 use quickcheck::quickcheck;
135 use serde::de::DeserializeOwned;
136 use serde::{Deserialize, Serialize};
137
138 use crate::de::Deserializer as ValueDeserializer;
139 use crate::err::Result;
140 use crate::ser::Serializer as ValueSerializer;
141 use crate::test::Runtime;
142 use crate::{MAX_SAFE_INTEGER, MIN_SAFE_INTEGER};
143
144 quickcheck! {
145 fn test_str(expected: String) -> Result<bool> {
146 let actual = do_roundtrip::<_, String>(&expected);
147 Ok(expected == actual)
148 }
149
150 fn test_u8(expected: u8) -> Result<bool> {
151 let actual = do_roundtrip::<_, u8>(&expected);
152 Ok(expected == actual)
153 }
154
155 fn test_u16(expected: u16) -> Result<bool> {
156 let actual = do_roundtrip::<_, u16>(&expected);
157 Ok(expected == actual)
158 }
159
160 fn test_f32(expected: f32) -> quickcheck::TestResult {
161 if expected.is_nan() {
162 return quickcheck::TestResult::discard();
163 }
164
165 let actual = do_roundtrip::<_, f32>(&expected);
166 quickcheck::TestResult::from_bool(expected == actual)
167 }
168
169 fn test_i32(expected: i32) -> Result<bool> {
170 let actual = do_roundtrip::<_, i32>(&expected);
171 Ok(expected == actual)
172 }
173
174 fn test_i64(expected: i64) -> Result<bool> {
182 if (MIN_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&expected) {
183 let actual = do_roundtrip::<_, i64>(&expected);
184 Ok(expected == actual)
185 } else {
186 let expected_f64 = expected as f64;
187 let actual = do_roundtrip::<_, f64>(&expected_f64);
188 Ok(expected_f64 == actual)
189 }
190 }
191
192 fn test_u32(expected: u32) -> Result<bool> {
193 let actual = do_roundtrip::<_, u32>(&expected);
194 Ok(expected == actual)
195 }
196
197 fn test_u64(expected: u64) -> Result<bool> {
205 if expected <= MAX_SAFE_INTEGER as u64 {
206 let actual = do_roundtrip::<_, u64>(&expected);
207 Ok(expected == actual)
208 } else {
209 let expected_f64 = expected as f64;
210 let actual = do_roundtrip::<_, f64>(&expected_f64);
211 Ok(expected_f64 == actual)
212 }
213 }
214
215 fn test_bool(expected: bool) -> Result<bool> {
216 let actual = do_roundtrip::<_, bool>(&expected);
217 Ok(expected == actual)
218 }
219 }
220
221 #[test]
222 fn test_map() {
223 let mut expected = BTreeMap::<String, String>::new();
224 expected.insert("foo".to_string(), "bar".to_string());
225 expected.insert("hello".to_string(), "world".to_string());
226
227 let actual = do_roundtrip::<_, BTreeMap<String, String>>(&expected);
228
229 assert_eq!(expected, actual);
230 }
231
232 #[test]
233 fn test_struct_into_map() {
234 #[derive(Debug, Serialize, Deserialize, PartialEq)]
235 struct MyObject {
236 foo: String,
237 bar: u32,
238 }
239 let expected = MyObject {
240 foo: "hello".to_string(),
241 bar: 1337,
242 };
243
244 let actual = do_roundtrip::<_, MyObject>(&expected);
245
246 assert_eq!(expected, actual);
247 }
248
249 #[test]
250 fn test_nested_maps() {
251 let mut expected = BTreeMap::<String, BTreeMap<String, String>>::new();
252 let mut a = BTreeMap::new();
253 a.insert("foo".to_string(), "bar".to_string());
254 a.insert("hello".to_string(), "world".to_string());
255 let mut b = BTreeMap::new();
256 b.insert("toto".to_string(), "titi".to_string());
257 expected.insert("aaa".to_string(), a);
258 expected.insert("bbb".to_string(), b);
259
260 let actual = do_roundtrip::<_, BTreeMap<String, BTreeMap<String, String>>>(&expected);
261
262 assert_eq!(expected, actual);
263 }
264
265 #[test]
266 fn test_nested_structs_into_maps() {
267 #[derive(Debug, Serialize, Deserialize, PartialEq)]
268 struct MyObjectB {
269 toto: String,
270 titi: i32,
271 }
272
273 #[derive(Debug, Serialize, Deserialize, PartialEq)]
274 struct MyObjectA {
275 foo: String,
276 bar: u32,
277 b: MyObjectB,
278 }
279 let expected = MyObjectA {
280 foo: "hello".to_string(),
281 bar: 1337,
282 b: MyObjectB {
283 toto: "world".to_string(),
284 titi: -42,
285 },
286 };
287
288 let actual = do_roundtrip::<_, MyObjectA>(&expected);
289
290 assert_eq!(expected, actual);
291 }
292
293 #[test]
294 fn test_sequence() {
295 let expected = vec!["hello".to_string(), "world".to_string()];
296
297 let actual = do_roundtrip::<_, Vec<String>>(&expected);
298
299 assert_eq!(expected, actual);
300 }
301
302 #[test]
303 fn test_nested_sequences() {
304 let mut expected = Vec::new();
305 let a = vec!["foo".to_string(), "bar".to_string()];
306 let b = vec!["toto".to_string(), "tata".to_string()];
307 expected.push(a);
308 expected.push(b);
309
310 let actual = do_roundtrip::<_, Vec<Vec<String>>>(&expected);
311
312 assert_eq!(expected, actual);
313 }
314
315 #[test]
316 fn test_sanity() {
317 #[derive(Debug, Serialize, Deserialize, PartialEq)]
318 struct MyObject {
319 a: u8,
320 b: u16,
321 c: u32,
322 d: u64,
323 e: i8,
324 f: i16,
325 g: i32,
326 h: i64,
327 i: f32,
328 j: f64,
329 k: String,
330 l: bool,
331 m: BTreeMap<String, u32>,
332 n: Vec<u32>,
333 o: BTreeMap<String, BTreeMap<String, u32>>,
334 p: Vec<Vec<u32>>,
335 bb: MyObjectB,
336 }
337
338 #[derive(Debug, Serialize, Deserialize, PartialEq)]
339 struct MyObjectB {
340 a: u32,
341 cc: MyObjectC,
342 }
343
344 #[derive(Debug, Serialize, Deserialize, PartialEq)]
345 struct MyObjectC {
346 a: Vec<u32>,
347 b: BTreeMap<String, u32>,
348 }
349
350 let mut cc_b = BTreeMap::new();
351 cc_b.insert("a".to_string(), 123);
352 cc_b.insert("b".to_string(), 456);
353 let cc = MyObjectC {
354 a: vec![1337, 42],
355 b: cc_b,
356 };
357
358 let bb = MyObjectB { a: 789, cc };
359
360 let mut m = BTreeMap::new();
361 m.insert("a".to_string(), 123);
362 m.insert("b".to_string(), 456);
363 m.insert("c".to_string(), 789);
364
365 let mut oo = BTreeMap::new();
366 oo.insert("e".to_string(), 123);
367
368 let mut o = BTreeMap::new();
369 o.insert("d".to_string(), oo);
370
371 let expected = MyObject {
372 a: u8::MAX,
373 b: u16::MAX,
374 c: u32::MAX,
375 d: MAX_SAFE_INTEGER as u64,
376 e: i8::MAX,
377 f: i16::MAX,
378 g: i32::MAX,
379 h: MIN_SAFE_INTEGER,
380 i: f32::MAX,
381 j: f64::MAX,
382 k: "hello world".to_string(),
383 l: true,
384 m,
385 n: vec![1, 2, 3, 4, 5],
386 o,
387 p: vec![vec![1, 2], vec![3, 4, 5]],
388 bb,
389 };
390
391 let actual = do_roundtrip::<_, MyObject>(&expected);
392
393 assert_eq!(expected, actual);
394 }
395
396 fn do_roundtrip<E, A>(expected: &E) -> A
397 where
398 E: Serialize,
399 A: DeserializeOwned,
400 {
401 let rt = Runtime::default();
402 rt.context().with(|cx| {
403 let mut serializer = ValueSerializer::from_context(cx).unwrap();
404 expected.serialize(&mut serializer).unwrap();
405 let mut deserializer = ValueDeserializer::from(serializer.value);
406 A::deserialize(&mut deserializer).unwrap()
407 })
408 }
409}