diff --git a/derive_builder/CHANGELOG.md b/derive_builder/CHANGELOG.md index 56ead485..4a95114f 100644 --- a/derive_builder/CHANGELOG.md +++ b/derive_builder/CHANGELOG.md @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - use full path for result #39 - support `#[deny(missing_docs)]` #37 +- support `#![no_std]` via `#[builder(no_std)]` #41 ## [0.3.0] - 2017-02-05 diff --git a/derive_builder/README.md b/derive_builder/README.md index 37d0efd3..6d38ad51 100644 --- a/derive_builder/README.md +++ b/derive_builder/README.md @@ -92,6 +92,7 @@ with [cargo-edit](https://github.com/killercup/cargo-edit): * **Setter visibility**: You can opt into private setter by preceding your struct with `#[builder(private)]`. * **Setter type conversions**: With ``#[builder(setter(into))]`, setter methods will be generic over the input types – you can then supply every argument that implements the [`Into`][into] trait for the field type. * **Generic structs**: Are also supported, but you **must not** use a type parameter named `VALUE`, if you also activate setter type conversions. +* **no_std support**: Just add `#[builder(no_std)]` to your struct and add `extern crate collections` to your crate. The latter requires the _nightly_ toolchain. * **Logging**: If anything works unexpectedly you can enable detailed logs in two steps. First, add `features = ["logging"]` to the `derive_builder` dependency in `Cargo.toml`. Second, set this environment variable before calling cargo `RUST_LOG=derive_builder=trace`. For more information and examples please take a look at our [documentation][doc]. diff --git a/derive_builder/src/lib.rs b/derive_builder/src/lib.rs index 54300975..854c5e3e 100644 --- a/derive_builder/src/lib.rs +++ b/derive_builder/src/lib.rs @@ -346,6 +346,13 @@ //! # fn main() {} //! ``` //! +//! # **`#![no_std]`** Support (on Nightly) +//! +//! You can activate support for `#![no_std]` by adding `#[builder(no_std)]` to your struct +//! and `#![feature(collections)] extern crate collections` to your crate. +//! +//! The latter requires the _nightly_ toolchain. +//! //! # Troubleshooting //! //! ## Gotchas diff --git a/derive_builder/src/options/field_mode.rs b/derive_builder/src/options/field_mode.rs index 367cd4c9..95facaa0 100644 --- a/derive_builder/src/options/field_mode.rs +++ b/derive_builder/src/options/field_mode.rs @@ -98,6 +98,11 @@ impl OptionsBuilderMode for FieldMode { fn where_diagnostics(&self) -> String { format!("on field `{}`", self.field_ident.as_ref()) } + + fn no_std(&mut self, _x: bool) { + panic!("Support for `#![no_std]` can only be set on the stuct level (but found {}).", + self.where_diagnostics()) + } } impl From> for FieldOptions { diff --git a/derive_builder/src/options/macros.rs b/derive_builder/src/options/macros.rs new file mode 100644 index 00000000..5b9ae5ce --- /dev/null +++ b/derive_builder/src/options/macros.rs @@ -0,0 +1,48 @@ +/// Helper macro to generate a setter for some `Option`. +/// +/// The setter will panic if the Option is already initialized. +/// +/// # Examples +/// +/// ```rust, ignore +/// OptionsBuilder { +/// foo: Option, +/// } +/// +/// impl OptionsBuilder { +/// impl_setter!{ +/// ident: foo, +/// desc: "foo", +/// map: |x: u32| { x }, +/// } +/// } +/// ``` +macro_rules! impl_setter { + ( + ident: $ident:ident, + desc: $desc:expr, + map: |$x:ident: $ty:ty| {$( $map:tt )*}, + ) => { + impl_setter!{ + ident: $ident for $ident, + desc: $desc, + map: |$x: $ty| {$( $map )*}, + } + }; + ( + ident: $setter:ident for $field:ident, + desc: $desc:expr, + map: |$x:ident: $ty:ty| {$( $map:tt )*}, + ) => { + fn $setter(&mut self, $x: $ty) { + if let Some(ref current) = self.$field { + panic!("Failed to set {} to `{:?}` (already defined as `{:?}`) {}.", + $desc, + $x, + current, + self.where_diagnostics()); + } + self.$field = Some({$( $map )*}); + } + } +} diff --git a/derive_builder/src/options/mod.rs b/derive_builder/src/options/mod.rs index 59ad9fea..bd985b92 100644 --- a/derive_builder/src/options/mod.rs +++ b/derive_builder/src/options/mod.rs @@ -1,6 +1,8 @@ use syn; use derive_builder_core::BuilderPattern; +#[macro_use] +mod macros; mod field_mode; mod field_options; mod struct_mode; @@ -46,6 +48,7 @@ pub trait OptionsBuilderMode: ::std::fmt::Debug { fn push_deprecation_note>(&mut self, x: T) -> &mut Self; /// Provide a diagnostic _where_-clause for panics. fn where_diagnostics(&self) -> String; + fn no_std(&mut self, x: bool); } impl From for OptionsBuilder { @@ -63,37 +66,6 @@ impl From for OptionsBuilder { } } -macro_rules! impl_setter { - ( - ident: $ident:ident, - desc: $desc:expr, - map: |$x:ident: $ty:ty| {$( $map:tt )*}, - ) => { - impl_setter!{ - ident: $ident for $ident, - desc: $desc, - map: |$x: $ty| {$( $map )*}, - } - }; - ( - ident: $setter:ident for $field:ident, - desc: $desc:expr, - map: |$x:ident: $ty:ty| {$( $map:tt )*}, - ) => { - fn $setter(&mut self, $x: $ty) -> &mut Self { - if let Some(ref current) = self.$field { - panic!("Failed to set {} to `{:?}` (already defined as `{:?}`) {}.", - $desc, - $x, - current, - self.where_diagnostics()); - } - self.$field = Some({$( $map )*}); - self - } - } -} - impl OptionsBuilder where Mode: OptionsBuilderMode { @@ -215,10 +187,13 @@ impl OptionsBuilder where "default" => { self.default_expression(DefaultExpression::Trait) }, + "no_std" => { + self.mode.no_std(true) + }, _ => { panic!("Unknown option `{}` {}", ident.as_ref(), self.where_diagnostics()) } - }; + } } /// e.g `setter_prefix="with"` in `#[builder(setter_prefix="with")]` diff --git a/derive_builder/src/options/struct_mode.rs b/derive_builder/src/options/struct_mode.rs index 6b68bf14..e86da60e 100644 --- a/derive_builder/src/options/struct_mode.rs +++ b/derive_builder/src/options/struct_mode.rs @@ -11,6 +11,7 @@ pub struct StructMode { builder_vis: Option, deprecation_notes: DeprecationNotes, struct_size_hint: usize, + no_std: Option, } impl OptionsBuilder { @@ -26,6 +27,7 @@ impl OptionsBuilder { builder_vis: None, deprecation_notes: Default::default(), struct_size_hint: 0, + no_std: None, }); builder.parse_attributes(&ast.attrs); @@ -34,11 +36,19 @@ impl OptionsBuilder { } } +impl StructMode { + impl_setter!{ + ident: builder_name, + desc: "builder name", + map: |x: String| { x }, + } +} + impl OptionsBuilderMode for StructMode { fn parse_builder_name(&mut self, name: &syn::Lit) { trace!("Parsing builder name `{:?}`", name); let value = parse_lit_as_string(name).unwrap(); - self.builder_name = Some(value.clone()); + self.builder_name(value.clone()); } fn push_deprecation_note>(&mut self, x: T) -> &mut Self { @@ -50,6 +60,12 @@ impl OptionsBuilderMode for StructMode { fn where_diagnostics(&self) -> String { format!("on struct `{}`", self.build_target_name) } + + impl_setter!{ + ident: no_std, + desc: "no_std support", + map: |x: bool| { x }, + } } impl From> for (StructOptions, OptionsBuilder) { @@ -77,6 +93,7 @@ impl From> for (StructOptions, OptionsBuilder { pub initializers: Vec, /// Doc-comment of the builder struct. pub doc_comment: Option, + /// Whether the generated code should comply with `#![no_std]`. + pub no_std: bool, } impl<'a> ToTokens for BuildMethod<'a> { @@ -63,12 +65,21 @@ impl<'a> ToTokens for BuildMethod<'a> { BuilderPattern::Immutable => quote!(&self), }; let doc_comment = &self.doc_comment; + + let (result, string) = if self.no_std {( + quote!(::core::result::Result), + quote!(::collections::string::String), + )} else {( + quote!(::std::result::Result), + quote!(::std::string::String), + )}; + if self.enabled { trace!("Deriving build method `{}`.", self.ident.as_ref()); tokens.append(quote!( #doc_comment #vis fn #ident(#self_param) - -> ::std::result::Result<#target_ty #target_ty_generics, ::std::string::String> + -> #result<#target_ty #target_ty_generics, #string> { Ok(#target_ty { #(#initializers)* @@ -112,6 +123,7 @@ macro_rules! default_build_method { target_ty_generics: None, initializers: vec![quote!(foo: self.foo,)], doc_comment: None, + no_std: false, } } } @@ -122,7 +134,7 @@ mod tests { use super::*; #[test] - fn test() { + fn std() { let build_method = default_build_method!(); assert_eq!(quote!(#build_method), quote!( @@ -133,4 +145,18 @@ mod tests { } )); } + + #[test] + fn no_std() { + let mut build_method = default_build_method!(); + build_method.no_std = true; + + assert_eq!(quote!(#build_method), quote!( + pub fn build(&self) -> ::core::result::Result { + Ok(Foo { + foo: self.foo, + }) + } + )); + } }