cherry_svm_decode/
deserialize.rs

1use anyhow::{anyhow, Context, Result};
2
3/// Represents a parameter input with a name and dynamic type
4#[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/// Represents a dynamic type that can be deserialized from binary data
22#[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    /// Complex types
36    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        // If the type name is str, it means it's a custom type, and we need to get the actual DynType value
51        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: {:?}",
108                                e
109                            )
110                            .into())
111                        }
112                    }
113                }
114                Ok(DynType::Struct(fields))
115            }
116            "Enum" => {
117                let py_variants = ob
118                    .getattr("variants")
119                    .context("Failed to retrieve Enum variants")?;
120                let mut variants: Vec<(String, Option<DynType>)> = Vec::new();
121                for variant in py_variants.try_iter()? {
122                    match variant {
123                        Ok(variant) => {
124                            let name = variant
125                                .getattr("name")
126                                .context("Failed to retrieve Enum variant name")?
127                                .to_string();
128                            let param_type = variant
129                                .getattr("element_type")
130                                .context("Failed to retrieve Enum variant type")?;
131                            match param_type.to_string().as_str() {
132                                "None" => variants.push((name, None)),
133                                _ => {
134                                    let param_type = param_type.extract::<DynType>()?;
135                                    variants.push((name, Some(param_type)));
136                                }
137                            }
138                        }
139                        Err(e) => {
140                            return Err(anyhow!(
141                                "Could not convert Enum variants into an iterator. Error: {:?}",
142                                e
143                            )
144                            .into())
145                        }
146                    }
147                }
148                Ok(DynType::Enum(variants))
149            }
150            "Option" => {
151                let inner_bound = ob
152                    .getattr("element_type")
153                    .context("Failed to retrieve Option element type")?;
154                let inner_type = inner_bound.extract::<DynType>()?;
155                Ok(DynType::Option(Box::new(inner_type)))
156            }
157            _ => Err(anyhow!("Not yet implemented type: {}", variant_str).into()),
158        }
159    }
160}
161
162/// Represents a dynamically deserialized value
163#[derive(Debug, Clone)]
164pub enum DynValue {
165    I8(i8),
166    I16(i16),
167    I32(i32),
168    I64(i64),
169    I128(i128),
170    U8(u8),
171    U16(u16),
172    U32(u32),
173    U64(u64),
174    U128(u128),
175    Bool(bool),
176    /// Complex values
177    Array(Vec<DynValue>),
178    Struct(Vec<(String, DynValue)>),
179    Enum(String, Option<Box<DynValue>>),
180    Option(Option<Box<DynValue>>),
181}
182
183/// Deserializes binary data into a vector of dynamic values based on the provided parameter types
184///
185/// # Arguments
186/// * `data` - The binary data to deserialize
187/// * `params` - The parameter types that define the structure of the data
188///
189/// # Returns
190/// A vector of deserialized values matching the parameter types
191///
192/// # Errors
193/// Returns an error if:
194/// * There is not enough data to deserialize all parameters
195/// * The data format doesn't match the expected parameter types
196/// * There is remaining data after deserializing all parameters
197pub fn deserialize_data(data: &[u8], params: &[ParamInput]) -> Result<Vec<DynValue>> {
198    let mut ix_values = Vec::with_capacity(params.len());
199    let mut remaining_data = data;
200
201    for param in params {
202        // Deserialize value based on type
203        let (value, new_data) = deserialize_value(&param.param_type, remaining_data)?;
204        ix_values.push(value);
205        remaining_data = new_data;
206    }
207
208    if !remaining_data.is_empty() {
209        return Err(anyhow!(
210            "Remaining data after deserialization: {:?}",
211            remaining_data
212        ));
213    }
214
215    Ok(ix_values)
216}
217
218/// Deserializes a single value of the specified type from binary data
219///
220/// # Arguments
221/// * `param_type` - The type of value to deserialize
222/// * `data` - The binary data to deserialize from
223///
224/// # Returns
225/// A tuple containing:
226/// * The deserialized value
227/// * The remaining data after deserialization
228///
229/// # Errors
230/// Returns an error if:
231/// * There is not enough data to deserialize the value
232/// * The data format doesn't match the expected type
233fn deserialize_value<'a>(param_type: &DynType, data: &'a [u8]) -> Result<(DynValue, &'a [u8])> {
234    match param_type {
235        DynType::Option(inner_type) => {
236            let value = data.first().context("Not enough data for option")?;
237            match value {
238                0 => Ok((DynValue::Option(None), &data[1..])),
239                1 => {
240                    let (value, new_data) = deserialize_value(inner_type, &data[1..])?;
241                    Ok((DynValue::Option(Some(Box::new(value))), new_data))
242                }
243                _ => Err(anyhow!("Invalid option value: {}", value)),
244            }
245        }
246        DynType::I8 => {
247            if data.is_empty() {
248                return Err(anyhow!(
249                    "Not enough data for i8: expected 1 byte, got {}",
250                    data.len()
251                ));
252            }
253            let value = i8::from_le_bytes(data[..1].try_into().unwrap());
254            Ok((DynValue::I8(value), &data[1..]))
255        }
256        DynType::I16 => {
257            if data.len() < 2 {
258                return Err(anyhow!(
259                    "Not enough data for i16: expected 2 bytes, got {}",
260                    data.len()
261                ));
262            }
263            let value = i16::from_le_bytes(data[..2].try_into().unwrap());
264            Ok((DynValue::I16(value), &data[2..]))
265        }
266        DynType::I32 => {
267            if data.len() < 4 {
268                return Err(anyhow!(
269                    "Not enough data for i32: expected 4 bytes, got {}",
270                    data.len()
271                ));
272            }
273            let value = i32::from_le_bytes(data[..4].try_into().unwrap());
274            Ok((DynValue::I32(value), &data[4..]))
275        }
276        DynType::I64 => {
277            if data.len() < 8 {
278                return Err(anyhow!(
279                    "Not enough data for i64: expected 8 bytes, got {}",
280                    data.len()
281                ));
282            }
283            let value = i64::from_le_bytes(data[..8].try_into().unwrap());
284            Ok((DynValue::I64(value), &data[8..]))
285        }
286        DynType::I128 => {
287            if data.len() < 16 {
288                return Err(anyhow!(
289                    "Not enough data for i128: expected 16 bytes, got {}",
290                    data.len()
291                ));
292            }
293            let value = i128::from_le_bytes(data[..16].try_into().unwrap());
294            Ok((DynValue::I128(value), &data[16..]))
295        }
296        DynType::U8 => {
297            if data.is_empty() {
298                return Err(anyhow!("Not enough data for u8: expected 1 byte, got 0"));
299            }
300            let value = data[0];
301            Ok((DynValue::U8(value), &data[1..]))
302        }
303        DynType::U16 => {
304            if data.len() < 2 {
305                return Err(anyhow!(
306                    "Not enough data for u16: expected 2 bytes, got {}",
307                    data.len()
308                ));
309            }
310            let value = u16::from_le_bytes(data[..2].try_into().unwrap());
311            Ok((DynValue::U16(value), &data[2..]))
312        }
313        DynType::U32 => {
314            if data.len() < 4 {
315                return Err(anyhow!(
316                    "Not enough data for u32: expected 4 bytes, got {}",
317                    data.len()
318                ));
319            }
320            let value = u32::from_le_bytes(data[..4].try_into().unwrap());
321            Ok((DynValue::U32(value), &data[4..]))
322        }
323        DynType::U64 => {
324            if data.len() < 8 {
325                return Err(anyhow!(
326                    "Not enough data for u64: expected 8 bytes, got {}",
327                    data.len()
328                ));
329            }
330            let value = u64::from_le_bytes(data[..8].try_into().unwrap());
331            Ok((DynValue::U64(value), &data[8..]))
332        }
333        DynType::U128 => {
334            if data.len() < 16 {
335                return Err(anyhow!(
336                    "Not enough data for u128: expected 16 bytes, got {}",
337                    data.len()
338                ));
339            }
340            let value = u128::from_le_bytes(data[..16].try_into().unwrap());
341            Ok((DynValue::U128(value), &data[16..]))
342        }
343        DynType::Bool => {
344            if data.is_empty() {
345                return Err(anyhow!("Not enough data for bool: expected 1 byte, got 0"));
346            }
347            let value = data[0] != 0;
348            Ok((DynValue::Bool(value), &data[1..]))
349        }
350        DynType::FixedArray(inner_type, size) => {
351            let inner_type_size = check_type_size(inner_type)?;
352            let total_size = inner_type_size * size;
353
354            if data.len() < total_size {
355                return Err(anyhow!(
356                    "Not enough data for fixed array: expected {} bytes, got {}",
357                    total_size,
358                    data.len()
359                ));
360            }
361            let value = data[..total_size]
362                .to_vec()
363                .chunks(inner_type_size)
364                .map(|chunk| {
365                    let (value, _) = deserialize_value(inner_type, chunk)?;
366                    Ok(value)
367                })
368                .collect::<Result<Vec<DynValue>>>()?;
369            Ok((DynValue::Array(value), &data[total_size..]))
370        }
371        DynType::Array(inner_type) => {
372            if data.len() < 4 {
373                return Err(anyhow!(
374                    "Not enough data for vector length: expected 4 bytes, got {}",
375                    data.len()
376                ));
377            }
378            let length = u32::from_le_bytes(data[..4].try_into().unwrap()) as usize;
379            let mut remaining_data = &data[4..];
380
381            let mut values = Vec::with_capacity(length);
382            for _ in 0..length {
383                let (value, new_data) = deserialize_value(inner_type, remaining_data)?;
384                values.push(value);
385                remaining_data = new_data;
386            }
387
388            Ok((DynValue::Array(values), remaining_data))
389        }
390        DynType::Struct(fields) => {
391            let mut values = Vec::new();
392            let mut remaining_data = data;
393            for field in fields {
394                let (value, new_data) = deserialize_value(&field.1, remaining_data)?;
395                values.push((field.0.clone(), value));
396                remaining_data = new_data;
397            }
398            Ok((DynValue::Struct(values), remaining_data))
399        }
400        DynType::Enum(variants) => {
401            if data.is_empty() {
402                return Err(anyhow!(
403                    "Not enough data for enum: expected at least 1 byte for variant index"
404                ));
405            }
406            let variant_index = data[0] as usize;
407            let remaining_data = &data[1..];
408
409            if variant_index >= variants.len() {
410                return Err(anyhow!("Invalid enum variant index: {}", variant_index));
411            }
412
413            let (variant_name, variant_type) = &variants[variant_index];
414
415            if let Some(variant_type) = variant_type {
416                let (variant_value, new_data) = deserialize_value(variant_type, remaining_data)?;
417                Ok((
418                    DynValue::Enum(variant_name.clone(), Some(Box::new(variant_value))),
419                    new_data,
420                ))
421            } else {
422                Ok((DynValue::Enum(variant_name.clone(), None), remaining_data))
423            }
424        }
425    }
426}
427
428fn check_type_size(param_type: &DynType) -> Result<usize> {
429    match param_type {
430        DynType::U8 => Ok(1),
431        DynType::U16 => Ok(2),
432        DynType::U32 => Ok(4),
433        DynType::U64 => Ok(8),
434        DynType::U128 => Ok(16),
435        DynType::I8 => Ok(1),
436        DynType::I16 => Ok(2),
437        DynType::I32 => Ok(4),
438        DynType::I64 => Ok(8),
439        DynType::I128 => Ok(16),
440        DynType::Bool => Ok(1),
441        _ => Err(anyhow!("Unsupported primitive type for fixed array")),
442    }
443}