new(codegen_register): add multiple custom value fields generator

This commit is contained in:
Wataru Otsubo 2025-02-02 04:08:36 +09:00
parent 30279dc2b3
commit 9728af3551

View file

@ -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<Literal>,
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)
}