alloy_dyn_abi/eip712/
parser.rsuse crate::{
eip712::resolver::{PropertyDef, TypeDef},
Error,
};
use alloc::vec::Vec;
use parser::{Error as TypeParserError, TypeSpecifier};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PropDef<'a> {
pub ty: TypeSpecifier<'a>,
pub name: &'a str,
}
impl PropDef<'_> {
pub fn to_owned(&self) -> PropertyDef {
PropertyDef::new(self.ty.span, self.name).unwrap()
}
}
impl<'a> TryFrom<&'a str> for PropDef<'a> {
type Error = Error;
#[inline]
fn try_from(input: &'a str) -> Result<Self, Self::Error> {
Self::parse(input)
}
}
impl<'a> PropDef<'a> {
pub fn parse(input: &'a str) -> Result<Self, Error> {
let (ty, name) =
input.rsplit_once(' ').ok_or_else(|| Error::invalid_property_def(input))?;
Ok(PropDef { ty: ty.trim().try_into()?, name: name.trim() })
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ComponentType<'a> {
pub span: &'a str,
pub type_name: &'a str,
pub props: Vec<PropDef<'a>>,
}
impl<'a> TryFrom<&'a str> for ComponentType<'a> {
type Error = Error;
#[inline]
fn try_from(input: &'a str) -> Result<Self, Self::Error> {
Self::parse(input)
}
}
impl<'a> ComponentType<'a> {
pub fn parse(input: &'a str) -> Result<Self, Error> {
let (name, props_str) = input
.split_once('(')
.ok_or_else(|| Error::TypeParser(TypeParserError::invalid_type_string(input)))?;
let mut props = vec![];
let mut depth = 1; let mut last = 0;
for (i, c) in props_str.chars().enumerate() {
match c {
'(' => depth += 1,
')' => {
depth -= 1;
if depth == 0 {
let candidate = &props_str[last..i];
if !candidate.is_empty() {
props.push(candidate.try_into()?);
}
last = i + 1;
break;
}
}
',' => {
if depth == 1 {
props.push(props_str[last..i].try_into()?);
last = i + 1;
}
}
_ => {}
}
}
Ok(Self { span: &input[..last + name.len() + 1], type_name: name, props })
}
pub fn to_owned(&self) -> TypeDef {
TypeDef::new(self.type_name, self.props.iter().map(|p| p.to_owned()).collect()).unwrap()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct EncodeType<'a> {
pub types: Vec<ComponentType<'a>>,
}
impl<'a> TryFrom<&'a str> for EncodeType<'a> {
type Error = Error;
#[inline]
fn try_from(input: &'a str) -> Result<Self, Self::Error> {
Self::parse(input)
}
}
impl<'a> EncodeType<'a> {
pub fn parse(input: &'a str) -> Result<Self, Error> {
let mut types = vec![];
let mut remaining = input;
while let Ok(t) = ComponentType::parse(remaining) {
remaining = &remaining[t.span.len()..];
types.push(t);
}
Ok(Self { types })
}
}
#[cfg(test)]
mod tests {
use super::*;
const EXAMPLE: &str = "Transaction(Person from,Person to,Asset tx)Asset(address token,uint256 amount)Person(address wallet,string name)";
#[test]
fn empty_type() {
let empty_domain_type =
ComponentType { span: "EIP712Domain()", type_name: "EIP712Domain", props: vec![] };
assert_eq!(ComponentType::parse("EIP712Domain()"), Ok(empty_domain_type.clone()));
assert_eq!(
EncodeType::try_from("EIP712Domain()"),
Ok(EncodeType { types: vec![empty_domain_type] })
);
}
#[test]
fn test_component_type() {
assert_eq!(
ComponentType::parse("Transaction(Person from,Person to,Asset tx)"),
Ok(ComponentType {
span: "Transaction(Person from,Person to,Asset tx)",
type_name: "Transaction",
props: vec![
"Person from".try_into().unwrap(),
"Person to".try_into().unwrap(),
"Asset tx".try_into().unwrap(),
],
})
);
}
#[test]
fn test_encode_type() {
assert_eq!(
EncodeType::parse(EXAMPLE),
Ok(EncodeType {
types: vec![
"Transaction(Person from,Person to,Asset tx)".try_into().unwrap(),
"Asset(address token,uint256 amount)".try_into().unwrap(),
"Person(address wallet,string name)".try_into().unwrap(),
]
})
);
}
}