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);
}
}