From a08d9f1a1afa6ec11bcb99e29b030b1d3a44b63f Mon Sep 17 00:00:00 2001 From: Mica White Date: Thu, 24 Sep 2026 20:59:43 -0400 Subject: Support base expressions --- Cargo.lock | 35 +++++++++++++++++++++++------------ devenv.nix | 6 ------ src/lib.rs | 35 +++++++++++++++++++++++++++++------ tests/basic.rs | 9 +++++++-- 4 files changed, 59 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e23344..c98510c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ "manyhow", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -29,7 +29,7 @@ dependencies = [ "proc-macro2", "quote", "quote-use", - "syn", + "syn 2.0.119", ] [[package]] @@ -40,13 +40,13 @@ checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084" [[package]] name = "derive-where" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" +checksum = "2e2b94854e8576378ccda7c8de8a66ed8b4e8acbd2c50ec3418ea6c8aaf4b567" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] @@ -56,7 +56,7 @@ dependencies = [ "attribute-derive", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -74,7 +74,7 @@ dependencies = [ "manyhow-macros", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -136,14 +136,14 @@ dependencies = [ "proc-macro-utils", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "smallvec" -version = "1.15.2" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" [[package]] name = "syn" @@ -156,8 +156,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" diff --git a/devenv.nix b/devenv.nix index 04cf216..e3ffe48 100644 --- a/devenv.nix +++ b/devenv.nix @@ -16,12 +16,6 @@ in cargo-seek cargo-nextest ]; - scripts.watcher = { - exec = '' - watchexec -c -e rs "cargo clippy && cargo test && cargo run" - ''; - packages = [ pkgs.watchexec ]; - }; enterShell = '' cargo update ''; diff --git a/src/lib.rs b/src/lib.rs index 314f813..8024048 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -293,6 +293,14 @@ pub fn derive_builder(input: TokenStream) -> TokenStream { #builder_macro + impl core::convert::From<#struct_name> for #builder_name<#(#trues),*> { + fn from(s: #struct_name) -> Self { + Self { + #(#field_names: Some(s.#field_names),)* + } + } + } + impl<#(const #const_generics: bool),*> core::default::Default for #builder_name<#(#const_generics),*> { fn default() -> Self { Self { @@ -305,6 +313,10 @@ pub fn derive_builder(input: TokenStream) -> TokenStream { #builder_visibility fn builder() -> #builder_name<#(#falses),*> { #builder_name::default() } + + #builder_visibility fn into_builder(self) -> #builder_name<#(#trues),*> { + #builder_name::from(self) + } } impl<#(const #const_generics: bool),*> #builder_name<#(#const_generics),*> { @@ -360,17 +372,28 @@ pub fn derive_builder(input: TokenStream) -> TokenStream { pub fn build(input: TokenStream) -> TokenStream { let structure = parse_macro_input!(input as ExprStruct); let struct_name = &structure.path; + let base = &structure.rest; let field_names = structure.fields.iter().map(|field| &field.member); let field_values = structure.fields.iter().map(|field| &field.expr); - quote! { - #struct_name - ::builder() - #(.#field_names(#field_values))* - .build() + if let Some(base) = base { + quote! { + #base + .into_builder() + #(.#field_names(#field_values))* + .build() + } + .into() + } else { + quote! { + #struct_name + ::builder() + #(.#field_names(#field_values))* + .build() + } + .into() } - .into() } /// Creates a declarative macro to construct a type that derives [`Builder`] diff --git a/tests/basic.rs b/tests/basic.rs index ce3abf8..52212d0 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -16,6 +16,8 @@ mod foo { use foo::Foo; +use crate::foo::FooBuild; + fn main() { let x = Foo::builder().baz(42).bar("hello").bat(5).build(); assert_eq!( @@ -27,8 +29,11 @@ fn main() { } ); - let bar = "hello"; - let _: Foo = Foo! { bar }; + let x: Foo = Foo! { + baz: 32, + bat: 64, + ..x + }; assert_eq!( x, Foo { -- cgit v1.3.1