diff options
Diffstat (limited to 'vendor/derive-new')
-rw-r--r-- | vendor/derive-new/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/derive-new/Cargo.toml | 34 | ||||
-rw-r--r-- | vendor/derive-new/README.md | 92 | ||||
-rw-r--r-- | vendor/derive-new/src/lib.rs | 453 | ||||
-rw-r--r-- | vendor/derive-new/tests/test.rs | 361 |
5 files changed, 941 insertions, 0 deletions
diff --git a/vendor/derive-new/.cargo-checksum.json b/vendor/derive-new/.cargo-checksum.json new file mode 100644 index 000000000..6cb4b7752 --- /dev/null +++ b/vendor/derive-new/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"3e95715ee0f542470854db178544d4910da0081ab5c5244d019a8c916bfa2067","README.md":"e3c5c183cca06c9c419eb69a42acb742d4e95b220eee3dd746b7329249f2c9b2","src/lib.rs":"0ab7b53e32c371c594b937b216035fd80334b7e20dd989ae124a65895fd6cef5","tests/test.rs":"99d471d22ebe68c55e052bf2f6236fbc966e9991d5738b85254cab9f2f5bd9f3"},"package":"71f31892cd5c62e414316f2963c5689242c43d8e7bbcaaeca97e5e28c95d91d9"}
\ No newline at end of file diff --git a/vendor/derive-new/Cargo.toml b/vendor/derive-new/Cargo.toml new file mode 100644 index 000000000..1542b4234 --- /dev/null +++ b/vendor/derive-new/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "derive-new" +version = "0.5.8" +authors = ["Nick Cameron <ncameron@mozilla.com>"] +description = "`#[derive(new)]` implements simple constructor functions for structs and enums." +license = "MIT" +repository = "https://github.com/nrc/derive-new" + +[lib] +proc-macro = true +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" + +[dependencies.syn] +version = "1" + +[features] +default = ["std"] +std = [] diff --git a/vendor/derive-new/README.md b/vendor/derive-new/README.md new file mode 100644 index 000000000..3568343c7 --- /dev/null +++ b/vendor/derive-new/README.md @@ -0,0 +1,92 @@ +# A custom derive implementation for `#[derive(new)]` + +A `derive(new)` attribute creates a `new` constructor function for the annotated +type. That function takes an argument for each field in the type giving a +trivial constructor. This is useful since as your type evolves you can make the +constructor non-trivial (and add or remove fields) without changing client code +(i.e., without breaking backwards compatibility). It is also the most succinct +way to initialise a struct or an enum. + +Implementation uses macros 1.1 custom derive (which works in stable Rust from +1.15 onwards). + +`#[no_std]` is fully supported if you switch off the default feature `"std"`. + +## Examples + +Cargo.toml: + +```toml +[dependencies] +derive-new = "0.5" +``` + +Include the macro: + +```rust +#[macro_use] +extern crate derive_new; +``` + +Generating constructor for a simple struct: + +```rust +#[derive(new)] +struct Bar { + a: i32, + b: String, +} + +let _ = Bar::new(42, "Hello".to_owned()); +``` + +Default values can be specified either via `#[new(default)]` attribute which removes +the argument from the constructor and populates the field with `Default::default()`, +or via `#[new(value = "..")]` which initializes the field with a given expression: + +```rust +#[derive(new)] +struct Foo { + x: bool, + #[new(value = "42")] + y: i32, + #[new(default)] + z: Vec<String>, +} + +let _ = Foo::new(true); +``` + +Generic types are supported; in particular, `PhantomData<T>` fields will be not +included in the argument list and will be intialized automatically: + +```rust +use std::marker::PhantomData; + +#[derive(new)] +struct Generic<'a, T: Default, P> { + x: &'a str, + y: PhantomData<P>, + #[new(default)] + z: T, +} + +let _ = Generic::<i32, u8>::new("Hello"); +``` + +For enums, one constructor method is generated for each variant, with the type +name being converted to snake case; otherwise, all features supported for +structs work for enum variants as well: + +```rust +#[derive(new)] +struct Enum { + FirstVariant, + SecondVariant(bool, #[new(default)] u8), + ThirdVariant { x: i32, #[new(value = "vec![1]")] y: Vec<u8> } +} + +let _ = Enum::new_first_variant(); +let _ = Enum::new_second_variant(true); +let _ = Enum::new_third_variant(42); +``` diff --git a/vendor/derive-new/src/lib.rs b/vendor/derive-new/src/lib.rs new file mode 100644 index 000000000..9fb1fb0bf --- /dev/null +++ b/vendor/derive-new/src/lib.rs @@ -0,0 +1,453 @@ +//!# A custom derive implementation for `#[derive(new)]` +//! +//!A `derive(new)` attribute creates a `new` constructor function for the annotated +//!type. That function takes an argument for each field in the type giving a +//!trivial constructor. This is useful since as your type evolves you can make the +//!constructor non-trivial (and add or remove fields) without changing client code +//!(i.e., without breaking backwards compatibility). It is also the most succinct +//!way to initialise a struct or an enum. +//! +//!Implementation uses macros 1.1 custom derive (which works in stable Rust from +//!1.15 onwards). +//! +//!## Examples +//! +//!Cargo.toml: +//! +//!```toml +//![dependencies] +//!derive-new = "0.5" +//!``` +//! +//!Include the macro: +//! +//!```rust +//!#[macro_use] +//!extern crate derive_new; +//!fn main() {} +//!``` +//! +//!Generating constructor for a simple struct: +//! +//!```rust +//!#[macro_use] +//!extern crate derive_new; +//!#[derive(new)] +//!struct Bar { +//! a: i32, +//! b: String, +//!} +//! +//!fn main() { +//! let _ = Bar::new(42, "Hello".to_owned()); +//!} +//!``` +//! +//!Default values can be specified either via `#[new(default)]` attribute which removes +//!the argument from the constructor and populates the field with `Default::default()`, +//!or via `#[new(value = "..")]` which initializes the field with a given expression: +//! +//!```rust +//!#[macro_use] +//!extern crate derive_new; +//!#[derive(new)] +//!struct Foo { +//! x: bool, +//! #[new(value = "42")] +//! y: i32, +//! #[new(default)] +//! z: Vec<String>, +//!} +//! +//!fn main() { +//! let _ = Foo::new(true); +//!} +//!``` +//! +//!Generic types are supported; in particular, `PhantomData<T>` fields will be not +//!included in the argument list and will be intialized automatically: +//! +//!```rust +//!#[macro_use] +//!extern crate derive_new; +//!use std::marker::PhantomData; +//! +//!#[derive(new)] +//!struct Generic<'a, T: Default, P> { +//! x: &'a str, +//! y: PhantomData<P>, +//! #[new(default)] +//! z: T, +//!} +//! +//!fn main() { +//! let _ = Generic::<i32, u8>::new("Hello"); +//!} +//!``` +//! +//!For enums, one constructor method is generated for each variant, with the type +//!name being converted to snake case; otherwise, all features supported for +//!structs work for enum variants as well: +//! +//!```rust +//!#[macro_use] +//!extern crate derive_new; +//!#[derive(new)] +//!enum Enum { +//! FirstVariant, +//! SecondVariant(bool, #[new(default)] u8), +//! ThirdVariant { x: i32, #[new(value = "vec![1]")] y: Vec<u8> } +//!} +//! +//!fn main() { +//! let _ = Enum::new_first_variant(); +//! let _ = Enum::new_second_variant(true); +//! let _ = Enum::new_third_variant(42); +//!} +//!``` +#![crate_type = "proc-macro"] +#![recursion_limit = "192"] + +extern crate proc_macro; +extern crate proc_macro2; +#[macro_use] +extern crate quote; +extern crate syn; + +macro_rules! my_quote { + ($($t:tt)*) => (quote_spanned!(proc_macro2::Span::call_site() => $($t)*)) +} + +fn path_to_string(path: &syn::Path) -> String { + path.segments.iter().map(|s| s.ident.to_string()).collect::<Vec<String>>().join("::") +} + +use proc_macro::TokenStream; +use syn::Token; + +#[proc_macro_derive(new, attributes(new))] +pub fn derive(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).expect("Couldn't parse item"); + let result = match ast.data { + syn::Data::Enum(ref e) => new_for_enum(&ast, e), + syn::Data::Struct(ref s) => new_for_struct(&ast, &s.fields, None), + syn::Data::Union(_) => panic!("doesn't work with unions yet"), + }; + result.into() +} + +fn new_for_struct( + ast: &syn::DeriveInput, + fields: &syn::Fields, + variant: Option<&syn::Ident>, +) -> proc_macro2::TokenStream { + match *fields { + syn::Fields::Named(ref fields) => new_impl(&ast, Some(&fields.named), true, variant), + syn::Fields::Unit => new_impl(&ast, None, false, variant), + syn::Fields::Unnamed(ref fields) => new_impl(&ast, Some(&fields.unnamed), false, variant), + } +} + +fn new_for_enum(ast: &syn::DeriveInput, data: &syn::DataEnum) -> proc_macro2::TokenStream { + if data.variants.is_empty() { + panic!("#[derive(new)] cannot be implemented for enums with zero variants"); + } + let impls = data.variants.iter().map(|v| { + if v.discriminant.is_some() { + panic!("#[derive(new)] cannot be implemented for enums with discriminants"); + } + new_for_struct(ast, &v.fields, Some(&v.ident)) + }); + my_quote!(#(#impls)*) +} + +fn new_impl( + ast: &syn::DeriveInput, + fields: Option<&syn::punctuated::Punctuated<syn::Field, Token![,]>>, + named: bool, + variant: Option<&syn::Ident>, +) -> proc_macro2::TokenStream { + let name = &ast.ident; + let unit = fields.is_none(); + let empty = Default::default(); + let fields: Vec<_> = fields + .unwrap_or(&empty) + .iter() + .enumerate() + .map(|(i, f)| FieldExt::new(f, i, named)) + .collect(); + let args = fields.iter().filter(|f| f.needs_arg()).map(|f| f.as_arg()); + let inits = fields.iter().map(|f| f.as_init()); + let inits = if unit { + my_quote!() + } else if named { + my_quote![{ #(#inits),* }] + } else { + my_quote![( #(#inits),* )] + }; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + let (mut new, qual, doc) = match variant { + None => ( + syn::Ident::new("new", proc_macro2::Span::call_site()), + my_quote!(), + format!("Constructs a new `{}`.", name), + ), + Some(ref variant) => ( + syn::Ident::new( + &format!("new_{}", to_snake_case(&variant.to_string())), + proc_macro2::Span::call_site(), + ), + my_quote!(::#variant), + format!("Constructs a new `{}::{}`.", name, variant), + ), + }; + new.set_span(proc_macro2::Span::call_site()); + let lint_attrs = collect_parent_lint_attrs(&ast.attrs); + let lint_attrs = my_quote![#(#lint_attrs),*]; + my_quote! { + impl #impl_generics #name #ty_generics #where_clause { + #[doc = #doc] + #lint_attrs + pub fn #new(#(#args),*) -> Self { + #name #qual #inits + } + } + } +} + +fn collect_parent_lint_attrs(attrs: &[syn::Attribute]) -> Vec<syn::Attribute> { + fn is_lint(item: &syn::Meta) -> bool { + if let syn::Meta::List(ref l) = *item { + let path = &l.path; + return path.is_ident("allow") || path.is_ident("deny") || path.is_ident("forbid") || path.is_ident("warn") + } + false + } + + fn is_cfg_attr_lint(item: &syn::Meta) -> bool { + if let syn::Meta::List(ref l) = *item { + if l.path.is_ident("cfg_attr") && l.nested.len() == 2 { + if let syn::NestedMeta::Meta(ref item) = l.nested[1] { + return is_lint(item); + } + } + } + false + } + + attrs + .iter() + .filter_map(|a| a.parse_meta().ok().map(|m| (m, a))) + .filter(|&(ref m, _)| is_lint(m) || is_cfg_attr_lint(m)) + .map(|p| p.1) + .cloned() + .collect() +} + +enum FieldAttr { + Default, + Value(proc_macro2::TokenStream), +} + +impl FieldAttr { + pub fn as_tokens(&self) -> proc_macro2::TokenStream { + match *self { + FieldAttr::Default => { + if cfg!(feature = "std") { + my_quote!(::std::default::Default::default()) + } else { + my_quote!(::core::default::Default::default()) + } + } + FieldAttr::Value(ref s) => my_quote!(#s), + } + } + + pub fn parse(attrs: &[syn::Attribute]) -> Option<FieldAttr> { + use syn::{AttrStyle, Meta, NestedMeta}; + + let mut result = None; + for attr in attrs.iter() { + match attr.style { + AttrStyle::Outer => {} + _ => continue, + } + let last_attr_path = attr + .path + .segments + .iter() + .last() + .expect("Expected at least one segment where #[segment[::segment*](..)]"); + if (*last_attr_path).ident != "new" { + continue; + } + let meta = match attr.parse_meta() { + Ok(meta) => meta, + Err(_) => continue, + }; + let list = match meta { + Meta::List(l) => l, + _ if meta.path().is_ident("new") => { + panic!("Invalid #[new] attribute, expected #[new(..)]") + } + _ => continue, + }; + if result.is_some() { + panic!("Expected at most one #[new] attribute"); + } + for item in list.nested.iter() { + match *item { + NestedMeta::Meta(Meta::Path(ref path)) => { + if path.is_ident("default") { + result = Some(FieldAttr::Default); + } else { + panic!("Invalid #[new] attribute: #[new({})]", path_to_string(&path)); + } + } + NestedMeta::Meta(Meta::NameValue(ref kv)) => { + if let syn::Lit::Str(ref s) = kv.lit { + if kv.path.is_ident("value") { + let tokens = s.value().parse().ok().expect(&format!( + "Invalid expression in #[new]: `{}`", + s.value() + )); + result = Some(FieldAttr::Value(tokens)); + } else { + panic!("Invalid #[new] attribute: #[new({} = ..)]", path_to_string(&kv.path)); + } + } else { + panic!("Non-string literal value in #[new] attribute"); + } + } + NestedMeta::Meta(Meta::List(ref l)) => { + panic!("Invalid #[new] attribute: #[new({}(..))]", path_to_string(&l.path)); + } + NestedMeta::Lit(_) => { + panic!("Invalid #[new] attribute: literal value in #[new(..)]"); + } + } + } + } + result + } +} + +struct FieldExt<'a> { + ty: &'a syn::Type, + attr: Option<FieldAttr>, + ident: syn::Ident, + named: bool, +} + +impl<'a> FieldExt<'a> { + pub fn new(field: &'a syn::Field, idx: usize, named: bool) -> FieldExt<'a> { + FieldExt { + ty: &field.ty, + attr: FieldAttr::parse(&field.attrs), + ident: if named { + field.ident.clone().unwrap() + } else { + syn::Ident::new(&format!("f{}", idx), proc_macro2::Span::call_site()) + }, + named: named, + } + } + + pub fn has_attr(&self) -> bool { + self.attr.is_some() + } + + pub fn is_phantom_data(&self) -> bool { + match *self.ty { + syn::Type::Path(syn::TypePath { + qself: None, + ref path, + }) => path + .segments + .last() + .map(|x| x.ident == "PhantomData") + .unwrap_or(false), + _ => false, + } + } + + pub fn needs_arg(&self) -> bool { + !self.has_attr() && !self.is_phantom_data() + } + + pub fn as_arg(&self) -> proc_macro2::TokenStream { + let f_name = &self.ident; + let ty = &self.ty; + my_quote!(#f_name: #ty) + } + + pub fn as_init(&self) -> proc_macro2::TokenStream { + let f_name = &self.ident; + let init = if self.is_phantom_data() { + if cfg!(feature = "std") { + my_quote!(::std::marker::PhantomData) + } else { + my_quote!(::core::marker::PhantomData) + } + } else { + match self.attr { + None => my_quote!(#f_name), + Some(ref attr) => attr.as_tokens(), + } + }; + if self.named { + my_quote!(#f_name: #init) + } else { + my_quote!(#init) + } + } +} + +fn to_snake_case(s: &str) -> String { + let (ch, next, mut acc): (Option<char>, Option<char>, String) = + s.chars() + .fold((None, None, String::new()), |(prev, ch, mut acc), next| { + if let Some(ch) = ch { + if let Some(prev) = prev { + if ch.is_uppercase() { + if prev.is_lowercase() + || prev.is_numeric() + || (prev.is_uppercase() && next.is_lowercase()) + { + acc.push('_'); + } + } + } + acc.extend(ch.to_lowercase()); + } + (ch, Some(next), acc) + }); + if let Some(next) = next { + if let Some(ch) = ch { + if (ch.is_lowercase() || ch.is_numeric()) && next.is_uppercase() { + acc.push('_'); + } + } + acc.extend(next.to_lowercase()); + } + acc +} + +#[test] +fn test_to_snake_case() { + assert_eq!(to_snake_case(""), ""); + assert_eq!(to_snake_case("a"), "a"); + assert_eq!(to_snake_case("B"), "b"); + assert_eq!(to_snake_case("BC"), "bc"); + assert_eq!(to_snake_case("Bc"), "bc"); + assert_eq!(to_snake_case("bC"), "b_c"); + assert_eq!(to_snake_case("Fred"), "fred"); + assert_eq!(to_snake_case("CARGO"), "cargo"); + assert_eq!(to_snake_case("_Hello"), "_hello"); + assert_eq!(to_snake_case("QuxBaz"), "qux_baz"); + assert_eq!(to_snake_case("FreeBSD"), "free_bsd"); + assert_eq!(to_snake_case("specialK"), "special_k"); + assert_eq!(to_snake_case("hello1World"), "hello1_world"); + assert_eq!(to_snake_case("Keep_underscore"), "keep_underscore"); + assert_eq!(to_snake_case("ThisISNotADrill"), "this_is_not_a_drill"); +} diff --git a/vendor/derive-new/tests/test.rs b/vendor/derive-new/tests/test.rs new file mode 100644 index 000000000..36f06e6ff --- /dev/null +++ b/vendor/derive-new/tests/test.rs @@ -0,0 +1,361 @@ +#![deny(non_snake_case)] + +#[macro_use] +extern crate derive_new; + +use std::default::Default; +use std::fmt::Debug; +use std::marker::PhantomData; + +/// A struct with no fields. +#[derive(new, PartialEq, Debug)] +pub struct Foo {} + +#[test] +fn test_empty_struct() { + let x = Foo::new(); + assert_eq!(x, Foo {}); +} + +/// A unit struct. +#[derive(new, PartialEq, Debug)] +pub struct Baz; + +#[test] +fn test_unit_struct() { + let x = Baz::new(); + assert_eq!(x, Baz); +} + +/// A struct with fields. +#[derive(new, PartialEq, Debug)] +pub struct Bar { + pub x: i32, + pub y: String, +} + +#[test] +fn test_simple_struct() { + let x = Bar::new(42, "Hello".to_owned()); + assert_eq!( + x, + Bar { + x: 42, + y: "Hello".to_owned() + } + ); +} + +/// A struct with a lifetime parameter. +#[derive(new, PartialEq, Debug)] +pub struct Intersection<'scene> { + pub object: &'scene Bar, + pub normal: Foo, + pub point: Foo, + pub t: f64, +} + +#[test] +fn test_struct_with_lifetime() { + let b = Bar::new(42, "Hello".to_owned()); + let x = Intersection::new(&b, Foo::new(), Foo::new(), 42.0); + assert_eq!( + x, + Intersection { + object: &b, + normal: Foo {}, + point: Foo {}, + t: 42.0 + } + ); +} + +/// A struct with generics and bounds. +#[derive(new, PartialEq, Debug)] +pub struct Qux<T: Debug + PartialEq, U: Debug + PartialEq> { + pub f1: T, + pub f2: Vec<U>, + pub f3: i32, +} + +#[test] +fn test_struct_with_bounds() { + let x = Qux::new("Hello!", Vec::<String>::new(), 42); + assert_eq!( + x, + Qux { + f1: "Hello!", + f2: vec![], + f3: 42 + } + ); + + let x: Qux<&'static str, String> = Qux::new("Hello!", Vec::<String>::new(), 42); + assert_eq!( + x, + Qux { + f1: "Hello!", + f2: vec![], + f3: 42 + } + ); + + let x = Qux::<_, String>::new("Hello!", vec![], 42); + assert_eq!( + x, + Qux { + f1: "Hello!", + f2: vec![], + f3: 42 + } + ); +} + +/// A struct with a lifetime parameter, generics and bounds. +#[derive(new, PartialEq, Debug)] +pub struct FooBar<'a, T, U> +where + T: 'a + PartialEq + Debug, + U: Sized + Send + 'a + PartialEq + Debug, +{ + pub f1: Box<T>, + pub f2: Vec<&'a U>, + pub f3: i32, +} + +#[test] +fn test_struct_lifetime_bounds() { + let a = 42; + let x = FooBar::new(Box::new("Hello".to_owned()), vec![&a], 42); + assert_eq!( + x, + FooBar { + f1: Box::new("Hello".to_owned()), + f2: vec![&a], + f3: 42 + } + ); +} + +/// A tuple struct. +#[derive(new, PartialEq, Debug)] +pub struct Tuple(pub i32, pub i32); + +#[test] +fn test_simple_tuple_struct() { + let x = Tuple::new(5, 6); + assert_eq!(x, Tuple(5, 6)); +} + +/// A tuple struct with a lifetime parameter. +#[derive(new, PartialEq, Debug)] +pub struct TupleWithLifetime<'a>(pub &'a str); + +#[test] +fn test_tuple_struct_lifetime() { + let x = TupleWithLifetime::new("Hello"); + assert_eq!(x, TupleWithLifetime("Hello")); +} + +/// A struct where fields have default values. +#[derive(new, PartialEq, Debug)] +pub struct Waldo<T: PartialEq + Debug + Default> { + #[new(default)] + pub x: i32, + pub y: u8, + #[new(default)] + pub z: T, +} + +#[test] +fn test_struct_with_defaults() { + let x = Waldo::<Vec<String>>::new(42); + assert_eq!( + x, + Waldo { + x: 0, + y: 42, + z: vec![] + } + ); +} + +/// A struct where fields have explicitly provided defaults. +#[derive(new, PartialEq, Debug)] +pub struct Fred { + #[new(value = "1 + 2")] + pub x: i32, + pub y: String, + #[new(value = "vec![-42, 42]")] + pub z: Vec<i8>, +} + +#[test] +fn test_struct_with_values() { + let x = Fred::new("Fred".to_owned()); + assert_eq!( + x, + Fred { + x: 3, + y: "Fred".to_owned(), + z: vec![-42, 42] + } + ); +} + +/// A struct with defaults and specified values. +#[derive(new, PartialEq, Debug)] +pub struct Thud { + #[new(value = r#""Thud".to_owned()"#)] + pub x: String, + #[new(default)] + pub y: String, +} + +#[test] +fn test_struct_mixed_defaults() { + let x = Thud::new(); + assert_eq!( + x, + Thud { + x: "Thud".to_owned(), + y: String::new() + } + ); +} + +/// A generic struct with PhantomData member. +#[derive(new, PartialEq, Debug)] +pub struct Bob<T: PartialEq + Debug> { + pub a: i32, + pub b: PhantomData<T>, +} + +#[test] +fn test_struct_phantom_data() { + let x = Bob::<i32>::new(42); + assert_eq!( + x, + Bob { + a: 42, + b: PhantomData + } + ); +} + +/// A tuple struct where fields have default values. +#[derive(new, PartialEq, Debug)] +pub struct Boom<T: PartialEq + Debug + Default>( + #[new(default)] pub i32, + pub u8, + #[new(default)] pub T, +); + +#[test] +fn test_tuple_with_defaults() { + let x = Boom::<Vec<String>>::new(42); + assert_eq!(x, Boom(0, 42, vec![])); +} + +/// A tuple struct where fields have explicitly provided defaults. +#[derive(new, PartialEq, Debug)] +pub struct Moog( + #[new(value = "1 + 2")] pub i32, + pub String, + #[new(value = "vec![-42, 42]")] pub Vec<i8>, +); + +#[test] +fn test_tuple_with_values() { + let x = Moog::new("Fred".to_owned()); + assert_eq!(x, Moog(3, "Fred".to_owned(), vec![-42, 42])); +} + +/// A tuple struct with defaults and specified values. +#[derive(new, PartialEq, Debug)] +pub struct Crab( + #[new(value = r#""Thud".to_owned()"#)] pub String, + #[new(default)] pub String, +); + +#[test] +fn test_tuple_mixed_defaults() { + let x = Crab::new(); + assert_eq!(x, Crab("Thud".to_owned(), String::new())); +} + +/// A generic tuple struct with PhantomData member. +#[derive(new, PartialEq, Debug)] +pub struct Sponge<T: PartialEq + Debug>(pub i32, pub PhantomData<T>); + +#[test] +fn test_tuple_phantom_data() { + let x = Sponge::<i32>::new(42); + assert_eq!(x, Sponge(42, PhantomData)); +} + +/// An enum with unit variants +#[derive(new, PartialEq, Debug)] +pub enum Fizz { + ThisISNotADrill, + BiteMe, +} + +#[test] +fn test_enum_unit_variants() { + let x = Fizz::new_this_is_not_a_drill(); + assert_eq!(x, Fizz::ThisISNotADrill); + + let x = Fizz::new_bite_me(); + assert_eq!(x, Fizz::BiteMe); +} + +/// A more involved enum +#[derive(new, PartialEq, Debug)] +pub enum Enterprise<T: PartialEq + Debug + Default> { + Picard, + Data( + #[new(value = "\"fascinating\".to_owned()")] String, + #[new(default)] T, + ), + Spock { + x: PhantomData<T>, + y: i32, + }, +} + +#[test] +fn test_more_involved_enum() { + let x = Enterprise::<u8>::new_picard(); + assert_eq!(x, Enterprise::Picard); + + let x = Enterprise::<u8>::new_data(); + assert_eq!(x, Enterprise::Data("fascinating".to_owned(), 0u8)); + + let x = Enterprise::<u8>::new_spock(42); + assert_eq!( + x, + Enterprise::Spock { + x: PhantomData, + y: 42 + } + ); +} + +#[allow(non_snake_case)] +#[derive(new, PartialEq, Debug)] +pub struct Upside { + X: i32, +} + +#[cfg_attr(test, allow(non_snake_case))] +#[derive(new, PartialEq, Debug)] +pub struct Down { + X: i32, +} + +#[derive(new, PartialEq, Debug)] +pub struct All { + #[allow(missing_docs)] + pub x: i32, +} |