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

Reexport macro with items #1

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ matrix:
- rust: 1.15.0
env: JOB=build CARGO_FEATURES="skeptic_tests struct_default private_fields"
- rust: nightly
env: JOB=build CARGO_FEATURES="skeptic_tests nightlytests logging"
env: JOB=build CARGO_FEATURES="skeptic_tests nightlytests"
- rust: nightly
env: JOB=style_check
allow_failures:
Expand Down Expand Up @@ -53,17 +53,21 @@ script: |
# `derive_builder` crate will implicitly build/doc the
# `derive_builder_core` crate too.
commands=(
"cd derive_builder && travis-cargo build -- --features \"$CARGO_FEATURES\""
"cd derive_builder && travis-cargo test -- --all --no-fail-fast --features \"$CARGO_FEATURES\""
"cd testsuite && travis-cargo build -- --features \"$CARGO_FEATURES\""
"cd testsuite && travis-cargo test -- --all --no-fail-fast --features \"$CARGO_FEATURES\""
"cd derive_builder && travis-cargo doc"
)
;;
style_check)
commands=(
"cd derive_builder_core && cargo clippy -- -Dclippy"
"cd derive_builder && cargo clippy -- -Dclippy"
"cd derive_builder_core && cargo fmt -- --write-mode diff"
"cd derive_builder && cargo fmt -- --write-mode diff"
"cd derive_builder_core && cargo clippy -- -Dclippy"
"cd derive_builder_macro && cargo clippy -- -Dclippy"
"cd derive_builder && cargo clippy -- -Dclippy"
"cd testsuite && cargo clippy -- -Dclippy"
"cd derive_builder_core && cargo fmt -- --write-mode diff"
"cd derive_builder_macro && cargo fmt -- --write-mode diff"
"cd derive_builder && cargo fmt -- --write-mode diff"
"cd testsuite && cargo fmt -- --write-mode diff"
)
;;
*)
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[workspace]
members = ["derive_builder", "derive_builder_core"]
members = ["derive_builder", "derive_builder_core", "derive_builder_macro",
"testsuite"]
30 changes: 7 additions & 23 deletions derive_builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ authors = ["Colin Kiegel <[email protected]>",
"Pascal Hertleif <[email protected]>",
"Jan-Erik Rediger <[email protected]>",
"Ted Driggs <[email protected]>"]

description = "Rust macro to automatically implement the builder pattern for arbitrary structs."
repository = "https://github.com/colin-kiegel/rust-derive-builder"
documentation = "https://docs.rs/derive_builder"
Expand All @@ -14,34 +13,19 @@ license = "MIT/Apache-2.0"
categories = ["development-tools", "rust-patterns"]
keywords = ["derive", "macro", "builder", "setter", "struct"]
readme = "README.md"
build = "build/mod.rs"

[badges]
travis-ci = { repository = "colin-kiegel/rust-derive-builder" }

[lib]
proc-macro = true
path = "src/lib.rs"

[features]
logging = [ "log", "env_logger", "derive_builder_core/logging" ]
struct_default = []
private_fields = []
skeptic_tests = ["skeptic"]
nightlytests = ["compiletest_rs"]
default = ["derive_builder_macro"]
logging = ["derive_builder_macro/logging"]
struct_default = ["derive_builder_macro/struct_default"]
private_fields = ["derive_builder_macro/private_fields"]
no_std = []

[dependencies]
syn = "0.11"
quote = "0.3"
log = { version = "0.3", optional = true }
env_logger = { version = "0.4", optional = true }
derive_builder_core = { version = "0.1", path = "../derive_builder_core" }
skeptic = { version = "0.9", optional = true }
compiletest_rs = { version = "0.2", optional = true }

[build-dependencies]
skeptic = { version = "0.9", optional = true }
log = { version = "0.3", optional = true }
env_logger = { version = "0.4", optional = true }

[dev-dependencies]
pretty_assertions = "0.1"
derive_builder_macro = { path = "../derive_builder_macro/", optional = true }
80 changes: 12 additions & 68 deletions derive_builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,77 +519,21 @@
//! [builder pattern]: https://aturon.github.io/ownership/builders.html
//! [`derive_builder_core`]: https://crates.io/crates/derive_builder_core

#![crate_type = "proc-macro"]
#![deny(warnings)]
extern crate core;

extern crate proc_macro;
extern crate syn;
#[allow(unused_imports)]
#[macro_use]
extern crate quote;
#[cfg(feature = "logging")]
#[macro_use]
extern crate log;
#[cfg(feature = "logging")]
extern crate env_logger;
extern crate derive_builder_core;

#[cfg(not(feature = "logging"))]
#[macro_use]
mod log_disabled;
mod options;

use proc_macro::TokenStream;
#[cfg(feature = "logging")]
use std::sync::{Once, ONCE_INIT};
use options::{struct_options_from, field_options_from};

#[cfg(feature = "logging")]
static INIT_LOGGER: Once = ONCE_INIT;
extern crate derive_builder_macro;

#[doc(hidden)]
#[proc_macro_derive(Builder, attributes(builder))]
pub fn derive(input: TokenStream) -> TokenStream {
#[cfg(feature = "logging")]
INIT_LOGGER.call_once(|| {
env_logger::init().unwrap();
});

let input = input.to_string();

let ast = syn::parse_macro_input(&input).expect("Couldn't parse item");

let result = builder_for_struct(ast).to_string();
debug!("generated tokens: {}", result);

result.parse().expect(&format!("Couldn't parse `{}` to tokens", result))
}

fn builder_for_struct(ast: syn::MacroInput) -> quote::Tokens {
debug!("Deriving Builder for `{}`.", ast.ident);
let (opts, field_defaults) = struct_options_from(&ast);

let fields = match ast.body {
syn::Body::Struct(syn::VariantData::Struct(fields)) => fields,
_ => panic!("`#[derive(Builder)]` can only be used with braced structs"),
};

let mut builder = opts.as_builder();
let mut build_fn = opts.as_build_method();

builder.doc_comment(format!(include_str!("doc_tpl/builder_struct.md"),
struct_name = ast.ident.as_ref()));
build_fn.doc_comment(format!(include_str!("doc_tpl/builder_method.md"),
struct_name = ast.ident.as_ref()));
pub use derive_builder_macro::*;

for f in fields {
let f_opts = field_options_from(f, &field_defaults);

builder.push_field(f_opts.as_builder_field());
builder.push_setter_fn(f_opts.as_setter());
build_fn.push_initializer(f_opts.as_initializer());
}

builder.push_build_fn(build_fn);

quote!(#builder)
#[doc(hidden)]
pub mod export {
pub use ::core::clone::Clone;
pub use ::core::convert::Into;
pub use ::core::default::Default;
pub use ::core::marker::PhantomData;
pub use ::core::option::Option::{self, Some, None};
pub use ::core::result::Result::{self, Ok, Err};
}
125 changes: 26 additions & 99 deletions derive_builder_core/src/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,125 +1,52 @@
use RawTokens;

/// Bindings to be used by the generated code.
#[derive(Debug, Clone, Copy, Default)]
pub struct Bindings {
/// Whether the generated code should comply with `#![no_std]`.
pub no_std: bool,
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Bindings {
/// Use the standard library.
Std,
/// Don't use the standard library.
NoStd,
}

impl Default for Bindings {
fn default() -> Self {
Bindings::Std
}
}

impl Bindings {
/// String type.
pub fn string_ty(&self) -> RawTokens<&'static str> {
RawTokens(if self.no_std {
":: collections :: string :: String"
} else {
":: std :: string :: String"
})
}

/// Result type.
pub fn result_ty(&self) -> RawTokens<&'static str> {
RawTokens(if self.no_std {
":: core :: result :: Result"
} else {
":: std :: result :: Result"
})
}

/// Option type.
pub fn option_ty(&self) -> RawTokens<&'static str> {
RawTokens(if self.no_std {
":: core :: option :: Option"
} else {
":: std :: option :: Option"
})
RawTokens(match *self {
Bindings::Std => ":: std :: string :: String",
Bindings::NoStd => ":: collections :: string :: String",
})
}

/// PhantomData type.
pub fn phantom_data_ty(&self) -> RawTokens<&'static str> {
RawTokens(if self.no_std {
":: core :: marker :: PhantomData"
} else {
":: std :: marker :: PhantomData"
})
}

/// Default trait.
pub fn default_trait(&self) -> RawTokens<&'static str> {
RawTokens(if self.no_std {
":: core :: default :: Default"
} else {
":: std :: default :: Default"
})
}

/// Clone trait.
pub fn clone_trait(&self) -> RawTokens<&'static str> {
RawTokens(if self.no_std {
":: core :: clone :: Clone"
} else {
":: std :: clone :: Clone"
})
}

/// Into trait.
pub fn into_trait(&self) -> RawTokens<&'static str> {
RawTokens(if self.no_std {
":: core :: convert :: Into"
} else {
":: std :: convert :: Into"
})
}

/// TryInto trait.
/// TryInto trait. Once `TryFrom` stabilizes, this should be removed and
/// `derive_builder::export` should export `core::convert::TryInto` directly.
pub fn try_into_trait(&self) -> RawTokens<&'static str> {
RawTokens(if self.no_std {
":: core :: convert :: TryInto"
} else {
":: std :: convert :: TryInto"
})
RawTokens(match *self {
Bindings::Std => ":: std :: convert :: TryInto",
Bindings::NoStd => ":: core :: convert :: TryInto",
})
}
}

#[test]
fn std() {
let b = Bindings { no_std: false };
let b = Bindings::Std;

assert_eq!(b.string_ty().to_tokens(), quote!(::std::string::String));

assert_eq!(b.result_ty().to_tokens(), quote!(::std::result::Result));

assert_eq!(b.option_ty().to_tokens(), quote!(::std::option::Option));

assert_eq!(b.phantom_data_ty().to_tokens(),
quote!(::std::marker::PhantomData));

assert_eq!(b.default_trait().to_tokens(),
quote!(::std::default::Default));

assert_eq!(b.clone_trait().to_tokens(), quote!(::std::clone::Clone));

assert_eq!(b.into_trait().to_tokens(), quote!(::std::convert::Into));
assert_eq!(b.try_into_trait().to_tokens(), quote!(::std::convert::TryInto));
}

#[test]
fn no_std() {
let b = Bindings { no_std: true };
let b = Bindings::NoStd;

assert_eq!(b.string_ty().to_tokens(),
quote!(::collections::string::String));

assert_eq!(b.result_ty().to_tokens(), quote!(::core::result::Result));

assert_eq!(b.option_ty().to_tokens(), quote!(::core::option::Option));

assert_eq!(b.phantom_data_ty().to_tokens(),
quote!(::core::marker::PhantomData));

assert_eq!(b.default_trait().to_tokens(),
quote!(::core::default::Default));

assert_eq!(b.clone_trait().to_tokens(), quote!(::core::clone::Clone));

assert_eq!(b.into_trait().to_tokens(), quote!(::core::convert::Into));
assert_eq!(b.try_into_trait().to_tokens(), quote!(::core::convert::TryInto));
}
Loading