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