use getset::{CloneGetters, Getters};
use proc_macro2::TokenStream;
use quote::{ToTokens, format_ident};
use crate::parsing::bitfields::bitfield_attribute::bitfield_arguments::BitfieldArguments;
use crate::parsing::bitfields::bits_attribute::bits_arguments::{BitsArguments, FieldAccess};
use crate::parsing::common::spanned_data_type::{DataType, SpannedDataTypeToken};
use crate::parsing::common::visibility::Visibility;
#[derive(Getters, CloneGetters)]
#[getset(get_clone = "pub")]
pub struct Bitfield {
user_attributes_tokens: Vec<TokenStream>,
visibility: Visibility,
name: String,
spanned_data_type_token: SpannedDataTypeToken,
fields: Vec<Field>,
ignored_fields: Vec<Field>,
arguments: BitfieldArguments,
}
impl Bitfield {
pub const fn new(
user_attributes_tokens: Vec<TokenStream>,
visibility: Visibility,
name: String,
spanned_data_type_token: SpannedDataTypeToken,
fields: Vec<Field>,
ignored_fields: Vec<Field>,
arguments: BitfieldArguments,
) -> Self {
Self {
user_attributes_tokens,
visibility,
name,
spanned_data_type_token,
fields,
ignored_fields,
arguments,
}
}
pub fn has_ignored_fields(&self) -> bool {
!self.ignored_fields.is_empty()
}
pub fn name_tokens(&self) -> TokenStream {
format_ident!("{}", self.name).to_token_stream()
}
pub const fn is_integer_backed(&self) -> bool {
matches!(self.spanned_data_type_token.data_type(), DataType::Integer(_))
}
}
#[derive(Debug, Clone, Getters, CloneGetters)]
#[getset(get_clone = "pub")]
pub struct Field {
#[getset(skip)]
visibility: Visibility,
name: String,
spanned_data_type_token: SpannedDataTypeToken,
bits: u32,
offset: u32,
reserved: bool,
access: FieldAccess,
arguments: Option<BitsArguments>,
ignored: bool,
}
impl Field {
#[allow(clippy::too_many_arguments)]
pub const fn new(
visibility: Visibility,
name: String,
spanned_data_type_token: SpannedDataTypeToken,
bits: u32,
offset: u32,
reserved: bool,
access: FieldAccess,
arguments: Option<BitsArguments>,
ignored: bool,
) -> Self {
Self {
visibility,
name,
spanned_data_type_token,
bits,
offset,
reserved,
access,
arguments,
ignored,
}
}
pub fn visibility(&self) -> Visibility {
let has_public_access =
matches!(self.access, FieldAccess::ReadWrite | FieldAccess::ReadOnly);
if !has_public_access {
return Visibility::Private;
}
self.visibility.clone()
}
pub fn name_tokens(&self) -> TokenStream {
format_ident!("{}", self.name).to_token_stream()
}
pub fn has_default_value(&self) -> bool {
self.arguments.as_ref().is_some_and(|arguments| arguments.default_value_expr().is_some())
}
pub const fn has_setter(&self) -> bool {
if self.reserved {
return false;
}
matches!(self.access, FieldAccess::WriteOnly)
|| matches!(self.access, FieldAccess::ReadWrite)
}
pub const fn has_getter(&self) -> bool {
if self.reserved {
return false;
}
matches!(self.access, FieldAccess::ReadOnly)
|| matches!(self.access, FieldAccess::ReadWrite)
}
pub const fn has_read_access(&self) -> bool {
matches!(self.access, FieldAccess::ReadOnly)
|| matches!(self.access, FieldAccess::ReadWrite)
}
pub const fn has_constants(&self) -> bool {
self.has_getter() || self.has_setter()
}
pub const fn is_reserved(&self) -> bool {
self.reserved
}
}