// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
use super ::{ZeroMap2d, ZeroMap2dBorrowed, ZeroMap2dCursor};
use crate ::map::{MutableZeroVecLike, ZeroMapKV, ZeroVecLike};
use crate ::ZeroVec;
use alloc::vec::Vec;
use core::fmt;
use core::marker::PhantomData;
use serde::de::{
self , Deserialize, Deserializer, MapAccess, Visitor};
#[ cfg(feature =
"serde" )]
use serde::ser::{Serialize, SerializeMap, Serializer};
/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
#[ cfg(feature =
"serde" )]
impl <
'a, K0, K1, V> Serialize for ZeroMap2d<' a, K0, K1, V>
where
K0: ZeroMapKV<
'a> + Serialize + ?Sized + Ord,
K1: ZeroMapKV<
'a> + Serialize + ?Sized + Ord,
V: ZeroMapKV<
'a> + Serialize + ?Sized,
K0::Container: Serialize,
K1::Container: Serialize,
V::Container: Serialize,
{
fn serialize<S>(&
self , serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
let mut serde_map = serializer.serialize_map(None)?;
for cursor
in self .iter0() {
K0::Container::zvl_get_as_t(cursor.key0(), |k| serde_map.serialize_key(k))?;
let inner_map = ZeroMap2dInnerMapSerialize { cursor };
serde_map.serialize_value(&inner_map)?;
}
serde_map.end()
}
else {
(&
self .keys0, &
self .joiner, &
='color:red'>self .keys1, &
self .values).serialize(serializer)
}
}
}
/// Helper struct for human-serializing the inner map of a ZeroMap2d
#[ cfg(feature =
"serde" )]
struct ZeroMap2dInnerMapSerialize<
'a, ' l, K0, K1, V>
where
K0: ZeroMapKV<
'a> + ?Sized + Ord,
K1: ZeroMapKV<
'a> + ?Sized + Ord,
V: ZeroMapKV<
'a> + ?Sized,
{
pub cursor: ZeroMap2dCursor<
'l, ' a, K0, K1, V>,
}
#[ cfg(feature =
"serde" )]
impl <
'a, ' l, K0, K1, V> Serialize
for ZeroMap2dInnerMapSerialize<
'a, ' l, K0, K1, V>
where
K0: ZeroMapKV<
'a> + Serialize + ?Sized + Ord,
K1: ZeroMapKV<
'a> + Serialize + ?Sized + Ord,
V: ZeroMapKV<
'a> + Serialize + ?Sized,
K0::Container: Serialize,
K1::Container: Serialize,
V::Container: Serialize,
{
fn serialize<S>(&
self , serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut serde_map = serializer.serialize_map(None)?;
for (key1, v)
in self .cursor.iter1() {
K1::Container::zvl_get_as_t(key1, |k| serde_map.serialize_key(k))?;
V::Container::zvl_get_as_t(v, |v| serde_map.serialize_value(v))?;
}
serde_map.end()
}
}
/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
#[ cfg(feature =
"serde" )]
impl <
'a, K0, K1, V> Serialize for ZeroMap2dBorrowed<' a, K0, K1, V>
where
K0: ZeroMapKV<
'a> + Serialize + ?Sized + Ord,
K1: ZeroMapKV<
'a> + Serialize + ?Sized + Ord,
V: ZeroMapKV<
'a> + Serialize + ?Sized,
K0::Container: Serialize,
K1::Container: Serialize,
V::Container: Serialize,
{
fn serialize<S>(&
self , serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
ZeroMap2d::<K0, K1, V>::from(*
self ).serialize(serializer)
}
}
/// Modified example from https://serde.rs/deserialize-map.html
struct ZeroMap2dMapVisitor<
'a, K0, K1, V>
where
K0: ZeroMapKV<
'a> + ?Sized + Ord,
K1: ZeroMapKV<
'a> + ?Sized + Ord,
V: ZeroMapKV<
'a> + ?Sized,
{
#[ allow(clippy::type_complexity)]
// it's a marker type, complexity doesn't matter
marker: PhantomData<
fn () -> (&
'a K0::OwnedType, &' a K1::Owned
Type, &'a V::OwnedType)>,
}
impl <'a, K0, K1, V> ZeroMap2dMapVisitor<' a, K0, K1, V>
where
K0: ZeroMapKV<'a> + ?Sized + Ord,
K1: ZeroMapKV<'a> + ?Sized + Ord,
V: ZeroMapKV<'a> + ?Sized,
{
fn new() -> Self {
ZeroMap2dMapVisitor {
marker: PhantomData,
}
}
}
impl <'a, ' de, K0, K1, V> Visitor<'de> for ZeroMap2dMapVisitor<' a, K0, K1, V>
where
K0: ZeroMapKV<'a> + Ord + ?Sized + Ord,
K1: ZeroMapKV<'a> + Ord + ?Sized + Ord,
V: ZeroMapKV<'a> + ?Sized,
K1::Container: Deserialize<'de>,
V::Container: Deserialize<'de>,
K0::OwnedType: Deserialize<'de>,
K1::OwnedType: Deserialize<'de>,
V::OwnedType: Deserialize<'de>,
{
type Value = ZeroMap2d<'a, K0, K1, V>;
fn expecting(&self , formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map produced by ZeroMap2d" )
}
fn visit_map<M>(self , mut access: M) -> Result<Self ::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = ZeroMap2d::with_capacity(access.size_hint().unwrap_or(0 ));
// On the first level, pull out the K0s and a TupleVecMap of the
// K1s and Vs, and then collect them into a ZeroMap2d
while let Some((key0, inner_map)) =
access.next_entry::<K0::OwnedType, TupleVecMap<K1::OwnedType, V::OwnedType>>()?
{
for (key1, value) in inner_map.entries.iter() {
if map
.try_append(
K0::Container::owned_as_t(&key0),
K1::Container::owned_as_t(key1),
V::Container::owned_as_t(value),
)
.is_some()
{
return Err(de::Error::custom(
"ZeroMap2d's keys must be sorted while deserializing" ,
));
}
}
}
Ok(map)
}
}
/// Helper struct for human-deserializing the inner map of a ZeroMap2d
struct TupleVecMap<K1, V> {
pub entries: Vec<(K1, V)>,
}
struct TupleVecMapVisitor<K1, V> {
#[ allow(clippy::type_complexity)] // it's a marker type, complexity doesn't matter
marker: PhantomData<fn () -> (K1, V)>,
}
impl <K1, V> TupleVecMapVisitor<K1, V> {
fn new() -> Self {
TupleVecMapVisitor {
marker: PhantomData,
}
}
}
impl <'de, K1, V> Visitor<' de> for TupleVecMapVisitor<K1, V>
where
K1: Deserialize<'de>,
V: Deserialize<'de>,
{
type Value = TupleVecMap<K1, V>;
fn expecting(&self , formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an inner map produced by ZeroMap2d" )
}
fn visit_map<M>(self , mut access: M) -> Result<Self ::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut result = Vec::with_capacity(access.size_hint().unwrap_or(0 ));
while let Some((key1, value)) = access.next_entry::<K1, V>()? {
result.push((key1, value));
}
Ok(TupleVecMap { entries: result })
}
}
impl <'de, K1, V> Deserialize<' de> for TupleVecMap<K1, V>
where
K1: Deserialize<'de>,
V: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self , D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(TupleVecMapVisitor::<K1, V>::new())
}
}
/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
impl <'de, ' a, K0, K1, V> Deserialize<'de> for ZeroMap2d<' a, K0, K1, V>
where
K0: ZeroMapKV<'a> + Ord + ?Sized,
K1: ZeroMapKV<'a> + Ord + ?Sized,
V: ZeroMapKV<'a> + ?Sized,
K0::Container: Deserialize<'de>,
K1::Container: Deserialize<'de>,
V::Container: Deserialize<'de>,
K0::OwnedType: Deserialize<'de>,
K1::OwnedType: Deserialize<'de>,
V::OwnedType: Deserialize<'de>,
'de: ' a,
{
fn deserialize<D>(deserializer: D) -> Result<Self , D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
deserializer.deserialize_map(ZeroMap2dMapVisitor::<'a, K0, K1, V>::new())
} else {
let (keys0, joiner, keys1, values): (
K0::Container,
ZeroVec<u32>,
K1::Container,
V::Container,
) = Deserialize::deserialize(deserializer)?;
// Invariant 1: len(keys0) == len(joiner)
if keys0.zvl_len() != joiner.len() {
return Err(de::Error::custom(
"Mismatched keys0 and joiner sizes in ZeroMap2d" ,
));
}
// Invariant 2: len(keys1) == len(values)
if keys1.zvl_len() != values.zvl_len() {
return Err(de::Error::custom(
"Mismatched keys1 and value sizes in ZeroMap2d" ,
));
}
// Invariant 3: joiner is sorted
if !joiner.zvl_is_ascending() {
return Err(de::Error::custom(
"ZeroMap2d deserializing joiner array out of order" ,
));
}
// Invariant 4: the last element of joiner is the length of keys1
if let Some(last_joiner0) = joiner.last() {
if keys1.zvl_len() != last_joiner0 as usize {
return Err(de::Error::custom(
"ZeroMap2d deserializing joiner array malformed" ,
));
}
}
let result = Self {
keys0,
joiner,
keys1,
values,
};
// In debug mode, check the optional invariants, too
#[ cfg(debug_assertions)]
result.check_invariants();
Ok(result)
}
}
}
/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
impl <'de, ' a, K0, K1, V> Deserialize<'de> for ZeroMap2dBorrowed<' a, K0, K1, V>
where
K0: ZeroMapKV<'a> + Ord + ?Sized,
K1: ZeroMapKV<'a> + Ord + ?Sized,
V: ZeroMapKV<'a> + ?Sized,
K0::Container: Deserialize<'de>,
K1::Container: Deserialize<'de>,
V::Container: Deserialize<'de>,
K0::OwnedType: Deserialize<'de>,
K1::OwnedType: Deserialize<'de>,
V::OwnedType: Deserialize<'de>,
'de: ' a,
{
fn deserialize<D>(deserializer: D) -> Result<Self , D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
Err(de::Error::custom(
"ZeroMap2dBorrowed cannot be deserialized from human-readable formats" ,
))
} else {
let deserialized: ZeroMap2d<'a, K0, K1, V> = ZeroMap2d::deserialize(deserializer)?;
let keys0 = if let Some(keys0) = deserialized.keys0.zvl_as_borrowed_inner() {
keys0
} else {
return Err(de::Error::custom(
"ZeroMap2dBorrowed can only deserialize in zero-copy ways" ,
));
};
let joiner = if let Some(joiner) = deserialized.joiner.zvl_as_borrowed_inner() {
joiner
} else {
return Err(de::Error::custom(
"ZeroMap2dBorrowed can only deserialize in zero-copy ways" ,
));
};
let keys1 = if let Some(keys1) = deserialized.keys1.zvl_as_borrowed_inner() {
keys1
} else {
return Err(de::Error::custom(
"ZeroMap2dBorrowed can only deserialize in zero-copy ways" ,
));
};
let values = if let Some(values) = deserialized.values.zvl_as_borrowed_inner() {
values
} else {
return Err(de::Error::custom(
"ZeroMap2dBorrowed can only deserialize in zero-copy ways" ,
));
};
Ok(Self {
keys0,
joiner,
keys1,
values,
})
}
}
}
#[ cfg(test)]
#[ allow(non_camel_case_types)]
mod test {
use crate ::map2d::{ZeroMap2d, ZeroMap2dBorrowed};
#[ derive(serde::Serialize, serde::Deserialize)]
struct DeriveTest_ZeroMap2d<'data> {
#[ serde(borrow)]
_data: ZeroMap2d<'data, u16, str, [u8]>,
}
#[ derive(serde::Serialize, serde::Deserialize)]
struct DeriveTest_ZeroMap2dBorrowed<'data> {
#[ serde(borrow)]
_data: ZeroMap2dBorrowed<'data, u16, str, [u8]>,
}
const JSON_STR: &str = "{\" 1 \":{\" 1 \":\" uno\"},\" 2 \":{\" 2 \":\" dos\",\" 3 \":\" tres\"}}" ;
const BINCODE_BYTES: &[u8] = &[
8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 3 , 0 ,
0 , 0 , 6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 2 , 0 , 3 , 0 , 20 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 0 , 0 ,
3 , 0 , 6 , 0 , 117 , 110 , 111 , 100 , 111 , 115 , 116 , 114 , 101 , 115 ,
];
fn make_map() -> ZeroMap2d<'static, u32, u16, str> {
let mut map = ZeroMap2d::new();
map.insert(&1 , &1 , "uno" );
map.insert(&2 , &2 , "dos" );
map.insert(&2 , &3 , "tres" );
map
}
#[ test]
fn test_serde_json() {
let map = make_map();
let json_str = serde_json::to_string(&map).expect("serialize" );
assert_eq!(JSON_STR, json_str);
let new_map: ZeroMap2d<u32, u16, str> =
serde_json::from_str(&json_str).expect("deserialize" );
assert_eq!(format!("{new_map:?}" ), format!("{map:?}" ));
}
#[ test]
fn test_bincode() {
let map = make_map();
let bincode_bytes = bincode::serialize(&map).expect("serialize" );
assert_eq!(BINCODE_BYTES, bincode_bytes);
let new_map: ZeroMap2d<u32, u16, str> =
bincode::deserialize(&bincode_bytes).expect("deserialize" );
assert_eq!(
format!("{new_map:?}" ),
format!("{map:?}" ).replace("Owned" , "Borrowed" ),
);
let new_map: ZeroMap2dBorrowed<u32, u16, str> =
bincode::deserialize(&bincode_bytes).expect("deserialize" );
assert_eq!(
format!("{new_map:?}" ),
format!("{map:?}" )
.replace("Owned" , "Borrowed" )
.replace("ZeroMap2d" , "ZeroMap2dBorrowed" )
);
}
#[ test]
fn test_serde_rmp() {
let map = make_map();
let rmp_buf = rmp_serde::to_vec(&map).expect("serialize" );
let new_map: ZeroMap2d<u32, u16, str> = rmp_serde::from_slice(&rmp_buf).unwrap();
assert_eq!(map, new_map);
}
#[ test]
fn test_sample_bincode() {
// This is the map from the main docs page for ZeroMap2d
let mut map: ZeroMap2d<u16, u16, str> = ZeroMap2d::new();
map.insert(&1 , &2 , "three" );
let bincode_bytes: Vec<u8> = bincode::serialize(&map).expect("serialize" );
assert_eq!(
bincode_bytes.as_slice(),
&[
2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 2 , 0 , 11 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 116 , 104 , 114 , 101 , 101
]
);
}
}
Messung V0.5 in Prozent C=95 H=94 G=94
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-22)
¤
*© Formatika GbR, Deutschland