serde_single_or_vec

Crates.ioserde_single_or_vec
lib.rsserde_single_or_vec
version1.0.1
sourcesrc
created_at2020-11-13 13:23:36.399799
updated_at2020-11-16 08:57:04.602803
descriptionType which can be deserialized from either a sequence or a single value
homepage
repositoryhttps://github.com/mettke/serde_single_or_vec
max_upload_size
id311934
size35,211
Marc Mettke (mettke)

documentation

README

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

Commit count: 3

cargo fmt