Skip to main content

whisky_common/data/primitives/
map.rs

1use std::collections::HashMap;
2use std::iter::FromIterator;
3
4use serde_json::{json, Value};
5
6use crate::{data::PlutusDataJson, WError};
7
8#[derive(Clone, Debug, PartialEq)]
9pub struct Map<K, V>
10where
11    K: Clone + PlutusDataJson,
12    V: Clone + PlutusDataJson,
13{
14    pub map: Vec<(K, V)>,
15}
16
17impl<K, V> Map<K, V>
18where
19    K: Clone + PlutusDataJson,
20    V: Clone + PlutusDataJson,
21{
22    pub fn new(map_items: &[(K, V)]) -> Self {
23        Map {
24            map: map_items.to_vec(),
25        }
26    }
27
28    pub fn from_map(hash_map: HashMap<K, V>) -> Self {
29        Map {
30            map: hash_map.into_iter().collect(),
31        }
32    }
33
34    pub fn insert(&mut self, key: K, value: V) {
35        self.map.push((key, value));
36    }
37}
38
39// Implement FromIterator for Map to allow .collect() to work
40impl<K, V> FromIterator<(K, V)> for Map<K, V>
41where
42    K: Clone + PlutusDataJson,
43    V: Clone + PlutusDataJson,
44{
45    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
46        let mut map = Map { map: Vec::new() };
47        for (key, value) in iter {
48            map.insert(key, value);
49        }
50        map
51    }
52}
53
54impl<K, V> PlutusDataJson for Map<K, V>
55where
56    K: Clone + PlutusDataJson,
57    V: Clone + PlutusDataJson,
58{
59    fn to_json(&self) -> Value {
60        let map_items_json: Vec<(Value, Value)> = self
61            .map
62            .iter()
63            .map(|(k, v)| (k.clone().to_json(), v.clone().to_json()))
64            .collect();
65        pairs(map_items_json)
66    }
67
68    fn from_json(value: &Value) -> Result<Self, WError> {
69        let map_json = value
70            .get("map")
71            .ok_or_else(|| WError::new("Map::from_json", "missing 'map' field"))?
72            .as_array()
73            .ok_or_else(|| WError::new("Map::from_json", "invalid 'map' value"))?;
74
75        let map = map_json
76            .iter()
77            .enumerate()
78            .map(|(i, item)| {
79                let k_value = item
80                    .get("k")
81                    .ok_or_else(|| WError::new("Map::from_json", "missing 'k' in map entry"))?;
82                let v_value = item
83                    .get("v")
84                    .ok_or_else(|| WError::new("Map::from_json", "missing 'v' in map entry"))?;
85
86                let k = K::from_json(k_value).map_err(WError::add_err_trace(
87                    Box::leak(format!("Map::from_json[{}].k", i).into_boxed_str())
88                ))?;
89                let v = V::from_json(v_value).map_err(WError::add_err_trace(
90                    Box::leak(format!("Map::from_json[{}].v", i).into_boxed_str())
91                ))?;
92
93                Ok((k, v))
94            })
95            .collect::<Result<Vec<(K, V)>, WError>>()?;
96
97        Ok(Map { map })
98    }
99}
100
101pub fn pairs<K: Into<Value>, V: Into<Value>>(items_map: Vec<(K, V)>) -> Value {
102    let map: Vec<Value> = items_map
103        .into_iter()
104        .map(|(k, v)| json!({"k": k.into(), "v": v.into()}))
105        .collect();
106    json!({ "map": map })
107}
108
109pub fn assoc_map<K: Into<Value>, V: Into<Value>>(items_map: Vec<(K, V)>) -> Value {
110    pairs(items_map)
111}