1use std::hash::Hash;
2
3#[cfg(feature = "lbf")]
4use lbr_prelude::json::{json_array, Json};
5use linked_hash_map::LinkedHashMap;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use crate::plutus_data::{IsPlutusData, PlutusData, PlutusDataError, PlutusType};
10
11#[derive(Debug, PartialEq, Eq, Clone, Default, PartialOrd, Ord, Hash)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17pub struct AssocMap<K, V>(pub Vec<(K, V)>);
18
19impl<K, V> AssocMap<K, V> {
20    pub fn new() -> Self {
21        AssocMap(Vec::new())
22    }
23
24    pub fn insert(&mut self, key: K, mut value: V) -> Option<V>
30    where
31        K: PartialEq,
32    {
33        let old_value = self.0.iter_mut().find(|(k, _v)| k == &key);
34        match old_value {
35            None => {
36                self.0.push((key, value));
37                None
38            }
39            Some((_, v)) => {
40                std::mem::swap(v, &mut value);
41                Some(value)
42            }
43        }
44    }
45
46    pub fn remove(&mut self, key: &K) -> Option<V>
50    where
51        K: PartialEq,
52        V: Clone,
53    {
54        let vec = &mut self.0;
55
56        let old_value = vec
57            .iter()
58            .enumerate()
59            .find_map(|(i, (k, _))| if k == key { Some(i) } else { None });
60        match old_value {
61            None => None,
62            Some(i) => {
63                let (_, v) = vec.remove(i);
64                Some(v)
65            }
66        }
67    }
68}
69
70impl<K: IsPlutusData, V: IsPlutusData> IsPlutusData for AssocMap<K, V> {
71    fn to_plutus_data(&self) -> PlutusData {
72        PlutusData::Map(
73            self.0
74                .iter()
75                .map(|(k, v)| (k.to_plutus_data(), v.to_plutus_data()))
76                .collect(),
77        )
78    }
79
80    fn from_plutus_data(plutus_data: &PlutusData) -> Result<Self, PlutusDataError> {
81        match plutus_data {
82            PlutusData::Map(pairs) => pairs
83                .iter()
84                .map(|(k, v)| Ok((K::from_plutus_data(k)?, V::from_plutus_data(v)?)))
85                .collect::<Result<Vec<(K, V)>, PlutusDataError>>()
86                .map(Self),
87            _ => Err(PlutusDataError::UnexpectedPlutusType {
88                got: From::from(plutus_data),
89                wanted: PlutusType::Map,
90            }),
91        }
92    }
93}
94
95impl<K, V> From<Vec<(K, V)>> for AssocMap<K, V> {
96    fn from(vec: Vec<(K, V)>) -> Self {
97        AssocMap(vec)
98    }
99}
100
101impl<K: Clone, V: Clone, const N: usize> From<[(K, V); N]> for AssocMap<K, V> {
102    fn from(vec: [(K, V); N]) -> Self {
103        AssocMap(vec.to_vec())
104    }
105}
106
107impl<K, V> From<AssocMap<K, V>> for Vec<(K, V)> {
108    fn from(m: AssocMap<K, V>) -> Self {
109        m.0
110    }
111}
112
113impl<K: Hash + Eq, V> From<AssocMap<K, V>> for LinkedHashMap<K, V> {
114    fn from(m: AssocMap<K, V>) -> Self {
115        m.0.into_iter().collect()
116    }
117}
118
119impl<K: Hash + Eq, V> From<LinkedHashMap<K, V>> for AssocMap<K, V> {
120    fn from(value: LinkedHashMap<K, V>) -> Self {
121        AssocMap(value.into_iter().collect())
122    }
123}
124
125#[cfg(feature = "lbf")]
126impl<K: Json, V: Json> Json for AssocMap<K, V> {
127    fn to_json(&self) -> serde_json::Value {
128        json_array(
129            self.0
130                .iter()
131                .map(|(k, v)| json_array(vec![k.to_json(), v.to_json()]))
132                .collect(),
133        )
134    }
135
136    fn from_json(value: &serde_json::Value) -> Result<Self, lbr_prelude::json::Error> {
137        let vec_of_vectors: Vec<Vec<serde_json::Value>> = Json::from_json(value)?;
138        let vec_of_pairs = vec_of_vectors
139            .into_iter()
140            .map(|vec| {
141                let [k, v]: [serde_json::Value; 2] =
142                    TryFrom::try_from(vec).map_err(|vec: Vec<_>| {
143                        lbr_prelude::json::Error::UnexpectedArrayLength {
144                            got: vec.len(),
145                            wanted: 2,
146                            parser: "v1::assoc_map::AssocMap".into(),
147                        }
148                    })?;
149
150                let k = K::from_json(&k)?;
151                let v = V::from_json(&v)?;
152
153                Ok((k, v))
154            })
155            .collect::<Result<Vec<(K, V)>, _>>()?;
156
157        Ok(Self(vec_of_pairs))
158    }
159}
160
161#[cfg(test)]
162mod test {
163    use super::*;
164
165    #[test]
166    fn assoc_map_insert() {
167        let mut assoc_map = AssocMap::new();
168
169        assoc_map.insert(1, "one");
170        assoc_map.insert(2, "to");
171        assoc_map.insert(3, "three");
172        assoc_map.insert(2, "two");
173
174        let expected = AssocMap::from([(1, "one"), (2, "two"), (3, "three")]);
175
176        assert_eq!(assoc_map, expected);
177    }
178
179    #[test]
180    fn assoc_map_remove() {
181        let mut assoc_map = AssocMap::from([(1, "one"), (2, "two"), (3, "three")]);
182
183        let removed = assoc_map.remove(&1);
184
185        let expected = AssocMap::from([(2, "two"), (3, "three")]);
186
187        assert_eq!(assoc_map, expected);
188        assert_eq!(removed, Some("one"))
189    }
190}