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}