use impl_serde::serialize as serde_hex;
use syn::spanned::Spanned;
use crate::ast;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SignatureTopicArg {
topic: [u8; 32],
}
impl SignatureTopicArg {
pub fn signature_topic(&self) -> [u8; 32] {
self.topic
}
}
impl From<&[u8; 32]> for SignatureTopicArg {
fn from(value: &[u8; 32]) -> Self {
Self { topic: *value }
}
}
impl TryFrom<&syn::Lit> for SignatureTopicArg {
type Error = syn::Error;
fn try_from(lit: &syn::Lit) -> Result<Self, Self::Error> {
if let syn::Lit::Str(s) = lit {
let bytes: [u8; 32] = serde_hex::from_hex(&s.value())
.map_err(|_| {
format_err_spanned!(
lit,
"`signature_topic` has invalid hex string",
)
})?
.try_into()
.map_err(|e: Vec<u8>| {
format_err_spanned!(
lit,
"`signature_topic` is expected to be 32-byte hex string. Found {} bytes",
e.len()
)
})?;
Ok(Self { topic: bytes })
} else {
Err(format_err_spanned!(
lit,
"Expected string literal argument for the `signature_topic`"
))
}
}
}
impl TryFrom<&ast::MetaValue> for SignatureTopicArg {
type Error = syn::Error;
fn try_from(value: &ast::MetaValue) -> Result<Self, Self::Error> {
if let ast::MetaValue::Lit(lit) = value {
Self::try_from(lit)
} else {
Err(format_err_spanned!(
value,
"Expected string argument for the `signature_topic`"
))
}
}
}
impl TryFrom<ast::AttributeArgs> for Option<SignatureTopicArg> {
type Error = syn::Error;
fn try_from(args: ast::AttributeArgs) -> Result<Self, Self::Error> {
let mut signature_topic: Option<SignatureTopicArg> = None;
for arg in args.into_iter() {
if arg.name().is_ident("hash") {
if signature_topic.is_some() {
return Err(format_err!(
arg.span(),
"encountered duplicate ink! event configuration argument"
));
}
signature_topic =
arg.value().map(SignatureTopicArg::try_from).transpose()?;
} else {
return Err(format_err_spanned!(
arg,
"encountered unknown or unsupported ink! event item configuration argument",
));
}
}
Ok(signature_topic)
}
}
impl TryFrom<&syn::MetaNameValue> for SignatureTopicArg {
type Error = syn::Error;
fn try_from(nv: &syn::MetaNameValue) -> Result<Self, Self::Error> {
if nv.path.is_ident("signature_topic") {
if let syn::Expr::Lit(lit_expr) = &nv.value {
Self::try_from(&lit_expr.lit)
} else {
Err(format_err_spanned!(&nv.value, "Expected literal argument"))
}
} else {
Err(format_err_spanned!(nv, "Expected `signature_topic` ident"))
}
}
}