leapfrog 0.3.3

A fast, lock-free concurrent hash map
Documentation
use crate::{LeapMap, Value};

use core::{
    fmt,
    hash::{BuildHasher, Hash},
    marker::PhantomData,
};

use serde_crate::{
    de::{Deserialize, MapAccess, Visitor},
    ser::{Serialize, SerializeMap, Serializer},
    Deserializer,
};

#[cfg(feature = "stable_alloc")]
use allocator_api2::alloc::{Allocator, Global};
#[cfg(not(feature = "stable_alloc"))]
use core::alloc::Allocator;
#[cfg(not(feature = "stable_alloc"))]
use std::alloc::Global;

pub struct LeapMapVisitor<K, V, H> {
    marker: PhantomData<fn() -> LeapMap<K, V, H, Global>>,
}

impl<K, V, H> LeapMapVisitor<K, V, H>
where
    K: Eq + Hash,
    V: Value,
    H: BuildHasher + Clone,
{
    fn new() -> Self {
        LeapMapVisitor {
            marker: PhantomData,
        }
    }
}

impl<'de, K, V, H> Visitor<'de> for LeapMapVisitor<K, V, H>
where
    K: Deserialize<'de> + Eq + Hash + Copy + std::fmt::Debug,
    V: Deserialize<'de> + Value,
    H: BuildHasher + Clone + Default,
{
    type Value = LeapMap<K, V, H, Global>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a LeapMap")
    }

    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let size = access.size_hint().unwrap_or(4);
        let map = LeapMap::with_capacity_and_hasher(size, Default::default());

        while let Some((key, value)) = access.next_entry()? {
            map.insert(key, value);
        }

        Ok(map)
    }
}

impl<'de, K, V, H> Deserialize<'de> for LeapMap<K, V, H, Global>
where
    K: Deserialize<'de> + Eq + Hash + Copy + std::fmt::Debug,
    V: Deserialize<'de> + Value,
    H: BuildHasher + Clone + Default,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_map(LeapMapVisitor::<K, V, H>::new())
    }
}

impl<K, V, H, A> Serialize for LeapMap<K, V, H, A>
where
    K: Serialize + Eq + Hash + Copy,
    V: Serialize + Value,
    H: BuildHasher + Clone + Default,
    A: Allocator,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut map = serializer.serialize_map(Some(self.len()))?;

        for mut item_ref in self.iter() {
            if let Some((k, v)) = item_ref.key_value() {
                map.serialize_entry(&k, &v)?;
            }
        }

        map.end()
    }
}

#[cfg(test)]
mod test {
    use crate::LeapMap;

    #[test]
    fn leapmap_serde() {
        let map = LeapMap::<u32, u8>::new();

        map.insert(0, 11);
        map.insert(1, 12);
        map.insert(2, 13);
        map.insert(3, 14);
        map.insert(4, 15);
        map.insert(5, 16);

        let serialized = serde_json::to_string(&map).expect("Couldn't serialize map");
        let deserialized: LeapMap<u32, u8> =
            serde_json::from_str(&serialized).expect("Couldn't deserialize map");

        assert_eq!(deserialized.get(&0).unwrap().value(), Some(11));
        assert_eq!(deserialized.get(&1).unwrap().value(), Some(12));
        assert_eq!(deserialized.get(&2).unwrap().value(), Some(13));
        assert_eq!(deserialized.get(&3).unwrap().value(), Some(14));
        assert_eq!(deserialized.get(&4).unwrap().value(), Some(15));
        assert_eq!(deserialized.get(&5).unwrap().value(), Some(16));
    }
}