use syn::{
punctuated::Punctuated, Data, DeriveInput, Field, Fields, GenericArgument, ItemStruct,
PathArguments, Result, Token, Type,
};
pub(crate) fn extract_fields_from_item_struct(
input: &ItemStruct,
) -> Result<&Punctuated<Field, Token![,]>> {
match &input.fields {
Fields::Named(fields) => Ok(&fields.named),
_ => Err(syn::Error::new_spanned(
input,
"Only structs with named fields are supported",
)),
}
}
pub(crate) fn extract_fields_from_derive_input(
input: &DeriveInput,
) -> Result<&Punctuated<Field, Token![,]>> {
match &input.data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => Ok(&fields.named),
Fields::Unnamed(_) => Err(syn::Error::new_spanned(
input,
"Only structs with named fields are supported. Tuple structs cannot be light accounts.",
)),
Fields::Unit => Err(syn::Error::new_spanned(
input,
"Only structs with named fields are supported. Unit structs cannot be light accounts.",
)),
},
Data::Enum(_) => Err(syn::Error::new_spanned(
input,
"Only structs are supported. Enums cannot be light accounts.",
)),
Data::Union(_) => Err(syn::Error::new_spanned(
input,
"Only structs are supported. Unions cannot be light accounts.",
)),
}
}
#[inline(never)]
pub(crate) fn is_copy_type(ty: &Type) -> bool {
match ty {
Type::Path(type_path) => {
if let Some(segment) = type_path.path.segments.last() {
let type_name = segment.ident.to_string();
matches!(
type_name.as_str(),
"u8" | "u16"
| "u32"
| "u64"
| "u128"
| "usize"
| "i8"
| "i16"
| "i32"
| "i64"
| "i128"
| "isize"
| "f32"
| "f64"
| "bool"
| "char"
| "Pubkey"
) || (type_name == "Option" && has_copy_inner_type(&segment.arguments))
} else {
false
}
}
Type::Array(_) => true,
_ => false,
}
}
#[inline(never)]
pub(crate) fn has_copy_inner_type(args: &PathArguments) -> bool {
match args {
PathArguments::AngleBracketed(args) => args.args.iter().any(|arg| {
if let GenericArgument::Type(ty) = arg {
is_copy_type(ty)
} else {
false
}
}),
_ => false,
}
}
#[inline(never)]
pub(crate) fn is_pubkey_type(ty: &Type) -> bool {
if let Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
segment.ident == "Pubkey"
} else {
false
}
} else {
false
}
}