use super::*;
pub(crate) fn generate_getter_value(ty: &Type, offset: &TokenStream, is_array_elem_getter: bool) -> TokenStream {
let elem_offset = if is_array_elem_getter {
let size = shared::generate_type_bitsize(ty);
quote! {
let size = #size;
cursor >>= size * index;
}
} else {
quote!()
};
let inner = generate_getter_inner(ty, true);
quote! {
type ArbIntOf<T> = <T as Bitsized>::ArbitraryInt;
type BaseIntOf<T> = <ArbIntOf<T> as Integer>::UnderlyingType;
let mut cursor = self.value.value();
let field_offset = #offset;
cursor >>= field_offset;
#elem_offset
#inner
}
}
pub(crate) fn generate_getter_inner(ty: &Type, is_getter: bool) -> TokenStream {
use Type::*;
match ty {
Tuple(tuple) => {
let unbraced = tuple
.elems
.iter()
.map(|elem| {
let getter = generate_getter_inner(elem, is_getter);
quote! { {#getter} }
})
.reduce(|acc, next| {
if is_getter {
quote!(#acc, #next)
} else {
quote!(#acc && #next)
}
})
.unwrap_or_else(|| quote!());
quote! { (#unbraced) }
}
Array(array) => {
let (len_expr, elem_ty) = length_and_type_of_nested_array(array);
let array_elem = generate_getter_inner(&elem_ty, is_getter);
if is_getter {
quote! {
let array = {
let mut array: [::core::mem::MaybeUninit<#elem_ty>; #len_expr] = unsafe {
::core::mem::MaybeUninit::uninit().assume_init()
};
let mut i = 0;
while i < #len_expr {
let elem_value = {
#array_elem
};
array[i].write(elem_value);
i += 1;
}
unsafe { ::core::mem::transmute(array) }
};
array
}
} else {
quote! { {
let mut is_filled = true;
let mut i = 0;
while i < #len_expr {
let elem_filled = {
#array_elem
};
is_filled = is_filled && elem_filled;
i += 1;
}
is_filled
} }
}
}
Path(_) => {
let size = shared::generate_type_bitsize(ty);
let elem_value = quote! {
let raw_value = cursor;
let size = #size;
cursor = cursor.wrapping_shr(size as u32);
let raw_value: BaseIntOf<#ty> = raw_value as BaseIntOf<#ty>;
let elem_value = <#ty as Bitsized>::ArbitraryInt::masked_new(raw_value);
};
if is_getter {
quote! {
#elem_value
match <#ty>::try_from(elem_value) {
Ok(v) => v,
Err(_) => panic!("unreachable"),
}
}
} else {
if shared::is_always_filled(ty) {
quote! {
let size = #size;
cursor = cursor.wrapping_shr(size as u32);
true
}
} else {
quote! { {
#elem_value
<#ty>::try_from(elem_value).is_ok()
} }
}
}
}
_ => unreachable(()),
}
}
pub(crate) fn generate_setter_value(ty: &Type, offset: &TokenStream, is_array_elem_setter: bool) -> TokenStream {
let elem_offset = if is_array_elem_setter {
let size = shared::generate_type_bitsize(ty);
quote! {
let size = #size;
offset += size * index;
}
} else {
quote!()
};
let value_shifted = generate_setter_inner(ty);
let mask = generate_ty_mask(ty);
quote! {
type ArbIntOf<T> = <T as Bitsized>::ArbitraryInt;
type BaseIntOf<T> = <ArbIntOf<T> as Integer>::UnderlyingType;
let mut offset = #offset;
#elem_offset
let field_mask = #mask;
let field_mask: BaseIntOf<Self> = field_mask << offset;
let others_mask: BaseIntOf<Self> = !field_mask;
let struct_value: BaseIntOf<Self> = self.value.value();
let others_values: BaseIntOf<Self> = struct_value & others_mask;
#value_shifted
let new_struct_value = others_values | value_shifted;
self.value = <ArbIntOf<Self>>::new(new_struct_value);
}
}
fn generate_setter_inner(ty: &Type) -> TokenStream {
use Type::*;
match ty {
Tuple(tuple) => {
let mut tuple_index = syn::Index::from(0);
let value_shifted = tuple
.elems
.iter()
.map(|elem| {
let elem_name = quote!(value.#tuple_index);
tuple_index.index += 1;
let value_shifted = generate_setter_inner(elem);
quote! { {
let value = #elem_name;
#value_shifted
value_shifted
} }
})
.reduce(|acc, next| quote!(#acc | #next))
.unwrap_or_else(|| quote!(0));
quote! {
let value_shifted = #value_shifted;
}
}
Array(array) => {
let (len_expr, elem_ty) = length_and_type_of_nested_array(array);
let value_shifted = generate_setter_inner(&elem_ty);
quote! {
#[allow(clippy::useless_transmute)]
let value: [#elem_ty; #len_expr] = unsafe { ::core::mem::transmute(value) };
let mut acc = 0;
let mut i = 0;
while i < #len_expr {
let value = value[i];
#value_shifted
acc |= value_shifted;
i += 1;
}
let value_shifted = acc;
}
}
Path(_) => {
let size = shared::generate_type_bitsize(ty);
quote! {
let value = (<ArbIntOf<#ty>>::from(value).value() & (<<ArbIntOf<#ty> as Integer>::UnsignedInteger as Integer>::MAX.value() as <ArbIntOf<#ty> as Integer>::UnderlyingType)) as <<ArbIntOf<#ty> as Integer>::UnsignedInteger as Integer>::UnderlyingType; let value: BaseIntOf<Self> = value as BaseIntOf<Self>;
let value_shifted = value << offset;
offset += #size;
}
}
_ => unreachable(()),
}
}
pub(crate) fn generate_constructor_part(ty: &Type, name: &Ident, shifted_name: &Ident) -> TokenStream {
let value_shifted = generate_setter_inner(ty);
quote! {
let #shifted_name = {
let value = #name;
#value_shifted
value_shifted
};
}
}
fn generate_ty_mask(ty: &Type) -> TokenStream {
use Type::*;
match ty {
Tuple(tuple) => {
let mut previous_elem_sizes = vec![];
tuple
.elems
.iter()
.map(|elem| {
let mask = generate_ty_mask(elem);
let elem_size = shared::generate_type_bitsize(elem);
let elem_offset = previous_elem_sizes.iter().cloned().reduce(|acc, next| quote!((#acc + #next)));
previous_elem_sizes.push(elem_size);
if let Some(elem_offset) = elem_offset {
quote!(#mask << #elem_offset)
} else {
quote!(#mask)
}
})
.reduce(|acc, next| quote!(#acc | #next))
.unwrap_or_else(|| quote!(0))
}
Array(array) => {
let elem_ty = &array.elem;
let len_expr = &array.len;
let mask = generate_ty_mask(elem_ty);
let ty_size = shared::generate_type_bitsize(elem_ty);
quote! { {
let mask = #mask;
let mut field_mask = 0;
let mut i = 0;
while i < #len_expr {
field_mask |= mask << (i * #ty_size);
i += 1;
}
field_mask
} }
}
Path(_) => quote! {
(<<ArbIntOf<#ty> as Integer>::UnsignedInteger as Integer>::MAX.value() as BaseIntOf<Self>) },
_ => unreachable(()),
}
}
fn length_and_type_of_nested_array(array: &syn::TypeArray) -> (TokenStream, Type) {
let elem_ty = &array.elem;
let len_expr = &array.len;
if let Type::Array(array) = &**elem_ty {
let (child_len, child_ty) = length_and_type_of_nested_array(array);
(quote!((#len_expr) * (#child_len)), child_ty)
} else {
(quote!(#len_expr), *elem_ty.clone())
}
}