aleo-struct-parser 0.2.1

Aleo Struct Parser
Documentation
use serde::de::{MapAccess, SeqAccess};
use serde_json::Value;

use crate::number::{try_parse_integer, try_parse_unsigned_integer};

struct AleoDeserializer {
    ast: Value,
}

impl AleoDeserializer {
    fn new(input: &str) -> Self {
        let ast = crate::parse_struct(input);
        Self { ast: ast }
    }

    fn from_value(value: Value) -> Self {
        Self { ast: value }
    }
}

macro_rules! impl_deserialize_any {
    ($($method:ident),*) => {
        $(
            fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
            where
                V: serde::de::Visitor<'de>,
            {
                self.deserialize_any(visitor)
            }
        )*
    };
}

impl<'de> serde::Deserializer<'de> for AleoDeserializer {
    type Error = serde_json::Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        match self.ast {
            serde_json::Value::Null => visitor.visit_none(),
            serde_json::Value::Bool(v) => visitor.visit_bool(v),
            serde_json::Value::Number(number) => visitor.visit_i64(number.as_i64().unwrap()),
            serde_json::Value::String(str) => {
                if let Some((number, bitsize)) = try_parse_unsigned_integer(&str) {
                    match bitsize {
                        8 => visitor.visit_u8(number as u8),
                        16 => visitor.visit_u16(number as u16),
                        32 => visitor.visit_u32(number as u32),
                        64 => visitor.visit_u64(number as u64),
                        _ => visitor.visit_u128(number),
                    }
                } else if let Some((number, bitsize)) = try_parse_integer(&str) {
                    match bitsize {
                        8 => visitor.visit_i8(number as i8),
                        16 => visitor.visit_i16(number as i16),
                        32 => visitor.visit_i32(number as i32),
                        64 => visitor.visit_i64(number as i64),
                        _ => visitor.visit_i128(number),
                    }
                } else {
                    visitor.visit_str(&str)
                }
            }
            serde_json::Value::Array(values) => {
                struct JsonSeqAccess {
                    iter: Vec<Value>,
                    idx: usize,
                }
                impl<'de> SeqAccess<'de> for JsonSeqAccess {
                    type Error = serde_json::Error;
                    fn next_element_seed<T>(
                        &mut self,
                        seed: T,
                    ) -> Result<Option<T::Value>, Self::Error>
                    where
                        T: serde::de::DeserializeSeed<'de>,
                    {
                        if self.idx >= self.iter.len() {
                            return Ok(None);
                        }
                        let res = self
                            .iter
                            .get(self.idx)
                            .map(|v| seed.deserialize(AleoDeserializer::from_value(v.clone())))
                            .transpose();
                        self.idx += 1;
                        res
                    }
                }
                visitor.visit_seq(JsonSeqAccess {
                    iter: values,
                    idx: 0,
                })
            }
            serde_json::Value::Object(map) => {
                struct JsonMapAccess {
                    iter: std::vec::IntoIter<(String, Value)>,
                    value: Option<Value>,
                }
                impl<'de> MapAccess<'de> for JsonMapAccess {
                    type Error = serde_json::Error;
                    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
                    where
                        K: serde::de::DeserializeSeed<'de>,
                    {
                        if let Some((k, v)) = self.iter.next() {
                            self.value = Some(v);
                            seed.deserialize(Value::String(k)).map(Some)
                        } else {
                            Ok(None)
                        }
                    }
                    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
                    where
                        V: serde::de::DeserializeSeed<'de>,
                    {
                        let v = self
                            .value
                            .take()
                            .expect("value must be available after key");
                        let de = AleoDeserializer::from_value(v);
                        seed.deserialize(de)
                    }
                }
                let entries: Vec<(String, Value)> = map.into_iter().collect();
                visitor.visit_map(JsonMapAccess {
                    iter: entries.into_iter(),
                    value: None,
                })
            }
        }
    }

    impl_deserialize_any! {
        deserialize_bool,
        deserialize_i8,
        deserialize_i16,
        deserialize_i32,
        deserialize_i64,
        deserialize_i128,
        deserialize_u8,
        deserialize_u16,
        deserialize_u32,
        deserialize_u64,
        deserialize_u128,
        deserialize_f32,
        deserialize_f64,
        deserialize_char,
        deserialize_str,
        deserialize_string,
        deserialize_bytes,
        deserialize_byte_buf,
        deserialize_option,
        deserialize_unit,
        deserialize_seq,
        deserialize_map,
        deserialize_identifier,
        deserialize_ignored_any
    }

    fn deserialize_unit_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_any(visitor)
    }

    fn deserialize_newtype_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_any(visitor)
    }

    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_any(visitor)
    }

    fn deserialize_tuple_struct<V>(
        self,
        _name: &'static str,
        _len: usize,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_any(visitor)
    }

    fn deserialize_struct<V>(
        self,
        _name: &'static str,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_any(visitor)
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_any(visitor)
    }
}

pub fn from_str<'a, T>(s: &'a str) -> Result<T, serde_json::Error>
where
    T: serde::Deserialize<'a>,
{
    let de = AleoDeserializer::new(s);
    T::deserialize(de)
}

#[derive(Debug)]
pub struct Address {
    pub address: String,
}

impl<'de> serde::Deserialize<'de> for Address {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let value = String::deserialize(deserializer)?;
        Ok(Address { address: value })
    }
}

#[cfg(test)]
mod tests {
    use serde::Deserialize;

    use super::*;

    #[test]
    fn test_parse_struct() {
        #[derive(Debug, Deserialize)]
        #[allow(dead_code)]
        struct TestStruct {
            program_id: String,
            function_name: String,
            arguments: Vec<Address>,
            struct2: TestStruct2,
            vec3: Vec<TestStruct2>,
        }

        #[derive(Debug, Deserialize)]
        #[allow(dead_code)]
        struct TestStruct2 {
            program_id: String,
            function_name: String,
            arguments: (Address, u64),
        }

        let input = r#"
            {
                program_id: puzzle_arcade_ticket_v002.aleo,
                function_name: mint,
                arguments: [
                    aleo13dn2lyphtrn8mujxcqt4vm2rc567k0s3gnnks985p0hhyvfc9yqqy6rdsl
                ],
                struct2: {
                    program_id: puzzle_arcade_ticket_v002.aleo,
                    function_name: mint,
                    arguments: [
                        aleo13dn2lyphtrn8mujxcqt4vm2rc567k0s3gnnks985p0hhyvfc9yqqy6rdsl,
                        1000u64
                    ]
                },
                vec3: [
                    {
                        program_id: puzzle_arcade_ticket_v002.aleo,
                        function_name: mint,
                        arguments: [
                            aleo13dn2lyphtrn8mujxcqt4vm2rc567k0s3gnnks985p0hhyvfc9yqqy6rdsl,
                            1000u64
                        ]
                    }
                ],
                extra: extra
            }
        "#;

        let result: TestStruct = from_str(input).unwrap();
        assert_eq!(result.program_id, "puzzle_arcade_ticket_v002.aleo");
        assert_eq!(result.struct2.arguments.1, 1000);

        let input = r#"
            [
                aleo13dn2lyphtrn8mujxcqt4vm2rc567k0s3gnnks985p0hhyvfc9yqqy6rdsl,
                1000u64
            ]
            "#;

        let result: (Address, u64) = from_str(input).unwrap();

        assert_eq!(result.1, 1000);

        let num: u64 = from_str("100u64").unwrap();
        assert_eq!(num, 100);
    }
}