From d25bf85169aa9f2e0c22276ed4084f76b7c4161b Mon Sep 17 00:00:00 2001 From: Handy-caT <37216852+Handy-caT@users.noreply.github.com> Date: Mon, 11 Aug 2025 11:34:48 +0300 Subject: [PATCH 1/2] WIP --- Cargo.toml | 4 +-- codegen/src/size_measure/generator/enum_.rs | 23 ++++++++++++++ codegen/src/size_measure/generator/mod.rs | 5 ++++ .../{generator.rs => generator/structure.rs} | 2 +- codegen/src/size_measure/mod.rs | 30 +++++++++++++------ codegen/src/size_measure/parser.rs | 9 +++++- src/util/sized.rs | 29 ++++++++++-------- 7 files changed, 77 insertions(+), 25 deletions(-) create mode 100644 codegen/src/size_measure/generator/enum_.rs create mode 100644 codegen/src/size_measure/generator/mod.rs rename codegen/src/size_measure/{generator.rs => generator/structure.rs} (95%) diff --git a/Cargo.toml b/Cargo.toml index 0db2b7e..ad0d6b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,6 @@ lockfree = "0.5.1" uuid = { version = "1.11.0", features = ["v4"] } ordered-float = "5.0.0" # indexset = { version = "0.12.3", features = ["concurrent", "cdc", "multimap"] } -# indexset = { package = "wt-indexset", path = "../indexset", version = "0.12.5", features = ["concurrent", "cdc", "multimap"] } -indexset = { package = "wt-indexset", version = "0.12.6", features = ["concurrent", "cdc", "multimap"] } +indexset = { package = "wt-indexset", path = "../indexset", version = "0.12.6", features = ["concurrent", "cdc", "multimap"] } +# indexset = { package = "wt-indexset", version = "0.12.6", features = ["concurrent", "cdc", "multimap"] } tokio = { version = "1", features = ["full"] } diff --git a/codegen/src/size_measure/generator/enum_.rs b/codegen/src/size_measure/generator/enum_.rs new file mode 100644 index 0000000..3b091bf --- /dev/null +++ b/codegen/src/size_measure/generator/enum_.rs @@ -0,0 +1,23 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::ItemEnum; + +pub struct Generator { + pub enum_def: ItemEnum, +} +impl Generator { + pub fn gen_impl(&self) -> TokenStream { + let enum_ident = &self.enum_def.ident; + + quote! { + impl SizeMeasurable for #enum_ident { + fn aligned_size(&self) -> usize { + std::mem::size_of::<#enum_ident>() + } + fn align() -> Option { + None + } + } + } + } +} diff --git a/codegen/src/size_measure/generator/mod.rs b/codegen/src/size_measure/generator/mod.rs new file mode 100644 index 0000000..502442b --- /dev/null +++ b/codegen/src/size_measure/generator/mod.rs @@ -0,0 +1,5 @@ +mod enum_; +mod structure; + +pub use enum_::Generator as EnumGenerator; +pub use structure::Generator as StructGenerator; diff --git a/codegen/src/size_measure/generator.rs b/codegen/src/size_measure/generator/structure.rs similarity index 95% rename from codegen/src/size_measure/generator.rs rename to codegen/src/size_measure/generator/structure.rs index 0544975..7da607f 100644 --- a/codegen/src/size_measure/generator.rs +++ b/codegen/src/size_measure/generator/structure.rs @@ -37,7 +37,7 @@ impl Generator { .map(|f| { let t = &f.ty; quote! { - if #t::align() == Some(8) { + if <#t as SizeMeasurable>::align() == Some(8) { return Some(8) } } diff --git a/codegen/src/size_measure/mod.rs b/codegen/src/size_measure/mod.rs index f541a2e..7b56391 100644 --- a/codegen/src/size_measure/mod.rs +++ b/codegen/src/size_measure/mod.rs @@ -4,18 +4,30 @@ mod parser; use proc_macro2::TokenStream; use quote::quote; -use crate::size_measure::generator::Generator; +use crate::size_measure::generator::{EnumGenerator, StructGenerator}; use crate::size_measure::parser::Parser; pub fn expand(input: &TokenStream) -> syn::Result { - let input_fn = Parser::parse_struct(input)?; - let gen = Generator { - struct_def: input_fn, - }; + if let Ok(input_fn) = Parser::parse_struct(input) { + let gen = StructGenerator { + struct_def: input_fn, + }; + let impl_def = gen.gen_impl(); - let impl_def = gen.gen_impl(); + return Ok(quote! { + #impl_def + }); + } + if let Ok(input_fn) = Parser::parse_enum(input) { + let gen = EnumGenerator { enum_def: input_fn }; + let impl_def = gen.gen_impl(); - Ok(quote! { - #impl_def - }) + Ok(quote! { + #impl_def + }) + } else { + Err(Parser::parse_enum(input) + .err() + .expect("should be error as checked before")) + } } diff --git a/codegen/src/size_measure/parser.rs b/codegen/src/size_measure/parser.rs index 8649504..a53a157 100644 --- a/codegen/src/size_measure/parser.rs +++ b/codegen/src/size_measure/parser.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use syn::spanned::Spanned; -use syn::ItemStruct; +use syn::{ItemEnum, ItemStruct}; pub struct Parser; @@ -11,4 +11,11 @@ impl Parser { Err(err) => Err(syn::Error::new(input.span(), err.to_string())), } } + + pub fn parse_enum(input: &TokenStream) -> syn::Result { + match syn::parse2::(input.clone()) { + Ok(data) => Ok(data), + Err(err) => Err(syn::Error::new(input.span(), err.to_string())), + } + } } diff --git a/src/util/sized.rs b/src/util/sized.rs index 1f7ea51..cb6419d 100644 --- a/src/util/sized.rs +++ b/src/util/sized.rs @@ -58,6 +58,23 @@ macro_rules! size_measurable_for_sized { size_measurable_for_sized! {u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool} +macro_rules! size_measurable_for_arrays { + ($($t:ident),+) => { + $( + impl SizeMeasurable for [$t; N] { + fn aligned_size(&self) -> usize { + mem::size_of::<[$t; N]>() + } + fn align() -> Option { + Some(align(mem::size_of::<[$t; N]>())) + } + } + )+ + }; +} + +size_measurable_for_arrays! {u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool} + impl SizeMeasurable for Link { fn aligned_size(&self) -> usize { LINK_LENGTH @@ -79,18 +96,6 @@ where } } -impl SizeMeasurable for [u8; 32] { - fn aligned_size(&self) -> usize { - mem::size_of::<[u8; 32]>() - } -} - -impl SizeMeasurable for [u8; 20] { - fn aligned_size(&self) -> usize { - mem::size_of::<[u8; 20]>() - } -} - impl SizeMeasurable for (T1, T2) where T1: SizeMeasurable, From e9791309036ab70c9f0f2da2ce531bc46b4d91c2 Mon Sep 17 00:00:00 2001 From: Handy-caT <37216852+Handy-caT@users.noreply.github.com> Date: Wed, 13 Aug 2025 14:27:49 +0300 Subject: [PATCH 2/2] add `DefaultSizeMeasurable` --- codegen/src/persistable/generator/obj_impl.rs | 12 +++---- .../persistable/generator/persistable_impl.rs | 6 ++-- src/lib.rs | 5 ++- src/link.rs | 16 ++++++++++ src/page/index/page.rs | 15 ++++----- src/page/index/page_cdc_impl.rs | 4 +-- src/page/index/page_for_unsized.rs | 14 +++++---- src/page/index/table_of_contents_page.rs | 4 +-- src/util/mod.rs | 4 ++- src/util/sized.rs | 31 ++++++++++++++----- 10 files changed, 75 insertions(+), 36 deletions(-) diff --git a/codegen/src/persistable/generator/obj_impl.rs b/codegen/src/persistable/generator/obj_impl.rs index a82891e..c46d4b6 100644 --- a/codegen/src/persistable/generator/obj_impl.rs +++ b/codegen/src/persistable/generator/obj_impl.rs @@ -20,7 +20,7 @@ impl Generator { if let GenericParam::Type(param) = generic { let ident = ¶m.ident; quote! { - #ident: Default + SizeMeasurable, + #ident: DefaultSizeMeasurable, } } else { quote! {} @@ -172,7 +172,7 @@ impl Generator { ); quote! { pub fn #fn_ident() -> usize { - <#ty as Default>::default().aligned_size() + <#ty as DefaultSizeMeasurable>::default_aligned_size() } } } @@ -218,7 +218,7 @@ impl Generator { ); let len_in_vec = if is_primitive(&inner_ty_str) { quote! { - align(length * <#inner_ty as Default>::default().aligned_size()) + 8 + align(length * <#inner_ty as DefaultSizeMeasurable>::default_aligned_size()) + 8 } } else { quote! { @@ -227,14 +227,14 @@ impl Generator { }; let len_value = if is_primitive(&inner_ty_str) { quote! { - <#inner_ty as Default>::default().aligned_size() + <#inner_ty as DefaultSizeMeasurable>::default_aligned_size() } } else { quote! { if <#inner_ty as SizeMeasurable>::align() == Some(8) { - align8(<#inner_ty as Default>::default().aligned_size()) + align8(<#inner_ty as DefaultSizeMeasurable>::default_aligned_size()) } else { - <#inner_ty as Default>::default().aligned_size() + <#inner_ty as DefaultSizeMeasurable>::default_aligned_size() } } }; diff --git a/codegen/src/persistable/generator/persistable_impl.rs b/codegen/src/persistable/generator/persistable_impl.rs index 873fc28..9ebb25e 100644 --- a/codegen/src/persistable/generator/persistable_impl.rs +++ b/codegen/src/persistable/generator/persistable_impl.rs @@ -212,7 +212,7 @@ impl Generator { let size_type = &f.ty; let size_ident = f.ident.as_ref().unwrap(); quote! { - let size_length = <#size_type as Default>::default().aligned_size(); + let size_length = <#size_type as DefaultSizeMeasurable>::default_aligned_size(); let archived = unsafe { rkyv::access_unchecked::<<#size_type as Archive>::Archived>(&bytes[offset..offset + size_length]) }; let #size_ident = @@ -237,7 +237,7 @@ impl Generator { fn gen_from_bytes_for_primitive(&self, ty: &Type, ident: &Ident) -> TokenStream { quote! { - let length = <#ty as Default>::default().aligned_size(); + let length = <#ty as DefaultSizeMeasurable>::default_aligned_size(); let mut v = rkyv::util::AlignedVec::<4>::new(); v.extend_from_slice(&bytes[offset..offset + length]); let archived = unsafe { rkyv::access_unchecked::<<#ty as Archive>::Archived>(&v[..]) }; @@ -271,7 +271,7 @@ impl Generator { let value_fn_ident = Ident::new(format!("{ident}_value_size").as_str(), Span::call_site()); let len = if is_primitive(&inner_ty_str) { quote! { - let values_len = align(#size_ident as usize * <#inner_ty as Default>::default().aligned_size()) + 8; + let values_len = align(#size_ident as usize * <#inner_ty as DefaultSizeMeasurable>::default_aligned_size()) + 8; } } else { quote! { diff --git a/src/lib.rs b/src/lib.rs index ca8fd96..76c11c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,4 +19,7 @@ pub use page::{ }; pub use persistence::{PersistableIndex, PersistableTable}; pub use space::Id as SpaceId; -pub use util::{align, align8, align_vec, Persistable, SizeMeasurable, VariableSizeMeasurable}; +pub use util::{ + align, align8, align_vec, DefaultSizeMeasurable, Persistable, SizeMeasurable, + VariableSizeMeasurable, +}; diff --git a/src/link.rs b/src/link.rs index 18ceec8..ee12ba8 100644 --- a/src/link.rs +++ b/src/link.rs @@ -25,6 +25,22 @@ pub struct Link { pub length: u32, } +impl Link { + /// Unites two [`Link`]'s into one if they have same border. If [`Link`]'s + /// could not be united, `None` returned. + pub fn unite(self, other: Link) -> Option { + if self.offset + self.length != other.offset || self.page_id != other.page_id { + None + } else { + Some(Link { + page_id: self.page_id, + offset: self.offset, + length: self.length + other.length, + }) + } + } +} + #[cfg(test)] mod tests { use crate::link::Link; diff --git a/src/page/index/page.rs b/src/page/index/page.rs index ece7286..3d9323c 100644 --- a/src/page/index/page.rs +++ b/src/page/index/page.rs @@ -20,12 +20,13 @@ use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; use crate::page::index::IndexPageUtility; use crate::page::{IndexValue, PageId}; use crate::{ - align, align8, seek_to_page_start, Link, Persistable, SizeMeasurable, GENERAL_HEADER_SIZE, + align, align8, seek_to_page_start, DefaultSizeMeasurable, Link, Persistable, SizeMeasurable, + GENERAL_HEADER_SIZE, }; pub fn get_index_page_size_from_data_length(length: usize) -> usize where - T: Default + SizeMeasurable, + T: DefaultSizeMeasurable, { let size_field_size = IndexPage::::size_size(); let node_id_size = IndexPage::::node_id_size(); @@ -51,7 +52,7 @@ where Archive, Clone, Deserialize, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Persistable, )] #[persistable(by_parts)] -pub struct IndexPage { +pub struct IndexPage { pub size: u16, pub node_id: IndexValue, pub current_index: u16, @@ -64,7 +65,7 @@ pub struct IndexPage { Archive, Clone, Deserialize, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Persistable, )] #[persistable(by_parts)] -pub struct SizedIndexPageUtility { +pub struct SizedIndexPageUtility { pub size: u16, pub node_id: IndexValue, pub current_index: u16, @@ -72,7 +73,7 @@ pub struct SizedIndexPageUtility { pub slots: Vec, } -impl IndexPageUtility for IndexPage +impl IndexPageUtility for IndexPage where T: Archive + for<'a> Serialize< @@ -114,7 +115,7 @@ where } } -impl IndexPage { +impl IndexPage { pub fn new(node_id: IndexValue, size: usize) -> Self where T: Clone, @@ -189,7 +190,7 @@ impl IndexPage { fn get_value_offset(size: usize, value_index: usize) -> usize where - T: Default + SizeMeasurable, + T: DefaultSizeMeasurable, { let mut offset = GENERAL_HEADER_SIZE; offset += IndexPage::::size_size(); diff --git a/src/page/index/page_cdc_impl.rs b/src/page/index/page_cdc_impl.rs index 65419db..050afb8 100644 --- a/src/page/index/page_cdc_impl.rs +++ b/src/page/index/page_cdc_impl.rs @@ -11,9 +11,9 @@ use rkyv::ser::Serializer; use rkyv::util::AlignedVec; use rkyv::{Archive, Deserialize, Serialize}; -use crate::{IndexPage, IndexValue, Link, SizeMeasurable}; +use crate::{DefaultSizeMeasurable, IndexPage, IndexValue, Link}; -impl IndexPage +impl IndexPage where T: Archive + Debug diff --git a/src/page/index/page_for_unsized.rs b/src/page/index/page_for_unsized.rs index d77e54e..367a0ed 100644 --- a/src/page/index/page_for_unsized.rs +++ b/src/page/index/page_for_unsized.rs @@ -16,12 +16,14 @@ use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; use crate::page::index::IndexPageUtility; use crate::page::PageId; use crate::{align8, VariableSizeMeasurable}; -use crate::{seek_to_page_start, IndexValue, SizeMeasurable, GENERAL_HEADER_SIZE}; +use crate::{ + seek_to_page_start, DefaultSizeMeasurable, IndexValue, SizeMeasurable, GENERAL_HEADER_SIZE, +}; use crate::{Link, Persistable}; #[derive(Archive, Clone, Deserialize, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct UnsizedIndexPage< - T: Default + SizeMeasurable + VariableSizeMeasurable, + T: DefaultSizeMeasurable + VariableSizeMeasurable, const DATA_LENGTH: u32, > { pub slots_size: u16, @@ -37,7 +39,7 @@ pub struct UnsizedIndexPage< Archive, Clone, Deserialize, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Persistable, )] #[persistable(by_parts, unsized_gens)] -pub struct UnsizedIndexPageUtility { +pub struct UnsizedIndexPageUtility { pub slots_size: u16, pub node_id_size: u16, pub node_id: IndexValue, @@ -46,7 +48,7 @@ pub struct UnsizedIndexPageUtility, } -impl UnsizedIndexPageUtility { +impl UnsizedIndexPageUtility { pub fn update_node_id(&mut self, node_id: IndexValue) -> eyre::Result<()> { self.node_id_size = node_id.aligned_size() as u16; self.node_id = node_id; @@ -55,8 +57,8 @@ impl UnsizedIndexPageUtili } } -impl - IndexPageUtility for UnsizedIndexPage +impl IndexPageUtility + for UnsizedIndexPage where T: Archive + Debug diff --git a/src/page/index/table_of_contents_page.rs b/src/page/index/table_of_contents_page.rs index 392dbb9..a132a59 100644 --- a/src/page/index/table_of_contents_page.rs +++ b/src/page/index/table_of_contents_page.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use std::fmt::Debug; use crate::page::PageId; -use crate::{align, Persistable, SizeMeasurable}; +use crate::{align, DefaultSizeMeasurable, Persistable, SizeMeasurable}; #[derive(Archive, Clone, Deserialize, Debug, Serialize)] pub struct TableOfContentsPage { @@ -21,7 +21,7 @@ where Self { records: BTreeMap::new(), empty_pages: vec![], - estimated_size: usize::default().aligned_size() + 12, + estimated_size: usize::default_aligned_size() + 12, } } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 84a1a24..f631398 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -2,4 +2,6 @@ mod persistable; mod sized; pub use persistable::Persistable; -pub use sized::{align, align8, align_vec, SizeMeasurable, VariableSizeMeasurable}; +pub use sized::{ + align, align8, align_vec, DefaultSizeMeasurable, SizeMeasurable, VariableSizeMeasurable, +}; diff --git a/src/util/sized.rs b/src/util/sized.rs index cb6419d..075daff 100644 --- a/src/util/sized.rs +++ b/src/util/sized.rs @@ -41,6 +41,22 @@ pub trait SizeMeasurable { } } +/// Similar to [`SizeMeasurable`] and automatically derived for [`Default`] types +/// that implement [`SizeMeasurable`] and allows to get size of default value +/// which is useful for sized types like `u32` and etc. +pub trait DefaultSizeMeasurable: Default + SizeMeasurable { + fn default_aligned_size() -> usize; +} + +impl DefaultSizeMeasurable for T +where + T: Default + SizeMeasurable, +{ + fn default_aligned_size() -> usize { + T::default().aligned_size() + } +} + macro_rules! size_measurable_for_sized { ($($t:ident),+) => { $( @@ -143,10 +159,10 @@ impl SizeMeasurable for String { impl SizeMeasurable for Vec where - T: SizeMeasurable + Default, + T: DefaultSizeMeasurable + SizeMeasurable, { fn aligned_size(&self) -> usize { - let val_size = T::default().aligned_size(); + let val_size = T::default_aligned_size(); let vec_content_size = if val_size == 2 { 2 } else if val_size == 4 { @@ -227,7 +243,7 @@ where K: VariableSizeMeasurable, { fn aligned_size(length: usize) -> usize { - align(Link::default().aligned_size() + K::aligned_size(length)) + align(Link::default_aligned_size() + K::aligned_size(length)) } } impl VariableSizeMeasurable for indexset::core::multipair::MultiPair @@ -235,7 +251,7 @@ where K: VariableSizeMeasurable, { fn aligned_size(length: usize) -> usize { - align(Link::default().aligned_size() + K::aligned_size(length)) + align(Link::default_aligned_size() + K::aligned_size(length)) } } @@ -243,7 +259,6 @@ where mod test { use crate::util::sized::SizeMeasurable; use crate::{IndexValue, Link}; - use rkyv::to_bytes; use uuid::Uuid; #[test] @@ -292,17 +307,17 @@ mod test { let t = (u64::MAX, Link::default()); assert_eq!( t.aligned_size(), - to_bytes::(&t).unwrap().len() + rkyv::to_bytes::(&t).unwrap().len() ); let t = (u32::MAX, Link::default()); assert_eq!( t.aligned_size(), - to_bytes::(&t).unwrap().len() + rkyv::to_bytes::(&t).unwrap().len() ); let t = (u8::MAX, Link::default()); assert_eq!( t.aligned_size(), - to_bytes::(&t).unwrap().len() + rkyv::to_bytes::(&t).unwrap().len() ) }