From f96aab4d9d3955c09fe5945308a332052ef520a9 Mon Sep 17 00:00:00 2001 From: Wataru Otsubo Date: Sun, 2 Feb 2025 02:50:40 +0900 Subject: [PATCH] fix: add values pattern to "single" registers, introducing `FieldType` --- src/generator/codegen_register.rs | 167 ++++++++++++++++++++++++++---- 1 file changed, 146 insertions(+), 21 deletions(-) diff --git a/src/generator/codegen_register.rs b/src/generator/codegen_register.rs index 4784f1c..6e06881 100644 --- a/src/generator/codegen_register.rs +++ b/src/generator/codegen_register.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use proc_macro2::{Ident, Literal, TokenStream}; use quote::quote; -use crate::types::{DataType, Field, MultipleParams, Register}; +use crate::types::{DataType, Field, MultipleParams, Register, Value}; use super::{ util::{self, RustUxTypes}, @@ -153,6 +153,11 @@ fn reg_type_def_with_field( 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 @@ -172,7 +177,10 @@ fn generate_field( 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 = util::RustUxTypes::from_mask(field.mask); + let field_type = match field.elements.is_empty() { + true => FieldType::RustType(util::RustUxTypes::from_mask(field.mask)), + false => FieldType::CustomValue(&field.elements), + }; let (code_mask, code_getter, code_setter) = match &field.multiple { Some(multiple_params) => generate_multiple_field( @@ -198,10 +206,11 @@ fn generate_field( /// Generate "single" field definition (mask, getter, setter). /// /// # Cases -/// This function is separated into two 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_mask_enumdef`] & todo /// /// For the details of types of register/field, see [`DataType`]. /// Note that in both cases, mask definitions are the same. @@ -209,17 +218,34 @@ fn generate_single_field( mask_name: Ident, base_type: Ident, mask_val: u32, - field_type: RustUxTypes, + field_type: FieldType, snake_case_name: Ident, ) -> (TokenStream, TokenStream, TokenStream) { let mask_val = util::parse_to_literal(&format!("0x{:x}", mask_val)).unwrap(); - let code_mask = quote! { - const #mask_name: #base_type = #mask_val; + let code_mask = match field_type { + FieldType::RustType(_) => { + quote! { + const #mask_name: #base_type = #mask_val; + } + } + FieldType::CustomValue(values) => { + let additional = + generate_custom_values_mask_enumdef(&base_type, &snake_case_name, values); + quote! { + const #mask_name: #base_type = #mask_val; + #additional + } + } }; let (code_getter, code_setter) = match field_type { - RustUxTypes::Bool => generate_single_bool_field(mask_name, snake_case_name), - RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => { - generate_single_ux_field(mask_name, base_type, snake_case_name, field_type) + FieldType::RustType(field_type) => match field_type { + RustUxTypes::Bool => generate_single_bool_field(mask_name, snake_case_name), + RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => { + generate_single_ux_field(mask_name, base_type, snake_case_name, field_type) + } + }, + FieldType::CustomValue(values) => { + generate_custom_values_field(mask_name, snake_case_name, values) } }; @@ -281,6 +307,96 @@ fn generate_single_ux_field( (code_getter, code_setter) } +fn custom_value_const_name(field_name: &Ident, value_name: &String) -> Ident { + util::parse_to_ident(&format!( + "{}_{}", + field_name.to_string().to_shouty_snake_case(), + value_name.to_shouty_snake_case() + )) + .unwrap() +} + +/// Generate const var and value enum definition. +fn generate_custom_values_mask_enumdef( + base_type: &Ident, + field_name: &Ident, + values: &[Value], +) -> TokenStream { + let masks = values.iter().map(|value| { + let const_name = custom_value_const_name(field_name, &value.name); + let val = value.data; + quote! { + const #const_name: #base_type = #val; + } + }); + let variants = values.iter().map(|value| { + let desc = value.desc.clone().unwrap_or("".to_string()); + let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap(); + quote! { + #[doc = #desc] + #variant_name + } + }); + let value_enum_name = + util::parse_to_ident(&field_name.to_string().to_upper_camel_case()).unwrap(); + + quote! { + #(#masks)* + pub enum #value_enum_name { + #(#variants),* + } + } +} + +fn generate_custom_values_field( + mask_name: Ident, + snake_case_name: Ident, + values: &[Value], +) -> (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(&snake_case_name, &value.name); + let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap(); + ( + quote! { + #const_name => #value_enum_name::#variant_name + }, + quote! { + #value_enum_name::#variant_name => #const_name + }, + ) + }) + .unzip(); + let code_getter = quote! { + 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 code_setter = quote! { + 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 @@ -288,17 +404,21 @@ fn generate_single_ux_field( /// /// - fields are `bool` => [`generate_multiple_bool_field`] /// - fields are `u8`/`u16`/`u32` => [`generate_multiple_ux_field`] +/// - fields are custom [`Value`] => todo fn generate_multiple_field( mask_name: Ident, base_type: Ident, single_mask_val: u32, - single_field_type: RustUxTypes, + single_field_type: FieldType, snake_case_name: Ident, multiple_params: &MultipleParams, ) -> (TokenStream, TokenStream, TokenStream) { let num_multiple = multiple_params.multiple; let id_num_multiple = util::parse_to_literal(&num_multiple.to_string()).unwrap(); - let id_field_type = single_field_type.to_rust_type_token(); + let id_field_type = match single_field_type { + FieldType::RustType(ref single_field_type) => single_field_type.to_rust_type_token(), + FieldType::CustomValue(_) => todo!("HERE NEXT"), + }; let masks: Vec<_> = (0..multiple_params.multiple) .map(|x| x * multiple_params.offset) .map(|offset| single_mask_val << offset) @@ -310,21 +430,26 @@ fn generate_multiple_field( }; let (code_getter, code_setter) = match single_field_type { - RustUxTypes::Bool => { - generate_multiple_bool_field(mask_name, base_type, snake_case_name, masks.clone()) - } - RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => generate_multiple_ux_field( - mask_name, - base_type, - snake_case_name, - single_field_type, - masks, - ), + FieldType::RustType(single_field_type) => match single_field_type { + RustUxTypes::Bool => { + generate_multiple_bool_field(mask_name, base_type, snake_case_name, masks.clone()) + } + RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => generate_multiple_ux_field( + mask_name, + base_type, + snake_case_name, + single_field_type, + masks, + ), + }, + FieldType::CustomValue(_) => todo!("HERE NEXT"), }; (code_mask, code_getter, code_setter) } +fn generate_single_value_field() -> () {} + /// Generate bool "multiple" field definition (getter, setter). fn generate_multiple_bool_field( mask_name: Ident,