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 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 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}