diff --git a/Cargo.toml b/Cargo.toml index 48b64d65..6eb185a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["codegen", "examples", "performance_measurement", "performance_measur [package] name = "worktable" -version = "0.6.4" +version = "0.6.5" edition = "2024" authors = ["Handy-caT"] license = "MIT" @@ -22,7 +22,7 @@ tokio = { version = "1", features = ["full"] } tracing = "0.1" rkyv = { version = "0.8.9", features = ["uuid-1"] } lockfree = { version = "0.5.1" } -worktable_codegen = { path = "codegen", version = "0.6.0" } +worktable_codegen = { path = "codegen", version = "0.6.5" } fastrand = "2.3.0" futures = "0.3.30" uuid = { version = "1.10.0", features = ["v4", "v7"] } diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index d7c67e52..dcc03799 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "worktable_codegen" -version = "0.6.0" +version = "0.6.5" edition = "2024" license = "MIT" description = "WorkTable codegeneration crate" diff --git a/codegen/src/worktable/generator/row.rs b/codegen/src/worktable/generator/row.rs index a9aa445e..142b6db4 100644 --- a/codegen/src/worktable/generator/row.rs +++ b/codegen/src/worktable/generator/row.rs @@ -73,8 +73,18 @@ impl Generator { rows[*pos] = quote! {pub #i: #type_,} } + let custom_derives = + if let Some(custom_derives) = &self.config.as_ref().map(|c| &c.row_derives) { + quote! { + #[derive(#(#custom_derives),*)] + } + } else { + quote! {} + }; + quote! { #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize, PartialEq, MemStat)] + #custom_derives #[rkyv(derive(Debug))] #[repr(C)] pub struct #ident { diff --git a/codegen/src/worktable/model/config.rs b/codegen/src/worktable/model/config.rs index bff52208..f61c3e59 100644 --- a/codegen/src/worktable/model/config.rs +++ b/codegen/src/worktable/model/config.rs @@ -1,4 +1,7 @@ +use proc_macro2::Ident; + #[derive(Debug, Default)] pub struct Config { pub page_size: Option, + pub row_derives: Vec, } diff --git a/codegen/src/worktable/parser/config.rs b/codegen/src/worktable/parser/config.rs index b7362aaa..48fa3ecc 100644 --- a/codegen/src/worktable/parser/config.rs +++ b/codegen/src/worktable/parser/config.rs @@ -57,35 +57,73 @@ impl Parser { } pub fn parse_config(&mut self, config: &mut Config) -> syn::Result> { - let Some(_) = self.input_iter.peek() else { - return Ok(None); - }; - let ident = self.input_iter.next().unwrap(); - let name = if let TokenTree::Ident(ident) = ident { - ident - } else { - return Err(syn::Error::new(ident.span(), "Expected identifier.")); - }; + while self.peek_next().is_some() { + let Some(_) = self.input_iter.peek() else { + return Ok(None); + }; + let ident = self.input_iter.next().unwrap(); + let name = if let TokenTree::Ident(ident) = ident { + ident + } else { + return Err(syn::Error::new(ident.span(), "Expected identifier.")); + }; - self.parse_colon()?; + self.parse_colon()?; + + match name.to_string().as_str() { + "page_size" => { + let value = self.input_iter.next().ok_or(syn::Error::new( + self.input.span(), + "Expected page size value in declaration", + ))?; + let value = if let TokenTree::Literal(value) = value { + value + } else { + return Err(syn::Error::new(value.span(), "Expected identifier.")); + }; + + self.try_parse_comma()?; + + let value = value.to_string(); + let value = value.replace("_", ""); - match name.to_string().as_str() { - "page_size" => { - let value = self.input_iter.next().ok_or(syn::Error::new( - self.input.span(), - "Expected page size value in declaration", - ))?; - let value = if let TokenTree::Literal(value) = value { - value - } else { - return Err(syn::Error::new(value.span(), "Expected identifier.")); - }; - let value = value.to_string(); - let value = value.replace("_", ""); - - config.page_size = Some(u32::from_str(value.as_str()).unwrap()) + config.page_size = Some(u32::from_str(value.as_str()).unwrap()) + } + "row_derives" => { + const CONFIG_VARIANTS: [&str; 2] = ["page_size", "row_derives"]; + + let mut derives = vec![]; + + while let Some(ident) = self.peek_next() { + if CONFIG_VARIANTS.contains(&ident.to_string().as_str()) { + if derives.is_empty() { + return Err(syn::Error::new( + ident.span(), + "Expected at least one derive in declaration.", + )); + } + break; + } + + let derive = self.input_iter.next().ok_or(syn::Error::new( + self.input.span(), + "Expected at least one derive in declaration", + ))?; + let derive = if let TokenTree::Ident(derive) = derive { + derive + } else { + return Err(syn::Error::new(derive.span(), "Expected identifier.")); + }; + + self.try_parse_comma()?; + + derives.push(derive) + } + + config.row_derives = derives; + } + _ => return Err(syn::Error::new(name.span(), "Unexpected identifier")), } - _ => return Err(syn::Error::new(name.span(), "Unexpected identifier")), } Ok(Some(())) diff --git a/tests/worktable/config.rs b/tests/worktable/config.rs index d4c709ae..6c96c0a1 100644 --- a/tests/worktable/config.rs +++ b/tests/worktable/config.rs @@ -5,8 +5,11 @@ worktable! ( name: Test, columns: { id: u64 primary_key autoincrement, + something: String, + another: u32, }, config: { + row_derives: Default, page_size: 32_000, } ); @@ -15,3 +18,11 @@ worktable! ( fn test_page_size() { assert_eq!(TEST_PAGE_SIZE, 32_000) } + +#[test] +fn test_default_available() { + let d = TestRow::default(); + assert_eq!(d.id, u64::default()); + assert_eq!(d.something, String::default()); + assert_eq!(d.another, u32::default()) +}