Skip to content

Commit

Permalink
officially support #![no_std] #41
Browse files Browse the repository at this point in the history
  • Loading branch information
colin-kiegel committed Mar 25, 2017
1 parent 87b955f commit b65cd24
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 35 deletions.
1 change: 1 addition & 0 deletions derive_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions derive_builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand Down
7 changes: 7 additions & 0 deletions derive_builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions derive_builder/src/options/field_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<OptionsBuilder<FieldMode>> for FieldOptions {
Expand Down
48 changes: 48 additions & 0 deletions derive_builder/src/options/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/// Helper macro to generate a setter for some `Option<T>`.
///
/// The setter will panic if the Option is already initialized.
///
/// # Examples
///
/// ```rust, ignore
/// OptionsBuilder {
/// foo: Option<u32>,
/// }
///
/// 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 )*});
}
}
}
39 changes: 7 additions & 32 deletions derive_builder/src/options/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use syn;
use derive_builder_core::BuilderPattern;

#[macro_use]
mod macros;
mod field_mode;
mod field_options;
mod struct_mode;
Expand Down Expand Up @@ -46,6 +48,7 @@ pub trait OptionsBuilderMode: ::std::fmt::Debug {
fn push_deprecation_note<T: Into<String>>(&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<Mode> From<Mode> for OptionsBuilder<Mode> {
Expand All @@ -63,37 +66,6 @@ impl<Mode> From<Mode> for OptionsBuilder<Mode> {
}
}

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<Mode> OptionsBuilder<Mode> where
Mode: OptionsBuilderMode
{
Expand Down Expand Up @@ -215,10 +187,13 @@ impl<Mode> OptionsBuilder<Mode> 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")]`
Expand Down
19 changes: 18 additions & 1 deletion derive_builder/src/options/struct_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct StructMode {
builder_vis: Option<syn::Visibility>,
deprecation_notes: DeprecationNotes,
struct_size_hint: usize,
no_std: Option<bool>,
}

impl OptionsBuilder<StructMode> {
Expand All @@ -26,6 +27,7 @@ impl OptionsBuilder<StructMode> {
builder_vis: None,
deprecation_notes: Default::default(),
struct_size_hint: 0,
no_std: None,
});

builder.parse_attributes(&ast.attrs);
Expand All @@ -34,11 +36,19 @@ impl OptionsBuilder<StructMode> {
}
}

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<T: Into<String>>(&mut self, x: T) -> &mut Self {
Expand All @@ -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<OptionsBuilder<StructMode>> for (StructOptions, OptionsBuilder<FieldMode>) {
Expand Down Expand Up @@ -77,6 +93,7 @@ impl From<OptionsBuilder<StructMode>> for (StructOptions, OptionsBuilder<FieldMo
deprecation_notes: m.deprecation_notes,
generics: m.build_target_generics,
struct_size_hint: m.struct_size_hint,
no_std: m.no_std.unwrap_or(false),
};

(struct_options, field_defaults)
Expand Down
3 changes: 3 additions & 0 deletions derive_builder/src/options/struct_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub struct StructOptions {
pub deprecation_notes: DeprecationNotes,
/// Number of fields on the target struct.
pub struct_size_hint: usize,
/// Whether the generated code should comply with `#![no_std]`.
pub no_std: bool,
}

impl StructOptions {
Expand Down Expand Up @@ -49,6 +51,7 @@ impl StructOptions {
target_ty_generics: Some(ty_generics),
initializers: Vec::with_capacity(self.struct_size_hint),
doc_comment: None,
no_std: self.no_std,
}
}
}
30 changes: 28 additions & 2 deletions derive_builder_core/src/build_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub struct BuildMethod<'a> {
pub initializers: Vec<Tokens>,
/// Doc-comment of the builder struct.
pub doc_comment: Option<syn::Attribute>,
/// Whether the generated code should comply with `#![no_std]`.
pub no_std: bool,
}

impl<'a> ToTokens for BuildMethod<'a> {
Expand All @@ -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)*
Expand Down Expand Up @@ -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,
}
}
}
Expand All @@ -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!(
Expand All @@ -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<Foo, ::collections::string::String> {
Ok(Foo {
foo: self.foo,
})
}
));
}
}

0 comments on commit b65cd24

Please sign in to comment.