use proc_macro2::TokenStream;
use quote::quote;
use crate::generating::bitfield::feature::{Feature, FeaturePosition};
use crate::parsing::bitfields::bitfield::Bitfield;
use crate::parsing::common::to_tokens::ToTokens;
#[derive(Default)]
pub struct BitfieldStructFeatureGenerator;
impl Feature for BitfieldStructFeatureGenerator {
fn generate_feature(&self, bitfield: &Bitfield) -> TokenStream {
Self::generate_bitfield_struct_feature_tokens(bitfield)
}
fn enabled(&self, _: &Bitfield) -> bool {
true
}
fn feature_position(&self) -> FeaturePosition {
FeaturePosition::Above
}
fn order_priority(&self) -> u32 {
0
}
}
const STRUCT_DOCUMENTATION: &str = "Represents a bitfield.";
impl BitfieldStructFeatureGenerator {
fn generate_bitfield_struct_feature_tokens(bitfield: &Bitfield) -> TokenStream {
let attributes_token_stream = Self::generate_struct_attributes_tokens(bitfield);
if Self::should_generate_name_field_struct_tokens(bitfield) {
Self::generate_named_field_struct_tokens(&attributes_token_stream, bitfield)
} else {
Self::generate_tuple_struct_tokens(&attributes_token_stream, bitfield)
}
}
fn generate_struct_attributes_tokens(bitfield: &Bitfield) -> Vec<TokenStream> {
let mut all_attributes = Self::get_default_attributes(bitfield);
all_attributes.extend(bitfield.user_attributes_tokens());
all_attributes
}
fn get_default_attributes(bitfield: &Bitfield) -> Vec<TokenStream> {
let mut attributes_tokens = Vec::new();
if Self::should_generate_name_field_struct_tokens(bitfield) {
attributes_tokens.push(quote! {
#[repr(C)]
});
} else {
attributes_tokens.push(quote! {
#[repr(transparent)]
});
}
if bitfield.arguments().derive_copy() {
let is_heap_array = bitfield.arguments().array_heap() && !bitfield.is_integer_backed();
if is_heap_array {
attributes_tokens.push(quote! {
#[derive(core::clone::Clone)]
});
} else {
attributes_tokens.push(quote! {
#[derive(std::marker::Copy, core::clone::Clone)]
});
}
}
attributes_tokens
}
fn should_generate_name_field_struct_tokens(bitfield: &Bitfield) -> bool {
bitfield.has_ignored_fields()
}
fn get_backing_field_type_tokens(bitfield: &Bitfield) -> TokenStream {
let inner = bitfield.spanned_data_type_token().to_tokens();
if bitfield.arguments().array_heap() && !bitfield.is_integer_backed() {
quote! { ::std::boxed::Box<#inner> }
} else {
inner
}
}
fn generate_tuple_struct_tokens(
attributes: &[TokenStream],
bitfield: &Bitfield,
) -> TokenStream {
let bitfield_name_tokens = bitfield.name_tokens();
let backing_field_type_tokens = Self::get_backing_field_type_tokens(bitfield);
let visibility_tokens = bitfield.visibility().to_tokens();
quote! {
#( #attributes )*
#[doc = #STRUCT_DOCUMENTATION]
#visibility_tokens struct #bitfield_name_tokens(#backing_field_type_tokens);
}
}
fn generate_named_field_struct_tokens(
attributes: &[TokenStream],
bitfield: &Bitfield,
) -> TokenStream {
let bitfield_name_tokens = bitfield.name_tokens();
let backing_field_type_tokens = Self::get_backing_field_type_tokens(bitfield);
let visibility_tokens = bitfield.visibility().to_tokens();
let ignored_fields_field_definitions_tokens =
Self::generate_ignored_fields_struct_field_definition(bitfield);
quote! {
#( #attributes )*
#[doc = #STRUCT_DOCUMENTATION]
#visibility_tokens struct #bitfield_name_tokens {
val: #backing_field_type_tokens,
#( #ignored_fields_field_definitions_tokens, )*
}
}
}
fn generate_ignored_fields_struct_field_definition(bitfield: &Bitfield) -> Vec<TokenStream> {
bitfield
.ignored_fields()
.iter()
.map(|field| {
let visibility_tokens = field.visibility().to_tokens();
let field_name_tokens = field.name_tokens();
let field_type_tokens = field.spanned_data_type_token().to_tokens();
quote! {
#visibility_tokens #field_name_tokens: #field_type_tokens
}
})
.collect()
}
}