Revision control

Copy as Markdown

Other Tools

#![allow(
// clippy is broken and shows wrong warnings
// clippy on stable does not know yet about the lint name
unknown_lints,
clippy::derive_partial_eq_without_eq,
)]
extern crate alloc;
mod collections;
mod default_on;
mod enum_map;
mod frominto;
mod key_value_map;
mod map_tuple_list;
mod pickfirst;
mod serde_as_macro;
mod serde_conv;
mod time;
#[path = "../utils.rs"]
mod utils;
use crate::utils::*;
use alloc::{
collections::{BTreeMap, BTreeSet, LinkedList, VecDeque},
rc::{Rc, Weak as RcWeak},
sync::{Arc, Weak as ArcWeak},
};
use core::cell::{Cell, RefCell};
use expect_test::expect;
use serde::{Deserialize, Serialize};
use serde_with::{
formats::{CommaSeparator, Flexible, Strict},
serde_as, BoolFromInt, BytesOrString, DisplayFromStr, Map, NoneAsEmptyString, OneOrMany, Same,
Seq, StringWithSeparator,
};
use std::{
collections::HashMap,
sync::{Mutex, RwLock},
};
#[test]
fn test_basic_wrappers() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SBox(#[serde_as(as = "Box<DisplayFromStr>")] Box<u32>);
is_equal(SBox(Box::new(123)), expect![[r#""123""#]]);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SRc(#[serde_as(as = "Rc<DisplayFromStr>")] Rc<u32>);
is_equal(SRc(Rc::new(123)), expect![[r#""123""#]]);
#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
struct SRcWeak(#[serde_as(as = "RcWeak<DisplayFromStr>")] RcWeak<u32>);
check_serialization(SRcWeak(RcWeak::new()), expect![[r#"null"#]]);
let s: SRcWeak = serde_json::from_str("null").unwrap();
assert!(s.0.upgrade().is_none());
let s: SRcWeak = serde_json::from_str("\"123\"").unwrap();
assert!(s.0.upgrade().is_none());
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SArc(#[serde_as(as = "Arc<DisplayFromStr>")] Arc<u32>);
is_equal(SArc(Arc::new(123)), expect![[r#""123""#]]);
#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
struct SArcWeak(#[serde_as(as = "ArcWeak<DisplayFromStr>")] ArcWeak<u32>);
check_serialization(SArcWeak(ArcWeak::new()), expect![[r#"null"#]]);
let s: SArcWeak = serde_json::from_str("null").unwrap();
assert!(s.0.upgrade().is_none());
let s: SArcWeak = serde_json::from_str("\"123\"").unwrap();
assert!(s.0.upgrade().is_none());
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SCell(#[serde_as(as = "Cell<DisplayFromStr>")] Cell<u32>);
is_equal(SCell(Cell::new(123)), expect![[r#""123""#]]);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SRefCell(#[serde_as(as = "RefCell<DisplayFromStr>")] RefCell<u32>);
is_equal(SRefCell(RefCell::new(123)), expect![[r#""123""#]]);
#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
struct SMutex(#[serde_as(as = "Mutex<DisplayFromStr>")] Mutex<u32>);
check_serialization(SMutex(Mutex::new(123)), expect![[r#""123""#]]);
let s: SMutex = serde_json::from_str("\"123\"").unwrap();
assert_eq!(*s.0.lock().unwrap(), 123);
#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
struct SRwLock(#[serde_as(as = "RwLock<DisplayFromStr>")] RwLock<u32>);
let expected = expect![[r#""123""#]];
check_serialization(SRwLock(RwLock::new(123)), expected);
let s: SRwLock = serde_json::from_str("\"123\"").unwrap();
assert_eq!(*s.0.read().unwrap(), 123);
}
#[test]
fn test_option() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S(#[serde_as(as = "_")] Option<u32>);
is_equal(S(None), expect![[r#"null"#]]);
is_equal(S(Some(9)), expect![[r#"9"#]]);
check_error_deserialization::<S>(
r#"{}"#,
expect![[r#"invalid type: map, expected u32 at line 1 column 0"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Struct {
#[serde_as(as = "_")]
value: Option<u32>,
}
check_error_deserialization::<Struct>(
r#"{}"#,
expect![[r#"missing field `value` at line 1 column 2"#]],
);
}
#[test]
fn test_result() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S(
#[serde_as(as = "Result<StringWithSeparator<CommaSeparator, u32>, DisplayFromStr>")]
Result<Vec<u32>, u32>,
);
is_equal(
S(Ok(vec![1, 2, 3])),
expect![[r#"
{
"Ok": "1,2,3"
}"#]],
);
is_equal(
S(Err(9)),
expect![[r#"
{
"Err": "9"
}"#]],
);
check_error_deserialization::<S>(r#"{}"#, expect![[r#"expected value at line 1 column 2"#]]);
}
#[test]
fn test_display_fromstr() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S(#[serde_as(as = "DisplayFromStr")] u32);
is_equal(S(123), expect![[r#""123""#]]);
}
#[test]
fn test_tuples() {
use std::net::IpAddr;
let ip = "1.2.3.4".parse().unwrap();
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S1(#[serde_as(as = "(DisplayFromStr,)")] (u32,));
is_equal(
S1((1,)),
expect![[r#"
[
"1"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S2a(#[serde_as(as = "(DisplayFromStr, DisplayFromStr)")] (u32, IpAddr));
is_equal(
S2a((555_888, ip)),
expect![[r#"
[
"555888",
"1.2.3.4"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S2b(#[serde_as(as = "(_, DisplayFromStr)")] (u32, IpAddr));
is_equal(
S2b((987, ip)),
expect![[r#"
[
987,
"1.2.3.4"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S2c(#[serde_as(as = "(Same, DisplayFromStr)")] (u32, IpAddr));
is_equal(
S2c((987, ip)),
expect![[r#"
[
987,
"1.2.3.4"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S6(
#[serde_as(as = "(Same, Same, Same, Same, Same, Same)")] (u8, u16, u32, i8, i16, i32),
);
is_equal(
S6((8, 16, 32, -8, 16, -32)),
expect![[r#"
[
8,
16,
32,
-8,
16,
-32
]"#]],
);
}
#[test]
fn test_arrays() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S0(#[serde_as(as = "[DisplayFromStr; 0]")] [u32; 0]);
is_equal(S0([]), expect![[r#"[]"#]]);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S1(#[serde_as(as = "[DisplayFromStr; 1]")] [u32; 1]);
is_equal(
S1([1]),
expect![[r#"
[
"1"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S2(#[serde_as(as = "[Same; 2]")] [u32; 2]);
is_equal(
S2([11, 22]),
expect![[r#"
[
11,
22
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S32(#[serde_as(as = "[Same; 32]")] [u32; 32]);
is_equal(
S32([
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
]),
expect![[r#"
[
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31
]"#]],
);
}
#[test]
fn test_sequence_like_types() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S1(#[serde_as(as = "Box<[Same]>")] Box<[u32]>);
is_equal(
S1(vec![1, 2, 3, 99].into()),
expect![[r#"
[
1,
2,
3,
99
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S2(#[serde_as(as = "BTreeSet<Same>")] BTreeSet<u32>);
is_equal(
S2(vec![1, 2, 3, 99].into_iter().collect()),
expect![[r#"
[
1,
2,
3,
99
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S3(#[serde_as(as = "LinkedList<Same>")] LinkedList<u32>);
is_equal(
S3(vec![1, 2, 3, 99].into_iter().collect()),
expect![[r#"
[
1,
2,
3,
99
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S4(#[serde_as(as = "Vec<Same>")] Vec<u32>);
is_equal(
S4(vec![1, 2, 3, 99]),
expect![[r#"
[
1,
2,
3,
99
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S5(#[serde_as(as = "VecDeque<Same>")] VecDeque<u32>);
is_equal(
S5(vec![1, 2, 3, 99].into()),
expect![[r#"
[
1,
2,
3,
99
]"#]],
);
}
#[test]
fn test_none_as_empty_string() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S(#[serde_as(as = "NoneAsEmptyString")] Option<String>);
is_equal(S(None), expect![[r#""""#]]);
is_equal(S(Some("Hello".to_string())), expect![[r#""Hello""#]]);
}
#[test]
fn test_bytes_or_string() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S(#[serde_as(as = "BytesOrString")] Vec<u8>);
is_equal(
S(vec![1, 2, 3]),
expect![[r#"
[
1,
2,
3
]"#]],
);
check_deserialization(S(vec![72, 101, 108, 108, 111]), r#""Hello""#);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SVec(#[serde_as(as = "Vec<BytesOrString>")] Vec<Vec<u8>>);
is_equal(
SVec(vec![vec![1, 2, 3]]),
expect![[r#"
[
[
1,
2,
3
]
]"#]],
);
check_deserialization(
SVec(vec![
vec![72, 101, 108, 108, 111],
vec![87, 111, 114, 108, 100],
vec![1, 2, 3],
]),
r#"["Hello","World",[1,2,3]]"#,
);
}
#[test]
fn string_with_separator() {
use serde_with::{
formats::{CommaSeparator, SpaceSeparator},
StringWithSeparator,
};
#[serde_as]
#[derive(Deserialize, Serialize)]
struct A {
#[serde_as(as = "StringWithSeparator::<SpaceSeparator, String>")]
tags: Vec<String>,
#[serde_as(as = "StringWithSeparator::<CommaSeparator, String>")]
// more_tags: Vec<String>,
more_tags: BTreeSet<String>,
}
let v: A = serde_json::from_str(
r##"{
"tags": "#hello #world",
"more_tags": "foo,bar,bar"
}"##,
)
.unwrap();
assert_eq!(vec!["#hello", "#world"], v.tags);
assert_eq!(2, v.more_tags.len());
let x = A {
tags: vec!["1".to_string(), "2".to_string(), "3".to_string()],
more_tags: Default::default(),
};
assert_eq!(
r#"{"tags":"1 2 3","more_tags":""}"#,
serde_json::to_string(&x).unwrap()
);
}
#[test]
fn test_vec_skip_error() {
use serde_with::VecSkipError;
#[serde_as]
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct S {
tag: String,
#[serde_as(as = "VecSkipError<_>")]
values: Vec<u8>,
}
check_deserialization(
S {
tag: "type".into(),
values: vec![0, 1],
},
r#"{"tag":"type","values":[0, "str", 1, [10, 11], -2, {}, 300]}"#,
);
is_equal(
S {
tag: "round-trip".into(),
values: vec![0, 255],
},
expect![[r#"
{
"tag": "round-trip",
"values": [
0,
255
]
}"#]],
);
}
#[test]
fn test_serialize_reference() {
#[serde_as]
#[derive(Debug, Serialize)]
struct S1<'a>(#[serde_as(as = "Vec<DisplayFromStr>")] &'a Vec<u32>);
check_serialization(
S1(&vec![1, 2]),
expect![[r#"
[
"1",
"2"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize)]
struct S1a<'a>(#[serde_as(as = "&Vec<DisplayFromStr>")] &'a Vec<u32>);
check_serialization(
S1(&vec![1, 2]),
expect![[r#"
[
"1",
"2"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize)]
struct S1Mut<'a>(#[serde_as(as = "Vec<DisplayFromStr>")] &'a mut Vec<u32>);
check_serialization(
S1(&vec![1, 2]),
expect![[r#"
[
"1",
"2"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize)]
struct S1aMut<'a>(#[serde_as(as = "&mut Vec<DisplayFromStr>")] &'a mut Vec<u32>);
check_serialization(
S1(&vec![1, 2]),
expect![[r#"
[
"1",
"2"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize)]
struct S2<'a>(#[serde_as(as = "&[DisplayFromStr]")] &'a [u32]);
check_serialization(
S2(&[1, 2]),
expect![[r#"
[
"1",
"2"
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize)]
struct S3<'a>(
#[serde_as(as = "&BTreeMap<DisplayFromStr, DisplayFromStr>")] &'a BTreeMap<bool, u32>,
);
let bmap = vec![(false, 123), (true, 456)].into_iter().collect();
check_serialization(
S3(&bmap),
expect![[r#"
{
"false": "123",
"true": "456"
}"#]],
);
#[serde_as]
#[derive(Debug, Serialize)]
struct S4<'a>(#[serde_as(as = "&Vec<(_, DisplayFromStr)>")] &'a BTreeMap<bool, u32>);
let bmap = vec![(false, 123), (true, 456)].into_iter().collect();
check_serialization(
S4(&bmap),
expect![[r#"
[
[
false,
"123"
],
[
true,
"456"
]
]"#]],
);
#[serde_as]
#[derive(Debug, Serialize)]
struct S5<'a>(
#[serde_as(as = "&BTreeMap<DisplayFromStr, &Vec<(_, _)>>")]
&'a Vec<(u32, &'a BTreeMap<bool, String>)>,
);
let bmap0 = vec![(false, "123".to_string()), (true, "456".to_string())]
.into_iter()
.collect();
let bmap1 = vec![(true, "Hello".to_string()), (false, "World".to_string())]
.into_iter()
.collect();
let vec = vec![(111, &bmap0), (999, &bmap1)];
check_serialization(
S5(&vec),
expect![[r#"
{
"111": [
[
false,
"123"
],
[
true,
"456"
]
],
"999": [
[
false,
"World"
],
[
true,
"Hello"
]
]
}"#]],
);
}
#[test]
fn test_big_arrays() {
// Single Big Array
#[serde_as]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct S1(#[serde_as(as = "[_; 64]")] [u8; 64]);
is_equal_compact(
S1([0; 64]),
expect![[
r#"[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"#
]],
);
// Too few entries
check_error_deserialization::<S1>(
r#"[0,0,0,0,0,0,0,0,0,0,0,0,0,0]"#,
expect![[r#"invalid length 14, expected an array of size 64 at line 1 column 29"#]],
);
// Too many entries
check_error_deserialization::<S1>(
r#"[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"#,
expect![[r#"trailing characters at line 1 column 130"#]],
);
// Single Big Array
#[serde_as]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct S2(#[serde_as(as = "[DisplayFromStr; 40]")] [u8; 40]);
is_equal_compact(
S2([0; 40]),
expect![[
r#"["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]"#
]],
);
// Nested Big Arrays
#[serde_as]
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct S3(#[serde_as(as = "[[_; 34]; 33]")] [[u8; 34]; 33]);
is_equal_compact(
S3([[0; 34]; 33]),
expect![[
r#"[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]"#
]],
);
}
#[test]
fn test_bytes() {
// The test case is copied from
// Original code by @dtolnay
use alloc::borrow::Cow;
use serde_test::{assert_de_tokens, assert_tokens, Token};
use serde_with::Bytes;
#[serde_as]
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Test<'a> {
#[serde_as(as = "Bytes")]
array: [u8; 52],
#[serde_as(as = "Bytes")]
slice: &'a [u8],
#[serde_as(as = "Bytes")]
vec: Vec<u8>,
#[serde_as(as = "Bytes")]
cow_slice: Cow<'a, [u8]>,
#[serde_as(as = "Box<Bytes>")]
boxed_array: Box<[u8; 52]>,
#[serde_as(as = "Bytes")]
boxed_array2: Box<[u8; 52]>,
#[serde_as(as = "Bytes")]
boxed_slice: Box<[u8]>,
#[serde_as(as = "Option<Bytes>")]
opt_slice: Option<&'a [u8]>,
#[serde_as(as = "Option<Bytes>")]
opt_vec: Option<Vec<u8>>,
#[serde_as(as = "Option<Bytes>")]
opt_cow_slice: Option<Cow<'a, [u8]>>,
}
let test = Test {
array: *b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz",
slice: b"...",
vec: b"...".to_vec(),
cow_slice: Cow::Borrowed(b"..."),
boxed_array: Box::new(*b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
boxed_array2: Box::new(*b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
boxed_slice: b"...".to_vec().into_boxed_slice(),
opt_slice: Some(b"..."),
opt_vec: Some(b"...".to_vec()),
opt_cow_slice: Some(Cow::Borrowed(b"...")),
};
assert_tokens(
&test,
&[
Token::Struct {
name: "Test",
len: 10,
},
Token::Str("array"),
Token::BorrowedBytes(b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
Token::Str("slice"),
Token::BorrowedBytes(b"..."),
Token::Str("vec"),
Token::Bytes(b"..."),
Token::Str("cow_slice"),
Token::BorrowedBytes(b"..."),
Token::Str("boxed_array"),
Token::BorrowedBytes(b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
Token::Str("boxed_array2"),
Token::BorrowedBytes(b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
Token::Str("boxed_slice"),
Token::Bytes(b"..."),
Token::Str("opt_slice"),
Token::Some,
Token::BorrowedBytes(b"..."),
Token::Str("opt_vec"),
Token::Some,
Token::Bytes(b"..."),
Token::Str("opt_cow_slice"),
Token::Some,
Token::BorrowedBytes(b"..."),
Token::StructEnd,
],
);
// Test string deserialization
assert_de_tokens(
&test,
&[
Token::Struct {
name: "Test",
len: 10,
},
Token::Str("array"),
Token::BorrowedStr("ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
Token::Str("slice"),
Token::BorrowedStr("..."),
Token::Str("vec"),
Token::Bytes(b"..."),
Token::Str("cow_slice"),
Token::BorrowedStr("..."),
Token::Str("boxed_array"),
Token::BorrowedStr("ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
Token::Str("boxed_array2"),
Token::BorrowedStr("ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
Token::Str("boxed_slice"),
Token::Bytes(b"..."),
Token::Str("opt_slice"),
Token::Some,
Token::BorrowedStr("..."),
Token::Str("opt_vec"),
Token::Some,
Token::Bytes(b"..."),
Token::Str("opt_cow_slice"),
Token::Some,
Token::BorrowedStr("..."),
Token::StructEnd,
],
);
}
#[test]
fn test_one_or_many_prefer_one() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S1Vec(#[serde_as(as = "OneOrMany<_>")] Vec<u32>);
// Normal
is_equal(S1Vec(vec![]), expect![[r#"[]"#]]);
is_equal(S1Vec(vec![1]), expect![[r#"1"#]]);
is_equal(
S1Vec(vec![1, 2, 3]),
expect![[r#"
[
1,
2,
3
]"#]],
);
check_deserialization(S1Vec(vec![1]), r#"1"#);
check_deserialization(S1Vec(vec![1]), r#"[1]"#);
check_error_deserialization::<S1Vec>(
r#"{}"#,
expect![[r#"
OneOrMany could not deserialize any variant:
One: invalid type: map, expected u32
Many: invalid type: map, expected a sequence"#]],
);
check_error_deserialization::<S1Vec>(
r#""xx""#,
expect![[r#"
OneOrMany could not deserialize any variant:
One: invalid type: string "xx", expected u32
Many: invalid type: string "xx", expected a sequence"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S2Vec(#[serde_as(as = "OneOrMany<DisplayFromStr>")] Vec<u32>);
// Normal
is_equal(S2Vec(vec![]), expect![[r#"[]"#]]);
is_equal(S2Vec(vec![1]), expect![[r#""1""#]]);
is_equal(
S2Vec(vec![1, 2, 3]),
expect![[r#"
[
"1",
"2",
"3"
]"#]],
);
check_deserialization(S2Vec(vec![1]), r#""1""#);
check_deserialization(S2Vec(vec![1]), r#"["1"]"#);
check_error_deserialization::<S2Vec>(
r#"{}"#,
expect![[r#"
OneOrMany could not deserialize any variant:
One: invalid type: map, expected a string
Many: invalid type: map, expected a sequence"#]],
);
check_error_deserialization::<S2Vec>(
r#""xx""#,
expect![[r#"
OneOrMany could not deserialize any variant:
One: invalid digit found in string
Many: invalid type: string "xx", expected a sequence"#]],
);
}
#[test]
fn test_one_or_many_prefer_many() {
use serde_with::formats::PreferMany;
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S1Vec(#[serde_as(as = "OneOrMany<_, PreferMany>")] Vec<u32>);
// Normal
is_equal(S1Vec(vec![]), expect![[r#"[]"#]]);
is_equal(
S1Vec(vec![1]),
expect![[r#"
[
1
]"#]],
);
is_equal(
S1Vec(vec![1, 2, 3]),
expect![[r#"
[
1,
2,
3
]"#]],
);
check_deserialization(S1Vec(vec![1]), r#"1"#);
check_deserialization(S1Vec(vec![1]), r#"[1]"#);
check_error_deserialization::<S1Vec>(
r#"{}"#,
expect![[r#"
OneOrMany could not deserialize any variant:
One: invalid type: map, expected u32
Many: invalid type: map, expected a sequence"#]],
);
check_error_deserialization::<S1Vec>(
r#""xx""#,
expect![[r#"
OneOrMany could not deserialize any variant:
One: invalid type: string "xx", expected u32
Many: invalid type: string "xx", expected a sequence"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S2Vec(#[serde_as(as = "OneOrMany<DisplayFromStr, PreferMany>")] Vec<u32>);
// Normal
is_equal(S2Vec(vec![]), expect![[r#"[]"#]]);
is_equal(
S2Vec(vec![1]),
expect![[r#"
[
"1"
]"#]],
);
is_equal(
S2Vec(vec![1, 2, 3]),
expect![[r#"
[
"1",
"2",
"3"
]"#]],
);
check_deserialization(S2Vec(vec![1]), r#""1""#);
check_deserialization(S2Vec(vec![1]), r#"["1"]"#);
check_error_deserialization::<S2Vec>(
r#"{}"#,
expect![[r#"
OneOrMany could not deserialize any variant:
One: invalid type: map, expected a string
Many: invalid type: map, expected a sequence"#]],
);
check_error_deserialization::<S2Vec>(
r#""xx""#,
expect![[r#"
OneOrMany could not deserialize any variant:
One: invalid digit found in string
Many: invalid type: string "xx", expected a sequence"#]],
);
}
/// Test that Cow borrows from the input
#[test]
fn test_borrow_cow_str() {
use alloc::borrow::Cow;
use serde_test::{assert_ser_tokens, Token};
use serde_with::BorrowCow;
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S1<'a> {
#[serde_as(as = "BorrowCow")]
cow: Cow<'a, str>,
#[serde_as(as = "Option<BorrowCow>")]
opt: Option<Cow<'a, str>>,
#[serde_as(as = "Box<BorrowCow>")]
b: Box<Cow<'a, str>>,
#[serde_as(as = "[BorrowCow; 1]")]
arr: [Cow<'a, str>; 1],
}
assert_ser_tokens(
&S1 {
cow: "abc".into(),
opt: Some("foo".into()),
b: Box::new("bar".into()),
arr: ["def".into()],
},
&[
Token::Struct { name: "S1", len: 4 },
Token::Str("cow"),
Token::BorrowedStr("abc"),
Token::Str("opt"),
Token::Some,
Token::BorrowedStr("foo"),
Token::Str("b"),
Token::BorrowedStr("bar"),
Token::Str("arr"),
Token::Tuple { len: 1 },
Token::BorrowedStr("def"),
Token::TupleEnd,
Token::StructEnd,
],
);
let s1: S1<'_> = serde_json::from_str(
r#"{
"cow": "abc",
"opt": "foo",
"b": "bar",
"arr": ["def"]
}"#,
)
.unwrap();
assert!(matches!(s1.cow, Cow::Borrowed(_)));
assert!(matches!(s1.opt, Some(Cow::Borrowed(_))));
assert!(matches!(*s1.b, Cow::Borrowed(_)));
assert!(matches!(s1.arr, [Cow::Borrowed(_)]));
let s1: S1<'_> = serde_json::from_str(
r#"{
"cow": "a\"c",
"opt": "f\"o",
"b": "b\"r",
"arr": ["d\"f"]
}"#,
)
.unwrap();
assert!(matches!(s1.cow, Cow::Owned(_)));
assert!(matches!(s1.opt, Some(Cow::Owned(_))));
assert!(matches!(*s1.b, Cow::Owned(_)));
assert!(matches!(s1.arr, [Cow::Owned(_)]));
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S2<'a> {
#[serde_as(as = "BorrowCow")]
cow: Cow<'a, [u8]>,
#[serde_as(as = "Option<BorrowCow>")]
opt: Option<Cow<'a, [u8]>>,
}
assert_ser_tokens(
&S2 {
cow: b"abc"[..].into(),
opt: Some(b"foo"[..].into()),
},
&[
Token::Struct { name: "S2", len: 2 },
Token::Str("cow"),
Token::Seq { len: Some(3) },
Token::U8(b'a'),
Token::U8(b'b'),
Token::U8(b'c'),
Token::SeqEnd,
Token::Str("opt"),
Token::Some,
Token::Seq { len: Some(3) },
Token::U8(b'f'),
Token::U8(b'o'),
Token::U8(b'o'),
Token::SeqEnd,
Token::StructEnd,
],
);
let tokens = &[
Token::Struct { name: "S2", len: 2 },
Token::Str("cow"),
Token::BorrowedBytes(b"abc"),
Token::Str("opt"),
Token::Some,
Token::BorrowedBytes(b"foo"),
Token::StructEnd,
];
let mut deser = serde_test::Deserializer::new(tokens);
let s2 = S2::deserialize(&mut deser).unwrap();
assert!(matches!(s2.cow, Cow::Borrowed(_)));
assert!(matches!(s2.opt, Some(Cow::Borrowed(_))));
// Check that a manual borrow works too
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S3<'a>(
#[serde(borrow = "'a")]
#[serde_as(as = "BorrowCow")]
Cow<'a, [u8]>,
// TODO add a test for Cow<'b, [u8; N]>
// #[serde_as(as = "BorrowCow")]
// Cow<'b, [u8; N]>,
);
let tokens = &[
Token::NewtypeStruct { name: "S3" },
Token::BorrowedBytes(b"abc"),
];
let mut deser = serde_test::Deserializer::new(tokens);
let s3 = S3::deserialize(&mut deser).unwrap();
assert!(matches!(s3.0, Cow::Borrowed(_)));
}
#[test]
fn test_boolfromint() {
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct S(#[serde_as(as = "BoolFromInt")] bool);
is_equal(S(false), expect![[r#"0"#]]);
is_equal(S(true), expect![[r#"1"#]]);
check_error_deserialization::<S>(
"2",
expect![[r#"invalid value: integer `2`, expected 0 or 1 at line 1 column 1"#]],
);
check_error_deserialization::<S>(
"-100",
expect![[r#"invalid value: integer `-100`, expected 0 or 1 at line 1 column 4"#]],
);
check_error_deserialization::<S>(
"18446744073709551615",
expect![[
r#"invalid value: integer `18446744073709551615`, expected 0 or 1 at line 1 column 20"#
]],
);
check_error_deserialization::<S>(
r#""""#,
expect![[r#"invalid type: string "", expected an integer 0 or 1 at line 1 column 2"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SStrict(#[serde_as(as = "BoolFromInt<Strict>")] bool);
is_equal(SStrict(false), expect![[r#"0"#]]);
is_equal(SStrict(true), expect![[r#"1"#]]);
check_error_deserialization::<SStrict>(
"2",
expect![[r#"invalid value: integer `2`, expected 0 or 1 at line 1 column 1"#]],
);
check_error_deserialization::<SStrict>(
"-100",
expect![[r#"invalid value: integer `-100`, expected 0 or 1 at line 1 column 4"#]],
);
check_error_deserialization::<SStrict>(
"18446744073709551615",
expect![[
r#"invalid value: integer `18446744073709551615`, expected 0 or 1 at line 1 column 20"#
]],
);
check_error_deserialization::<SStrict>(
r#""""#,
expect![[r#"invalid type: string "", expected an integer 0 or 1 at line 1 column 2"#]],
);
#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SFlexible(#[serde_as(as = "BoolFromInt<Flexible>")] bool);
is_equal(SFlexible(false), expect![[r#"0"#]]);
is_equal(SFlexible(true), expect![[r#"1"#]]);
check_deserialization::<SFlexible>(SFlexible(true), "2");
check_deserialization::<SFlexible>(SFlexible(true), "-100");
check_deserialization::<SFlexible>(SFlexible(true), "18446744073709551615");
check_error_deserialization::<SFlexible>(
r#""""#,
expect![[r#"invalid type: string "", expected an integer at line 1 column 2"#]],
);
}