Skip to main content

whisky_common/data/primitives/
tuple.rs

1use serde_json::{json, Value};
2
3use crate::{data::{PlutusData, PlutusDataJson}, WError};
4
5#[derive(Clone, Debug, PartialEq)]
6pub struct Tuple<T = PlutusData>
7where
8    T: Clone + PlutusDataJson,
9{
10    pub items: T,
11}
12
13impl<T> Tuple<T>
14where
15    T: Clone + PlutusDataJson,
16{
17    pub fn new(items: T) -> Self {
18        Tuple { items }
19    }
20}
21
22impl<T> PlutusDataJson for Tuple<T>
23where
24    T: Clone + PlutusDataJson,
25{
26    fn to_json(&self) -> Value {
27        let items_json = self.items.to_constr_field();
28        tuple(items_json)
29    }
30
31    fn from_json(value: &Value) -> Result<Self, WError> {
32        // Tuple is stored as {"list": [...]}
33        let list = value
34            .get("list")
35            .ok_or_else(|| WError::new("Tuple::from_json", "missing 'list' field"))?;
36
37        let items = T::from_json(list)
38            .map_err(WError::add_err_trace("Tuple::from_json"))?;
39
40        Ok(Tuple { items })
41    }
42}
43
44pub fn tuple<T: Into<Value>>(p_tuple: Vec<T>) -> Value {
45    let list: Vec<Value> = p_tuple.into_iter().map(|item| item.into()).collect();
46    json!({ "list": list })
47}
48
49#[macro_export]
50macro_rules! impl_plutus_data_tuple {
51    ( $( $name:ident )+ ) => {
52        #[allow(non_snake_case)]
53        impl<$($name,)+> PlutusDataJson for ($($name,)+)
54        where
55            $($name: PlutusDataJson + Clone,)+
56        {
57            fn to_json(&self) -> Value {
58                json!(self.to_constr_field())
59            }
60            fn to_constr_field(&self) -> Vec<Value> {
61                let ($($name,)+) = self.clone();
62                vec![$($name.to_json(),)+]
63            }
64            fn from_json(value: &Value) -> Result<Self, WError> {
65                let arr = value
66                    .as_array()
67                    .ok_or_else(|| WError::new("tuple::from_json", "expected array"))?;
68
69                let mut iter = arr.iter();
70                $(
71                    let $name = {
72                        let item = iter.next()
73                            .ok_or_else(|| WError::new("tuple::from_json", "not enough elements"))?;
74                        $name::from_json(item)
75                            .map_err(WError::add_err_trace("tuple::from_json"))?
76                    };
77                )+
78
79                Ok(($($name,)+))
80            }
81        }
82    }
83}
84
85impl_plutus_data_tuple!(T1);
86impl_plutus_data_tuple!(T1 T2);
87impl_plutus_data_tuple!(T1 T2 T3);
88impl_plutus_data_tuple!(T1 T2 T3 T4);
89impl_plutus_data_tuple!(T1 T2 T3 T4 T5);