use quote::ToTokens;
use syn::{Error, Field, Fields, ItemStruct, Result};
#[derive(Debug, PartialEq)]
pub(crate) enum FieldAttribute {
Hash,
Skip,
Flatten,
None,
}
#[derive(Debug, PartialEq)]
pub(crate) enum FieldType {
VecU8,
OptionVecU8,
Option,
Pubkey,
U8Array,
OptionU8Array,
Default,
}
pub(crate) fn validate_input(input: &ItemStruct) -> Result<()> {
match &input.fields {
Fields::Named(_) => (),
_ => {
return Err(Error::new_spanned(
input,
"Only structs with named fields are supported",
))
}
};
let field_count = input.fields.iter().count();
if field_count >= 13 {
return Err(Error::new_spanned(
input,
"Structs with 13 or more fields are not supported.",
));
}
let flatten_field_exists = input
.fields
.iter()
.any(|field| get_field_attribute(field) == FieldAttribute::Flatten);
if flatten_field_exists {
return Err(Error::new_spanned(
input,
"Flatten attribute is not supported.",
));
}
Ok(())
}
pub(crate) fn validate_input_sha(input: &ItemStruct) -> Result<()> {
match &input.fields {
Fields::Named(_) => (),
_ => {
return Err(Error::new_spanned(
input,
"Only structs with named fields are supported",
))
}
};
let flatten_field_exists = input
.fields
.iter()
.any(|field| get_field_attribute(field) == FieldAttribute::Flatten);
if flatten_field_exists {
return Err(Error::new_spanned(
input,
"Flatten attribute is not supported in SHA256 hasher.",
));
}
Ok(())
}
pub(crate) fn get_field_attribute(field: &Field) -> FieldAttribute {
if field.attrs.iter().any(|attr| attr.path().is_ident("hash")) {
FieldAttribute::Hash
} else if field.attrs.iter().any(|attr| attr.path().is_ident("skip")) {
FieldAttribute::Skip
} else if field
.attrs
.iter()
.any(|attr| attr.path().is_ident("flatten"))
{
FieldAttribute::Flatten
} else {
FieldAttribute::None
}
}
pub(crate) fn detect_field_type(field: &Field) -> FieldType {
let type_str = field.ty.to_token_stream().to_string();
if type_str == "Vec < u8 >" {
FieldType::VecU8
} else if type_str.starts_with("Option < Vec < u8 > >") {
FieldType::OptionVecU8
} else if type_str.starts_with("Option < ") {
FieldType::Option
} else if type_str.starts_with("Pubkey") {
FieldType::Pubkey
} else if type_str.starts_with("[ u8 ;") {
FieldType::U8Array
} else if type_str.starts_with("Option < [ u8 ;") {
FieldType::OptionU8Array
} else {
FieldType::Default
}
}