From dd31592f7eab9d11f83c154caad900bc1a553d20 Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Sat, 25 Jul 2020 00:36:19 +0200 Subject: [PATCH 1/5] structural error --- derive_builder/examples/validation.rs | 2 +- derive_builder/src/lib.rs | 9 +- derive_builder/src/options/darling_opts.rs | 9 + derive_builder/tests/builder_name.rs | 6 +- derive_builder/tests/custom_default.rs | 6 +- derive_builder/tests/generic_structs.rs | 6 +- derive_builder/tests/lifetime.rs | 6 +- derive_builder/tests/setter_visibility.rs | 7 +- derive_builder/tests/validation.rs | 9 +- derive_builder_core/src/build_method.rs | 19 +- derive_builder_core/src/builder.rs | 239 ++++++++++++++++++++- derive_builder_core/src/initializer.rs | 27 ++- 12 files changed, 298 insertions(+), 47 deletions(-) diff --git a/derive_builder/examples/validation.rs b/derive_builder/examples/validation.rs index ebbaf835..154b937e 100644 --- a/derive_builder/examples/validation.rs +++ b/derive_builder/examples/validation.rs @@ -30,5 +30,5 @@ fn main() { let x = LoremBuilder::default().ipsum(120).build().unwrap_err(); // .. the build will fail: - assert_eq!(&x, "You'll tire yourself out"); + assert_eq!(&x.to_string(), "You'll tire yourself out"); } diff --git a/derive_builder/src/lib.rs b/derive_builder/src/lib.rs index 148e9e8c..916055e8 100644 --- a/derive_builder/src/lib.rs +++ b/derive_builder/src/lib.rs @@ -63,7 +63,8 @@ //! //! You can easily opt into different patterns and control many other aspects. //! -//! The build method returns `Result`, where `T` is the struct you started with. +//! The build method returns `Result`, where `T` is the struct you started with +//! and E is a generated builder error type. //! It returns `Err` if you didn't initialize all fields and no default values were //! provided. //! @@ -74,7 +75,7 @@ //! ```rust //! # #[macro_use] extern crate derive_builder; //! # #[derive(Builder)] struct Lorem { ipsum: u32 } -//! # fn try_main() -> Result<(), String> { +//! # fn try_main() -> Result<(), Box> { //! let x: Lorem = LoremBuilder::default().ipsum(42).build()?; //! # Ok(()) //! # } fn main() { try_main().unwrap(); } @@ -87,7 +88,7 @@ //! ```rust //! # #[macro_use] extern crate derive_builder; //! # #[derive(Builder)] struct Lorem { ipsum: u32 } -//! # fn try_main() -> Result<(), String> { +//! # fn try_main() -> Result<(), Box> { //! # let geek = true; //! let mut builder = LoremBuilder::default(); //! if geek { @@ -439,7 +440,7 @@ //! let x = LoremBuilder::default().ipsum(120).build().unwrap_err(); //! //! // .. the build will fail: -//! assert_eq!(&x, "You'll tire yourself out"); +//! assert_eq!(&x.to_string(), "You'll tire yourself out"); //! } //! ``` //! diff --git a/derive_builder/src/options/darling_opts.rs b/derive_builder/src/options/darling_opts.rs index 1616b773..cd5e45c6 100644 --- a/derive_builder/src/options/darling_opts.rs +++ b/derive_builder/src/options/darling_opts.rs @@ -319,6 +319,14 @@ impl Options { .expect("Struct name with Builder suffix should be an ident") } + pub fn builder_error_ident(&self) -> Ident { + if let Some(ref custom) = self.name { + format_ident!("{}Error", custom) + } else { + format_ident!("{}BuilderError", self.ident) + } + } + /// The visibility of the builder struct. /// If a visibility was declared in attributes, that will be used; /// otherwise the struct's own visibility will be used. @@ -393,6 +401,7 @@ impl Options { pattern: self.pattern, target_ty: &self.ident, target_ty_generics: Some(ty_generics), + error_ty: self.builder_error_ident(), initializers: Vec::with_capacity(self.field_count()), doc_comment: None, bindings: self.bindings(), diff --git a/derive_builder/tests/builder_name.rs b/derive_builder/tests/builder_name.rs index 70c0bd69..3b2cd570 100644 --- a/derive_builder/tests/builder_name.rs +++ b/derive_builder/tests/builder_name.rs @@ -13,9 +13,9 @@ struct Lorem { } #[test] -#[should_panic(expected = "`ipsum` must be initialized")] -fn panic_if_uninitialized() { - MyBuilder::default().build().unwrap(); +fn error_if_uninitialized() { + let error = MyBuilder::default().build().unwrap_err(); + assert_eq!(&error.to_string(), "`ipsum` must be initialized"); } #[test] diff --git a/derive_builder/tests/custom_default.rs b/derive_builder/tests/custom_default.rs index 943faa7e..b2dfbf66 100644 --- a/derive_builder/tests/custom_default.rs +++ b/derive_builder/tests/custom_default.rs @@ -24,9 +24,9 @@ mod field_level { } #[test] - #[should_panic(expected = "`required` must be initialized")] - fn panic_if_uninitialized() { - LoremBuilder::default().build().unwrap(); + fn error_if_uninitialized() { + let error = LoremBuilder::default().build().unwrap_err(); + assert_eq!(&error.to_string(), "`required` must be initialized"); } #[test] diff --git a/derive_builder/tests/generic_structs.rs b/derive_builder/tests/generic_structs.rs index 26984992..f5119f55 100644 --- a/derive_builder/tests/generic_structs.rs +++ b/derive_builder/tests/generic_structs.rs @@ -24,9 +24,9 @@ where } #[test] -#[should_panic(expected = "`ipsum` must be initialized")] -fn panic_if_uninitialized() { - GenericBuilder::::default().build().unwrap(); +fn error_if_uninitialized() { + let error = GenericBuilder::::default().build().unwrap_err(); + assert_eq!(&error.to_string(), "`ipsum` must be initialized"); } #[test] diff --git a/derive_builder/tests/lifetime.rs b/derive_builder/tests/lifetime.rs index 264e4ed3..13f2a08e 100644 --- a/derive_builder/tests/lifetime.rs +++ b/derive_builder/tests/lifetime.rs @@ -9,9 +9,9 @@ struct Lorem<'a> { } #[test] -#[should_panic(expected = "`ipsum` must be initialized")] -fn panic_if_uninitialized() { - LoremBuilder::default().build().unwrap(); +fn error_if_uninitialized() { + let error = LoremBuilder::default().build().unwrap_err(); + assert_eq!(&error.to_string(), "`ipsum` must be initialized"); } #[test] diff --git a/derive_builder/tests/setter_visibility.rs b/derive_builder/tests/setter_visibility.rs index 71ae0866..99950934 100644 --- a/derive_builder/tests/setter_visibility.rs +++ b/derive_builder/tests/setter_visibility.rs @@ -53,12 +53,11 @@ pub mod foo { } #[test] -#[should_panic(expected = "`private` must be initialized")] fn public_setters_foreign_module() { - let y = foo::IpsumBuilder::default() + let error = foo::IpsumBuilder::default() .public("Hello") .build() - .unwrap(); + .unwrap_err(); - assert_eq!(y.public, "Hello".to_string()); + assert_eq!(&error.to_string(), "`private` must be initialized"); } diff --git a/derive_builder/tests/validation.rs b/derive_builder/tests/validation.rs index ce721c2f..87776428 100644 --- a/derive_builder/tests/validation.rs +++ b/derive_builder/tests/validation.rs @@ -43,14 +43,19 @@ impl LoremBuilder { #[test] fn out_of_bounds() { assert_eq!( - &LoremBuilder::default().my_effort(120).build().unwrap_err(), + &LoremBuilder::default() + .my_effort(120) + .build() + .unwrap_err() + .to_string(), "Don't wear yourself out" ); assert_eq!( &LoremBuilder::default() .rivals_effort(120) .build() - .unwrap_err(), + .unwrap_err() + .to_string(), "Your rival is cheating" ); } diff --git a/derive_builder_core/src/build_method.rs b/derive_builder_core/src/build_method.rs index 58d46b59..ec0fbff3 100644 --- a/derive_builder_core/src/build_method.rs +++ b/derive_builder_core/src/build_method.rs @@ -27,7 +27,7 @@ use DEFAULT_STRUCT_NAME; /// # let build_method = default_build_method!(); /// # /// # assert_eq!(quote!(#build_method).to_string(), quote!( -/// pub fn build(&self) -> ::std::result::Result { +/// pub fn build(&self) -> ::std::result::Result { /// Ok(Foo { /// foo: self.foo, /// }) @@ -51,6 +51,8 @@ pub struct BuildMethod<'a> { pub target_ty: &'a syn::Ident, /// Type parameters and lifetimes attached to this builder struct. pub target_ty_generics: Option>, + /// Type of error. + pub error_ty: syn::Ident, /// Field initializers for the target type. pub initializers: Vec, /// Doc-comment of the builder struct. @@ -84,14 +86,14 @@ impl<'a> ToTokens for BuildMethod<'a> { }); let validate_fn = self.validate_fn.as_ref().map(|vfn| quote!(#vfn(&self)?;)); let result = self.bindings.result_ty(); - let string = self.bindings.string_ty(); + let error_ty = &self.error_ty; if self.enabled { trace!("Deriving build method `{}`.", self.ident); tokens.append_all(quote!( #doc_comment #vis fn #ident(#self_param) - -> #result<#target_ty #target_ty_generics, #string> + -> #result<#target_ty #target_ty_generics, #error_ty> { #validate_fn #default_struct @@ -137,6 +139,7 @@ macro_rules! default_build_method { pattern: BuilderPattern::Mutable, 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,)], doc_comment: None, bindings: Default::default(), @@ -159,7 +162,7 @@ mod tests { assert_eq!( quote!(#build_method).to_string(), quote!( - pub fn build(&self) -> ::std::result::Result { + pub fn build(&self) -> ::std::result::Result { Ok(Foo { foo: self.foo, }) @@ -178,7 +181,7 @@ mod tests { assert_eq!( quote!(#build_method).to_string(), quote!( - pub fn build(&self) -> ::core::result::Result { + pub fn build(&self) -> ::core::result::Result { Ok(Foo { foo: self.foo, }) @@ -197,7 +200,7 @@ mod tests { assert_eq!( quote!(#build_method).to_string(), quote!( - pub fn build(&self) -> ::std::result::Result { + pub fn build(&self) -> ::std::result::Result { let __default: Foo = { Default::default() }; Ok(Foo { foo: self.foo, @@ -227,7 +230,7 @@ mod tests { assert_eq!( quote!(#build_method).to_string(), quote!( - pub fn finish(&self) -> ::std::result::Result { + pub fn finish(&self) -> ::std::result::Result { Ok(Foo { foo: self.foo, }) @@ -249,7 +252,7 @@ mod tests { assert_eq!( quote!(#build_method).to_string(), quote!( - pub fn build(&self) -> ::std::result::Result { + pub fn build(&self) -> ::std::result::Result { IpsumBuilder::validate(&self)?; Ok(Foo { diff --git a/derive_builder_core/src/builder.rs b/derive_builder_core/src/builder.rs index 18340087..499192a0 100644 --- a/derive_builder_core/src/builder.rs +++ b/derive_builder_core/src/builder.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream; -use quote::{ToTokens, TokenStreamExt}; +use quote::{format_ident, ToTokens, TokenStreamExt}; use syn::punctuated::Punctuated; use syn::{self, Path, TraitBound, TraitBoundModifier, TypeParamBound}; @@ -41,6 +41,38 @@ use Setter; /// pub struct FooBuilder { /// foo: u32, /// } +/// +/// #[doc="Error type for FooBuilder"] +/// #[derive(Debug)] +/// pub enum FooBuilderError { +/// /// Uninitialized field +/// UninitializedField(&'static str), +/// /// Custom validation error +/// ValidationError(String), +/// } +/// +/// impl ::std::convert::From<&'static str> for FooBuilderError { +/// fn from(s: &'static str) -> Self { +/// Self::UninitializedField(s) +/// } +/// } +/// +/// impl ::std::convert::From for FooBuilderError { +/// fn from(s: String) -> Self { +/// Self::ValidationError(s) +/// } +/// } +/// +/// impl ::std::fmt::Display for FooBuilderError { +/// fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +/// match self { +/// Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), +/// Self::ValidationError(ref error) => write!(f, "{}", error), +/// } +/// } +/// } +/// +/// impl ::std::error::Error for FooBuilderError {} /// # )); /// # #[cfg(not(feature = "clippy"))] /// # result.append_all(quote!(#[allow(clippy::all)])); @@ -136,12 +168,47 @@ impl<'a> ToTokens for Builder<'a> { #[cfg(not(feature = "clippy"))] tokens.append_all(quote!(#[allow(clippy::all)])); + let builder_error_ident = format_ident!("{}Error", builder_ident); + let builder_error_doc = format!("Error type for {}", builder_ident); + tokens.append_all(quote!( #[derive(#derived_traits)] #builder_doc_comment #builder_vis struct #builder_ident #struct_generics #where_clause { #(#builder_fields)* } + + #[doc=#builder_error_doc] + #[derive(Debug)] + #builder_vis enum #builder_error_ident { + /// Uninitialized field + UninitializedField(&'static str), + /// Custom validation error + ValidationError(String), + } + + impl ::std::convert::From<&'static str> for #builder_error_ident { + fn from(s: &'static str) -> Self { + Self::UninitializedField(s) + } + } + + impl ::std::convert::From for #builder_error_ident { + fn from(s: String) -> Self { + Self::ValidationError(s) + } + } + + impl ::std::fmt::Display for #builder_error_ident { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), + Self::ValidationError(ref error) => write!(f, "{}", error), + } + } + } + + impl ::std::error::Error for #builder_error_ident {} )); #[cfg(not(feature = "clippy"))] @@ -262,6 +329,40 @@ mod tests { } )); + result.append_all(quote!( + #[doc="Error type for FooBuilder"] + #[derive(Debug)] + pub enum FooBuilderError { + /// Uninitialized field + UninitializedField(&'static str), + /// Custom validation error + ValidationError(String), + } + + impl ::std::convert::From<&'static str> for FooBuilderError { + fn from(s: &'static str) -> Self { + Self::UninitializedField(s) + } + } + + impl ::std::convert::From for FooBuilderError { + fn from(s: String) -> Self { + Self::ValidationError(s) + } + } + + impl ::std::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), + Self::ValidationError(ref error) => write!(f, "{}", error), + } + } + } + + impl ::std::error::Error for FooBuilderError {} + )); + #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); @@ -307,6 +408,40 @@ mod tests { } )); + result.append_all(quote!( + #[doc="Error type for FooBuilder"] + #[derive(Debug)] + pub enum FooBuilderError { + /// Uninitialized field + UninitializedField(&'static str), + /// Custom validation error + ValidationError(String), + } + + impl ::std::convert::From<&'static str> for FooBuilderError { + fn from(s: &'static str) -> Self { + Self::UninitializedField(s) + } + } + + impl ::std::convert::From for FooBuilderError { + fn from(s: String) -> Self { + Self::ValidationError(s) + } + } + + impl ::std::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), + Self::ValidationError(ref error) => write!(f, "{}", error), + } + } + } + + impl ::std::error::Error for FooBuilderError {} + )); + #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); @@ -352,6 +487,40 @@ mod tests { } )); + result.append_all(quote!( + #[doc="Error type for FooBuilder"] + #[derive(Debug)] + pub enum FooBuilderError { + /// Uninitialized field + UninitializedField(&'static str), + /// Custom validation error + ValidationError(String), + } + + impl ::std::convert::From<&'static str> for FooBuilderError { + fn from(s: &'static str) -> Self { + Self::UninitializedField(s) + } + } + + impl ::std::convert::From for FooBuilderError { + fn from(s: String) -> Self { + Self::ValidationError(s) + } + } + + impl ::std::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), + Self::ValidationError(ref error) => write!(f, "{}", error), + } + } + } + + impl ::std::error::Error for FooBuilderError {} + )); + #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); @@ -401,6 +570,40 @@ mod tests { } )); + result.append_all(quote!( + #[doc="Error type for FooBuilder"] + #[derive(Debug)] + pub enum FooBuilderError { + /// Uninitialized field + UninitializedField(&'static str), + /// Custom validation error + ValidationError(String), + } + + impl ::std::convert::From<&'static str> for FooBuilderError { + fn from(s: &'static str) -> Self { + Self::UninitializedField(s) + } + } + + impl ::std::convert::From for FooBuilderError { + fn from(s: String) -> Self { + Self::ValidationError(s) + } + } + + impl ::std::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), + Self::ValidationError(ref error) => write!(f, "{}", error), + } + } + } + + impl ::std::error::Error for FooBuilderError {} + )); + #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); @@ -447,6 +650,40 @@ mod tests { } )); + result.append_all(quote!( + #[doc="Error type for FooBuilder"] + #[derive(Debug)] + pub enum FooBuilderError { + /// Uninitialized field + UninitializedField(&'static str), + /// Custom validation error + ValidationError(String), + } + + impl ::std::convert::From<&'static str> for FooBuilderError { + fn from(s: &'static str) -> Self { + Self::UninitializedField(s) + } + } + + impl ::std::convert::From for FooBuilderError { + fn from(s: String) -> Self { + Self::ValidationError(s) + } + } + + impl ::std::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), + Self::ValidationError(ref error) => write!(f, "{}", error), + } + } + } + + impl ::std::error::Error for FooBuilderError {} + )); + #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); diff --git a/derive_builder_core/src/initializer.rs b/derive_builder_core/src/initializer.rs index 329c89ee..9026c523 100644 --- a/derive_builder_core/src/initializer.rs +++ b/derive_builder_core/src/initializer.rs @@ -101,12 +101,9 @@ impl<'a> Initializer<'a> { if self.use_default_struct { MatchNone::UseDefaultStructField(self.field_ident) } else if self.bindings.no_std { - MatchNone::ReturnErrorNoStd(format!( - "`{}` must be initialized", - self.field_ident - )) + MatchNone::ReturnErrorNoStd(self.field_ident.to_string()) } else { - MatchNone::ReturnError(format!("`{}` must be initialized", self.field_ident)) + MatchNone::ReturnError(self.field_ident.to_string()) } } } @@ -155,11 +152,11 @@ impl<'a> ToTokens for MatchNone<'a> { )) } MatchNone::ReturnError(ref err) => tokens.append_all(quote!( - None => return ::std::result::Result::Err(::std::string::String::from(#err)) + None => return ::std::result::Result::Err(::std::convert::Into::into(#err)) )), MatchNone::ReturnErrorNoStd(ref err) => tokens.append_all(quote!( None => return ::core::result::Result::Err( - ::alloc::string::String::from(#err)) + ::std::convert::Into::into(#err)) )), } } @@ -220,8 +217,8 @@ mod tests { quote!( foo: match self.foo { Some(ref value) => ::std::clone::Clone::clone(value), - None => return ::std::result::Result::Err(::std::string::String::from( - "`foo` must be initialized" + None => return ::std::result::Result::Err(::std::convert::Into::into( + "foo" )), }, ) @@ -239,8 +236,8 @@ mod tests { quote!( foo: match self.foo { Some(ref value) => ::std::clone::Clone::clone(value), - None => return ::std::result::Result::Err(::std::string::String::from( - "`foo` must be initialized" + None => return ::std::result::Result::Err(::std::convert::Into::into( + "foo" )), }, ) @@ -258,8 +255,8 @@ mod tests { quote!( foo: match self.foo { Some(value) => value, - None => return ::std::result::Result::Err(::std::string::String::from( - "`foo` must be initialized" + None => return ::std::result::Result::Err(::std::convert::Into::into( + "foo" )), }, ) @@ -322,8 +319,8 @@ mod tests { quote!( foo: match self.foo { Some(ref value) => ::core::clone::Clone::clone(value), - None => return ::core::result::Result::Err(::alloc::string::String::from( - "`foo` must be initialized" + None => return ::core::result::Result::Err(::std::convert::Into::into( + "foo" )), }, ) From 01381c3a39e408dedd61f7a79dd26d166b1be9ff Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Tue, 28 Jul 2020 19:54:08 +0200 Subject: [PATCH 2/5] fix nightly tests --- derive_builder/tests/try_setter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/derive_builder/tests/try_setter.rs b/derive_builder/tests/try_setter.rs index 7b47babf..28f6a01c 100644 --- a/derive_builder/tests/try_setter.rs +++ b/derive_builder/tests/try_setter.rs @@ -36,14 +36,14 @@ struct Ipsum { pub source: MyAddr, } -fn exact_helper() -> Result { +fn exact_helper() -> Result { LoremBuilder::default() .source(IpAddr::from_str("1.2.3.4").unwrap()) .dest(IpAddr::from_str("0.0.0.0").unwrap()) .build() } -fn try_helper() -> Result { +fn try_helper() -> Result { LoremBuilder::default() .try_source("1.2.3.4") .map_err(|e| e.to_string())? From d02d2ecc33c17fc7109b8a4a9faf4a8d22664376 Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Tue, 28 Jul 2020 20:31:24 +0200 Subject: [PATCH 3/5] Support no_std --- derive_builder/tests/run-pass/custom_types.rs | 26 +++++-- derive_builder_core/src/builder.rs | 77 ++++++++++--------- 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/derive_builder/tests/run-pass/custom_types.rs b/derive_builder/tests/run-pass/custom_types.rs index 8f8daaa4..2b4f999e 100644 --- a/derive_builder/tests/run-pass/custom_types.rs +++ b/derive_builder/tests/run-pass/custom_types.rs @@ -3,12 +3,26 @@ #[macro_use] extern crate derive_builder; -type Clone = (); -type Into = (); -type Option = (); -type Result = (); -type Some = (); -type String = (); +struct Unit; + +type Clone = Unit; +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 { + write!(f, "()") + } +} + +impl core::fmt::Display for Unit { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "()") + } +} #[derive(Builder)] struct IgnoreEmptyStruct {} diff --git a/derive_builder_core/src/builder.rs b/derive_builder_core/src/builder.rs index 499192a0..046a9ecd 100644 --- a/derive_builder_core/src/builder.rs +++ b/derive_builder_core/src/builder.rs @@ -51,20 +51,20 @@ use Setter; /// ValidationError(String), /// } /// -/// impl ::std::convert::From<&'static str> for FooBuilderError { +/// impl core::convert::From<&'static str> for FooBuilderError { /// fn from(s: &'static str) -> Self { /// Self::UninitializedField(s) /// } /// } /// -/// impl ::std::convert::From for FooBuilderError { +/// impl core::convert::From for FooBuilderError { /// fn from(s: String) -> Self { /// Self::ValidationError(s) /// } /// } /// -/// impl ::std::fmt::Display for FooBuilderError { -/// fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { +/// impl core::fmt::Display for FooBuilderError { +/// fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { /// match self { /// Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), /// Self::ValidationError(ref error) => write!(f, "{}", error), @@ -72,7 +72,8 @@ use Setter; /// } /// } /// -/// impl ::std::error::Error for FooBuilderError {} +/// #[cfg(not(no_std))] +/// impl std::error::Error for FooBuilderError {} /// # )); /// # #[cfg(not(feature = "clippy"))] /// # result.append_all(quote!(#[allow(clippy::all)])); @@ -187,20 +188,20 @@ impl<'a> ToTokens for Builder<'a> { ValidationError(String), } - impl ::std::convert::From<&'static str> for #builder_error_ident { + impl core::convert::From<&'static str> for #builder_error_ident { fn from(s: &'static str) -> Self { Self::UninitializedField(s) } } - impl ::std::convert::From for #builder_error_ident { + impl core::convert::From for #builder_error_ident { fn from(s: String) -> Self { Self::ValidationError(s) } } - impl ::std::fmt::Display for #builder_error_ident { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl core::fmt::Display for #builder_error_ident { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), Self::ValidationError(ref error) => write!(f, "{}", error), @@ -208,7 +209,8 @@ impl<'a> ToTokens for Builder<'a> { } } - impl ::std::error::Error for #builder_error_ident {} + #[cfg(not(no_std))] + impl std::error::Error for #builder_error_ident {} )); #[cfg(not(feature = "clippy"))] @@ -339,20 +341,20 @@ mod tests { ValidationError(String), } - impl ::std::convert::From<&'static str> for FooBuilderError { + impl core::convert::From<&'static str> for FooBuilderError { fn from(s: &'static str) -> Self { Self::UninitializedField(s) } } - impl ::std::convert::From for FooBuilderError { + impl core::convert::From for FooBuilderError { fn from(s: String) -> Self { Self::ValidationError(s) } } - impl ::std::fmt::Display for FooBuilderError { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl core::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), Self::ValidationError(ref error) => write!(f, "{}", error), @@ -360,7 +362,8 @@ mod tests { } } - impl ::std::error::Error for FooBuilderError {} + #[cfg(not(no_std))] + impl std::error::Error for FooBuilderError {} )); #[cfg(not(feature = "clippy"))] @@ -418,20 +421,20 @@ mod tests { ValidationError(String), } - impl ::std::convert::From<&'static str> for FooBuilderError { + impl core::convert::From<&'static str> for FooBuilderError { fn from(s: &'static str) -> Self { Self::UninitializedField(s) } } - impl ::std::convert::From for FooBuilderError { + impl core::convert::From for FooBuilderError { fn from(s: String) -> Self { Self::ValidationError(s) } } - impl ::std::fmt::Display for FooBuilderError { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl core::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), Self::ValidationError(ref error) => write!(f, "{}", error), @@ -439,7 +442,8 @@ mod tests { } } - impl ::std::error::Error for FooBuilderError {} + #[cfg(not(no_std))] + impl std::error::Error for FooBuilderError {} )); #[cfg(not(feature = "clippy"))] @@ -497,20 +501,20 @@ mod tests { ValidationError(String), } - impl ::std::convert::From<&'static str> for FooBuilderError { + impl core::convert::From<&'static str> for FooBuilderError { fn from(s: &'static str) -> Self { Self::UninitializedField(s) } } - impl ::std::convert::From for FooBuilderError { + impl core::convert::From for FooBuilderError { fn from(s: String) -> Self { Self::ValidationError(s) } } - impl ::std::fmt::Display for FooBuilderError { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl core::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), Self::ValidationError(ref error) => write!(f, "{}", error), @@ -518,7 +522,8 @@ mod tests { } } - impl ::std::error::Error for FooBuilderError {} + #[cfg(not(no_std))] + impl std::error::Error for FooBuilderError {} )); #[cfg(not(feature = "clippy"))] @@ -580,20 +585,20 @@ mod tests { ValidationError(String), } - impl ::std::convert::From<&'static str> for FooBuilderError { + impl core::convert::From<&'static str> for FooBuilderError { fn from(s: &'static str) -> Self { Self::UninitializedField(s) } } - impl ::std::convert::From for FooBuilderError { + impl core::convert::From for FooBuilderError { fn from(s: String) -> Self { Self::ValidationError(s) } } - impl ::std::fmt::Display for FooBuilderError { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl core::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), Self::ValidationError(ref error) => write!(f, "{}", error), @@ -601,7 +606,8 @@ mod tests { } } - impl ::std::error::Error for FooBuilderError {} + #[cfg(not(no_std))] + impl std::error::Error for FooBuilderError {} )); #[cfg(not(feature = "clippy"))] @@ -660,20 +666,20 @@ mod tests { ValidationError(String), } - impl ::std::convert::From<&'static str> for FooBuilderError { + impl core::convert::From<&'static str> for FooBuilderError { fn from(s: &'static str) -> Self { Self::UninitializedField(s) } } - impl ::std::convert::From for FooBuilderError { + impl core::convert::From for FooBuilderError { fn from(s: String) -> Self { Self::ValidationError(s) } } - impl ::std::fmt::Display for FooBuilderError { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl core::fmt::Display for FooBuilderError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), Self::ValidationError(ref error) => write!(f, "{}", error), @@ -681,7 +687,8 @@ mod tests { } } - impl ::std::error::Error for FooBuilderError {} + #[cfg(not(no_std))] + impl std::error::Error for FooBuilderError {} )); #[cfg(not(feature = "clippy"))] From 124346ac55d5f44de6b13b7c6b9a486ea8689f37 Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Tue, 28 Jul 2020 20:33:48 +0200 Subject: [PATCH 4/5] non exhaustive error enum --- derive_builder_core/src/builder.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/derive_builder_core/src/builder.rs b/derive_builder_core/src/builder.rs index 046a9ecd..83b7b4fe 100644 --- a/derive_builder_core/src/builder.rs +++ b/derive_builder_core/src/builder.rs @@ -44,6 +44,7 @@ use Setter; /// /// #[doc="Error type for FooBuilder"] /// #[derive(Debug)] +/// #[non_exhaustive] /// pub enum FooBuilderError { /// /// Uninitialized field /// UninitializedField(&'static str), @@ -181,6 +182,7 @@ impl<'a> ToTokens for Builder<'a> { #[doc=#builder_error_doc] #[derive(Debug)] + #[non_exhaustive] #builder_vis enum #builder_error_ident { /// Uninitialized field UninitializedField(&'static str), @@ -334,6 +336,7 @@ mod tests { result.append_all(quote!( #[doc="Error type for FooBuilder"] #[derive(Debug)] + #[non_exhaustive] pub enum FooBuilderError { /// Uninitialized field UninitializedField(&'static str), @@ -414,6 +417,7 @@ mod tests { result.append_all(quote!( #[doc="Error type for FooBuilder"] #[derive(Debug)] + #[non_exhaustive] pub enum FooBuilderError { /// Uninitialized field UninitializedField(&'static str), @@ -494,6 +498,7 @@ mod tests { result.append_all(quote!( #[doc="Error type for FooBuilder"] #[derive(Debug)] + #[non_exhaustive] pub enum FooBuilderError { /// Uninitialized field UninitializedField(&'static str), @@ -578,6 +583,7 @@ mod tests { result.append_all(quote!( #[doc="Error type for FooBuilder"] #[derive(Debug)] + #[non_exhaustive] pub enum FooBuilderError { /// Uninitialized field UninitializedField(&'static str), @@ -659,6 +665,7 @@ mod tests { result.append_all(quote!( #[doc="Error type for FooBuilder"] #[derive(Debug)] + #[non_exhaustive] pub enum FooBuilderError { /// Uninitialized field UninitializedField(&'static str), From 18e160642d20076503926a6043dc9eb20a36e6ad Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Tue, 28 Jul 2020 21:57:15 +0200 Subject: [PATCH 5/5] fix logging tests --- derive_builder/build/skeptic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive_builder/build/skeptic.rs b/derive_builder/build/skeptic.rs index 3119eb31..4c0ebe4b 100644 --- a/derive_builder/build/skeptic.rs +++ b/derive_builder/build/skeptic.rs @@ -62,7 +62,7 @@ use std::io::{Write, Read}; const DOC_TPL_DIR: &'static str = "src/doc_tpl/"; const DOC_TPL_OUT_DIR: &'static str = "doc_tpl/"; -fn generate_doc_tpl_tests() -> Result, Box> { +fn generate_doc_tpl_tests() -> Result, Box> { trace!("Generating doc template tests"); let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); let mut tpl_dir = root_dir;