use serde::{
de::{Error, MapAccess, Visitor},
Deserialize, Deserializer,
};
use std::fmt;
use crate::{ParamType, TupleParam};
#[derive(Debug, Clone, PartialEq)]
pub struct Param {
pub name: String,
pub kind: ParamType,
}
impl<'a> Deserialize<'a> for Param {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(ParamVisitor)
}
}
struct ParamVisitor;
impl<'a> Visitor<'a> for ParamVisitor {
type Value = Param;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid event parameter spec")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'a>,
{
let mut name = None;
let mut kind = None;
let mut components = None;
while let Some(ref key) = map.next_key::<String>()? {
match key.as_ref() {
"name" => {
if name.is_some() {
return Err(Error::duplicate_field("name"));
}
name = Some(map.next_value()?);
}
"type" => {
if kind.is_some() {
return Err(Error::duplicate_field("kind"));
}
kind = Some(map.next_value()?);
}
"components" => {
if components.is_some() {
return Err(Error::duplicate_field("components"));
}
let component: Vec<TupleParam> = map.next_value()?;
components = Some(component)
}
_ => {}
}
}
let name = name.ok_or_else(|| Error::missing_field("name"))?;
let kind =
kind.ok_or_else(|| Error::missing_field("kind")).and_then(|param_type: ParamType| match param_type {
ParamType::Tuple(_) => {
let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
Ok(ParamType::Tuple(tuple_params.into_iter().map(|param| param.kind).collect()))
}
ParamType::Array(inner_param_type) => match *inner_param_type {
ParamType::Tuple(_) => {
let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
Ok(ParamType::Array(Box::new(ParamType::Tuple(
tuple_params.into_iter().map(|param| param.kind).collect(),
))))
}
_ => Ok(ParamType::Array(inner_param_type)),
},
ParamType::FixedArray(inner_param_type, size) => match *inner_param_type {
ParamType::Tuple(_) => {
let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
Ok(ParamType::FixedArray(
Box::new(ParamType::Tuple(tuple_params.into_iter().map(|param| param.kind).collect())),
size,
))
}
_ => Ok(ParamType::FixedArray(inner_param_type, size)),
},
_ => Ok(param_type),
})?;
Ok(Param { name, kind })
}
}
#[cfg(test)]
mod tests {
use crate::{Param, ParamType};
#[test]
fn param_deserialization() {
let s = r#"{
"name": "foo",
"type": "address"
}"#;
let deserialized: Param = serde_json::from_str(s).unwrap();
assert_eq!(deserialized, Param { name: "foo".to_owned(), kind: ParamType::Address });
}
#[test]
fn param_tuple_deserialization() {
let s = r#"{
"name": "foo",
"type": "tuple",
"components": [
{
"name": "amount",
"type": "uint48"
},
{
"name": "things",
"type": "tuple",
"components": [
{
"name": "baseTupleParam",
"type": "address"
}
]
}
]
}"#;
let deserialized: Param = serde_json::from_str(s).unwrap();
assert_eq!(
deserialized,
Param {
name: "foo".to_owned(),
kind: ParamType::Tuple(vec![ParamType::Uint(48), ParamType::Tuple(vec![ParamType::Address])]),
}
);
}
#[test]
fn param_tuple_array_deserialization() {
let s = r#"{
"name": "foo",
"type": "tuple[]",
"components": [
{
"name": "amount",
"type": "uint48"
},
{
"name": "to",
"type": "address"
},
{
"name": "from",
"type": "address"
}
]
}"#;
let deserialized: Param = serde_json::from_str(s).unwrap();
assert_eq!(
deserialized,
Param {
name: "foo".to_owned(),
kind: ParamType::Array(Box::new(ParamType::Tuple(vec![
ParamType::Uint(48),
ParamType::Address,
ParamType::Address
]))),
}
);
}
#[test]
fn param_tuple_fixed_array_deserialization() {
let s = r#"{
"name": "foo",
"type": "tuple[2]",
"components": [
{
"name": "amount",
"type": "uint48"
},
{
"name": "to",
"type": "address"
},
{
"name": "from",
"type": "address"
}
]
}"#;
let deserialized: Param = serde_json::from_str(s).unwrap();
assert_eq!(
deserialized,
Param {
name: "foo".to_owned(),
kind: ParamType::FixedArray(
Box::new(ParamType::Tuple(vec![ParamType::Uint(48), ParamType::Address, ParamType::Address])),
2
),
}
);
}
#[test]
fn param_tuple_with_nested_tuple_arrays_deserialization() {
let s = r#"{
"name": "foo",
"type": "tuple",
"components": [
{
"name": "bar",
"type": "tuple[]",
"components": [
{
"name": "a",
"type": "address"
}
]
},
{
"name": "baz",
"type": "tuple[42]",
"components": [
{
"name": "b",
"type": "address"
}
]
}
]
}"#;
let deserialized: Param = serde_json::from_str(s).unwrap();
assert_eq!(
deserialized,
Param {
name: "foo".to_owned(),
kind: ParamType::Tuple(vec![
ParamType::Array(Box::new(ParamType::Tuple(vec![ParamType::Address]))),
ParamType::FixedArray(Box::new(ParamType::Tuple(vec![ParamType::Address])), 42,)
]),
}
);
}
}