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