use super::LiteMap;
use crate::store::*;
use alloc::vec::Vec;
use core::fmt;
use core::marker::PhantomData;
use serde_core::{
de::{MapAccess, SeqAccess, Visitor},
ser::{SerializeMap, SerializeSeq},
Deserialize, Deserializer, Serialize, Serializer,
};
impl<K, V, R> Serialize for LiteMap<K, V, R>
where
K: Serialize,
V: Serialize,
R: Store<K, V>,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
let k_is_num_or_string = self
.values
.lm_get(0)
.is_some_and(|(k, _)| super::serde_helpers::is_num_or_string(k));
if !k_is_num_or_string {
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for index in 0..self.len() {
#[expect(clippy::unwrap_used)] seq.serialize_element(&self.get_indexed(index).unwrap())?;
}
return seq.end();
}
}
let mut map = serializer.serialize_map(Some(self.len()))?;
for index in 0..self.len() {
#[expect(clippy::unwrap_used)] let (k, v) = self.get_indexed(index).unwrap();
map.serialize_entry(k, v)?;
}
map.end()
}
}
#[expect(clippy::type_complexity)]
struct LiteMapVisitor<K, V, R> {
marker: PhantomData<fn() -> LiteMap<K, V, R>>,
}
impl<K, V, R> LiteMapVisitor<K, V, R> {
fn new() -> Self {
Self {
marker: PhantomData,
}
}
}
impl<'de, K, V, R> Visitor<'de> for LiteMapVisitor<K, V, R>
where
K: Deserialize<'de> + Ord,
V: Deserialize<'de>,
R: StoreBulkMut<K, V>,
{
type Value = LiteMap<K, V, R>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map produced by LiteMap")
}
fn visit_seq<S>(self, mut access: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
let mut map = LiteMap::with_capacity(access.size_hint().unwrap_or(0));
let mut out_of_order = Vec::new();
while let Some((key, value)) = access.next_element()? {
if let Some((key, value)) = map.try_append(key, value) {
out_of_order.push((key, value));
}
}
if !out_of_order.is_empty() {
map.extend(out_of_order);
}
Ok(map)
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = LiteMap::with_capacity(access.size_hint().unwrap_or(0));
let mut out_of_order = Vec::new();
while let Some((key, value)) = access.next_entry()? {
if let Some((key, value)) = map.try_append(key, value) {
out_of_order.push((key, value));
}
}
if !out_of_order.is_empty() {
map.extend(out_of_order);
}
Ok(map)
}
}
impl<'de, K, V, R> Deserialize<'de> for LiteMap<K, V, R>
where
K: Ord + Deserialize<'de>,
V: Deserialize<'de>,
R: StoreBulkMut<K, V>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
deserializer.deserialize_any(LiteMapVisitor::new())
} else {
deserializer.deserialize_map(LiteMapVisitor::new())
}
}
}
#[cfg(test)]
mod test {
use crate::LiteMap;
use alloc::borrow::ToOwned;
use alloc::string::String;
fn get_simple_map() -> LiteMap<u32, String> {
[
(1, "one".to_owned()),
(2, "two".to_owned()),
(4, "four".to_owned()),
(5, "five".to_owned()),
]
.into_iter()
.collect()
}
fn get_tuple_map() -> LiteMap<(u32, String), String> {
[
((1, "en".to_owned()), "one".to_owned()),
((1, "zh".to_owned()), "一".to_owned()),
((2, "en".to_owned()), "two".to_owned()),
((2, "zh".to_owned()), "二".to_owned()),
((4, "en".to_owned()), "four".to_owned()),
((5, "en".to_owned()), "five".to_owned()),
((5, "zh".to_owned()), "五".to_owned()),
((7, "zh".to_owned()), "七".to_owned()),
]
.into_iter()
.collect()
}
#[test]
fn test_roundtrip_json() {
let map = get_simple_map();
let json = serde_json::to_string(&map).unwrap();
assert_eq!(
json,
"{\"1\":\"one\",\"2\":\"two\",\"4\":\"four\",\"5\":\"five\"}"
);
let deserialized: LiteMap<u32, String> = serde_json::from_str(&json).unwrap();
assert_eq!(map, deserialized);
let map = get_tuple_map();
let json = serde_json::to_string(&map).unwrap();
assert_eq!(
json,
"[[[1,\"en\"],\"one\"],[[1,\"zh\"],\"一\"],[[2,\"en\"],\"two\"],\
[[2,\"zh\"],\"二\"],[[4,\"en\"],\"four\"],[[5,\"en\"],\"five\"],\
[[5,\"zh\"],\"五\"],[[7,\"zh\"],\"七\"]]"
);
let deserialized: LiteMap<(u32, String), String> = serde_json::from_str(&json).unwrap();
assert_eq!(map, deserialized);
}
#[test]
fn test_roundtrip_postcard() {
let map = get_simple_map();
let postcard = postcard::to_stdvec(&map).unwrap();
let deserialized: LiteMap<u32, String> = postcard::from_bytes(&postcard).unwrap();
assert_eq!(map, deserialized);
let map = get_tuple_map();
let postcard = postcard::to_stdvec(&map).unwrap();
let deserialized: LiteMap<(u32, String), String> = postcard::from_bytes(&postcard).unwrap();
assert_eq!(map, deserialized);
}
#[test]
fn test_deserialize_capacity() {
for len in 0..50 {
let mut map = (0..len).map(|i| (i, i.to_string())).collect::<Vec<_>>();
let postcard = postcard::to_stdvec(&map).unwrap();
let deserialized: LiteMap<u32, String> = postcard::from_bytes(&postcard).unwrap();
assert_eq!(deserialized.values.capacity(), len);
assert_eq!(deserialized.values.len(), len);
rand::seq::SliceRandom::shuffle(&mut map[..], &mut rand::rng());
let postcard = postcard::to_stdvec(&map).unwrap();
let deserialized: LiteMap<u32, String> = postcard::from_bytes(&postcard).unwrap();
assert_eq!(deserialized.values.capacity(), len);
assert_eq!(deserialized.values.len(), len);
}
}
}