1use anyhow::{anyhow, Context, Result};
2
3#[derive(Debug, Clone)]
5pub struct ParamInput {
6 pub name: String,
7 pub param_type: DynType,
8}
9
10#[cfg(feature = "pyo3")]
11impl<'a, 'py> pyo3::FromPyObject<'a, 'py> for ParamInput {
12 type Error = pyo3::PyErr;
13 fn extract(ob: pyo3::Borrowed<'a, 'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
14 use pyo3::types::PyAnyMethods;
15
16 let name = ob.getattr("name")?.extract::<String>()?;
17 let param_type = ob.getattr("param_type")?.extract::<DynType>()?;
18 Ok(ParamInput { name, param_type })
19 }
20}
21
22#[derive(Debug, Clone, PartialEq)]
24pub enum DynType {
25 I8,
26 I16,
27 I32,
28 I64,
29 I128,
30 U8,
31 U16,
32 U32,
33 U64,
34 U128,
35 Bool,
36 FixedArray(Box<DynType>, usize),
38 Array(Box<DynType>),
39 Struct(Vec<(String, DynType)>),
40 Enum(Vec<(String, Option<DynType>)>),
41 Option(Box<DynType>),
42}
43
44#[cfg(feature = "pyo3")]
45impl<'a, 'py> pyo3::FromPyObject<'a, 'py> for DynType {
46 type Error = pyo3::PyErr;
47 fn extract(ob: pyo3::Borrowed<'a, 'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
48 use pyo3::types::PyAnyMethods;
49 use pyo3::types::PyTypeMethods;
50
51 let variant_str: String = ob.get_type().name()?.to_string();
52 let variant_str = if variant_str == "str" {
54 ob.to_string()
55 } else {
56 variant_str
57 };
58
59 match variant_str.as_str() {
60 "i8" => Ok(DynType::I8),
61 "i16" => Ok(DynType::I16),
62 "i32" => Ok(DynType::I32),
63 "i64" => Ok(DynType::I64),
64 "i128" => Ok(DynType::I128),
65 "u8" => Ok(DynType::U8),
66 "u16" => Ok(DynType::U16),
67 "u32" => Ok(DynType::U32),
68 "u64" => Ok(DynType::U64),
69 "u128" => Ok(DynType::U128),
70 "bool" => Ok(DynType::Bool),
71 "FixedArray" => {
72 let inner_bound = ob
73 .getattr("element_type")
74 .context("Failed to retrieve FixedArray element type")?;
75 let size: usize = ob
76 .getattr("size")
77 .context("Failed to retrieve size")?
78 .extract::<usize>()?;
79 let inner_type = inner_bound.extract::<DynType>()?;
80 Ok(DynType::FixedArray(Box::new(inner_type), size))
81 }
82 "Array" => {
83 let inner_bound = ob
84 .getattr("element_type")
85 .context("Failed to retrieve Array element type")?;
86 let inner_type = inner_bound.extract::<DynType>()?;
87 Ok(DynType::Array(Box::new(inner_type)))
88 }
89 "Struct" => {
90 let py_fields = ob
91 .getattr("fields")
92 .context("Failed to retrieve Struct fields")?;
93 let mut fields: Vec<(String, DynType)> = Vec::new();
94 for field in py_fields.try_iter()? {
95 match field {
96 Ok(field) => {
97 let name = field
98 .getattr("name")
99 .context("Failed to retrieve Struct field name")?
100 .to_string();
101 let param_type = field
102 .getattr("element_type")
103 .context("Failed to retrieve Struct field type")?
104 .extract::<DynType>()?;
105 fields.push((name, param_type));
106 }
107 Err(e) => {
108 return Err(anyhow!(
109 "Could not convert Struct fields into an iterator. Error: {e:?}"
110 )
111 .into())
112 }
113 }
114 }
115 Ok(DynType::Struct(fields))
116 }
117 "Enum" => {
118 let py_variants = ob
119 .getattr("variants")
120 .context("Failed to retrieve Enum variants")?;
121 let mut variants: Vec<(String, Option<DynType>)> = Vec::new();
122 for variant in py_variants.try_iter()? {
123 match variant {
124 Ok(variant) => {
125 let name = variant
126 .getattr("name")
127 .context("Failed to retrieve Enum variant name")?
128 .to_string();
129 let param_type = variant
130 .getattr("element_type")
131 .context("Failed to retrieve Enum variant type")?;
132 if param_type.to_string().as_str() == "None" {
133 variants.push((name, None));
134 } else {
135 let param_type = param_type.extract::<DynType>()?;
136 variants.push((name, Some(param_type)));
137 }
138 }
139 Err(e) => {
140 return Err(anyhow!(
141 "Could not convert Enum variants into an iterator. Error: {e:?}"
142 ))
143 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
144 }
145 }
146 }
147 Ok(DynType::Enum(variants))
148 }
149 "Option" => {
150 let inner_bound = ob
151 .getattr("element_type")
152 .context("Failed to retrieve Option element type")?;
153 let inner_type = inner_bound.extract::<DynType>()?;
154 Ok(DynType::Option(Box::new(inner_type)))
155 }
156 _ => Err(anyhow!("Not yet implemented type: {variant_str}").into()),
157 }
158 }
159}
160
161#[derive(Debug, Clone)]
163pub enum DynValue {
164 I8(i8),
165 I16(i16),
166 I32(i32),
167 I64(i64),
168 I128(i128),
169 U8(u8),
170 U16(u16),
171 U32(u32),
172 U64(u64),
173 U128(u128),
174 Bool(bool),
175 Array(Vec<DynValue>),
177 Struct(Vec<(String, DynValue)>),
178 Enum(String, Option<Box<DynValue>>),
179 Option(Option<Box<DynValue>>),
180}
181
182pub fn deserialize_data(
199 data: &[u8],
200 params: &[ParamInput],
201 error_on_remaining: bool,
202) -> Result<Vec<DynValue>> {
203 let mut ix_values = Vec::with_capacity(params.len());
204 let mut remaining_data = data;
205
206 for param in params {
207 let (value, new_data) = deserialize_value(¶m.param_type, remaining_data)?;
208 ix_values.push(value);
209 remaining_data = new_data;
210 }
211
212 if error_on_remaining && !remaining_data.is_empty() {
213 return Err(anyhow!(
214 "Remaining data after deserialization: {remaining_data:?}"
215 ));
216 }
217
218 Ok(ix_values)
219}
220
221fn deserialize_value<'a>(param_type: &DynType, data: &'a [u8]) -> Result<(DynValue, &'a [u8])> {
237 match param_type {
238 DynType::Option(inner_type) => {
239 let value = data.first().context("Not enough data for option")?;
240 match value {
241 0 => Ok((DynValue::Option(None), &data[1..])),
242 1 => {
243 let (value, new_data) = deserialize_value(inner_type, &data[1..])?;
244 Ok((DynValue::Option(Some(Box::new(value))), new_data))
245 }
246 _ => Err(anyhow!("Invalid option value: {value}")),
247 }
248 }
249 DynType::I8 => {
250 if data.is_empty() {
251 return Err(anyhow!(
252 "Not enough data for i8: expected 1 byte, got {}",
253 data.len()
254 ));
255 }
256 let value = i8::from_le_bytes(data[..1].try_into().context("i8 conversion")?);
257
258 Ok((DynValue::I8(value), &data[1..]))
259 }
260 DynType::I16 => {
261 if data.len() < 2 {
262 return Err(anyhow!(
263 "Not enough data for i16: expected 2 bytes, got {}",
264 data.len()
265 ));
266 }
267 let value = i16::from_le_bytes(data[..2].try_into().context("i16 conversion")?);
268
269 Ok((DynValue::I16(value), &data[2..]))
270 }
271 DynType::I32 => {
272 if data.len() < 4 {
273 return Err(anyhow!(
274 "Not enough data for i32: expected 4 bytes, got {}",
275 data.len()
276 ));
277 }
278 let value = i32::from_le_bytes(data[..4].try_into().context("i32 conversion")?);
279
280 Ok((DynValue::I32(value), &data[4..]))
281 }
282 DynType::I64 => {
283 if data.len() < 8 {
284 return Err(anyhow!(
285 "Not enough data for i64: expected 8 bytes, got {}",
286 data.len()
287 ));
288 }
289 let value = i64::from_le_bytes(data[..8].try_into().context("i64 conversion")?);
290
291 Ok((DynValue::I64(value), &data[8..]))
292 }
293 DynType::I128 => {
294 if data.len() < 16 {
295 return Err(anyhow!(
296 "Not enough data for i128: expected 16 bytes, got {}",
297 data.len()
298 ));
299 }
300 let value = i128::from_le_bytes(data[..16].try_into().context("i128 conversion")?);
301
302 Ok((DynValue::I128(value), &data[16..]))
303 }
304 DynType::U8 => {
305 if data.is_empty() {
306 return Err(anyhow!("Not enough data for u8: expected 1 byte, got 0"));
307 }
308 let value = data[0];
309 Ok((DynValue::U8(value), &data[1..]))
310 }
311 DynType::U16 => {
312 if data.len() < 2 {
313 return Err(anyhow!(
314 "Not enough data for u16: expected 2 bytes, got {}",
315 data.len()
316 ));
317 }
318 let value = u16::from_le_bytes(data[..2].try_into().context("u16 conversion")?);
319
320 Ok((DynValue::U16(value), &data[2..]))
321 }
322 DynType::U32 => {
323 if data.len() < 4 {
324 return Err(anyhow!(
325 "Not enough data for u32: expected 4 bytes, got {}",
326 data.len()
327 ));
328 }
329 let value = u32::from_le_bytes(data[..4].try_into().context("u32 conversion")?);
330
331 Ok((DynValue::U32(value), &data[4..]))
332 }
333 DynType::U64 => {
334 if data.len() < 8 {
335 return Err(anyhow!(
336 "Not enough data for u64: expected 8 bytes, got {}",
337 data.len()
338 ));
339 }
340 let value = u64::from_le_bytes(data[..8].try_into().context("u64 conversion")?);
341
342 Ok((DynValue::U64(value), &data[8..]))
343 }
344 DynType::U128 => {
345 if data.len() < 16 {
346 return Err(anyhow!(
347 "Not enough data for u128: expected 16 bytes, got {}",
348 data.len()
349 ));
350 }
351 let value = u128::from_le_bytes(data[..16].try_into().context("u128 conversion")?);
352
353 Ok((DynValue::U128(value), &data[16..]))
354 }
355 DynType::Bool => {
356 if data.is_empty() {
357 return Err(anyhow!("Not enough data for bool: expected 1 byte, got 0"));
358 }
359 let value = data[0] != 0;
360 Ok((DynValue::Bool(value), &data[1..]))
361 }
362 DynType::FixedArray(inner_type, size) => {
363 let inner_type_size = check_type_size(inner_type)?;
364 let total_size = inner_type_size * size;
365
366 if data.len() < total_size {
367 return Err(anyhow!(
368 "Not enough data for fixed array: expected {} bytes, got {}",
369 total_size,
370 data.len()
371 ));
372 }
373 let value = data[..total_size]
374 .to_vec()
375 .chunks(inner_type_size)
376 .map(|chunk| {
377 let (value, _) = deserialize_value(inner_type, chunk)?;
378 Ok(value)
379 })
380 .collect::<Result<Vec<DynValue>>>()?;
381 Ok((DynValue::Array(value), &data[total_size..]))
382 }
383 DynType::Array(inner_type) => {
384 if data.len() < 4 {
385 return Err(anyhow!(
386 "Not enough data for vector length: expected 4 bytes, got {}",
387 data.len()
388 ));
389 }
390 let length =
391 u32::from_le_bytes(data[..4].try_into().context("array length conversion")?)
392 as usize;
393 let mut remaining_data = &data[4..];
394
395 let mut values = Vec::with_capacity(length);
396 for _ in 0..length {
397 let (value, new_data) = deserialize_value(inner_type, remaining_data)?;
398 values.push(value);
399 remaining_data = new_data;
400 }
401
402 Ok((DynValue::Array(values), remaining_data))
403 }
404 DynType::Struct(fields) => {
405 let mut values = Vec::new();
406 let mut remaining_data = data;
407 for field in fields {
408 let (value, new_data) = deserialize_value(&field.1, remaining_data)?;
409 values.push((field.0.clone(), value));
410 remaining_data = new_data;
411 }
412 Ok((DynValue::Struct(values), remaining_data))
413 }
414 DynType::Enum(variants) => {
415 if data.is_empty() {
416 return Err(anyhow!(
417 "Not enough data for enum: expected at least 1 byte for variant index"
418 ));
419 }
420 let variant_index = data[0] as usize;
421 let remaining_data = &data[1..];
422
423 if variant_index >= variants.len() {
424 return Err(anyhow!("Invalid enum variant index: {variant_index}"));
425 }
426
427 let (variant_name, variant_type) = &variants[variant_index];
428
429 if let Some(variant_type) = variant_type {
430 let (variant_value, new_data) = deserialize_value(variant_type, remaining_data)?;
431 Ok((
432 DynValue::Enum(variant_name.clone(), Some(Box::new(variant_value))),
433 new_data,
434 ))
435 } else {
436 Ok((DynValue::Enum(variant_name.clone(), None), remaining_data))
437 }
438 }
439 }
440}
441
442fn check_type_size(param_type: &DynType) -> Result<usize> {
443 match param_type {
444 DynType::U8 | DynType::I8 | DynType::Bool => Ok(1),
445 DynType::U16 | DynType::I16 => Ok(2),
446 DynType::U32 | DynType::I32 => Ok(4),
447 DynType::U64 | DynType::I64 => Ok(8),
448 DynType::U128 | DynType::I128 => Ok(16),
449 _ => Err(anyhow!("Unsupported primitive type for fixed array")),
450 }
451}