//! Generator for [`Register`]. //! The entry point is [`reg_type_def`]. use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase}; use itertools::Itertools; use proc_macro2::{Ident, Literal, TokenStream}; use quote::quote; use crate::types::{DataType, Field, MultipleParams, Register, Value}; use super::{ CodeGenError, util::{self, RustUxTypes}, }; /// Generate underlying `T` and its implementation for `RegisterSpec`. /// /// # Returns /// tuple of /// - code of `T` definition and its impls /// - [`Ident`] of `T` /// - [`Ident`] of `Ux` /// /// # Cases /// - `T` == `Ux` => [`reg_type_def_simple`] /// - `T` is masked `Ux` => [`reg_type_def_masked`] /// - `T` has 1+ fields => [`reg_type_def_with_field`] pub(super) fn reg_type_def( reg: &Register, upper_camel_name: &Ident, ) -> Result<(TokenStream, Ident, Ident), CodeGenError> { Ok(match reg.elements.is_empty() { true => match reg.mask { Some(mask) => reg_type_def_masked(®.r#type, mask, upper_camel_name), None => reg_type_def_simple(®.r#type), }, false => reg_type_def_with_field(®.r#type, ®.elements, upper_camel_name)?, }) } /// Where `T` == `Ux`. /// /// No `T` def nor impl are required. /// /// # Returns /// same as [`reg_type_def`] fn reg_type_def_simple(basetype: &DataType) -> (TokenStream, Ident, Ident) { let type_t_ux = { let x: RustUxTypes = basetype.into(); x.to_rust_type_token() }; let out = quote! {}; (out, type_t_ux.clone(), type_t_ux) } /// Where `T` is masked `Ux`. /// /// `T` is a one-length "tuple struct" `T(pub Ux)`. /// `impl TryFrom for T` and `impl From for Ux` are included, /// but without `impl T`. /// /// # Returns /// same as [`reg_type_def`] fn reg_type_def_masked( basetype: &DataType, mask: u32, upper_camel_name: &Ident, ) -> (TokenStream, Ident, Ident) { let type_ux = { let x: RustUxTypes = basetype.into(); x.to_rust_type_token() }; let type_t = RustUxTypes::from_exact_mask(mask); // u8, u16 already implements Into and TryFrom with u32 // but bool doen't implement TryFrom, so it cannot be used as `T` here match type_t { None | Some(RustUxTypes::Bool) => { let out = quote! { #[derive(Debug, Clone, Copy, Default)] pub struct #upper_camel_name(pub #type_ux); impl TryFrom<#type_ux> for #upper_camel_name { type Error = crate::register_spec::DataConversionError<#type_ux, Self>; fn try_from(value: #type_ux) -> Result { Ok(Self(value & #mask)) } } impl From<#upper_camel_name> for #type_ux { fn from(value: #upper_camel_name) -> Self { value.0 } } }; (out, upper_camel_name.clone(), type_ux) } Some(type_t) => { let out = quote! {}; (out, type_t.to_rust_type_token(), type_ux) } } } /// Where `T` has fields. /// /// `T` is a "struct struct" which has a single field `inner: Ux`. /// Also, a bunch of "mask" constants and getter/setter are defined for each fields. /// /// # Returns /// same as [`reg_type_def`] /// /// # Field generation /// This function calls [`generate_field`] for each [`Field`] entries to generate field definitions. /// See the doc of `generate_field` for more detail fn reg_type_def_with_field( basetype: &DataType, fields: &[Field], upper_camel_name: &Ident, ) -> Result<(TokenStream, Ident, Ident), CodeGenError> { let type_ux = { let x: RustUxTypes = basetype.into(); x.to_rust_type_token() }; let (code_masks, code_getters, code_setters): ( Vec, Vec, Vec, ) = fields .iter() .map(|field| generate_field(field, basetype)) .process_results(|iter| iter.multiunzip())?; let out = quote! { #(#code_masks)* #[derive(Debug, Clone, Copy, Default)] pub struct #upper_camel_name { inner: #type_ux, } impl #upper_camel_name { #(#code_getters)* #(#code_setters)* } impl TryFrom<#type_ux> for #upper_camel_name { type Error = crate::register_spec::DataConversionError<#type_ux, Self>; fn try_from(value: #type_ux) -> Result { Ok(Self { inner: value }) } } impl From<#upper_camel_name> for u32 { fn from(value: #upper_camel_name) -> Self { value.inner } } }; Ok((out, upper_camel_name.clone(), type_ux)) } enum FieldType<'a> { RustType(RustUxTypes), CustomValue(&'a [Value]), } /// Generate code for each field, which consists of these three. /// 1. mask definition /// 2. getter method /// 3. setter method /// /// # Cases /// This function is separated into two cases. /// See each function docs for more detail. /// /// 1. field is not "multiple" => [`generate_single_field`] /// 2. field is "multiple" => [`generate_multiple_field`] fn generate_field( field: &Field, basetype: &DataType, ) -> Result<(TokenStream, TokenStream, TokenStream), CodeGenError> { let mask_name = util::parse_to_ident(&format!("{}_MASK", field.name.to_shouty_snake_case()))?; let base_type = util::RustUxTypes::from(basetype).to_rust_type_token(); let snake_case_name = util::parse_to_ident(&field.name.to_snake_case())?; let field_type = match field.elements.is_empty() { true => FieldType::RustType(util::RustUxTypes::from_mask(field.mask)), false => FieldType::CustomValue(&field.elements), }; let desc = match field.desc.clone() { None => "".to_string(), Some(s) if s.is_empty() => s, Some(desc) => util::escape_brackets_with_numbers(&desc), }; let (code_mask, code_getter, code_setter) = match &field.multiple { Some(multiple_params) => generate_multiple_field( mask_name, base_type, field.mask, field_type, snake_case_name, multiple_params, &desc, ), None => generate_single_field( mask_name, base_type, field.mask, field_type, snake_case_name, &desc, ), }; Ok((code_mask, code_getter, code_setter)) } /// Generate "single" field definition (mask, getter, setter). /// /// # Cases /// This function is separated into three cases based on field types [`FieldType`]. /// /// - field is `bool` => [`generate_single_bool_field`] /// - field is `u8`/`u16`/`u32` => [`generate_single_ux_field`] /// - field is custom [`Value`] => [`generate_custom_values_const_enumdef`] & [`generate_single_custom_values_field`] /// /// For the details of types of register/field, see [`DataType`]. /// Note that in both cases, mask definitions are the same. fn generate_single_field( mask_name: Ident, base_type: Ident, mask_val: u32, field_type: FieldType, snake_case_name: Ident, desc: &str, ) -> (TokenStream, TokenStream, TokenStream) { let mask_val = util::parse_to_literal(&format!("0x{mask_val:x}")).unwrap(); let code_mask = match field_type { FieldType::RustType(_) => { quote! { const #mask_name: #base_type = #mask_val; } } FieldType::CustomValue(values) => { let values_enum_masks = generate_custom_values_const_enumdef(&base_type, &snake_case_name, values); quote! { const #mask_name: #base_type = #mask_val; #values_enum_masks } } }; let (code_getter, code_setter) = match field_type { FieldType::RustType(field_type) => match field_type { RustUxTypes::Bool => generate_single_bool_field(mask_name, snake_case_name, desc), RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => { generate_single_ux_field(mask_name, base_type, snake_case_name, field_type, desc) } }, FieldType::CustomValue(values) => { generate_single_custom_values_field(mask_name, snake_case_name, values, desc) } }; (code_mask, code_getter, code_setter) } /// Generate bool "single" field definition (getter, setter). fn generate_single_bool_field( mask_name: Ident, snake_case_name: Ident, desc: &str, ) -> (TokenStream, TokenStream) { let setter_name = util::parse_to_ident(&format!("set_{snake_case_name}")).unwrap(); let getter_doc = format!("Getter. {desc}"); let code_getter = quote! { #[doc = #getter_doc] pub fn #snake_case_name(&self) -> bool { (self.inner & #mask_name) == #mask_name } }; let setter_doc = format!("Setter. {desc}"); let code_setter = quote! { #[doc = #setter_doc] pub fn #setter_name(self, val: bool) -> Self { let mut inner = self.inner; if val { inner |= #mask_name } else { inner &= !#mask_name }; Self { inner } } }; (code_getter, code_setter) } /// Generate u8/u16/u32 "single" field definition (getter, setter). fn generate_single_ux_field( mask_name: Ident, base_type: Ident, snake_case_name: Ident, field_type: RustUxTypes, desc: &str, ) -> (TokenStream, TokenStream) { let field_type = field_type.to_rust_type_token(); let setter_name = util::parse_to_ident(&format!("set_{snake_case_name}")).unwrap(); let getter_doc = format!("Getter. {desc}"); let code_getter = quote! { #[doc = #getter_doc] pub fn #snake_case_name(&self) -> #field_type { const RIGHT_SHIFT: #base_type = #mask_name.trailing_zeros(); ((self.inner & #mask_name) >> RIGHT_SHIFT) .try_into() .unwrap() } }; let setter_doc = format!("Setter. {desc}"); let code_setter = quote! { #[doc = #setter_doc] pub fn #setter_name(&self, val: #field_type) -> Self { let update: #base_type = (val as #base_type) & #mask_name; let mut inner = self.inner; inner &= !#mask_name; inner |= update; Self { inner } } }; (code_getter, code_setter) } fn custom_value_const_name(value_name: &str) -> Ident { util::parse_to_ident(&format!("VAL_{}", value_name.to_shouty_snake_case())).unwrap() } /// Generate const var and value enum definition. /// /// Both for single & multiple. fn generate_custom_values_const_enumdef( base_type: &Ident, field_name: &Ident, values: &[Value], ) -> TokenStream { let consts = values.iter().map(|value| { let const_name = custom_value_const_name(&value.name); let val = value.data; quote! { const #const_name: #base_type = #val; } }); let variants = values.iter().map(|value| { let doc = match value.desc { None => quote! {}, Some(ref s) if s.is_empty() => quote! {}, Some(ref desc) => { let desc = util::escape_brackets_with_numbers(desc); quote! { #[doc = #desc] } } }; let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap(); quote! { #doc #variant_name } }); let value_enum_name = util::parse_to_ident(&field_name.to_string().to_upper_camel_case()).unwrap(); quote! { #[derive(Clone, Copy)] pub enum #value_enum_name { #(#variants),* } impl #value_enum_name { #(#consts)* } } } /// Generate custom [`Value`] "single" field definition (getter, setter). fn generate_single_custom_values_field( mask_name: Ident, snake_case_name: Ident, values: &[Value], desc: &str, ) -> (TokenStream, TokenStream) { let setter_name = util::parse_to_ident(&format!("set_{snake_case_name}")).unwrap(); let value_enum_name = util::parse_to_ident(&snake_case_name.to_string().to_upper_camel_case()).unwrap(); let (getter_match_arms, setter_match_arms): (Vec<_>, Vec<_>) = values .iter() .map(|value| { let const_name = custom_value_const_name(&value.name); let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap(); ( quote! { #value_enum_name::#const_name => #value_enum_name::#variant_name }, quote! { #value_enum_name::#variant_name => #value_enum_name::#const_name }, ) }) .unzip(); let getter_doc = format!("Getter. {desc}"); let code_getter = quote! { #[doc = #getter_doc] pub fn #snake_case_name(&self) -> #value_enum_name { match (self.inner & #mask_name) >> #mask_name.trailing_zeros() { #(#getter_match_arms),*, _ => panic!("must not reachable"), } } }; let setter_doc = format!("Setter. {desc}"); let code_setter = quote! { #[doc = #setter_doc] pub fn #setter_name(self, val: #value_enum_name) -> Self { let val = match val { #(#setter_match_arms),* }; let mut inner = self.inner; inner &= !#mask_name; inner |= val; Self { inner } } }; (code_getter, code_setter) } /// Generate "multiple" field definition (mask, getter, setter). /// /// # Cases /// As "single" field cases, this function is separated into two cases; /// /// - fields are `bool` => [`generate_multiple_bool_field`] /// - fields are `u8`/`u16`/`u32` => [`generate_multiple_ux_field`] /// - fields are custom [`Value`] => [`generate_custom_values_const_enumdef`] & [`generate_multiple_custom_values_field`] fn generate_multiple_field( mask_name: Ident, base_type: Ident, single_mask_val: u32, single_field_type: FieldType, snake_case_name: Ident, multiple_params: &MultipleParams, desc: &str, ) -> (TokenStream, TokenStream, TokenStream) { let num_multiple = multiple_params.multiple; let id_num_multiple = util::parse_to_literal(&num_multiple.to_string()).unwrap(); let masks: Vec<_> = (0..multiple_params.multiple) .map(|x| x * multiple_params.offset) .map(|offset| single_mask_val << offset) .map(|mask| util::parse_to_literal(&format!("0x{mask:x}")).unwrap()) .collect(); debug_assert_eq!(masks.len(), num_multiple.try_into().unwrap()); let value_const_enumdefs = match single_field_type { FieldType::RustType(_) => quote! {}, FieldType::CustomValue(values) => { generate_custom_values_const_enumdef(&base_type, &snake_case_name, values) } }; let code_mask = quote! { const #mask_name: [#base_type; #id_num_multiple] = [#(#masks),*]; #value_const_enumdefs }; let (code_getter, code_setter) = match single_field_type { FieldType::RustType(single_field_type) => match single_field_type { RustUxTypes::Bool => generate_multiple_bool_field( mask_name, base_type, snake_case_name, masks.clone(), desc, ), RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => generate_multiple_ux_field( mask_name, base_type, snake_case_name, single_field_type, masks, desc, ), }, FieldType::CustomValue(values) => generate_multiple_custom_values_field( mask_name, base_type, snake_case_name, masks, values, desc, ), }; (code_mask, code_getter, code_setter) } /// Generate bool "multiple" field definition (getter, setter). fn generate_multiple_bool_field( mask_name: Ident, base_type: Ident, snake_case_name: Ident, masks: Vec, desc: &str, ) -> (TokenStream, TokenStream) { let num_multiple = masks.len(); let elem_getter = masks.iter().enumerate().map(|(i, _mask)| { quote! { (self.inner & #mask_name[#i]) == #mask_name[#i] } }); let getter_doc = format!("Getter. {desc}"); let code_getter = quote! { #[doc = #getter_doc] pub fn #snake_case_name(&self) -> [bool; #num_multiple] { [ #(#elem_getter),* ] } }; let setter_name = util::parse_to_ident(&format!("set_{snake_case_name}")).unwrap(); let setter_doc = format!("Setter. {desc}"); let code_setter = quote! { #[doc = #setter_doc] pub fn #setter_name(self, val: [bool; #num_multiple]) -> Self { let mask: #base_type = #mask_name.iter().sum(); let update: #base_type = #mask_name .iter() .zip(val) .filter_map(|(mask, val)| val.then_some(mask)) .sum(); let mut inner = self.inner; inner &= !mask; inner |= update; Self { inner } } }; (code_getter, code_setter) } /// Generate u8/u16/u32 "multiple" field definition (getter, setter). fn generate_multiple_ux_field( mask_name: Ident, base_type: Ident, snake_case_name: Ident, single_field_type: RustUxTypes, masks: Vec, desc: &str, ) -> (TokenStream, TokenStream) { let field_type = single_field_type.to_rust_type_token(); let num_multiple = masks.len(); let elem_getter = masks.iter().enumerate().map(|(i, _mask)| { quote! { ((self.inner & #mask_name[#i]) >> (#mask_name[#i].trailing_zeros())) .try_into() .unwrap() } }); let getter_doc = format!("Getter. {desc}"); let code_getter = quote! { #[doc = #getter_doc] pub fn #snake_case_name(&self) -> [#field_type; #num_multiple] { [ #(#elem_getter),* ] } }; let setter_name = util::parse_to_ident(&format!("set_{snake_case_name}")).unwrap(); let setter_doc = format!("Setter. {desc}"); let code_setter = quote! { #[doc = #setter_doc] pub fn #setter_name(&self, val: [#field_type; #num_multiple]) -> Self { let mask: #base_type = #mask_name.iter().sum(); let update: #base_type = #mask_name .iter() .zip(val) .map(|(mask, val)| (#base_type::from(val)) << (mask.trailing_zeros())) .sum(); let mut inner = self.inner; inner &= !mask; inner |= update; Self { inner } } }; (code_getter, code_setter) } /// Generate custom [`Value`] "single" field definition (getter, setter). fn generate_multiple_custom_values_field( mask_name: Ident, base_type: Ident, snake_case_name: Ident, masks: Vec, values: &[Value], desc: &str, ) -> (TokenStream, TokenStream) { let value_enum_name = util::parse_to_ident(&snake_case_name.to_string().to_upper_camel_case()).unwrap(); let num_multiple = masks.len(); let (getter_match_arms, setter_match_arms): (Vec<_>, Vec<_>) = values .iter() .map(|value| { let const_name = custom_value_const_name(&value.name); let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap(); ( quote! { #value_enum_name::#const_name => #value_enum_name::#variant_name }, quote! { #value_enum_name::#variant_name => #value_enum_name::#const_name }, ) }) .unzip(); let elem_getter = masks.iter().enumerate().map(|(i, _mask)| { quote! { match ((self.inner & #mask_name[#i])) >> (#mask_name[#i].trailing_zeros()) { #(#getter_match_arms),*, _ => panic!("must not reachable"), } } }); let getter_doc = format!("Getter. {desc}"); let code_getter = quote! { #[doc = #getter_doc] pub fn #snake_case_name(&self) -> [#value_enum_name; #num_multiple] { [ #(#elem_getter),* ] } }; let setter_name = util::parse_to_ident(&format!("set_{snake_case_name}")).unwrap(); let elem_setter = masks.iter().enumerate().map(|(i, _mask)| { quote! { match val[#i] { #(#setter_match_arms),* } } }); let setter_doc = format!("Setter. {desc}"); let code_setter = quote! { #[doc = #setter_doc] pub fn #setter_name(&self, val: [#value_enum_name; #num_multiple]) -> Self { let val: [#base_type; #num_multiple] = [ #(#elem_setter),* ]; let mask: #base_type = #mask_name.iter().sum(); let update: #base_type = #mask_name .iter() .zip(val) .map(|(mask, val)| (#base_type::from(val)) << (mask.trailing_zeros())) .sum(); let mut inner = self.inner; inner &= !mask; inner |= update; Self { inner } } }; (code_getter, code_setter) }