plutus_parser/
primitives.rs

1use std::{
2    collections::{BTreeMap, HashMap},
3    hash::Hash,
4};
5
6use indexmap::IndexMap;
7
8use crate::{
9    AsPlutus, BigInt, BoundedBytes, DecodeError, PlutusData, create_array, create_constr,
10    create_map, parse_constr, parse_map, parse_tuple, parse_variant, type_name,
11};
12
13impl AsPlutus for BigInt {
14    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
15        let PlutusData::BigInt(int) = data else {
16            return Err(DecodeError::UnexpectedType {
17                expected: "BigInt".to_string(),
18                actual: type_name(&data),
19            });
20        };
21        Ok(int)
22    }
23
24    fn to_plutus(self) -> PlutusData {
25        PlutusData::BigInt(self)
26    }
27}
28
29impl AsPlutus for BoundedBytes {
30    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
31        let PlutusData::BoundedBytes(bytes) = data else {
32            return Err(DecodeError::UnexpectedType {
33                expected: "BoundedBytes".to_string(),
34                actual: type_name(&data),
35            });
36        };
37        Ok(bytes)
38    }
39
40    fn to_plutus(self) -> PlutusData {
41        PlutusData::BoundedBytes(self)
42    }
43}
44
45impl AsPlutus for bool {
46    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
47        let (variant, fields) = parse_constr(data)?;
48        if variant == 0 {
49            let [] = parse_variant(variant, fields)?;
50            return Ok(false);
51        }
52        if variant == 1 {
53            let [] = parse_variant(variant, fields)?;
54            return Ok(true);
55        }
56        Err(DecodeError::UnexpectedVariant { variant })
57    }
58
59    fn to_plutus(self) -> PlutusData {
60        match self {
61            false => create_constr(0, vec![]),
62            true => create_constr(1, vec![]),
63        }
64    }
65}
66
67macro_rules! impl_number {
68    () => {
69        fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
70            let PlutusData::BigInt(BigInt::Int(value)) = data else {
71                return Err(DecodeError::UnexpectedType {
72                    expected: "BigInt".into(),
73                    actual: type_name(&data),
74                });
75            };
76            let value: i128 = value.into();
77            Ok(value as _)
78        }
79
80        fn to_plutus(self) -> PlutusData {
81            let val = self as i128;
82            PlutusData::BigInt(BigInt::Int(val.try_into().unwrap()))
83        }
84    };
85}
86
87impl AsPlutus for u8 {
88    impl_number!();
89
90    // Vec<u8> should be BoundedBytes
91    fn vec_from_plutus(data: PlutusData) -> Result<Vec<Self>, DecodeError> {
92        let bytes = BoundedBytes::from_plutus(data)?;
93        Ok(bytes.to_vec())
94    }
95
96    fn vec_to_plutus(value: Vec<Self>) -> PlutusData {
97        let bytes = BoundedBytes::from(value);
98        PlutusData::BoundedBytes(bytes)
99    }
100}
101impl AsPlutus for u16 {
102    impl_number!();
103}
104impl AsPlutus for u32 {
105    impl_number!();
106}
107impl AsPlutus for u64 {
108    impl_number!();
109}
110impl AsPlutus for i8 {
111    impl_number!();
112}
113impl AsPlutus for i16 {
114    impl_number!();
115}
116impl AsPlutus for i32 {
117    impl_number!();
118}
119impl AsPlutus for i64 {
120    impl_number!();
121}
122
123macro_rules! impl_tuple {
124    ($($param:ident),*) => {
125        impl<$($param),*> AsPlutus for ($($param),*)
126        where
127            $($param: AsPlutus),*
128        {
129            #[allow(non_snake_case)]
130            fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
131                let [$($param),*] = parse_tuple(data)?;
132                Ok(($(AsPlutus::from_plutus($param)?),*))
133            }
134
135            #[allow(non_snake_case)]
136            fn to_plutus(self) -> PlutusData {
137                let ($($param),*) = self;
138                create_array(vec![$($param.to_plutus()),*])
139            }
140        }
141    };
142}
143
144impl_tuple!(T1, T2);
145impl_tuple!(T1, T2, T3);
146impl_tuple!(T1, T2, T3, T4);
147impl_tuple!(T1, T2, T3, T4, T5);
148impl_tuple!(T1, T2, T3, T4, T5, T6);
149impl_tuple!(T1, T2, T3, T4, T5, T6, T7);
150impl_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);
151
152impl AsPlutus for String {
153    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
154        let bytes = BoundedBytes::from_plutus(data)?;
155        String::from_utf8(bytes.to_vec())
156            .map_err(|err| DecodeError::Custom(format!("error decoding string: {err}")))
157    }
158
159    fn to_plutus(self) -> PlutusData {
160        let bytes = BoundedBytes::from(self.into_bytes());
161        bytes.to_plutus()
162    }
163}
164
165impl<T: AsPlutus> AsPlutus for Option<T> {
166    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
167        let (variant, fields) = parse_constr(data)?;
168        if variant == 0 {
169            let [value] = parse_variant(variant, fields)?;
170            return Ok(Some(T::from_plutus(value)?));
171        }
172        if variant == 1 {
173            let [] = parse_variant(variant, fields)?;
174            return Ok(None);
175        }
176        Err(DecodeError::UnexpectedVariant { variant })
177    }
178
179    fn to_plutus(self) -> PlutusData {
180        match self {
181            Some(value) => create_constr(0, vec![value.to_plutus()]),
182            None => create_constr(1, vec![]),
183        }
184    }
185}
186
187impl<T: AsPlutus> AsPlutus for Vec<T> {
188    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
189        T::vec_from_plutus(data)
190    }
191
192    fn to_plutus(self) -> PlutusData {
193        T::vec_to_plutus(self)
194    }
195}
196
197macro_rules! impl_map {
198    () => {
199        fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
200            let mut map = Self::new();
201            for (key, value) in parse_map(data)? {
202                map.insert(TKey::from_plutus(key)?, TVal::from_plutus(value)?);
203            }
204            Ok(map)
205        }
206
207        fn to_plutus(self) -> PlutusData {
208            let kvps = self
209                .into_iter()
210                .map(|(k, v)| (k.to_plutus(), v.to_plutus()))
211                .collect();
212            create_map(kvps)
213        }
214    };
215}
216
217impl<TKey: AsPlutus + Hash + Eq, TVal: AsPlutus> AsPlutus for IndexMap<TKey, TVal> {
218    impl_map!();
219}
220
221impl<TKey: AsPlutus + Hash + Eq, TVal: AsPlutus> AsPlutus for HashMap<TKey, TVal> {
222    impl_map!();
223}
224
225impl<TKey: AsPlutus + PartialOrd + Ord, TVal: AsPlutus> AsPlutus for BTreeMap<TKey, TVal> {
226    impl_map!();
227}