This crate provides unofficial serde helpers to support converting a map to a sequence of named key-value pairs for human-readable encoding formats.
This allows for a stable schema in the face of a mutable map.
For example, let's say we have a map containing the values
[(1, "one"), (2, "two"), (3, "three")]
. Encoded to JSON this is:
json
{"1":"one","2":"two","3":"three"}
We cannot specify a schema for this JSON Object though unless the contents of the map are
guaranteed to always contain two entries under the keys 1
, 2
and 3
.
This crate allows for such a map to be encoded to a JSON Array of Objects, each containing exactly two elements with static names:
json
[{"key":1,"value":"one"},{"key":2,"value":"two"},{"key":3,"value":"three"}]
for which a schema can be generated.
Furthermore, this avoids encoding the key type of the map to a string.
By default, the key-value pairs will be given the labels "key" and "value", but this can be
modified by providing your own labels via a struct which implements KeyValueLabels
.
Note that for binary (non-human-readable) encoding formats, default serialization and deserialization is retained.
no_std
By default, the crate is no_std
, but uses alloc
. In this case, support for BTreeMap
s and
BTreeMap
-like types is provided.
If feature std
is enabled then support for HashMap
s and HashMap
-like types is also
provided, but no_std
support is disabled.
```rust use std::collections::BTreeMap; use serde::{Deserialize, Serialize}; use serdemapto_array::BTreeMapToArray;
struct Data {
#[serde(with = "BTreeMapToArray::
let mut data = Data::default(); data.inner.insert(1, "one".tostring()); data.inner.insert(2, "two".tostring());
asserteq!( serdejson::to_string(&data).unwrap(), r#"{"inner":[{"key":1,"value":"one"},{"key":2,"value":"two"}]}"# ); ```
```rust use std::collections::HashMap; use serde::{Deserialize, Serialize}; use serdemapto_array::{KeyValueLabels, HashMapToArray};
struct MyKeyValueLabels;
impl KeyValueLabels for MyKeyValueLabels { const KEY: &'static str = "id"; const VALUE: &'static str = "name"; }
struct Data {
#[serde(with = "HashMapToArray::
let mut data = Data::default(); data.inner.insert(1, "one".tostring()); data.inner.insert(2, "two".tostring()); // The hashmap orders the entries randomly. let expected_json = if *data.inner.keys().next().unwrap() == 1 { r#"{"inner":[{"id":1,"name":"one"},{"id":2,"name":"two"}]}"# } else { r#"{"inner":[{"id":2,"name":"two"},{"id":1,"name":"one"}]}"# };
asserteq!(serdejson::tostring(&data).unwrap(), expectedjson); ```
BTreeMap
-like type```rust use std::collections::{btreemap, BTreeMap}; use serde::{Deserialize, Serialize}; use serdemaptoarray::{BTreeMapToArray, DefaultLabels};
struct MyMap(BTreeMap
/// We need to implement IntoIterator
to allow serialization.
impl<'a> IntoIterator for &'a MyMap {
type Item = (&'a u64, &'a String);
type IntoIter = btreemap::Iter<'a, u64, String>;
fn intoiter(self) -> Self::IntoIter {
self.0.iter()
}
}
/// We need to implement From<BTreeMap>
to allow deserialization.
impl From
struct Data {
#[serde(with = "BTreeMapToArray::
HashMap
with a non-standard hasher```rust use std::collections::HashMap; use serde::{Deserialize, Serialize}; use hashhasher::HashBuildHasher; use serdemaptoarray::{DefaultLabels, HashMapToArray};
struct Data {
#[serde(with = "HashMapToArray::
HashMap
-like type```rust use std::collections::{hashmap::{self, RandomState}, HashMap}; use serde::{Deserialize, Serialize}; use serdemaptoarray::{DefaultLabels, HashMapToArray};
struct MyMap(HashMap
/// We need to implement IntoIterator
to allow serialization.
impl<'a> IntoIterator for &'a MyMap {
type Item = (&'a u64, &'a String);
type IntoIter = hashmap::Iter<'a, u64, String>;
fn intoiter(self) -> Self::IntoIter {
self.0.iter()
}
}
/// We need to implement From<HashMap>
to allow deserialization.
impl From
struct Data {
#[serde(with = "HashMapToArray::
serde-map-to-array
is distributed under the terms of both the MIT license and the Apache License (Version 2.0).
See LICENSE-MIT and LICENSE-APACHE for details.