From ab8f4f7f94112a1d0bf5cbabe781c935ec3c89f7 Mon Sep 17 00:00:00 2001 From: Dominik Nakamura Date: Wed, 6 Dec 2023 16:51:34 +0900 Subject: [PATCH] feat: introduce sizing methods to calculate needed bytes Each struct and enum in a schema can now calculate its total encoded byte size. As each collection must be iterated it can be a costly operation but it might be faster (or sometimes even required) to allocate a buffer upfront instead of dynamically growing it. --- crates/stef-build/src/definition.rs | 10 +- crates/stef-build/src/lib.rs | 1 + crates/stef-build/src/size.rs | 415 ++++++++++++++++++ .../compiler__compile@alias_basic.stef.snap | 2 +- ...ompiler__compile@attribute_multi.stef.snap | 14 +- ...mpiler__compile@attribute_single.stef.snap | 14 +- ...compiler__compile@attribute_unit.stef.snap | 14 +- .../compiler__compile@attributes.stef.snap | 14 +- ...piler__compile@attributes_min_ws.stef.snap | 14 +- .../compiler__compile@const_basic.stef.snap | 2 +- .../compiler__compile@const_string.stef.snap | 2 +- .../compiler__compile@enum_basic.stef.snap | 27 +- .../compiler__compile@enum_generics.stef.snap | 32 +- .../compiler__compile@enum_many_ws.stef.snap | 27 +- .../compiler__compile@enum_min_ws.stef.snap | 32 +- .../compiler__compile@import_basic.stef.snap | 2 +- .../compiler__compile@module_basic.stef.snap | 33 +- .../compiler__compile@schema_basic.stef.snap | 41 +- .../compiler__compile@struct_basic.stef.snap | 16 +- ...ompiler__compile@struct_generics.stef.snap | 20 +- ...compiler__compile@struct_many_ws.stef.snap | 20 +- .../compiler__compile@struct_min_ws.stef.snap | 20 +- .../compiler__compile@struct_tuple.stef.snap | 16 +- .../compiler__compile@types_basic.stef.snap | 45 +- .../compiler__compile@types_generic.stef.snap | 82 +++- .../compiler__compile@types_nested.stef.snap | 33 +- ...compiler__compile@types_non_zero.stef.snap | 59 ++- .../compiler__compile@types_ref.stef.snap | 47 +- .../compiler__compile_extra@alias.stef.snap | 2 +- .../compiler__compile_extra@const.stef.snap | 2 +- .../compiler__compile_extra@enum.stef.snap | 37 +- .../compiler__compile_extra@import.stef.snap | 2 +- .../compiler__compile_extra@module.stef.snap | 4 +- .../compiler__compile_extra@struct.stef.snap | 28 +- crates/stef/src/buf/encode.rs | 2 +- crates/stef/src/buf/mod.rs | 2 + crates/stef/src/buf/size.rs | 268 +++++++++++ crates/stef/src/varint.rs | 26 +- 38 files changed, 1385 insertions(+), 42 deletions(-) create mode 100644 crates/stef-build/src/size.rs create mode 100644 crates/stef/src/buf/size.rs diff --git a/crates/stef-build/src/definition.rs b/crates/stef-build/src/definition.rs index 7330479..7b3e985 100644 --- a/crates/stef-build/src/definition.rs +++ b/crates/stef-build/src/definition.rs @@ -5,7 +5,7 @@ use stef_parser::{ Module, NamedField, Schema, Struct, Type, TypeAlias, UnnamedField, Variant, }; -use super::{decode, encode}; +use super::{decode, encode, size}; use crate::{BytesType, Opts}; #[must_use] @@ -14,7 +14,7 @@ pub fn compile_schema(opts: &Opts, Schema { definitions, .. }: &Schema<'_>) -> T quote! { #[allow(unused_imports)] - use ::stef::buf::{Decode, Encode}; + use ::stef::buf::{Decode, Encode, Size}; #(#definitions)* } @@ -27,22 +27,26 @@ fn compile_definition(opts: &Opts, definition: &Definition<'_>) -> TokenStream { let def = compile_struct(opts, s); let encode = encode::compile_struct(opts, s); let decode = decode::compile_struct(opts, s); + let size = size::compile_struct(opts, s); quote! { #def #encode #decode + #size } } Definition::Enum(e) => { let def = compile_enum(opts, e); let encode = encode::compile_enum(opts, e); let decode = decode::compile_enum(opts, e); + let size = size::compile_enum(opts, e); quote! { #def #encode #decode + #size } } Definition::TypeAlias(a) => compile_alias(opts, a), @@ -67,7 +71,7 @@ fn compile_module( #comment pub mod #name { #[allow(unused_imports)] - use ::stef::buf::{Decode, Encode}; + use ::stef::buf::{Decode, Encode, Size}; #(#definitions)* } diff --git a/crates/stef-build/src/lib.rs b/crates/stef-build/src/lib.rs index f0b9a2e..adcd88c 100644 --- a/crates/stef-build/src/lib.rs +++ b/crates/stef-build/src/lib.rs @@ -11,6 +11,7 @@ pub use self::definition::compile_schema; mod decode; mod definition; mod encode; +mod size; pub type Result = std::result::Result; diff --git a/crates/stef-build/src/size.rs b/crates/stef-build/src/size.rs new file mode 100644 index 0000000..e96765c --- /dev/null +++ b/crates/stef-build/src/size.rs @@ -0,0 +1,415 @@ +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use stef_parser::{ + DataType, Enum, Fields, Generics, NamedField, Struct, Type, UnnamedField, Variant, +}; + +use crate::{BytesType, Opts}; + +pub(super) fn compile_struct( + opts: &Opts, + Struct { + comment: _, + attributes: _, + name, + generics, + fields, + }: &Struct<'_>, +) -> TokenStream { + let name = Ident::new(name.get(), Span::call_site()); + let (generics, generics_where) = compile_generics(generics); + let fields = compile_struct_fields(opts, fields); + + quote! { + #[automatically_derived] + impl #generics ::stef::buf::Size for #name #generics #generics_where { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + #fields + } + } + } +} + +fn compile_struct_fields(opts: &Opts, fields: &Fields<'_>) -> TokenStream { + match fields { + Fields::Named(named) => { + let calls = named.iter().map( + |NamedField { + comment: _, + name, + ty, + id, + .. + }| { + let id = proc_macro2::Literal::u32_unsuffixed(id.get()); + let name = proc_macro2::Ident::new(name.get(), Span::call_site()); + + if let DataType::Option(ty) = &ty.value { + let ty = compile_data_type( + opts, + ty, + if is_copy(&ty.value) { + quote! { *v } + } else { + quote! { v } + }, + ); + quote! { + ::stef::buf::size_field_option(#id, self.#name.as_ref(), |v| { #ty }) + } + } else { + let ty = compile_data_type(opts, ty, quote! { self.#name }); + quote! { ::stef::buf::size_field(#id, || { #ty }) } + } + }, + ); + + quote! { + #(#calls +)* + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + Fields::Unnamed(unnamed) => { + let calls = unnamed + .iter() + .enumerate() + .map(|(idx, UnnamedField { ty, id, .. })| { + let id = proc_macro2::Literal::u32_unsuffixed(id.get()); + let idx = proc_macro2::Literal::usize_unsuffixed(idx); + + if let DataType::Option(ty) = &ty.value { + let ty = compile_data_type( + opts, + ty, + if is_copy(&ty.value) { + quote! { *v } + } else { + quote! { v } + }, + ); + quote! { + ::stef::buf::size_field_option(#id, self.#idx.as_ref(), |v| { #ty }) + } + } else { + let ty = compile_data_type(opts, ty, quote! { self.#idx }); + quote! { ::stef::buf::size_field(#id, || { #ty }) } + } + }); + + quote! { + #(#calls +)* + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + Fields::Unit => quote! { 0 }, + } +} + +pub(super) fn compile_enum( + opts: &Opts, + Enum { + comment: _, + attributes: _, + name, + generics, + variants, + }: &Enum<'_>, +) -> TokenStream { + let name = Ident::new(name.get(), Span::call_site()); + let (generics, generics_where) = compile_generics(generics); + let variants = variants.iter().map(|v| compile_variant(opts, v)); + + quote! { + #[automatically_derived] + impl #generics ::stef::buf::Size for #name #generics #generics_where { + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + #(#variants,)* + } + } + } + } +} + +fn compile_variant( + opts: &Opts, + Variant { + comment: _, + name, + fields, + id, + .. + }: &Variant<'_>, +) -> TokenStream { + let id = proc_macro2::Literal::u32_unsuffixed(id.get()); + let name = Ident::new(name.get(), Span::call_site()); + let fields_body = compile_variant_fields(opts, fields); + + match fields { + Fields::Named(named) => { + let field_names = named + .iter() + .map(|NamedField { name, .. }| Ident::new(name.get(), Span::call_site())); + + quote! { + Self::#name{ #(#field_names,)* } => { + ::stef::buf::size_id(#id) + + #fields_body + } + } + } + Fields::Unnamed(unnamed) => { + let field_names = unnamed + .iter() + .enumerate() + .map(|(idx, _)| Ident::new(&format!("n{idx}"), Span::call_site())); + + quote! { + Self::#name(#(#field_names,)*) => { + ::stef::buf::size_id(#id) + + #fields_body + } + } + } + Fields::Unit => quote! { + Self::#name => { + ::stef::buf::size_id(#id) + } + }, + } +} + +fn compile_variant_fields(opts: &Opts, fields: &Fields<'_>) -> TokenStream { + match fields { + Fields::Named(named) => { + let calls = named.iter().map( + |NamedField { + comment: _, + name, + ty, + id, + .. + }| { + let id = proc_macro2::Literal::u32_unsuffixed(id.get()); + let name = proc_macro2::Ident::new(name.get(), Span::call_site()); + + if matches!(ty.value, DataType::Option(_)) { + quote! { ::stef::buf::size_field_option(#id, #name.as_ref()) } + } else { + let ty = compile_data_type(opts, ty, quote! { *#name }); + quote! { ::stef::buf::size_field(#id, || { #ty }) } + } + }, + ); + + quote! { + #(#calls +)* + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + Fields::Unnamed(unnamed) => { + let calls = unnamed + .iter() + .enumerate() + .map(|(idx, UnnamedField { ty, id, .. })| { + let id = proc_macro2::Literal::u32_unsuffixed(id.get()); + let name = Ident::new(&format!("n{idx}"), Span::call_site()); + + if matches!(ty.value, DataType::Option(_)) { + quote! { ::stef::buf::size_field_option(#id, #name.as_ref()) } + } else { + let ty = compile_data_type(opts, ty, quote! { *#name }); + quote! { ::stef::buf::size_field(#id, || { #ty }) } + } + }); + + quote! { + #(#calls +)* + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + Fields::Unit => quote! { 0 }, + } +} + +fn compile_generics(Generics(types): &Generics<'_>) -> (TokenStream, TokenStream) { + (!types.is_empty()) + .then(|| { + let types = types + .iter() + .map(|ty| Ident::new(ty.get(), Span::call_site())); + let types2 = types.clone(); + + ( + quote! { <#(#types,)*> }, + quote! { where #(#types2: ::stef::buf::Size,)* }, + ) + }) + .unwrap_or_default() +} + +fn is_copy(ty: &DataType<'_>) -> bool { + matches!( + ty, + DataType::Bool + | DataType::U8 + | DataType::U16 + | DataType::U32 + | DataType::U64 + | DataType::U128 + | DataType::I8 + | DataType::I16 + | DataType::I32 + | DataType::I64 + | DataType::I128 + | DataType::F32 + | DataType::F64 + ) +} + +#[allow(clippy::needless_pass_by_value, clippy::too_many_lines)] +fn compile_data_type(opts: &Opts, ty: &Type<'_>, name: TokenStream) -> TokenStream { + match &ty.value { + DataType::Bool => quote! { ::stef::buf::size_bool(#name) }, + DataType::U8 => quote! { ::stef::buf::size_u8(#name) }, + DataType::U16 => quote! { ::stef::buf::size_u16(#name) }, + DataType::U32 => quote! { ::stef::buf::size_u32(#name) }, + DataType::U64 => quote! { ::stef::buf::size_u64(#name) }, + DataType::U128 => quote! { ::stef::buf::size_u128(#name) }, + DataType::I8 => quote! { ::stef::buf::size_i8(#name) }, + DataType::I16 => quote! { ::stef::buf::size_i16(#name) }, + DataType::I32 => quote! { ::stef::buf::size_i32(#name) }, + DataType::I64 => quote! { ::stef::buf::size_i64(#name) }, + DataType::I128 => quote! { ::stef::buf::size_i128(#name) }, + DataType::F32 => quote! { ::stef::buf::size_f32(#name) }, + DataType::F64 => quote! { ::stef::buf::size_f64(#name) }, + DataType::String | DataType::StringRef | DataType::BoxString => { + quote! { ::stef::buf::size_string(&#name) } + } + DataType::Bytes | DataType::BytesRef | DataType::BoxBytes => match opts.bytes_type { + BytesType::VecU8 => quote! { ::stef::buf::size_bytes_std(&#name) }, + BytesType::Bytes => quote! { ::stef::buf::size_bytes_bytes(&#name) }, + }, + DataType::Vec(ty) => { + let ty = compile_data_type( + opts, + ty, + if is_copy(&ty.value) { + quote! { *v } + } else { + quote! { v } + }, + ); + quote! { ::stef::buf::size_vec(&#name, |v| { #ty }) } + } + DataType::HashMap(kv) => { + let ty_k = compile_data_type( + opts, + &kv.0, + if is_copy(&kv.0.value) { + quote! { *k } + } else { + quote! { k } + }, + ); + let ty_v = compile_data_type( + opts, + &kv.1, + if is_copy(&kv.1.value) { + quote! { *v } + } else { + quote! { v } + }, + ); + quote! { ::stef::buf::size_hash_map(&#name, |k| { #ty_k }, |v| { #ty_v }) } + } + DataType::HashSet(ty) => { + let ty = compile_data_type( + opts, + ty, + if is_copy(&ty.value) { + quote! { *v } + } else { + quote! { v } + }, + ); + quote! { ::stef::buf::size_hash_set(&#name, |v| { #ty }) } + } + DataType::Option(ty) => { + let ty = compile_data_type( + opts, + ty, + if is_copy(&ty.value) { + quote! { *v } + } else { + quote! { v } + }, + ); + quote! { ::stef::buf::size_option(#name.as_ref(), |v| { #ty }) } + } + DataType::NonZero(ty) => match &ty.value { + DataType::U8 => quote! { ::stef::buf::size_u8(#name.get()) }, + DataType::U16 => quote! { ::stef::buf::size_u16(#name.get()) }, + DataType::U32 => quote! { ::stef::buf::size_u32(#name.get()) }, + DataType::U64 => quote! { ::stef::buf::size_u64(#name.get()) }, + DataType::U128 => quote! { ::stef::buf::size_u128(#name.get()) }, + DataType::I8 => quote! { ::stef::buf::size_i8(#name.get()) }, + DataType::I16 => quote! { ::stef::buf::size_i16(#name.get()) }, + DataType::I32 => quote! { ::stef::buf::size_i32(#name.get()) }, + DataType::I64 => quote! { ::stef::buf::size_i64(#name.get()) }, + DataType::I128 => quote! { ::stef::buf::size_i128(#name.get()) }, + DataType::String + | DataType::StringRef + | DataType::Bytes + | DataType::BytesRef + | DataType::Vec(_) + | DataType::HashMap(_) + | DataType::HashSet(_) => compile_data_type(opts, ty, quote! { #name.get() }), + ty => todo!("compiler should catch invalid {ty:?} type"), + }, + DataType::Tuple(types) => match types.len() { + 2..=12 => { + let types = types.iter().enumerate().map(|(idx, ty)| { + let idx = proc_macro2::Literal::usize_unsuffixed(idx); + compile_data_type( + opts, + ty, + if is_copy(&ty.value) { + quote! { #name.#idx } + } else { + quote! { &(#name.#idx) } + }, + ) + }); + quote! { #(#types)+* } + } + n => todo!("compiler should catch invalid tuple with {n} elements"), + }, + DataType::Array(ty, _size) => { + let ty = compile_data_type( + opts, + ty, + if is_copy(&ty.value) { + quote! { *v } + } else { + quote! { v } + }, + ); + quote! { ::stef::buf::size_array(&#name, |v| { #ty }) } + } + DataType::External(_) => { + quote! { (#name).size() } + } + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@alias_basic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@alias_basic.stef.snap index 0e93452..b1ddd0a 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@alias_basic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@alias_basic.stef.snap @@ -4,7 +4,7 @@ description: "/// Sample type alias.\ntype Sample = u32;" input_file: crates/stef-parser/tests/inputs/alias_basic.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Sample type alias. #[allow(dead_code, clippy::module_name_repetitions, clippy::option_option)] pub type Sample = u32; diff --git a/crates/stef-build/tests/snapshots/compiler__compile@attribute_multi.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@attribute_multi.stef.snap index 38c8296..8983104 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@attribute_multi.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@attribute_multi.stef.snap @@ -4,7 +4,7 @@ description: "#[validate(min = 1, max = 100)]\nstruct Sample" input_file: crates/stef-parser/tests/inputs/attribute_multi.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample; @@ -25,4 +25,16 @@ impl ::stef::Decode for Sample { Ok(Self) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + 0 + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@attribute_single.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@attribute_single.stef.snap index c1b11d2..7ec9f01 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@attribute_single.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@attribute_single.stef.snap @@ -4,7 +4,7 @@ description: "#[deprecated = \"don't use\"]\nstruct Sample" input_file: crates/stef-parser/tests/inputs/attribute_single.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample; @@ -25,4 +25,16 @@ impl ::stef::Decode for Sample { Ok(Self) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + 0 + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@attribute_unit.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@attribute_unit.stef.snap index b8ea5b4..263fdd9 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@attribute_unit.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@attribute_unit.stef.snap @@ -4,7 +4,7 @@ description: "#[deprecated]\nstruct Sample" input_file: crates/stef-parser/tests/inputs/attribute_unit.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample; @@ -25,4 +25,16 @@ impl ::stef::Decode for Sample { Ok(Self) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + 0 + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@attributes.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@attributes.stef.snap index 2aa74d6..c6edb7a 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@attributes.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@attributes.stef.snap @@ -4,7 +4,7 @@ description: "#[deprecated = \"don't use\", compress]\n#[validate(\n in_range input_file: crates/stef-parser/tests/inputs/attributes.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample; @@ -25,4 +25,16 @@ impl ::stef::Decode for Sample { Ok(Self) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + 0 + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@attributes_min_ws.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@attributes_min_ws.stef.snap index caca7fd..303c993 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@attributes_min_ws.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@attributes_min_ws.stef.snap @@ -4,7 +4,7 @@ description: "#[deprecated=\"don't use\",compress]\n#[validate(in_range(min=100, input_file: crates/stef-parser/tests/inputs/attributes_min_ws.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample; @@ -25,4 +25,16 @@ impl ::stef::Decode for Sample { Ok(Self) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + 0 + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@const_basic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@const_basic.stef.snap index 1a1b83f..4f91e80 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@const_basic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@const_basic.stef.snap @@ -4,7 +4,7 @@ description: "const BOOL_TRUE: bool = true;\nconst BOOL_FALSE: bool = false;\nco input_file: crates/stef-parser/tests/inputs/const_basic.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[allow(dead_code)] pub const BOOL_TRUE: bool = true; #[allow(dead_code)] diff --git a/crates/stef-build/tests/snapshots/compiler__compile@const_string.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@const_string.stef.snap index 86704af..3504156 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@const_string.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@const_string.stef.snap @@ -4,7 +4,7 @@ description: "const SIMPLE: string = \"value\";\n\nconst NEWLINE_ESCAPE: string input_file: crates/stef-parser/tests/inputs/const_string.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[allow(dead_code)] pub const SIMPLE: &str = "value"; #[allow(dead_code)] diff --git a/crates/stef-build/tests/snapshots/compiler__compile@enum_basic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@enum_basic.stef.snap index d6d790d..bb2b34b 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@enum_basic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@enum_basic.stef.snap @@ -4,7 +4,7 @@ description: "/// Sample enum.\nenum Sample {\n One @1,\n /// Second varia input_file: crates/stef-parser/tests/inputs/enum_basic.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Sample enum. #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -113,4 +113,29 @@ impl ::stef::Decode for Sample { } } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + Self::One => ::stef::buf::size_id(1), + Self::Two(n0, n1) => { + ::stef::buf::size_id(2) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*n0) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_u64(*n1) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + Self::Three { field1, field2 } => { + ::stef::buf::size_id(3) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*field1) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(*field2) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@enum_generics.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@enum_generics.stef.snap index b73ff14..c9404ac 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@enum_generics.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@enum_generics.stef.snap @@ -4,7 +4,7 @@ description: "/// Enum with generics.\nenum Sample {\n One @1,\n input_file: crates/stef-parser/tests/inputs/enum_generics.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Enum with generics. #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -112,4 +112,34 @@ where } } } +#[automatically_derived] +impl ::stef::buf::Size for Sample +where + A: ::stef::buf::Size, + B: ::stef::buf::Size, + C: ::stef::buf::Size, + D: ::stef::buf::Size, +{ + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + Self::One => ::stef::buf::size_id(1), + Self::Two(n0, n1) => { + ::stef::buf::size_id(2) + ::stef::buf::size_field(1, || { (*n0).size() }) + + ::stef::buf::size_field(2, || { (*n1).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + Self::Three { field1, field2 } => { + ::stef::buf::size_id(3) + + ::stef::buf::size_field(1, || { (*field1).size() }) + + ::stef::buf::size_field(2, || { (*field2).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@enum_many_ws.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@enum_many_ws.stef.snap index 6d915b1..b479511 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@enum_many_ws.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@enum_many_ws.stef.snap @@ -4,7 +4,7 @@ description: "/// Sample enum.\n enum Sample {\n\n One @1,\n\n input_file: crates/stef-parser/tests/inputs/enum_many_ws.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Sample enum. #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -108,4 +108,29 @@ impl ::stef::Decode for Sample { } } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + Self::One => ::stef::buf::size_id(1), + Self::Two(n0, n1) => { + ::stef::buf::size_id(2) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*n0) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_u64(*n1) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + Self::Three { field1, field2 } => { + ::stef::buf::size_id(3) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*field1) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(*field2) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@enum_min_ws.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@enum_min_ws.stef.snap index c3e3a7b..1470aaa 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@enum_min_ws.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@enum_min_ws.stef.snap @@ -4,7 +4,7 @@ description: "enum Sample{One@1,Two(u32@1,u64@2,T@3)@2,Three{field1:u32@1,fie input_file: crates/stef-parser/tests/inputs/enum_min_ws.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub enum Sample { @@ -129,4 +129,34 @@ where } } } +#[automatically_derived] +impl ::stef::buf::Size for Sample +where + T: ::stef::buf::Size, +{ + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + Self::One => ::stef::buf::size_id(1), + Self::Two(n0, n1, n2) => { + ::stef::buf::size_id(2) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*n0) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_u64(*n1) }) + + ::stef::buf::size_field(3, || { (*n2).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + Self::Three { field1, field2, field3 } => { + ::stef::buf::size_id(3) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*field1) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(*field2) }) + + ::stef::buf::size_field(3, || { (*field3).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@import_basic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@import_basic.stef.snap index bd18da8..df862af 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@import_basic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@import_basic.stef.snap @@ -4,7 +4,7 @@ description: "use other::schema::Sample;\nuse second::submodule;" input_file: crates/stef-parser/tests/inputs/import_basic.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[allow(unused_imports)] use super::other::schema::Sample; #[allow(unused_imports)] diff --git a/crates/stef-build/tests/snapshots/compiler__compile@module_basic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@module_basic.stef.snap index 65b682e..0648ae3 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@module_basic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@module_basic.stef.snap @@ -4,14 +4,14 @@ description: "mod a {\n /// Inner module\n mod b {\n enum Sample {\ input_file: crates/stef-parser/tests/inputs/module_basic.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; pub mod a { #[allow(unused_imports)] - use ::stef::buf::{Decode, Encode}; + use ::stef::buf::{Decode, Encode, Size}; /// Inner module pub mod b { #[allow(unused_imports)] - use ::stef::buf::{Decode, Encode}; + use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub enum Sample { @@ -42,6 +42,19 @@ pub mod a { } } } + #[automatically_derived] + impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + Self::One => ::stef::buf::size_id(1), + } + } + } } #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -103,5 +116,19 @@ pub mod a { }) } } + #[automatically_derived] + impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(self.value) }) + + ::stef::buf::size_field(2, || { (self.inner).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } } diff --git a/crates/stef-build/tests/snapshots/compiler__compile@schema_basic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@schema_basic.stef.snap index 637313c..786304d 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@schema_basic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@schema_basic.stef.snap @@ -4,7 +4,7 @@ description: "/// Basic struct.\nstruct SampleStruct {\n a: u32 @1,\n b: b input_file: crates/stef-parser/tests/inputs/schema_basic.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Basic struct. #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -66,6 +66,20 @@ impl ::stef::Decode for SampleStruct { }) } } +#[automatically_derived] +impl ::stef::buf::Size for SampleStruct { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(self.a) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(self.b) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} /// Sample enum. #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -169,4 +183,29 @@ impl ::stef::Decode for SampleEnum { } } } +#[automatically_derived] +impl ::stef::buf::Size for SampleEnum { + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + Self::One => ::stef::buf::size_id(1), + Self::Two(n0, n1) => { + ::stef::buf::size_id(2) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*n0) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_u64(*n1) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + Self::Three { field1, field2 } => { + ::stef::buf::size_id(3) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*field1) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(*field2) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@struct_basic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@struct_basic.stef.snap index dfcfbac..9505a4f 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@struct_basic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@struct_basic.stef.snap @@ -4,7 +4,7 @@ description: "/// Basic struct.\nstruct Sample {\n a: u32 @1,\n /// Second input_file: crates/stef-parser/tests/inputs/struct_basic.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Basic struct. #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -67,4 +67,18 @@ impl ::stef::Decode for Sample { }) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(self.a) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(self.b) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@struct_generics.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@struct_generics.stef.snap index 2a2e25e..87cdc0b 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@struct_generics.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@struct_generics.stef.snap @@ -4,7 +4,7 @@ description: "/// Generic key-value pair.\nstruct KeyValue {\n key: K @ input_file: crates/stef-parser/tests/inputs/struct_generics.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Generic key-value pair. #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -74,4 +74,22 @@ where }) } } +#[automatically_derived] +impl ::stef::buf::Size for KeyValue +where + K: ::stef::buf::Size, + V: ::stef::buf::Size, +{ + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { (self.key).size() }) + + ::stef::buf::size_field(2, || { (self.value).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@struct_many_ws.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@struct_many_ws.stef.snap index 5c74b76..460f1bc 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@struct_many_ws.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@struct_many_ws.stef.snap @@ -4,7 +4,7 @@ description: "/// Some comment\n struct Sample<\n T\n input_file: crates/stef-parser/tests/inputs/struct_many_ws.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Some comment #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -87,4 +87,22 @@ where }) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample +where + T: ::stef::buf::Size, +{ + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(self.a) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(self.b) }) + + ::stef::buf::size_field(3, || { (self.c).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@struct_min_ws.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@struct_min_ws.stef.snap index 4c02110..1a7014e 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@struct_min_ws.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@struct_min_ws.stef.snap @@ -4,7 +4,7 @@ description: "struct Sample{a:u32@1,b:bool@2,c:T@3}" input_file: crates/stef-parser/tests/inputs/struct_min_ws.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample { @@ -86,4 +86,22 @@ where }) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample +where + T: ::stef::buf::Size, +{ + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(self.a) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(self.b) }) + + ::stef::buf::size_field(3, || { (self.c).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@struct_tuple.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@struct_tuple.stef.snap index 59b2879..ddeb50d 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@struct_tuple.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@struct_tuple.stef.snap @@ -4,7 +4,7 @@ description: "/// Basic struct.\nstruct Sample(u32 @1, bool @2)" input_file: crates/stef-parser/tests/inputs/struct_tuple.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Basic struct. #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -65,4 +65,18 @@ impl ::stef::Decode for Sample { ) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(self.0) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_bool(self.1) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@types_basic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@types_basic.stef.snap index e23016b..d03920c 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@types_basic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@types_basic.stef.snap @@ -4,7 +4,7 @@ description: "struct Sample {\n f01: bool @1,\n f02: u8 @2,\n f03: u16 input_file: crates/stef-parser/tests/inputs/types_basic.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample { @@ -375,4 +375,47 @@ impl ::stef::Decode for Sample { }) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_bool(self.f01) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_u8(self.f02) }) + + ::stef::buf::size_field(3, || { ::stef::buf::size_u16(self.f03) }) + + ::stef::buf::size_field(4, || { ::stef::buf::size_u32(self.f04) }) + + ::stef::buf::size_field(5, || { ::stef::buf::size_u64(self.f05) }) + + ::stef::buf::size_field(6, || { ::stef::buf::size_u128(self.f06) }) + + ::stef::buf::size_field(7, || { ::stef::buf::size_i8(self.f07) }) + + ::stef::buf::size_field(8, || { ::stef::buf::size_i16(self.f08) }) + + ::stef::buf::size_field(9, || { ::stef::buf::size_i32(self.f09) }) + + ::stef::buf::size_field(10, || { ::stef::buf::size_i64(self.f10) }) + + ::stef::buf::size_field(11, || { ::stef::buf::size_i128(self.f11) }) + + ::stef::buf::size_field(12, || { ::stef::buf::size_f32(self.f12) }) + + ::stef::buf::size_field(13, || { ::stef::buf::size_f64(self.f13) }) + + ::stef::buf::size_field(14, || { ::stef::buf::size_string(&self.f14) }) + + ::stef::buf::size_field(15, || { ::stef::buf::size_string(&self.f15) }) + + ::stef::buf::size_field(16, || { ::stef::buf::size_bytes_std(&self.f16) }) + + ::stef::buf::size_field(17, || { ::stef::buf::size_bytes_std(&self.f17) }) + + ::stef::buf::size_field(18, || { ::stef::buf::size_string(&self.f18) }) + + ::stef::buf::size_field(19, || { ::stef::buf::size_bytes_std(&self.f19) }) + + ::stef::buf::size_field( + 20, + || { + ::stef::buf::size_u32(self.f20.0) + ::stef::buf::size_u32(self.f20.1) + + ::stef::buf::size_u32(self.f20.2) + }, + ) + + ::stef::buf::size_field( + 21, + || { + ::stef::buf::size_array(&self.f21, |v| { ::stef::buf::size_u32(*v) }) + }, + ) + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@types_generic.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@types_generic.stef.snap index 0db64bd..40f20d8 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@types_generic.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@types_generic.stef.snap @@ -4,7 +4,7 @@ description: "struct Sample {\n f1: vec @1,\n f2: hash_map usize { + ::stef::buf::size_field( + 1, + || { ::stef::buf::size_vec(&self.f1, |v| { ::stef::buf::size_u32(*v) }) }, + ) + + ::stef::buf::size_field( + 2, + || { + ::stef::buf::size_hash_map( + &self.f2, + |k| { ::stef::buf::size_u32(*k) }, + |v| { ::stef::buf::size_string(&v) }, + ) + }, + ) + + ::stef::buf::size_field( + 3, + || { + ::stef::buf::size_hash_set( + &self.f3, + |v| { ::stef::buf::size_u32(*v) }, + ) + }, + ) + + ::stef::buf::size_field_option( + 4, + self.f4.as_ref(), + |v| { ::stef::buf::size_u32(*v) }, + ) + ::stef::buf::size_field(5, || { ::stef::buf::size_u32(self.f5.get()) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct SampleUnnamed( @@ -291,4 +331,44 @@ impl ::stef::Decode for SampleUnnamed { ) } } +#[automatically_derived] +impl ::stef::buf::Size for SampleUnnamed { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field( + 1, + || { ::stef::buf::size_vec(&self.0, |v| { ::stef::buf::size_u32(*v) }) }, + ) + + ::stef::buf::size_field( + 2, + || { + ::stef::buf::size_hash_map( + &self.1, + |k| { ::stef::buf::size_u32(*k) }, + |v| { ::stef::buf::size_string(&v) }, + ) + }, + ) + + ::stef::buf::size_field( + 3, + || { + ::stef::buf::size_hash_set( + &self.2, + |v| { ::stef::buf::size_u32(*v) }, + ) + }, + ) + + ::stef::buf::size_field_option( + 4, + self.3.as_ref(), + |v| { ::stef::buf::size_u32(*v) }, + ) + ::stef::buf::size_field(5, || { ::stef::buf::size_u32(self.4.get()) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@types_nested.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@types_nested.stef.snap index 9fc7855..cd23749 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@types_nested.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@types_nested.stef.snap @@ -4,7 +4,7 @@ description: "struct Sample {\n value: vec usize { + ::stef::buf::size_field( + 1, + || { + ::stef::buf::size_vec( + &self.value, + |v| { + ::stef::buf::size_option( + v.as_ref(), + |v| { + ::stef::buf::size_hash_map( + &v.get(), + |k| { ::stef::buf::size_i64(*k) }, + |v| { ::stef::buf::size_string(&v) }, + ) + }, + ) + }, + ) + }, + ) + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@types_non_zero.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@types_non_zero.stef.snap index 08f93a3..1de9d21 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@types_non_zero.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@types_non_zero.stef.snap @@ -4,7 +4,7 @@ description: "struct Sample {\n f01: non_zero @1,\n f02: non_zero input_file: crates/stef-parser/tests/inputs/types_non_zero.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample { @@ -303,4 +303,61 @@ impl ::stef::Decode for Sample { }) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_u8(self.f01.get()) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_u16(self.f02.get()) }) + + ::stef::buf::size_field(3, || { ::stef::buf::size_u32(self.f03.get()) }) + + ::stef::buf::size_field(4, || { ::stef::buf::size_u64(self.f04.get()) }) + + ::stef::buf::size_field(5, || { ::stef::buf::size_u128(self.f05.get()) }) + + ::stef::buf::size_field(6, || { ::stef::buf::size_i8(self.f06.get()) }) + + ::stef::buf::size_field(7, || { ::stef::buf::size_i16(self.f07.get()) }) + + ::stef::buf::size_field(8, || { ::stef::buf::size_i32(self.f08.get()) }) + + ::stef::buf::size_field(9, || { ::stef::buf::size_i64(self.f09.get()) }) + + ::stef::buf::size_field(10, || { ::stef::buf::size_i128(self.f10.get()) }) + + ::stef::buf::size_field( + 11, + || { ::stef::buf::size_string(&self.f11.get()) }, + ) + + ::stef::buf::size_field( + 12, + || { ::stef::buf::size_bytes_std(&self.f12.get()) }, + ) + + ::stef::buf::size_field( + 13, + || { + ::stef::buf::size_vec( + &self.f13.get(), + |v| { ::stef::buf::size_string(&v) }, + ) + }, + ) + + ::stef::buf::size_field( + 14, + || { + ::stef::buf::size_hash_map( + &self.f14.get(), + |k| { ::stef::buf::size_string(&k) }, + |v| { ::stef::buf::size_bytes_std(&v) }, + ) + }, + ) + + ::stef::buf::size_field( + 15, + || { + ::stef::buf::size_hash_set( + &self.f15.get(), + |v| { ::stef::buf::size_string(&v) }, + ) + }, + ) + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile@types_ref.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile@types_ref.stef.snap index d5b5a71..ba15fc1 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile@types_ref.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile@types_ref.stef.snap @@ -4,7 +4,7 @@ description: "struct Sample {\n basic: Test123 @1,\n with_generics: KeyVal input_file: crates/stef-parser/tests/inputs/types_ref.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct Sample { @@ -65,6 +65,20 @@ impl ::stef::Decode for Sample { }) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { (self.basic).size() }) + + ::stef::buf::size_field(2, || { (self.with_generics).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub enum Test123 { @@ -95,6 +109,19 @@ impl ::stef::Decode for Test123 { } } } +#[automatically_derived] +impl ::stef::buf::Size for Test123 { + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + Self::Value => ::stef::buf::size_id(1), + } + } +} #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] pub struct KeyValue { @@ -163,4 +190,22 @@ where }) } } +#[automatically_derived] +impl ::stef::buf::Size for KeyValue +where + K: ::stef::buf::Size, + V: ::stef::buf::Size, +{ + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { (self.key).size() }) + + ::stef::buf::size_field(2, || { (self.value).size() }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile_extra@alias.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile_extra@alias.stef.snap index 1c9e3ab..83af27d 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile_extra@alias.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile_extra@alias.stef.snap @@ -4,7 +4,7 @@ description: "/// Hello world!\ntype Sample = String;" input_file: crates/stef-build/tests/inputs_extra/alias.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Hello world! #[allow(dead_code, clippy::module_name_repetitions, clippy::option_option)] pub type Sample = String; diff --git a/crates/stef-build/tests/snapshots/compiler__compile_extra@const.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile_extra@const.stef.snap index 8c6b700..95941de 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile_extra@const.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile_extra@const.stef.snap @@ -4,7 +4,7 @@ description: "/// A bool.\nconst BOOL: bool = true;\n/// An integer.\nconst INT: input_file: crates/stef-build/tests/inputs_extra/const.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// A bool. #[allow(dead_code)] pub const BOOL: bool = true; diff --git a/crates/stef-build/tests/snapshots/compiler__compile_extra@enum.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile_extra@enum.stef.snap index 79ebe86..ee855e5 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile_extra@enum.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile_extra@enum.stef.snap @@ -4,7 +4,7 @@ description: "/// Hello world!\nenum Sample {\n Variant1 @1,\n Variant2(u3 input_file: crates/stef-build/tests/inputs_extra/enum.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Hello world! #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -123,4 +123,39 @@ impl ::stef::Decode for Sample { } } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::semicolon_if_nothing_returned, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + match self { + Self::Variant1 => ::stef::buf::size_id(1), + Self::Variant2(n0, n1) => { + ::stef::buf::size_id(2) + + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(*n0) }) + + ::stef::buf::size_field(2, || { ::stef::buf::size_u8(*n1) }) + + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + Self::Variant3 { field1, field2 } => { + ::stef::buf::size_id(3) + + ::stef::buf::size_field( + 1, + || { ::stef::buf::size_string(&*field1) }, + ) + + ::stef::buf::size_field( + 2, + || { + ::stef::buf::size_vec( + &*field2, + |v| { ::stef::buf::size_bool(*v) }, + ) + }, + ) + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } + } + } +} diff --git a/crates/stef-build/tests/snapshots/compiler__compile_extra@import.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile_extra@import.stef.snap index f556eb3..b7f10e6 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile_extra@import.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile_extra@import.stef.snap @@ -4,7 +4,7 @@ description: "use other::module;\nuse other::module::Type;" input_file: crates/stef-build/tests/inputs_extra/import.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; #[allow(unused_imports)] use super::other::module; #[allow(unused_imports)] diff --git a/crates/stef-build/tests/snapshots/compiler__compile_extra@module.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile_extra@module.stef.snap index 487da13..cce10fb 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile_extra@module.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile_extra@module.stef.snap @@ -4,10 +4,10 @@ description: "/// Hello world!\nmod sample {}" input_file: crates/stef-build/tests/inputs_extra/module.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Hello world! pub mod sample { #[allow(unused_imports)] - use ::stef::buf::{Decode, Encode}; + use ::stef::buf::{Decode, Encode, Size}; } diff --git a/crates/stef-build/tests/snapshots/compiler__compile_extra@struct.stef.snap b/crates/stef-build/tests/snapshots/compiler__compile_extra@struct.stef.snap index e857444..84feb20 100644 --- a/crates/stef-build/tests/snapshots/compiler__compile_extra@struct.stef.snap +++ b/crates/stef-build/tests/snapshots/compiler__compile_extra@struct.stef.snap @@ -4,7 +4,7 @@ description: "/// Hello world!\nstruct Sample {\n field1: u32 @1,\n field2 input_file: crates/stef-build/tests/inputs_extra/struct.stef --- #[allow(unused_imports)] -use ::stef::buf::{Decode, Encode}; +use ::stef::buf::{Decode, Encode, Size}; /// Hello world! #[derive(Clone, Debug, PartialEq)] #[allow(clippy::module_name_repetitions, clippy::option_option)] @@ -103,4 +103,30 @@ impl ::stef::Decode for Sample { }) } } +#[automatically_derived] +impl ::stef::buf::Size for Sample { + #[allow( + clippy::borrow_deref_ref, + clippy::explicit_auto_deref, + clippy::needless_borrow, + clippy::too_many_lines, + )] + fn size(&self) -> usize { + ::stef::buf::size_field(1, || { ::stef::buf::size_u32(self.field1) }) + + ::stef::buf::size_field( + 2, + || { ::stef::buf::size_bytes_std(&self.field2) }, + ) + + ::stef::buf::size_field( + 3, + || { + ::stef::buf::size_bool(self.field3.0) + + ::stef::buf::size_array( + &&(self.field3.1), + |v| { ::stef::buf::size_i16(*v) }, + ) + }, + ) + ::stef::buf::size_u32(::stef::buf::END_MARKER) + } +} diff --git a/crates/stef/src/buf/encode.rs b/crates/stef/src/buf/encode.rs index d7049ef..88be4cc 100644 --- a/crates/stef/src/buf/encode.rs +++ b/crates/stef/src/buf/encode.rs @@ -114,7 +114,7 @@ where W: BufMut, E: Fn(&mut W, &T), { - encode_u64(w, array.len() as u64); + encode_u64(w, N as u64); for value in array { encode(w, value); diff --git a/crates/stef/src/buf/mod.rs b/crates/stef/src/buf/mod.rs index ad1e0d7..9e707c5 100644 --- a/crates/stef/src/buf/mod.rs +++ b/crates/stef/src/buf/mod.rs @@ -2,9 +2,11 @@ pub use decode::*; pub use encode::*; +pub use size::*; mod decode; mod encode; +mod size; #[cfg(test)] mod tests { diff --git a/crates/stef/src/buf/size.rs b/crates/stef/src/buf/size.rs new file mode 100644 index 0000000..53643b7 --- /dev/null +++ b/crates/stef/src/buf/size.rs @@ -0,0 +1,268 @@ +use std::collections::{HashMap, HashSet}; + +use bytes::Bytes; + +use crate::{varint, NonZero}; + +macro_rules! size_fixed { + ($ty:ty => $size:literal) => { + paste::paste! { + #[inline(always)] + #[must_use] + pub const fn [](_: $ty) -> usize { + $size + } + } + }; + ($($ty:ty => $size:literal),+ $(,)?) => { + $(size_fixed!($ty => $size);)+ + }; +} + +size_fixed!( + bool => 1, + u8 => 1, + i8 => 1, + f32 => 4, + f64 => 8, +); + +macro_rules! size_int { + ($ty:ty) => { + paste::paste! { + #[must_use] + pub const fn [](value: $ty) -> usize { + varint::[](value) + } + } + }; + ($($ty:ty),+ $(,)?) => { + $(size_int!($ty);)+ + }; +} + +size_int!(u16, u32, u64, u128); +size_int!(i16, i32, i64, i128); + +#[must_use] +pub const fn size_string(value: &str) -> usize { + size_bytes_std(value.as_bytes()) +} + +#[must_use] +pub const fn size_bytes_std(value: &[u8]) -> usize { + size_u64(value.len() as u64) + value.len() +} + +pub const fn size_bytes_bytes(value: &Bytes) -> usize { + size_u64(value.len() as u64) + value.len() +} + +pub fn size_vec(vec: &[T], size: S) -> usize +where + S: Fn(&T) -> usize, +{ + size_u64(vec.len() as u64) + vec.iter().map(size).sum::() +} + +pub fn size_hash_map(map: &HashMap, size_key: SK, size_value: SV) -> usize +where + SK: Fn(&K) -> usize, + SV: Fn(&V) -> usize, +{ + size_u64(map.len() as u64) + + map + .iter() + .map(|(key, value)| size_key(key) + size_value(value)) + .sum::() +} + +pub fn size_hash_set(set: &HashSet, size: S) -> usize +where + S: Fn(&T) -> usize, +{ + size_u64(set.len() as u64) + set.iter().map(size).sum::() +} + +pub fn size_option(option: Option<&T>, size: S) -> usize +where + S: Fn(&T) -> usize, +{ + size_u8(0) + option.map_or(0, size) +} + +pub fn size_array(array: &[T; N], size: S) -> usize +where + S: Fn(&T) -> usize, +{ + size_u64(N as u64) + array.iter().map(size).sum::() +} + +#[inline(always)] +#[must_use] +pub fn size_id(id: u32) -> usize { + size_u32(id) +} + +#[inline(always)] +pub fn size_field(id: u32, size: S) -> usize +where + S: Fn() -> usize, +{ + size_id(id) + size() +} + +#[inline(always)] +pub fn size_field_option(id: u32, option: Option<&T>, size: S) -> usize +where + S: Fn(&T) -> usize, +{ + option.map_or(0, |value| size_id(id) + size(value)) +} + +pub trait Size { + fn size(&self) -> usize; +} + +macro_rules! forward { + ($ty:ty) => { + paste::paste! { + impl Size for $ty { + #[inline(always)] + fn size(&self) -> usize { + [](*self) + } + } + } + }; + ($($ty:ty),+ $(,)?) => { + $(forward!($ty);)+ + }; +} + +forward!(bool); +forward!(u8, u16, u32, u64, u128); +forward!(i8, i16, i32, i64, i128); +forward!(f32, f64); + +impl Size for String { + #[inline(always)] + fn size(&self) -> usize { + size_string(self) + } +} + +impl Size for Box { + #[inline(always)] + fn size(&self) -> usize { + size_string(self) + } +} + +impl Size for Box<[u8]> { + #[inline(always)] + fn size(&self) -> usize { + size_bytes_std(self) + } +} + +impl Size for Vec +where + T: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + size_vec(self, Size::size) + } +} + +impl Size for &'_ [T] +where + T: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + size_vec(self, Size::size) + } +} + +impl Size for HashMap +where + K: Size, + V: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + size_hash_map(self, Size::size, Size::size) + } +} + +impl Size for HashSet +where + T: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + size_hash_set(self, Size::size) + } +} + +impl Size for Option +where + T: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + size_option(self.as_ref(), Size::size) + } +} + +impl Size for [T; N] +where + T: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + size_array(self, Size::size) + } +} + +impl Size for NonZero +where + T: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + self.0.size() + } +} + +impl Size for std::borrow::Cow<'_, T> +where + T: Clone + Size, +{ + #[inline(always)] + fn size(&self) -> usize { + T::size(self) + } +} + +impl Size for std::rc::Rc +where + T: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + T::size(self) + } +} + +impl Size for std::sync::Arc +where + T: Size, +{ + #[inline(always)] + fn size(&self) -> usize { + T::size(self) + } +} diff --git a/crates/stef/src/varint.rs b/crates/stef/src/varint.rs index 2a275f6..5e62cb8 100644 --- a/crates/stef/src/varint.rs +++ b/crates/stef/src/varint.rs @@ -7,13 +7,13 @@ macro_rules! zigzag { paste::paste! { #[doc = "Use the _ZigZag_ scheme to encode an `" $from "` as `" $to "`."] #[inline] - fn [](value: $from) -> $to { + const fn [](value: $from) -> $to { ((value << 1) ^ (value >> ($from::BITS - 1))) as $to } #[doc = "Convert a _ZigZag_ encoded `" $from "` back to its original data."] #[inline] - fn [](value: $to) -> $from { + const fn [](value: $to) -> $from { ((value >> 1) as $from) ^ (-((value & 0b1) as $from)) } } @@ -32,8 +32,13 @@ zigzag!( /// Calculate the maximum amount of bytes that an integer might require to be encoded as _varint_. #[inline] -pub(crate) const fn max_size() -> usize { - (std::mem::size_of::() * 8 + 7) / 7 +const fn max_size() -> usize { + (std::mem::size_of::() * 8 + 6) / 7 +} + +#[inline] +const fn size(leading_zeros: usize) -> usize { + (std::mem::size_of::() * 8 - leading_zeros + 6) / 7 } macro_rules! varint { @@ -72,6 +77,12 @@ macro_rules! varint { Err(DecodeIntError) } + #[inline] + #[must_use] + pub const fn [](value: $ty) -> usize { + size::<$ty>(value.leading_zeros() as usize) + } + #[inline] #[must_use] pub fn [](value: $signed) -> ([u8; max_size::<$ty>()], usize) { @@ -82,6 +93,13 @@ macro_rules! varint { pub fn [](buf: &[u8]) -> Result<($signed, usize), DecodeIntError> { [](buf).map(|(v, b)| ([](v), b)) } + + #[inline] + #[must_use] + pub const fn [](value: $signed) -> usize { + size::<$ty>([](value).leading_zeros() as usize) + } + } }; ($(($ty:ty, $signed:ty)),+ $(,)?) => {