midnight_base_crypto/fab/
conversions.rs1use super::{Aligned, DynAligned};
15use super::{AlignedValue, Value, ValueAtom, ValueSlice};
16use crate::hash::{HashOutput, PERSISTENT_HASH_BYTES as PHB};
17use std::convert::Infallible;
18use std::error::Error;
19use std::fmt::{self, Debug, Display, Formatter};
20
21impl<T: Clone + Into<Value>> From<&T> for Value {
22 fn from(val: &T) -> Value {
23 val.clone().into()
24 }
25}
26
27macro_rules! forward_primitive_value {
28 ($($ty:ty),*) => {
29 $(
30 impl From<$ty> for Value {
31 fn from(val: $ty) -> Value {
32 Value(vec![val.into()])
33 }
34 }
35
36 impl TryFrom<&ValueSlice> for $ty {
37 type Error = InvalidBuiltinDecode;
38
39 fn try_from(value: &ValueSlice) -> Result<$ty, InvalidBuiltinDecode> {
40 if value.0.len() == 1 {
41 Ok(<$ty>::try_from(&value.0[0])?)
42 } else {
43 Err(InvalidBuiltinDecode(stringify!($ty)))
44 }
45 }
46 }
47 )*
48 }
49}
50
51impl From<u128> for ValueAtom {
52 fn from(val: u128) -> ValueAtom {
53 ValueAtom(val.to_le_bytes().to_vec()).normalize()
54 }
55}
56
57impl TryFrom<&ValueAtom> for u128 {
58 type Error = InvalidBuiltinDecode;
59
60 fn try_from(value: &ValueAtom) -> Result<Self, Self::Error> {
61 if value.0.len() <= 128 / 8 {
62 let mut le_bytes = [0u8; 128 / 8];
63 le_bytes[..value.0.len()].copy_from_slice(&value.0);
64 Ok(u128::from_le_bytes(le_bytes))
65 } else {
66 Err(InvalidBuiltinDecode("Fr"))
67 }
68 }
69}
70
71macro_rules! wrap_via_u128 {
72 ($($ty:ty),*) => {
73 $(
74 impl From<$ty> for ValueAtom {
75 fn from(val: $ty) -> ValueAtom {
76 u128::from(val).into()
77 }
78 }
79
80 impl TryFrom<&ValueAtom> for $ty {
81 type Error = InvalidBuiltinDecode;
82
83 fn try_from(value: &ValueAtom) -> Result<$ty, InvalidBuiltinDecode> {
84 u128::try_from(value)?.try_into().map_err(|_| InvalidBuiltinDecode(stringify!($ty)))
85 }
86 }
87 )*
88 }
89}
90
91impl From<bool> for ValueAtom {
92 fn from(value: bool) -> Self {
93 ValueAtom(vec![value as u8]).normalize()
94 }
95}
96
97impl TryFrom<&ValueAtom> for bool {
98 type Error = InvalidBuiltinDecode;
99
100 fn try_from(value: &ValueAtom) -> Result<Self, Self::Error> {
101 let byte = u8::try_from(value)?;
102 match byte {
103 0 => Ok(false),
104 1 => Ok(true),
105 _ => Err(InvalidBuiltinDecode("bool")),
106 }
107 }
108}
109
110wrap_via_u128!(u8, u16, u32, u64);
111
112forward_primitive_value!(HashOutput, u8, u16, u32, u64, u128, bool, Vec<u8>);
113
114impl From<HashOutput> for ValueAtom {
115 fn from(hash: HashOutput) -> ValueAtom {
116 ValueAtom(hash.0.to_vec()).normalize()
117 }
118}
119
120impl TryFrom<&ValueAtom> for HashOutput {
121 type Error = InvalidBuiltinDecode;
122
123 fn try_from(value: &ValueAtom) -> Result<HashOutput, InvalidBuiltinDecode> {
124 let mut buf = [0u8; PHB];
125 if value.0.len() <= PHB {
126 buf[..value.0.len()].copy_from_slice(&value.0[..]);
127 Ok(HashOutput(buf))
128 } else {
129 Err(InvalidBuiltinDecode("HashOutput"))
130 }
131 }
132}
133
134impl From<&[u8]> for ValueAtom {
135 fn from(val: &[u8]) -> ValueAtom {
136 let mut vec = val.to_vec();
137 while let Some(0u8) = vec.last() {
138 vec.pop();
139 }
140 ValueAtom(vec)
141 }
142}
143
144impl From<&ValueAtom> for Vec<u8> {
145 fn from(value: &ValueAtom) -> Vec<u8> {
146 value.0.clone()
147 }
148}
149
150impl From<()> for ValueAtom {
151 fn from((): ()) -> ValueAtom {
152 ValueAtom(vec![])
153 }
154}
155
156impl TryFrom<&ValueAtom> for () {
157 type Error = InvalidBuiltinDecode;
158
159 fn try_from(value: &ValueAtom) -> Result<(), InvalidBuiltinDecode> {
160 if value.0.is_empty() {
161 Ok(())
162 } else {
163 Err(InvalidBuiltinDecode("()"))
164 }
165 }
166}
167
168impl From<Vec<u8>> for ValueAtom {
169 fn from(mut value: Vec<u8>) -> ValueAtom {
170 while let Some(0u8) = value.last() {
171 value.pop();
172 }
173 ValueAtom(value)
174 }
175}
176
177macro_rules! tuple_conversions {
178 () => {
179 impl From<()> for Value {
180 fn from(_: ()) -> Value {
181 Value(Vec::new())
182 }
183 }
184
185 impl TryFrom<&ValueSlice> for () {
186 type Error = InvalidBuiltinDecode;
187
188 fn try_from(value: &ValueSlice) -> Result<(), InvalidBuiltinDecode> {
189 if value.0.is_empty() {
190 Ok(())
191 } else {
192 Err(InvalidBuiltinDecode("()"))
193 }
194 }
195 }
196 };
197 ($a:ident$(, $as:ident)*) => {
198 impl<$a$(, $as)*> From<($a, $($as, )*)> for Value
199 where Value: From<$a>$( + From<$as>)*
200 {
201 #[allow(non_snake_case)]
202 fn from(($a, $($as, )*): ($a, $($as, )*)) -> Value {
203 Value::concat([&Value::from($a)$(, &$as.into())*])
204 }
205 }
206
207 impl<$a$(, $as)*> TryFrom<&ValueSlice> for ($a, $($as, )*)
208 where
209 $a: Aligned + for<'a> TryFrom<&'a ValueSlice, Error = InvalidBuiltinDecode>,
210 $($as: Aligned + for<'a> TryFrom<&'a ValueSlice, Error = InvalidBuiltinDecode>,)*
211 {
212 type Error = InvalidBuiltinDecode;
213
214 #[allow(non_snake_case)]
215 fn try_from(mut val: &ValueSlice) -> Result<Self, InvalidBuiltinDecode> {
216 let err = || InvalidBuiltinDecode(stringify!(($a, $($as),*)));
217 let a_align = <$a>::alignment();
218 let a_end = a_align.consume_internal(val, &|idx: &mut usize, _| *idx += 1, &|idx| *idx, 0usize).ok_or_else(err)?;
219 let a_slice = ValueSlice::from_prim_slice(&val.0[..a_end]);
220 let a_val = <$a>::try_from(a_slice)?;
221 val = ValueSlice::from_prim_slice(&val.0[a_end..]);
222 $(
223 let as_align = <$as>::alignment();
224 let as_end = as_align.consume_internal(val, &|idx: &mut usize, _| *idx += 1, &|idx| *idx, 0usize).ok_or_else(err)?;
225 let as_slice = ValueSlice::from_prim_slice(&val.0[..as_end]);
226 let $as = <$as>::try_from(as_slice)?;
227 val = ValueSlice::from_prim_slice(&val.0[as_end..]);
228 )*
229 if val.0.is_empty() {
230 Ok((a_val, $($as, )*))
231 } else {
232 Err(err())
233 }
234 }
235 }
236
237 tuple_conversions!($($as),*);
238 }
239}
240
241tuple_conversions!(A, B, C, D, E, F, G, H, I, J, K);
242
243#[allow(clippy::from_over_into)]
244impl Into<Value> for AlignedValue {
245 fn into(self) -> Value {
246 self.value.clone()
247 }
248}
249
250impl<T: DynAligned> From<T> for AlignedValue
252where
253 Value: From<T>,
254{
255 fn from(inp: T) -> AlignedValue {
256 let align = inp.dyn_alignment();
257 let value = inp.into();
258 AlignedValue::new(value, align).expect("Aligned value should match alignment")
259 }
260}
261
262impl<T: Into<Value> + Default> From<Option<T>> for Value {
263 fn from(inp: Option<T>) -> Value {
264 let (is_some, value) = match inp {
265 Some(val) => (true, val),
266 None => (false, T::default()),
267 };
268 Value::concat([Value::from(is_some), value.into()].iter())
269 }
270}
271
272impl<const N: usize> From<[u8; N]> for ValueAtom {
273 fn from(inp: [u8; N]) -> ValueAtom {
274 let mut vec = inp.to_vec();
275 while let Some(0) = vec.last() {
276 vec.pop();
277 }
278 ValueAtom(vec)
279 }
280}
281
282impl<const N: usize> TryFrom<ValueAtom> for [u8; N] {
283 type Error = InvalidBuiltinDecode;
284
285 fn try_from(atom: ValueAtom) -> Result<[u8; N], InvalidBuiltinDecode> {
286 let mut buf = [0u8; N];
287 if atom.0.len() <= buf.len() {
288 buf[..atom.0.len()].copy_from_slice(&atom.0);
289 Ok(buf)
290 } else {
291 Err(InvalidBuiltinDecode(std::any::type_name::<[u8; N]>()))
292 }
293 }
294}
295
296impl<const N: usize> From<[u8; N]> for Value {
297 fn from(inp: [u8; N]) -> Value {
298 Value(vec![inp.into()])
299 }
300}
301
302impl<const N: usize> TryFrom<Value> for [u8; N] {
303 type Error = InvalidBuiltinDecode;
304
305 fn try_from(mut value: Value) -> Result<[u8; N], InvalidBuiltinDecode> {
306 if value.0.len() == 1 {
307 value.0.remove(0).try_into()
308 } else {
309 Err(InvalidBuiltinDecode(std::any::type_name::<[u8; N]>()))
310 }
311 }
312}
313
314#[derive(Debug, Clone, PartialEq, Eq)]
317pub struct InvalidBuiltinDecode(pub &'static str);
318
319impl Display for InvalidBuiltinDecode {
320 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
321 write!(
322 formatter,
323 "failed to decode for built-in type {} after successful typecheck",
324 self.0
325 )
326 }
327}
328
329impl From<Infallible> for InvalidBuiltinDecode {
330 fn from(e: Infallible) -> InvalidBuiltinDecode {
331 match e {}
332 }
333}
334
335impl Error for InvalidBuiltinDecode {}