Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
@@ -0,0 +1,78 @@
#[macro_use]
extern crate derive_builder;
/// A struct that deliberately doesn't implement `Clone`.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Dolor(String);
/// Notice that this type derives Builder without disallowing
/// `Lorem<Dolor>`.
#[derive(Debug, Clone, Builder, PartialEq, Eq, Default)]
#[builder(field(private), setter(into))]
pub struct Lorem<T> {
ipsum: T,
}
#[derive(Debug, Clone, Builder, PartialEq, Eq, Default)]
#[builder(field(private))]
pub struct VecLorem<T> {
ipsum: Vec<T>,
}
#[derive(Debug, Clone, Builder, PartialEq, Eq)]
#[builder(pattern = "owned", field(private))]
pub struct OwnedLorem<T> {
ipsum: T,
}
#[test]
fn generic_field_with_clone_has_builder_impl() {
assert_eq!(
LoremBuilder::default().ipsum(10).build().unwrap(),
Lorem { ipsum: 10 }
);
}
/// The `LoremBuilder` type does not require that `T: Clone`, so we should
/// be able to name a `LoremBuilder<Dolor>`. But all the methods are on an impl
/// bound with `T: Clone`, so we can't do anything with it.
#[test]
fn builder_with_non_clone_generic_compiles() {
let _: LoremBuilder<Dolor>;
}
/// In this case, we're trying to emit something that converts into a thing that
/// implements clone.
#[test]
fn builder_with_into_generic_compiles() {
assert_eq!(
LoremBuilder::<String>::default().ipsum("").build().unwrap(),
Lorem::default()
);
}
#[test]
fn builder_with_vec_t_compiles() {
assert_eq!(
VecLoremBuilder::<String>::default()
.ipsum(vec!["Hello".to_string()])
.build()
.unwrap(),
VecLorem {
ipsum: vec!["Hello".to_string()],
}
);
}
#[test]
fn generic_field_without_clone_has_owned_builder() {
assert_eq!(
OwnedLoremBuilder::default()
.ipsum(Dolor::default())
.build()
.unwrap(),
OwnedLorem {
ipsum: Dolor::default()
}
);
}
+66
View File
@@ -0,0 +1,66 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, Builder, PartialEq)]
#[builder(build_fn(skip))]
pub struct Lorem {
percentile: u8,
}
#[derive(Debug, Builder, PartialEq)]
#[builder(build_fn(name = "finish"))]
pub struct Ipsum {
percentile: u8,
}
impl Lorem {
pub fn new(pct: u8) -> Result<Self, String> {
if pct <= 100 {
Ok(Lorem { percentile: pct })
} else {
Err(format!("Percentile must be between 0 and 100; was {}", pct))
}
}
}
impl LoremBuilder {
pub fn build(&self) -> Result<Lorem, String> {
if let Some(ref pct) = self.percentile {
Lorem::new(*pct)
} else {
Err("Percentile was not initialized".to_string())
}
}
}
impl IpsumBuilder {
/// This should be fine, because we renamed the generated build_fn.
#[allow(dead_code)]
fn build(&self) -> Result<Self, String> {
unimplemented!()
}
}
#[test]
fn happy_path() {
let lorem = LoremBuilder::default().percentile(80).build().unwrap();
assert_eq!(lorem, Lorem { percentile: 80 });
}
#[test]
fn uninitialized() {
let lorem_err = LoremBuilder::default().build().unwrap_err();
assert_eq!("Percentile was not initialized", &lorem_err);
}
#[test]
fn out_of_range() {
let lorem_err = LoremBuilder::default().percentile(120).build().unwrap_err();
assert_eq!("Percentile must be between 0 and 100; was 120", &lorem_err);
}
#[test]
fn rename() {
let ipsum = IpsumBuilder::default().percentile(110).finish().unwrap();
assert_eq!(Ipsum { percentile: 110 }, ipsum);
}
@@ -0,0 +1,49 @@
#[macro_use]
extern crate derive_builder;
use std::num::ParseIntError;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
pub struct Lorem {
#[builder(field(ty = "Option<usize>", build = self.ipsum.unwrap_or(42) + 1))]
ipsum: usize,
#[builder(setter(into), field(ty = "String", build = self.dolor.parse()?))]
dolor: u32,
}
impl From<ParseIntError> for LoremBuilderError {
fn from(e: ParseIntError) -> LoremBuilderError {
LoremBuilderError::ValidationError(e.to_string())
}
}
#[test]
fn custom_fields() {
let x = LoremBuilder::default().dolor("7").build().unwrap();
assert_eq!(
x,
Lorem {
ipsum: 43,
dolor: 7,
}
);
let x = LoremBuilder::default()
.ipsum(Some(12))
.dolor("66")
.build()
.unwrap();
assert_eq!(
x,
Lorem {
ipsum: 13,
dolor: 66,
}
);
let x = LoremBuilder::default().build().unwrap_err().to_string();
assert_eq!(x, "cannot parse integer from empty string");
}
@@ -0,0 +1,38 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(name = "MyBuilder")]
struct Lorem {
ipsum: &'static str,
pub dolor: Option<&'static str>,
pub sit: i32,
amet: bool,
}
#[test]
fn error_if_uninitialized() {
let error = MyBuilder::default().build().unwrap_err();
assert_eq!(&error.to_string(), "`ipsum` must be initialized");
}
#[test]
fn builder_test() {
let x: Lorem = MyBuilder::default()
.ipsum("lorem")
.dolor(Some("dolor"))
.sit(42)
.amet(true)
.build()
.unwrap();
assert_eq!(
x,
Lorem {
ipsum: "lorem",
dolor: Some("dolor"),
sit: 42,
amet: true,
}
);
}
@@ -0,0 +1,27 @@
use derive_builder::Builder;
#[derive(Builder)]
#[builder(build_fn(error(validation_error = false, path = "hello")))]
struct Fee {
hi: u32,
}
#[derive(Builder)]
#[builder(build_fn(error(validation_error = false), validate = "hello"))]
struct Foo {
hi: u32,
}
#[derive(Builder)]
#[builder(build_fn(error(path = "hello")))]
struct Fii {
hi: u32,
}
#[derive(Builder)]
#[builder(build_fn(error()))]
struct Fum {
hi: u32,
}
fn main() {}
@@ -0,0 +1,31 @@
error: Unknown field: `path`
--> tests/compile-fail/build_fn_error.rs:4:52
|
4 | #[builder(build_fn(error(validation_error = false, path = "hello")))]
| ^^^^
error: Cannot set `error(validation_error = false)` when using `validate`
--> tests/compile-fail/build_fn_error.rs:10:45
|
10 | #[builder(build_fn(error(validation_error = false), validate = "hello"))]
| ^^^^^
error: Unknown field: `path`
--> tests/compile-fail/build_fn_error.rs:16:26
|
16 | #[builder(build_fn(error(path = "hello")))]
| ^^^^
error: Missing field `validation_error` at build_fn/error
--> tests/compile-fail/build_fn_error.rs:15:10
|
15 | #[derive(Builder)]
| ^^^^^^^
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
error: Missing field `validation_error`
--> tests/compile-fail/build_fn_error.rs:22:20
|
22 | #[builder(build_fn(error()))]
| ^^^^^
@@ -0,0 +1,12 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
pub struct Lorem {
ok: String,
#[builder_field_attr(no_such_attribute)]
broken: String,
}
fn main() {}
@@ -0,0 +1,5 @@
error: cannot find attribute `no_such_attribute` in this scope
--> tests/compile-fail/builder_field_attr.rs:8:26
|
8 | #[builder_field_attr(no_such_attribute)]
| ^^^^^^^^^^^^^^^^^
@@ -0,0 +1,22 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
pub struct Lorem {
// `default` is incompatible with `field.build`
#[builder(
default = "1",
field(build = "self.ipsum.map(|v| v + 42).unwrap_or(100)")
)]
ipsum: usize,
// `default` is incompatible with `field.ty`, even without `field.build`
#[builder(default = "2", field(ty = "usize"))]
sit: usize,
// Both errors can occur on the same field
#[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))]
amet: usize,
}
fn main() {}
@@ -0,0 +1,23 @@
error: #[builder(default)] and #[builder(field(build="..."))] cannot be used together
--> tests/compile-fail/builder_field_custom.rs:8:19
|
8 | default = "1",
| ^^^
error: #[builder(default)] and #[builder(field(ty="..."))] cannot be used together
--> tests/compile-fail/builder_field_custom.rs:14:25
|
14 | #[builder(default = "2", field(ty = "usize"))]
| ^^^
error: #[builder(default)] and #[builder(field(build="..."))] cannot be used together
--> tests/compile-fail/builder_field_custom.rs:18:25
|
18 | #[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))]
| ^^^
error: #[builder(default)] and #[builder(field(ty="..."))] cannot be used together
--> tests/compile-fail/builder_field_custom.rs:18:25
|
18 | #[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))]
| ^^^
@@ -0,0 +1,16 @@
#![deny(unused_must_use)]
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
pub struct Lorem {
ok: String,
#[builder_setter_attr(must_use)]
broken: usize,
}
fn main() {
LoremBuilder::default().broken(42);
}
@@ -0,0 +1,11 @@
error: unused return value of `LoremBuilder::broken` that must be used
--> tests/compile-fail/builder_setter_attr.rs:15:5
|
15 | LoremBuilder::default().broken(42);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> tests/compile-fail/builder_setter_attr.rs:1:9
|
1 | #![deny(unused_must_use)]
| ^^^^^^^^^^^^^^^
@@ -0,0 +1,16 @@
#[macro_use]
extern crate derive_builder;
// This is a stand-in for any bad crate directive
mod empty {}
#[derive(Builder)]
// It would be nice if the "failed to resolve" errors would identify `"empty"` as the error span,
// but doing so would require rewriting a lot of the code generation to use the crate_root span
// for the full path of the thing being imported, and that doesn't seem worth the code churn.
#[builder(crate = "empty")]
struct BadCrate {
lorem: String,
}
fn main() {}
@@ -0,0 +1,122 @@
error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ could not find `export` in `empty`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty::export::core::option`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
|
5 | use core::option::Option;
|
5 | use derive_builder::export::core::option::Option;
|
5 | use serde::__private::Option;
|
5 | use std::option::Option;
|
error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty::export::core::clone`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
|
5 | use core::clone::Clone;
|
5 | use derive_builder::export::core::clone::Clone;
|
5 | use serde::__private::Clone;
|
5 | use std::clone::Clone;
|
error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty::export::core::result`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
|
5 | use core::fmt::Result;
|
5 | use core::result::Result;
|
5 | use derive_builder::export::core::fmt::Result;
|
5 | use derive_builder::export::core::io::Result;
|
and 9 other candidates
error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty::export::core::convert`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
|
5 | use core::convert::Into;
|
5 | use derive_builder::export::core::convert::Into;
|
5 | use serde::__private::Into;
|
5 | use std::convert::Into;
|
error[E0433]: failed to resolve: could not find `UninitializedFieldError` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this struct
|
5 | use derive_builder::UninitializedFieldError;
|
error[E0433]: failed to resolve: could not find `export` in `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty::export::core::default`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing one of these items
|
5 | use core::default::Default;
|
5 | use derive_builder::export::core::default::Default;
|
5 | use serde::__private::Default;
|
5 | use std::default::Default;
|
error[E0412]: cannot find type `UninitializedFieldError` in module `empty`
--> tests/compile-fail/crate_root.rs:7:10
|
7 | #[derive(Builder)]
| ^^^^^^^ not found in `empty`
|
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this struct
|
5 | use derive_builder::UninitializedFieldError;
|
@@ -0,0 +1,44 @@
#[macro_use]
extern crate derive_builder;
use derive_builder::UninitializedFieldError;
trait Popular {
fn is_popular(&self) -> bool;
}
impl<'a> Popular for &'a str {
fn is_popular(&self) -> bool {
!self.starts_with('b')
}
}
#[derive(Debug, Builder)]
#[builder(build_fn(validate = "check_person", error = "Error<N>"))]
struct Person<N> {
name: N,
age: u16,
}
enum Error<N> {
UninitializedField(&'static str),
UnpopularName(N),
}
impl<N> From<UninitializedFieldError> for Error<N> {
fn from(error: UninitializedFieldError) -> Self {
Self::UninitializedField(error.field_name())
}
}
fn check_person<N: Popular + Clone>(builder: &PersonBuilder<N>) -> Result<(), Error<N>> {
if let Some(name) = &builder.name {
if !name.is_popular() {
return Err(Error::UnpopularName(name.clone()));
}
}
Ok(())
}
fn main() {}
@@ -0,0 +1,15 @@
error[E0277]: the trait bound `N: Popular` is not satisfied
--> tests/compile-fail/custom_error_generic_missing_bound.rs:17:31
|
17 | #[builder(build_fn(validate = "check_person", error = "Error<N>"))]
| ^^^^^^^^^^^^^^ the trait `Popular` is not implemented for `N`
|
note: required by a bound in `check_person`
--> tests/compile-fail/custom_error_generic_missing_bound.rs:34:20
|
34 | fn check_person<N: Popular + Clone>(builder: &PersonBuilder<N>) -> Result<(), Error<N>> {
| ^^^^^^^ required by this bound in `check_person`
help: consider restricting type parameter `N`
|
18 | struct Person<N: Popular> {
| +++++++++
@@ -0,0 +1,37 @@
#[macro_use]
extern crate derive_builder;
fn validate_age(age: usize) -> Result<(), Error> {
if age > 200 {
Err(Error::UnrealisticAge(age))
} else {
Ok(())
}
}
fn check_person(builder: &PersonBuilder) -> Result<(), Error> {
if let Some(age) = builder.age {
validate_age(age)
} else {
Ok(())
}
}
#[derive(Builder)]
#[builder(build_fn(validate = "check_person", error = "Error"))]
struct Person {
name: String,
age: usize,
}
// NOTE: This enum has a variant for the uninitialized field case (called MissingData)
// but has forgotten `impl From<derive_builder::UninitializedFieldError>`, which is a
// compile-blocking mistake.
#[derive(Debug)]
enum Error {
/// A required field is not filled out.
MissingData(&'static str),
UnrealisticAge(usize),
}
fn main() {}
@@ -0,0 +1,7 @@
error[E0277]: the trait bound `Error: From<UninitializedFieldError>` is not satisfied
--> tests/compile-fail/custom_error_no_from.rs:21:55
|
21 | #[builder(build_fn(validate = "check_person", error = "Error"))]
| ^^^^^^^ the trait `From<UninitializedFieldError>` is not implemented for `Error`
|
= note: required because of the requirements on the impl of `Into<Error>` for `UninitializedFieldError`
@@ -0,0 +1,12 @@
#[macro_use]
extern crate derive_builder;
// deny `#[builder(default = "")]`, because we don't want to define a meaning (yet)! :-)
#[allow(dead_code)]
#[derive(Builder)]
struct Lorem {
#[builder(default = "")]
ipsum: String,
}
fn main() {}
@@ -0,0 +1,5 @@
error: Unknown literal value ``
--> $DIR/deny_empty_default.rs:8:25
|
8 | #[builder(default = "")]
| ^^
@@ -0,0 +1,30 @@
#[macro_use]
extern crate derive_builder;
mod container {
/// `LoremBuilder` should be accessible outside the module, but its
/// build method should not be.
#[derive(Debug, Default, Builder)]
#[builder(default, public, build_fn(private))]
pub struct Lorem {
foo: usize,
bar: String,
}
impl LoremBuilder {
/// Create a `Lorem`
pub fn my_build(&self) -> Lorem {
self.build().expect("All good")
}
}
}
fn main() {
use container::{Lorem, LoremBuilder};
let lorem1 = LoremBuilder::default().my_build();
let lorem2 = LoremBuilder::default().build().unwrap();
println!("{:?} vs {:?}", lorem1, lorem2);
}
@@ -0,0 +1,16 @@
warning: unused import: `Lorem`
--> tests/compile-fail/private_build_fn.rs:23:21
|
23 | use container::{Lorem, LoremBuilder};
| ^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error[E0624]: associated function `build` is private
--> tests/compile-fail/private_build_fn.rs:27:42
|
7 | #[derive(Debug, Default, Builder)]
| ------- private associated function defined here
...
27 | let lorem2 = LoremBuilder::default().build().unwrap();
| ^^^^^ private associated function
@@ -0,0 +1,23 @@
#[macro_use]
extern crate derive_builder;
pub mod foo {
/// The builder struct's declaration of privacy should override the field's
/// attempt to be public later on.
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(private, setter(into))]
pub struct Lorem {
pub private: String,
#[builder(public)]
pub public: String,
}
}
fn main() {
let x = foo::LoremBuilder::default()
.public("Hello")
.build()
.unwrap();
assert_eq!(x.public, "Hello".to_string());
}
@@ -0,0 +1,21 @@
error[E0603]: struct `LoremBuilder` is private
--> tests/compile-fail/private_builder.rs:17:18
|
17 | let x = foo::LoremBuilder::default()
| ^^^^^^^^^^^^ private struct
|
note: the struct `LoremBuilder` is defined here
--> tests/compile-fail/private_builder.rs:7:41
|
7 | #[derive(Debug, PartialEq, Default, Builder, Clone)]
| ^^^^^^^
= note: this error originates in the derive macro `Builder` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0624]: associated function `build` is private
--> tests/compile-fail/private_builder.rs:19:10
|
7 | #[derive(Debug, PartialEq, Default, Builder, Clone)]
| ------- private associated function defined here
...
19 | .build()
| ^^^^^ private associated function
@@ -0,0 +1,26 @@
#[macro_use]
extern crate derive_builder;
/// This builder is in an inner module to make sure private fields aren't accessible
/// from the `main` function.
mod inner {
/// The `LoremBuilder` struct will have private fields for `ipsum` and `dolor`, and
/// a public `sit` field.
#[derive(Debug, Builder)]
#[builder(field(private), setter(into))]
pub struct Lorem {
ipsum: String,
dolor: u16,
#[builder(field(public))]
sit: bool,
}
}
fn main() {
use inner::LoremBuilder;
let mut lorem = LoremBuilder::default();
lorem.dolor(15u16);
lorem.sit = Some(true); // <-- public
lorem.dolor = Some(0); // <-- private
}
@@ -0,0 +1,5 @@
error[E0616]: field `dolor` of struct `LoremBuilder` is private
--> tests/compile-fail/private_fields.rs:25:11
|
25 | lorem.dolor = Some(0); // <-- private
| ^^^^^ private field
@@ -0,0 +1,25 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(name = "foo"))]
struct Lorem {
ipsum: &'static str,
pub dolor: &'static str,
}
fn main() {
let x = LoremBuilder::default()
.ipsum("ipsum")
.foo("dolor")
.build()
.unwrap();
assert_eq!(
x,
Lorem {
ipsum: "ipsum",
dolor: "dolor",
}
);
}
@@ -0,0 +1,11 @@
error: Unknown field: `name`
--> tests/compile-fail/rename_setter_struct_level.rs:5:18
|
5 | #[builder(setter(name = "foo"))]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type `LoremBuilder`
--> tests/compile-fail/rename_setter_struct_level.rs:12:13
|
12 | let x = LoremBuilder::default()
| ^^^^^^^^^^^^ use of undeclared type `LoremBuilder`
@@ -0,0 +1,21 @@
#[macro_use]
extern crate derive_builder;
#[derive(Builder)]
#[builder(public, vis = "pub(crate)")]
pub struct Example {
#[builder(public, private)]
field: String,
}
#[derive(Builder)]
#[builder(public, vis = "pub(crate)", build_fn(private, public))]
pub struct SecondExample {
#[builder(private, vis = "pub")]
a_field: String,
}
fn main() {
ExampleBuilder::default().build();
SecondExampleBuilder::default().build();
}
@@ -0,0 +1,29 @@
error: `public` and `vis` cannot be used together
--> tests/compile-fail/vis_conflict.rs:5:25
|
5 | #[builder(public, vis = "pub(crate)")]
| ^^^^^^^^^^^^
error: `public` and `private` cannot be used together
--> tests/compile-fail/vis_conflict.rs:12:48
|
12 | #[builder(public, vis = "pub(crate)", build_fn(private, public))]
| ^^^^^^^
error: `public` and `vis` cannot be used together
--> tests/compile-fail/vis_conflict.rs:12:25
|
12 | #[builder(public, vis = "pub(crate)", build_fn(private, public))]
| ^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type `ExampleBuilder`
--> tests/compile-fail/vis_conflict.rs:19:5
|
19 | ExampleBuilder::default().build();
| ^^^^^^^^^^^^^^ use of undeclared type `ExampleBuilder`
error[E0433]: failed to resolve: use of undeclared type `SecondExampleBuilder`
--> tests/compile-fail/vis_conflict.rs:20:5
|
20 | SecondExampleBuilder::default().build();
| ^^^^^^^^^^^^^^^^^^^^ use of undeclared type `SecondExampleBuilder`
@@ -0,0 +1,12 @@
#![cfg(compiletests)]
extern crate rustversion;
extern crate trybuild;
#[rustversion::stable(1.59)]
#[test]
fn compile_test() {
let t = trybuild::TestCases::new();
t.pass("tests/run-pass/*.rs");
t.compile_fail("tests/compile-fail/*.rs");
}
@@ -0,0 +1,50 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Eq, Builder)]
#[builder(custom_constructor, build_fn(private, name = "fallible_build"))]
struct Request {
url: &'static str,
username: &'static str,
#[builder(default, setter(into))]
password: Option<&'static str>,
}
impl RequestBuilder {
pub fn new(url: &'static str, username: &'static str) -> Self {
Self {
url: Some(url),
username: Some(username),
..Self::create_empty()
}
}
pub fn build(&self) -> Request {
self.fallible_build()
.expect("All required fields set upfront")
}
}
#[test]
fn new_then_build_succeeds() {
assert_eq!(
RequestBuilder::new("...", "!!!").build(),
Request {
url: "...",
username: "!!!",
password: None
}
);
}
#[test]
fn new_then_set_succeeds() {
assert_eq!(
RequestBuilder::new("...", "!!!").password("test").build(),
Request {
url: "...",
username: "!!!",
password: Some("test")
}
);
}
@@ -0,0 +1,136 @@
#[macro_use]
extern crate derive_builder;
mod field_level {
use derive_builder::UninitializedFieldError;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
struct Lorem {
required: String,
#[builder(default)]
explicit_default: String,
#[builder(default = "foo".to_string())]
escaped_default: String,
#[builder(default = format!("Hello {}!", "World"))]
raw_default: String,
#[builder(default = {format!("{}-{}-{}-{}",
Clone::clone(self.required
.as_ref()
.ok_or_else(|| UninitializedFieldError::new("required"))?),
match self.explicit_default { Some(ref x) => x, None => "EMPTY" },
self.escaped_default.as_ref().map(|x| x.as_ref()).unwrap_or("EMPTY"),
if let Some(ref x) = self.raw_default { x } else { "EMPTY" })})]
computed_default: String,
}
#[test]
fn error_if_uninitialized() {
let error = LoremBuilder::default().build().unwrap_err();
assert_eq!(&error.to_string(), "`required` must be initialized");
}
#[test]
fn custom_default() {
let x = LoremBuilder::default()
.required("ipsum".to_string())
.build()
.unwrap();
assert_eq!(
x,
Lorem {
required: "ipsum".to_string(),
explicit_default: "".to_string(),
escaped_default: "foo".to_string(),
raw_default: "Hello World!".to_string(),
computed_default: "ipsum-EMPTY-EMPTY-EMPTY".to_string(),
}
);
}
#[test]
fn builder_test() {
let x = LoremBuilder::default()
.required("ipsum".to_string())
.explicit_default("lorem".to_string())
.escaped_default("dolor".to_string())
.raw_default("sit".to_string())
.build()
.unwrap();
assert_eq!(
x,
Lorem {
required: "ipsum".to_string(),
explicit_default: "lorem".to_string(),
escaped_default: "dolor".to_string(),
raw_default: "sit".to_string(),
computed_default: "ipsum-lorem-dolor-sit".to_string(),
}
);
}
}
mod struct_level {
#[derive(Debug, Clone, PartialEq, Eq, Builder)]
#[builder(default = explicit_default())]
struct Lorem {
#[builder(default = true)]
overwritten: bool,
not_type_default: Option<&'static str>,
}
fn explicit_default() -> Lorem {
Lorem {
overwritten: false,
not_type_default: Some("defined on struct-level"),
}
}
#[derive(Debug, Clone, PartialEq, Eq, Builder)]
#[builder(default)]
struct Ipsum {
not_type_default: Option<u16>,
also_custom: bool,
is_type_default: String,
}
impl Default for Ipsum {
fn default() -> Self {
Ipsum {
not_type_default: Some(20),
also_custom: true,
is_type_default: Default::default(),
}
}
}
#[test]
fn explicit_defaults_are_equal() {
let lorem = LoremBuilder::default().build().unwrap();
assert_eq!(
lorem,
Lorem {
overwritten: true,
..explicit_default()
}
);
}
#[test]
fn implicit_defaults_are_equal() {
let ipsum = IpsumBuilder::default().build().unwrap();
assert_eq!(ipsum, Ipsum::default());
}
#[test]
fn overrides_work() {
let ipsum = IpsumBuilder::default()
.not_type_default(None)
.build()
.expect("Struct-level default makes all fields optional");
assert_eq!(ipsum.not_type_default, None);
}
}
@@ -0,0 +1,25 @@
#![allow(dead_code)]
#[macro_use]
extern crate derive_builder;
#[derive(Debug, Default, Clone)]
struct NotPartialEq(String);
#[derive(Debug, Clone, Builder)]
#[builder(derive(Debug, PartialEq, Eq))]
struct Lorem {
foo: u8,
/// This type doesn't have `PartialEq` support, but that's fine
/// since we don't want it in the builder.
#[builder(setter(skip))]
excluded: NotPartialEq,
}
#[test]
fn defaults() {
// This macro requires that the two sides implement `PartialEq` AND `Debug`,
// so this one line is testing that the requested traits were really generated.
assert_eq!(LoremBuilder::default(), LoremBuilder::default());
}
@@ -0,0 +1,24 @@
#![deny(non_snake_case)]
#[macro_use]
extern crate derive_builder;
#[derive(Builder)]
// If this attribute is not forwarded to both the struct and the impl block, there would
// be a compile error on either the field or the setter method name. Therefore, forwarding
// is working as-expected if this test compiles.
#[allow(non_snake_case)]
pub struct Example {
aPascalName: &'static str,
}
fn main() {
assert_eq!(
ExampleBuilder::default()
.aPascalName("hello")
.build()
.unwrap()
.aPascalName,
"hello"
);
}
@@ -0,0 +1,29 @@
#[macro_use]
extern crate derive_builder;
extern crate serde;
extern crate serde_json;
#[derive(Builder)]
#[builder(setter(into), derive(serde::Serialize))]
#[builder_struct_attr(serde(rename_all = "camelCase"))]
#[allow(dead_code)]
struct Example {
first_name: String,
middle_name: String,
#[builder_field_attr(serde(rename = "familyName"))]
last_name: String,
}
#[test]
fn serialize_builder() {
assert_eq!(
serde_json::to_string(
&ExampleBuilder::default()
.first_name("Jane")
.middle_name("Alice")
.last_name("Doe"),
)
.unwrap(),
r#"{"firstName":"Jane","middleName":"Alice","familyName":"Doe"}"#
);
}
@@ -0,0 +1,57 @@
#[macro_use]
extern crate derive_builder;
use std::clone::Clone;
use std::fmt::Display;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
struct Generic<T: Display>
where
T: Clone,
{
ipsum: &'static str,
pub dolor: T,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
pub struct GenericReference<'a, T: 'a + Default>
where
T: Display,
{
pub bar: Option<&'a T>,
}
#[test]
fn error_if_uninitialized() {
let error = GenericBuilder::<String>::default().build().unwrap_err();
assert_eq!(&error.to_string(), "`ipsum` must be initialized");
}
#[test]
fn generic_builder() {
let x = GenericBuilder::default()
.ipsum("Generic")
.dolor(true)
.build()
.unwrap();
assert_eq!(
x,
Generic {
ipsum: "Generic".into(),
dolor: true,
}
);
}
#[test]
fn generic_reference_builder() {
static BAR: u32 = 42;
let x = GenericReferenceBuilder::<'static, u32>::default()
.bar(Some(&BAR))
.build()
.unwrap();
assert_eq!(x, GenericReference { bar: Some(&BAR) });
}
@@ -0,0 +1,36 @@
#[macro_use]
extern crate derive_builder;
/// Struct taken from `@shockham/caper` to make sure we emit the correct
/// code for struct-level defaults in tandem with generics.
#[derive(Builder, Clone, PartialEq)]
#[builder(default)]
pub struct RenderItem<T: Default> {
/// The vertices representing this items mesh
pub vertices: Vec<()>,
/// Whether the item is active/should be rendered
pub active: bool,
/// The name of the RenderItem for lookup
pub name: String,
/// Tag Type for grouping similar items
pub tag: T,
}
impl<T: Default> Default for RenderItem<T> {
fn default() -> Self {
RenderItem {
vertices: Default::default(),
active: true,
name: "ri".into(),
tag: Default::default(),
}
}
}
#[test]
fn create_with_string() {
let ri: RenderItem<String> = RenderItemBuilder::default().build().unwrap();
assert_eq!(ri.tag, "");
assert_eq!(ri.name, "ri");
assert!(ri.active);
}
@@ -0,0 +1,87 @@
//! Compile behavior test for derive_builder on no_std. Unfortunately, this has broken
//! too many times due to changes in requirements for no_std, and therefore this test
//! is no longer part of the required nightly pass.
// requires nightly toolchain!
//
// compile-flags:-C panic=abort
#![no_std]
#![feature(alloc, allocator_api, lang_items, start, core_intrinsics, oom)]
#![allow(dead_code)]
use core::intrinsics;
use core::panic::PanicInfo;
// Pull in the system libc library for what crt0.o likely requires.
// extern crate libc;
#[macro_use]
extern crate derive_builder;
extern crate alloc;
#[derive(Builder)]
#[builder(no_std)]
struct IgnoreEmptyStruct {}
#[derive(Builder, PartialEq, Debug)]
#[builder(no_std)]
struct Foo {
#[builder(default)]
defaulted: u32,
#[builder(setter(skip), try_setter)]
skipped: u32,
}
fn main() {
let foo = FooBuilder::default()
.build()
.unwrap();
assert_eq!(foo, Foo {
defaulted: 0,
skipped: 0,
})
}
///////////////////////////////////////////////////////////////
// some no_std-boilerplate
// from https://doc.rust-lang.org/book/no-stdlib.html
///////////////////////////////////////////////////////////////
// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "eh_personality"]
#[no_mangle]
pub extern fn eh_personality() {}
// This function may be needed based on the compilation target.
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern fn rust_eh_unwind_resume() {
}
#[panic_handler]
#[no_mangle]
fn panic(_info: &PanicInfo) -> ! {
unsafe { intrinsics::abort() }
}
#[lang = "oom"]
#[no_mangle]
pub extern fn rust_oom(_: core::alloc::Layout) -> ! {
unsafe { intrinsics::abort() }
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
unsafe { intrinsics::abort() }
}
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
main();
0
}
+20
View File
@@ -0,0 +1,20 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
struct Lorem<'a> {
ipsum: &'a str,
}
#[test]
fn error_if_uninitialized() {
let error = LoremBuilder::default().build().unwrap_err();
assert_eq!(&error.to_string(), "`ipsum` must be initialized");
}
#[test]
fn builder_test() {
let x = LoremBuilder::default().ipsum("ipsum").build().unwrap();
assert_eq!(x, Lorem { ipsum: "ipsum" });
}
@@ -0,0 +1,22 @@
#[macro_use]
extern crate derive_builder;
/// This is a doc comment for the struct
#[warn(missing_docs)]
#[allow(non_snake_case, dead_code)]
#[derive(Builder)]
struct Lorem {
/// This is a doc comment for a field
field_with_doc_comment: String,
#[allow(missing_docs)]
undocumented: String,
#[allow(non_snake_case)]
CamelCase: i32,
#[cfg(target_os = "macos")]
mac_only: bool,
#[allow(non_snake_case)]
#[cfg(target_os = "linux")]
LinuxOnly: (),
}
fn main() { }
@@ -0,0 +1,24 @@
//! Test that an alias of derive_builder is valid in #[builder(crate = "...")]
//!
//! This test is imperfect, as it still passes without setting `crate = "..."`.
//! This is likely because `derive_builder` is automatically present in 2018
//! without needing the extern crate line.
//!
//! The test will fail if an incorrect alias is used, so it adds limited value.
#[macro_use]
extern crate derive_builder as db;
#[derive(Builder)]
#[builder(crate = "db")]
struct AliasedCrate {
#[builder(setter(into))]
lorem: String,
}
fn main() {
AliasedCrateBuilder::default()
.lorem("hello")
.build()
.unwrap();
}
@@ -0,0 +1,49 @@
//! This test ensures custom errors don't need a conversion from `UninitializedFieldError`
//! if uninitialized fields are impossible.
#[macro_use]
extern crate derive_builder;
#[derive(Default, Builder)]
#[builder(default, build_fn(validate = "check_person", error = "Error"))]
struct Person {
name: String,
age: u16,
}
/// An error that deliberately doesn't have `impl From<UninitializedFieldError>`; as long
/// as `PersonBuilder` uses `Person::default` then missing field errors are never possible.
enum Error {
UnpopularName(String),
UnrealisticAge(u16),
}
fn check_age_realistic(age: u16) -> Result<(), Error> {
if age > 150 {
Err(Error::UnrealisticAge(age))
} else {
Ok(())
}
}
fn check_name_popular(name: &str) -> Result<(), Error> {
if name.starts_with('B') {
Err(Error::UnpopularName(name.to_string()))
} else {
Ok(())
}
}
fn check_person(builder: &PersonBuilder) -> Result<(), Error> {
if let Some(age) = &builder.age {
check_age_realistic(*age)?;
}
if let Some(name) = &builder.name {
check_name_popular(name)?;
}
Ok(())
}
fn main() {}
@@ -0,0 +1,30 @@
#![allow(dead_code)]
#[macro_use]
extern crate derive_builder;
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 {}
fn main() { }
@@ -0,0 +1,30 @@
//! Test ensuring that default type params gets forwarded to Builder.
#[macro_use]
extern crate derive_builder;
#[derive(Builder)]
#[builder(setter(strip_option))]
struct Settings<T, U = (), C = fn(T) -> U> {
first: T,
#[builder(default)]
second: Option<U>,
#[builder(default)]
third: Option<C>,
}
fn main() {
SettingsBuilder::<usize>::default()
.first(1)
.second(())
.third(|_: usize| ())
.build()
.unwrap();
SettingsBuilder::<usize, usize>::default()
.first(1)
.second(2)
.third(|_: usize| 3)
.build()
.unwrap();
}
@@ -0,0 +1,8 @@
#[macro_use]
extern crate derive_builder;
#[allow(dead_code)]
#[derive(Builder)]
struct IgnoreEmptyStruct {}
fn main() { }
@@ -0,0 +1,16 @@
#[macro_use]
extern crate derive_builder;
#[allow(dead_code)]
#[derive(Builder)]
struct Foo {
lorem: bool,
}
#[allow(dead_code)]
#[derive(Builder)]
struct Bar {
ipsum: bool,
}
fn main() { }
@@ -0,0 +1,93 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(skip = false), default)]
struct SetterCustom {
#[builder(setter(custom = true))]
setter_custom_by_explicit_opt_in: u32,
#[builder(setter(custom))]
setter_custom_shorthand: u32,
#[builder(setter(custom = false))]
setter_custom_by_explicit_opt_out: u32,
#[builder(setter(custom = true), default = "4")]
setter_custom_with_explicit_default: u32,
#[builder(setter(custom = true, strip_option))]
setter_custom_with_strip_option: Option<u32>,
#[builder(try_setter, setter(custom = true, strip_option))]
setter_custom_with_strip_option_try_setter: Option<u32>,
}
// compile test
#[allow(dead_code)]
impl SetterCustomBuilder {
// only possible if setter was skipped
fn setter_custom_by_explicit_opt_in(&mut self) -> &mut Self {
self.setter_custom_by_explicit_opt_in = Some(1);
self
}
// only possible if setter was skipped
fn setter_custom_shorthand(&mut self) -> &mut Self {
self.setter_custom_shorthand = Some(2);
self
}
// only possible if setter was skipped
fn setter_custom_with_explicit_default(&mut self) -> &mut Self {
self.setter_custom_with_explicit_default = Some(43);
self
}
// only possible if setter was skipped
fn setter_custom_with_strip_option(&mut self) -> &mut Self {
self.setter_custom_with_strip_option = Some(Some(6));
self
}
fn setter_custom_with_strip_option_try_setter(&mut self) -> &mut Self {
self.setter_custom_with_strip_option_try_setter = Some(Some(32));
self
}
}
#[test]
fn setter_custom_defaults() {
let x: SetterCustom = SetterCustomBuilder::default().build().unwrap();
assert_eq!(
x,
SetterCustom {
setter_custom_by_explicit_opt_in: 0,
setter_custom_shorthand: 0,
setter_custom_by_explicit_opt_out: 0,
setter_custom_with_explicit_default: 4,
setter_custom_with_strip_option: None,
setter_custom_with_strip_option_try_setter: None
}
);
}
#[test]
fn setter_custom_setters_called() {
let x: SetterCustom = SetterCustomBuilder::default()
.setter_custom_by_explicit_opt_in() // set to 1
.setter_custom_shorthand() // set to 2
.setter_custom_by_explicit_opt_out(42)
.setter_custom_with_explicit_default() // set to 43
.setter_custom_with_strip_option() // set to 6
.setter_custom_with_strip_option_try_setter() // set to 32
.build()
.unwrap();
assert_eq!(
x,
SetterCustom {
setter_custom_by_explicit_opt_in: 1,
setter_custom_shorthand: 2,
setter_custom_by_explicit_opt_out: 42,
setter_custom_with_explicit_default: 43,
setter_custom_with_strip_option: Some(6),
setter_custom_with_strip_option_try_setter: Some(32)
}
);
}
@@ -0,0 +1,158 @@
#[macro_use]
extern crate derive_builder;
use std::collections::HashMap;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
struct Lorem {
#[builder(setter(each = "foo_append"))]
foo: String,
#[builder(setter(each = "bar"))]
bars: Vec<String>,
#[builder(setter(each = "baz"))]
bazes: HashMap<String, i32>,
#[builder(setter(strip_option, each = "qux"))]
quxes: Option<Vec<String>>,
#[builder(setter(strip_option, each = "quux"))]
quuxes: Option<HashMap<String, i32>>,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(pattern = "mutable")]
struct Ipsum {
#[builder(setter(each(name = "foo_append")))]
foo: String,
#[builder(setter(each(name = "bar")))]
bars: Vec<String>,
#[builder(setter(each(name = "baz")))]
bazes: HashMap<String, i32>,
#[builder(setter(strip_option, each = "qux"))]
quxes: Option<Vec<String>>,
#[builder(setter(strip_option, each = "quux"))]
quuxes: Option<HashMap<String, i32>>,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder]
struct Dolor {
#[builder(setter(each(name = "foo_append")))]
foo: String,
#[builder(setter(each(name = "bar", into)))]
bars: Vec<String>,
#[builder(setter(each(name = "baz")))]
bazes: HashMap<String, i32>,
}
#[test]
fn extend_field() {
let x = LoremBuilder::default()
.foo("foo".into())
.bar("bar".into())
.bar("bar bar".into())
.bar("bar bar bar".into())
.foo_append('-')
.baz(("baz".into(), 1))
.baz(("bazz".into(), 2))
.baz(("bazzz".into(), 3))
.foo_append("foo")
.qux("qux".into())
.qux("qux qux".into())
.quux(("quux".into(), 1))
.quux(("quuxx".into(), 2))
.build()
.unwrap();
assert_eq!(
x,
Lorem {
foo: "foo-foo".into(),
bars: vec!["bar".into(), "bar bar".into(), "bar bar bar".into()],
bazes: vec![("baz".into(), 1), ("bazz".into(), 2), ("bazzz".into(), 3)]
.into_iter()
.collect(),
quxes: Some(vec!["qux".into(), "qux qux".into()]),
quuxes: Some(
vec![("quux".into(), 1), ("quuxx".into(), 2)]
.into_iter()
.collect()
),
}
);
}
#[test]
fn extend_field_into() {
let x = DolorBuilder::default()
.foo("foo".into())
.bar("bar")
.bar("bar bar")
.bar("bar bar bar")
.foo_append('-')
.baz(("baz".into(), 1))
.baz(("bazz".into(), 2))
.baz(("bazzz".into(), 3))
.foo_append("foo")
.build()
.unwrap();
assert_eq!(
x,
Dolor {
foo: "foo-foo".into(),
bars: vec!["bar".into(), "bar bar".into(), "bar bar bar".into()],
bazes: vec![("baz".into(), 1), ("bazz".into(), 2), ("bazzz".into(), 3)]
.into_iter()
.collect(),
}
);
}
#[test]
fn extend_field_mutable() {
let x = IpsumBuilder::default()
.foo("foo".into())
.bar("bar".into())
.bar("bar bar".into())
.bar("bar bar bar".into())
.foo_append('-')
.baz(("baz".into(), 1))
.baz(("bazz".into(), 2))
.baz(("bazzz".into(), 3))
.foo_append("foo")
.qux("qux".into())
.qux("qux qux".into())
.quux(("quux".into(), 1))
.quux(("quuxx".into(), 2))
.build()
.unwrap();
assert_eq!(
x,
Ipsum {
foo: "foo-foo".into(),
bars: vec!["bar".into(), "bar bar".into(), "bar bar bar".into()],
bazes: vec![("baz".into(), 1), ("bazz".into(), 2), ("bazzz".into(), 3)]
.into_iter()
.collect(),
quxes: Some(vec!["qux".into(), "qux qux".into()]),
quuxes: Some(
vec![("quux".into(), 1), ("quuxx".into(), 2)]
.into_iter()
.collect()
),
}
);
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(skip))]
struct Sit {
#[builder(setter(each(name = "foo")))]
foos: Vec<i32>,
}
#[test]
fn extend_field_enabled() {
let x = SitBuilder::default().foo(1).foo(2).build().unwrap();
assert_eq!(x, Sit { foos: vec![1, 2] });
}
@@ -0,0 +1,33 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
struct Lorem {
#[builder(setter(into))]
foo: String,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(into))]
struct Ipsum {
foo: u32,
}
#[test]
fn generic_field() {
let x = LoremBuilder::default().foo("foo").build().unwrap();
assert_eq!(
x,
Lorem {
foo: "foo".to_string()
}
);
}
#[test]
fn generic_struct() {
let x = IpsumBuilder::default().foo(42u8).build().unwrap();
assert_eq!(x, Ipsum { foo: 42u32 });
}
@@ -0,0 +1,27 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(prefix = "with"))]
struct Lorem {
ipsum: &'static str,
#[builder(setter(name = "foo"))]
pub dolor: &'static str,
}
#[test]
fn renamed_setter() {
let x = LoremBuilder::default()
.with_ipsum("ipsum")
.foo("dolor")
.build()
.unwrap();
assert_eq!(
x,
Lorem {
ipsum: "ipsum",
dolor: "dolor",
}
);
}
@@ -0,0 +1,105 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(pattern = "immutable")]
struct Lorem {
immutable: u32,
#[builder(pattern = "mutable")]
mutable_override: u32,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(pattern = "mutable")]
struct Ipsum {
mutable: u32,
#[builder(pattern = "owned")]
owned_override: u32,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(pattern = "owned")]
struct Dolor {
#[builder(pattern = "immutable")]
immutable_override: u32,
owned: u32,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
struct Sit {
default: u32,
}
type ImmutableSetter<T, U> = fn(&T, U) -> T;
type OwnedSetter<T, U> = fn(T, U) -> T;
type MutableSetter<T, U> = fn(&mut T, U) -> &mut T;
#[test]
fn mutable_by_default() {
// the setter must have the correct signature
let mutable_setter: MutableSetter<SitBuilder, u32> = SitBuilder::default;
let mut old = <SitBuilder as Default>::default();
mutable_setter(&mut old, 42);
assert_eq!(old.default, Some(42));
}
#[test]
fn mutable() {
// the setter must have the correct signature
let mutable_setter: MutableSetter<IpsumBuilder, u32> = IpsumBuilder::mutable;
let mut old = IpsumBuilder::default();
mutable_setter(&mut old, 42);
assert_eq!(old.mutable, Some(42));
}
#[test]
fn mutable_override() {
// the setter must have the correct signature
let mutable_setter: MutableSetter<LoremBuilder, u32> = LoremBuilder::mutable_override;
let mut old = LoremBuilder::default();
mutable_setter(&mut old, 42);
assert_eq!(old.mutable_override, Some(42));
}
#[test]
fn immutable() {
// the setter must have the correct signature
let immutable_setter: ImmutableSetter<LoremBuilder, u32> = LoremBuilder::immutable;
let old = LoremBuilder::default();
let new = immutable_setter(&old, 42);
assert_eq!(new.immutable, Some(42));
}
#[test]
fn immutable_override() {
// the setter must have the correct signature
let immutable_setter: ImmutableSetter<DolorBuilder, u32> = DolorBuilder::immutable_override;
let old = DolorBuilder::default();
let new = immutable_setter(&old, 42);
assert_eq!(new.immutable_override, Some(42));
}
#[test]
fn owned() {
// the setter must have the correct signature
let owned_setter: OwnedSetter<DolorBuilder, u32> = DolorBuilder::owned;
let old = DolorBuilder::default();
let new = owned_setter(old, 42);
assert_eq!(new.owned, Some(42));
}
#[test]
fn owned_override() {
// the setter must have the correct signature
let owned_setter: OwnedSetter<IpsumBuilder, u32> = IpsumBuilder::owned_override;
let old = IpsumBuilder::default();
let new = owned_setter(old, 42);
assert_eq!(new.owned_override, Some(42));
}
@@ -0,0 +1,27 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(prefix = "with"))]
struct Lorem {
ipsum: &'static str,
#[builder(setter(prefix = "set"))]
pub dolor: &'static str,
}
#[test]
fn prefixed_setters() {
let x = LoremBuilder::default()
.with_ipsum("ipsum")
.set_dolor("dolor")
.build()
.unwrap();
assert_eq!(
x,
Lorem {
ipsum: "ipsum",
dolor: "dolor",
}
);
}
@@ -0,0 +1,62 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, PartialEq, Default, Builder, Clone)]
struct Lorem {
#[builder(setter(into))]
full_opt: Option<String>,
#[builder(setter(into, strip_option))]
strip_opt: Option<String>,
#[builder(setter(strip_option))]
strip_opt_i32: Option<i32>,
#[builder(setter(strip_option))]
strip_opt_vec: Option<Vec<i32>>,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(into, strip_option))]
struct Ipsum {
foo: u32,
strip_opt: Option<String>,
#[builder(default)]
strip_opt_with_default: Option<String>,
}
#[test]
fn generic_field() {
let x = LoremBuilder::default()
.full_opt(Some("foo".to_string()))
.strip_opt("bar")
.strip_opt_i32(32)
.strip_opt_vec(vec![33])
.build()
.unwrap();
assert_eq!(
x,
Lorem {
full_opt: Some("foo".to_string()),
strip_opt: Some("bar".to_string()),
strip_opt_i32: Some(32),
strip_opt_vec: Some(vec![33]),
}
);
}
#[test]
fn generic_struct() {
let x = IpsumBuilder::default()
.foo(42u8)
.strip_opt("bar")
.build()
.unwrap();
assert_eq!(
x,
Ipsum {
foo: 42u32,
strip_opt: Some("bar".to_string()),
strip_opt_with_default: None,
}
);
}
@@ -0,0 +1,61 @@
#[macro_use]
extern crate derive_builder;
pub mod foo {
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(private, setter(into))]
pub struct Lorem {
pub private: String,
#[builder(public)]
pub public: String,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(public, setter(into))]
pub struct Ipsum {
#[builder(private)]
pub private: String,
pub public: String,
}
#[test]
fn setters_same_module() {
let x = LoremBuilder::default()
.public("Hello")
.private("world!")
.build()
.unwrap();
assert_eq!(
x,
Lorem {
public: "Hello".into(),
private: "world!".into(),
}
);
let y = IpsumBuilder::default()
.public("Hello")
.private("world!")
.build()
.unwrap();
assert_eq!(
y,
Ipsum {
public: "Hello".into(),
private: "world!".into(),
}
);
}
}
#[test]
fn public_setters_foreign_module() {
let error = foo::IpsumBuilder::default()
.public("Hello")
.build()
.unwrap_err();
assert_eq!(&error.to_string(), "`private` must be initialized");
}
+136
View File
@@ -0,0 +1,136 @@
// https://github.com/colin-kiegel/rust-derive-builder/issues/15
#[macro_use]
extern crate derive_builder;
#[derive(Debug, Clone, PartialEq)]
struct NotDefaultable(String);
fn new_notdefaultable() -> NotDefaultable {
NotDefaultable("Lorem".to_string())
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(skip = false))]
struct SetterOptOut {
setter_present_by_explicit_default: u32,
#[builder(setter(skip = true))]
setter_skipped_by_explicit_opt_out: u32,
#[builder(setter(skip))]
setter_skipped_by_shorthand_opt_out: u32,
#[builder(setter(skip), default = "4")]
setter_skipped_with_explicit_default: u32,
}
#[derive(Debug, PartialEq, Default, Builder, Clone)]
#[builder(setter(skip))]
struct SetterOptIn {
setter_skipped_by_shorthand_default: u32,
#[builder(setter(skip = false))]
setter_present_by_explicit_opt_in: u32,
#[builder(setter)]
setter_present_by_shorthand_opt_in: u32,
#[builder(setter(prefix = "set"))]
setter_present_by_shorthand_opt_in_2: u32,
}
#[derive(Debug, PartialEq, Builder, Clone)]
#[builder(default, setter(skip))]
struct SetterOptInStructDefault {
setter_skipped_with_struct_default: NotDefaultable,
setter_skipped_with_type_default: u32,
}
#[derive(Debug, PartialEq, Builder, Clone)]
#[builder(setter(into))]
struct SetterOptInFieldDefault {
#[builder(setter(skip), default = "new_notdefaultable()")]
setter_skipped_with_field_default: NotDefaultable,
#[builder(default)]
setter_present_by_default: u32,
}
// compile test
#[allow(dead_code)]
impl SetterOptOut {
// only possible if setter was skipped
fn setter_skipped_by_explicit_opt_out() {}
// only possible if setter was skipped
fn setter_skipped_by_shorthand_opt_out() {}
}
// compile test
#[allow(dead_code)]
impl SetterOptIn {
// only possible if setter was skipped
fn setter_skipped_by_shorthand_default() {}
}
impl Default for SetterOptInStructDefault {
fn default() -> Self {
SetterOptInStructDefault {
setter_skipped_with_struct_default: new_notdefaultable(),
setter_skipped_with_type_default: Default::default(),
}
}
}
#[test]
fn setter_opt_out() {
let x: SetterOptOut = SetterOptOutBuilder::default()
.setter_present_by_explicit_default(42u32)
.build()
.unwrap();
assert_eq!(
x,
SetterOptOut {
setter_present_by_explicit_default: 42,
setter_skipped_by_explicit_opt_out: 0,
setter_skipped_by_shorthand_opt_out: 0,
setter_skipped_with_explicit_default: 4,
}
);
}
#[test]
fn setter_opt_in() {
let x: SetterOptIn = SetterOptInBuilder::default()
.setter_present_by_explicit_opt_in(47u32)
.setter_present_by_shorthand_opt_in(11u32)
.set_setter_present_by_shorthand_opt_in_2(815u32)
.build()
.unwrap();
assert_eq!(
x,
SetterOptIn {
setter_skipped_by_shorthand_default: 0,
setter_present_by_explicit_opt_in: 47,
setter_present_by_shorthand_opt_in: 11,
setter_present_by_shorthand_opt_in_2: 815,
}
);
}
#[test]
fn setter_skipped_with_struct_default() {
let x = SetterOptInStructDefaultBuilder::default().build().unwrap();
assert_eq!(x, SetterOptInStructDefault::default());
}
#[test]
fn setter_skipped_with_field_default() {
let x = SetterOptInFieldDefaultBuilder::default()
.build()
.expect("All fields were defaulted");
assert_eq!(
x,
SetterOptInFieldDefault {
setter_skipped_with_field_default: new_notdefaultable(),
setter_present_by_default: Default::default(),
}
);
}
+92
View File
@@ -0,0 +1,92 @@
#[macro_use]
extern crate derive_builder;
use std::convert::TryFrom;
use std::net::{AddrParseError, IpAddr};
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq)]
pub struct MyAddr(IpAddr);
impl From<IpAddr> for MyAddr {
fn from(v: IpAddr) -> Self {
MyAddr(v)
}
}
impl<'a> TryFrom<&'a str> for MyAddr {
type Error = AddrParseError;
fn try_from(v: &str) -> Result<Self, Self::Error> {
Ok(MyAddr(v.parse()?))
}
}
#[derive(Debug, PartialEq, Builder)]
#[builder(try_setter, setter(into))]
struct Lorem {
pub source: MyAddr,
pub dest: MyAddr,
}
#[derive(Debug, PartialEq, Builder)]
#[builder(try_setter, setter(into, prefix = "set"))]
struct Ipsum {
pub source: MyAddr,
}
fn exact_helper() -> Result<Lorem, LoremBuilderError> {
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<Lorem, LoremBuilderError> {
LoremBuilder::default()
.try_source("1.2.3.4")
.map_err(|e| e.to_string())?
.try_dest("0.0.0.0")
.map_err(|e| e.to_string())?
.build()
}
#[test]
fn infallible_set() {
let _ = LoremBuilder::default()
.source(IpAddr::from_str("1.2.3.4").unwrap())
.dest(IpAddr::from_str("0.0.0.0").unwrap())
.build();
}
#[test]
fn fallible_set() {
let mut builder = LoremBuilder::default();
let try_result = builder.try_source("1.2.3.4");
let built = try_result
.expect("Passed well-formed address")
.dest(IpAddr::from_str("0.0.0.0").unwrap())
.build()
.unwrap();
assert_eq!(built, exact_helper().unwrap());
}
#[test]
fn with_helper() {
assert_eq!(exact_helper().unwrap(), try_helper().unwrap());
}
#[test]
fn renamed() {
IpsumBuilder::default()
.try_set_source("0.0.0.0")
.unwrap()
.build()
.expect("All fields were provided");
}
#[derive(Debug, PartialEq, Builder)]
#[builder(try_setter, setter(into, strip_option))]
struct MaybeIpsum {
pub source: Option<MyAddr>,
}
+79
View File
@@ -0,0 +1,79 @@
#[macro_use]
extern crate derive_builder;
#[derive(Debug, Clone, Builder, PartialEq, Eq)]
#[builder(build_fn(validate = "LoremBuilder::validate"))]
pub struct Lorem {
/// A percentile. Must be between 0 and 100.
my_effort: u8,
/// A percentile. Must be less than or equal to `Lorem::my_effort`.
#[builder(default = 40)]
their_effort: u8,
/// A percentile. Must be between 0 and 100.
rivals_effort: u8,
}
impl LoremBuilder {
/// Performs bound checks.
fn validate(&self) -> Result<(), String> {
if let Some(ref my_effort) = self.my_effort {
if *my_effort > 100 {
return Err("Don't wear yourself out".to_string());
}
}
if let Some(ref their_effort) = self.their_effort {
if *their_effort > 100 {
return Err("The game has changed".to_string());
}
}
if let Some(ref rivals_effort) = self.rivals_effort {
if *rivals_effort > 100 {
return Err("Your rival is cheating".to_string());
}
}
Ok(())
}
}
#[test]
fn out_of_bounds() {
assert_eq!(
&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()
.to_string(),
"Your rival is cheating"
);
}
#[test]
fn validation_pass() {
let lorem = LoremBuilder::default()
.my_effort(90)
.rivals_effort(89)
.build()
.expect("All validations should be passing");
assert_eq!(
lorem,
Lorem {
my_effort: 90,
rivals_effort: 89,
their_effort: 40,
}
);
}