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