From 9728af3551989de28d7703d57f2a77ac12f85399 Mon Sep 17 00:00:00 2001 From: Wataru Otsubo Date: Sun, 2 Feb 2025 04:08:36 +0900 Subject: [PATCH] new(codegen_register): add multiple custom value fields generator --- src/generator/codegen_register.rs | 88 ++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/generator/codegen_register.rs b/src/generator/codegen_register.rs index 0e1d811..0195490 100644 --- a/src/generator/codegen_register.rs +++ b/src/generator/codegen_register.rs @@ -421,8 +421,15 @@ fn generate_multiple_field( .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 { @@ -438,7 +445,13 @@ fn generate_multiple_field( masks, ), }, - FieldType::CustomValue(_) => todo!("HERE NEXT"), + FieldType::CustomValue(values) => generate_multiple_custom_values_field( + mask_name, + base_type, + snake_case_name, + masks, + values, + ), }; (code_mask, code_getter, code_setter) @@ -528,3 +541,76 @@ fn generate_multiple_ux_field( (code_getter, code_setter) } + +fn generate_multiple_custom_values_field( + mask_name: Ident, + base_type: Ident, + snake_case_name: Ident, + masks: Vec, + values: &[Value], +) -> (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(&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 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 code_getter = quote! { + 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 code_setter = quote! { + 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) +}