diff --git a/CHANGELOG.md b/CHANGELOG.md index c199fb7..728b66b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ All notable changes to this project will be documented in this file. ### 🚜 Refactor -- Generate definitions and impls together ([e65b8cd](https://github.com/dnaka91/wazzup/commit/e65b8cdc8a3256eef36c4d5d0f42176506c9a90b)) +- Generate definitions and impls together ([b32bcfd](https://github.com/dnaka91/wazzup/commit/b32bcfd8630bc445421ce32b784de6601659aade)) ### ⚙️ Miscellaneous Tasks diff --git a/crates/stef-build/src/decode.rs b/crates/stef-build/src/decode.rs new file mode 100644 index 0000000..1767e54 --- /dev/null +++ b/crates/stef-build/src/decode.rs @@ -0,0 +1,252 @@ +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use stef_parser::{DataType, Enum, Fields, NamedField, Struct, UnnamedField, Variant}; + +pub fn compile_struct( + Struct { + comment: _, + attributes: _, + name, + generics: _, + fields, + }: &Struct<'_>, +) -> TokenStream { + let name = Ident::new(name, Span::call_site()); + let field_vars = compile_field_vars(fields); + let field_matches = compile_field_matches(fields); + let field_assigns = compile_field_assigns(fields); + + quote! { + impl ::stef::Decode for #name { + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + #field_vars + + loop{ + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + #field_matches + _ => continue, + } + } + + Ok(Self #field_assigns) + } + } + } +} + +pub fn compile_enum( + Enum { + comment: _, + attributes: _, + name, + generics: _, + variants, + }: &Enum<'_>, +) -> TokenStream { + let name = Ident::new(name, Span::call_site()); + let variants = variants.iter().map(compile_variant); + + quote! { + impl ::stef::Decode for #name { + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + match ::stef::buf::decode_id(r)? { + #(#variants,)* + id => Err(Error::UnknownVariant(id)), + } + } + } + } +} + +fn compile_variant( + Variant { + comment: _, + name, + fields, + id, + }: &Variant<'_>, +) -> TokenStream { + let id = proc_macro2::Literal::u32_unsuffixed(id.0); + let name = Ident::new(name, Span::call_site()); + let field_vars = compile_field_vars(fields); + let field_matches = compile_field_matches(fields); + let field_assigns = compile_field_assigns(fields); + + quote! { + #id => { + #field_vars + + loop{ + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + #field_matches + _ => continue, + } + } + + Ok(Self::#name #field_assigns) + } + } +} + +fn compile_field_vars(fields: &Fields<'_>) -> TokenStream { + match fields { + Fields::Named(named) => { + let vars = named.iter().map(|named| { + let name = Ident::new(named.name, Span::call_site()); + let ty = super::definition::compile_data_type(&named.ty); + + quote! { let mut #name: Option<#ty> = None; } + }); + + quote! { #(#vars)* } + } + Fields::Unnamed(unnamed) => { + let vars = unnamed.iter().enumerate().map(|(idx, unnamed)| { + let name = Ident::new(&format!("n{idx}"), Span::call_site()); + let ty = super::definition::compile_data_type(&unnamed.ty); + + quote! { let mut #name: Option<#ty> = None;} + }); + + quote! { #(#vars)* } + } + Fields::Unit => quote! {}, + } +} + +fn compile_field_matches(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.0); + let name = proc_macro2::Ident::new(name, Span::call_site()); + let ty = compile_data_type(ty); + + quote! { #id => #name = Some(#ty?) } + }, + ); + + quote! { #(#calls,)* } + } + Fields::Unnamed(unnamed) => { + let calls = unnamed + .iter() + .enumerate() + .map(|(idx, UnnamedField { ty, id })| { + let id = proc_macro2::Literal::u32_unsuffixed(id.0); + let name = Ident::new(&format!("n{idx}"), Span::call_site()); + let ty = compile_data_type(ty); + + quote! { #id => #name = Some(#ty?) } + }); + + quote! { #(#calls,)* } + } + Fields::Unit => quote! {}, + } +} + +fn compile_field_assigns(fields: &Fields<'_>) -> TokenStream { + match fields { + Fields::Named(named) => { + let assigns = named.iter().map(|named| { + let name = Ident::new(named.name, Span::call_site()); + let name_lit = proc_macro2::Literal::string(named.name); + let id = proc_macro2::Literal::u32_unsuffixed(named.id.0); + + if matches!(named.ty, DataType::Option(_)) { + quote! { #name } + } else { + quote! { #name: #name.unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: #id, + name: Some(#name_lit), + }) } + } + }); + + quote! { {#(#assigns,)*} } + } + Fields::Unnamed(unnamed) => { + let assigns = unnamed.iter().enumerate().map(|(idx, unnamed)| { + let name = Ident::new(&format!("n{idx}"), Span::call_site()); + let id = proc_macro2::Literal::u32_unsuffixed(unnamed.id.0); + + if matches!(unnamed.ty, DataType::Option(_)) { + quote! { #name } + } else { + quote! { #name.unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: #id, + name: None, + }) } + } + }); + + quote! { (#(#assigns,)*) } + } + Fields::Unit => quote! {}, + } +} + +#[allow(clippy::needless_pass_by_value)] +fn compile_data_type(ty: &DataType<'_>) -> TokenStream { + match ty { + DataType::Bool => quote! { ::stef::buf::decode_bool(r) }, + DataType::U8 => quote! { ::stef::buf::decode_u8(r) }, + DataType::U16 => quote! { ::stef::buf::decode_u16(r) }, + DataType::U32 => quote! { ::stef::buf::decode_u32(r) }, + DataType::U64 => quote! { ::stef::buf::decode_u64(r) }, + DataType::U128 => quote! { ::stef::buf::decode_u128(r) }, + DataType::I8 => quote! { ::stef::buf::decode_i8(r) }, + DataType::I16 => quote! { ::stef::buf::decode_i16(r) }, + DataType::I32 => quote! { ::stef::buf::decode_i32(r) }, + DataType::I64 => quote! { ::stef::buf::decode_i64(r) }, + DataType::I128 => quote! { ::stef::buf::decode_i128(r) }, + DataType::F32 => quote! { ::stef::buf::decode_f32(r) }, + DataType::F64 => quote! { ::stef::buf::decode_f64(r) }, + DataType::String | DataType::StringRef => quote! { ::stef::buf::decode_string(r) }, + DataType::Bytes | DataType::BytesRef => quote! { ::stef::buf::decode_bytes(r) }, + DataType::Vec(_ty) => quote! { ::stef::buf::decode_vec(r) }, + DataType::HashMap(_kv) => quote! { ::stef::buf::decode_hash_map(r) }, + DataType::HashSet(_ty) => quote! { ::stef::buf::decode_hash_set(r) }, + DataType::Option(ty) => compile_data_type(ty), + DataType::NonZero(ty) => match **ty { + DataType::U8 => quote! { NonZeroU8::decode(r) }, + DataType::U16 => quote! { NonZeroU16::decode(r) }, + DataType::U32 => quote! { NonZeroU32::decode(r) }, + DataType::U64 => quote! { NonZeroU64::decode(r) }, + DataType::U128 => quote! { NonZeroU128::decode(r) }, + DataType::I8 => quote! { NonZeroI8::decode(r) }, + DataType::I16 => quote! { NonZeroI16::decode(r) }, + DataType::I32 => quote! { NonZeroI32::decode(r) }, + DataType::I64 => quote! { NonZeroI64::decode(r) }, + DataType::I128 => quote! { NonZeroI128::decode(r) }, + _ => todo!(), + }, + DataType::BoxString => quote! { Box::decode(r) }, + DataType::BoxBytes => quote! { Box<[u8]>::decode(r) }, + DataType::Tuple(types) => match types.len() { + size @ 2..=12 => { + let fn_name = Ident::new(&format!("decode_tuple{size}"), Span::call_site()); + quote! { ::stef::buf::#fn_name(r) } + } + 0 => panic!("tuple with zero elements"), + 1 => panic!("tuple with single element"), + _ => panic!("tuple with more than 12 elements"), + }, + DataType::Array(_ty, _size) => { + quote! { ::stef::buf::decode_array(r) } + } + DataType::External(ty) => { + let ty = Ident::new(ty.name, Span::call_site()); + quote! { #ty::decode(r) } + } + } +} diff --git a/crates/stef-build/src/definition.rs b/crates/stef-build/src/definition.rs index 9001a3a..b742d1d 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, TypeAlias, UnnamedField, Variant, }; -use super::encode; +use super::{decode, encode}; pub(crate) fn compile_schema(Schema { definitions }: &Schema<'_>) -> TokenStream { let definitions = definitions.iter().map(compile_definition); @@ -19,19 +19,23 @@ fn compile_definition(definition: &Definition<'_>) -> TokenStream { Definition::Struct(s) => { let def = compile_struct(s); let encode = encode::compile_struct(s); + let decode = decode::compile_struct(s); quote! { #def #encode + #decode } } Definition::Enum(e) => { let def = compile_enum(e); let encode = encode::compile_enum(e); + let decode = decode::compile_enum(e); quote! { #def #encode + #decode } } Definition::TypeAlias(a) => compile_alias(a), @@ -222,7 +226,7 @@ fn compile_fields(fields: &Fields<'_>, public: bool) -> TokenStream { } } -fn compile_data_type(ty: &DataType<'_>) -> TokenStream { +pub(super) fn compile_data_type(ty: &DataType<'_>) -> TokenStream { match ty { DataType::Bool => quote! { bool }, DataType::U8 => quote! { u8 }, @@ -331,6 +335,8 @@ fn compile_literal(literal: &Literal) -> TokenStream { #[cfg(test)] mod tests { + #![allow(clippy::too_many_lines)] + use indoc::indoc; use pretty_assertions::assert_eq; @@ -382,9 +388,50 @@ mod tests { } impl ::stef::Encode for Sample { fn encode(&self, w: &mut impl ::stef::BufMut) { - ::stef::write_field(w, 1, |w| { ::stef::encode_u32(w, self.field1) }); - ::stef::write_field(w, 2, |w| { ::stef::encode_bytes(w, &self.field2) }); - ::stef::write_field(w, 3, |w| { ::stef::write_tuple2(w, &self.field3) }); + ::stef::buf::encode_field(w, 1, |w| { ::stef::buf::encode_u32(w, self.field1) }); + ::stef::buf::encode_field( + w, + 2, + |w| { ::stef::buf::encode_bytes(w, &self.field2) }, + ); + ::stef::buf::encode_field( + w, + 3, + |w| { ::stef::buf::encode_tuple2(w, &self.field3) }, + ); + } + } + impl ::stef::Decode for Sample { + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + let mut field1: Option = None; + let mut field2: Option> = None; + let mut field3: Option<(bool, [i16; 4])> = None; + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + 1 => field1 = Some(::stef::buf::decode_u32(r)?), + 2 => field2 = Some(::stef::buf::decode_bytes(r)?), + 3 => field3 = Some(::stef::buf::decode_tuple2(r)?), + _ => continue, + } + } + Ok(Self { + field1: field1 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 1, + name: Some("field1"), + }), + field2: field2 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 2, + name: Some("field2"), + }), + field3: field3 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 3, + name: Some("field3"), + }), + }) } } "#}; @@ -416,18 +463,92 @@ mod tests { fn encode(&self, w: &mut impl ::stef::BufMut) { match self { Self::Variant1 => { - ::stef::write_id(w, 1); + ::stef::buf::encode_id(w, 1); } Self::Variant2(n0, n1) => { - ::stef::write_id(w, 2); - ::stef::write_field(w, 1, |w| { ::stef::encode_u32(w, n0) }); - ::stef::write_field(w, 2, |w| { ::stef::encode_u8(w, n1) }); + ::stef::buf::encode_id(w, 2); + ::stef::buf::encode_field(w, 1, |w| { ::stef::buf::encode_u32(w, n0) }); + ::stef::buf::encode_field(w, 2, |w| { ::stef::buf::encode_u8(w, n1) }); } Self::Variant3 { field1, field2 } => { - ::stef::write_id(w, 3); - ::stef::write_field(w, 1, |w| { ::stef::encode_string(w, &field1) }); - ::stef::write_field(w, 2, |w| { ::stef::encode_vec(w, &field2) }); + ::stef::buf::encode_id(w, 3); + ::stef::buf::encode_field( + w, + 1, + |w| { ::stef::buf::encode_string(w, &field1) }, + ); + ::stef::buf::encode_field( + w, + 2, + |w| { ::stef::buf::encode_vec(w, &field2) }, + ); + } + } + } + } + impl ::stef::Decode for Sample { + fn decode(r: &mut impl ::stef::Buf) -> ::stef::buf::Result { + match ::stef::buf::decode_id(r)? { + 1 => { + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + _ => continue, + } + } + Ok(Self::Variant1) + } + 2 => { + let mut n0: Option = None; + let mut n1: Option = None; + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + 1 => n0 = Some(::stef::buf::decode_u32(r)?), + 2 => n1 = Some(::stef::buf::decode_u8(r)?), + _ => continue, + } + } + Ok( + Self::Variant2( + n0 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 1, + name: None, + }), + n1 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 2, + name: None, + }), + ), + ) + } + 3 => { + let mut field1: Option = None; + let mut field2: Option> = None; + loop { + match ::stef::buf::decode_id(r)? { + ::stef::buf::END_MARKER => break, + 1 => field1 = Some(::stef::buf::decode_string(r)?), + 2 => field2 = Some(::stef::buf::decode_vec(r)?), + _ => continue, + } + } + Ok(Self::Variant3 { + field1: field1 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 1, + name: Some("field1"), + }), + field2: field2 + .unwrap_or_else(|| ::stef::buf::Error::MissingField { + id: 2, + name: Some("field2"), + }), + }) } + id => Err(Error::UnknownVariant(id)), } } } diff --git a/crates/stef-build/src/encode.rs b/crates/stef-build/src/encode.rs index 3bd973f..f2589c4 100644 --- a/crates/stef-build/src/encode.rs +++ b/crates/stef-build/src/encode.rs @@ -37,7 +37,7 @@ fn compile_struct_fields(fields: &Fields<'_>) -> TokenStream { let name = proc_macro2::Ident::new(name, Span::call_site()); let ty = compile_data_type(ty, quote! { self.#name }); - quote! { ::stef::write_field(w, #id, |w| { #ty }); } + quote! { ::stef::buf::encode_field(w, #id, |w| { #ty }); } }, ); @@ -52,7 +52,7 @@ fn compile_struct_fields(fields: &Fields<'_>) -> TokenStream { let idx = proc_macro2::Literal::usize_unsuffixed(idx); let ty = compile_data_type(ty, quote! { self.#idx }); - quote! { ::stef::write_field(w, #id, |w| { #ty }); } + quote! { ::stef::buf::encode_field(w, #id, |w| { #ty }); } }); quote! { #(#calls)* } @@ -104,7 +104,7 @@ fn compile_variant( quote! { Self::#name{ #(#field_names,)* } => { - ::stef::write_id(w, #id); + ::stef::buf::encode_id(w, #id); #fields_body } } @@ -117,14 +117,14 @@ fn compile_variant( quote! { Self::#name(#(#field_names,)*) => { - ::stef::write_id(w, #id); + ::stef::buf::encode_id(w, #id); #fields_body } } } Fields::Unit => quote! { Self::#name => { - ::stef::write_id(w, #id); + ::stef::buf::encode_id(w, #id); #fields_body } }, @@ -145,7 +145,7 @@ fn compile_variant_fields(fields: &Fields<'_>) -> TokenStream { let name = proc_macro2::Ident::new(name, Span::call_site()); let ty = compile_data_type(ty, quote! { #name }); - quote! { ::stef::write_field(w, #id, |w| { #ty }); } + quote! { ::stef::buf::encode_field(w, #id, |w| { #ty }); } }, ); @@ -160,7 +160,7 @@ fn compile_variant_fields(fields: &Fields<'_>) -> TokenStream { let name = Ident::new(&format!("n{idx}"), Span::call_site()); let ty = compile_data_type(ty, name.to_token_stream()); - quote! { ::stef::write_field(w, #id, |w| { #ty }); } + quote! { ::stef::buf::encode_field(w, #id, |w| { #ty }); } }); quote! { #(#calls)* } @@ -172,37 +172,38 @@ fn compile_variant_fields(fields: &Fields<'_>) -> TokenStream { #[allow(clippy::needless_pass_by_value)] fn compile_data_type(ty: &DataType<'_>, name: TokenStream) -> TokenStream { match ty { - DataType::Bool => quote! { ::stef::encode_bool(w, #name) }, - DataType::U8 => quote! { ::stef::encode_u8(w, #name) }, - DataType::U16 => quote! { ::stef::encode_u16(w, #name) }, - DataType::U32 => quote! { ::stef::encode_u32(w, #name) }, - DataType::U64 => quote! { ::stef::encode_u64(w, #name) }, - DataType::U128 => quote! { ::stef::encode_u128(w, #name) }, - DataType::I8 => quote! { ::stef::encode_i8(w, #name) }, - DataType::I16 => quote! { ::stef::encode_i16(w, #name) }, - DataType::I32 => quote! { ::stef::encode_i32(w, #name) }, - DataType::I64 => quote! { ::stef::encode_i64(w, #name) }, - DataType::I128 => quote! { ::stef::encode_i128(w, #name) }, - DataType::F32 => quote! { ::stef::encode_f32(w, #name) }, - DataType::F64 => quote! { ::stef::encode_f64(w, #name) }, - DataType::String | DataType::StringRef => quote! { ::stef::encode_string(w, &#name) }, - DataType::Bytes | DataType::BytesRef => quote! { ::stef::encode_bytes(w, &#name) }, - DataType::Vec(_ty) => quote! { ::stef::encode_vec(w, &#name) }, - DataType::HashMap(_kv) => quote! { ::stef::encode_hash_map(w, #name) }, - DataType::HashSet(_ty) => quote! { ::stef::encode_hash_set(w, #name) }, - DataType::Option(_ty) => quote! { ::stef::encode_option(w, #name) }, - DataType::BoxString => quote! { ::stef::encode_string(w, &*#name) }, - DataType::BoxBytes => quote! { ::stef::encode_bytes(w, &*#name) }, + DataType::Bool => quote! { ::stef::buf::encode_bool(w, #name) }, + DataType::U8 => quote! { ::stef::buf::encode_u8(w, #name) }, + DataType::U16 => quote! { ::stef::buf::encode_u16(w, #name) }, + DataType::U32 => quote! { ::stef::buf::encode_u32(w, #name) }, + DataType::U64 => quote! { ::stef::buf::encode_u64(w, #name) }, + DataType::U128 => quote! { ::stef::buf::encode_u128(w, #name) }, + DataType::I8 => quote! { ::stef::buf::encode_i8(w, #name) }, + DataType::I16 => quote! { ::stef::buf::encode_i16(w, #name) }, + DataType::I32 => quote! { ::stef::buf::encode_i32(w, #name) }, + DataType::I64 => quote! { ::stef::buf::encode_i64(w, #name) }, + DataType::I128 => quote! { ::stef::buf::encode_i128(w, #name) }, + DataType::F32 => quote! { ::stef::buf::encode_f32(w, #name) }, + DataType::F64 => quote! { ::stef::buf::encode_f64(w, #name) }, + DataType::String | DataType::StringRef => quote! { ::stef::buf::encode_string(w, &#name) }, + DataType::Bytes | DataType::BytesRef => quote! { ::stef::buf::encode_bytes(w, &#name) }, + DataType::Vec(_ty) => quote! { ::stef::buf::encode_vec(w, &#name) }, + DataType::HashMap(_kv) => quote! { ::stef::buf::encode_hash_map(w, #name) }, + DataType::HashSet(_ty) => quote! { ::stef::buf::encode_hash_set(w, #name) }, + DataType::Option(_ty) => quote! { ::stef::buf::encode_option(w, #name) }, + DataType::BoxString => quote! { ::stef::buf::encode_string(w, &*#name) }, + DataType::BoxBytes => quote! { ::stef::buf::encode_bytes(w, &*#name) }, DataType::Tuple(types) => match types.len() { - size @ 1..=12 => { - let fn_name = Ident::new(&format!("write_tuple{size}"), Span::call_site()); - quote! { ::stef::#fn_name(w, &#name) } + size @ 2..=12 => { + let fn_name = Ident::new(&format!("encode_tuple{size}"), Span::call_site()); + quote! { ::stef::buf::#fn_name(w, &#name) } } 0 => panic!("tuple with zero elements"), + 1 => panic!("tuple with single element"), _ => panic!("tuple with more than 12 elements"), }, DataType::Array(_ty, _size) => { - quote! { ::stef::encode_array(w, &#name) } + quote! { ::stef::buf::encode_array(w, &#name) } } DataType::NonZero(_) | DataType::External(_) => { quote! { #name.encode(w) } diff --git a/crates/stef-build/src/lib.rs b/crates/stef-build/src/lib.rs index 6234067..7e9a34f 100644 --- a/crates/stef-build/src/lib.rs +++ b/crates/stef-build/src/lib.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use stef_parser::Schema; use thiserror::Error; +mod decode; mod definition; mod encode; diff --git a/crates/stef/src/buf/decode.rs b/crates/stef/src/buf/decode.rs new file mode 100644 index 0000000..d23505d --- /dev/null +++ b/crates/stef/src/buf/decode.rs @@ -0,0 +1,668 @@ +#![allow(clippy::type_complexity)] + +use std::{ + collections::{HashMap, HashSet}, + fmt::Debug, + hash::Hash, +}; + +pub use bytes::Buf; + +use crate::varint; + +pub type Result = std::result::Result; + +pub enum Error { + InsufficentData, + DecodeInt(varint::DecodeIntError), + NonUtf8(std::string::FromUtf8Error), + MissingField { id: u32, name: Option<&'static str> }, +} + +impl From for Error { + fn from(value: varint::DecodeIntError) -> Self { + Self::DecodeInt(value) + } +} + +impl From for Error { + fn from(value: std::string::FromUtf8Error) -> Self { + Self::NonUtf8(value) + } +} + +pub const END_MARKER: u32 = 0; + +macro_rules! ensure_size { + ($r:ident, $size:expr) => { + if $r.remaining() < $size { + return Err(Error::InsufficentData); + } + }; +} + +pub fn decode_bool(r: &mut impl Buf) -> Result { + ensure_size!(r, 1); + Ok(r.get_u8() != 0) +} + +pub fn decode_u8(r: &mut impl Buf) -> Result { + ensure_size!(r, 1); + Ok(r.get_u8()) +} + +pub fn decode_i8(r: &mut impl Buf) -> Result { + ensure_size!(r, 1); + Ok(r.get_i8()) +} + +macro_rules! decode_int { + ($ty:ty) => { + paste::paste! { + pub fn [](r: &mut impl Buf) -> Result<$ty> { + let (value, consumed) = varint::[](r.chunk())?; + r.advance(consumed); + Ok(value) + } + } + }; + ($($ty:ty),+ $(,)?) => { + $(decode_int!($ty);)+ + }; +} + +decode_int!(u16, u32, u64, u128); +decode_int!(i16, i32, i64, i128); + +pub fn decode_f32(r: &mut impl Buf) -> Result { + ensure_size!(r, 4); + Ok(r.get_f32()) +} + +pub fn decode_f64(r: &mut impl Buf) -> Result { + ensure_size!(r, 8); + Ok(r.get_f64()) +} + +pub fn decode_string(r: &mut impl Buf) -> Result { + String::from_utf8(decode_bytes(r)?).map_err(Into::into) +} + +pub fn decode_bytes(r: &mut impl Buf) -> Result> { + let (len, consumed) = varint::decode_u64(r.chunk())?; + r.advance(consumed); + + ensure_size!(r, len as usize); + Ok(r.copy_to_bytes(len as usize).to_vec()) +} + +pub fn decode_vec(r: &mut impl Buf) -> Result> { + let len = decode_u64(r)?; + (0..len).map(|_| T::decode(r)).collect() +} + +pub fn decode_hash_map( + r: &mut impl Buf, +) -> Result> { + let len = decode_u64(r)?; + (0..len) + .map(|_| Ok((K::decode(r)?, V::decode(r)?))) + .collect() +} + +pub fn decode_hash_set(r: &mut impl Buf) -> Result> { + let len = decode_u64(r)?; + (0..len).map(|_| T::decode(r)).collect() +} + +pub fn decode_array(r: &mut impl Buf) -> Result<[T; N]> { + let len = decode_u64(r)?; + if (len as usize) < N { + return Err(Error::InsufficentData); + } + + let buf = (0..N).map(|_| T::decode(r)).collect::>>()?; + + // read any remaining values, in case the old array definition was larger. + // still have to decode the values to advance the buffer accordingly. + for _ in N..len as usize { + T::decode(r)?; + } + + // SAFETY: we can unwrap here, because we ensured the Vec exactly matches + // with the length of the array. + Ok(buf.try_into().unwrap()) +} + +pub fn decode_tuple2(r: &mut impl Buf) -> Result<(T0, T1)> +where + T0: Decode, + T1: Decode, +{ + Ok((T0::decode(r)?, T1::decode(r)?)) +} + +pub fn decode_tuple3(r: &mut impl Buf) -> Result<(T0, T1, T2)> +where + T0: Decode, + T1: Decode, + T2: Decode, +{ + Ok((T0::decode(r)?, T1::decode(r)?, T2::decode(r)?)) +} + +pub fn decode_tuple4(r: &mut impl Buf) -> Result<(T0, T1, T2, T3)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + )) +} + +pub fn decode_tuple5(r: &mut impl Buf) -> Result<(T0, T1, T2, T3, T4)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + T4::decode(r)?, + )) +} + +pub fn decode_tuple6(r: &mut impl Buf) -> Result<(T0, T1, T2, T3, T4, T5)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + T4::decode(r)?, + T5::decode(r)?, + )) +} + +pub fn decode_tuple7( + r: &mut impl Buf, +) -> Result<(T0, T1, T2, T3, T4, T5, T6)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + T4::decode(r)?, + T5::decode(r)?, + T6::decode(r)?, + )) +} + +pub fn decode_tuple8( + r: &mut impl Buf, +) -> Result<(T0, T1, T2, T3, T4, T5, T6, T7)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + T4::decode(r)?, + T5::decode(r)?, + T6::decode(r)?, + T7::decode(r)?, + )) +} + +pub fn decode_tuple9( + r: &mut impl Buf, +) -> Result<(T0, T1, T2, T3, T4, T5, T6, T7, T8)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, + T8: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + T4::decode(r)?, + T5::decode(r)?, + T6::decode(r)?, + T7::decode(r)?, + T8::decode(r)?, + )) +} + +pub fn decode_tuple10( + r: &mut impl Buf, +) -> Result<(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, + T8: Decode, + T9: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + T4::decode(r)?, + T5::decode(r)?, + T6::decode(r)?, + T7::decode(r)?, + T8::decode(r)?, + T9::decode(r)?, + )) +} + +pub fn decode_tuple11( + r: &mut impl Buf, +) -> Result<(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, + T8: Decode, + T9: Decode, + T10: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + T4::decode(r)?, + T5::decode(r)?, + T6::decode(r)?, + T7::decode(r)?, + T8::decode(r)?, + T9::decode(r)?, + T10::decode(r)?, + )) +} + +pub fn decode_tuple12( + r: &mut impl Buf, +) -> Result<(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)> +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, + T8: Decode, + T9: Decode, + T10: Decode, + T11: Decode, +{ + Ok(( + T0::decode(r)?, + T1::decode(r)?, + T2::decode(r)?, + T3::decode(r)?, + T4::decode(r)?, + T5::decode(r)?, + T6::decode(r)?, + T7::decode(r)?, + T8::decode(r)?, + T9::decode(r)?, + T10::decode(r)?, + T11::decode(r)?, + )) +} + +#[inline(always)] +pub fn decode_id(r: &mut impl Buf) -> Result { + decode_u32(r) +} + +pub trait Decode: Sized { + fn decode(r: &mut impl Buf) -> Result; +} + +macro_rules! forward { + ($ty:ty) => { + paste::paste! { + impl Decode for $ty { + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + [](r) + } + } + } + }; + ($($ty:ty),+ $(,)?) => { + $(forward!($ty);)+ + }; +} + +forward!(bool); +forward!(u8, u16, u32, u64, u128); +forward!(i8, i16, i32, i64, i128); +forward!(f32, f64); + +impl Decode for Box { + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_string(r).map(String::into_boxed_str) + } +} + +impl Decode for Box<[u8]> { + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_bytes(r).map(Vec::into_boxed_slice) + } +} + +impl Decode for Vec +where + T: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_vec(r) + } +} + +impl Decode for HashMap +where + K: Hash + Eq + Decode, + V: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_hash_map(r) + } +} + +impl Decode for HashSet +where + T: Hash + Eq + Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_hash_set(r) + } +} + +impl Decode for [T; N] +where + T: Debug + Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_array(r) + } +} + +impl Decode for (T0, T1) +where + T0: Decode, + T1: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple2(r) + } +} + +impl Decode for (T0, T1, T2) +where + T0: Decode, + T1: Decode, + T2: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple3(r) + } +} + +impl Decode for (T0, T1, T2, T3) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple4(r) + } +} + +impl Decode for (T0, T1, T2, T3, T4) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple5(r) + } +} + +impl Decode for (T0, T1, T2, T3, T4, T5) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple6(r) + } +} + +impl Decode for (T0, T1, T2, T3, T4, T5, T6) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple7(r) + } +} + +impl Decode for (T0, T1, T2, T3, T4, T5, T6, T7) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple8(r) + } +} + +impl Decode for (T0, T1, T2, T3, T4, T5, T6, T7, T8) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, + T8: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple9(r) + } +} + +impl Decode for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, + T8: Decode, + T9: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple10(r) + } +} + +impl Decode + for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, + T8: Decode, + T9: Decode, + T10: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple11(r) + } +} + +impl Decode + for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) +where + T0: Decode, + T1: Decode, + T2: Decode, + T3: Decode, + T4: Decode, + T5: Decode, + T6: Decode, + T7: Decode, + T8: Decode, + T9: Decode, + T10: Decode, + T11: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + decode_tuple12(r) + } +} + +// ----------------------------- +// TODO: NonZero +// ----------------------------- + +impl<'a, T> Decode for std::borrow::Cow<'a, T> +where + T: Copy + Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + T::decode(r).map(std::borrow::Cow::Owned) + } +} + +impl Decode for std::rc::Rc +where + T: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + T::decode(r).map(std::rc::Rc::new) + } +} + +impl Decode for std::sync::Arc +where + T: Decode, +{ + #[inline(always)] + fn decode(r: &mut impl Buf) -> Result { + T::decode(r).map(std::sync::Arc::new) + } +} diff --git a/crates/stef/src/buf/encode.rs b/crates/stef/src/buf/encode.rs new file mode 100644 index 0000000..93130d7 --- /dev/null +++ b/crates/stef/src/buf/encode.rs @@ -0,0 +1,701 @@ +use std::{ + collections::{HashMap, HashSet}, + num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU128, NonZeroU16, + NonZeroU32, NonZeroU64, NonZeroU8, + }, +}; + +pub use bytes::BufMut; + +use crate::varint; + +pub fn encode_bool(w: &mut impl BufMut, value: bool) { + w.put_u8(value.into()); +} + +pub fn encode_u8(w: &mut impl BufMut, value: u8) { + w.put_u8(value); +} + +pub fn encode_i8(w: &mut impl BufMut, value: i8) { + w.put_i8(value); +} + +macro_rules! encode_int { + ($ty:ty) => { + paste::paste! { + pub fn [](w: &mut impl BufMut, value: $ty) { + let (buf, len) = varint::[](value); + w.put(&buf[..len]); + } + } + }; + ($($ty:ty),+ $(,)?) => { + $(encode_int!($ty);)+ + }; +} + +encode_int!(u16, u32, u64, u128); +encode_int!(i16, i32, i64, i128); + +pub fn encode_f32(w: &mut impl BufMut, value: f32) { + w.put_f32(value); +} + +pub fn encode_f64(w: &mut impl BufMut, value: f64) { + w.put_f64(value); +} + +pub fn encode_string(w: &mut impl BufMut, value: &str) { + encode_bytes(w, value.as_bytes()); +} + +pub fn encode_bytes(w: &mut impl BufMut, value: &[u8]) { + encode_u64(w, value.len() as u64); + w.put(value) +} + +pub fn encode_vec(w: &mut impl BufMut, vec: &[T]) { + encode_u64(w, vec.len() as u64); + + for value in vec { + value.encode(w); + } +} + +pub fn encode_hash_map(w: &mut impl BufMut, map: &HashMap) { + encode_u64(w, map.len() as u64); + + for (key, value) in map { + key.encode(w); + value.encode(w); + } +} + +pub fn encode_hash_set(w: &mut impl BufMut, set: &HashSet) { + encode_u64(w, set.len() as u64); + + for value in set { + value.encode(w); + } +} + +pub fn encode_option(w: &mut impl BufMut, option: &Option) { + if let Some(value) = option { + value.encode(w); + } +} + +pub fn encode_array(w: &mut impl BufMut, array: &[T; N]) { + encode_u64(w, array.len() as u64); + + for value in array { + value.encode(w); + } +} + +pub fn encode_tuple2(w: &mut impl BufMut, tuple: &(T0, T1)) +where + T0: Encode, + T1: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); +} + +pub fn encode_tuple3(w: &mut impl BufMut, tuple: &(T0, T1, T2)) +where + T0: Encode, + T1: Encode, + T2: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); +} + +pub fn encode_tuple4(w: &mut impl BufMut, tuple: &(T0, T1, T2, T3)) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); +} + +pub fn encode_tuple5(w: &mut impl BufMut, tuple: &(T0, T1, T2, T3, T4)) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); + tuple.4.encode(w); +} + +pub fn encode_tuple6(w: &mut impl BufMut, tuple: &(T0, T1, T2, T3, T4, T5)) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); + tuple.4.encode(w); + tuple.5.encode(w); +} + +pub fn encode_tuple7( + w: &mut impl BufMut, + tuple: &(T0, T1, T2, T3, T4, T5, T6), +) where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); + tuple.4.encode(w); + tuple.5.encode(w); + tuple.6.encode(w); +} + +pub fn encode_tuple8( + w: &mut impl BufMut, + tuple: &(T0, T1, T2, T3, T4, T5, T6, T7), +) where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); + tuple.4.encode(w); + tuple.5.encode(w); + tuple.6.encode(w); + tuple.7.encode(w); +} + +pub fn encode_tuple9( + w: &mut impl BufMut, + tuple: &(T0, T1, T2, T3, T4, T5, T6, T7, T8), +) where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, + T8: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); + tuple.4.encode(w); + tuple.5.encode(w); + tuple.6.encode(w); + tuple.7.encode(w); + tuple.8.encode(w); +} + +pub fn encode_tuple10( + w: &mut impl BufMut, + tuple: &(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), +) where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, + T8: Encode, + T9: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); + tuple.4.encode(w); + tuple.5.encode(w); + tuple.6.encode(w); + tuple.7.encode(w); + tuple.8.encode(w); + tuple.9.encode(w); +} + +pub fn encode_tuple11( + w: &mut impl BufMut, + tuple: &(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), +) where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, + T8: Encode, + T9: Encode, + T10: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); + tuple.4.encode(w); + tuple.5.encode(w); + tuple.6.encode(w); + tuple.7.encode(w); + tuple.8.encode(w); + tuple.9.encode(w); + tuple.10.encode(w); +} + +#[allow(clippy::type_complexity)] +pub fn encode_tuple12( + w: &mut impl BufMut, + tuple: &(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), +) where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, + T8: Encode, + T9: Encode, + T10: Encode, + T11: Encode, +{ + tuple.0.encode(w); + tuple.1.encode(w); + tuple.2.encode(w); + tuple.3.encode(w); + tuple.4.encode(w); + tuple.5.encode(w); + tuple.6.encode(w); + tuple.7.encode(w); + tuple.8.encode(w); + tuple.9.encode(w); + tuple.10.encode(w); + tuple.11.encode(w); +} + +#[inline(always)] +pub fn encode_id(w: &mut impl BufMut, id: u32) { + encode_u32(w, id) +} + +#[inline(always)] +pub fn encode_field(w: &mut W, id: u32, encode: E) +where + W: BufMut, + E: Fn(&mut W), +{ + encode_id(w, id); + encode(w); +} + +pub trait Encode { + fn encode(&self, w: &mut impl BufMut); +} + +macro_rules! forward { + ($ty:ty) => { + paste::paste! { + impl Encode for $ty { + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + [](w, *self) + } + } + } + }; + ($($ty:ty),+ $(,)?) => { + $(forward!($ty);)+ + }; +} + +forward!(bool); +forward!(u8, u16, u32, u64, u128); +forward!(i8, i16, i32, i64, i128); +forward!(f32, f64); + +impl Encode for Box { + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_string(w, self) + } +} + +impl Encode for Box<[u8]> { + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_bytes(w, self) + } +} + +impl Encode for Vec +where + T: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_vec(w, self) + } +} + +impl<'a, T> Encode for &'a [T] +where + T: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_vec(w, self) + } +} + +impl Encode for HashMap +where + K: Encode, + V: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_hash_map(w, self) + } +} + +impl Encode for HashSet +where + T: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_hash_set(w, self) + } +} + +impl Encode for Option +where + T: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_option(w, self) + } +} + +impl Encode for [T; N] +where + T: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_array(w, self) + } +} + +impl Encode for (T0, T1) +where + T0: Encode, + T1: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple2(w, self) + } +} + +impl Encode for (T0, T1, T2) +where + T0: Encode, + T1: Encode, + T2: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple3(w, self) + } +} + +impl Encode for (T0, T1, T2, T3) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple4(w, self) + } +} + +impl Encode for (T0, T1, T2, T3, T4) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple5(w, self) + } +} + +impl Encode for (T0, T1, T2, T3, T4, T5) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple6(w, self) + } +} + +impl Encode for (T0, T1, T2, T3, T4, T5, T6) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple7(w, self) + } +} + +impl Encode for (T0, T1, T2, T3, T4, T5, T6, T7) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple8(w, self) + } +} + +impl Encode for (T0, T1, T2, T3, T4, T5, T6, T7, T8) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, + T8: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple9(w, self) + } +} + +impl Encode for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, + T8: Encode, + T9: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple10(w, self) + } +} + +impl Encode + for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, + T8: Encode, + T9: Encode, + T10: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple11(w, self) + } +} + +impl Encode + for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) +where + T0: Encode, + T1: Encode, + T2: Encode, + T3: Encode, + T4: Encode, + T5: Encode, + T6: Encode, + T7: Encode, + T8: Encode, + T9: Encode, + T10: Encode, + T11: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + encode_tuple12(w, self) + } +} + +impl Encode for NonZeroU8 { + fn encode(&self, w: &mut impl BufMut) { + encode_u8(w, self.get()); + } +} + +impl Encode for NonZeroU16 { + fn encode(&self, w: &mut impl BufMut) { + encode_u16(w, self.get()); + } +} + +impl Encode for NonZeroU32 { + fn encode(&self, w: &mut impl BufMut) { + encode_u32(w, self.get()); + } +} + +impl Encode for NonZeroU64 { + fn encode(&self, w: &mut impl BufMut) { + encode_u64(w, self.get()); + } +} + +impl Encode for NonZeroU128 { + fn encode(&self, w: &mut impl BufMut) { + encode_u128(w, self.get()); + } +} + +impl Encode for NonZeroI8 { + fn encode(&self, w: &mut impl BufMut) { + encode_i8(w, self.get()); + } +} + +impl Encode for NonZeroI16 { + fn encode(&self, w: &mut impl BufMut) { + encode_i16(w, self.get()); + } +} + +impl Encode for NonZeroI32 { + fn encode(&self, w: &mut impl BufMut) { + encode_i32(w, self.get()); + } +} + +impl Encode for NonZeroI64 { + fn encode(&self, w: &mut impl BufMut) { + encode_i64(w, self.get()); + } +} + +impl Encode for NonZeroI128 { + fn encode(&self, w: &mut impl BufMut) { + encode_i128(w, self.get()); + } +} + +impl<'a, T> Encode for std::borrow::Cow<'a, T> +where + T: Clone + Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + T::encode(self, w) + } +} + +impl Encode for std::rc::Rc +where + T: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + T::encode(self, w) + } +} + +impl Encode for std::sync::Arc +where + T: Encode, +{ + #[inline(always)] + fn encode(&self, w: &mut impl BufMut) { + T::encode(self, w) + } +} diff --git a/crates/stef/src/buf/mod.rs b/crates/stef/src/buf/mod.rs new file mode 100644 index 0000000..97b3c8f --- /dev/null +++ b/crates/stef/src/buf/mod.rs @@ -0,0 +1,7 @@ +//! Format en- and decoding on in-memory data buffers. + +pub use decode::*; +pub use encode::*; + +mod decode; +mod encode; diff --git a/crates/stef/src/lib.rs b/crates/stef/src/lib.rs index 23c1483..420c38d 100644 --- a/crates/stef/src/lib.rs +++ b/crates/stef/src/lib.rs @@ -1,732 +1,4 @@ -use std::{ - collections::{HashMap, HashSet}, - num::{ - NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU128, NonZeroU16, - NonZeroU32, NonZeroU64, NonZeroU8, - }, -}; - -pub use bytes::BufMut; +pub use buf::{Buf, BufMut, Encode}; +pub mod buf; pub mod varint; - -pub fn encode_bool(w: &mut impl BufMut, value: bool) { - w.put_u8(value.into()); -} - -pub fn encode_u8(w: &mut impl BufMut, value: u8) { - w.put_u8(value); -} - -pub fn encode_i8(w: &mut impl BufMut, value: i8) { - w.put_i8(value); -} - -macro_rules! encode_int { - ($ty:ty) => { - paste::paste! { - pub fn [](w: &mut impl BufMut, value: $ty) { - let (buf, len) = varint::[](value); - w.put(&buf[..len]); - } - } - }; - ($($ty:ty),+ $(,)?) => { - $(encode_int!($ty);)+ - } -} - -encode_int!(u16, u32, u64, u128); -encode_int!(i16, i32, i64, i128); - -pub fn encode_f32(w: &mut impl BufMut, value: f32) { - w.put_f32(value); -} - -pub fn encode_f64(w: &mut impl BufMut, value: f64) { - w.put_f64(value); -} - -pub fn write_id(w: &mut impl BufMut, id: u32) { - let (buf, len) = varint::encode_u32(id); - w.put(&buf[..len]); -} - -pub fn write_discr(w: &mut impl BufMut, discr: u32) { - let (buf, len) = varint::encode_u32(discr); - - w.put(&buf[..len]); -} - -pub fn encode_string(w: &mut impl BufMut, value: &str) { - encode_bytes(w, value.as_bytes()); -} - -pub fn encode_bytes(w: &mut impl BufMut, value: &[u8]) { - let (buf, len) = varint::encode_u64(value.len() as u64); - - w.put(&buf[..len]); - w.put(value) -} - -pub trait Encode { - fn encode(&self, w: &mut impl BufMut); -} - -macro_rules! forward { - ($ty:ty) => { - paste::paste! { - impl Encode for $ty { - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - [](w, *self) - } - } - } - }; - ($($ty:ty),+ $(,)?) => { - $(forward!($ty);)+ - }; -} - -forward!(bool); -forward!(u8, u16, u32, u64, u128); -forward!(i8, i16, i32, i64, i128); -forward!(f32, f64); - -impl<'a> Encode for &'a str { - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_string(w, self) - } -} - -impl Encode for Box { - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_string(w, self) - } -} - -impl<'a> Encode for &'a [u8] { - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_bytes(w, self) - } -} - -impl Encode for Box<[u8]> { - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_bytes(w, self) - } -} - -pub fn encode_vec(w: &mut impl BufMut, vec: &Vec) { - encode_u64(w, vec.len() as u64); - - for value in vec { - value.encode(w); - } -} - -impl Encode for Vec -where - T: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_vec(w, self) - } -} - -pub fn encode_hash_map(w: &mut impl BufMut, map: &HashMap) { - encode_u64(w, map.len() as u64); - - for (key, value) in map { - key.encode(w); - value.encode(w); - } -} - -impl Encode for HashMap -where - K: Encode, - V: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_hash_map(w, self) - } -} - -pub fn encode_hash_set(w: &mut impl BufMut, set: &HashSet) { - encode_u64(w, set.len() as u64); - - for value in set { - value.encode(w); - } -} - -impl Encode for HashSet -where - T: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_hash_set(w, self) - } -} - -pub fn encode_option(w: &mut impl BufMut, option: &Option) { - if let Some(value) = option { - value.encode(w); - } -} - -impl Encode for Option -where - T: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_option(w, self) - } -} - -// TODO: NonZero - -pub fn encode_array(w: &mut impl BufMut, array: &[T; N]) { - encode_u64(w, array.len() as u64); - - for value in array { - value.encode(w); - } -} - -impl Encode for [T; N] -where - T: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - encode_array(w, self) - } -} - -pub fn write_tuple1(w: &mut impl BufMut, tuple: &(T0,)) -where - T0: Encode, -{ - tuple.0.encode(w); -} - -impl Encode for (T0,) -where - T0: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple1(w, self) - } -} - -pub fn write_tuple2(w: &mut impl BufMut, tuple: &(T0, T1)) -where - T0: Encode, - T1: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); -} - -impl Encode for (T0, T1) -where - T0: Encode, - T1: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple2(w, self) - } -} - -pub fn write_tuple3(w: &mut impl BufMut, tuple: &(T0, T1, T2)) -where - T0: Encode, - T1: Encode, - T2: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); -} - -impl Encode for (T0, T1, T2) -where - T0: Encode, - T1: Encode, - T2: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple3(w, self) - } -} - -pub fn write_tuple4(w: &mut impl BufMut, tuple: &(T0, T1, T2, T3)) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); -} - -impl Encode for (T0, T1, T2, T3) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple4(w, self) - } -} - -pub fn write_tuple5(w: &mut impl BufMut, tuple: &(T0, T1, T2, T3, T4)) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); - tuple.4.encode(w); -} - -impl Encode for (T0, T1, T2, T3, T4) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple5(w, self) - } -} - -pub fn write_tuple6(w: &mut impl BufMut, tuple: &(T0, T1, T2, T3, T4, T5)) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); - tuple.4.encode(w); - tuple.5.encode(w); -} - -impl Encode for (T0, T1, T2, T3, T4, T5) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple6(w, self) - } -} - -pub fn write_tuple7( - w: &mut impl BufMut, - tuple: &(T0, T1, T2, T3, T4, T5, T6), -) where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); - tuple.4.encode(w); - tuple.5.encode(w); - tuple.6.encode(w); -} - -impl Encode for (T0, T1, T2, T3, T4, T5, T6) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple7(w, self) - } -} - -pub fn write_tuple8( - w: &mut impl BufMut, - tuple: &(T0, T1, T2, T3, T4, T5, T6, T7), -) where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); - tuple.4.encode(w); - tuple.5.encode(w); - tuple.6.encode(w); - tuple.7.encode(w); -} - -impl Encode for (T0, T1, T2, T3, T4, T5, T6, T7) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple8(w, self) - } -} - -pub fn write_tuple9( - w: &mut impl BufMut, - tuple: &(T0, T1, T2, T3, T4, T5, T6, T7, T8), -) where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, - T8: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); - tuple.4.encode(w); - tuple.5.encode(w); - tuple.6.encode(w); - tuple.7.encode(w); - tuple.8.encode(w); -} - -impl Encode for (T0, T1, T2, T3, T4, T5, T6, T7, T8) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, - T8: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple9(w, self) - } -} - -pub fn write_tuple10( - w: &mut impl BufMut, - tuple: &(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9), -) where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, - T8: Encode, - T9: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); - tuple.4.encode(w); - tuple.5.encode(w); - tuple.6.encode(w); - tuple.7.encode(w); - tuple.8.encode(w); - tuple.9.encode(w); -} - -impl Encode for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, - T8: Encode, - T9: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple10(w, self) - } -} - -pub fn write_tuple11( - w: &mut impl BufMut, - tuple: &(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), -) where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, - T8: Encode, - T9: Encode, - T10: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); - tuple.4.encode(w); - tuple.5.encode(w); - tuple.6.encode(w); - tuple.7.encode(w); - tuple.8.encode(w); - tuple.9.encode(w); - tuple.10.encode(w); -} - -impl Encode - for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, - T8: Encode, - T9: Encode, - T10: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple11(w, self) - } -} - -#[allow(clippy::type_complexity)] -pub fn write_tuple12( - w: &mut impl BufMut, - tuple: &(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11), -) where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, - T8: Encode, - T9: Encode, - T10: Encode, - T11: Encode, -{ - tuple.0.encode(w); - tuple.1.encode(w); - tuple.2.encode(w); - tuple.3.encode(w); - tuple.4.encode(w); - tuple.5.encode(w); - tuple.6.encode(w); - tuple.7.encode(w); - tuple.8.encode(w); - tuple.9.encode(w); - tuple.10.encode(w); - tuple.11.encode(w); -} - -impl Encode - for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) -where - T0: Encode, - T1: Encode, - T2: Encode, - T3: Encode, - T4: Encode, - T5: Encode, - T6: Encode, - T7: Encode, - T8: Encode, - T9: Encode, - T10: Encode, - T11: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - write_tuple12(w, self) - } -} - -impl Encode for NonZeroU8 { - fn encode(&self, w: &mut impl BufMut) { - encode_u8(w, self.get()); - } -} - -impl Encode for NonZeroU16 { - fn encode(&self, w: &mut impl BufMut) { - encode_u16(w, self.get()); - } -} - -impl Encode for NonZeroU32 { - fn encode(&self, w: &mut impl BufMut) { - encode_u32(w, self.get()); - } -} - -impl Encode for NonZeroU64 { - fn encode(&self, w: &mut impl BufMut) { - encode_u64(w, self.get()); - } -} - -impl Encode for NonZeroU128 { - fn encode(&self, w: &mut impl BufMut) { - encode_u128(w, self.get()); - } -} - -impl Encode for NonZeroI8 { - fn encode(&self, w: &mut impl BufMut) { - encode_i8(w, self.get()); - } -} - -impl Encode for NonZeroI16 { - fn encode(&self, w: &mut impl BufMut) { - encode_i16(w, self.get()); - } -} - -impl Encode for NonZeroI32 { - fn encode(&self, w: &mut impl BufMut) { - encode_i32(w, self.get()); - } -} - -impl Encode for NonZeroI64 { - fn encode(&self, w: &mut impl BufMut) { - encode_i64(w, self.get()); - } -} - -impl Encode for NonZeroI128 { - fn encode(&self, w: &mut impl BufMut) { - encode_i128(w, self.get()); - } -} - -impl<'a, T> Encode for std::borrow::Cow<'a, T> -where - T: Clone + Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - T::encode(self, w) - } -} - -impl Encode for std::rc::Rc -where - T: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - T::encode(self, w) - } -} - -impl Encode for std::sync::Arc -where - T: Encode, -{ - #[inline(always)] - fn encode(&self, w: &mut impl BufMut) { - T::encode(self, w) - } -} - -#[inline(always)] -pub fn write_field(w: &mut W, id: u32, encode: E) -where - W: BufMut, - E: Fn(&mut W), -{ - write_id(w, id); - encode(w); -} diff --git a/crates/stef/src/varint.rs b/crates/stef/src/varint.rs index b4c6799..55ffeb7 100644 --- a/crates/stef/src/varint.rs +++ b/crates/stef/src/varint.rs @@ -1,3 +1,5 @@ +//! Encoding and decoding for variable integers. + use thiserror::Error; macro_rules! zigzag { @@ -56,13 +58,13 @@ macro_rules! varint { } #[inline] - pub fn [](buf: &[u8]) -> Result<($ty, &[u8]), DecodeIntError> { + pub fn [](buf: &[u8]) -> Result<($ty, usize), DecodeIntError> { let mut value = 0; for (i, b) in buf.iter().copied().enumerate().take(max_size::<$ty>()) { value |= ((b & 0x7f) as $ty) << (7 * i); if b & 0x80 == 0 { - return Ok((value, &buf[i + 1..])); + return Ok((value, i + 1)); } } @@ -75,7 +77,7 @@ macro_rules! varint { } #[inline] - pub fn [](buf: &[u8]) -> Result<($signed, &[u8]), DecodeIntError> { + pub fn [](buf: &[u8]) -> Result<($signed, usize), DecodeIntError> { [](buf).map(|(v, b)| ([](v), b)) } }