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