use getset::{CloneGetters, Getters};
use proc_macro2::Span;
use syn::parse::{Parse, ParseStream};
use crate::parsing::bitflags::bitflag_arguments::BitflagArguments;
use crate::parsing::common::compiler_error::create_user_parsing_compiler_error;
use crate::parsing::common::spanned_data_type::{DataType, SpannedDataTypeToken};
use crate::parsing::common::type_parse_error::TypeParsingError;
#[derive(Clone, Debug, Getters, CloneGetters)]
#[getset(get_clone = "pub")]
pub struct BitflagAttribute {
spanned_data_type_token: SpannedDataTypeToken,
arguments: BitflagArguments,
}
impl Parse for BitflagAttribute {
fn parse(input: ParseStream) -> syn::Result<Self> {
let spanned_data_type_token = Self::parse_bitflag_type(input)?;
Self::check_supported_bitflag_type(&spanned_data_type_token)?;
let arguments = BitflagArguments::parse(input)?;
Ok(Self {
spanned_data_type_token,
arguments,
})
}
}
const BITFLAG_ATTRIBUTE_NON_UNSIGNED_INTEGER_FIRST_ARGUMENT_ERROR_MESSAGE: &str =
"The bitflag attribute must have an unsigned integer type as its first argument";
const BITFLAG_ATTRIBUTE_FLOAT_FIRST_ARGUMENT_ERROR_MESSAGE: &str =
"The bitflag attribute must have an unsigned integer type as its first argument, floats are \
unsupported.";
impl BitflagAttribute {
fn parse_bitflag_type(input: ParseStream) -> syn::Result<SpannedDataTypeToken> {
match Self::parse_type(input) {
Ok(spanned_data_type_token) => Ok(spanned_data_type_token),
Err(err) => match err {
TypeParsingError::NonType(ty) => {
Err(Self::create_unsupported_type_compiler_error(&ty, input.span()))
},
TypeParsingError::UnexpectedFloat => Err(create_user_parsing_compiler_error(
input.span(),
BITFLAG_ATTRIBUTE_FLOAT_FIRST_ARGUMENT_ERROR_MESSAGE,
)),
_ => Err(create_user_parsing_compiler_error(
input.span(),
format!(
"{BITFLAG_ATTRIBUTE_NON_UNSIGNED_INTEGER_FIRST_ARGUMENT_ERROR_MESSAGE}."
),
)),
},
}
}
pub fn parse_type(input: ParseStream) -> Result<SpannedDataTypeToken, TypeParsingError> {
if input.is_empty() {
return Err(TypeParsingError::UnexpectedEndOfInput);
}
match input.parse::<syn::Type>() {
Ok(ty) => SpannedDataTypeToken::new(&ty),
Err(err) => Err(TypeParsingError::NonType(err.to_string())),
}
}
fn check_supported_bitflag_type(
spanned_data_type_token: &SpannedDataTypeToken,
) -> syn::Result<()> {
let data_type = spanned_data_type_token.data_type();
if matches!(data_type, DataType::Custom) || !data_type.unsigned() {
return Err(Self::create_unsupported_type_compiler_error(
&spanned_data_type_token.to_string(),
spanned_data_type_token.span(),
));
}
Ok(())
}
fn create_unsupported_type_compiler_error(type_string_repr: &str, span: Span) -> syn::Error {
create_user_parsing_compiler_error(
span,
format!(
"{BITFLAG_ATTRIBUTE_NON_UNSIGNED_INTEGER_FIRST_ARGUMENT_ERROR_MESSAGE}, \
'{type_string_repr}' is unsupported."
),
)
}
}