use core::borrow::Borrow;
use crate::zbase::{ZBase, ZEntry, ZHashableEntry};
use crate::{Hashable, NounDecode, NounEncode};
use alloc::fmt::Debug;
#[cfg(feature = "wasm")]
use alloc::{boxed::Box, format, string::ToString};
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hashable, NounDecode, NounEncode)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi, type = "[K, V]"))]
pub struct ZMapEntry<K, V> {
key: K,
value: V,
}
impl<K: Hashable + NounEncode, V: NounEncode> ZEntry for ZMapEntry<K, V> {
type Key = K;
type Value = V;
type Pair = (K, V);
type BorrowPair<'a>
= (&'a K, &'a V)
where
K: 'a,
V: 'a;
fn key(&self) -> &Self::Key {
&self.key
}
fn value(&self) -> &Self::Value {
&self.value
}
fn value_mut(&mut self) -> &mut Self::Value {
&mut self.value
}
fn pair(&self) -> Self::BorrowPair<'_> {
(&self.key, &self.value)
}
fn into_key(self) -> Self::Key {
self.key
}
fn into_value(self) -> Self::Value {
self.value
}
fn into_pair(self) -> Self::Pair {
(self.key, self.value)
}
fn from_pair((key, value): Self::Pair) -> Self {
Self { key, value }
}
}
impl<K: Hashable + NounEncode, V: Hashable + NounEncode> ZHashableEntry for ZMapEntry<K, V> {
type HashableBorrowPair<'a>
= (&'a K, &'a V)
where
K: 'a,
V: 'a;
fn hashable_pair(&self) -> Self::HashableBorrowPair<'_> {
(&self.key, &self.value)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, NounDecode, NounEncode, Hashable)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ZMap<K, V>(pub ZBase<ZMapEntry<K, V>>);
impl<K, V> serde::Serialize for ZMap<K, V>
where
K: Hashable + NounEncode + serde::Serialize,
V: NounEncode + serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(None)?;
for entry in self.0.iter() {
seq.serialize_element(&entry)?;
}
seq.end()
}
}
impl<'de, K, V> serde::Deserialize<'de> for ZMap<K, V>
where
K: Hashable + NounEncode + serde::Deserialize<'de>,
V: NounEncode + serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Self(ZBase::deserialize(deserializer)?))
}
}
impl<K, V> Default for ZMap<K, V>
where
K: Hashable + NounEncode,
V: NounEncode,
{
fn default() -> Self {
Self(ZBase::default())
}
}
impl<K, V> core::ops::Deref for ZMap<K, V> {
type Target = ZBase<ZMapEntry<K, V>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<K, V> core::ops::DerefMut for ZMap<K, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<K, V> IntoIterator for ZMap<K, V>
where
K: Hashable + NounEncode,
V: NounEncode,
{
type Item = (K, V);
type IntoIter = crate::zbase::ZBaseIntoIterator<ZMapEntry<K, V>>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<K, V> FromIterator<(K, V)> for ZMap<K, V>
where
K: Hashable + NounEncode,
V: NounEncode,
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
Self(ZBase::from_iter(iter))
}
}
impl<K, V> From<ZMap<K, V>> for alloc::vec::Vec<(K, V)>
where
K: Hashable + NounEncode,
V: NounEncode,
{
fn from(map: ZMap<K, V>) -> Self {
map.into_iter().collect()
}
}
impl<'a, K, V> IntoIterator for &'a ZMap<K, V>
where
K: Hashable + NounEncode,
V: NounEncode,
{
type Item = (&'a K, &'a V);
type IntoIter = crate::zbase::ZBaseIterator<'a, ZMapEntry<K, V>>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<K, V> From<alloc::vec::Vec<(K, V)>> for ZMap<K, V>
where
K: Hashable + NounEncode,
V: NounEncode,
{
fn from(v: alloc::vec::Vec<(K, V)>) -> Self {
Self(crate::zbase::ZBase::from(v))
}
}
impl<K, V, const N: usize> From<[(K, V); N]> for ZMap<K, V>
where
K: Hashable + NounEncode,
V: NounEncode,
{
fn from(v: [(K, V); N]) -> Self {
Self(crate::zbase::ZBase::from(v))
}
}
impl<K: Hashable + NounEncode, V: NounEncode> ZMap<K, V> {
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, key: K, value: V) {
self.0.insert_entry(ZMapEntry { key, value });
}
pub fn get_key_value<Q: NounEncode + ?Sized>(&self, key: &Q) -> Option<(&K, &V)>
where
K: Borrow<Q>,
{
self.0.get_entry(key).map(|e| e.pair())
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
#[test]
fn test_zmap_encode_decode() {
let mut zm = ZMap::<String, u64>::new();
zm.insert("ver".to_string(), 10);
zm.insert("ve2".to_string(), 11);
let zm_noun = zm.to_noun();
let zm_decode = ZMap::<String, u64>::from_noun(&zm_noun).unwrap();
assert_eq!(Vec::from(zm), Vec::from(zm_decode));
}
#[test]
fn test_zmap_serde() {
let mut zm = ZMap::<String, (u64, u64)>::new();
zm.insert("ver".to_string(), (10, 12));
zm.insert("ve2".to_string(), (11, 13));
let json = serde_json::to_string(&zm).unwrap();
let zm2: ZMap<String, (u64, u64)> = serde_json::from_str(&json).unwrap();
assert_eq!(zm, zm2);
}
}