bitstructs_macro 0.2.1

Procedural macro for bitstructs.
Documentation
use crate::tokens::BitstructFieldTargetType;

use super::*;

pub(crate) fn gen_bitstruct_field_enum_types_def(
    cache: &mut Cache,
    bitstruct: &Bitstruct,
) -> Result<TokenStream2> {
    let mut enum_types_def = Vec::new();
    for field in bitstruct.fields.iter() {
        if let Some(field_target_type) = &field.target_type {
            if let BitstructFieldTargetType::InlineEnum(field_enum_type) = field_target_type {
                let field_bit_width = field.bit_width()?;
                check_bitstruct_enum_type_def(field_enum_type, field_bit_width)?;
                enum_types_def.push(unsafe {
                    unchecked_gen_bitstruct_field_enum_type_def(
                        cache,
                        field_enum_type,
                        field_bit_width,
                        false,
                    )?
                });
            }
        }
    }
    Ok(quote! {
        #(#enum_types_def)*
    })
}

/// Check whether the enum type definition meets the requirements.
///
/// Divided into the following checks:
/// 1. Check to ensure that the number of enum type variables does not exceed 2^field size
/// and the maximum number of enum type variables `2^BitstructFieldEnumType::SUPPORT_MAX_BIT_WIDTH`
/// For example, if the field size is 2, then the number of enum type variables cannot exceed 4 and `2^BitstructFieldEnumType::SUPPORT_MAX_BIT_WIDTH`
/// 2. Check whether the enum type variable value is non-negative
/// 3. Enum variables are not repeated. (Not done here, use the rustc compiler to check the enum type)
///
/// 检查枚举类型定义是否符合要求。
///
/// 细分为以下几个检查:
/// 1. 检查,保证枚举类型的变量数量不超过2^字段大小和最大枚举类型变量数量`2^BitstructFieldEnumType::SUPPORT_MAX_BIT_WIDTH`
/// 例如,字段大小为2,那么枚举类型的变量数量不能超过4和`2^BitstructFieldEnumType::SUPPORT_MAX_BIT_WIDTH`
/// 2. 检查枚举类型的变量值是否为非负数
/// 3. 枚举变量不重复。(此处不做,利用rustc编译器对枚举类型的检查)
pub fn check_bitstruct_enum_type_def(
    field_enum_type: &BitstructFieldEnumType,
    field_bit_width: u32,
) -> Result<()> {
    if field_bit_width > BitstructFieldEnumType::SUPPORT_MAX_BIT_WIDTH {
        return Err(syn::Error::new(
            field_enum_type.span(),
            format!(
                "field bit size must be less than or equal to {0}, biger than {0} is not supported",
                BitstructFieldEnumType::SUPPORT_MAX_BIT_WIDTH
            ),
        ));
    }
    let two_power_of_field_bit_width = 2_usize.pow(field_bit_width);
    if field_enum_type.variants.len() > 0 {
        let variants = &field_enum_type.variants;
        let mut variant_count = 0;
        let mut variant_max_value = core::usize::MIN;
        for variant in variants.iter() {
            variant_count += 1;
            let value = variant.value.base10_parse::<i128>()?;
            if value < 0 {
                return Err(syn::Error::new(
                    variant.value.span(),
                    "enum variant value must be non-negative in bitstruct field",
                ));
            }
            if value > variant_max_value as i128 {
                variant_max_value = value as usize;
            }
        }
        if variant_count > two_power_of_field_bit_width {
            return Err(syn::Error::new(
                field_enum_type.span(),
                format!(
                    "enum type variant count must be less than or equal to 2^{}",
                    field_bit_width
                ),
            ));
        }
        if variant_max_value >= two_power_of_field_bit_width {
            return Err(syn::Error::new(
                field_enum_type.span(),
                format!(
                    "enum type variant value must be less than 2^{}",
                    field_bit_width
                ),
            ));
        }
    } else {
        return Err(syn::Error::new(
            field_enum_type.span(),
            "enum type must have variants",
        ));
    }
    Ok(())
}

/// Generate a field's enum type definition, if the number of enum type variants is insufficient,
/// it will be automatically padded.
/// # Safety
/// 1. The number of enum type variants does not exceed 2^field size
/// 2. The value of the enum type variant is non-negative
/// 3. The value of the enum type variant is not repeated
///
/// 生成一个字段的枚举类型定义,如果枚举类型的变体(variant)数量不足的情况,会自动补齐。
/// # Safety
/// 1. 枚举类型的变量数量不超过2^字段大小
/// 2. 枚举类型的变量值为非负数
/// 3. 枚举类型的变量值不重复
pub(super) unsafe fn unchecked_gen_bitstruct_field_enum_type_def(
    cache: &mut Cache,
    field_enum_type: &BitstructFieldEnumType,
    field_bit_width: u32,
    impl_trait: bool,
) -> Result<TokenStream2> {
    let enum_ident = &field_enum_type.ident;
    let enum_variants = &field_enum_type.variants;

    let mut variants_value_set = std::collections::HashSet::new();
    let mut enum_variants_def = vec![];
    let mut enum_value2variant_arm = vec![];
    let mut enum_variant2value_arm = vec![];
    for variant in enum_variants.iter() {
        let variant_attrs = &variant.attrs;
        let variant_ident = &variant.ident;
        let variant_value = &variant.value;
        enum_variants_def.push(quote! {
            #(#variant_attrs)*
            #variant_ident = #variant_value,
        });
        enum_value2variant_arm.push(quote! {
            #variant_value => #enum_ident::#variant_ident,
        });
        enum_variant2value_arm.push(quote! {
            #enum_ident::#variant_ident => #variant_value,
        });
        variants_value_set.insert(variant_value.base10_parse::<usize>()?);
    }
    for i in 0..(2_usize.pow(field_bit_width as u32)) {
        if !variants_value_set.contains(&i) {
            let ident = syn::Ident::new(&format!("__Reserved{}", i), field_enum_type.span());
            let value = syn::LitInt::new(&format!("{}", i), field_enum_type.span());
            enum_variants_def.push(quote! {
                #ident = #value,
            });
            enum_value2variant_arm.push(quote! {
                #value => #enum_ident::#ident,
            });
            enum_variant2value_arm.push(quote! {
                #enum_ident::#ident => #value,
            });
        }
    }
    let enum_attrs = &field_enum_type.attrs;
    let enum_vis = &field_enum_type.vis;
    let sotre_type = tokens::BitstructField::infer_store_type_by_field_bit_width(field_bit_width)?;

    if impl_trait {
        Ok(quote! {
            #(#enum_attrs)*
            #enum_vis enum #enum_ident {
                #(#enum_variants_def)*
            }
            unsafe impl bitstructs::BitstructFromValue for #enum_ident {
                const BIT_WIDTH: u32 = #field_bit_width;
                type StoreType = #sotre_type;
                unsafe fn from_value(value: Self::StoreType) -> Self {
                    match value {
                        #(#enum_value2variant_arm)*
                        _ => unreachable!(),
                    }
                }
            }
            unsafe impl bitstructs::BitstructToValue for #enum_ident {
                const BIT_WIDTH: u32 = #field_bit_width;
                type StoreType = #sotre_type;
                unsafe fn to_value(self) -> Self::StoreType {
                    match self {
                        #(#enum_variant2value_arm)*
                    }
                }
            }
        })
    } else {
        cache.field_enum_type_match_arms.insert(
            field_enum_type.ident.clone(),
            (enum_value2variant_arm, enum_variant2value_arm),
        );

        Ok(quote! {
            #(#enum_attrs)*
            #enum_vis enum #enum_ident {
                #(#enum_variants_def)*
            }
        })
    }
}