fn field_serialized_size()

in lain_derive/src/serialize.rs [441:543]


fn field_serialized_size(
    field: &Field,
    name_prefix: &'static str,
    is_destructured: bool,
    visitor_type: SerializedSizeVisitorType,
) -> (TokenStream, String, TokenStream) {
    let ty = &field.ty;
    let field_ident_string = match field.member {
        syn::Member::Named(ref ident) => ident.to_string(),
        syn::Member::Unnamed(ref idx) => idx.index.to_string(),
    };

    let value_ident =
        TokenStream::from_str(&format!("{}{}", name_prefix, field_ident_string)).unwrap();
    let borrow = if is_destructured {
        TokenStream::new()
    } else {
        quote! {&}
    };

    let serialized_size_stmts = if let Some(bits) = field.attrs.bits() {
        let bit_shift = field.attrs.bit_shift().unwrap();
        let bitfield_type = field.attrs.bitfield_type().unwrap_or(&field.ty);
        let is_last_field = field.attrs.is_last_field();

        let type_total_bits = if is_primitive_type(bitfield_type, "u8") {
            8
        } else if is_primitive_type(&bitfield_type, "u16") {
            16
        } else if is_primitive_type(&bitfield_type, "u32") {
            32
        } else if is_primitive_type(&bitfield_type, "u64") {
            64
        } else {
            panic!("got to field_serialize_size with an unsupported bitfield type `{}`. ensure that checks in ast code are correct", bitfield_type.into_token_stream());
        };

        let bitfield_value = if field.attrs.bitfield_type().is_some() {
            quote_spanned! {field.original.span() => #borrow#value_ident.to_primitive()}
        } else {
            quote_spanned! { field.original.span() => #borrow#value_ident}
        };

        // kind of a hack but only emit the size of the bitfield for the first element
        if bits + bit_shift == type_total_bits || is_last_field {
            match visitor_type {
                SerializedSizeVisitorType::SerializedSize => {
                    quote_spanned! {field.original.span() => _lain::traits::SerializedSize::serialized_size(#bitfield_value)}
                }
                SerializedSizeVisitorType::MinNonzeroElements
                | SerializedSizeVisitorType::MinEnumVariantSize => {
                    quote_spanned! {field.original.span() => <#bitfield_type>::min_nonzero_elements_size()}
                }
                SerializedSizeVisitorType::MaxDefaultObjectSize => {
                    quote_spanned! {field.original.span() => <#bitfield_type>::max_default_object_size()}
                }
            }
        } else {
            quote! {0 /* bitfield */}
        }
    } else {
        match visitor_type {
            SerializedSizeVisitorType::SerializedSize => {
                quote_spanned! { field.original.span() => _lain::traits::SerializedSize::serialized_size(#borrow#value_ident)}
            }
            SerializedSizeVisitorType::MinNonzeroElements
            | SerializedSizeVisitorType::MinEnumVariantSize => match ty {
                syn::Type::Path(ref p)
                    if p.path.segments[0].ident == "Vec" && field.attrs.min().is_some() =>
                {
                    let min = field.attrs.min().unwrap();
                    quote_spanned! { field.original.span() => <#ty>::min_nonzero_elements_size() * #min }
                }
                _ => {
                    quote_spanned! { field.original.span() => (<#ty>::min_nonzero_elements_size() ) }
                }
            },
            SerializedSizeVisitorType::MaxDefaultObjectSize => match ty {
                syn::Type::Path(ref p)
                    if p.path.segments[0].ident == "Vec" && field.attrs.min().is_some() =>
                {
                    let min = field
                        .attrs
                        .min()
                        .map(|min| {
                            if min.to_string() == "0" {
                                quote! {1}
                            } else {
                                min.clone()
                            }
                        })
                        .unwrap_or(quote! {1});
                    quote_spanned! { field.original.span() => <#ty>::max_default_object_size() * #min }
                }
                _ => {
                    quote_spanned! { field.original.span() => (<#ty>::max_default_object_size() ) }
                }
            },
        }
    };

    (value_ident, field_ident_string, serialized_size_stmts)
}