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