Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicitely create UninitializedField errors #192

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion derive_builder/tests/run-pass/custom_types.rs
Expand Up @@ -10,7 +10,6 @@ type Into = Unit;
type Option = Unit;
type Result = Unit;
type Some = Unit;
type String = Unit;

impl core::fmt::Debug for Unit {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
Expand Down
44 changes: 18 additions & 26 deletions derive_builder_core/src/build_method.rs
@@ -1,10 +1,10 @@
use crate::macro_options::FieldWithDefaults;
use doc_comment_from;
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, TokenStreamExt};
use syn;
use Block;
use BuilderPattern;
use Initializer;
use DEFAULT_STRUCT_NAME;

/// Initializer for the struct fields in the build method, implementing
Expand Down Expand Up @@ -52,8 +52,8 @@ pub struct BuildMethod<'a> {
pub target_ty_generics: Option<syn::TypeGenerics<'a>>,
/// Type of error.
pub error_ty: syn::Ident,
/// Field initializers for the target type.
pub initializers: Vec<TokenStream>,
/// Fields for the target type.
pub fields: Vec<FieldWithDefaults<'a>>,
/// Doc-comment of the builder struct.
pub doc_comment: Option<syn::Attribute>,
/// Default value for the whole struct.
Expand All @@ -71,7 +71,13 @@ impl<'a> ToTokens for BuildMethod<'a> {
let vis = &self.visibility;
let target_ty = &self.target_ty;
let target_ty_generics = &self.target_ty_generics;
let initializers = &self.initializers;
let error_ty = &self.error_ty;
let error_constructor = quote!(#error_ty::UninitializedField);
let initializers = &self
.fields
.iter()
.map(|field| field.as_initializer(&error_constructor))
.collect::<Vec<_>>();
let self_param = match self.pattern {
BuilderPattern::Owned => quote!(self),
BuilderPattern::Mutable | BuilderPattern::Immutable => quote!(&self),
Expand All @@ -82,7 +88,6 @@ impl<'a> ToTokens for BuildMethod<'a> {
quote!(let #ident: #target_ty #target_ty_generics = #default_expr;)
});
let validate_fn = self.validate_fn.as_ref().map(|vfn| quote!(#vfn(&self)?;));
let error_ty = &self.error_ty;

if self.enabled {
tokens.append_all(quote!(
Expand All @@ -108,13 +113,9 @@ impl<'a> BuildMethod<'a> {
self
}

/// Populate the `BuildMethod` with appropriate initializers of the
/// underlying struct.
///
/// For each struct field this must be called with the appropriate
/// initializer.
pub fn push_initializer(&mut self, init: Initializer) -> &mut Self {
self.initializers.push(quote!(#init));
/// Set fields for this item.
pub fn fields(&mut self, fields: &[FieldWithDefaults<'a>]) -> &mut Self {
self.fields = fields.to_vec();
self
}
}
Expand All @@ -133,7 +134,7 @@ macro_rules! default_build_method {
target_ty: &syn::Ident::new("Foo", ::proc_macro2::Span::call_site()),
target_ty_generics: None,
error_ty: syn::Ident::new("FooBuilderError", ::proc_macro2::Span::call_site()),
initializers: vec![quote!(foo: self.foo,)],
fields: vec![],
doc_comment: None,
default_struct: None,
validate_fn: None,
Expand All @@ -155,9 +156,7 @@ mod tests {
quote!(#build_method).to_string(),
quote!(
pub fn build(&self) -> ::derive_builder::export::core::result::Result<Foo, FooBuilderError> {
Ok(Foo {
foo: self.foo,
})
Ok(Foo {})
}
)
.to_string()
Expand All @@ -175,9 +174,7 @@ mod tests {
quote!(
pub fn build(&self) -> ::derive_builder::export::core::result::Result<Foo, FooBuilderError> {
let __default: Foo = { Default::default() };
Ok(Foo {
foo: self.foo,
})
Ok(Foo {})
}
)
.to_string()
Expand All @@ -204,9 +201,7 @@ mod tests {
quote!(#build_method).to_string(),
quote!(
pub fn finish(&self) -> ::derive_builder::export::core::result::Result<Foo, FooBuilderError> {
Ok(Foo {
foo: self.foo,
})
Ok(Foo {})
}
)
.to_string()
Expand All @@ -227,10 +222,7 @@ mod tests {
quote!(
pub fn build(&self) -> ::derive_builder::export::core::result::Result<Foo, FooBuilderError> {
IpsumBuilder::validate(&self)?;

Ok(Foo {
foo: self.foo,
})
Ok(Foo {})
}
)
.to_string()
Expand Down
90 changes: 30 additions & 60 deletions derive_builder_core/src/builder.rs
Expand Up @@ -51,12 +51,6 @@ use Setter;
/// ValidationError(String),
/// }
///
/// impl ::derive_builder::export::core::convert::From<&'static str> for FooBuilderError {
/// fn from(s: &'static str) -> Self {
/// Self::UninitializedField(s)
/// }
/// }
///
/// impl ::derive_builder::export::core::convert::From<String> for FooBuilderError {
/// fn from(s: String) -> Self {
/// Self::ValidationError(s)
Expand Down Expand Up @@ -196,15 +190,11 @@ impl<'a> ToTokens for Builder<'a> {
ValidationError(String),
}

impl ::derive_builder::export::core::convert::From<&'static str> for #builder_error_ident {
fn from(s: &'static str) -> Self {
Self::UninitializedField(s)
}
}

impl ::derive_builder::export::core::convert::From<String> for #builder_error_ident {
fn from(s: String) -> Self {
Self::ValidationError(s)
impl<E> ::derive_builder::export::core::convert::From<E> for #builder_error_ident
where E: ::derive_builder::export::core::convert::AsRef<str>
{
fn from(s: E) -> Self {
Self::ValidationError(s.as_ref().to_string())
}
}

Expand Down Expand Up @@ -357,15 +347,11 @@ mod tests {
ValidationError(String),
}

impl ::derive_builder::export::core::convert::From<&'static str> for FooBuilderError {
fn from(s: &'static str) -> Self {
Self::UninitializedField(s)
}
}

impl ::derive_builder::export::core::convert::From<String> for FooBuilderError {
fn from(s: String) -> Self {
Self::ValidationError(s)
impl<E> ::derive_builder::export::core::convert::From<E> for FooBuilderError
where E: ::derive_builder::export::core::convert::AsRef<str>
{
fn from(s: E) -> Self {
Self::ValidationError(s.as_ref().to_string())
}
}

Expand Down Expand Up @@ -446,15 +432,11 @@ mod tests {
ValidationError(String),
}

impl ::derive_builder::export::core::convert::From<&'static str> for FooBuilderError {
fn from(s: &'static str) -> Self {
Self::UninitializedField(s)
}
}

impl ::derive_builder::export::core::convert::From<String> for FooBuilderError {
fn from(s: String) -> Self {
Self::ValidationError(s)
impl<E> ::derive_builder::export::core::convert::From<E> for FooBuilderError
where E: ::derive_builder::export::core::convert::AsRef<str>
{
fn from(s: E) -> Self {
Self::ValidationError(s.as_ref().to_string())
}
}

Expand Down Expand Up @@ -535,15 +517,11 @@ mod tests {
ValidationError(String),
}

impl ::derive_builder::export::core::convert::From<&'static str> for FooBuilderError {
fn from(s: &'static str) -> Self {
Self::UninitializedField(s)
}
}

impl ::derive_builder::export::core::convert::From<String> for FooBuilderError {
fn from(s: String) -> Self {
Self::ValidationError(s)
impl<E> ::derive_builder::export::core::convert::From<E> for FooBuilderError
where E: ::derive_builder::export::core::convert::AsRef<str>
{
fn from(s: E) -> Self {
Self::ValidationError(s.as_ref().to_string())
}
}

Expand Down Expand Up @@ -627,15 +605,11 @@ mod tests {
ValidationError(String),
}

impl ::derive_builder::export::core::convert::From<&'static str> for FooBuilderError {
fn from(s: &'static str) -> Self {
Self::UninitializedField(s)
}
}

impl ::derive_builder::export::core::convert::From<String> for FooBuilderError {
fn from(s: String) -> Self {
Self::ValidationError(s)
impl<E> ::derive_builder::export::core::convert::From<E> for FooBuilderError
where E: ::derive_builder::export::core::convert::AsRef<str>
{
fn from(s: E) -> Self {
Self::ValidationError(s.as_ref().to_string())
}
}

Expand Down Expand Up @@ -718,15 +692,11 @@ mod tests {
ValidationError(String),
}

impl ::derive_builder::export::core::convert::From<&'static str> for FooBuilderError {
fn from(s: &'static str) -> Self {
Self::UninitializedField(s)
}
}

impl ::derive_builder::export::core::convert::From<String> for FooBuilderError {
fn from(s: String) -> Self {
Self::ValidationError(s)
impl<E> ::derive_builder::export::core::convert::From<E> for FooBuilderError
where E: ::derive_builder::export::core::convert::AsRef<str>
{
fn from(s: E) -> Self {
Self::ValidationError(s.as_ref().to_string())
}
}

Expand Down
41 changes: 24 additions & 17 deletions derive_builder_core/src/initializer.rs
Expand Up @@ -48,6 +48,8 @@ pub struct Initializer<'a> {
pub default_value: Option<Block>,
/// Whether the build_method defines a default struct.
pub use_default_struct: bool,
/// Error constructor
pub error_constructor: &'a TokenStream,
}

impl<'a> ToTokens for Initializer<'a> {
Expand Down Expand Up @@ -90,7 +92,10 @@ impl<'a> Initializer<'a> {
if self.use_default_struct {
MatchNone::UseDefaultStructField(self.field_ident)
} else {
MatchNone::ReturnError(self.field_ident.to_string())
MatchNone::ReturnError {
field_ident: self.field_ident,
error_constructor: self.error_constructor,
}
}
}
}
Expand Down Expand Up @@ -118,7 +123,10 @@ enum MatchNone<'a> {
/// The default struct must be in scope in the build_method.
UseDefaultStructField(&'a syn::Ident),
/// Inner value must be the field name
ReturnError(String),
ReturnError {
field_ident: &'a syn::Ident,
error_constructor: &'a TokenStream,
},
}

impl<'a> ToTokens for MatchNone<'a> {
Expand All @@ -133,9 +141,15 @@ impl<'a> ToTokens for MatchNone<'a> {
None => #struct_ident.#field_ident
))
}
MatchNone::ReturnError(ref err) => tokens.append_all(quote!(
None => return ::derive_builder::export::core::result::Result::Err(::derive_builder::export::core::convert::Into::into(#err))
)),
MatchNone::ReturnError {
ref field_ident,
ref error_constructor,
} => {
let field_name = field_ident.to_string();
tokens.append_all(quote!(
None => return ::derive_builder::export::core::result::Result::Err(#error_constructor(#field_name))
))
}
}
}
}
Expand Down Expand Up @@ -171,6 +185,7 @@ macro_rules! default_initializer {
builder_pattern: BuilderPattern::Mutable,
default_value: None,
use_default_struct: false,
error_constructor: &syn::parse_str("FooError::UninitializedField").unwrap(),
}
};
}
Expand All @@ -190,9 +205,7 @@ mod tests {
quote!(
foo: match self.foo {
Some(ref value) => ::derive_builder::export::core::clone::Clone::clone(value),
None => return ::derive_builder::export::core::result::Result::Err(::derive_builder::export::core::convert::Into::into(
"foo"
)),
None => return ::derive_builder::export::core::result::Result::Err(FooError::UninitializedField("foo")),
},
)
.to_string()
Expand All @@ -209,9 +222,7 @@ mod tests {
quote!(
foo: match self.foo {
Some(ref value) => ::derive_builder::export::core::clone::Clone::clone(value),
None => return ::derive_builder::export::core::result::Result::Err(::derive_builder::export::core::convert::Into::into(
"foo"
)),
None => return ::derive_builder::export::core::result::Result::Err(FooError::UninitializedField("foo")),
},
)
.to_string()
Expand All @@ -228,9 +239,7 @@ mod tests {
quote!(
foo: match self.foo {
Some(value) => value,
None => return ::derive_builder::export::core::result::Result::Err(::derive_builder::export::core::convert::Into::into(
"foo"
)),
None => return ::derive_builder::export::core::result::Result::Err(FooError::UninitializedField("foo")),
},
)
.to_string()
Expand Down Expand Up @@ -291,9 +300,7 @@ mod tests {
quote!(
foo: match self.foo {
Some(ref value) => ::derive_builder::export::core::clone::Clone::clone(value),
None => return ::derive_builder::export::core::result::Result::Err(::derive_builder::export::core::convert::Into::into(
"foo"
)),
None => return ::derive_builder::export::core::result::Result::Err(FooError::UninitializedField("foo")),
},
)
.to_string()
Expand Down