diff --git a/README.md b/README.md index 02c2649..e3e8e1b 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ pub struct ResourceLimits { // ... } #[derive(Builder)] -#[group(program = at_least(1))] +#[groups(program = at_least(1))] pub struct Launchd { #[builder(mandatory)] label: Option, @@ -93,14 +93,14 @@ This is a quick overview of the features in this library. See [`const_typed_buil - `#[builder(assume_mandatory)]`: Indicates that all fields in the struct should be assumed as mandatory. If provided without an equals sign (e.g., `#[builder(assume_mandatory)]`), it sets the `mandatory` flag for fields to true. If provided with an equals sign (e.g., `#[builder(assume_mandatory = true)]`), it sets the `mandatory` flag for fields based on the value. -- `#[group(group_name = (exact(N)|at_least(N)|at_most(N)|single)]`: +- `#[groups(group_name = (exact(N)|at_least(N)|at_most(N)|single)]`: Associates fields of the struct with a group named "group_name" and specifies the group's behavior. The `group_name` should be a string identifier. The group can have one of the following behaviors: - `exact(N)`: Exactly N fields in the group must be set during the builder construction. - `at_least(N)`: At least N fields in the group must be set during the builder construction. - `at_most(N)`: At most N fields in the group can be set during the builder construction. - `single`: Only one field in the group can be set during the builder construction. This is a shorthand for `exact(1)`. - e.g `#[group(foo = at_least(2))]` creates a group where at least 2 of the fields need to be initialized. + e.g `#[groups(foo = at_least(2))]` creates a group where at least 2 of the fields need to be initialized. - `#[builder(solver = (brute_force|compiler))]`: **Use sparingly, see note at bottom of this file!** Specifies the solver type to be used for building the struct. The `solve_type` should be one of the predefined solver types, such as `brute_force` or `compiler`. If provided with an equals sign (e.g., `#[builder(solver = brute_force)]`), it sets the "solver type" accordingly. This attribute is still tested, and `brute_force` is the default, and only if there are problems in compilation time then you can try `compiler`. `compiler` gives less guarantees though. diff --git a/const_typed_builder_derive/Cargo.toml b/const_typed_builder_derive/Cargo.toml index 3f93675..358e7e2 100644 --- a/const_typed_builder_derive/Cargo.toml +++ b/const_typed_builder_derive/Cargo.toml @@ -19,6 +19,7 @@ proc-macro2 = "1.0.70" itertools = "0.12.0" convert_case = "0.6.0" proc-macro-error = "1.0.4" +strum = { version = "0.25.0", features = ["derive"] } [lib] proc-macro = true diff --git a/const_typed_builder_derive/src/generator/builder_generator.rs b/const_typed_builder_derive/src/generator/builder_generator.rs index dc3b41e..05e3c50 100644 --- a/const_typed_builder_derive/src/generator/builder_generator.rs +++ b/const_typed_builder_derive/src/generator/builder_generator.rs @@ -3,7 +3,7 @@ use crate::info::{ Container, Field, FieldKind, GroupType, SetterKind, SolverKind, TrackedField, TrackedFieldKind, }; use itertools::{Itertools, Powerset}; -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use proc_macro_error::emit_error; use quote::{quote, ToTokens}; use std::{collections::BTreeSet, ops::Deref}; @@ -314,11 +314,11 @@ Setter for the [`{}::{field_ident}`] field. let all = self.info.group_collection().values().map(|group| { let partials = group.indices().iter().map(|index| self.info.field_collection().get(*index).expect("Could not find field associated to group").const_ident()); - let function_call: syn::Ident = group.function_symbol().into(); + let function_call = syn::Ident::new(group.function_symbol().as_ref(), Span::call_site()); let count = group.expected_count(); let ident = group.ident(); - let function_ident = group.function_symbol().to_string(); - let err_text = format!("`.build()` failed because the bounds of group `{ident}` where not met ({function_ident} {count})"); + let function_name = group.function_symbol(); + let err_text = format!("`.build()` failed because the bounds of group `{ident}` where not met ({function_name} {count})"); quote!( if !Self::#function_call(&[#(#partials),*], #count) { diff --git a/const_typed_builder_derive/src/info/group.rs b/const_typed_builder_derive/src/info/group.rs index 393faa8..8b75499 100644 --- a/const_typed_builder_derive/src/info/group.rs +++ b/const_typed_builder_derive/src/info/group.rs @@ -1,4 +1,4 @@ -use crate::symbol::{Symbol, AT_LEAST, AT_MOST, EXACT}; +use crate::symbol::Symbol; use proc_macro_error::{emit_error, emit_warning}; use std::{ cmp::Ordering, @@ -62,9 +62,9 @@ impl Group { /// Retrieves the function symbol associated with the group type. pub fn function_symbol(&self) -> Symbol { match self.group_type { - GroupType::Exact(_) => EXACT, - GroupType::AtLeast(_) => AT_LEAST, - GroupType::AtMost(_) => AT_MOST, + GroupType::Exact(_) => Symbol::Exact, + GroupType::AtLeast(_) => Symbol::AtLeast, + GroupType::AtMost(_) => Symbol::AtMost, } } diff --git a/const_typed_builder_derive/src/lib.rs b/const_typed_builder_derive/src/lib.rs index 63966a1..6afa6ff 100644 --- a/const_typed_builder_derive/src/lib.rs +++ b/const_typed_builder_derive/src/lib.rs @@ -26,7 +26,7 @@ use syn::DeriveInput; /// /// This will generate a builder pattern for `MyStruct`, allowing you to /// construct instances of `MyStruct` with a fluent API. -#[proc_macro_derive(Builder, attributes(builder, group))] +#[proc_macro_derive(Builder, attributes(builder, group, groups))] #[proc_macro_error] pub fn derive_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(input as DeriveInput); diff --git a/const_typed_builder_derive/src/parser/container_parser.rs b/const_typed_builder_derive/src/parser/container_parser.rs index 8a94278..97bcdf8 100644 --- a/const_typed_builder_derive/src/parser/container_parser.rs +++ b/const_typed_builder_derive/src/parser/container_parser.rs @@ -1,9 +1,10 @@ use super::{FieldParser, GroupParser}; use crate::{ info::{Container, Field, FieldCollection, GroupCollection, SolverKind}, - symbol, + symbol::Symbol, }; use proc_macro_error::{emit_call_site_error, emit_error, emit_warning}; +use std::str::FromStr; /// Represents the parser for struct generation. #[derive(Debug)] @@ -82,10 +83,25 @@ impl ContainerParser { note = err ), } - match (&attr_ident.to_string()).into() { - symbol::GROUP => GroupParser::new(&mut self.groups).parse(attr), - symbol::BUILDER => self.handle_attribute_builder(attr), - _ => emit_error!(&attr, "Unknown attribute"), + match Symbol::from_str(&attr_ident.to_string()) { + Ok(symbol) => match symbol { + Symbol::Group => { + emit_warning!(&attr_ident, "The use of group as a top level attribute is being deprecated, use groups instead"); + GroupParser::new(&mut self.groups).parse(attr) + } + Symbol::Groups => GroupParser::new(&mut self.groups).parse(attr), + Symbol::Builder => self.handle_attribute_builder(attr), + symbol => { + emit_error!( + &attr.meta, + format!("Attribute {symbol} can't be used at container level") + ) + } + }, + Err(err) => emit_error!( + &attr_ident, "Unknown symbol"; + note = err + ), } } @@ -110,31 +126,43 @@ impl ContainerParser { Err(err) => { emit_error!( &attr.meta, "Specifier cannot be parsed"; - help = "Try specifying it like #[{}(specifier)]", symbol::BUILDER; + help = "Try specifying it like #[{}(specifier)]", Symbol::Builder; note = err ); return Ok(()); } }; - - match (&path_ident.to_string()).into() { - symbol::ASSUME_MANDATORY => { - self.assume_mandatory = true; - } - symbol::INTO => { - self.assume_into = true; - } - symbol::SOLVER => { - let syn::ExprPath { path, .. } = meta.value()?.parse()?; - match (&path.require_ident()?.to_string()).into() { - symbol::BRUTE_FORCE => self.solver_kind = SolverKind::BruteForce, - symbol::COMPILER => self.solver_kind = SolverKind::Compiler, - _ => emit_error!(&path, "Unknown solver type"), + match Symbol::from_str(&path_ident.to_string()) { + Ok(symbol) => match symbol { + Symbol::Solver => { + let syn::ExprPath { path, .. } = meta.value()?.parse()?; + match Symbol::from_str(&path.require_ident()?.to_string()) { + Ok(solver) => match solver { + Symbol::BruteForce => self.solver_kind = SolverKind::BruteForce, + Symbol::Compiler => self.solver_kind = SolverKind::Compiler, + solver => { + emit_error!(&path, format!("{solver} is not a solver type")) + } + }, + Err(err) => emit_error!( + &path, "Unknown symbol"; + note = err + ), + } } - } - _ => { - emit_error!(meta.path, "Unknown attribute"); - } + Symbol::AssumeMandatory => self.assume_mandatory = true, + Symbol::Into => self.assume_into = true, + symbol => { + emit_error!( + &attr.meta, + format!("Specifier {symbol} can't be used at container level") + ) + } + }, + Err(err) => emit_error!( + &attr.meta, "Unknown symbol"; + note = err + ), } Ok(()) }) diff --git a/const_typed_builder_derive/src/parser/field_parser.rs b/const_typed_builder_derive/src/parser/field_parser.rs index b93a342..ea0dfe0 100644 --- a/const_typed_builder_derive/src/parser/field_parser.rs +++ b/const_typed_builder_derive/src/parser/field_parser.rs @@ -1,9 +1,10 @@ use crate::{ info::{Field, FieldKind, GroupCollection, SetterKind}, - symbol, + symbol::Symbol, util::is_option, }; use proc_macro_error::{emit_error, emit_warning}; +use std::str::FromStr; /// Represents settings for struct field generation. #[derive(Debug)] @@ -97,7 +98,7 @@ impl<'parser> FieldParser<'parser> { /// fn handle_attribute(&mut self, attr: &syn::Attribute) { let attr_ident = match attr.path().require_ident() { - Ok(ident) if ident == symbol::BUILDER => ident, + Ok(ident) if Symbol::from_str(&ident.to_string()) == Ok(Symbol::Builder) => ident, Ok(ident) => { emit_error!(ident, format!("{ident} can't be used as a field attribute")); return; @@ -137,17 +138,25 @@ impl<'parser> FieldParser<'parser> { } }; - match (&path_ident.to_string()).into() { - symbol::SKIP => self.handle_attribute_skip(path_ident), - symbol::MANDATORY => self.handle_attribute_mandatory(path_ident), - symbol::OPTIONAL => self.handle_attribute_optional(path_ident), - symbol::GROUP => self.handle_attribute_group(&meta), - symbol::PROPAGATE => self.handle_setter_kind(SetterKind::Propagate, path_ident), - symbol::ASREF => self.handle_setter_kind(SetterKind::AsRef, path_ident), - symbol::ASMUT => self.handle_setter_kind(SetterKind::AsMut, path_ident), - symbol::INTO => self.handle_setter_kind(SetterKind::Into, path_ident), - symbol::STANDARD => self.handle_setter_kind(SetterKind::Standard, path_ident), - _ => emit_error!(&attr.meta, "Unknown attribute"), + match Symbol::from_str(&path_ident.to_string()) { + Ok(symbol) => match symbol { + Symbol::Skip => self.handle_attribute_skip(path_ident), + Symbol::Mandatory => self.handle_attribute_mandatory(path_ident), + Symbol::Optional => self.handle_attribute_optional(path_ident), + Symbol::Group => self.handle_attribute_group(&meta), + Symbol::Propagate => self.handle_setter_kind(SetterKind::Propagate, path_ident), + Symbol::AsRef => self.handle_setter_kind(SetterKind::AsRef, path_ident), + Symbol::AsMut => self.handle_setter_kind(SetterKind::AsMut, path_ident), + Symbol::Into => self.handle_setter_kind(SetterKind::Into, path_ident), + Symbol::Standard => self.handle_setter_kind(SetterKind::Standard, path_ident), + symbol => { + emit_error!(&attr.meta, format!("Specifier {symbol} can't be used here")) + } + }, + Err(err) => emit_error!( + &attr.meta, "Unknown attribute"; + note = err + ), } Ok(()) }) @@ -263,7 +272,7 @@ impl<'parser> FieldParser<'parser> { Err(err) => { emit_error!( meta.path, "Group name not specified correctly"; - help = "Try defining it like #[{}(foo)]", symbol::BUILDER; + help = "Try defining it like #[{}(foo)]", Symbol::Builder; note = err ); } diff --git a/const_typed_builder_derive/src/parser/group_parser.rs b/const_typed_builder_derive/src/parser/group_parser.rs index 9b49556..79bbd53 100644 --- a/const_typed_builder_derive/src/parser/group_parser.rs +++ b/const_typed_builder_derive/src/parser/group_parser.rs @@ -1,8 +1,9 @@ use crate::{ info::{Group, GroupCollection, GroupType}, - symbol, + symbol::Symbol, }; use proc_macro_error::emit_error; +use std::str::FromStr; pub struct GroupParser<'a> { groups: &'a mut GroupCollection, @@ -20,7 +21,7 @@ impl<'a> GroupParser<'a> { Err(err) => { emit_error!( &meta.path , "Group name is not specified correctly"; - help = "Try to define it like `#[{}(foo = {}(1))]`", symbol::GROUP, symbol::AT_LEAST; + help = "Try to define it like `#[{}(foo = {}(1))]`", Symbol::Group, Symbol::AtLeast; note = err ); return Ok(()); @@ -33,7 +34,7 @@ impl<'a> GroupParser<'a> { _ => { emit_error!( &attr.meta, "Can't parse group type"; - hint = "Try to define it like `#[group({} = {}(1))]`", group_name, symbol::AT_LEAST + hint = "Try to define it like `#[groups({} = {}(1))]`", group_name, Symbol::AtLeast ); return Ok(()); } @@ -66,7 +67,7 @@ impl<'a> GroupParser<'a> { Err(err) => { emit_error!( &expr , "Group type is not specified correctly"; - help = "Try to define it like `#[group(foo = {}(1))]`", symbol::AT_LEAST; + help = "Try to define it like `#[{}(foo = {}(1))]`", Symbol::Group, Symbol::AtLeast; note = err ); return None; @@ -75,7 +76,7 @@ impl<'a> GroupParser<'a> { _ => { emit_error!( &expr, "No group type specified"; - help = "Try to define it like `#[group(foo = {}(1))]`", symbol::AT_LEAST + help = "Try to define it like `#[{}(foo = {}(1))]`", Symbol::Group, Symbol::AtLeast ); return None; } @@ -102,27 +103,35 @@ impl<'a> GroupParser<'a> { } }; - let group_type = match (&type_ident.to_string()).into() { - symbol::EXACT => GroupType::Exact(group_argument), - symbol::AT_LEAST => GroupType::AtLeast(group_argument), - symbol::AT_MOST => GroupType::AtMost(group_argument), - symbol::SINGLE => { - emit_error!( - args, - "`{}` is the only group type that doesn't take any arguments", symbol::SINGLE; - help = "`{}` is shorthand for {}(1)", symbol::SINGLE, symbol::EXACT - ); - return None; - } - _ => { + match Symbol::from_str(&type_ident.to_string()) { + Ok(symbol) => match symbol { + Symbol::AtLeast => Some(GroupType::AtLeast(group_argument)), + Symbol::AtMost => Some(GroupType::AtMost(group_argument)), + Symbol::Exact => Some(GroupType::Exact(group_argument)), + Symbol::Single => { + emit_error!( + args, + "`{}` is the only group type that doesn't take any arguments", Symbol::Single; + help = "`{}` is shorthand for {}(1)", Symbol::Single, Symbol::Exact + ); + None + } + symbol => { + emit_error!( + type_ident, format!("{symbol} is an unknown group type"); + help = "Known group types are {}, {} and {}", Symbol::Single, Symbol::AtLeast, Symbol::AtMost + ); + None + } + }, + Err(err) => { emit_error!( - type_ident, "Unknown group type"; - help = "Known group types are {}, {} and {}", symbol::EXACT, symbol::AT_LEAST, symbol::AT_MOST + &type_ident, "Unknown specifier"; + note = err ); - return None; + None } - }; - Some(group_type) + } } fn handle_group_path(&self, expr: &syn::ExprPath) -> Option { @@ -132,28 +141,35 @@ impl<'a> GroupParser<'a> { Err(err) => { emit_error!( &expr , "Group type is not specified correctly"; - help = "Try to define it like `#[group(foo = {}(1))]`", symbol::AT_LEAST; + help = "Try to define it like `#[{}(foo = {}(1))]`", Symbol::Group, Symbol::AtLeast; note = err ); return None; } }; - - match (&type_ident.to_string()).into() { - symbol::SINGLE => Some(GroupType::Exact(1)), - symbol::EXACT | symbol::AT_LEAST | symbol::AT_MOST => { - emit_error!( - &expr, - "Missing arguments for group type"; - help = "Try `{}(1)`, or any other usize", &type_ident - ); - None - } - _ => { + match Symbol::from_str(&type_ident.to_string()) { + Ok(symbol) => match symbol { + Symbol::Single => Some(GroupType::Exact(1)), + Symbol::Exact | Symbol::AtLeast | Symbol::AtMost => { + emit_error!( + &expr, + "Missing arguments for group type"; + help = "Try `{}(1)`, or any other usize", &type_ident + ); + None + } + symbol => { + emit_error!( + type_ident, format!("{symbol} is an unknown group type"); + help = "Known group types are {}, {} and {}", Symbol::Single, Symbol::AtLeast, Symbol::AtMost + ); + None + } + }, + Err(err) => { emit_error!( - type_ident, - "Unknown group type"; - help = "Known group types are {}, {} and {}", symbol::EXACT, symbol::AT_LEAST, symbol::AT_MOST + &type_ident, "Unknown specifier"; + note = err ); None } diff --git a/const_typed_builder_derive/src/symbol.rs b/const_typed_builder_derive/src/symbol.rs index fa11c1a..0d30c59 100644 --- a/const_typed_builder_derive/src/symbol.rs +++ b/const_typed_builder_derive/src/symbol.rs @@ -1,104 +1,36 @@ -use proc_macro2::Span; -use std::fmt::Display; -use syn::{Ident, Path}; - -/// A `Symbol` is a wrapper around a string identifier used for constants and identifiers. -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct Symbol<'a>(&'a str); - -/// Constant representing the `mandatory` symbol. -pub const MANDATORY: Symbol = Symbol("mandatory"); -/// Constant representing the `group` symbol. -pub const GROUP: Symbol = Symbol("group"); -/// Constant representing the `builder` symbol. -pub const BUILDER: Symbol = Symbol("builder"); -/// Constant representing the `single` symbol. -pub const SINGLE: Symbol = Symbol("single"); -/// Constant representing the `at_least` symbol. -pub const AT_LEAST: Symbol = Symbol("at_least"); -/// Constant representing the `at_most` symbol. -pub const AT_MOST: Symbol = Symbol("at_most"); -/// Constant representing the `exact` symbol. -pub const EXACT: Symbol = Symbol("exact"); -/// Constant representing the `propagate` symbol. -pub const PROPAGATE: Symbol = Symbol("propagate"); -/// Constant representing the `assume_mandatory` symbol. -pub const ASSUME_MANDATORY: Symbol = Symbol("assume_mandatory"); -/// Constant representing the `optional` symbol. -pub const OPTIONAL: Symbol = Symbol("optional"); -/// Constant representing the `solver` symbol. -pub const SOLVER: Symbol = Symbol("solver"); -/// Constant representing the `brute_force` symbol. -pub const BRUTE_FORCE: Symbol = Symbol("brute_force"); -/// Constant representing the `compiler` symbol. -pub const COMPILER: Symbol = Symbol("compiler"); -/// Constant representing the `skip` symbol. -pub const SKIP: Symbol = Symbol("skip"); -/// Constant representing the `setter` symbol. -pub const INTO: Symbol = Symbol("into"); -/// Constant representing the `setter` symbol. -pub const ASREF: Symbol = Symbol("asref"); -/// Constant representing the `setter` symbol. -pub const ASMUT: Symbol = Symbol("asmut"); -/// Constant representing the `setter` symbol. -pub const STANDARD: Symbol = Symbol("standard"); - -impl<'a> From<&'a String> for Symbol<'a> { - fn from(value: &'a String) -> Self { - Symbol(value) - } -} - -impl<'a> From> for syn::Ident { - fn from(value: Symbol) -> Self { - syn::Ident::new(value.0, Span::call_site()) - } -} - -// impl <'a> From<&'a Ident> for Symbol<'a> { -// fn from(value: &'a Ident) -> Self { -// Symbol(value.to_string().as_str()) -// } -// } - -impl<'a> PartialEq> for String { - fn eq(&self, word: &Symbol) -> bool { - self == word.0 - } -} - -impl<'a> PartialEq> for str { - fn eq(&self, word: &Symbol) -> bool { - self == word.0 - } -} - -impl<'a> PartialEq> for Ident { - fn eq(&self, word: &Symbol) -> bool { - self == word.0 - } -} - -impl<'a> PartialEq> for &'a Ident { - fn eq(&self, word: &Symbol) -> bool { - *self == word.0 - } -} - -impl<'a> PartialEq> for Path { - fn eq(&self, word: &Symbol) -> bool { - self.is_ident(word.0) - } -} - -impl<'a> PartialEq> for &'a Path { - fn eq(&self, word: &Symbol) -> bool { - self.is_ident(word.0) - } -} - -impl<'a> Display for Symbol<'a> { - fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str(self.0) - } +use strum::{AsRefStr, Display, EnumString}; + +#[derive(AsRefStr, Debug, Display, EnumString, PartialEq, Eq)] +#[strum(serialize_all = "snake_case")] +pub enum Symbol { + // Top level attributes + Builder, + Groups, + + // Field kinds + Group, // Deprecated as top level attribute + Mandatory, + Skip, + Optional, + AssumeMandatory, + + // Group kinds + Single, + AtLeast, + AtMost, + Exact, + + // Solver kinds + Solver, + BruteForce, + Compiler, + + // Setter kinds + Propagate, + Into, + #[strum(serialize = "as_ref", serialize = "asref")] + AsRef, + #[strum(serialize = "as_mut", serialize = "asmut")] + AsMut, + Standard, } diff --git a/const_typed_builder_test/Cargo.toml b/const_typed_builder_test/Cargo.toml index 53897c1..203f16d 100644 --- a/const_typed_builder_test/Cargo.toml +++ b/const_typed_builder_test/Cargo.toml @@ -13,6 +13,6 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] +[dev-dependencies] const_typed_builder = { path = "../../const_typed_builder", version = "=0.3.0" } trybuild = "1.0.84" \ No newline at end of file diff --git a/const_typed_builder_test/compile_fail/group_1.rs b/const_typed_builder_test/compile_fail/group_1.rs index 4ca314f..00af065 100644 --- a/const_typed_builder_test/compile_fail/group_1.rs +++ b/const_typed_builder_test/compile_fail/group_1.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(baz = at_least(2))] + #[groups(baz = at_least(2))] pub struct Foo { #[builder(group = baz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_1.stderr b/const_typed_builder_test/compile_fail/group_1.stderr index 0ff3bf9..f99aaec 100644 --- a/const_typed_builder_test/compile_fail/group_1.stderr +++ b/const_typed_builder_test/compile_fail/group_1.stderr @@ -2,10 +2,10 @@ error: Group can never be satisfied = note: Expected amount of fields: at least 2, amount of available fields: 1 - --> ./compile_fail/group_1.rs:5:13 + --> ./compile_fail/group_1.rs:5:14 | -5 | #[group(baz = at_least(2))] - | ^^^ +5 | #[groups(baz = at_least(2))] + | ^^^ error[E0599]: no function or associated item named `builder` found for struct `Foo` in the current scope --> ./compile_fail/group_1.rs:10:27 diff --git a/const_typed_builder_test/compile_fail/group_2.rs b/const_typed_builder_test/compile_fail/group_2.rs index f2cd9ca..5cf0571 100644 --- a/const_typed_builder_test/compile_fail/group_2.rs +++ b/const_typed_builder_test/compile_fail/group_2.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(baz = at_least(2))] + #[groups(baz = at_least(2))] pub struct Foo { #[builder(group = baz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_and_mandatory_1.rs b/const_typed_builder_test/compile_fail/group_and_mandatory_1.rs index d92e476..9a1bb31 100644 --- a/const_typed_builder_test/compile_fail/group_and_mandatory_1.rs +++ b/const_typed_builder_test/compile_fail/group_and_mandatory_1.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = single)] + #[groups(quz = single)] pub struct Foo { #[builder(group = quz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_and_mandatory_2.rs b/const_typed_builder_test/compile_fail/group_and_mandatory_2.rs index 70bb983..e3cc31e 100644 --- a/const_typed_builder_test/compile_fail/group_and_mandatory_2.rs +++ b/const_typed_builder_test/compile_fail/group_and_mandatory_2.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = single)] + #[groups(quz = single)] pub struct Foo { #[builder(group = quz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_and_mandatory_3.rs b/const_typed_builder_test/compile_fail/group_and_mandatory_3.rs index e7fd1d5..ac57ffe 100644 --- a/const_typed_builder_test/compile_fail/group_and_mandatory_3.rs +++ b/const_typed_builder_test/compile_fail/group_and_mandatory_3.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = single)] + #[groups(quz = single)] pub struct Foo { #[builder(group = quz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_and_mandatory_4.rs b/const_typed_builder_test/compile_fail/group_and_mandatory_4.rs index 8a87692..5f114d1 100644 --- a/const_typed_builder_test/compile_fail/group_and_mandatory_4.rs +++ b/const_typed_builder_test/compile_fail/group_and_mandatory_4.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = single)] + #[groups(quz = single)] pub struct Foo { #[builder(group = quz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_at_least_1.rs b/const_typed_builder_test/compile_fail/group_at_least_1.rs index 7bf5ff6..b947ccf 100644 --- a/const_typed_builder_test/compile_fail/group_at_least_1.rs +++ b/const_typed_builder_test/compile_fail/group_at_least_1.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = at_least(2))] + #[groups(quz = at_least(2))] pub struct Foo { #[builder(group = quz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_at_least_2.rs b/const_typed_builder_test/compile_fail/group_at_least_2.rs index d926e91..d79a49e 100644 --- a/const_typed_builder_test/compile_fail/group_at_least_2.rs +++ b/const_typed_builder_test/compile_fail/group_at_least_2.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = at_least(2))] + #[groups(quz = at_least(2))] pub struct Foo { #[builder(group = quz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_at_most_1.rs b/const_typed_builder_test/compile_fail/group_at_most_1.rs index 4384edb..95f6725 100644 --- a/const_typed_builder_test/compile_fail/group_at_most_1.rs +++ b/const_typed_builder_test/compile_fail/group_at_most_1.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = at_most(2))] + #[groups(quz = at_most(2))] pub struct Foo { #[builder(group = quz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_multiple_member_1.rs b/const_typed_builder_test/compile_fail/group_multiple_member_1.rs index 1cd2916..e4997d1 100644 --- a/const_typed_builder_test/compile_fail/group_multiple_member_1.rs +++ b/const_typed_builder_test/compile_fail/group_multiple_member_1.rs @@ -2,7 +2,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(baz = single)] + #[groups(baz = single)] pub struct Foo { #[builder(group = baz)] bar: Option, diff --git a/const_typed_builder_test/compile_fail/group_solver_compiler_1.rs b/const_typed_builder_test/compile_fail/group_solver_compiler_1.rs index da8d080..0616959 100644 --- a/const_typed_builder_test/compile_fail/group_solver_compiler_1.rs +++ b/const_typed_builder_test/compile_fail/group_solver_compiler_1.rs @@ -3,7 +3,7 @@ use const_typed_builder::Builder; fn main() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(baz = at_least(2))] + #[groups(baz = at_least(2))] #[builder(solver = compiler)] pub struct Foo { #[builder(group = baz)] diff --git a/const_typed_builder_test/src/lib.rs b/const_typed_builder_test/src/lib.rs index bf7c5da..006bf2b 100644 --- a/const_typed_builder_test/src/lib.rs +++ b/const_typed_builder_test/src/lib.rs @@ -240,7 +240,7 @@ mod test { #[test] fn group() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(baz = single)] + #[groups(baz = single)] pub struct Foo { #[builder(group = baz)] bar: Option, @@ -259,7 +259,7 @@ mod test { #[test] fn group_solver_compiler() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(baz = single)] + #[groups(baz = single)] #[builder(solver = compiler)] pub struct Foo { #[builder(group = baz)] @@ -279,7 +279,7 @@ mod test { #[test] fn group_multiple_member() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(baz = single)] + #[groups(baz = single)] pub struct Foo { #[builder(group = baz)] bar: Option, @@ -305,7 +305,7 @@ mod test { #[test] fn group_and_mandatory() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = single)] + #[groups(quz = single)] pub struct Foo { #[builder(group = quz)] bar: Option, @@ -342,7 +342,7 @@ mod test { #[test] fn group_and_option_mandatory() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = single)] + #[groups(quz = single)] pub struct Foo { #[builder(group = quz)] bar: Option, @@ -380,7 +380,7 @@ mod test { #[test] fn group_at_least() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = at_least(2))] + #[groups(quz = at_least(2))] pub struct Foo { #[builder(group = quz)] bar: Option, @@ -431,7 +431,7 @@ mod test { #[test] fn group_at_most() { #[derive(Debug, Default, PartialEq, Eq, Builder)] - #[group(quz = at_most(2))] + #[groups(quz = at_most(2))] pub struct Foo { #[builder(group = quz)] bar: Option, @@ -798,6 +798,21 @@ mod test { assert_eq!(foo, expected); } + #[test] + fn as_ref() { + #[derive(Debug, PartialEq, Builder)] + pub struct Foo<'a> { + #[builder(asref)] + bar: &'a str, + } + let m_str = "Hello world!".to_string(); + + let expected = Foo { bar: &m_str }; + + let foo = Foo::builder().bar(&m_str).build(); + assert_eq!(foo, expected); + } + #[test] fn asref_optional() { #[derive(Debug, PartialEq, Builder)] @@ -832,6 +847,23 @@ mod test { assert_eq!(foo, expected); } + #[test] + fn as_mut() { + #[derive(Debug, PartialEq, Builder)] + pub struct Foo<'a> { + #[builder(as_mut)] + bar: &'a mut str, + } + let mut m_str = "Hello world!".to_string(); + + let expected = Foo { + bar: &mut m_str.clone(), + }; + + let foo = Foo::builder().bar(&mut m_str).build(); + assert_eq!(foo, expected); + } + #[test] fn asmut_optional() { #[derive(Debug, PartialEq, Builder)] diff --git a/src/lib.rs b/src/lib.rs index 4298f62..526faa2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,7 @@ /// ```rust /// # use const_typed_builder::Builder; /// #[derive(Builder)] -/// #[group(my_group = single)] +/// #[groups(my_group = single)] /// pub struct Foo { /// #[builder(group = my_group)] /// bar: Option, @@ -148,7 +148,7 @@ /// ```compile_fail /// # use const_typed_builder::Builder; /// #[derive(Builder)] -/// #[group(my_group = single)] +/// #[groups(my_group = single)] /// pub struct Foo { /// #[builder(group = my_group)] /// bar: Option, @@ -165,7 +165,7 @@ /// ```rust /// # use const_typed_builder::Builder; /// #[derive(Builder)] -/// #[group(my_group = at_least(2))] +/// #[groups(my_group = at_least(2))] /// pub struct Foo { /// #[builder(group = my_group)] /// bar: Option, @@ -186,8 +186,8 @@ /// ```rust /// # use const_typed_builder::Builder; /// #[derive(Builder)] -/// #[group(least = at_least(2))] -/// #[group(most = at_most(3))] +/// #[groups(least = at_least(2))] +/// #[groups(most = at_most(3))] /// pub struct Foo { /// #[builder(group = least, group = most)] /// bar: Option,