plutus_parser/
primitives.rs

1use crate::{
2    AsPlutus, BigInt, BoundedBytes, Constr, DecodeError, Hash, KeyValuePairs, MaybeIndefArray,
3    PlutusData, create_array, create_constr, create_map, parse_constr, parse_map, parse_tuple,
4    parse_variant, type_name,
5};
6
7impl AsPlutus for PlutusData {
8    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
9        Ok(data)
10    }
11
12    fn to_plutus(self) -> PlutusData {
13        self
14    }
15}
16
17impl AsPlutus for Constr<PlutusData> {
18    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
19        let PlutusData::Constr(constr) = data else {
20            return Err(DecodeError::unexpected_type("Constr", type_name(&data)));
21        };
22        Ok(constr)
23    }
24
25    fn to_plutus(self) -> PlutusData {
26        PlutusData::Constr(self)
27    }
28}
29
30impl AsPlutus for KeyValuePairs<PlutusData, PlutusData> {
31    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
32        let PlutusData::Map(map) = data else {
33            return Err(DecodeError::unexpected_type("Map", type_name(&data)));
34        };
35        Ok(map)
36    }
37
38    fn to_plutus(self) -> PlutusData {
39        PlutusData::Map(self)
40    }
41}
42
43impl AsPlutus for MaybeIndefArray<PlutusData> {
44    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
45        let PlutusData::Array(array) = data else {
46            return Err(DecodeError::unexpected_type("Array", type_name(&data)));
47        };
48        Ok(array)
49    }
50
51    fn to_plutus(self) -> PlutusData {
52        PlutusData::Array(self)
53    }
54}
55
56impl AsPlutus for BigInt {
57    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
58        let PlutusData::BigInt(int) = data else {
59            return Err(DecodeError::unexpected_type("BigInt", type_name(&data)));
60        };
61        Ok(int)
62    }
63
64    fn to_plutus(self) -> PlutusData {
65        PlutusData::BigInt(self)
66    }
67}
68
69impl AsPlutus for BoundedBytes {
70    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
71        let PlutusData::BoundedBytes(bytes) = data else {
72            return Err(DecodeError::unexpected_type(
73                "BoundedBytes",
74                type_name(&data),
75            ));
76        };
77        Ok(bytes)
78    }
79
80    fn to_plutus(self) -> PlutusData {
81        PlutusData::BoundedBytes(self)
82    }
83}
84
85impl AsPlutus for bool {
86    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
87        let (variant, fields) = parse_constr(data)?;
88        if variant == 0 {
89            let [] = parse_variant(variant, fields)?;
90            return Ok(false);
91        }
92        if variant == 1 {
93            let [] = parse_variant(variant, fields)?;
94            return Ok(true);
95        }
96        Err(DecodeError::unexpected_variant(variant))
97    }
98
99    fn to_plutus(self) -> PlutusData {
100        match self {
101            false => create_constr(0, vec![]),
102            true => create_constr(1, vec![]),
103        }
104    }
105}
106
107macro_rules! impl_number {
108    () => {
109        fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
110            let PlutusData::BigInt(value) = data else {
111                return Err(DecodeError::unexpected_type("BigInt", type_name(&data)));
112            };
113            match value {
114                BigInt::Int(value) => {
115                    let value: i128 = value.into();
116                    Self::try_from(value).map_err(|_| DecodeError::out_of_range(value))
117                }
118                BigInt::BigUInt(value) => Err(DecodeError::out_of_range(format!(
119                    "0x{}",
120                    hex::encode(&*value)
121                ))),
122                BigInt::BigNInt(value) => Err(DecodeError::out_of_range(format!(
123                    "-1 - 0x{}",
124                    hex::encode(&*value)
125                ))),
126            }
127        }
128
129        fn to_plutus(self) -> PlutusData {
130            let val = self as i128;
131            PlutusData::BigInt(BigInt::Int(val.try_into().unwrap()))
132        }
133    };
134}
135
136impl AsPlutus for u8 {
137    impl_number!();
138
139    // Vec<u8> should be BoundedBytes
140    fn vec_from_plutus(data: PlutusData) -> Result<Vec<Self>, DecodeError> {
141        let bytes = BoundedBytes::from_plutus(data)?;
142        Ok(bytes.into())
143    }
144
145    fn vec_to_plutus(value: Vec<Self>) -> PlutusData {
146        let bytes = BoundedBytes::from(value);
147        PlutusData::BoundedBytes(bytes)
148    }
149
150    // [u8; N] should be BoundedBytes
151    fn array_from_plutus<const N: usize>(data: PlutusData) -> Result<[Self; N], DecodeError> {
152        let bytes = BoundedBytes::from_plutus(data)?;
153        let vec: Vec<u8> = bytes.into();
154        match vec.try_into() {
155            Ok(array) => Ok(array),
156            Err(v) => Err(DecodeError::wrong_length(N, v.len())),
157        }
158    }
159
160    fn array_to_plutus<const N: usize>(value: [Self; N]) -> PlutusData {
161        let bytes = BoundedBytes::from(value.to_vec());
162        PlutusData::BoundedBytes(bytes)
163    }
164}
165impl AsPlutus for u16 {
166    impl_number!();
167}
168impl AsPlutus for u32 {
169    impl_number!();
170}
171impl AsPlutus for u64 {
172    impl_number!();
173}
174impl AsPlutus for i8 {
175    impl_number!();
176}
177impl AsPlutus for i16 {
178    impl_number!();
179}
180impl AsPlutus for i32 {
181    impl_number!();
182}
183impl AsPlutus for i64 {
184    impl_number!();
185}
186
187macro_rules! impl_tuple {
188    ($($param:ident $index:expr),*) => {
189        impl<$($param),*> AsPlutus for ($($param),*)
190        where
191            $($param: AsPlutus),*
192        {
193            #[allow(non_snake_case)]
194            fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
195                let [$($param),*] = parse_tuple(data)?;
196                Ok(($(AsPlutus::from_plutus($param).map_err(|e| e.with_field_name($index))?),*))
197            }
198
199            #[allow(non_snake_case)]
200            fn to_plutus(self) -> PlutusData {
201                let ($($param),*) = self;
202                create_array(vec![$($param.to_plutus()),*])
203            }
204        }
205    };
206}
207
208impl_tuple!(T1 0, T2 1);
209impl_tuple!(T1 0, T2 1, T3 2);
210impl_tuple!(T1 0, T2 1, T3 2, T4 3);
211impl_tuple!(T1 0, T2 1, T3 2, T4 3, T5 4);
212impl_tuple!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5);
213impl_tuple!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6);
214impl_tuple!(T1 0, T2 1, T3 2, T4 3, T5 4, T6 5, T7 6, T8 7);
215
216impl AsPlutus for String {
217    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
218        let bytes = BoundedBytes::from_plutus(data)?;
219        String::from_utf8(bytes.to_vec())
220            .map_err(|err| DecodeError::custom(format!("error decoding string: {err}")))
221    }
222
223    fn to_plutus(self) -> PlutusData {
224        let bytes = BoundedBytes::from(self.into_bytes());
225        bytes.to_plutus()
226    }
227}
228
229impl<const BYTES: usize> AsPlutus for Hash<BYTES> {
230    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
231        let bytes: [u8; BYTES] = AsPlutus::from_plutus(data)?;
232        Ok(Hash::new(bytes))
233    }
234
235    fn to_plutus(self) -> PlutusData {
236        let bytes = BoundedBytes::from(self.to_vec());
237        bytes.to_plutus()
238    }
239}
240
241impl<T: AsPlutus> AsPlutus for Option<T> {
242    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
243        let (variant, fields) = parse_constr(data)?;
244        if variant == 0 {
245            let [value] = parse_variant(variant, fields)?;
246            return Ok(Some(T::from_plutus(value)?));
247        }
248        if variant == 1 {
249            let [] = parse_variant(variant, fields)?;
250            return Ok(None);
251        }
252        Err(DecodeError::unexpected_variant(variant))
253    }
254
255    fn to_plutus(self) -> PlutusData {
256        match self {
257            Some(value) => create_constr(0, vec![value.to_plutus()]),
258            None => create_constr(1, vec![]),
259        }
260    }
261}
262
263impl<T: AsPlutus, const N: usize> AsPlutus for [T; N] {
264    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
265        T::array_from_plutus(data)
266    }
267
268    fn to_plutus(self) -> PlutusData {
269        T::array_to_plutus(self)
270    }
271}
272
273impl<T: AsPlutus> AsPlutus for Vec<T> {
274    fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
275        T::vec_from_plutus(data)
276    }
277
278    fn to_plutus(self) -> PlutusData {
279        T::vec_to_plutus(self)
280    }
281}
282
283macro_rules! impl_map {
284    () => {
285        fn from_plutus(data: PlutusData) -> Result<Self, DecodeError> {
286            let mut map = Self::new();
287            for (index, (key, value)) in parse_map(data)?.into_iter().enumerate() {
288                let key = TKey::from_plutus(key)
289                    .map_err(|e| e.with_field_name(format!("[(key #{index})]")))?;
290                let value = TVal::from_plutus(value)
291                    .map_err(|e| e.with_field_name(format!("[(value #{index})]")))?;
292                map.insert(key, value);
293            }
294            Ok(map)
295        }
296
297        fn to_plutus(self) -> PlutusData {
298            let kvps = self
299                .into_iter()
300                .map(|(k, v)| (k.to_plutus(), v.to_plutus()))
301                .collect();
302            create_map(kvps)
303        }
304    };
305}
306
307impl<TKey: AsPlutus + std::hash::Hash + Eq, TVal: AsPlutus> AsPlutus
308    for indexmap::IndexMap<TKey, TVal>
309{
310    impl_map!();
311}
312
313impl<TKey: AsPlutus + std::hash::Hash + Eq, TVal: AsPlutus> AsPlutus
314    for std::collections::HashMap<TKey, TVal>
315{
316    impl_map!();
317}
318
319impl<TKey: AsPlutus + PartialOrd + Ord, TVal: AsPlutus> AsPlutus
320    for std::collections::BTreeMap<TKey, TVal>
321{
322    impl_map!();
323}