#single #serialize-deserialize #serde #vec

no-std serde_single_or_vec2

Type which can be deserialized from either a sequence or a single value

1 stable release

1.0.0 Sep 9, 2022

#1550 in Data structures

Download history 20/week @ 2024-08-26 9/week @ 2024-09-02 38/week @ 2024-09-09 46/week @ 2024-09-16 31/week @ 2024-09-23 30/week @ 2024-09-30 2/week @ 2024-10-07 12/week @ 2024-10-14 8/week @ 2024-10-21 37/week @ 2024-10-28 106/week @ 2024-11-04 37/week @ 2024-11-11 136/week @ 2024-11-18 9/week @ 2024-11-25 115/week @ 2024-12-02 73/week @ 2024-12-09

334 downloads per month

MIT/Apache

22KB
400 lines

serde_single_or_vec

This crate provides the SingleOrVec Type which allows parsing either a single type T or a vector of type T using serde. This is required when a server either returns an array if there are multiple values or one value if there is only one.

Example


#[derive(Deserialize, Serialize)]
struct Response {
    single: SingleOrVec<'static, u8>,
    multiple: SingleOrVec<'static, u8>,
}

let json = r#"{
  "single": 0,
  "multiple": [
    0,
    1,
    2
  ]
}"#;
let res: Response = serde_json::from_str(json).unwrap();
assert_eq!(json, &serde_json::to_string_pretty(&res).unwrap());

Format

By default the SingleOrVec Type deserializes its content either to a single value or an array if it contains multiple values. To change this behaviour, its possible to define the output format.


#[derive(Deserialize, Serialize)]
struct Response {
    single: SingleOrVec<'static, u8>,
    multiple: SingleOrVec<'static, u8>,
}

let json = "[0]";

let res: SingleOrVec<'_, u8, PreferSingle> = serde_json::from_str(json).unwrap();
assert_eq!("0", &serde_json::to_string(&res).unwrap());

let res: SingleOrVec<'_, u8, AlwaysVector> = serde_json::from_str(json).unwrap();
assert_eq!("[0]", &serde_json::to_string(&res).unwrap());

Storage Backend

The default Backend is a Vec<T> and thus always results in an allocation. An alternativ is to use a Cow<'_, T> as backend which only requires an allocation for a single value.

Note that this is only valid when using or serializing this value, deserialisation always allocates due to serde#1852

let json = "[0,1,2]";
let res: SingleOrVec<'_, u8, PreferSingle, Cow<'_, [u8]>> = serde_json::from_str(json).unwrap();
assert_eq!(json, &serde_json::to_string(&res).unwrap());

Custom Storage Type

Its also possible to implement Custom Storage Backends by using the Storage Trait.

use arrayvec::ArrayVec;

struct ArrayVecStorage {}

impl<T> Storage<'_, T> for ArrayVecStorage {
    type Backing = ArrayVec<[T; 4]>;

    fn single(ty: T) -> Self::Backing {
        let mut vec = ArrayVec::new();
        vec.push(ty);
        vec
    }

    fn get_first_with_len(b: &Self::Backing) -> Option<(&T, usize)> {
        b.split_first().map(|(t, r)| (t, r.len()))
    }
}

let json = "[0,1,2]";
let res: SingleOrVec<'_, u8, PreferSingle, ArrayVecStorage> = serde_json::from_str(json).unwrap();
assert_eq!(json, &serde_json::to_string(&res).unwrap());

let json = "0";
let res: SingleOrVec<'_, u8, PreferSingle, ArrayVecStorage> = serde_json::from_str(json).unwrap();
assert_eq!(json, &serde_json::to_string(&res).unwrap());

no_std

It is possible to use this crate with no_std, however, like serde, either std or alloc is required.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

License: MIT OR Apache-2.0

Dependencies

~0.3–1MB
~21K SLoC