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