├── .gitignore ├── doc ├── debug-transparent.rs ├── styles │ └── website.css ├── debug-transparent-orig.rs ├── default-enum.rs ├── default-enum-orig.rs ├── custom.css ├── default-value.rs ├── default-value-orig.rs ├── eq-ignore.rs ├── eq-ignore-orig.rs ├── SUMMARY.md ├── Clone.md ├── Hash.md ├── README.md ├── Default.md ├── cmp.md └── Debug.md ├── tests ├── issue-67.rs ├── compile-fail │ ├── derive-partial-ord.rs │ ├── derive-partial-ord.stderr │ ├── derive-debug-unused.stderr │ ├── derive-debug.rs │ ├── unknown-attribute.rs │ ├── derive-debug-unused.rs │ ├── unknown-attribute.stderr │ ├── unknown-derive.rs │ ├── invalid-attribute.rs │ ├── derive-debug.stderr │ ├── unknown-derive.stderr │ └── invalid-attribute.stderr ├── clippy-warning-clone-from.rs ├── issue-82.rs ├── issue-37-turbofish.rs ├── compile-test.rs ├── issue-58.rs ├── issue-57.rs ├── issue-55.rs ├── derive-clone-generics.rs ├── rustc-deriving-bounds.rs ├── rustc-issue-23649-3.rs ├── rustc-issue-42453.rs ├── rustc-deriving-clone-tuple-struct.rs ├── rustc-issue-19102.rs ├── rustc-issue-25394.rs ├── rustc-deriving-clone-array.rs ├── rustc-deriving-clone-generic-tuple-struct.rs ├── rustc-deriving-in-fn.rs ├── rustc-issue-32292.rs ├── rustc-issue-21402.rs ├── rustc-issue-29710.rs ├── rustc-issue-6341.rs ├── rustc-issue-29030.rs ├── rustc-deriving-clone-generic-enum.rs ├── rustc-deriving-clone-enum.rs ├── rustc-issue-3935.rs ├── rustc-deriving-enum-single-variant.rs ├── rustc-deriving-default-box.rs ├── derive-debug-transparent.rs ├── rustc-deriving-via-extension-hash-enum.rs ├── rustc-expr-copy.rs ├── rustc-issue-19135.rs ├── rustc-issue-16530.rs ├── rustc-deriving-via-extension-type-params.rs ├── rustc-deriving-via-extension-hash-struct.rs ├── rustc-issue-19037.rs ├── rustc-issue-19358.rs ├── rustc-issue-13434.rs ├── rustc-deriving-clone-struct.rs ├── derive-eq.rs ├── derive-default-bounds.rs ├── rustc-deriving-meta.rs ├── rustc-issue-24085.rs ├── rustc-exterior.rs ├── rustc-deriving-meta-multiple.rs ├── rustc-zero-sized-btreemap-insert.rs ├── rustc-deriving-show.rs ├── derive-eq-packed.rs ├── rustc-deriving-cmp-generic-tuple-struct.rs ├── rustc-deriving-cmp-generic-struct.rs ├── derive-debug-packed.rs ├── derive-clone.rs ├── derive-debug.rs ├── rustc-deriving-cmp-generic-enum.rs ├── rustc-deriving-cmp-generic-struct-enum.rs ├── rustc-deriving-copyclone.rs ├── derive-default.rs ├── rustc-deriving-show-2.rs ├── rustc-issue-12860.rs ├── derive-debug-bounds.rs ├── rustc-deriving-hash.rs ├── derive-debug-generics.rs ├── derive-partial-eq-packed.rs ├── derive-hash.rs ├── rustc-issue-28561.rs ├── derive-partial-eq.rs ├── derive-ord-packed.rs ├── derive-ord.rs └── rustc-issue-58319.rs ├── book.toml ├── src ├── paths.rs ├── utils.rs ├── hash.rs ├── lib.rs ├── default.rs ├── ast.rs ├── bound.rs ├── clone.rs └── debug.rs ├── CONTRIBUTING.md ├── .github ├── workflows │ ├── coverage.yml │ ├── doc.yml │ └── main.yml └── ISSUE_TEMPLATE │ └── bug_report.md ├── Cargo.toml ├── LICENSE-MIT ├── README.md ├── CHANGELOG.md └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | /book 4 | /node_modules 5 | -------------------------------------------------------------------------------- /doc/debug-transparent.rs: -------------------------------------------------------------------------------- 1 | # extern crate derivative; 2 | # use derivative::Derivative; 3 | #[derive(Derivative)] 4 | #[derivative(Debug="transparent")] 5 | pub struct Wrapping(pub T); -------------------------------------------------------------------------------- /doc/styles/website.css: -------------------------------------------------------------------------------- 1 | code .hljs-meta { 2 | color: #969896 3 | } 4 | 5 | code .hljs-meta-string { 6 | color: #183691 7 | } 8 | 9 | code .hljs-title { 10 | color: #a71d5d !important 11 | } 12 | -------------------------------------------------------------------------------- /doc/debug-transparent-orig.rs: -------------------------------------------------------------------------------- 1 | # use std::fmt; 2 | pub struct Wrapping(pub T); 3 | 4 | impl fmt::Debug for Wrapping { 5 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 6 | self.0.fmt(f) 7 | } 8 | } -------------------------------------------------------------------------------- /tests/issue-67.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Derivative)] 8 | #[derivative(Hash)] 9 | enum _Enumeration { 10 | _Variant(T), 11 | } -------------------------------------------------------------------------------- /tests/compile-fail/derive-partial-ord.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate derivative; 3 | 4 | #[derive(Derivative, PartialEq)] 5 | #[derivative(PartialOrd)] 6 | enum Option { 7 | Some, 8 | None, 9 | } 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/clippy-warning-clone-from.rs: -------------------------------------------------------------------------------- 1 | #![deny(clippy::all)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | #[derive(Derivative)] 10 | #[derivative(Clone(clone_from = "true"))] 11 | pub struct Foo {} -------------------------------------------------------------------------------- /tests/issue-82.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Copy, Clone, Derivative)] 8 | #[derivative(Debug)] 9 | #[repr(C, packed)] 10 | struct Test { 11 | a: u8, 12 | b: u32, 13 | } -------------------------------------------------------------------------------- /doc/default-enum.rs: -------------------------------------------------------------------------------- 1 | # extern crate derivative; 2 | # use derivative::Derivative; 3 | #[derive(Derivative)] 4 | #[derivative(Default(bound=""))] 5 | pub enum Option { 6 | #[derivative(Default)] 7 | /// No value 8 | None, 9 | /// Some value `T` 10 | Some(T), 11 | } -------------------------------------------------------------------------------- /tests/compile-fail/derive-partial-ord.stderr: -------------------------------------------------------------------------------- 1 | error: can't use `#[derivative(PartialOrd)]` on an enumeration without `feature_allow_slow_enum`; see the documentation for more details 2 | --> $DIR/derive-partial-ord.rs:5:1 3 | | 4 | 5 | #[derivative(PartialOrd)] 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/issue-37-turbofish.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Derivative)] 8 | #[derivative(Debug)] 9 | pub struct A { 10 | #[derivative(Debug(format_with = "std::fmt::Debug::fmt"))] 11 | v: u64, 12 | } 13 | -------------------------------------------------------------------------------- /tests/compile-test.rs: -------------------------------------------------------------------------------- 1 | extern crate trybuild; 2 | 3 | #[test] 4 | #[ignore] 5 | fn compile_test() { 6 | let t = trybuild::TestCases::new(); 7 | let pattern = std::env::var("DERIVATIVE_TEST_FILTER").unwrap_or_else(|_| String::from("*.rs")); 8 | t.compile_fail(format!("tests/compile-fail/{}", pattern)); 9 | } 10 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | title = "Derivative" 3 | src = "doc" 4 | 5 | [rust] 6 | edition = "2018" 7 | 8 | [build] 9 | create-missing = false 10 | 11 | [output.html.search] 12 | limit-results = 15 13 | 14 | [output.html] 15 | additional-css = ["doc/custom.css"] 16 | git-repository-url = "https://github.com/mcarton/rust-derivative" -------------------------------------------------------------------------------- /tests/compile-fail/derive-debug-unused.stderr: -------------------------------------------------------------------------------- 1 | error: field is never used: `bar` 2 | --> $DIR/derive-debug-unused.rs:14:5 3 | | 4 | 14 | bar: u8, 5 | | ^^^^^^^ 6 | | 7 | note: lint level defined here 8 | --> $DIR/derive-debug-unused.rs:1:9 9 | | 10 | 1 | #![deny(dead_code)] 11 | | ^^^^^^^^^ 12 | -------------------------------------------------------------------------------- /tests/compile-fail/derive-debug.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Derivative)] 8 | #[derivative(Debug)] 9 | struct Foo { 10 | foo: T, 11 | #[derivative(Debug(format_with="std::fmt::Debug::fmt"))] 12 | bar: U, 13 | } 14 | 15 | fn main() {} -------------------------------------------------------------------------------- /tests/compile-fail/unknown-attribute.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Derivative)] 8 | #[derivative(Clone = "does_not_exist")] 9 | struct Foo; 10 | 11 | #[derive(Derivative)] 12 | #[derivative(Clone(does_not_exist = "true"))] 13 | struct Bar; 14 | 15 | fn main() {} -------------------------------------------------------------------------------- /src/paths.rs: -------------------------------------------------------------------------------- 1 | //! Contains some standard paths. 2 | 3 | /// Return the path of the `discriminant` function, that is `::std::mem::discriminant`. 4 | pub fn discriminant_path() -> syn::Path { 5 | if cfg!(feature = "use_core") { 6 | parse_quote!(::core::mem::discriminant) 7 | } else { 8 | parse_quote!(::std::mem::discriminant) 9 | } 10 | } -------------------------------------------------------------------------------- /tests/issue-58.rs: -------------------------------------------------------------------------------- 1 | #![deny(clippy::all)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | #[derive(Default, Derivative)] 10 | #[derivative(Debug)] 11 | pub struct Foo { 12 | foo: u8, 13 | } 14 | 15 | #[test] 16 | fn main() { 17 | let foo1 = Foo::default(); 18 | println!("foo = {:?}", foo1); 19 | } 20 | -------------------------------------------------------------------------------- /tests/compile-fail/derive-debug-unused.rs: -------------------------------------------------------------------------------- 1 | #![deny(dead_code)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | #[derive(Derivative)] 10 | #[derivative(Debug)] 11 | struct Foo { 12 | foo: u8, 13 | #[derivative(Debug="ignore")] 14 | bar: u8, 15 | } 16 | 17 | fn main() { 18 | let _ = Foo { foo: 42, bar: 1 }; 19 | } -------------------------------------------------------------------------------- /doc/default-enum-orig.rs: -------------------------------------------------------------------------------- 1 | # #![no_implicit_prelude] 2 | # extern crate core; 3 | # use core::default::Default; 4 | # use Option::None; 5 | # 6 | pub enum Option { 7 | /// No value 8 | None, 9 | /// Some value `T` 10 | Some(T), 11 | } 12 | 13 | impl Default for Option { 14 | /// Returns None. 15 | #[inline] 16 | fn default() -> Option { 17 | None 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/issue-57.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | macro_rules! gen { 8 | ($name:ident) => { 9 | #[derive(Derivative)] 10 | #[derivative(Debug)] 11 | pub struct $name { 12 | a: i32 13 | } 14 | }; 15 | } 16 | 17 | gen!(Test); 18 | 19 | #[test] 20 | fn call_it() { 21 | println!("{:?}", Test { a: 42 }); 22 | } -------------------------------------------------------------------------------- /tests/issue-55.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | trait Foo {} 8 | 9 | fn fmt(_: &T, _: &mut std::fmt::Formatter) -> std::fmt::Result { 10 | unimplemented!() 11 | } 12 | 13 | #[derive(Debug)] 14 | struct Qux<'a, T: Foo>(&'a T); 15 | 16 | #[derive(Derivative)] 17 | #[derivative(Debug)] 18 | struct _Bar<'a, T: Foo>(#[derivative(Debug(format_with="fmt"))] Qux<'a, T>); -------------------------------------------------------------------------------- /tests/compile-fail/unknown-attribute.stderr: -------------------------------------------------------------------------------- 1 | error: Unknown attribute `does_not_exist` for trait `Clone` 2 | --> $DIR/unknown-attribute.rs:8:22 3 | | 4 | 8 | #[derivative(Clone = "does_not_exist")] 5 | | ^^^^^^^^^^^^^^^^ 6 | 7 | error: Unknown attribute `does_not_exist` for trait `Clone` 8 | --> $DIR/unknown-attribute.rs:12:20 9 | | 10 | 12 | #[derivative(Clone(does_not_exist = "true"))] 11 | | ^^^^^^^^^^^^^^ 12 | -------------------------------------------------------------------------------- /tests/compile-fail/unknown-derive.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Derivative)] 8 | #[derivative(DoesNotExist1)] 9 | struct Foo; 10 | 11 | #[derive(Derivative)] 12 | #[derivative(DoesNotExist2(with_some="argument"))] 13 | struct Bar; 14 | 15 | #[derive(Derivative)] 16 | #[derivative(Debug)] 17 | struct Baz { 18 | #[derivative(DoesNotExist3)] 19 | _baz: (), 20 | } 21 | 22 | fn main() {} -------------------------------------------------------------------------------- /doc/custom.css: -------------------------------------------------------------------------------- 1 | #content > main > table { 2 | position: relative; 3 | left: 50%; 4 | transform: translateX(-50%); 5 | 6 | margin-left: 0px; 7 | margin-right: 0px; 8 | } 9 | 10 | #content > main > table td { 11 | vertical-align: top; 12 | } 13 | 14 | #content > main > table .hljs { 15 | background: none; 16 | } 17 | 18 | .readme-example { 19 | background: #f1f1f1; 20 | } 21 | 22 | table .readme-example > td { 23 | border: 1px hsl(0, 0%, 0%) solid; 24 | } -------------------------------------------------------------------------------- /tests/compile-fail/invalid-attribute.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Derivative)] 8 | #[derivative(Clone = not_a_string)] 9 | struct Foo1; 10 | 11 | #[derive(Derivative)] 12 | #[derivative(Clone = 1+2)] 13 | struct Foo2; 14 | 15 | #[derive(Derivative)] 16 | #[derivative(Default(new = "True"))] 17 | struct Foo3; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Debug(bound))] 21 | struct Foo4; 22 | 23 | fn main() {} -------------------------------------------------------------------------------- /tests/compile-fail/derive-debug.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: `U` doesn't implement `std::fmt::Debug` 2 | --> $DIR/derive-debug.rs:11:36 3 | | 4 | 11 | #[derivative(Debug(format_with="std::fmt::Debug::fmt"))] 5 | | ^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` 6 | | 7 | = help: the trait `std::fmt::Debug` is not implemented for `U` 8 | = help: consider adding a `where U: std::fmt::Debug` bound 9 | = note: required by `std::fmt::Debug::fmt` 10 | -------------------------------------------------------------------------------- /doc/default-value.rs: -------------------------------------------------------------------------------- 1 | # extern crate derivative; 2 | # use derivative::Derivative; 3 | #[derive(Derivative)] 4 | #[derivative(Default)] 5 | pub struct RegexOptions { 6 | pub pats: Vec, 7 | #[derivative(Default(value="10 * (1 << 20)"))] 8 | pub size_limit: usize, 9 | #[derivative(Default(value="2 * (1 << 20)"))] 10 | pub dfa_size_limit: usize, 11 | pub case_insensitive: bool, 12 | pub multi_line: bool, 13 | pub dot_matches_new_line: bool, 14 | pub swap_greed: bool, 15 | pub ignore_whitespace: bool, 16 | #[derivative(Default(value="true"))] 17 | pub unicode: bool, 18 | } -------------------------------------------------------------------------------- /tests/compile-fail/unknown-derive.stderr: -------------------------------------------------------------------------------- 1 | error: deriving `DoesNotExist1` is not supported by derivative 2 | --> $DIR/unknown-derive.rs:8:14 3 | | 4 | 8 | #[derivative(DoesNotExist1)] 5 | | ^^^^^^^^^^^^^ 6 | 7 | error: deriving `DoesNotExist2` is not supported by derivative 8 | --> $DIR/unknown-derive.rs:12:14 9 | | 10 | 12 | #[derivative(DoesNotExist2(with_some="argument"))] 11 | | ^^^^^^^^^^^^^ 12 | 13 | error: deriving `DoesNotExist3` is not supported by derivative 14 | --> $DIR/unknown-derive.rs:18:18 15 | | 16 | 18 | #[derivative(DoesNotExist3)] 17 | | ^^^^^^^^^^^^^ 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributions are welcome! 2 | 3 | There are several ways you can contribute: 4 | 5 | * Submit ideas and feature requests on the [issue tracker]. 6 | * File bug reports on the [issue tracker]. Include as much details as you can 7 | and, ideally, a self-contained example if you can make one. 8 | * Improve the [documentation]. It consists of markdown files in the [doc](doc) 9 | directory. It uses [mdBook] to generate the website. 10 | * Implement something, fix bugs, etc. You know the deal. 11 | 12 | [documentation]: https://mcarton.github.io/rust-derivative/ 13 | [mdBook]: https://rust-lang.github.io/mdBook/ 14 | [issue tracker]: https://github.com/mcarton/rust-derivative/issues 15 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | on: [push] 2 | 3 | name: Test coverage 4 | 5 | jobs: 6 | test: 7 | name: coverage 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions-rs/toolchain@v1 11 | with: 12 | profile: minimal 13 | toolchain: stable 14 | override: true 15 | - run: cargo install cargo-tarpaulin 16 | - name: Checkout repository 17 | uses: actions/checkout@v2 18 | - name: Generate code coverage 19 | run: cargo tarpaulin --verbose --exclude-files doc --exclude-files book --out Xml 20 | - name: Upload to codecov.io 21 | uses: codecov/codecov-action@v1 22 | with: 23 | fail_ci_if_error: true -------------------------------------------------------------------------------- /tests/compile-fail/invalid-attribute.stderr: -------------------------------------------------------------------------------- 1 | error: invalid attribute: expected literal 2 | --> $DIR/invalid-attribute.rs:8:22 3 | | 4 | 8 | #[derivative(Clone = not_a_string)] 5 | | ^^^^^^^^^^^^ 6 | 7 | error: invalid attribute: expected `,` 8 | --> $DIR/invalid-attribute.rs:12:23 9 | | 10 | 12 | #[derivative(Clone = 1+2)] 11 | | ^ 12 | 13 | error: expected `"true"` or `"false"` for `new`, got `True` 14 | --> $DIR/invalid-attribute.rs:16:28 15 | | 16 | 16 | #[derivative(Default(new = "True"))] 17 | | ^^^^^^ 18 | 19 | error: expected named value 20 | --> $DIR/invalid-attribute.rs:20:20 21 | | 22 | 20 | #[derivative(Debug(bound))] 23 | | ^^^^^ 24 | -------------------------------------------------------------------------------- /tests/derive-clone-generics.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | use std::marker::PhantomData; 8 | 9 | struct NoClone; 10 | 11 | #[derive(Derivative)] 12 | #[derivative(Clone, PartialEq)] 13 | struct PhantomField { 14 | foo: PhantomData, 15 | } 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Clone, PartialEq)] 19 | struct PhantomTuple { 20 | foo: PhantomData<(T,)>, 21 | } 22 | 23 | #[test] 24 | fn main() { 25 | let phantom_field = PhantomField:: { foo: Default::default() }; 26 | let phantom_tuple = PhantomTuple:: { foo: Default::default() }; 27 | assert!(phantom_field == phantom_field.clone()); 28 | assert!(phantom_tuple == phantom_tuple.clone()); 29 | } 30 | -------------------------------------------------------------------------------- /tests/rustc-deriving-bounds.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Copy, Clone)] 19 | struct Test; 20 | 21 | #[test] 22 | fn main() { 23 | let _ = Test; 24 | } 25 | -------------------------------------------------------------------------------- /tests/rustc-issue-23649-3.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[allow(dead_code)] 18 | #[derive(Derivative)] 19 | #[derivative(PartialEq)] 20 | struct Slice { slice: [u8] } 21 | 22 | #[test] 23 | fn main() {} 24 | -------------------------------------------------------------------------------- /tests/rustc-issue-42453.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![deny(warnings)] 12 | 13 | #![allow(dead_code)] 14 | #![allow(non_camel_case_types)] 15 | 16 | #[cfg(feature = "use_core")] 17 | extern crate core; 18 | 19 | #[macro_use] 20 | extern crate derivative; 21 | 22 | #[derive(Derivative)] 23 | #[derivative(Debug)] 24 | struct builder; -------------------------------------------------------------------------------- /tests/rustc-deriving-clone-tuple-struct.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Clone)] 21 | struct S((), ()); 22 | 23 | #[test] 24 | fn main() {} 25 | -------------------------------------------------------------------------------- /doc/default-value-orig.rs: -------------------------------------------------------------------------------- 1 | pub struct RegexOptions { 2 | pub pats: Vec, 3 | pub size_limit: usize, 4 | pub dfa_size_limit: usize, 5 | pub case_insensitive: bool, 6 | pub multi_line: bool, 7 | pub dot_matches_new_line: bool, 8 | pub swap_greed: bool, 9 | pub ignore_whitespace: bool, 10 | pub unicode: bool, 11 | } 12 | 13 | impl Default for RegexOptions { 14 | fn default() -> Self { 15 | RegexOptions { 16 | pats: vec![], 17 | size_limit: 10 * (1 << 20), 18 | dfa_size_limit: 2 * (1 << 20), 19 | case_insensitive: false, 20 | multi_line: false, 21 | dot_matches_new_line: false, 22 | swap_greed: false, 23 | ignore_whitespace: false, 24 | unicode: true, 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /tests/rustc-issue-19102.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![deny(unused_qualifications)] 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(PartialEq="feature_allow_slow_enum")] 21 | pub enum A { 22 | B, 23 | } 24 | 25 | #[test] 26 | fn main() {} 27 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "derivative" 3 | version = "2.2.0" 4 | authors = ["mcarton "] 5 | license = "MIT/Apache-2.0" 6 | readme = "README.md" 7 | documentation = "https://mcarton.github.io/rust-derivative/" 8 | repository = "https://github.com/mcarton/rust-derivative" 9 | description = "A set of alternative `derive` attributes for Rust" 10 | keywords = ["derive", "macro", "macro1-1", "plugin"] 11 | categories = ["rust-patterns"] 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [dependencies] 17 | proc-macro2 = "1.0" 18 | quote = "1.0" 19 | syn = { version = "1.0.3", features = ["visit", "extra-traits"] } 20 | 21 | [dev-dependencies] 22 | # 1.0.23 requires rustc 1.36, while our msrv is 1.34 23 | runtime-macros-derive = "0.4.0" 24 | trybuild = "1.0.18, <1.0.23" 25 | walkdir = "2" 26 | 27 | [features] 28 | use_core = [] 29 | -------------------------------------------------------------------------------- /tests/rustc-issue-25394.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Debug)] 19 | struct Row([T]); 20 | 21 | #[cfg(not(tarpaulin_include))] 22 | fn use_row(_: &Row) {} 23 | 24 | #[test] 25 | fn main() { 26 | let _ = use_row; 27 | } 28 | -------------------------------------------------------------------------------- /tests/rustc-deriving-clone-array.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // test for issue #30244 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Copy, Clone)] 21 | #[allow(dead_code)] 22 | struct Array { 23 | arr: [[u8; 256]; 4] 24 | } 25 | 26 | #[test] 27 | fn main() {} 28 | -------------------------------------------------------------------------------- /tests/rustc-deriving-clone-generic-tuple-struct.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Clone)] 21 | struct S(T, ()); 22 | 23 | #[test] 24 | fn main() { 25 | let _ = S(1, ()).clone(); 26 | } 27 | -------------------------------------------------------------------------------- /tests/rustc-deriving-in-fn.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[test] 18 | fn main() { 19 | #[derive(Derivative)] 20 | #[derivative(Debug)] 21 | struct Foo { 22 | foo: isize, 23 | } 24 | 25 | let f = Foo { foo: 10 }; 26 | format!("{:?}", f); 27 | } 28 | -------------------------------------------------------------------------------- /tests/rustc-issue-32292.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![deny(warnings)] 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Hash, Eq, PartialEq, Debug, Clone, Copy)] 21 | // TODO: Ord, PartialOrd 22 | struct Foo; 23 | 24 | #[test] 25 | fn main() { 26 | let _ = Foo; 27 | } 28 | -------------------------------------------------------------------------------- /tests/rustc-issue-21402.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Hash)] 21 | #[allow(dead_code)] 22 | struct Foo { 23 | a: Vec, 24 | b: (bool, bool), 25 | c: [bool; 2], 26 | } 27 | 28 | #[test] 29 | fn main() {} 30 | -------------------------------------------------------------------------------- /tests/rustc-issue-29710.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![deny(unused_results)] 12 | #![allow(dead_code)] 13 | 14 | #[cfg(feature = "use_core")] 15 | extern crate core; 16 | 17 | #[macro_use] 18 | extern crate derivative; 19 | 20 | #[derive(Derivative)] 21 | #[derivative(Debug)] 22 | struct A(usize); 23 | 24 | #[derive(Derivative)] 25 | #[derivative(Debug)] 26 | struct B { a: usize } 27 | 28 | #[test] 29 | fn main() {} 30 | -------------------------------------------------------------------------------- /tests/rustc-issue-6341.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(PartialEq)] 21 | struct A { x: usize } 22 | 23 | impl Drop for A { 24 | fn drop(&mut self) {} 25 | } 26 | 27 | #[test] 28 | fn main() { 29 | A { x: 42 }; 30 | } 31 | -------------------------------------------------------------------------------- /doc/eq-ignore.rs: -------------------------------------------------------------------------------- 1 | # extern crate derivative; 2 | # use derivative::Derivative; 3 | # #[derive(PartialEq, Hash)] 4 | # struct Identifier; 5 | #[derive(Derivative)] 6 | #[derivative(PartialEq, Hash)] 7 | pub struct Version { 8 | /// The major version. 9 | pub major: u64, 10 | /// The minor version. 11 | pub minor: u64, 12 | /// The patch version. 13 | pub patch: u64, 14 | /// The pre-release version identifier. 15 | pub pre: Vec, 16 | // We should ignore build metadata 17 | // here, otherwise versions v1 and 18 | // v2 can exist such that !(v1 < v2) 19 | // && !(v1 > v2) && v1 != v2, which 20 | // violate strict total ordering rules. 21 | #[derivative(PartialEq="ignore")] 22 | #[derivative(Hash="ignore")] 23 | /// The build metadata, ignored when 24 | /// determining version precedence. 25 | pub build: Vec, 26 | } -------------------------------------------------------------------------------- /tests/rustc-issue-29030.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Debug)] 19 | struct Message<'a, P: 'a = &'a [u8]> { 20 | header: &'a [u8], 21 | payload: P, 22 | } 23 | 24 | #[test] 25 | fn main() { 26 | let _ = Message { 27 | header: &[1], 28 | payload: &[1], 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /tests/rustc-deriving-clone-generic-enum.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Clone)] 21 | #[allow(dead_code)] 22 | enum E { 23 | A(T), 24 | B(T,U), 25 | C 26 | } 27 | 28 | #[test] 29 | fn main() { 30 | let _ = E::A::(1).clone(); 31 | } 32 | -------------------------------------------------------------------------------- /tests/rustc-deriving-clone-enum.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Clone)] 21 | enum E { 22 | A, 23 | B(()), 24 | C, 25 | } 26 | 27 | #[test] 28 | fn main() { 29 | let _ = E::A.clone(); 30 | let _ = E::B(()).clone(); 31 | let _ = E::C.clone(); 32 | } 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: Title (eg. attribute `X` does not work as expected on Mondays) 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Include minimum complete example reproducing the problem. 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Errors** 20 | Compiler error if relevant. 21 | 22 | **Version (please complete the following information):** 23 | 24 | Please include the output of the following commands, and any other version you think is relevant: 25 | 26 | ```sh 27 | rustup --version 28 | cargo --version 29 | rustc --version 30 | ``` 31 | - Version of `derivative`: [e.g. 1.0.3] 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /tests/rustc-issue-3935.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[derive(Derivative)] 18 | #[derivative(PartialEq)] 19 | struct Bike { 20 | name: String, 21 | } 22 | 23 | #[test] 24 | fn main() { 25 | let town_bike = Bike { name: "schwinn".to_string() }; 26 | let my_bike = Bike { name: "surly".to_string() }; 27 | 28 | assert!(town_bike != my_bike); 29 | } 30 | -------------------------------------------------------------------------------- /tests/rustc-deriving-enum-single-variant.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | pub type TaskId = isize; 20 | 21 | #[derive(Derivative)] 22 | #[derivative(PartialEq="feature_allow_slow_enum")] 23 | pub enum Task { 24 | TaskHandle(TaskId) 25 | } 26 | 27 | #[test] 28 | fn main() { 29 | let _ = Task::TaskHandle(42); 30 | } 31 | -------------------------------------------------------------------------------- /tests/rustc-deriving-default-box.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | use std::default::Default; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Default)] 21 | struct A { 22 | foo: Box<[bool]>, 23 | } 24 | 25 | #[test] 26 | fn main() { 27 | let a: A = Default::default(); 28 | let b: Box<[_]> = Box::<[bool; 0]>::new([]); 29 | assert_eq!(a.foo, b); 30 | } 31 | -------------------------------------------------------------------------------- /tests/derive-debug-transparent.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Derivative)] 8 | #[derivative(Debug="transparent")] 9 | struct A(isize); 10 | 11 | #[derive(Derivative)] 12 | #[derivative(Debug="transparent")] 13 | struct B([isize; 1]); 14 | 15 | #[derive(Derivative)] 16 | #[derivative(Debug)] 17 | enum C { 18 | Foo(u8), 19 | #[derivative(Debug="transparent")] 20 | Bar(u8), 21 | } 22 | 23 | trait ToDebug { 24 | fn to_show(&self) -> String; 25 | } 26 | 27 | impl ToDebug for T { 28 | fn to_show(&self) -> String { 29 | format!("{:?}", self) 30 | } 31 | } 32 | 33 | #[test] 34 | fn main() { 35 | assert_eq!(A(42).to_show(), "42".to_string()); 36 | assert_eq!(B([42]).to_show(), "[42]".to_string()); 37 | assert_eq!(C::Foo(42).to_show(), "Foo(42)".to_string()); 38 | assert_eq!(C::Bar(42).to_show(), "42".to_string()); 39 | } 40 | -------------------------------------------------------------------------------- /tests/rustc-deriving-via-extension-hash-enum.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Hash)] 19 | #[allow(dead_code)] 20 | enum Foo { 21 | Bar(isize, char), 22 | Baz(char, isize) 23 | } 24 | 25 | #[derive(Derivative)] 26 | #[derivative(Hash)] 27 | #[allow(dead_code)] 28 | enum A { 29 | B, 30 | C, 31 | D, 32 | E 33 | } 34 | 35 | #[test] 36 | fn main(){} 37 | -------------------------------------------------------------------------------- /tests/rustc-expr-copy.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | 18 | fn f(arg: &mut A) { 19 | arg.a = 100; 20 | } 21 | 22 | #[derive(Derivative)] 23 | #[derivative(Copy, Clone)] 24 | struct A { a: isize } 25 | 26 | #[test] 27 | fn main() { 28 | let mut x = A {a: 10}; 29 | f(&mut x); 30 | assert_eq!(x.a, 100); 31 | x.a = 20; 32 | let mut y = x; 33 | f(&mut y); 34 | assert_eq!(x.a, 20); 35 | } 36 | -------------------------------------------------------------------------------- /tests/rustc-issue-19135.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | use std::marker::PhantomData; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Debug)] 21 | struct LifetimeStruct<'a>(PhantomData<&'a ()>); 22 | 23 | #[test] 24 | fn main() { 25 | takes_hrtb_closure(|lts| println!("{:?}", lts)); 26 | } 27 | 28 | fn takes_hrtb_closureFnMut(LifetimeStruct<'a>)>(mut f: F) { 29 | f(LifetimeStruct(PhantomData)); 30 | } 31 | -------------------------------------------------------------------------------- /tests/rustc-issue-16530.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(deprecated)] 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | use std::hash::{SipHasher, Hasher, Hash}; 17 | 18 | #[macro_use] 19 | extern crate derivative; 20 | 21 | #[derive(Derivative)] 22 | #[derivative(Hash)] 23 | struct Empty; 24 | 25 | #[test] 26 | fn main() { 27 | let mut s1 = SipHasher::new_with_keys(0, 0); 28 | Empty.hash(&mut s1); 29 | let mut s2 = SipHasher::new_with_keys(0, 0); 30 | Empty.hash(&mut s2); 31 | assert_eq!(s1.finish(), s2.finish()); 32 | } 33 | -------------------------------------------------------------------------------- /tests/rustc-deriving-via-extension-type-params.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[derive(Derivative)] 18 | #[derivative(PartialEq, Hash, Debug)] 19 | struct Foo { 20 | x: isize, 21 | y: T, 22 | z: isize 23 | } 24 | 25 | #[test] 26 | fn main() { 27 | let a = Foo { x: 1, y: 2.0f64, z: 3 }; 28 | let b = Foo { x: 1, y: 2.0f64, z: 3 }; 29 | assert_eq!(a, b); 30 | assert!(!(a != b)); 31 | assert!(a.eq(&b)); 32 | assert!(!a.ne(&b)); 33 | } 34 | -------------------------------------------------------------------------------- /tests/rustc-deriving-via-extension-hash-struct.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | use std::collections::hash_map::DefaultHasher; 20 | 21 | #[derive(Derivative)] 22 | #[derivative(Hash)] 23 | struct Foo { 24 | x: isize, 25 | y: isize, 26 | z: isize 27 | } 28 | 29 | #[test] 30 | fn main() { 31 | use std::hash::Hash; 32 | let mut hasher = DefaultHasher::new(); 33 | Foo { x: 0, y: 0, z: 0 }.hash(&mut hasher); 34 | } 35 | -------------------------------------------------------------------------------- /tests/rustc-issue-19037.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #![allow(dead_code)] 14 | 15 | #[cfg(feature = "use_core")] 16 | extern crate core; 17 | 18 | #[macro_use] 19 | extern crate derivative; 20 | 21 | struct Str([u8]); 22 | 23 | #[derive(Derivative)] 24 | #[derivative(Clone)] 25 | struct CharSplits<'a, Sep> { 26 | string: &'a Str, 27 | sep: Sep, 28 | allow_trailing_empty: bool, 29 | only_ascii: bool, 30 | finished: bool, 31 | } 32 | 33 | #[cfg(not(tarpaulin_include))] 34 | fn clone(s: &Str) -> &Str { 35 | Clone::clone(&s) 36 | } 37 | 38 | #[test] 39 | fn main() {} 40 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Martin Carton 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /tests/rustc-issue-19358.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | trait Trait { 15 | #[cfg(not(tarpaulin_include))] 16 | fn dummy(&self) { } 17 | } 18 | 19 | #[macro_use] 20 | extern crate derivative; 21 | 22 | #[derive(Derivative)] 23 | #[derivative(Debug)] 24 | struct Foo { 25 | foo: T, 26 | } 27 | 28 | #[derive(Derivative)] 29 | #[derivative(Debug)] 30 | struct Bar where T: Trait { 31 | bar: T, 32 | } 33 | 34 | impl Trait for isize {} 35 | 36 | #[test] 37 | fn main() { 38 | let a = Foo { foo: 12 }; 39 | let b = Bar { bar: 12 }; 40 | println!("{:?} {:?}", a, b); 41 | } 42 | -------------------------------------------------------------------------------- /tests/rustc-issue-13434.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Debug)] 19 | struct MyStruct; 20 | 21 | trait Repro { 22 | fn repro(self, s: MyStruct) -> String; 23 | } 24 | 25 | impl Repro for F where F: FnOnce(MyStruct) -> String { 26 | fn repro(self, s: MyStruct) -> String { 27 | self(s) 28 | } 29 | } 30 | 31 | fn do_stuff(r: R) -> String { 32 | r.repro(MyStruct) 33 | } 34 | 35 | #[test] 36 | fn main() { 37 | assert_eq!("MyStruct".to_string(), do_stuff(|s: MyStruct| format!("{:?}", s))); 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/doc.yml: -------------------------------------------------------------------------------- 1 | on: [push] 2 | 3 | name: Deploy documentation 4 | 5 | jobs: 6 | deploy: 7 | name: Deploy documentation 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions-rs/toolchain@v1 11 | with: 12 | profile: minimal 13 | toolchain: stable 14 | override: true 15 | - run: cargo +stable install mdbook --no-default-features --features search --vers "^0.4.0" 16 | - uses: actions/checkout@v2 17 | with: 18 | path: code 19 | - run: mdbook build 20 | working-directory: code 21 | - uses: actions/checkout@v2 22 | with: 23 | path: doc 24 | ref: gh-pages 25 | - run: | 26 | mkdir -p doc/branches 27 | rm -fr doc/branches/${GITHUB_REF##*/} 28 | mv code/book doc/branches/${GITHUB_REF##*/} 29 | - working-directory: doc 30 | run: | 31 | git config user.name bot 32 | git config user.email bot@bot 33 | git add . 34 | git diff-index --quiet HEAD || git commit -m "Autogenerate documentation for branch ${GITHUB_REF##*/}" 35 | git push -------------------------------------------------------------------------------- /tests/rustc-deriving-clone-struct.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #![allow(clippy::redundant_clone)] 14 | 15 | #[cfg(feature = "use_core")] 16 | extern crate core; 17 | 18 | #[macro_use] 19 | extern crate derivative; 20 | 21 | #[derive(Default, Derivative)] 22 | #[derivative(Clone)] 23 | struct S { 24 | _int: isize, 25 | _i8: i8, 26 | _i16: i16, 27 | _i32: i32, 28 | _i64: i64, 29 | 30 | _uint: usize, 31 | _u8: u8, 32 | _u16: u16, 33 | _u32: u32, 34 | _u64: u64, 35 | 36 | _f32: f32, 37 | _f64: f64, 38 | 39 | _bool: bool, 40 | _char: char, 41 | _nil: () 42 | } 43 | 44 | #[test] 45 | fn main() { 46 | let _ = S::default().clone(); 47 | } 48 | -------------------------------------------------------------------------------- /tests/derive-eq.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::eq_op)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | #[derive(Derivative, PartialEq)] 10 | #[derivative(Eq)] 11 | struct Foo { 12 | foo: u8 13 | } 14 | 15 | #[derive(Derivative)] 16 | #[derivative(Eq)] 17 | struct WithPtr { 18 | #[derivative(Eq(bound=""))] 19 | foo: *const T 20 | } 21 | 22 | impl PartialEq for WithPtr { 23 | fn eq(&self, other: &Self) -> bool { 24 | self.foo == other.foo 25 | } 26 | } 27 | 28 | trait SomeTrait {} 29 | struct SomeType { 30 | #[allow(dead_code)] 31 | foo: u8 32 | } 33 | impl SomeTrait for SomeType {} 34 | 35 | fn assert_eq(_: T) {} 36 | 37 | #[test] 38 | fn main() { 39 | assert!(Foo { foo: 7 } == Foo { foo: 7 }); 40 | assert!(Foo { foo: 7 } != Foo { foo: 42 }); 41 | 42 | assert_eq(Foo { foo: 7 }); 43 | 44 | let ptr1: *const dyn SomeTrait = &SomeType { foo: 0 }; 45 | let ptr2: *const dyn SomeTrait = &SomeType { foo: 1 }; 46 | assert!(WithPtr { foo: ptr1 } == WithPtr { foo: ptr1 }); 47 | assert!(WithPtr { foo: ptr1 } != WithPtr { foo: ptr2 }); 48 | 49 | assert_eq(WithPtr { foo: ptr1 }); 50 | } 51 | -------------------------------------------------------------------------------- /tests/derive-default-bounds.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Debug, Derivative, PartialEq)] 8 | #[derivative(Default="new")] 9 | struct Foo { 10 | foo: T, 11 | #[derivative(Default(value="min()", bound="U: std::ops::Not, U: Default"))] 12 | bar: U, 13 | } 14 | 15 | #[derive(Debug, Derivative, PartialEq)] 16 | #[derivative(Default(bound="T: Default, U: std::ops::Not, U: Default", new="true"))] 17 | struct Bar { 18 | foo: T, 19 | #[derivative(Default(value="min()"))] 20 | bar: U, 21 | } 22 | 23 | fn min>() -> T { 24 | !T::default() 25 | } 26 | 27 | #[derive(Debug, Derivative, PartialEq)] 28 | #[derivative(Default(bound=""))] 29 | struct WithOption { 30 | foo: Option, 31 | } 32 | 33 | struct NonDefault; 34 | 35 | #[test] 36 | fn main() { 37 | assert_eq!(Foo::default(), Foo { foo: 0u8, bar: 0xffu8 }); 38 | assert_eq!(Bar::default(), Bar { foo: 0u8, bar: 0xffu8 }); 39 | assert_eq!(Foo::new(), Foo { foo: 0u8, bar: 0xffu8 }); 40 | assert_eq!(Bar::new(), Bar { foo: 0u8, bar: 0xffu8 }); 41 | WithOption::::default(); 42 | } 43 | -------------------------------------------------------------------------------- /tests/rustc-deriving-meta.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #![allow(clippy::eq_op, clippy::redundant_clone)] 14 | 15 | #[cfg(feature = "use_core")] 16 | extern crate core; 17 | 18 | #[macro_use] 19 | extern crate derivative; 20 | 21 | use std::hash::Hash; 22 | 23 | #[derive(Derivative)] 24 | #[derivative(PartialEq, Clone, Hash)] 25 | struct Foo { 26 | bar: usize, 27 | baz: isize 28 | } 29 | 30 | fn hash(_t: &T) {} 31 | 32 | #[test] 33 | fn main() { 34 | let a = Foo {bar: 4, baz: -3}; 35 | 36 | let _ = a == a; // check for PartialEq impl w/o testing its correctness 37 | let _ = a.clone(); // check for Clone impl w/o testing its correctness 38 | hash(&a); // check for Hash impl w/o testing its correctness 39 | } 40 | -------------------------------------------------------------------------------- /doc/eq-ignore-orig.rs: -------------------------------------------------------------------------------- 1 | # use std::{cmp, hash}; 2 | # #[derive(PartialEq, Hash)] 3 | # struct Identifier; 4 | pub struct Version { 5 | /// The major version. 6 | pub major: u64, 7 | /// The minor version. 8 | pub minor: u64, 9 | /// The patch version. 10 | pub patch: u64, 11 | /// The pre-release version identifier. 12 | pub pre: Vec, 13 | /// The build metadata, ignored when 14 | /// determining version precedence. 15 | pub build: Vec, 16 | } 17 | 18 | impl cmp::PartialEq for Version { 19 | #[inline] 20 | fn eq(&self, other: &Version) -> bool { 21 | // We should ignore build metadata 22 | // here, otherwise versions v1 and 23 | // v2 can exist such that !(v1 < v2) 24 | // && !(v1 > v2) && v1 != v2, which 25 | // violate strict total ordering rules. 26 | self.major == other.major && 27 | self.minor == other.minor && 28 | self.patch == other.patch && 29 | self.pre == other.pre 30 | } 31 | } 32 | 33 | impl hash::Hash for Version { 34 | fn hash(&self, into: &mut H) { 35 | self.major.hash(into); 36 | self.minor.hash(into); 37 | self.patch.hash(into); 38 | self.pre.hash(into); 39 | } 40 | } -------------------------------------------------------------------------------- /tests/rustc-issue-24085.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // Regression test for #24085. Errors were occurring in region 12 | // inference due to the requirement that `'a:b'`, which was getting 13 | // incorrectly translated in connection with the closure below. 14 | 15 | #![allow(clippy::redundant_closure)] 16 | 17 | #[cfg(feature = "use_core")] 18 | extern crate core; 19 | 20 | #[macro_use] 21 | extern crate derivative; 22 | 23 | #[derive(Derivative)] 24 | #[derivative(Copy,Clone)] 25 | #[allow(dead_code)] 26 | struct Path<'a:'b, 'b> { 27 | x: &'a i32, 28 | tail: Option<&'b Path<'a, 'b>> 29 | } 30 | 31 | #[allow(dead_code, unconditional_recursion)] 32 | fn foo<'a,'b,F>(p: Path<'a, 'b>, mut f: F) 33 | where F: for<'c> FnMut(Path<'a, 'c>) { 34 | foo(p, |x| f(x)) 35 | } 36 | 37 | #[test] 38 | fn main() { } 39 | -------------------------------------------------------------------------------- /tests/rustc-exterior.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | use std::cell::Cell; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Copy, Clone)] 21 | struct Point {x: isize, y: isize, z: isize} 22 | 23 | fn f(p: &Cell) { 24 | assert_eq!(p.get().z, 12); 25 | p.set(Point {x: 10, y: 11, z: 13}); 26 | assert_eq!(p.get().z, 13); 27 | } 28 | 29 | #[test] 30 | fn main() { 31 | let a: Point = Point {x: 10, y: 11, z: 12}; 32 | let b: &Cell = &Cell::new(a); 33 | assert_eq!(b.get().z, 12); 34 | f(b); 35 | assert_eq!(a.x, 10); 36 | assert_eq!(a.y, 11); 37 | assert_eq!(a.z, 12); 38 | assert_eq!(b.get().x, 10); 39 | assert_eq!(b.get().y, 11); 40 | assert_eq!(b.get().z, 13); 41 | } 42 | -------------------------------------------------------------------------------- /doc/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Overview](README.md) 4 | * [`Copy` and `Clone` traits](Clone.md) 5 | 6 | 7 | * [`Debug` trait](Debug.md) 8 | 9 | 10 | 11 | 12 | * [`Default` trait](Default.md) 13 | 14 | 15 | 16 | 17 | * [`Hash` trait](Hash.md) 18 | 19 | 20 | 21 | * [Comparison traits](cmp.md) 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/rustc-deriving-meta-multiple.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // pretty-expanded FIXME #23616 12 | 13 | #![allow(clippy::eq_op, clippy::redundant_clone)] 14 | 15 | #[cfg(feature = "use_core")] 16 | extern crate core; 17 | 18 | #[macro_use] 19 | extern crate derivative; 20 | 21 | use std::hash::Hash; 22 | 23 | // testing multiple separate deriving attributes 24 | #[derive(Derivative)] 25 | #[derivative(PartialEq)] 26 | #[derivative(Clone)] 27 | #[derivative(Hash)] 28 | struct Foo { 29 | bar: usize, 30 | baz: isize 31 | } 32 | 33 | fn hash(_t: &T) {} 34 | 35 | #[test] 36 | fn main() { 37 | let a = Foo {bar: 4, baz: -3}; 38 | 39 | let _ = a == a; // check for PartialEq impl w/o testing its correctness 40 | let _ = a.clone(); // check for Clone impl w/o testing its correctness 41 | hash(&a); // check for Hash impl w/o testing its correctness 42 | } 43 | -------------------------------------------------------------------------------- /tests/rustc-zero-sized-btreemap-insert.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | use std::collections::BTreeMap; 18 | use std::iter::Iterator; 19 | 20 | #[derive(Derivative)] 21 | #[derive(Ord, PartialOrd)] 22 | #[derivative(Eq, Hash, Debug, PartialEq)] 23 | // TODO: Ord, PartialOrd 24 | struct Zst; 25 | 26 | #[test] 27 | fn main() { 28 | const N: usize = 8; 29 | 30 | for len in 0..N { 31 | let mut tester = BTreeMap::new(); 32 | assert_eq!(tester.len(), 0); 33 | for _ in 0..len { 34 | tester.insert(Zst, ()); 35 | } 36 | assert_eq!(tester.len(), if len == 0 { 0 } else { 1 }); 37 | assert_eq!(tester.iter().count(), if len == 0 { 0 } else { 1 }); 38 | assert_eq!(tester.get(&Zst).is_some(), len > 0); 39 | tester.clear(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/rustc-deriving-show.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #[cfg(feature = "use_core")] 12 | extern crate core; 13 | 14 | #[macro_use] 15 | extern crate derivative; 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Debug)] 19 | struct Unit; 20 | 21 | #[derive(Derivative)] 22 | #[derivative(Debug)] 23 | struct Tuple(isize, usize); 24 | 25 | #[derive(Derivative)] 26 | #[derivative(Debug)] 27 | struct Struct { x: isize, y: usize } 28 | 29 | #[derive(Derivative)] 30 | #[derivative(Debug)] 31 | enum Enum { 32 | Nullary, 33 | Variant(isize, usize), 34 | StructVariant { x: isize, y : usize } 35 | } 36 | 37 | macro_rules! t { 38 | ($x:expr, $expected:expr) => { 39 | assert_eq!(format!("{:?}", $x), $expected.to_string()) 40 | } 41 | } 42 | 43 | #[test] 44 | fn main() { 45 | t!(Unit, "Unit"); 46 | t!(Tuple(1, 2), "Tuple(1, 2)"); 47 | t!(Struct { x: 1, y: 2 }, "Struct { x: 1, y: 2 }"); 48 | t!(Enum::Nullary, "Nullary"); 49 | t!(Enum::Variant(1, 2), "Variant(1, 2)"); 50 | t!(Enum::StructVariant { x: 1, y: 2 }, "StructVariant { x: 1, y: 2 }"); 51 | } 52 | -------------------------------------------------------------------------------- /tests/derive-eq-packed.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::eq_op)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | #[derive(Derivative, PartialEq)] 10 | #[derivative(Eq)] 11 | #[repr(C, packed)] 12 | struct Foo { 13 | foo: u8 14 | } 15 | 16 | #[derive(Derivative)] 17 | #[derivative(Eq)] 18 | #[repr(C, packed)] 19 | struct WithPtr { 20 | #[derivative(Eq(bound=""))] 21 | foo: *const T 22 | } 23 | 24 | impl PartialEq for WithPtr { 25 | fn eq(&self, other: &Self) -> bool { 26 | self.foo == other.foo 27 | } 28 | } 29 | 30 | #[derive(Derivative)] 31 | #[derivative(PartialEq, Eq)] 32 | #[repr(C, packed)] 33 | struct Generic(T); 34 | 35 | trait SomeTrait {} 36 | #[derive(Clone, Copy, PartialEq, Eq)] 37 | struct SomeType { 38 | #[allow(dead_code)] 39 | foo: u8 40 | } 41 | impl SomeTrait for SomeType {} 42 | 43 | fn assert_eq(_: T) {} 44 | 45 | #[test] 46 | fn main() { 47 | assert!(Foo { foo: 7 } == Foo { foo: 7 }); 48 | assert!(Foo { foo: 7 } != Foo { foo: 42 }); 49 | 50 | assert_eq(Foo { foo: 7 }); 51 | 52 | let ptr1: *const dyn SomeTrait = &SomeType { foo: 0 }; 53 | let ptr2: *const dyn SomeTrait = &SomeType { foo: 1 }; 54 | assert!(WithPtr { foo: ptr1 } == WithPtr { foo: ptr1 }); 55 | assert!(WithPtr { foo: ptr1 } != WithPtr { foo: ptr2 }); 56 | 57 | assert_eq(WithPtr { foo: ptr1 }); 58 | 59 | assert!(Generic(SomeType { foo: 0 }) == Generic(SomeType { foo: 0 })); 60 | assert_eq(Generic(SomeType { foo: 0 })); 61 | } 62 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2; 2 | 3 | use ast; 4 | use attr; 5 | use bound; 6 | use syn; 7 | 8 | /// Make generic with all the generics in the input, plus a bound `T: ` for each 9 | /// generic field type that will be shown. 10 | pub fn build_impl_generics( 11 | item: &ast::Input, 12 | trait_path: &syn::Path, 13 | needs_debug_bound: F, 14 | field_bound: G, 15 | input_bound: H, 16 | ) -> syn::Generics 17 | where 18 | F: Fn(&attr::Field) -> bool, 19 | G: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>, 20 | H: Fn(&attr::Input) -> Option<&[syn::WherePredicate]>, 21 | { 22 | let generics = bound::without_defaults(item.generics); 23 | let generics = bound::with_where_predicates_from_fields(item, &generics, field_bound); 24 | 25 | match input_bound(&item.attrs) { 26 | Some(predicates) => bound::with_where_predicates(&generics, predicates), 27 | None => bound::with_bound(item, &generics, needs_debug_bound, trait_path), 28 | } 29 | } 30 | 31 | /// Construct a name for the inner type parameter that can't collide with any 32 | /// type parameters of the item. This is achieved by starting with a base and 33 | /// then concatenating the names of all other type parameters. 34 | pub fn hygienic_type_parameter(item: &ast::Input, base: &str) -> syn::Ident { 35 | let mut typaram = String::with_capacity(150); 36 | typaram.push_str(base); 37 | let typaram = item.generics.type_params().fold(typaram, |mut acc, ty| { 38 | acc.push_str(&format!("{}", &ty.ident)); 39 | acc 40 | }); 41 | 42 | syn::Ident::new(&typaram, proc_macro2::Span::call_site()) 43 | } 44 | -------------------------------------------------------------------------------- /doc/Clone.md: -------------------------------------------------------------------------------- 1 | # Custom attributes 2 | 3 | The `Copy` and `Clone` traits support the following attributes: 4 | 5 | * **Container attributes** 6 | * [`(bound="")`](#custom-bound) 7 | * [`Clone(clone_from="true")`](#clone-from) 8 | * **Field attributes** 9 | * [`(bound="")`](#custom-bound) 10 | 11 | # `clone_from` 12 | 13 | The [`Clone`] trait has a default implementation for [`clone_from`] and 14 | `derive(Clone)` never implements that method. *derivative* can implement it if 15 | asked explicitly. 16 | 17 | Note that while the generated implementation is good for structures, it might 18 | not be very efficient for enumerations. What it does is check if both `self` 19 | and the clone-from value have the same variant, if they have, use `clone_from` 20 | on the members, otherwise fallback to `*self = other.clone();`. Ask yourself if 21 | you really need this. 22 | 23 | # Custom bound 24 | As most other traits, `Copy` and `Debug` support a custom bound on container 25 | and fields. See [`Debug`'s documentation](Debug.md#custom-bound) for more 26 | information. 27 | 28 | # Limitations 29 | 30 | *rustc* can optimize `derive(Clone, Copy)` to generate faster, smaller code. 31 | So does *derivative*. But *rustc* does not know about `derivative(Copy)` and 32 | would not optimize `#[derivative(Copy)] #[derive(Clone)]`. 33 | To avoid that issue, you should avoid deriving `Clone` using *rustc*'s default 34 | `derive` and `Copy` using `derivative`. *derivative* will error if it detects 35 | that, but can't always do it. 36 | 37 | [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html 38 | [`clone_from`]: https://doc.rust-lang.org/std/clone/trait.Clone.html#method.clone_from 39 | -------------------------------------------------------------------------------- /tests/rustc-deriving-cmp-generic-tuple-struct.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // no-pretty-expanded FIXME #15189 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(PartialEq, Eq, PartialOrd, Ord)] 21 | struct TS(T, T); 22 | 23 | #[test] 24 | pub fn main() { 25 | let ts1 = TS(1, 1); 26 | let ts2 = TS(1, 2); 27 | 28 | // in order for both PartialOrd and Ord 29 | let tss = [ts1, ts2]; 30 | 31 | for (i, ts1) in tss.iter().enumerate() { 32 | for (j, ts2) in tss.iter().enumerate() { 33 | let ord = i.cmp(&j); 34 | 35 | let eq = i == j; 36 | let lt = i < j; 37 | let le = i <= j; 38 | let gt = i > j; 39 | let ge = i >= j; 40 | 41 | // PartialEq 42 | assert_eq!(*ts1 == *ts2, eq); 43 | assert_eq!(*ts1 != *ts2, !eq); 44 | 45 | // PartialOrd 46 | assert_eq!(*ts1 < *ts2, lt); 47 | assert_eq!(*ts1 > *ts2, gt); 48 | 49 | assert_eq!(*ts1 <= *ts2, le); 50 | assert_eq!(*ts1 >= *ts2, ge); 51 | 52 | // Ord 53 | assert_eq!(ts1.cmp(ts2), ord); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/rustc-deriving-cmp-generic-struct.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // no-pretty-expanded FIXME #15189 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(PartialEq, Eq, PartialOrd, Ord)] 21 | struct S { 22 | x: T, 23 | y: T, 24 | } 25 | 26 | #[test] 27 | pub fn main() { 28 | let s1 = S { x: 1, y: 1 }; 29 | let s2 = S { x: 1, y: 2 }; 30 | 31 | // in order for both PartialOrd and Ord 32 | let ss = [s1, s2]; 33 | 34 | for (i, s1) in ss.iter().enumerate() { 35 | for (j, s2) in ss.iter().enumerate() { 36 | let ord = i.cmp(&j); 37 | 38 | let eq = i == j; 39 | let lt = i < j; 40 | let le = i <= j; 41 | let gt = i > j; 42 | let ge = i >= j; 43 | 44 | // PartialEq 45 | assert_eq!(*s1 == *s2, eq); 46 | assert_eq!(*s1 != *s2, !eq); 47 | 48 | // PartialOrd 49 | assert_eq!(*s1 < *s2, lt); 50 | assert_eq!(*s1 > *s2, gt); 51 | 52 | assert_eq!(*s1 <= *s2, le); 53 | assert_eq!(*s1 >= *s2, ge); 54 | 55 | // Ord 56 | assert_eq!(s1.cmp(s2), ord); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/derive-debug-packed.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Derivative)] 8 | #[derivative(Debug)] 9 | #[repr(C, packed)] 10 | struct Foo { 11 | foo: u8, 12 | #[derivative(Debug="ignore")] 13 | bar: u8, 14 | } 15 | 16 | #[derive(Derivative)] 17 | #[derivative(Debug)] 18 | #[repr(C, packed)] 19 | struct Bar ( 20 | u8, 21 | #[derivative(Debug="ignore")] 22 | u8, 23 | ); 24 | 25 | #[derive(Derivative)] 26 | #[derivative(Debug)] 27 | #[repr(C, packed)] 28 | struct F(#[derivative(Debug="ignore")] isize); 29 | 30 | #[derive(Derivative)] 31 | #[derivative(Debug)] 32 | #[repr(C, packed)] 33 | struct G(isize, #[derivative(Debug="ignore")] isize); 34 | 35 | #[derive(Derivative)] 36 | #[derivative(Debug)] 37 | #[repr(C, packed)] 38 | struct J(#[derivative(Debug="ignore")] NoDebug); 39 | 40 | #[derive(Derivative)] 41 | #[derivative(Debug)] 42 | #[repr(C, packed)] 43 | struct K(isize, #[derivative(Debug="ignore")] NoDebug); 44 | 45 | #[derive(Derivative)] 46 | #[derivative(Debug)] 47 | #[repr(C, packed)] 48 | struct L { 49 | #[derivative(Debug="ignore")] 50 | foo: NoDebug 51 | } 52 | 53 | struct NoDebug; 54 | 55 | trait ToDebug { 56 | fn to_show(&self) -> String; 57 | } 58 | 59 | impl ToDebug for T { 60 | fn to_show(&self) -> String { 61 | format!("{:?}", self) 62 | } 63 | } 64 | 65 | #[test] 66 | fn main() { 67 | assert_eq!(Foo { foo: 42, bar: 1 }.to_show(), "Foo { foo: 42 }".to_string()); 68 | assert_eq!(Bar(42, 1).to_show(), "Bar(42)".to_string()); 69 | assert_eq!(F(42).to_show(), "F".to_string()); 70 | assert_eq!(G(42, 0).to_show(), "G(42)".to_string()); 71 | assert_eq!(J(NoDebug).to_show(), "J".to_string()); 72 | assert_eq!(K(42, NoDebug).to_show(), "K(42)".to_string()); 73 | assert_eq!(L{ foo: NoDebug }.to_show(), "L".to_string()); 74 | } 75 | -------------------------------------------------------------------------------- /tests/derive-clone.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::blacklisted_name, clippy::redundant_clone, clippy::trivially_copy_pass_by_ref)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | #[derive(Debug, Derivative, PartialEq)] 10 | #[derivative(Clone)] 11 | struct Foo { 12 | foo: u8, 13 | #[derivative(Clone(clone_with="seventh"))] 14 | bar: u8, 15 | } 16 | 17 | fn seventh(a: &u8) -> u8 { 18 | a/7 19 | } 20 | 21 | #[derive(Debug, PartialEq)] 22 | struct EvilCloneFrom(u8); 23 | 24 | impl Clone for EvilCloneFrom { 25 | #[cfg(not(tarpaulin_include))] 26 | fn clone(&self) -> Self { 27 | EvilCloneFrom(self.0) 28 | } 29 | 30 | fn clone_from(&mut self, _: &Self) { 31 | self.0 = 42; 32 | } 33 | } 34 | 35 | #[derive(Derivative)] 36 | #[derivative(Clone(clone_from="true"))] 37 | struct StructWithCloneFrom(EvilCloneFrom); 38 | 39 | #[derive(Debug, Derivative, PartialEq)] 40 | #[derivative(Clone(clone_from="true"))] 41 | enum EnumWithCloneFrom { 42 | Evil(EvilCloneFrom), 43 | Good(u32), 44 | None 45 | } 46 | 47 | #[test] 48 | fn main() { 49 | let foo = Foo { foo: 31, bar: 42 }; 50 | assert_eq!(Foo { foo: 31, bar: 6 }, foo.clone()); 51 | 52 | let mut foo = StructWithCloneFrom(EvilCloneFrom(27)); 53 | foo.clone_from(&StructWithCloneFrom(EvilCloneFrom(0))); 54 | assert_eq!((foo.0).0, 42); 55 | 56 | let mut foo = EnumWithCloneFrom::Evil(EvilCloneFrom(27)); 57 | foo.clone_from(&EnumWithCloneFrom::Evil(EvilCloneFrom(0))); 58 | assert_eq!(foo, EnumWithCloneFrom::Evil(EvilCloneFrom(42))); 59 | 60 | let mut foo = EnumWithCloneFrom::Evil(EvilCloneFrom(27)); 61 | foo.clone_from(&EnumWithCloneFrom::None); 62 | assert_eq!(foo, EnumWithCloneFrom::None); 63 | 64 | let mut foo = EnumWithCloneFrom::Good(27); 65 | foo.clone_from(&EnumWithCloneFrom::None); 66 | assert_eq!(foo, EnumWithCloneFrom::None); 67 | } 68 | -------------------------------------------------------------------------------- /tests/derive-debug.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | #[derive(Derivative)] 10 | #[derivative(Debug)] 11 | struct Foo { 12 | foo: u8, 13 | #[derivative(Debug="ignore")] 14 | bar: u8, 15 | } 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Debug)] 19 | struct Bar ( 20 | u8, 21 | #[derivative(Debug="ignore")] 22 | u8, 23 | ); 24 | 25 | #[derive(Derivative)] 26 | #[derivative(Debug)] 27 | enum C { 28 | V1(isize), 29 | V2(#[derivative(Debug="ignore")] i32), 30 | V3(String), 31 | } 32 | 33 | #[derive(Derivative)] 34 | #[derivative(Debug)] 35 | enum D { 36 | V1 { 37 | #[derivative(Debug="ignore")] 38 | a: isize 39 | } 40 | } 41 | 42 | #[derive(Derivative)] 43 | #[derivative(Debug)] 44 | struct F(#[derivative(Debug="ignore")] isize); 45 | 46 | #[derive(Derivative)] 47 | #[derivative(Debug)] 48 | struct G(isize, #[derivative(Debug="ignore")] isize); 49 | 50 | #[derive(Derivative)] 51 | #[derivative(Debug)] 52 | struct J(#[derivative(Debug="ignore")] NoDebug); 53 | 54 | struct NoDebug; 55 | 56 | trait ToDebug { 57 | fn to_show(&self) -> String; 58 | } 59 | 60 | impl ToDebug for T { 61 | fn to_show(&self) -> String { 62 | format!("{:?}", self) 63 | } 64 | } 65 | 66 | #[test] 67 | fn main() { 68 | assert_eq!(Foo { foo: 42, bar: 1 }.to_show(), "Foo { foo: 42 }".to_string()); 69 | assert_eq!(Bar(42, 1).to_show(), "Bar(42)".to_string()); 70 | assert_eq!(C::V1(12).to_show(), "V1(12)".to_string()); 71 | assert_eq!(C::V2(12).to_show(), "V2".to_string()); 72 | assert_eq!(C::V3("foo".to_string()).to_show(), "V3(\"foo\")".to_string()); 73 | assert_eq!(D::V1 { a: 42 }.to_show(), "V1".to_string()); 74 | assert_eq!(F(42).to_show(), "F".to_string()); 75 | assert_eq!(G(42, 0).to_show(), "G(42)".to_string()); 76 | assert_eq!(J(NoDebug).to_show(), "J".to_string()); 77 | } 78 | -------------------------------------------------------------------------------- /tests/rustc-deriving-cmp-generic-enum.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // no-pretty-expanded FIXME #15189 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative( 21 | PartialEq = "feature_allow_slow_enum", 22 | Eq, 23 | PartialOrd = "feature_allow_slow_enum", 24 | Ord = "feature_allow_slow_enum" 25 | )] 26 | enum E { 27 | V0, 28 | V1(T), 29 | V2(T, T), 30 | } 31 | 32 | #[test] 33 | fn main() { 34 | let e0 = E::V0; 35 | let e11 = E::V1(1); 36 | let e12 = E::V1(2); 37 | let e21 = E::V2(1, 1); 38 | let e22 = E::V2(1, 2); 39 | 40 | // in order for both PartialOrd and Ord 41 | let es = [e0, e11, e12, e21, e22]; 42 | 43 | for (i, e1) in es.iter().enumerate() { 44 | for (j, e2) in es.iter().enumerate() { 45 | let ord = i.cmp(&j); 46 | 47 | let eq = i == j; 48 | let lt = i < j; 49 | let le = i <= j; 50 | let gt = i > j; 51 | let ge = i >= j; 52 | 53 | // PartialEq 54 | assert_eq!(*e1 == *e2, eq); 55 | assert_eq!(*e1 != *e2, !eq); 56 | 57 | // PartialOrd 58 | assert_eq!(*e1 < *e2, lt); 59 | assert_eq!(*e1 > *e2, gt); 60 | 61 | assert_eq!(*e1 <= *e2, le); 62 | assert_eq!(*e1 >= *e2, ge); 63 | 64 | // Ord 65 | assert_eq!(e1.cmp(e2), ord); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Derivative 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/derivative.svg?maxAge=3600)](https://crates.io/crates/derivative) 4 | [![Crates.io](https://img.shields.io/crates/l/derivative.svg?maxAge=3600)](https://github.com/mcarton/rust-derivative#license) 5 | ![Continuous integration](https://github.com/mcarton/rust-derivative/workflows/Continuous%20integration/badge.svg) 6 | 7 | This crate provides a set of alternative customizable `#[derive]` attributes for Rust. 8 | 9 | ## [Documentation][documentation] 10 | ## Stability 11 | 12 | This crate is stable and follows semver. It requires *rustc 1.34 or later* and changing the minimal rustc version will be considered a semver breaking change. 13 | 14 | ## What it does 15 | 16 | ```rust 17 | #[derive(Derivative)] 18 | #[derivative(Debug)] 19 | struct Foo { 20 | foo: u8, 21 | #[derivative(Debug="ignore")] 22 | bar: u8, 23 | } 24 | 25 | // Prints `Foo { foo: 42 }` 26 | println!("{:?}", Foo { foo: 42, bar: 1 }); 27 | ``` 28 | 29 | Check the [documentation] for more! 30 | 31 | ## License 32 | 33 | Licensed under either of 34 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or 35 | ) 36 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) 37 | 38 | at your option. 39 | 40 | ## Acknowledgements 41 | 42 | This is inspired from how [`serde`] wonderfully handles attributes. 43 | This also takes some code and ideas from `serde` itself. 44 | 45 | Some tests are directly adapted from `rustc`'s tests. 46 | 47 | ## Contribution 48 | 49 | Unless you explicitly state otherwise, any contribution intentionally submitted 50 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 51 | be dual licensed as above, without any additional terms or conditions. 52 | 53 | [`serde`]: https://crates.io/crates/serde 54 | [documentation]: https://mcarton.github.io/rust-derivative/latest/index.html 55 | [rustc]: https://github.com/rust-lang/rust 56 | -------------------------------------------------------------------------------- /tests/rustc-deriving-cmp-generic-struct-enum.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | // no-pretty-expanded FIXME #15189 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative( 21 | PartialEq = "feature_allow_slow_enum", 22 | Eq, 23 | PartialOrd = "feature_allow_slow_enum", 24 | Ord = "feature_allow_slow_enum" 25 | )] 26 | enum ES { 27 | ES1 { x: T }, 28 | ES2 { x: T, y: T }, 29 | } 30 | 31 | #[test] 32 | pub fn main() { 33 | let (es11, es12, es21, es22) = ( 34 | ES::ES1 { x: 1 }, 35 | ES::ES1 { x: 2 }, 36 | ES::ES2 { x: 1, y: 1 }, 37 | ES::ES2 { x: 1, y: 2 }, 38 | ); 39 | 40 | // in order for both PartialOrd and Ord 41 | let ess = [es11, es12, es21, es22]; 42 | 43 | for (i, es1) in ess.iter().enumerate() { 44 | for (j, es2) in ess.iter().enumerate() { 45 | let ord = i.cmp(&j); 46 | 47 | let eq = i == j; 48 | let (lt, le) = (i < j, i <= j); 49 | let (gt, ge) = (i > j, i >= j); 50 | 51 | // PartialEq 52 | assert_eq!(*es1 == *es2, eq); 53 | assert_eq!(*es1 != *es2, !eq); 54 | 55 | // PartialOrd 56 | assert_eq!(*es1 < *es2, lt); 57 | assert_eq!(*es1 > *es2, gt); 58 | 59 | assert_eq!(*es1 <= *es2, le); 60 | assert_eq!(*es1 >= *es2, ge); 61 | 62 | // Ord 63 | assert_eq!(es1.cmp(es2), ord); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/rustc-deriving-copyclone.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | //! Test that #[derive(Copy, Clone)] produces a shallow copy 12 | //! even when a member violates RFC 1521 13 | 14 | #![allow(clippy::clone_on_copy)] 15 | 16 | #[cfg(feature = "use_core")] 17 | extern crate core; 18 | 19 | #[macro_use] 20 | extern crate derivative; 21 | 22 | use std::sync::atomic::{AtomicBool, Ordering}; 23 | 24 | /// A struct that pretends to be Copy, but actually does something 25 | /// in its Clone impl 26 | #[derive(Copy)] 27 | struct Liar; 28 | 29 | /// Static cooperating with the rogue Clone impl 30 | static CLONED: AtomicBool = AtomicBool::new(false); 31 | 32 | impl Clone for Liar { 33 | #[cfg(not(tarpaulin_include))] // The intended effect is for this function not to be called! 34 | fn clone(&self) -> Self { 35 | // this makes Clone vs Copy observable 36 | CLONED.store(true, Ordering::SeqCst); 37 | 38 | *self 39 | } 40 | } 41 | 42 | /// This struct is actually Copy... at least, it thinks it is! 43 | #[derive(Copy, Clone)] 44 | struct TheirTheir(Liar); 45 | 46 | #[derive(Derivative)] 47 | #[derivative(Copy, Clone)] 48 | struct OurOur1(Liar); 49 | #[derive(Derivative)] 50 | #[derivative(Clone, Copy)] 51 | struct OurOur2(Liar); 52 | 53 | #[test] 54 | fn main() { 55 | let _ = TheirTheir(Liar).clone(); 56 | assert!(!CLONED.load(Ordering::SeqCst), "TheirTheir"); 57 | 58 | let _ = OurOur1(Liar).clone(); 59 | assert!(!CLONED.load(Ordering::SeqCst), "OurOur1"); 60 | let _ = OurOur2(Liar).clone(); 61 | assert!(!CLONED.load(Ordering::SeqCst), "OurOur2"); 62 | } 63 | -------------------------------------------------------------------------------- /tests/derive-default.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | #[derive(Debug, Derivative, PartialEq)] 8 | #[derivative(Default="new")] 9 | struct Foo { 10 | foo: u8, 11 | #[derivative(Default(value="42"))] 12 | bar: u8, 13 | } 14 | 15 | #[derive(Debug, Derivative, PartialEq)] 16 | #[derivative(Default(new="true"))] 17 | struct Bar ( 18 | u8, 19 | #[derivative(Default(value="42"))] 20 | u8, 21 | ); 22 | 23 | #[derive(Debug, PartialEq)] 24 | struct B1(u8, u8); 25 | #[derive(Debug, PartialEq)] 26 | struct B2{a:u8, b:u8} 27 | 28 | #[derive(Debug, Derivative, PartialEq)] 29 | #[derivative(Default(new="true"))] 30 | struct Baz ( 31 | #[derivative(Default(value="[1,2]"))] 32 | [u8;2], 33 | #[derivative(Default(value="[3;2]"))] 34 | [u8;2], 35 | #[derivative(Default(value="(4,5)"))] 36 | (u8, u8), 37 | #[derivative(Default(value="B1(6,7)"))] 38 | B1, 39 | #[derivative(Default(value="B2{a:8,b:9}"))] 40 | B2, 41 | ); 42 | 43 | #[derive(Debug, Derivative, PartialEq)] 44 | #[derivative(Default)] 45 | enum Enum1 { 46 | #[allow(dead_code)] 47 | A, 48 | #[derivative(Default)] 49 | B, 50 | } 51 | 52 | #[derive(Debug, Derivative, PartialEq)] 53 | #[derivative(Default)] 54 | enum Enum2 { 55 | #[derivative(Default)] 56 | A, 57 | #[allow(dead_code)] 58 | B, 59 | } 60 | 61 | #[derive(Debug, Derivative, PartialEq)] 62 | #[derivative(Default)] 63 | struct A(#[derivative(Default(value="NoDefault"))] NoDefault); 64 | 65 | #[derive(Debug, PartialEq)] 66 | struct NoDefault; 67 | 68 | #[test] 69 | fn main() { 70 | assert_eq!(Foo::default(), Foo { foo: 0, bar: 42 }); 71 | assert_eq!(Foo::new(), Foo { foo: 0, bar: 42 }); 72 | assert_eq!(Bar::default(), Bar(0, 42)); 73 | assert_eq!(Bar::new(), Bar(0, 42)); 74 | assert_eq!(Baz::new(), Baz([1,2], [3,3], (4,5), B1(6,7), B2{a:8,b:9})); 75 | assert_eq!(A::default(), A(NoDefault)); 76 | assert_eq!(Enum1::default(), Enum1::B); 77 | assert_eq!(Enum2::default(), Enum2::A); 78 | } 79 | -------------------------------------------------------------------------------- /tests/rustc-deriving-show-2.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![deny(unused_variables)] // We used to generate warning: unused variable: `f` 3 | 4 | #[cfg(feature = "use_core")] 5 | extern crate core; 6 | 7 | #[macro_use] 8 | extern crate derivative; 9 | 10 | use std::fmt; 11 | 12 | #[derive(Derivative)] 13 | #[derivative(Debug)] 14 | enum A {} 15 | #[derive(Derivative)] 16 | #[derivative(Debug)] 17 | enum B { V1, V2, V3 } 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Debug)] 21 | enum C { V1(isize), V2(B), V3(String) } 22 | 23 | #[derive(Derivative)] 24 | #[derivative(Debug)] 25 | enum D { V1{ a: isize } } 26 | 27 | #[derive(Derivative)] 28 | #[derivative(Debug)] 29 | struct E; 30 | #[derive(Derivative)] 31 | #[derivative(Debug)] 32 | struct F(isize); 33 | #[derive(Derivative)] 34 | #[derivative(Debug)] 35 | struct G(isize, isize); 36 | #[derive(Derivative)] 37 | #[derivative(Debug)] 38 | struct H { a: isize } 39 | #[derive(Derivative)] 40 | #[derivative(Debug)] 41 | struct I { a: isize, b: isize } 42 | #[derive(Derivative)] 43 | #[derivative(Debug)] 44 | struct J(Custom); 45 | 46 | struct Custom; 47 | impl fmt::Debug for Custom { 48 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 49 | write!(f, "yay") 50 | } 51 | } 52 | 53 | trait ToDebug { 54 | fn to_show(&self) -> String; 55 | } 56 | 57 | impl ToDebug for T { 58 | fn to_show(&self) -> String { 59 | format!("{:?}", self) 60 | } 61 | } 62 | 63 | #[test] 64 | fn main() { 65 | assert_eq!(B::V1.to_show(), "V1".to_string()); 66 | assert_eq!(B::V2.to_show(), "V2".to_string()); 67 | assert_eq!(C::V1(3).to_show(), "V1(3)".to_string()); 68 | assert_eq!(C::V2(B::V2).to_show(), "V2(V2)".to_string()); 69 | assert_eq!(D::V1{ a: 2 }.to_show(), "V1 { a: 2 }".to_string()); 70 | assert_eq!(E.to_show(), "E".to_string()); 71 | assert_eq!(F(3).to_show(), "F(3)".to_string()); 72 | assert_eq!(G(3, 4).to_show(), "G(3, 4)".to_string()); 73 | assert_eq!(I{ a: 2, b: 4 }.to_show(), "I { a: 2, b: 4 }".to_string()); 74 | assert_eq!(J(Custom).to_show(), "J(yay)".to_string()); 75 | } 76 | -------------------------------------------------------------------------------- /tests/rustc-issue-12860.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(clippy::derive_hash_xor_eq)] 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | use std::collections::HashSet; 17 | 18 | #[macro_use] 19 | extern crate derivative; 20 | 21 | #[derive(Derivative)] 22 | #[derivative(Hash)] 23 | #[derive(Copy, Clone, PartialEq, Eq)] 24 | struct XYZ { 25 | x: isize, 26 | y: isize, 27 | z: isize 28 | } 29 | 30 | #[test] 31 | fn main() { 32 | let mut connected = HashSet::new(); 33 | let mut border = HashSet::new(); 34 | 35 | let middle = XYZ{x: 0, y: 0, z: 0}; 36 | border.insert(middle); 37 | 38 | while !border.is_empty() && connected.len() < 10000 { 39 | let choice = *(border.iter().next().unwrap()); 40 | border.remove(&choice); 41 | connected.insert(choice); 42 | 43 | let cxp = XYZ{x: choice.x + 1, y: choice.y, z: choice.z}; 44 | let cxm = XYZ{x: choice.x - 1, y: choice.y, z: choice.z}; 45 | let cyp = XYZ{x: choice.x, y: choice.y + 1, z: choice.z}; 46 | let cym = XYZ{x: choice.x, y: choice.y - 1, z: choice.z}; 47 | let czp = XYZ{x: choice.x, y: choice.y, z: choice.z + 1}; 48 | let czm = XYZ{x: choice.x, y: choice.y, z: choice.z - 1}; 49 | 50 | if !connected.contains(&cxp) { 51 | border.insert(cxp); 52 | } 53 | if !connected.contains(&cxm){ 54 | border.insert(cxm); 55 | } 56 | if !connected.contains(&cyp){ 57 | border.insert(cyp); 58 | } 59 | if !connected.contains(&cym) { 60 | border.insert(cym); 61 | } 62 | if !connected.contains(&czp){ 63 | border.insert(czp); 64 | } 65 | if !connected.contains(&czm) { 66 | border.insert(czm); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/derive-debug-bounds.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use_core")] 2 | extern crate core; 3 | 4 | #[macro_use] 5 | extern crate derivative; 6 | 7 | use std::fmt::{Formatter, Result as FmtResult}; 8 | 9 | #[derive(Derivative)] 10 | #[derivative(Debug)] 11 | struct Foo { 12 | foo: T, 13 | #[derivative(Debug(format_with="MyDebug::my_fmt", bound="U: MyDebug"))] 14 | bar: U, 15 | } 16 | 17 | #[derive(Derivative)] 18 | #[derivative(Debug(bound="T: std::fmt::Debug, U: MyDebug"))] 19 | struct Foo2 { 20 | foo: T, 21 | #[derivative(Debug(format_with="MyDebug::my_fmt"))] 22 | bar: U, 23 | } 24 | 25 | #[derive(Derivative)] 26 | #[derivative(Debug)] 27 | struct Bar ( 28 | T, 29 | #[derivative(Debug(format_with="MyDebug::my_fmt", bound="U: MyDebug"))] 30 | U, 31 | ); 32 | 33 | #[derive(Derivative)] 34 | #[derivative(Debug(bound="T: std::fmt::Debug, U: MyDebug"))] 35 | struct Bar2 ( 36 | T, 37 | #[derivative(Debug(format_with="MyDebug::my_fmt"))] 38 | U, 39 | ); 40 | 41 | struct NoDebug; 42 | 43 | struct GenericNeedsNoDebug(T); 44 | impl std::fmt::Debug for GenericNeedsNoDebug { 45 | fn fmt(&self, f: &mut std::fmt::Formatter) -> FmtResult { 46 | f.write_str("GenericNeedsNoDebug") 47 | } 48 | } 49 | 50 | #[derive(Derivative)] 51 | #[derivative(Debug)] 52 | struct TestUnneededBound( // Test that we don't add T: Debug 53 | #[derivative(Debug(bound=""))] GenericNeedsNoDebug, 54 | ); 55 | 56 | trait MyDebug { 57 | fn my_fmt(&self, f: &mut Formatter) -> FmtResult { 58 | f.write_str("MyDebug") 59 | } 60 | } 61 | 62 | impl MyDebug for i32 { } 63 | impl<'a, T> MyDebug for &'a T { } 64 | 65 | 66 | trait ToDebug { 67 | fn to_show(&self) -> String; 68 | } 69 | 70 | impl ToDebug for T { 71 | fn to_show(&self) -> String { 72 | format!("{:?}", self) 73 | } 74 | } 75 | 76 | #[test] 77 | fn main() { 78 | assert_eq!(Foo { foo: 42, bar: 0 }.to_show(), "Foo { foo: 42, bar: MyDebug }".to_string()); 79 | assert_eq!(Foo2 { foo: 42, bar: 0 }.to_show(), "Foo2 { foo: 42, bar: MyDebug }".to_string()); 80 | assert_eq!(Bar(42, 0).to_show(), "Bar(42, MyDebug)".to_string()); 81 | assert_eq!(Bar2(42, 0).to_show(), "Bar2(42, MyDebug)".to_string()); 82 | assert_eq!(TestUnneededBound(GenericNeedsNoDebug(NoDebug)).to_show(), "TestUnneededBound(GenericNeedsNoDebug)".to_string()); 83 | } 84 | -------------------------------------------------------------------------------- /tests/rustc-deriving-hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(non_camel_case_types)] 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | use std::hash::{Hash, Hasher}; 20 | use std::collections::hash_map::DefaultHasher; 21 | 22 | #[derive(Derivative)] 23 | #[derivative(Hash)] 24 | struct Person { 25 | id: u16, 26 | name: String, 27 | phone: u64, 28 | } 29 | 30 | // test for hygiene name collisions 31 | #[derive(Derivative)] 32 | #[derivative(Hash)] struct __H__H; 33 | #[derive(Derivative)] 34 | #[allow(dead_code)] #[derivative(Hash)] struct Collision<__H> ( __H ); 35 | // TODO(rustc) #[derivative(Hash)] enum Collision<__H> { __H { __H__H: __H } } 36 | 37 | #[derive(Derivative)] 38 | #[derivative(Hash)] 39 | enum E { A=1, B } 40 | 41 | fn hash(t: &T) -> u64 { 42 | let mut s = DefaultHasher::new(); 43 | t.hash(&mut s); 44 | s.finish() 45 | } 46 | 47 | struct FakeHasher<'a>(&'a mut Vec); 48 | impl<'a> Hasher for FakeHasher<'a> { 49 | #[cfg(not(tarpaulin_include))] 50 | fn finish(&self) -> u64 { 51 | unimplemented!() 52 | } 53 | 54 | fn write(&mut self, bytes: &[u8]) { 55 | self.0.extend(bytes); 56 | } 57 | } 58 | 59 | fn fake_hash(v: &mut Vec, e: E) { 60 | e.hash(&mut FakeHasher(v)); 61 | } 62 | 63 | #[test] 64 | fn main() { 65 | let person1 = Person { 66 | id: 5, 67 | name: "Janet".to_string(), 68 | phone: 555_666_777, 69 | }; 70 | let person2 = Person { 71 | id: 5, 72 | name: "Bob".to_string(), 73 | phone: 555_666_777, 74 | }; 75 | assert_eq!(hash(&person1), hash(&person1)); 76 | assert!(hash(&person1) != hash(&person2)); 77 | 78 | // test #21714 79 | let mut va = vec![]; 80 | let mut vb = vec![]; 81 | fake_hash(&mut va, E::A); 82 | fake_hash(&mut vb, E::B); 83 | assert!(va != vb); 84 | } 85 | -------------------------------------------------------------------------------- /doc/Hash.md: -------------------------------------------------------------------------------- 1 | # Custom attributes 2 | The `Hash` trait supports the following attributes: 3 | 4 | * **Container attributes** 5 | * [`Hash(bound="")`](#custom-bound) 6 | * **Field attributes** 7 | * [`Hash(bound="")`](#custom-bound) 8 | * [`Hash(hash_with="")`](#hash-with) 9 | * [`Hash="ignore"`](#ignoring-a-field) 10 | 11 | # Ignoring a field 12 | 13 | You can use *derivative* to ignore fields from a `Hash` implementation: 14 | 15 | ```rust 16 | # extern crate derivative; 17 | # use derivative::Derivative; 18 | #[derive(Derivative)] 19 | #[derivative(Hash)] 20 | struct Foo { 21 | foo: u8, 22 | #[derivative(Hash="ignore")] 23 | bar: i32, 24 | } 25 | 26 | #[derive(Hash)] 27 | struct Bar { 28 | foo: u8, 29 | } 30 | 31 | # fn hash(t: &T) -> u64 { 32 | # use std::hash::Hasher; 33 | # let mut s = std::collections::hash_map::DefaultHasher::new(); 34 | # t.hash(&mut s); 35 | # s.finish() 36 | # } 37 | # 38 | assert_eq!(hash(&Foo { foo: 42, bar: -1337 }), hash(&Bar { foo: 42 })); 39 | ``` 40 | 41 | # Hash with 42 | 43 | You can pass a field to a hash function: 44 | 45 | ```rust 46 | # extern crate derivative; 47 | # use derivative::Derivative; 48 | # mod path { 49 | # pub struct SomeTypeThatMightNotBeHash; 50 | # pub mod to { 51 | # pub fn my_hash_fn(_: &super::SomeTypeThatMightNotBeHash, state: &mut H) where H: std::hash::Hasher { unimplemented!() } 52 | # } 53 | # } 54 | # use path::SomeTypeThatMightNotBeHash; 55 | #[derive(Derivative)] 56 | #[derivative(Hash)] 57 | struct Foo { 58 | foo: u32, 59 | #[derivative(Hash(hash_with="path::to::my_hash_fn"))] 60 | bar: SomeTypeThatMightNotBeHash, 61 | } 62 | ``` 63 | 64 | The field `bar` will be hashed with `path::to::my_hash_fn(&bar, &mut state)` 65 | where `state` is the current [`Hasher`]. 66 | 67 | The function must the following prototype: 68 | 69 | ```rust,ignore 70 | fn my_hash_fn(&T, state: &mut H) where H: Hasher; 71 | ``` 72 | 73 | # Limitations 74 | 75 | On structure, `derivative(Hash)` will produce the same hash as `derive(Hash)`. 76 | On unions however, it will produces the same hashes *only for unitary 77 | variants*! 78 | 79 | # Custom bound 80 | As most other traits, `Hash` supports a custom bound on container and fields. 81 | See [`Debug`'s documentation](Debug.md#custom-bound) for more information. 82 | 83 | [`Hasher`]: https://doc.rust-lang.org/std/hash/trait.Hasher.html 84 | -------------------------------------------------------------------------------- /tests/derive-debug-generics.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | use std::marker::PhantomData; 10 | 11 | #[derive(Derivative)] 12 | #[derivative(Debug)] 13 | struct Foo { 14 | foo: T, 15 | #[derivative(Debug="ignore")] 16 | bar: U, 17 | } 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Debug)] 21 | struct Bar ( 22 | T, 23 | #[derivative(Debug="ignore")] 24 | U, 25 | ); 26 | 27 | #[derive(Derivative)] 28 | #[derivative(Debug)] 29 | enum C { 30 | V1(T), 31 | V2(#[derivative(Debug="ignore")] U), 32 | V3(String), 33 | } 34 | 35 | #[derive(Derivative)] 36 | #[derivative(Debug)] 37 | enum D { 38 | V1 { 39 | #[derivative(Debug="ignore")] 40 | a: U 41 | } 42 | } 43 | 44 | #[derive(Derivative)] 45 | #[derivative(Debug)] 46 | struct F(#[derivative(Debug="ignore")] U); 47 | 48 | #[derive(Derivative)] 49 | #[derivative(Debug)] 50 | struct G(isize, #[derivative(Debug="ignore")] U); 51 | 52 | #[derive(Derivative)] 53 | #[derivative(Debug)] 54 | struct J(#[derivative(Debug="ignore")] U); 55 | 56 | struct NoDebug; 57 | 58 | trait ToDebug { 59 | fn to_show(&self) -> String; 60 | } 61 | 62 | impl ToDebug for T { 63 | fn to_show(&self) -> String { 64 | format!("{:?}", self) 65 | } 66 | } 67 | 68 | #[derive(Derivative)] 69 | #[derivative(Debug)] 70 | struct PhantomField { 71 | foo: PhantomData, 72 | } 73 | 74 | #[derive(Derivative)] 75 | #[derivative(Debug)] 76 | struct PhantomTuple { 77 | foo: PhantomData<(T,)>, 78 | } 79 | 80 | #[test] 81 | fn main() { 82 | assert_eq!(Foo { foo: 42, bar: NoDebug }.to_show(), "Foo { foo: 42 }".to_string()); 83 | assert_eq!(Bar(42, NoDebug).to_show(), "Bar(42)".to_string()); 84 | assert_eq!(C::V1::(12).to_show(), "V1(12)".to_string()); 85 | assert_eq!(C::V2::(NoDebug).to_show(), "V2".to_string()); 86 | assert_eq!(C::V3::("foo".to_string()).to_show(), "V3(\"foo\")".to_string()); 87 | assert_eq!(D::V1 { a: NoDebug }.to_show(), "V1".to_string()); 88 | assert_eq!(F(NoDebug).to_show(), "F".to_string()); 89 | assert_eq!(G(42, NoDebug).to_show(), "G(42)".to_string()); 90 | assert_eq!(J(NoDebug).to_show(), "J".to_string()); 91 | assert_eq!(&format!("{:?}", PhantomField:: { foo: Default::default() }), "PhantomField { foo: PhantomData }"); 92 | assert_eq!(&format!("{:?}", PhantomTuple:: { foo: Default::default() }), "PhantomTuple { foo: PhantomData }"); 93 | } 94 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Derivative 2 | 3 | This crate provides a set of alternative `#[derive]` attributes for Rust. 4 | 5 | ## Examples 6 | 7 | *derivative* uses attributes to make it possible to derive more implementations 8 | than the built-in `derive(Trait)`. Here are a few examples of stuffs you cannot 9 | just `derive`. 10 | 11 | You can derive `Default` on enumerations: 12 | 13 | 14 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 31 | 35 | 36 |
16 | 17 | With *derivative* 18 | 20 | 21 | [Original][default-value-source] 22 |
28 | 29 | {{#playground default-enum.rs}} 30 | 32 | 33 | {{#playground default-enum-orig.rs}} 34 |
37 | 38 | You can use different default values for some fields: 39 | 40 | 41 | 42 | 46 | 50 | 51 | 52 | 53 | 54 | 58 | 62 | 63 |
43 | 44 | With *derivative* 45 | 47 | 48 | [Original][default-value-source] 49 |
55 | 56 | {{#playground default-value.rs}} 57 | 59 | 60 | {{#playground default-value-orig.rs}} 61 |
64 | 65 | 66 | Want a transparent `Debug` implementation for your wrapper? We got that: 67 | 68 | 69 | 70 | 74 | 78 | 79 | 80 | 81 | 82 | 86 | 90 | 91 |
71 | 72 | With *derivative* 73 | 75 | 76 | [Original][transparent-source] 77 |
83 | 84 | {{#playground debug-transparent.rs}} 85 | 87 | 88 | {{#playground debug-transparent-orig.rs}} 89 |
92 | 93 | 94 | Need to ignore a field? We got that too: 95 | 96 | 97 | 98 | 102 | 106 | 107 | 108 | 109 | 110 | 114 | 118 | 119 |
99 | 100 | With *derivative* 101 | 103 | 104 | [Original][eq-ignore-source] 105 |
111 | 112 | {{#playground eq-ignore.rs}} 113 | 115 | 116 | {{#playground eq-ignore-orig.rs}} 117 |
120 | 121 | 122 | [default-value-source]: https://github.com/rust-lang-nursery/regex/blob/3cfef1e79d135a3e8a670aff53e7fabef453a3e1/src/re_builder.rs#L12-L39 123 | [default-enum-source]: https://github.com/rust-lang/rust/blob/16eeeac783d2ede28e09f2a433c612dea309fe33/src/libcore/option.rs#L714-L718 124 | [transparent-source]: https://github.com/rust-lang/rust/blob/5457c35ece57bbc4a65baff239a02d6abb81c8a2/src/libcore/num/mod.rs#L46-L54 125 | [eq-ignore-source]: https://github.com/steveklabnik/semver/blob/baa0fbb57c80a7fb344fbeedac24a28439ddf5b5/src/version.rs#L196-L205 126 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | 5 | ## 2.2.0 6 | * Add support for deriving traits on `repr(packed)` types ([#84]). 7 | * Fix bug with `Debug` bounds ([#83]). 8 | * Migrate documentation to `mdbook` and fix issues found in examples ([#83]). 9 | 10 | ## 2.1.3 11 | * Fix Clippy warning ([#81]). 12 | 13 | ## 2.1.2 14 | * Fix bug when used in combination with other attributes ([#79]). 15 | 16 | ## 2.1.1 17 | * Improve error reporting. ([#70]) 18 | * Fix a Clippy warning in generated code. ([#71]). 19 | 20 | ## 2.1.0 21 | * `feature_allow_slow_enum` is not required anymore on `enum` with `PartialEq`. ([#64]) 22 | * `PartialEq` generates more efficient code for C-like `enum`. ([#65]) 23 | * Fix issue with deriving `Hash` on generic `enums` #68. ([#68]) 24 | 25 | ## 2.0.2 26 | * Fix a bug with `format_with` on `Debug` derives with generic types with trait bounds. 27 | 28 | ## 2.0.1 29 | * Fix a hygiene bug with `Debug`. ([#60]) 30 | 31 | ## 2.0.0 32 | This release should be compatible with version 1.*, but now requires rustc version 1.34 or later. 33 | * Update `syn`, `quote`, and `proc-macro2` dependencies. ([#59]) 34 | 35 | ## 1.0.4 36 | This is the last version to support rustc versions 1.15 to 1.33. 37 | 38 | * Implement `PartialOrd` and `Ord` deriving. 39 | 40 | ## 1.0.3 41 | * Do not require `syn`'s `full` feature anymore. ([#38], [#45]) 42 | * Fix an issue with using `#[derivative(Debug(format_with = "…"))]` on non-generic types. ([#40]) 43 | * Fix some warnings in the library with recent versions of `rustc`. 44 | * Fix some `clippy::pedantic` warnings in generated code. ([#46]) 45 | 46 | ## 1.0.2 47 | * Add `use_core` feature to make `Derivative` usable in `core` crates. 48 | 49 | ## 1.0.1 50 | * Updated `syn` to `0.15`. ([#25]) 51 | * Updated `quote` to `0.6`. ([#25]) 52 | 53 | ## 1.0.0 54 | * Make stable. 55 | 56 | ## 0.3.1 57 | * Fix a warning in `derivative(Debug)`. 58 | * Remove all `feature`s, this makes the crate usable on `beta`. 59 | 60 | [#25]: https://github.com/mcarton/rust-derivative/issues/25 61 | [#38]: https://github.com/mcarton/rust-derivative/pull/38 62 | [#40]: https://github.com/mcarton/rust-derivative/pull/40 63 | [#45]: https://github.com/mcarton/rust-derivative/pull/45 64 | [#46]: https://github.com/mcarton/rust-derivative/pull/46 65 | [#59]: https://github.com/mcarton/rust-derivative/pull/59 66 | [#60]: https://github.com/mcarton/rust-derivative/pull/60 67 | [#61]: https://github.com/mcarton/rust-derivative/pull/61 68 | [#64]: https://github.com/mcarton/rust-derivative/pull/64 69 | [#65]: https://github.com/mcarton/rust-derivative/pull/65 70 | [#68]: https://github.com/mcarton/rust-derivative/pull/68 71 | [#70]: https://github.com/mcarton/rust-derivative/pull/70 72 | [#71]: https://github.com/mcarton/rust-derivative/pull/71 73 | [#79]: https://github.com/mcarton/rust-derivative/pull/79 74 | [#81]: https://github.com/mcarton/rust-derivative/pull/81 75 | [#83]: https://github.com/mcarton/rust-derivative/pull/83 76 | [#84]: https://github.com/mcarton/rust-derivative/pull/84 -------------------------------------------------------------------------------- /doc/Default.md: -------------------------------------------------------------------------------- 1 | # Custom attributes 2 | The `Default` trait supports the following attributes: 3 | 4 | * **Container attributes** 5 | * [`Default(bound="")`](#custom-bound) 6 | * [`Default="new"`](#new-function) 7 | * **Variant attributes** 8 | * [`Default`](#default-enumeration) 9 | * **Field attributes** 10 | * [`Default(bound="")`](#custom-bound) 11 | * [`Default(value="")`](#setting-the-value-of-a-field) 12 | 13 | # Default enumeration 14 | 15 | You can use *derivative* to derive a default implementation on enumerations! 16 | This does not work with *rustc*'s `#[derive(Default)]`. 17 | All you need is to specify what variant is the default value: 18 | 19 | ```rust 20 | # extern crate derivative; 21 | # use derivative::Derivative; 22 | #[derive(Debug, Derivative)] 23 | #[derivative(Default)] 24 | enum Enum { 25 | A, 26 | #[derivative(Default)] 27 | B, 28 | } 29 | 30 | println!("{:?}", Enum::default()); // B 31 | ``` 32 | 33 | # Setting the value of a field 34 | 35 | You can use *derivative* to change the default value of a field in a `Default` 36 | implementation: 37 | 38 | ```rust 39 | # extern crate derivative; 40 | # use derivative::Derivative; 41 | #[derive(Debug, Derivative)] 42 | #[derivative(Default)] 43 | struct Foo { 44 | foo: u8, 45 | #[derivative(Default(value="42"))] 46 | bar: u8, 47 | } 48 | 49 | println!("{:?}", Foo::default()); // Foo { foo: 0, bar: 42 } 50 | ``` 51 | 52 | # `new` function 53 | 54 | You can use *derivative* to derive a convenience `new` method for your type 55 | that calls `Default::default`: 56 | 57 | ```rust 58 | # extern crate derivative; 59 | # use derivative::Derivative; 60 | #[derive(Debug, Derivative)] 61 | #[derivative(Default(new="true"))] 62 | struct Foo { 63 | foo: u8, 64 | bar: u8, 65 | } 66 | 67 | println!("{:?}", Foo::new()); // Foo { foo: 0, bar: 0 } 68 | ``` 69 | 70 | # Custom bound 71 | 72 | The following does not work because `derive` adds a `T: Default` bound on the 73 | `impl Default for Foo`: 74 | 75 | ```rust,compile_fail 76 | # extern crate derivative; 77 | # use derivative::Derivative; 78 | #[derive(Default)] 79 | struct Foo { 80 | foo: Option, 81 | } 82 | 83 | struct NonDefault; 84 | 85 | Foo::::default(); // gives: 86 | // error: no associated item named `default` found for type `Foo` in the current scope 87 | // = note: the method `default` exists but the following trait bounds were not satisfied: `NonDefault : std::default::Default` 88 | ``` 89 | 90 | That bound however is useless as `Option: Default` for any `T`. 91 | `derivative` allows you to explicitly specify a bound if the inferred one is not 92 | correct: 93 | 94 | ```rust 95 | # extern crate derivative; 96 | # use derivative::Derivative; 97 | #[derive(Derivative)] 98 | #[derivative(Default(bound=""))] // don't need any bound 99 | struct Foo { 100 | foo: Option, 101 | } 102 | 103 | struct NonDefault; 104 | 105 | Foo::::default(); // works! 106 | ``` 107 | -------------------------------------------------------------------------------- /src/hash.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2; 2 | 3 | use ast; 4 | use attr; 5 | use matcher; 6 | use paths; 7 | use syn; 8 | use utils; 9 | 10 | pub fn derive(input: &ast::Input) -> proc_macro2::TokenStream { 11 | let hasher_trait_path = hasher_trait_path(); 12 | let hash_trait_path = hash_trait_path(); 13 | 14 | let discriminant = if let ast::Body::Enum(_) = input.body { 15 | let discriminant = paths::discriminant_path(); 16 | Some(quote!( 17 | #hash_trait_path::hash(&#discriminant(self), __state); 18 | )) 19 | } else { 20 | None 21 | }; 22 | 23 | let body = matcher::Matcher::new(matcher::BindingStyle::Ref, input.attrs.is_packed).build_arms( 24 | input, 25 | "__arg", 26 | |_, _, _, _, _, bis| { 27 | let field_prints = bis.iter().filter_map(|bi| { 28 | if bi.field.attrs.ignore_hash() { 29 | return None; 30 | } 31 | 32 | let arg = &bi.expr; 33 | 34 | if let Some(hash_with) = bi.field.attrs.hash_with() { 35 | Some(quote! { 36 | #hash_with(&#arg, __state); 37 | }) 38 | } else { 39 | Some(quote! { 40 | #hash_trait_path::hash(&#arg, __state); 41 | }) 42 | } 43 | }); 44 | 45 | quote! { 46 | #(#field_prints)* 47 | } 48 | }, 49 | ); 50 | 51 | let name = &input.ident; 52 | let generics = utils::build_impl_generics( 53 | input, 54 | &hash_trait_path, 55 | needs_hash_bound, 56 | |field| field.hash_bound(), 57 | |input| input.hash_bound(), 58 | ); 59 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 60 | 61 | let hasher_ty_parameter = utils::hygienic_type_parameter(input, "__H"); 62 | quote! { 63 | #[allow(unused_qualifications)] 64 | impl #impl_generics #hash_trait_path for #name #ty_generics #where_clause { 65 | fn hash<#hasher_ty_parameter>(&self, __state: &mut #hasher_ty_parameter) 66 | where #hasher_ty_parameter: #hasher_trait_path 67 | { 68 | #discriminant 69 | match *self { 70 | #body 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | fn needs_hash_bound(attrs: &attr::Field) -> bool { 78 | !attrs.ignore_hash() && attrs.hash_bound().is_none() 79 | } 80 | 81 | /// Return the path of the `Hash` trait, that is `::std::hash::Hash`. 82 | fn hash_trait_path() -> syn::Path { 83 | if cfg!(feature = "use_core") { 84 | parse_quote!(::core::hash::Hash) 85 | } else { 86 | parse_quote!(::std::hash::Hash) 87 | } 88 | } 89 | 90 | /// Return the path of the `Hasher` trait, that is `::std::hash::Hasher`. 91 | fn hasher_trait_path() -> syn::Path { 92 | if cfg!(feature = "use_core") { 93 | parse_quote!(::core::hash::Hasher) 94 | } else { 95 | parse_quote!(::std::hash::Hasher) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Continuous integration 4 | 5 | jobs: 6 | check: 7 | name: Check 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | rust: 12 | - 1.34.0 13 | - stable 14 | - beta 15 | - nightly 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions-rs/toolchain@v1 19 | with: 20 | profile: minimal 21 | toolchain: ${{ matrix.rust }} 22 | override: true 23 | - uses: actions-rs/cargo@v1 24 | with: 25 | command: check 26 | 27 | test: 28 | name: Test Suite 29 | runs-on: ${{ matrix.os }} 30 | strategy: 31 | matrix: 32 | os: 33 | - ubuntu-18.04 34 | - macos-latest 35 | - windows-latest 36 | rust: 37 | - 1.34.0 38 | - stable 39 | - beta 40 | - nightly 41 | features: 42 | - '' 43 | - 'use_core' 44 | extra_args: 45 | - '' 46 | include: 47 | # The compiler output isn't stable from one version to another of rustc, so we only 48 | # test that on one version 49 | - os: ubuntu-18.04 50 | rust: 1.34.0 51 | features: '' 52 | extra_args: '' 53 | - os: ubuntu-18.04 54 | rust: 1.34.0 55 | features: '' 56 | extra_args: 'compile_test -- --ignored' 57 | - os: ubuntu-18.04 58 | rust: 1.34.0 59 | features: 'use_core' 60 | extra_args: '' 61 | - os: ubuntu-18.04 62 | rust: 1.34.0 63 | features: 'use_core' 64 | extra_args: 'compile_test -- --ignored' 65 | steps: 66 | - uses: actions/checkout@v2 67 | - uses: actions-rs/toolchain@v1 68 | with: 69 | profile: minimal 70 | toolchain: ${{ matrix.rust }} 71 | override: true 72 | - uses: actions-rs/cargo@v1 73 | env: 74 | RUST_BACKTRACE: 1 75 | with: 76 | command: test 77 | args: --features=${{ matrix.features }} ${{ matrix.extra_args }} 78 | - uses: actions-rs/toolchain@v1 79 | with: 80 | profile: minimal 81 | toolchain: stable 82 | - run: cargo +stable install mdbook --no-default-features --features search --vers "^0.4.0" 83 | - run: mdbook build 84 | - run: mdbook test -L ./target/debug/deps/ 85 | if: ${{ matrix.features }} != 'use_core' 86 | 87 | clippy: 88 | name: Clippy 89 | runs-on: ubuntu-latest 90 | strategy: 91 | matrix: 92 | rust: 93 | - 1.34.0 94 | - stable 95 | features: 96 | - '' 97 | - 'use_core' 98 | steps: 99 | - uses: actions/checkout@v2 100 | - uses: actions-rs/toolchain@v1 101 | with: 102 | profile: minimal 103 | toolchain: ${{ matrix.rust }} 104 | override: true 105 | - run: rustup component add clippy 106 | - uses: actions-rs/cargo@v1 107 | with: 108 | command: clippy 109 | args: --all-targets --features=${{ matrix.features }} -- -D warnings -------------------------------------------------------------------------------- /tests/derive-partial-eq-packed.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::eq_op, clippy::trivially_copy_pass_by_ref)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | #[derive(Derivative)] 10 | #[derivative(PartialEq)] 11 | #[repr(C, packed)] 12 | struct Foo { 13 | foo: u8, 14 | } 15 | 16 | #[derive(Derivative)] 17 | #[derivative(PartialEq)] 18 | #[repr(C, packed)] 19 | struct WithPtr { 20 | #[derivative(PartialEq(bound = ""))] 21 | foo: *const T, 22 | } 23 | 24 | #[derive(Derivative)] 25 | #[derivative(PartialEq)] 26 | #[repr(C, packed)] 27 | struct Empty; 28 | 29 | #[derive(Derivative)] 30 | #[derivative(PartialEq)] 31 | #[repr(C, packed)] 32 | struct AllIgnored { 33 | #[derivative(PartialEq = "ignore")] 34 | foo: u8, 35 | } 36 | 37 | #[derive(Derivative)] 38 | #[derivative(PartialEq)] 39 | #[repr(C, packed)] 40 | struct OneIgnored { 41 | #[derivative(PartialEq = "ignore")] 42 | foo: u8, 43 | bar: u8, 44 | } 45 | 46 | #[derive(Derivative)] 47 | #[derivative(PartialEq)] 48 | #[repr(C, packed)] 49 | struct Parity(#[derivative(PartialEq(compare_with = "same_parity"))] u8); 50 | 51 | fn same_parity(lhs: &u8, rhs: &u8) -> bool { 52 | lhs % 2 == rhs % 2 53 | } 54 | 55 | #[derive(Derivative)] 56 | #[derivative(PartialEq)] 57 | #[repr(C, packed)] 58 | struct Generic(#[derivative(PartialEq(compare_with = "dummy_cmp", bound = ""))] T); 59 | 60 | fn dummy_cmp(_: &T, _: &T) -> bool { 61 | true 62 | } 63 | 64 | struct NonPartialEq; 65 | 66 | #[derive(Derivative)] 67 | #[derivative(PartialEq, Eq)] 68 | #[repr(C, packed)] 69 | struct GenericIgnore { 70 | f: u32, 71 | #[derivative(PartialEq = "ignore")] 72 | t: T, 73 | } 74 | 75 | trait SomeTrait {} 76 | 77 | #[derive(Copy, Clone)] 78 | struct SomeType { 79 | #[allow(dead_code)] 80 | foo: u8, 81 | } 82 | impl SomeTrait for SomeType {} 83 | 84 | #[test] 85 | fn main() { 86 | assert!(Foo { foo: 7 } == Foo { foo: 7 }); 87 | assert!(Foo { foo: 7 } != Foo { foo: 42 }); 88 | 89 | let ptr1: *const dyn SomeTrait = &SomeType { foo: 0 }; 90 | let ptr2: *const dyn SomeTrait = &SomeType { foo: 1 }; 91 | assert!(WithPtr { foo: ptr1 } == WithPtr { foo: ptr1 }); 92 | assert!(WithPtr { foo: ptr1 } != WithPtr { foo: ptr2 }); 93 | 94 | assert!(Empty == Empty); 95 | assert!(AllIgnored { foo: 0 } == AllIgnored { foo: 42 }); 96 | assert!(OneIgnored { foo: 0, bar: 6 } == OneIgnored { foo: 42, bar: 6 }); 97 | assert!(OneIgnored { foo: 0, bar: 6 } != OneIgnored { foo: 42, bar: 7 }); 98 | 99 | assert!(Option::Some(42) == Option::Some(42)); 100 | assert!(Option::Some(0) != Option::Some(42)); 101 | assert!(Option::Some(42) != Option::None); 102 | assert!(Option::None != Option::Some(42)); 103 | assert!(Option::None:: == Option::None::); 104 | 105 | assert!(Parity(3) == Parity(7)); 106 | assert!(Parity(2) == Parity(42)); 107 | assert!(Parity(3) != Parity(42)); 108 | assert!(Parity(2) != Parity(7)); 109 | 110 | assert!(Generic(SomeType { foo: 0 }) == Generic(SomeType { foo: 0 })); 111 | assert!( 112 | GenericIgnore { 113 | f: 123, 114 | t: NonPartialEq 115 | } == GenericIgnore { 116 | f: 123, 117 | t: NonPartialEq 118 | } 119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // We need to support Rust 1.34 to stable 2 | #![allow(deprecated)] 3 | #![allow(renamed_and_removed_lints)] // support for multiple Clippy versions 4 | #![allow(clippy::unknown_clippy_lints)] // because of other #![allow]s 5 | #![allow(clippy::mem_replace_with_default)] // needs rustc 1.40 6 | #![allow(clippy::option_as_ref_deref)] // needs rustc 1.40 7 | #![allow(clippy::cyclomatic_complexity)] // old name of cognitive_complexity 8 | #![allow(clippy::cognitive_complexity)] // in code generated by macros 9 | #![allow(clippy::redundant_closure)] 10 | 11 | extern crate proc_macro; 12 | extern crate proc_macro2; 13 | #[macro_use] 14 | extern crate syn; 15 | 16 | #[macro_use] 17 | extern crate quote; 18 | 19 | mod ast; 20 | mod attr; 21 | mod bound; 22 | mod clone; 23 | mod cmp; 24 | mod debug; 25 | mod default; 26 | mod hash; 27 | mod matcher; 28 | mod paths; 29 | mod utils; 30 | 31 | use proc_macro::TokenStream; 32 | 33 | fn derive_impls( 34 | input: &mut ast::Input, 35 | errors: &mut proc_macro2::TokenStream, 36 | ) -> proc_macro2::TokenStream { 37 | let mut tokens = proc_macro2::TokenStream::new(); 38 | 39 | if input.attrs.clone.is_some() { 40 | tokens.extend(clone::derive_clone(input)); 41 | } 42 | if input.attrs.copy.is_some() { 43 | tokens.extend(clone::derive_copy(input)); 44 | } 45 | if input.attrs.debug.is_some() { 46 | tokens.extend(debug::derive(input)); 47 | } 48 | if let Some(ref default) = input.attrs.default { 49 | tokens.extend(default::derive(input, default)); 50 | } 51 | if input.attrs.eq.is_some() { 52 | tokens.extend(cmp::derive_eq(input)); 53 | } 54 | if input.attrs.hash.is_some() { 55 | tokens.extend(hash::derive(input)); 56 | } 57 | if input.attrs.partial_eq.is_some() { 58 | tokens.extend(cmp::derive_partial_eq(input)); 59 | } 60 | if input.attrs.partial_ord.is_some() { 61 | tokens.extend(cmp::derive_partial_ord(input, errors)); 62 | } 63 | if input.attrs.ord.is_some() { 64 | tokens.extend(cmp::derive_ord(input, errors)); 65 | } 66 | 67 | tokens.extend(std::mem::replace(errors, Default::default())); 68 | 69 | tokens 70 | } 71 | 72 | #[cfg(not(tarpaulin_include))] 73 | #[cfg_attr(not(test), proc_macro_derive(Derivative, attributes(derivative)))] 74 | pub fn derivative(input: TokenStream) -> TokenStream { 75 | derivative_internal(syn::parse_macro_input!(input as syn::DeriveInput)).into() 76 | } 77 | 78 | fn derivative_internal(input: syn::DeriveInput) -> proc_macro2::TokenStream { 79 | let mut errors = proc_macro2::TokenStream::new(); 80 | 81 | let mut output = ast::Input::from_ast(&input, &mut errors) 82 | .map(|mut input| derive_impls(&mut input, &mut errors)) 83 | .unwrap_or_default(); 84 | 85 | output.extend(errors); 86 | output 87 | } 88 | 89 | #[test] 90 | fn macro_code_coverage() { 91 | for entry in walkdir::WalkDir::new("tests") 92 | .into_iter() 93 | .map(|e| e.unwrap()) 94 | .filter(|e| e.file_type().is_file()) 95 | .filter(|e| e.path().extension().map(|e| e == "rs").unwrap_or(false)) 96 | { 97 | let file = std::fs::File::open(entry.path()).unwrap(); 98 | 99 | runtime_macros_derive::emulate_derive_expansion_fallible( 100 | file, 101 | "Derivative", 102 | derivative_internal, 103 | ) 104 | .unwrap(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /tests/derive-hash.rs: -------------------------------------------------------------------------------- 1 | //! This tests that we compute the same hash as `derive(Hash)`. 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | #[macro_use] 7 | extern crate derivative; 8 | 9 | macro_rules! define { 10 | ($kw:tt $($rest:tt)*) => { 11 | #[derive(Derivative)] 12 | #[derivative(Hash)] 13 | $kw Ours $($rest)* 14 | 15 | #[derive(Hash)] 16 | $kw Theirs $($rest)* 17 | } 18 | } 19 | 20 | struct FakeHasher<'a>(&'a mut Vec); 21 | impl<'a> ::std::hash::Hasher for FakeHasher<'a> { 22 | #[cfg(not(tarpaulin_include))] 23 | fn finish(&self) -> u64 { 24 | unimplemented!() 25 | } 26 | 27 | fn write(&mut self, bytes: &[u8]) { 28 | self.0.extend(bytes); 29 | } 30 | } 31 | 32 | fn fake_hash(e: E) -> Vec { 33 | let mut v = Vec::new(); 34 | e.hash(&mut FakeHasher(&mut v)); 35 | v 36 | } 37 | 38 | #[test] 39 | fn main() { 40 | { 41 | define! { 42 | struct; 43 | } 44 | 45 | assert_eq!(fake_hash(Ours), fake_hash(Theirs)); 46 | } 47 | 48 | { 49 | define! { 50 | struct { 51 | foo: u8 52 | } 53 | } 54 | 55 | assert_eq!(fake_hash(Ours { foo: 0 }), fake_hash(Theirs { foo: 0 })); 56 | assert_eq!(fake_hash(Ours { foo: 42 }), fake_hash(Theirs { foo: 42 })); 57 | } 58 | 59 | { 60 | define! { 61 | struct<'a> { 62 | foo: u8, 63 | bar: &'a str, 64 | } 65 | } 66 | 67 | assert_eq!(fake_hash(Ours { foo: 0, bar: "bar" }), fake_hash(Theirs { foo: 0, bar: "bar" })); 68 | assert_eq!(fake_hash(Ours { foo: 42, bar: "bar" }), fake_hash(Theirs { foo: 42, bar: "bar" })); 69 | } 70 | 71 | { 72 | define! { 73 | struct<'a> (u8, &'a str); 74 | } 75 | 76 | assert_eq!(fake_hash(Ours ( 0, "bar" )), fake_hash(Theirs ( 0, "bar" ))); 77 | assert_eq!(fake_hash(Ours ( 42, "bar" )), fake_hash(Theirs ( 42, "bar" ))); 78 | } 79 | 80 | { 81 | define! { 82 | enum { 83 | A, B, C 84 | } 85 | } 86 | 87 | assert_eq!(fake_hash(Ours::A), fake_hash(Theirs::A)); 88 | assert_eq!(fake_hash(Ours::B), fake_hash(Theirs::B)); 89 | assert_eq!(fake_hash(Ours::C), fake_hash(Theirs::C)); 90 | } 91 | 92 | { 93 | define! { 94 | enum { 95 | A, B = 42, C 96 | } 97 | } 98 | 99 | assert_eq!(fake_hash(Ours::A), fake_hash(Theirs::A)); 100 | assert_eq!(fake_hash(Ours::B), fake_hash(Theirs::B)); 101 | assert_eq!(fake_hash(Ours::C), fake_hash(Theirs::C)); 102 | } 103 | 104 | { 105 | define! { 106 | enum { 107 | A, B = 42, C=1 108 | } 109 | } 110 | 111 | assert_eq!(fake_hash(Ours::A), fake_hash(Theirs::A)); 112 | assert_eq!(fake_hash(Ours::B), fake_hash(Theirs::B)); 113 | assert_eq!(fake_hash(Ours::C), fake_hash(Theirs::C)); 114 | } 115 | 116 | { 117 | #[derive(Derivative)] 118 | #[derivative(Hash)] 119 | struct Ours<'a> { 120 | foo: u8, 121 | #[derivative(Hash="ignore")] 122 | bar: &'a str, 123 | baz: i64, 124 | } 125 | 126 | #[derive(Hash)] 127 | struct Theirs { 128 | foo: u8, 129 | baz: i64, 130 | } 131 | 132 | assert_eq!(fake_hash(Ours { foo: 0, bar: "bar", baz: 312 }), fake_hash(Theirs { foo: 0, baz: 312 })); 133 | assert_eq!(fake_hash(Ours { foo: 42, bar: "bar", baz: 312 }), fake_hash(Theirs { foo: 42, baz: 312 })); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /tests/rustc-issue-28561.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![allow(clippy::zero_prefixed_literal, clippy::type_complexity)] 12 | 13 | #[cfg(feature = "use_core")] 14 | extern crate core; 15 | 16 | #[macro_use] 17 | extern crate derivative; 18 | 19 | #[derive(Derivative)] 20 | #[derivative(Debug, Default, Eq, Hash, PartialEq)] 21 | // TODO: Ord, PartialOrd 22 | struct Array { 23 | f00: [T; 00], 24 | f01: [T; 01], 25 | f02: [T; 02], 26 | f03: [T; 03], 27 | f04: [T; 04], 28 | f05: [T; 05], 29 | f06: [T; 06], 30 | f07: [T; 07], 31 | f08: [T; 08], 32 | f09: [T; 09], 33 | f10: [T; 10], 34 | f11: [T; 11], 35 | f12: [T; 12], 36 | f13: [T; 13], 37 | f14: [T; 14], 38 | f15: [T; 15], 39 | f16: [T; 16], 40 | f17: [T; 17], 41 | f18: [T; 18], 42 | f19: [T; 19], 43 | f20: [T; 20], 44 | f21: [T; 21], 45 | f22: [T; 22], 46 | f23: [T; 23], 47 | f24: [T; 24], 48 | f25: [T; 25], 49 | f26: [T; 26], 50 | f27: [T; 27], 51 | f28: [T; 28], 52 | f29: [T; 29], 53 | f30: [T; 30], 54 | f31: [T; 31], 55 | f32: [T; 32], 56 | } 57 | 58 | // FIXME(#7622): merge with `Array` once `[T; N]: Clone` where `T: Clone` 59 | #[derive(Derivative)] 60 | #[derivative(Clone, Copy)] 61 | struct CopyArray { 62 | f00: [T; 00], 63 | f01: [T; 01], 64 | f02: [T; 02], 65 | f03: [T; 03], 66 | f04: [T; 04], 67 | f05: [T; 05], 68 | f06: [T; 06], 69 | f07: [T; 07], 70 | f08: [T; 08], 71 | f09: [T; 09], 72 | f10: [T; 10], 73 | f11: [T; 11], 74 | f12: [T; 12], 75 | f13: [T; 13], 76 | f14: [T; 14], 77 | f15: [T; 15], 78 | f16: [T; 16], 79 | f17: [T; 17], 80 | f18: [T; 18], 81 | f19: [T; 19], 82 | f20: [T; 20], 83 | f21: [T; 21], 84 | f22: [T; 22], 85 | f23: [T; 23], 86 | f24: [T; 24], 87 | f25: [T; 25], 88 | f26: [T; 26], 89 | f27: [T; 27], 90 | f28: [T; 28], 91 | f29: [T; 29], 92 | f30: [T; 30], 93 | f31: [T; 31], 94 | f32: [T; 32], 95 | } 96 | 97 | #[derive(Derivative)] 98 | #[derivative(Clone, Copy, Debug, Eq, Hash, PartialEq)] 99 | // TODO: Ord, PartialOrd 100 | struct Fn { 101 | f00: fn(), 102 | f01: fn(A), 103 | f02: fn(A, B), 104 | f03: fn(A, B, C), 105 | f04: fn(A, B, C, D), 106 | f05: fn(A, B, C, D, E), 107 | f06: fn(A, B, C, D, E, F), 108 | f07: fn(A, B, C, D, E, F, G), 109 | f08: fn(A, B, C, D, E, F, G, H), 110 | f09: fn(A, B, C, D, E, F, G, H, I), 111 | f10: fn(A, B, C, D, E, F, G, H, I, J), 112 | f11: fn(A, B, C, D, E, F, G, H, I, J, K), 113 | f12: fn(A, B, C, D, E, F, G, H, I, J, K, L), 114 | } 115 | 116 | #[derive(Derivative)] 117 | #[derivative(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] 118 | // TODO: Ord, PartialOrd 119 | struct Tuple { 120 | f00: (), 121 | f01: (A,), 122 | f02: (A, B), 123 | f03: (A, B, C), 124 | f04: (A, B, C, D), 125 | f05: (A, B, C, D, E), 126 | f06: (A, B, C, D, E, F), 127 | f07: (A, B, C, D, E, F, G), 128 | f08: (A, B, C, D, E, F, G, H), 129 | f09: (A, B, C, D, E, F, G, H, I), 130 | f10: (A, B, C, D, E, F, G, H, I, J), 131 | f11: (A, B, C, D, E, F, G, H, I, J, K), 132 | f12: (A, B, C, D, E, F, G, H, I, J, K, L), 133 | } 134 | 135 | #[test] 136 | fn main() {} 137 | -------------------------------------------------------------------------------- /tests/derive-partial-eq.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::eq_op, clippy::trivially_copy_pass_by_ref, dead_code)] 2 | 3 | #[cfg(feature = "use_core")] 4 | extern crate core; 5 | 6 | use std::marker::PhantomData; 7 | 8 | #[macro_use] 9 | extern crate derivative; 10 | 11 | #[derive(Derivative)] 12 | #[derivative(PartialEq)] 13 | struct Foo { 14 | foo: u8, 15 | } 16 | 17 | /// Test for backward compatibility. 18 | #[derive(Derivative)] 19 | #[derivative(PartialEq = "feature_allow_slow_enum")] 20 | #[allow(unused)] 21 | enum AllowsFeature { 22 | Some(T), 23 | None, 24 | } 25 | 26 | #[derive(Derivative)] 27 | #[derivative(PartialEq)] 28 | enum Option { 29 | Some(T), 30 | None, 31 | } 32 | 33 | #[derive(Derivative)] 34 | #[derivative(PartialEq)] 35 | enum SimpleEnum { 36 | Some, 37 | None, 38 | } 39 | 40 | #[derive(Derivative)] 41 | #[derivative(PartialEq)] 42 | enum UnitEnum { 43 | Single, 44 | } 45 | 46 | #[derive(Derivative)] 47 | #[derivative(PartialEq)] 48 | struct WithPtr { 49 | #[derivative(PartialEq(bound = ""))] 50 | foo: *const T, 51 | } 52 | 53 | #[derive(Derivative)] 54 | #[derivative(PartialEq)] 55 | struct Empty; 56 | 57 | #[derive(Derivative)] 58 | #[derivative(PartialEq)] 59 | struct AllIgnored { 60 | #[derivative(PartialEq = "ignore")] 61 | foo: u8, 62 | } 63 | 64 | #[derive(Derivative)] 65 | #[derivative(PartialEq)] 66 | struct OneIgnored { 67 | #[derivative(PartialEq = "ignore")] 68 | foo: u8, 69 | bar: u8, 70 | } 71 | 72 | #[derive(Derivative)] 73 | #[derivative(PartialEq)] 74 | struct Parity(#[derivative(PartialEq(compare_with = "same_parity"))] u8); 75 | 76 | fn same_parity(lhs: &u8, rhs: &u8) -> bool { 77 | lhs % 2 == rhs % 2 78 | } 79 | 80 | #[derive(Derivative)] 81 | #[derivative(PartialEq)] 82 | struct Generic(#[derivative(PartialEq(compare_with = "dummy_cmp", bound = ""))] T); 83 | 84 | fn dummy_cmp(_: &T, _: &T) -> bool { 85 | true 86 | } 87 | 88 | struct NonPartialEq; 89 | 90 | #[derive(Derivative)] 91 | #[derivative(PartialEq, Eq)] 92 | struct GenericIgnore { 93 | f: u32, 94 | #[derivative(PartialEq = "ignore")] 95 | t: PhantomData, 96 | } 97 | 98 | trait SomeTrait {} 99 | struct SomeType { 100 | #[allow(dead_code)] 101 | foo: u8, 102 | } 103 | impl SomeTrait for SomeType {} 104 | 105 | #[test] 106 | fn main() { 107 | assert!(Foo { foo: 7 } == Foo { foo: 7 }); 108 | assert!(Foo { foo: 7 } != Foo { foo: 42 }); 109 | 110 | let ptr1: *const dyn SomeTrait = &SomeType { foo: 0 }; 111 | let ptr2: *const dyn SomeTrait = &SomeType { foo: 1 }; 112 | assert!(WithPtr { foo: ptr1 } == WithPtr { foo: ptr1 }); 113 | assert!(WithPtr { foo: ptr1 } != WithPtr { foo: ptr2 }); 114 | 115 | assert!(Empty == Empty); 116 | assert!(AllIgnored { foo: 0 } == AllIgnored { foo: 42 }); 117 | assert!(OneIgnored { foo: 0, bar: 6 } == OneIgnored { foo: 42, bar: 6 }); 118 | assert!(OneIgnored { foo: 0, bar: 6 } != OneIgnored { foo: 42, bar: 7 }); 119 | 120 | assert!(Option::Some(42) == Option::Some(42)); 121 | assert!(Option::Some(0) != Option::Some(42)); 122 | assert!(Option::Some(42) != Option::None); 123 | assert!(Option::None != Option::Some(42)); 124 | assert!(Option::None:: == Option::None::); 125 | 126 | assert!(SimpleEnum::Some == SimpleEnum::Some); 127 | assert!(SimpleEnum::None == SimpleEnum::None); 128 | assert!(SimpleEnum::Some != SimpleEnum::None); 129 | assert!(SimpleEnum::None != SimpleEnum::Some); 130 | 131 | assert!(UnitEnum::Single == UnitEnum::Single); 132 | 133 | assert!(Parity(3) == Parity(7)); 134 | assert!(Parity(2) == Parity(42)); 135 | assert!(Parity(3) != Parity(42)); 136 | assert!(Parity(2) != Parity(7)); 137 | 138 | assert!(Generic(SomeType { foo: 0 }) == Generic(SomeType { foo: 0 })); 139 | assert!( 140 | GenericIgnore { 141 | f: 123, 142 | t: PhantomData::::default() 143 | } == GenericIgnore { 144 | f: 123, 145 | t: PhantomData::::default() 146 | } 147 | ); 148 | } 149 | -------------------------------------------------------------------------------- /src/default.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2; 2 | 3 | use ast; 4 | use attr; 5 | use syn; 6 | use utils; 7 | 8 | /// Derive `Default` for `input`. 9 | pub fn derive(input: &ast::Input, default: &attr::InputDefault) -> proc_macro2::TokenStream { 10 | fn make_variant_data( 11 | variant_name: &proc_macro2::TokenStream, 12 | style: ast::Style, 13 | fields: &[ast::Field], 14 | ) -> proc_macro2::TokenStream { 15 | let default_trait_path = default_trait_path(); 16 | 17 | match style { 18 | ast::Style::Struct => { 19 | let mut defaults = Vec::new(); 20 | 21 | for f in fields { 22 | let name = f 23 | .ident 24 | .as_ref() 25 | .expect("A structure field must have a name"); 26 | let default = f 27 | .attrs 28 | .default_value() 29 | .map_or_else(|| quote!(#default_trait_path::default()), |v| quote!(#v)); 30 | 31 | defaults.push(quote!(#name: #default)); 32 | } 33 | 34 | quote!(#variant_name { #(#defaults),* }) 35 | } 36 | ast::Style::Tuple => { 37 | let mut defaults = Vec::new(); 38 | 39 | for f in fields { 40 | let default = f 41 | .attrs 42 | .default_value() 43 | .map_or_else(|| quote!(#default_trait_path::default()), |v| quote!(#v)); 44 | 45 | defaults.push(default); 46 | } 47 | 48 | quote!(#variant_name ( #(#defaults),* )) 49 | } 50 | ast::Style::Unit => quote!(#variant_name), 51 | } 52 | } 53 | 54 | let name = &input.ident; 55 | let default_trait_path = default_trait_path(); 56 | let generics = utils::build_impl_generics( 57 | input, 58 | &default_trait_path, 59 | |attrs| attrs.default_bound().is_none(), 60 | |field| field.default_bound(), 61 | |input| input.default_bound(), 62 | ); 63 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 64 | 65 | let body = match input.body { 66 | ast::Body::Enum(ref data) => { 67 | let arms = data.iter().filter_map(|variant| { 68 | if variant.attrs.default.is_some() { 69 | let vname = &variant.ident; 70 | 71 | Some(make_variant_data( 72 | "e!(#name::#vname), 73 | variant.style, 74 | &variant.fields, 75 | )) 76 | } else { 77 | None 78 | } 79 | }); 80 | 81 | quote!(#(#arms),*) 82 | } 83 | ast::Body::Struct(style, ref vd) => make_variant_data("e!(#name), style, vd), 84 | }; 85 | 86 | let new_fn = if default.new { 87 | Some(quote!( 88 | #[allow(unused_qualifications)] 89 | impl #impl_generics #name #ty_generics #where_clause { 90 | /// Creates a default value for this type. 91 | #[inline] 92 | pub fn new() -> Self { 93 | ::default() 94 | } 95 | } 96 | )) 97 | } else { 98 | None 99 | }; 100 | 101 | quote!( 102 | #new_fn 103 | 104 | #[allow(unused_qualifications)] 105 | impl #impl_generics #default_trait_path for #name #ty_generics #where_clause { 106 | fn default() -> Self { 107 | #body 108 | } 109 | } 110 | ) 111 | } 112 | 113 | /// Return the path of the `Default` trait, that is `::std::default::Default`. 114 | fn default_trait_path() -> syn::Path { 115 | if cfg!(feature = "use_core") { 116 | parse_quote!(::core::default::Default) 117 | } else { 118 | parse_quote!(::std::default::Default) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /doc/cmp.md: -------------------------------------------------------------------------------- 1 | # Custom attributes 2 | The `PartialEq`, `Eq`, `PartialOrd` and `Ord` traits support the following attributes: 3 | 4 | * **Container attributes** 5 | * [`(bound="")`](#custom-bound) 6 | * **Field attributes** 7 | * [`(bound="")`](#custom-bound) 8 | 9 | The `PartialEq`, `PartialOrd` and `Ord` traits also supports the following attributes: 10 | 11 | * **Container attributes** 12 | * [`="feature_allow_slow_enum"`](#enumerations) 13 | * **Field attributes** 14 | * [`="ignore"`](#ignoring-a-field) 15 | * [`(compare_with="")`](#compare-with) 16 | 17 | (These attributes are not relevant for `Eq` which is just a marker trait.) 18 | 19 | # Enumerations 20 | 21 | Unfortunately, there is no way for derivative to derive `PartialOrd` or `Ord` on 22 | enumerations as efficiently as the built-in `derive(…)` yet. 23 | 24 | If you want to use derivative on enumerations anyway, you can add 25 | 26 | ```rust,ignore 27 | #[derivative(PartialOrd="feature_allow_slow_enum")] 28 | ``` 29 | 30 | to your enumeration. This acts as a “feature-gate”. 31 | 32 | This attribute is also allowed for `PartialEq` for historical reason. It is not 33 | necessary anymore as of v2.1.0. It was never necessary nor allowed for `Eq`. 34 | 35 | # Ignoring a field 36 | 37 | You can use *derivative* to ignore a field when comparing: 38 | 39 | ```rust 40 | # extern crate derivative; 41 | # use derivative::Derivative; 42 | #[derive(Derivative)] 43 | #[derivative(PartialEq)] 44 | struct Foo { 45 | foo: u8, 46 | #[derivative(PartialEq="ignore")] 47 | bar: u8, 48 | } 49 | 50 | assert!(Foo { foo: 0, bar: 42 } == Foo { foo: 0, bar: 7}); 51 | assert!(Foo { foo: 42, bar: 0 } != Foo { foo: 7, bar: 0}); 52 | ``` 53 | 54 | # Compare with 55 | 56 | Usually fields are compared using `==`, `PartialOrd::partial_cmp` or `Ord::cmp`. You can use an alternative comparison 57 | function if you like: 58 | 59 | ```rust 60 | # extern crate derivative; 61 | # use derivative::Derivative; 62 | # mod path { 63 | # pub struct SomeTypeThatMightNotBePartialEq; 64 | # pub mod to { 65 | # pub fn my_cmp_fn(_: &super::SomeTypeThatMightNotBePartialEq, _: &super::SomeTypeThatMightNotBePartialEq) -> bool { false } 66 | # } 67 | # } 68 | # use path::SomeTypeThatMightNotBePartialEq; 69 | #[derive(Derivative)] 70 | #[derivative(PartialEq)] 71 | struct Foo { 72 | foo: u32, 73 | #[derivative(PartialEq(compare_with="path::to::my_cmp_fn"))] 74 | bar: SomeTypeThatMightNotBePartialEq, 75 | } 76 | ``` 77 | 78 | `foo` will be compared with `==` and `bar` will be compared with 79 | `path::to::my_cmp_fn` which must have the following prototype: 80 | 81 | | Trait | Signature | 82 | |--------------|-----------| 83 | | `PartialEq` | `fn my_cmp_fn(&T, &T) -> bool;` 84 | | `PartialOrd` | `fn my_cmp_fn(&T, &T) -> std::option::Option;` 85 | | `Ord` | `fn my_cmp_fn(&T, &T) -> std::cmp::Ordering;` 86 | 87 | # Custom bound 88 | 89 | Usually if you derive `CmpTrait`, a `T: CmpTrait` bound is added for each type parameter `T`. You can use 90 | override this behavior if the inferred bound is not correct for you. 91 | 92 | Eg. comparing raw pointers does not require the type to be `Eq`, so you could 93 | use: 94 | 95 | ```rust 96 | # extern crate derivative; 97 | # use derivative::Derivative; 98 | #[derive(Derivative)] 99 | #[derivative(PartialEq)] 100 | struct WithPtr { 101 | #[derivative(PartialEq(bound=""))] 102 | foo: *const T 103 | } 104 | ``` 105 | 106 | See [`Default`'s documentation](./Default.md#custom-bound) for more details. 107 | 108 | # Packed structures 109 | 110 | You can use *derivative* to implement the comparison traits on packed structures. Unlike the standard `derive`, *derivative* does not require the structure itself to be `Copy`, but like the standard `derive`, it requires each (non-ignored) field to be `Copy`. 111 | 112 | ```rust 113 | # extern crate derivative; 114 | # use derivative::Derivative; 115 | #[derive(Derivative)] 116 | #[derivative(PartialEq)] 117 | #[repr(C, packed)] 118 | struct Foo { 119 | f: u32, 120 | #[derivative(PartialEq = "ignore")] 121 | t: String, 122 | } 123 | ``` 124 | -------------------------------------------------------------------------------- /doc/Debug.md: -------------------------------------------------------------------------------- 1 | # Custom attributes 2 | The `Debug` trait supports the following attributes: 3 | 4 | * **Container attributes** 5 | * [`Debug(bound="")`](#custom-bound) 6 | * [`Debug="transparent"`](#hiding-newtypes) 7 | * **Variant attributes** 8 | * [`Debug="transparent"`](#hiding-newtypes) 9 | * **Field attributes** 10 | * [`Debug(bound="")`](#custom-bound) 11 | * [`Debug(format_with="")`](#format-with) 12 | * [`Debug="ignore"`](#ignoring-a-field) 13 | 14 | # Ignoring a field 15 | 16 | You can use *derivative* to hide fields from a structure or enumeration `Debug` 17 | implementation: 18 | 19 | ```rust 20 | # extern crate derivative; 21 | # use derivative::Derivative; 22 | #[derive(Derivative)] 23 | #[derivative(Debug)] 24 | struct Foo { 25 | foo: u8, 26 | #[derivative(Debug="ignore")] 27 | bar: u8, 28 | } 29 | 30 | println!("{:?}", Foo { foo: 42, bar: 1 }); // Foo { foo: 42 } 31 | ``` 32 | 33 | # Hiding newtypes 34 | 35 | You can use *derivative* to automatically unwrap newtypes and enumeration 36 | variants with only one field: 37 | 38 | ```rust 39 | # extern crate derivative; 40 | # use derivative::Derivative; 41 | #[derive(Derivative)] 42 | #[derivative(Debug="transparent")] 43 | struct A(isize); 44 | 45 | #[derive(Derivative)] 46 | #[derivative(Debug)] 47 | enum C { 48 | Foo(u8), 49 | #[derivative(Debug="transparent")] 50 | Bar(u8), 51 | } 52 | 53 | println!("{:?}", A(42)); // 42 54 | println!("{:?}", C::Bar(42)); // 42 55 | 56 | // But: 57 | println!("{:?}", C::Foo(42)); // Foo(42) 58 | ``` 59 | 60 | # Format with 61 | 62 | You can pass a field to a format function: 63 | 64 | ```rust 65 | # extern crate derivative; 66 | # use derivative::Derivative; 67 | # mod path { 68 | # pub struct SomeTypeThatMightNotBeDebug; 69 | # pub mod to { 70 | # pub fn my_fmt_fn(_: &super::SomeTypeThatMightNotBeDebug, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { unimplemented!() } 71 | # } 72 | # } 73 | # use path::SomeTypeThatMightNotBeDebug; 74 | #[derive(Derivative)] 75 | #[derivative(Debug)] 76 | struct Foo { 77 | foo: u32, 78 | #[derivative(Debug(format_with="path::to::my_fmt_fn"))] 79 | bar: SomeTypeThatMightNotBeDebug, 80 | } 81 | ``` 82 | 83 | The field `bar` will be displayed with `path::to::my_fmt_fn(&bar, &mut fmt)` 84 | where `fmt` is the current [`Formatter`]. 85 | 86 | The function must the following prototype: 87 | 88 | ```rust,ignore 89 | fn fmt(&T, &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>; 90 | ``` 91 | 92 | # Custom bound 93 | 94 | Usually, *derivative* will add a `T: Debug` bound for each type parameter `T` 95 | of the current type. If you do not want that, you can specify an explicit bound: 96 | 97 | * Either on the type. This replaces all bounds: 98 | 99 | ```rust 100 | # extern crate derivative; 101 | # use derivative::Derivative; 102 | # trait MyDebug { 103 | # fn my_fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>; 104 | # } 105 | # use std::fmt::Debug; 106 | #[derive(Derivative)] 107 | #[derivative(Debug(bound="T: Debug, U: MyDebug"))] 108 | struct Foo { 109 | foo: T, 110 | #[derivative(Debug(format_with="MyDebug::my_fmt"))] 111 | bar: U, 112 | } 113 | ``` 114 | 115 | * Or on a field. This replaces the bound *derivative* guessed for that field. The example below is equivalent to the above: 116 | 117 | ```rust 118 | # extern crate derivative; 119 | # use derivative::Derivative; 120 | # trait MyDebug { 121 | # fn my_fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>; 122 | # } 123 | #[derive(Derivative)] 124 | #[derivative(Debug)] 125 | struct Foo { 126 | foo: T, 127 | #[derivative(Debug(format_with="MyDebug::my_fmt", bound="U: MyDebug"))] 128 | bar: U, 129 | } 130 | ``` 131 | 132 | With `bound=""` it is possible to remove any bound for the type. This is useful 133 | if your type contains a `Foo` that is `Debug` even if `T` is not. 134 | 135 | [`Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html 136 | 137 | # Packed structures 138 | 139 | You can use *derivative* to implement `Debug` on packed structures. Unlike the standard `derive(debug)`, *derivative* does not require the structure itself to be `Copy`, but like the standard `derive(debug)`, it requires each (non-ignored) field to be `Copy`. 140 | 141 | ```rust 142 | # extern crate derivative; 143 | # use derivative::Derivative; 144 | #[derive(Derivative)] 145 | #[derivative(Debug)] 146 | #[repr(C, packed)] 147 | struct Foo { 148 | foo: u8, 149 | // `String` isn't `Copy` so it must be ignored to derive `Debug` 150 | #[derivative(Debug="ignore")] 151 | bar: String, 152 | } 153 | ``` -------------------------------------------------------------------------------- /src/ast.rs: -------------------------------------------------------------------------------- 1 | use attr; 2 | use proc_macro2; 3 | use syn; 4 | use syn::spanned::Spanned as SynSpanned; 5 | 6 | #[derive(Debug)] 7 | pub struct Input<'a> { 8 | pub attrs: attr::Input, 9 | pub body: Body<'a>, 10 | pub generics: &'a syn::Generics, 11 | pub ident: syn::Ident, 12 | pub span: proc_macro2::Span, 13 | } 14 | 15 | #[derive(Debug)] 16 | pub enum Body<'a> { 17 | Enum(Vec>), 18 | Struct(Style, Vec>), 19 | } 20 | 21 | #[derive(Debug)] 22 | pub struct Variant<'a> { 23 | pub attrs: attr::Input, 24 | pub fields: Vec>, 25 | pub ident: syn::Ident, 26 | pub style: Style, 27 | } 28 | 29 | #[derive(Debug)] 30 | pub struct Field<'a> { 31 | pub attrs: attr::Field, 32 | pub ident: Option, 33 | pub ty: &'a syn::Type, 34 | pub span: proc_macro2::Span, 35 | } 36 | 37 | #[derive(Clone, Copy, Debug)] 38 | pub enum Style { 39 | Struct, 40 | Tuple, 41 | Unit, 42 | } 43 | 44 | impl<'a> Input<'a> { 45 | pub fn from_ast( 46 | item: &'a syn::DeriveInput, 47 | errors: &mut proc_macro2::TokenStream, 48 | ) -> Result, ()> { 49 | let attrs = attr::Input::from_ast(&item.attrs, errors)?; 50 | 51 | let body = match item.data { 52 | syn::Data::Enum(syn::DataEnum { ref variants, .. }) => { 53 | Body::Enum(enum_from_ast(variants, errors)?) 54 | } 55 | syn::Data::Struct(syn::DataStruct { ref fields, .. }) => { 56 | let (style, fields) = struct_from_ast(fields, errors)?; 57 | Body::Struct(style, fields) 58 | } 59 | syn::Data::Union(..) => { 60 | errors.extend( 61 | syn::Error::new_spanned(item, "derivative does not support unions") 62 | .to_compile_error(), 63 | ); 64 | return Err(()); 65 | } 66 | }; 67 | 68 | Ok(Input { 69 | attrs, 70 | body, 71 | generics: &item.generics, 72 | ident: item.ident.clone(), 73 | span: item.span(), 74 | }) 75 | } 76 | 77 | /// Checks whether this type is an enum with only unit variants. 78 | pub fn is_trivial_enum(&self) -> bool { 79 | match &self.body { 80 | Body::Enum(e) => e.iter().all(|v| v.is_unit()), 81 | Body::Struct(..) => false, 82 | } 83 | } 84 | } 85 | 86 | impl<'a> Body<'a> { 87 | pub fn all_fields(&self) -> Vec<&Field> { 88 | match *self { 89 | Body::Enum(ref variants) => variants 90 | .iter() 91 | .flat_map(|variant| variant.fields.iter()) 92 | .collect(), 93 | Body::Struct(_, ref fields) => fields.iter().collect(), 94 | } 95 | } 96 | 97 | pub fn is_empty(&self) -> bool { 98 | match *self { 99 | Body::Enum(ref variants) => variants.is_empty(), 100 | Body::Struct(_, ref fields) => fields.is_empty(), 101 | } 102 | } 103 | } 104 | 105 | impl<'a> Variant<'a> { 106 | /// Checks whether this variant is a unit variant. 107 | pub fn is_unit(&self) -> bool { 108 | self.fields.is_empty() 109 | } 110 | } 111 | 112 | fn enum_from_ast<'a>( 113 | variants: &'a syn::punctuated::Punctuated, 114 | errors: &mut proc_macro2::TokenStream, 115 | ) -> Result>, ()> { 116 | variants 117 | .iter() 118 | .map(|variant| { 119 | let (style, fields) = struct_from_ast(&variant.fields, errors)?; 120 | Ok(Variant { 121 | attrs: attr::Input::from_ast(&variant.attrs, errors)?, 122 | fields, 123 | ident: variant.ident.clone(), 124 | style, 125 | }) 126 | }) 127 | .collect() 128 | } 129 | 130 | fn struct_from_ast<'a>( 131 | fields: &'a syn::Fields, 132 | errors: &mut proc_macro2::TokenStream, 133 | ) -> Result<(Style, Vec>), ()> { 134 | match *fields { 135 | syn::Fields::Named(ref fields) => { 136 | Ok((Style::Struct, fields_from_ast(&fields.named, errors)?)) 137 | } 138 | syn::Fields::Unnamed(ref fields) => { 139 | Ok((Style::Tuple, fields_from_ast(&fields.unnamed, errors)?)) 140 | } 141 | syn::Fields::Unit => Ok((Style::Unit, Vec::new())), 142 | } 143 | } 144 | 145 | fn fields_from_ast<'a>( 146 | fields: &'a syn::punctuated::Punctuated, 147 | errors: &mut proc_macro2::TokenStream, 148 | ) -> Result>, ()> { 149 | fields 150 | .iter() 151 | .map(|field| { 152 | Ok(Field { 153 | attrs: attr::Field::from_ast(field, errors)?, 154 | ident: field.ident.clone(), 155 | ty: &field.ty, 156 | span: field.span(), 157 | }) 158 | }) 159 | .collect() 160 | } 161 | -------------------------------------------------------------------------------- /src/bound.rs: -------------------------------------------------------------------------------- 1 | /* This file incorporates work covered by the following copyright and 2 | * permission notice: 3 | * Copyright 2016 The serde Developers. See 4 | * https://github.com/serde-rs/serde/blob/3f28a9324042950afa80354722aeeee1a55cbfa3/README.md#license. 5 | * 6 | * Licensed under the Apache License, Version 2.0 or the MIT license 8 | * , at your 9 | * option. This file may not be copied, modified, or distributed 10 | * except according to those terms. 11 | */ 12 | 13 | use ast; 14 | use attr; 15 | use std::collections::HashSet; 16 | use syn::{self, visit, GenericParam}; 17 | 18 | // use internals::ast::Item; 19 | // use internals::attr; 20 | 21 | /// Remove the default from every type parameter because in the generated `impl`s 22 | /// they look like associated types: "error: associated type bindings are not 23 | /// allowed here". 24 | pub fn without_defaults(generics: &syn::Generics) -> syn::Generics { 25 | syn::Generics { 26 | params: generics 27 | .params 28 | .iter() 29 | .map(|generic_param| match *generic_param { 30 | GenericParam::Type(ref ty_param) => syn::GenericParam::Type(syn::TypeParam { 31 | default: None, 32 | ..ty_param.clone() 33 | }), 34 | ref param => param.clone(), 35 | }) 36 | .collect(), 37 | ..generics.clone() 38 | } 39 | } 40 | 41 | pub fn with_where_predicates( 42 | generics: &syn::Generics, 43 | predicates: &[syn::WherePredicate], 44 | ) -> syn::Generics { 45 | let mut cloned = generics.clone(); 46 | cloned 47 | .make_where_clause() 48 | .predicates 49 | .extend(predicates.iter().cloned()); 50 | cloned 51 | } 52 | 53 | pub fn with_where_predicates_from_fields( 54 | item: &ast::Input, 55 | generics: &syn::Generics, 56 | from_field: F, 57 | ) -> syn::Generics 58 | where 59 | F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>, 60 | { 61 | let mut cloned = generics.clone(); 62 | { 63 | let fields = item.body.all_fields(); 64 | let field_where_predicates = fields 65 | .iter() 66 | .flat_map(|field| from_field(&field.attrs)) 67 | .flat_map(|predicates| predicates.to_vec()); 68 | 69 | cloned 70 | .make_where_clause() 71 | .predicates 72 | .extend(field_where_predicates); 73 | } 74 | cloned 75 | } 76 | 77 | /// Puts the given bound on any generic type parameters that are used in fields 78 | /// for which filter returns true. 79 | /// 80 | /// For example, the following structure needs the bound `A: Debug, B: Debug`. 81 | /// 82 | /// ```ignore 83 | /// struct S<'b, A, B: 'b, C> { 84 | /// a: A, 85 | /// b: Option<&'b B> 86 | /// #[derivative(Debug="ignore")] 87 | /// c: C, 88 | /// } 89 | /// ``` 90 | pub fn with_bound( 91 | item: &ast::Input, 92 | generics: &syn::Generics, 93 | filter: F, 94 | bound: &syn::Path, 95 | ) -> syn::Generics 96 | where 97 | F: Fn(&attr::Field) -> bool, 98 | { 99 | #[derive(Debug)] 100 | struct FindTyParams { 101 | /// Set of all generic type parameters on the current struct (A, B, C in 102 | /// the example). Initialized up front. 103 | all_ty_params: HashSet, 104 | /// Set of generic type parameters used in fields for which filter 105 | /// returns true (A and B in the example). Filled in as the visitor sees 106 | /// them. 107 | relevant_ty_params: HashSet, 108 | } 109 | impl<'ast> visit::Visit<'ast> for FindTyParams { 110 | fn visit_path(&mut self, path: &'ast syn::Path) { 111 | if is_phantom_data(path) { 112 | // Hardcoded exception, because `PhantomData` implements 113 | // most traits whether or not `T` implements it. 114 | return; 115 | } 116 | if path.leading_colon.is_none() && path.segments.len() == 1 { 117 | let id = &path.segments[0].ident; 118 | if self.all_ty_params.contains(id) { 119 | self.relevant_ty_params.insert(id.clone()); 120 | } 121 | } 122 | visit::visit_path(self, path); 123 | } 124 | } 125 | 126 | let all_ty_params: HashSet<_> = generics 127 | .type_params() 128 | .map(|ty_param| ty_param.ident.clone()) 129 | .collect(); 130 | 131 | let relevant_tys = item 132 | .body 133 | .all_fields() 134 | .into_iter() 135 | .filter(|field| { 136 | if let syn::Type::Path(syn::TypePath { ref path, .. }) = *field.ty { 137 | !is_phantom_data(path) 138 | } else { 139 | true 140 | } 141 | }) 142 | .filter(|field| filter(&field.attrs)) 143 | .map(|field| &field.ty); 144 | 145 | let mut visitor = FindTyParams { 146 | all_ty_params, 147 | relevant_ty_params: HashSet::new(), 148 | }; 149 | for ty in relevant_tys { 150 | visit::visit_type(&mut visitor, ty); 151 | } 152 | 153 | let mut cloned = generics.clone(); 154 | { 155 | let relevant_where_predicates = generics 156 | .type_params() 157 | .map(|ty_param| &ty_param.ident) 158 | .filter(|id| visitor.relevant_ty_params.contains(id)) 159 | .map(|id| -> syn::WherePredicate { parse_quote!( #id : #bound ) }); 160 | 161 | cloned 162 | .make_where_clause() 163 | .predicates 164 | .extend(relevant_where_predicates); 165 | } 166 | cloned 167 | } 168 | 169 | #[allow(clippy::match_like_matches_macro)] // needs rustc 1.42 170 | fn is_phantom_data(path: &syn::Path) -> bool { 171 | match path.segments.last() { 172 | Some(path) if path.ident == "PhantomData" => true, 173 | _ => false, 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/clone.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2; 2 | 3 | use ast; 4 | use attr; 5 | use matcher; 6 | use syn; 7 | use utils; 8 | 9 | /// Derive `Copy` for `input`. 10 | pub fn derive_copy(input: &ast::Input) -> proc_macro2::TokenStream { 11 | let name = &input.ident; 12 | 13 | let copy_trait_path = copy_trait_path(); 14 | let generics = utils::build_impl_generics( 15 | input, 16 | ©_trait_path, 17 | |attrs| attrs.copy_bound().is_none(), 18 | |field| field.copy_bound(), 19 | |input| input.copy_bound(), 20 | ); 21 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 22 | 23 | quote! { 24 | #[allow(unused_qualifications)] 25 | impl #impl_generics #copy_trait_path for #name #ty_generics #where_clause {} 26 | } 27 | } 28 | 29 | /// Derive `Clone` for `input`. 30 | pub fn derive_clone(input: &ast::Input) -> proc_macro2::TokenStream { 31 | let name = &input.ident; 32 | 33 | let clone_trait_path = clone_trait_path(); 34 | let generics = utils::build_impl_generics( 35 | input, 36 | &clone_trait_path, 37 | needs_clone_bound, 38 | |field| field.clone_bound(), 39 | |input| input.clone_bound(), 40 | ); 41 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 42 | 43 | let is_copy = input.attrs.copy.is_some(); 44 | if is_copy && input.generics.type_params().count() == 0 { 45 | quote! { 46 | #[allow(unused_qualifications)] 47 | impl #impl_generics #clone_trait_path for #name #ty_generics #where_clause { 48 | fn clone(&self) -> Self { 49 | *self 50 | } 51 | } 52 | } 53 | } else { 54 | let body = matcher::Matcher::new(matcher::BindingStyle::Ref, input.attrs.is_packed).build_arms( 55 | input, 56 | "__arg", 57 | |arm_path, _, _, style, _, bis| { 58 | let field_clones = bis.iter().map(|bi| { 59 | let arg = &bi.expr; 60 | 61 | let clone = if let Some(clone_with) = bi.field.attrs.clone_with() { 62 | quote!(#clone_with(&#arg)) 63 | } else { 64 | quote!(#arg.clone()) 65 | }; 66 | 67 | if let Some(ref name) = bi.field.ident { 68 | quote! { 69 | #name: #clone 70 | } 71 | } else { 72 | clone 73 | } 74 | }); 75 | 76 | match style { 77 | ast::Style::Struct => { 78 | quote! { 79 | #arm_path { 80 | #(#field_clones),* 81 | } 82 | } 83 | } 84 | ast::Style::Tuple => { 85 | quote! { 86 | #arm_path (#(#field_clones),*) 87 | } 88 | } 89 | ast::Style::Unit => { 90 | quote! { 91 | #arm_path 92 | } 93 | } 94 | } 95 | }, 96 | ); 97 | 98 | let clone_from = if input.attrs.clone_from() { 99 | Some( 100 | matcher::Matcher::new(matcher::BindingStyle::RefMut, input.attrs.is_packed).build_arms( 101 | input, 102 | "__arg", 103 | |outer_arm_path, _, _, _, _, outer_bis| { 104 | let body = matcher::Matcher::new(matcher::BindingStyle::Ref, input.attrs.is_packed).build_arms( 105 | input, 106 | "__other", 107 | |inner_arm_path, _, _, _, _, inner_bis| { 108 | if outer_arm_path == inner_arm_path { 109 | let field_clones = outer_bis.iter().zip(inner_bis).map( 110 | |(outer_bi, inner_bi)| { 111 | let outer = &outer_bi.expr; 112 | let inner = &inner_bi.expr; 113 | 114 | quote!(#outer.clone_from(&#inner);) 115 | }, 116 | ); 117 | 118 | quote! { 119 | #(#field_clones)* 120 | return; 121 | } 122 | } else { 123 | quote!() 124 | } 125 | }, 126 | ); 127 | 128 | quote! { 129 | match *other { 130 | #body 131 | } 132 | } 133 | }, 134 | ), 135 | ) 136 | } else { 137 | None 138 | }; 139 | 140 | let clone_from = clone_from.map(|body| { 141 | // Enumerations are only cloned-from if both variants are the same. 142 | // If they are different, fallback to normal cloning. 143 | let fallback = if let ast::Body::Enum(_) = input.body { 144 | Some(quote!(*self = other.clone();)) 145 | } else { 146 | None 147 | }; 148 | 149 | quote! { 150 | #[allow(clippy::needless_return)] 151 | fn clone_from(&mut self, other: &Self) { 152 | match *self { 153 | #body 154 | } 155 | 156 | #fallback 157 | } 158 | } 159 | }); 160 | 161 | quote! { 162 | #[allow(unused_qualifications)] 163 | impl #impl_generics #clone_trait_path for #name #ty_generics #where_clause { 164 | fn clone(&self) -> Self { 165 | match *self { 166 | #body 167 | } 168 | } 169 | 170 | #clone_from 171 | } 172 | } 173 | } 174 | } 175 | 176 | fn needs_clone_bound(attrs: &attr::Field) -> bool { 177 | attrs.clone_bound().is_none() 178 | } 179 | 180 | /// Return the path of the `Clone` trait, that is `::std::clone::Clone`. 181 | fn clone_trait_path() -> syn::Path { 182 | if cfg!(feature = "use_core") { 183 | parse_quote!(::core::clone::Clone) 184 | } else { 185 | parse_quote!(::std::clone::Clone) 186 | } 187 | } 188 | 189 | /// Return the path of the `Copy` trait, that is `::std::marker::Copy`. 190 | fn copy_trait_path() -> syn::Path { 191 | if cfg!(feature = "use_core") { 192 | parse_quote!(::core::marker::Copy) 193 | } else { 194 | parse_quote!(::std::marker::Copy) 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/debug.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2; 2 | 3 | use ast; 4 | use attr; 5 | use matcher; 6 | use syn; 7 | use syn::spanned::Spanned; 8 | use utils; 9 | 10 | pub fn derive(input: &ast::Input) -> proc_macro2::TokenStream { 11 | let debug_trait_path = debug_trait_path(); 12 | let fmt_path = fmt_path(); 13 | 14 | let formatter = quote_spanned! {input.span=> __f}; 15 | 16 | let body = matcher::Matcher::new(matcher::BindingStyle::Ref, input.attrs.is_packed) 17 | .with_field_filter(|f: &ast::Field| !f.attrs.ignore_debug()) 18 | .build_arms(input, "__arg", |_, _, arm_name, style, attrs, bis| { 19 | let field_prints = bis.iter().filter_map(|bi| { 20 | if bi.field.attrs.ignore_debug() { 21 | return None; 22 | } 23 | 24 | if attrs.debug_transparent() { 25 | return Some(quote_spanned! {arm_name.span()=> 26 | #debug_trait_path::fmt(__arg_0, #formatter) 27 | }); 28 | } 29 | 30 | let arg_expr = &bi.expr; 31 | let arg_ident = &bi.ident; 32 | 33 | let dummy_debug = bi.field.attrs.debug_format_with().map(|format_fn| { 34 | format_with( 35 | bi.field, 36 | &input.attrs.debug_bound(), 37 | &arg_expr, 38 | &arg_ident, 39 | format_fn, 40 | input.generics.clone(), 41 | ) 42 | }); 43 | let expr = if bi.field.attrs.debug_format_with().is_some() { 44 | quote_spanned! {arm_name.span()=> 45 | &#arg_ident 46 | } 47 | } else { 48 | quote_spanned! {arm_name.span()=> 49 | &&#arg_expr 50 | } 51 | }; 52 | 53 | let builder = if let Some(ref name) = bi.field.ident { 54 | let name = name.to_string(); 55 | quote_spanned! {arm_name.span()=> 56 | #dummy_debug 57 | let _ = __debug_trait_builder.field(#name, #expr); 58 | } 59 | } else { 60 | quote_spanned! {arm_name.span()=> 61 | #dummy_debug 62 | let _ = __debug_trait_builder.field(#expr); 63 | } 64 | }; 65 | 66 | Some(builder) 67 | }); 68 | 69 | let method = match style { 70 | ast::Style::Struct => "debug_struct", 71 | ast::Style::Tuple | ast::Style::Unit => "debug_tuple", 72 | }; 73 | let method = syn::Ident::new(method, proc_macro2::Span::call_site()); 74 | 75 | if attrs.debug_transparent() { 76 | quote_spanned! {arm_name.span()=> 77 | #(#field_prints)* 78 | } 79 | } else { 80 | let name = arm_name.to_string(); 81 | quote_spanned! {arm_name.span()=> 82 | let mut __debug_trait_builder = #formatter.#method(#name); 83 | #(#field_prints)* 84 | __debug_trait_builder.finish() 85 | } 86 | } 87 | }); 88 | 89 | let name = &input.ident; 90 | 91 | let generics = utils::build_impl_generics( 92 | input, 93 | &debug_trait_path, 94 | needs_debug_bound, 95 | |field| field.debug_bound(), 96 | |input| input.debug_bound(), 97 | ); 98 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 99 | 100 | // don't attach a span to prevent issue #58 101 | let match_self = quote!(match *self); 102 | quote_spanned! {input.span=> 103 | #[allow(unused_qualifications)] 104 | #[allow(clippy::unneeded_field_pattern)] 105 | impl #impl_generics #debug_trait_path for #name #ty_generics #where_clause { 106 | fn fmt(&self, #formatter: &mut #fmt_path::Formatter) -> #fmt_path::Result { 107 | #match_self { 108 | #body 109 | } 110 | } 111 | } 112 | } 113 | } 114 | 115 | fn needs_debug_bound(attrs: &attr::Field) -> bool { 116 | !attrs.ignore_debug() && attrs.debug_bound().is_none() 117 | } 118 | 119 | /// Return the path of the `Debug` trait, that is `::std::fmt::Debug`. 120 | fn debug_trait_path() -> syn::Path { 121 | if cfg!(feature = "use_core") { 122 | parse_quote!(::core::fmt::Debug) 123 | } else { 124 | parse_quote!(::std::fmt::Debug) 125 | } 126 | } 127 | 128 | /// Return the path of the `fmt` module, that is `::std::fmt`. 129 | fn fmt_path() -> syn::Path { 130 | if cfg!(feature = "use_core") { 131 | parse_quote!(::core::fmt) 132 | } else { 133 | parse_quote!(::std::fmt) 134 | } 135 | } 136 | 137 | /// Return the path of the `PhantomData` type, that is `::std::marker::PhantomData`. 138 | fn phantom_path() -> syn::Path { 139 | if cfg!(feature = "use_core") { 140 | parse_quote!(::core::marker::PhantomData) 141 | } else { 142 | parse_quote!(::std::marker::PhantomData) 143 | } 144 | } 145 | 146 | fn format_with( 147 | f: &ast::Field, 148 | bounds: &Option<&[syn::WherePredicate]>, 149 | arg_expr: &proc_macro2::TokenStream, 150 | arg_ident: &syn::Ident, 151 | format_fn: &syn::Path, 152 | mut generics: syn::Generics, 153 | ) -> proc_macro2::TokenStream { 154 | let debug_trait_path = debug_trait_path(); 155 | let fmt_path = fmt_path(); 156 | let phantom_path = phantom_path(); 157 | 158 | generics 159 | .make_where_clause() 160 | .predicates 161 | .extend(f.attrs.debug_bound().unwrap_or(&[]).iter().cloned()); 162 | 163 | generics 164 | .params 165 | .push(syn::GenericParam::Lifetime(syn::LifetimeDef::new( 166 | parse_quote!('_derivative), 167 | ))); 168 | let where_predicates = generics 169 | .type_params() 170 | .map(|ty| { 171 | let mut bounds = syn::punctuated::Punctuated::new(); 172 | bounds.push(syn::TypeParamBound::Lifetime(syn::Lifetime::new( 173 | "'_derivative", 174 | proc_macro2::Span::call_site(), 175 | ))); 176 | 177 | let path = syn::Path::from(syn::PathSegment::from(ty.ident.clone())); 178 | 179 | syn::WherePredicate::Type(syn::PredicateType { 180 | lifetimes: None, 181 | bounded_ty: syn::Type::Path(syn::TypePath { qself: None, path }), 182 | colon_token: Default::default(), 183 | bounds, 184 | }) 185 | }) 186 | .chain(bounds.iter().flat_map(|b| b.iter().cloned())) 187 | .collect::>(); 188 | generics 189 | .make_where_clause() 190 | .predicates 191 | .extend(where_predicates); 192 | 193 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 194 | 195 | let ty = f.ty; 196 | 197 | // Leave off the type parameter bounds, defaults, and attributes 198 | let phantom = generics.type_params().map(|tp| &tp.ident); 199 | 200 | let mut ctor_generics = generics.clone(); 201 | *ctor_generics 202 | .lifetimes_mut() 203 | .last() 204 | .expect("There must be a '_derivative lifetime") = syn::LifetimeDef::new(parse_quote!('_)); 205 | let (_, ctor_ty_generics, _) = ctor_generics.split_for_impl(); 206 | let ctor_ty_generics = ctor_ty_generics.as_turbofish(); 207 | 208 | // don't attach a span to prevent issue #58 209 | let match_self = quote!(match self.0); 210 | quote_spanned!(format_fn.span()=> 211 | let #arg_ident = { 212 | struct Dummy #impl_generics (&'_derivative #ty, #phantom_path <(#(#phantom,)*)>) #where_clause; 213 | 214 | impl #impl_generics #debug_trait_path for Dummy #ty_generics #where_clause { 215 | fn fmt(&self, __f: &mut #fmt_path::Formatter) -> #fmt_path::Result { 216 | #match_self { 217 | this => #format_fn(this, __f) 218 | } 219 | } 220 | } 221 | 222 | Dummy #ctor_ty_generics (&&#arg_expr, #phantom_path) 223 | }; 224 | ) 225 | } 226 | -------------------------------------------------------------------------------- /tests/derive-ord-packed.rs: -------------------------------------------------------------------------------- 1 | #![allow(renamed_and_removed_lints)] // clippy::cyclomatic_complexity → clippy::cognitive_complexity 2 | #![allow(clippy::cyclomatic_complexity)] 3 | #![allow(clippy::cognitive_complexity)] 4 | #![allow(clippy::trivially_copy_pass_by_ref)] 5 | #![allow(clippy::unknown_clippy_lints)] 6 | 7 | #[cfg(feature = "use_core")] 8 | extern crate core; 9 | 10 | #[macro_use] 11 | extern crate derivative; 12 | 13 | #[derive(PartialEq, Eq, Derivative)] 14 | #[derivative(PartialOrd, Ord)] 15 | #[repr(C, packed)] 16 | struct Foo { 17 | foo: u8, 18 | } 19 | 20 | #[derive(Derivative)] 21 | #[derivative(PartialEq, PartialOrd, Ord, Eq)] 22 | #[repr(C, packed)] 23 | struct WithPtr { 24 | #[derivative(PartialEq(bound = ""))] 25 | #[derivative(PartialOrd(bound = ""))] 26 | #[derivative(Ord(bound = ""))] 27 | #[derivative(Eq(bound = ""))] 28 | foo: *const T, 29 | } 30 | 31 | #[derive(PartialEq, Eq, Derivative)] 32 | #[derivative(PartialOrd, Ord)] 33 | #[repr(C, packed)] 34 | struct Empty; 35 | 36 | #[derive(PartialEq, Eq, Derivative)] 37 | #[derivative(PartialOrd, Ord)] 38 | #[repr(C, packed)] 39 | struct AllIgnored { 40 | #[derivative(PartialOrd = "ignore")] 41 | #[derivative(Ord = "ignore")] 42 | foo: u8, 43 | } 44 | 45 | #[derive(PartialEq, Eq, Derivative)] 46 | #[derivative(PartialOrd, Ord)] 47 | #[repr(C, packed)] 48 | struct OneIgnored { 49 | #[derivative(PartialOrd = "ignore")] 50 | #[derivative(Ord = "ignore")] 51 | foo: u8, 52 | bar: u8, 53 | } 54 | 55 | #[derive(PartialEq, Eq, Derivative)] 56 | #[derivative(PartialOrd, Ord)] 57 | #[repr(C, packed)] 58 | struct Tenth( 59 | #[derivative( 60 | PartialOrd(compare_with = "partial_cmp_tenth"), 61 | Ord(compare_with = "cmp_tenth") 62 | )] 63 | u8, 64 | ); 65 | 66 | fn partial_cmp_tenth(lhs: &u8, rhs: &u8) -> std::option::Option { 67 | if *lhs == 0 { 68 | None 69 | } else { 70 | Some((lhs / 10).cmp(&(rhs / 10))) 71 | } 72 | } 73 | fn cmp_tenth(lhs: &u8, rhs: &u8) -> std::cmp::Ordering { 74 | (lhs / 10).cmp(&(rhs / 10)) 75 | } 76 | 77 | #[derive(Derivative)] 78 | #[derivative(PartialOrd, Ord, PartialEq, Eq)] 79 | #[repr(C, packed)] 80 | struct Generic( 81 | #[derivative( 82 | PartialEq = "ignore", 83 | PartialOrd(compare_with = "dummy_partial_cmp", bound = ""), 84 | Ord(compare_with = "dummy_cmp", bound = "") 85 | )] 86 | T, 87 | ); 88 | 89 | fn dummy_partial_cmp(_: &T, _: &T) -> std::option::Option { 90 | Some(std::cmp::Ordering::Less) 91 | } 92 | fn dummy_cmp(_: &T, _: &T) -> std::cmp::Ordering { 93 | std::cmp::Ordering::Less 94 | } 95 | 96 | struct NonPartialOrd; 97 | 98 | #[derive(Derivative)] 99 | #[derivative(PartialEq, PartialOrd, Ord, Eq)] 100 | #[repr(C, packed)] 101 | struct GenericIgnore { 102 | f: u32, 103 | #[derivative(PartialEq = "ignore")] 104 | #[derivative(PartialOrd = "ignore")] 105 | #[derivative(Ord = "ignore")] 106 | t: T, 107 | } 108 | 109 | trait SomeTrait {} 110 | 111 | #[derive(Clone, Copy)] 112 | struct SomeType { 113 | #[allow(dead_code)] 114 | foo: u8, 115 | } 116 | impl SomeTrait for SomeType {} 117 | 118 | #[test] 119 | fn main() { 120 | use std::cmp::Ordering; 121 | 122 | assert_eq!( 123 | Foo { foo: 7 }.partial_cmp(&Foo { foo: 42 }), 124 | Some(Ordering::Less) 125 | ); 126 | assert_eq!( 127 | Foo { foo: 42 }.partial_cmp(&Foo { foo: 42 }), 128 | Some(Ordering::Equal) 129 | ); 130 | assert_eq!( 131 | Foo { foo: 42 }.partial_cmp(&Foo { foo: 7 }), 132 | Some(Ordering::Greater) 133 | ); 134 | assert_eq!(Foo { foo: 7 }.cmp(&Foo { foo: 42 }), Ordering::Less); 135 | assert_eq!(Foo { foo: 42 }.cmp(&Foo { foo: 42 }), Ordering::Equal); 136 | assert_eq!(Foo { foo: 42 }.cmp(&Foo { foo: 7 }), Ordering::Greater); 137 | 138 | let pointers: [*const dyn SomeTrait; 2] = [&SomeType { foo: 1 }, &SomeType { foo: 0 }]; 139 | let ptr1: *const dyn SomeTrait = pointers[0]; 140 | let ptr2: *const dyn SomeTrait = pointers[1]; 141 | let (ptr1, ptr2) = (std::cmp::min(ptr1, ptr2), std::cmp::max(ptr1, ptr2)); 142 | assert_eq!( 143 | WithPtr { foo: ptr1 }.partial_cmp(&WithPtr { foo: ptr1 }), 144 | Some(Ordering::Equal) 145 | ); 146 | assert_eq!( 147 | WithPtr { foo: ptr1 }.cmp(&WithPtr { foo: ptr1 }), 148 | Ordering::Equal 149 | ); 150 | assert_eq!( 151 | WithPtr { foo: ptr1 }.partial_cmp(&WithPtr { foo: ptr2 }), 152 | Some(Ordering::Less) 153 | ); 154 | assert_eq!( 155 | WithPtr { foo: ptr1 }.cmp(&WithPtr { foo: ptr2 }), 156 | Ordering::Less 157 | ); 158 | 159 | assert_eq!(Empty.partial_cmp(&Empty), Some(Ordering::Equal)); 160 | assert_eq!( 161 | AllIgnored { foo: 0 }.partial_cmp(&AllIgnored { foo: 42 }), 162 | Some(Ordering::Equal) 163 | ); 164 | assert_eq!( 165 | OneIgnored { foo: 0, bar: 6 }.partial_cmp(&OneIgnored { foo: 42, bar: 7 }), 166 | Some(Ordering::Less) 167 | ); 168 | assert_eq!( 169 | OneIgnored { foo: 0, bar: 6 }.partial_cmp(&OneIgnored { foo: 42, bar: 6 }), 170 | Some(Ordering::Equal) 171 | ); 172 | assert_eq!( 173 | OneIgnored { foo: 0, bar: 7 }.partial_cmp(&OneIgnored { foo: 42, bar: 6 }), 174 | Some(Ordering::Greater) 175 | ); 176 | assert_eq!(Empty.cmp(&Empty), Ordering::Equal); 177 | assert_eq!( 178 | AllIgnored { foo: 0 }.cmp(&AllIgnored { foo: 42 }), 179 | Ordering::Equal 180 | ); 181 | assert_eq!( 182 | OneIgnored { foo: 0, bar: 6 }.cmp(&OneIgnored { foo: 42, bar: 7 }), 183 | Ordering::Less 184 | ); 185 | assert_eq!( 186 | OneIgnored { foo: 0, bar: 6 }.cmp(&OneIgnored { foo: 42, bar: 6 }), 187 | Ordering::Equal 188 | ); 189 | assert_eq!( 190 | OneIgnored { foo: 0, bar: 7 }.cmp(&OneIgnored { foo: 42, bar: 6 }), 191 | Ordering::Greater 192 | ); 193 | 194 | assert_eq!( 195 | Option::None::.partial_cmp(&Option::Some(7)), 196 | Some(Ordering::Less) 197 | ); 198 | assert_eq!( 199 | Option::Some(6).partial_cmp(&Option::Some(7)), 200 | Some(Ordering::Less) 201 | ); 202 | assert_eq!( 203 | Option::Some(42).partial_cmp(&Option::Some(42)), 204 | Some(Ordering::Equal) 205 | ); 206 | assert_eq!( 207 | Option::None::.partial_cmp(&Option::None::), 208 | Some(Ordering::Equal) 209 | ); 210 | assert_eq!( 211 | Option::Some(7).partial_cmp(&Option::Some(6)), 212 | Some(Ordering::Greater) 213 | ); 214 | assert_eq!( 215 | Option::Some(7).partial_cmp(&Option::None::), 216 | Some(Ordering::Greater) 217 | ); 218 | assert_eq!(Option::None::.cmp(&Option::Some(7)), Ordering::Less); 219 | assert_eq!(Option::Some(6).cmp(&Option::Some(7)), Ordering::Less); 220 | assert_eq!(Option::Some(42).cmp(&Option::Some(42)), Ordering::Equal); 221 | assert_eq!(Option::None::.cmp(&Option::None::), Ordering::Equal); 222 | assert_eq!(Option::Some(7).cmp(&Option::Some(6)), Ordering::Greater); 223 | assert_eq!(Option::Some(7).cmp(&Option::None::), Ordering::Greater); 224 | 225 | assert_eq!(Tenth(0).partial_cmp(&Tenth(67)), None); 226 | assert_eq!(Tenth(42).partial_cmp(&Tenth(67)), Some(Ordering::Less)); 227 | assert_eq!(Tenth(60).partial_cmp(&Tenth(67)), Some(Ordering::Equal)); 228 | assert_eq!(Tenth(100).partial_cmp(&Tenth(67)), Some(Ordering::Greater)); 229 | assert_eq!(Tenth(42).cmp(&Tenth(67)), Ordering::Less); 230 | assert_eq!(Tenth(60).cmp(&Tenth(67)), Ordering::Equal); 231 | assert_eq!(Tenth(100).cmp(&Tenth(67)), Ordering::Greater); 232 | 233 | assert_eq!( 234 | Generic(SomeType { foo: 0 }).partial_cmp(&Generic(SomeType { foo: 0 })), 235 | Some(Ordering::Less) 236 | ); 237 | assert_eq!( 238 | Generic(SomeType { foo: 0 }).cmp(&Generic(SomeType { foo: 0 })), 239 | Ordering::Less 240 | ); 241 | 242 | assert_eq!( 243 | GenericIgnore { 244 | f: 123, 245 | t: NonPartialOrd 246 | } 247 | .cmp(&GenericIgnore { 248 | f: 123, 249 | t: NonPartialOrd 250 | }), 251 | Ordering::Equal 252 | ); 253 | assert_eq!( 254 | GenericIgnore { 255 | f: 123, 256 | t: NonPartialOrd 257 | } 258 | .partial_cmp(&GenericIgnore { 259 | f: 123, 260 | t: NonPartialOrd 261 | }), 262 | Some(Ordering::Equal) 263 | ); 264 | } 265 | -------------------------------------------------------------------------------- /tests/derive-ord.rs: -------------------------------------------------------------------------------- 1 | #![allow(renamed_and_removed_lints)] // clippy::cyclomatic_complexity → clippy::cognitive_complexity 2 | #![allow(clippy::cyclomatic_complexity)] 3 | #![allow(clippy::cognitive_complexity)] 4 | #![allow(clippy::trivially_copy_pass_by_ref)] 5 | #![allow(clippy::unknown_clippy_lints)] 6 | 7 | #[cfg(feature = "use_core")] 8 | extern crate core; 9 | 10 | use std::marker::PhantomData; 11 | 12 | #[macro_use] 13 | extern crate derivative; 14 | 15 | #[derive(PartialEq, Eq, Derivative)] 16 | #[derivative(PartialOrd, Ord)] 17 | struct Foo { 18 | foo: u8, 19 | } 20 | 21 | #[derive(PartialEq, Eq, Derivative)] 22 | #[derivative( 23 | PartialOrd = "feature_allow_slow_enum", 24 | Ord = "feature_allow_slow_enum" 25 | )] 26 | enum Option { 27 | None, 28 | Some(T), 29 | } 30 | 31 | #[derive(Derivative)] 32 | #[derivative(PartialEq, PartialOrd, Ord, Eq)] 33 | struct WithPtr { 34 | #[derivative(PartialEq(bound = ""))] 35 | #[derivative(PartialOrd(bound = ""))] 36 | #[derivative(Ord(bound = ""))] 37 | #[derivative(Eq(bound = ""))] 38 | foo: *const T, 39 | } 40 | 41 | #[derive(PartialEq, Eq, Derivative)] 42 | #[derivative(PartialOrd, Ord)] 43 | struct Empty; 44 | 45 | #[derive(PartialEq, Eq, Derivative)] 46 | #[derivative(PartialOrd, Ord)] 47 | struct AllIgnored { 48 | #[derivative(PartialOrd = "ignore")] 49 | #[derivative(Ord = "ignore")] 50 | foo: u8, 51 | } 52 | 53 | #[derive(PartialEq, Eq, Derivative)] 54 | #[derivative(PartialOrd, Ord)] 55 | struct OneIgnored { 56 | #[derivative(PartialOrd = "ignore")] 57 | #[derivative(Ord = "ignore")] 58 | foo: u8, 59 | bar: u8, 60 | } 61 | 62 | #[derive(PartialEq, Eq, Derivative)] 63 | #[derivative(PartialOrd, Ord)] 64 | struct Tenth( 65 | #[derivative( 66 | PartialOrd(compare_with = "partial_cmp_tenth"), 67 | Ord(compare_with = "cmp_tenth") 68 | )] 69 | u8, 70 | ); 71 | 72 | fn partial_cmp_tenth(lhs: &u8, rhs: &u8) -> std::option::Option { 73 | if *lhs == 0 { 74 | None 75 | } else { 76 | Some((lhs / 10).cmp(&(rhs / 10))) 77 | } 78 | } 79 | fn cmp_tenth(lhs: &u8, rhs: &u8) -> std::cmp::Ordering { 80 | (lhs / 10).cmp(&(rhs / 10)) 81 | } 82 | 83 | #[derive(Derivative)] 84 | #[derivative(PartialOrd, Ord, PartialEq, Eq)] 85 | struct Generic( 86 | #[derivative( 87 | PartialEq = "ignore", 88 | PartialOrd(compare_with = "dummy_partial_cmp", bound = ""), 89 | Ord(compare_with = "dummy_cmp", bound = "") 90 | )] 91 | T, 92 | ); 93 | 94 | fn dummy_partial_cmp(_: &T, _: &T) -> std::option::Option { 95 | Some(std::cmp::Ordering::Less) 96 | } 97 | fn dummy_cmp(_: &T, _: &T) -> std::cmp::Ordering { 98 | std::cmp::Ordering::Less 99 | } 100 | 101 | struct NonPartialOrd; 102 | 103 | #[derive(Derivative)] 104 | #[derivative(PartialEq, PartialOrd, Ord, Eq)] 105 | struct GenericIgnore { 106 | f: u32, 107 | #[derivative(PartialEq = "ignore")] 108 | #[derivative(PartialOrd = "ignore")] 109 | #[derivative(Ord = "ignore")] 110 | t: PhantomData, 111 | } 112 | 113 | trait SomeTrait {} 114 | struct SomeType { 115 | #[allow(dead_code)] 116 | foo: u8, 117 | } 118 | impl SomeTrait for SomeType {} 119 | 120 | #[test] 121 | fn main() { 122 | use std::cmp::Ordering; 123 | 124 | assert_eq!( 125 | Foo { foo: 7 }.partial_cmp(&Foo { foo: 42 }), 126 | Some(Ordering::Less) 127 | ); 128 | assert_eq!( 129 | Foo { foo: 42 }.partial_cmp(&Foo { foo: 42 }), 130 | Some(Ordering::Equal) 131 | ); 132 | assert_eq!( 133 | Foo { foo: 42 }.partial_cmp(&Foo { foo: 7 }), 134 | Some(Ordering::Greater) 135 | ); 136 | assert_eq!(Foo { foo: 7 }.cmp(&Foo { foo: 42 }), Ordering::Less); 137 | assert_eq!(Foo { foo: 42 }.cmp(&Foo { foo: 42 }), Ordering::Equal); 138 | assert_eq!(Foo { foo: 42 }.cmp(&Foo { foo: 7 }), Ordering::Greater); 139 | 140 | let pointers: [*const dyn SomeTrait; 2] = [&SomeType { foo: 1 }, &SomeType { foo: 0 }]; 141 | let ptr1: *const dyn SomeTrait = pointers[0]; 142 | let ptr2: *const dyn SomeTrait = pointers[1]; 143 | let (ptr1, ptr2) = (std::cmp::min(ptr1, ptr2), std::cmp::max(ptr1, ptr2)); 144 | assert_eq!( 145 | WithPtr { foo: ptr1 }.partial_cmp(&WithPtr { foo: ptr1 }), 146 | Some(Ordering::Equal) 147 | ); 148 | assert_eq!( 149 | WithPtr { foo: ptr1 }.cmp(&WithPtr { foo: ptr1 }), 150 | Ordering::Equal 151 | ); 152 | assert_eq!( 153 | WithPtr { foo: ptr1 }.partial_cmp(&WithPtr { foo: ptr2 }), 154 | Some(Ordering::Less) 155 | ); 156 | assert_eq!( 157 | WithPtr { foo: ptr1 }.cmp(&WithPtr { foo: ptr2 }), 158 | Ordering::Less 159 | ); 160 | 161 | assert_eq!(Empty.partial_cmp(&Empty), Some(Ordering::Equal)); 162 | assert_eq!( 163 | AllIgnored { foo: 0 }.partial_cmp(&AllIgnored { foo: 42 }), 164 | Some(Ordering::Equal) 165 | ); 166 | assert_eq!( 167 | OneIgnored { foo: 0, bar: 6 }.partial_cmp(&OneIgnored { foo: 42, bar: 7 }), 168 | Some(Ordering::Less) 169 | ); 170 | assert_eq!( 171 | OneIgnored { foo: 0, bar: 6 }.partial_cmp(&OneIgnored { foo: 42, bar: 6 }), 172 | Some(Ordering::Equal) 173 | ); 174 | assert_eq!( 175 | OneIgnored { foo: 0, bar: 7 }.partial_cmp(&OneIgnored { foo: 42, bar: 6 }), 176 | Some(Ordering::Greater) 177 | ); 178 | assert_eq!(Empty.cmp(&Empty), Ordering::Equal); 179 | assert_eq!( 180 | AllIgnored { foo: 0 }.cmp(&AllIgnored { foo: 42 }), 181 | Ordering::Equal 182 | ); 183 | assert_eq!( 184 | OneIgnored { foo: 0, bar: 6 }.cmp(&OneIgnored { foo: 42, bar: 7 }), 185 | Ordering::Less 186 | ); 187 | assert_eq!( 188 | OneIgnored { foo: 0, bar: 6 }.cmp(&OneIgnored { foo: 42, bar: 6 }), 189 | Ordering::Equal 190 | ); 191 | assert_eq!( 192 | OneIgnored { foo: 0, bar: 7 }.cmp(&OneIgnored { foo: 42, bar: 6 }), 193 | Ordering::Greater 194 | ); 195 | 196 | assert_eq!( 197 | Option::None::.partial_cmp(&Option::Some(7)), 198 | Some(Ordering::Less) 199 | ); 200 | assert_eq!( 201 | Option::Some(6).partial_cmp(&Option::Some(7)), 202 | Some(Ordering::Less) 203 | ); 204 | assert_eq!( 205 | Option::Some(42).partial_cmp(&Option::Some(42)), 206 | Some(Ordering::Equal) 207 | ); 208 | assert_eq!( 209 | Option::None::.partial_cmp(&Option::None::), 210 | Some(Ordering::Equal) 211 | ); 212 | assert_eq!( 213 | Option::Some(7).partial_cmp(&Option::Some(6)), 214 | Some(Ordering::Greater) 215 | ); 216 | assert_eq!( 217 | Option::Some(7).partial_cmp(&Option::None::), 218 | Some(Ordering::Greater) 219 | ); 220 | assert_eq!(Option::None::.cmp(&Option::Some(7)), Ordering::Less); 221 | assert_eq!(Option::Some(6).cmp(&Option::Some(7)), Ordering::Less); 222 | assert_eq!(Option::Some(42).cmp(&Option::Some(42)), Ordering::Equal); 223 | assert_eq!(Option::None::.cmp(&Option::None::), Ordering::Equal); 224 | assert_eq!(Option::Some(7).cmp(&Option::Some(6)), Ordering::Greater); 225 | assert_eq!(Option::Some(7).cmp(&Option::None::), Ordering::Greater); 226 | 227 | assert_eq!(Tenth(0).partial_cmp(&Tenth(67)), None); 228 | assert_eq!(Tenth(42).partial_cmp(&Tenth(67)), Some(Ordering::Less)); 229 | assert_eq!(Tenth(60).partial_cmp(&Tenth(67)), Some(Ordering::Equal)); 230 | assert_eq!(Tenth(100).partial_cmp(&Tenth(67)), Some(Ordering::Greater)); 231 | assert_eq!(Tenth(42).cmp(&Tenth(67)), Ordering::Less); 232 | assert_eq!(Tenth(60).cmp(&Tenth(67)), Ordering::Equal); 233 | assert_eq!(Tenth(100).cmp(&Tenth(67)), Ordering::Greater); 234 | 235 | assert_eq!( 236 | Generic(SomeType { foo: 0 }).partial_cmp(&Generic(SomeType { foo: 0 })), 237 | Some(Ordering::Less) 238 | ); 239 | assert_eq!( 240 | Generic(SomeType { foo: 0 }).cmp(&Generic(SomeType { foo: 0 })), 241 | Ordering::Less 242 | ); 243 | 244 | assert_eq!( 245 | GenericIgnore { 246 | f: 123, 247 | t: PhantomData::::default() 248 | } 249 | .cmp(&GenericIgnore { 250 | f: 123, 251 | t: PhantomData::::default() 252 | }), 253 | Ordering::Equal 254 | ); 255 | assert_eq!( 256 | GenericIgnore { 257 | f: 123, 258 | t: PhantomData::::default() 259 | } 260 | .partial_cmp(&GenericIgnore { 261 | f: 123, 262 | t: PhantomData::::default() 263 | }), 264 | Some(Ordering::Equal) 265 | ); 266 | } 267 | -------------------------------------------------------------------------------- /tests/rustc-issue-58319.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT 2 | // file at the top-level directory of this distribution and at 3 | // http://rust-lang.org/COPYRIGHT. 4 | // 5 | // Licensed under the Apache License, Version 2.0 or the MIT license 7 | // , at your 8 | // option. This file may not be copied, modified, or distributed 9 | // except according to those terms. 10 | 11 | #![deny(warnings)] 12 | 13 | #![allow(dead_code)] 14 | #![allow(non_camel_case_types)] 15 | 16 | #[cfg(feature = "use_core")] 17 | extern crate core; 18 | 19 | #[macro_use] 20 | extern crate derivative; 21 | 22 | #[derive(Derivative)] 23 | #[derivative(Clone)] 24 | pub struct Little; 25 | 26 | #[derive(Clone)] 27 | pub struct Big( 28 | Little, 29 | Little, 30 | Little, 31 | Little, 32 | Little, 33 | Little, 34 | Little, 35 | Little, 36 | Little, 37 | Little, 38 | Little, 39 | Little, 40 | Little, 41 | Little, 42 | Little, 43 | Little, 44 | Little, 45 | Little, 46 | Little, 47 | Little, 48 | Little, 49 | Little, 50 | Little, 51 | Little, 52 | Little, 53 | Little, 54 | Little, 55 | Little, 56 | Little, 57 | Little, 58 | Little, 59 | Little, 60 | Little, 61 | Little, 62 | Little, 63 | Little, 64 | Little, 65 | Little, 66 | Little, 67 | Little, 68 | Little, 69 | Little, 70 | Little, 71 | Little, 72 | Little, 73 | Little, 74 | Little, 75 | Little, 76 | Little, 77 | Little, 78 | Little, 79 | Little, 80 | Little, 81 | Little, 82 | Little, 83 | Little, 84 | Little, 85 | Little, 86 | Little, 87 | Little, 88 | Little, 89 | Little, 90 | Little, 91 | Little, 92 | Little, 93 | Little, 94 | Little, 95 | Little, 96 | Little, 97 | Little, 98 | Little, 99 | Little, 100 | Little, 101 | Little, 102 | Little, 103 | Little, 104 | Little, 105 | Little, 106 | Little, 107 | Little, 108 | Little, 109 | Little, 110 | Little, 111 | Little, 112 | Little, 113 | Little, 114 | Little, 115 | Little, 116 | Little, 117 | Little, 118 | Little, 119 | Little, 120 | Little, 121 | Little, 122 | Little, 123 | Little, 124 | Little, 125 | Little, 126 | Little, 127 | Little, 128 | Little, 129 | Little, 130 | Little, 131 | Little, 132 | Little, 133 | Little, 134 | Little, 135 | Little, 136 | Little, 137 | Little, 138 | Little, 139 | Little, 140 | Little, 141 | Little, 142 | Little, 143 | Little, 144 | Little, 145 | Little, 146 | Little, 147 | Little, 148 | Little, 149 | Little, 150 | Little, 151 | Little, 152 | Little, 153 | Little, 154 | Little, 155 | Little, 156 | Little, 157 | Little, 158 | Little, 159 | Little, 160 | Little, 161 | Little, 162 | Little, 163 | Little, 164 | Little, 165 | Little, 166 | Little, 167 | Little, 168 | Little, 169 | Little, 170 | Little, 171 | Little, 172 | Little, 173 | Little, 174 | Little, 175 | Little, 176 | Little, 177 | Little, 178 | Little, 179 | Little, 180 | Little, 181 | Little, 182 | Little, 183 | Little, 184 | Little, 185 | Little, 186 | Little, 187 | Little, 188 | Little, 189 | Little, 190 | Little, 191 | Little, 192 | Little, 193 | Little, 194 | Little, 195 | Little, 196 | Little, 197 | Little, 198 | Little, 199 | Little, 200 | Little, 201 | Little, 202 | Little, 203 | Little, 204 | Little, 205 | Little, 206 | Little, 207 | Little, 208 | Little, 209 | Little, 210 | Little, 211 | Little, 212 | Little, 213 | Little, 214 | Little, 215 | Little, 216 | Little, 217 | Little, 218 | Little, 219 | Little, 220 | Little, 221 | Little, 222 | Little, 223 | Little, 224 | Little, 225 | Little, 226 | Little, 227 | Little, 228 | Little, 229 | Little, 230 | Little, 231 | Little, 232 | Little, 233 | Little, 234 | Little, 235 | Little, 236 | Little, 237 | Little, 238 | Little, 239 | Little, 240 | Little, 241 | Little, 242 | Little, 243 | Little, 244 | Little, 245 | Little, 246 | Little, 247 | Little, 248 | Little, 249 | Little, 250 | Little, 251 | Little, 252 | Little, 253 | Little, 254 | Little, 255 | Little, 256 | Little, 257 | Little, 258 | Little, 259 | Little, 260 | Little, 261 | Little, 262 | Little, 263 | Little, 264 | Little, 265 | Little, 266 | Little, 267 | Little, 268 | Little, 269 | Little, 270 | Little, 271 | Little, 272 | Little, 273 | Little, 274 | Little, 275 | Little, 276 | Little, 277 | Little, 278 | Little, 279 | Little, 280 | Little, 281 | Little, 282 | Little, 283 | Little, 284 | Little, 285 | Little, 286 | Little, 287 | Little, 288 | Little, 289 | Little, 290 | Little, 291 | Little, 292 | Little, 293 | Little, 294 | Little, 295 | Little, 296 | Little, 297 | Little, 298 | Little, 299 | Little, 300 | Little, 301 | Little, 302 | Little, 303 | Little, 304 | Little, 305 | Little, 306 | Little, 307 | Little, 308 | Little, 309 | Little, 310 | Little, 311 | Little, 312 | Little, 313 | Little, 314 | Little, 315 | Little, 316 | Little, 317 | Little, 318 | Little, 319 | Little, 320 | Little, 321 | Little, 322 | Little, 323 | Little, 324 | Little, 325 | Little, 326 | Little, 327 | Little, 328 | Little, 329 | Little, 330 | Little, 331 | Little, 332 | Little, 333 | Little, 334 | Little, 335 | Little, 336 | Little, 337 | Little, 338 | Little, 339 | Little, 340 | Little, 341 | Little, 342 | Little, 343 | Little, 344 | Little, 345 | Little, 346 | Little, 347 | Little, 348 | Little, 349 | Little, 350 | Little, 351 | Little, 352 | Little, 353 | Little, 354 | Little, 355 | Little, 356 | Little, 357 | Little, 358 | Little, 359 | Little, 360 | Little, 361 | Little, 362 | Little, 363 | Little, 364 | Little, 365 | Little, 366 | Little, 367 | Little, 368 | Little, 369 | Little, 370 | Little, 371 | Little, 372 | Little, 373 | Little, 374 | Little, 375 | Little, 376 | Little, 377 | Little, 378 | Little, 379 | Little, 380 | Little, 381 | Little, 382 | Little, 383 | Little, 384 | Little, 385 | Little, 386 | Little, 387 | Little, 388 | Little, 389 | Little, 390 | Little, 391 | Little, 392 | Little, 393 | Little, 394 | Little, 395 | Little, 396 | Little, 397 | Little, 398 | Little, 399 | Little, 400 | Little, 401 | Little, 402 | Little, 403 | Little, 404 | Little, 405 | Little, 406 | Little, 407 | Little, 408 | Little, 409 | Little, 410 | Little, 411 | Little, 412 | Little, 413 | Little, 414 | Little, 415 | Little, 416 | Little, 417 | Little, 418 | Little, 419 | Little, 420 | Little, 421 | Little, 422 | Little, 423 | Little, 424 | Little, 425 | Little, 426 | Little, 427 | Little, 428 | Little, 429 | Little, 430 | Little, 431 | Little, 432 | Little, 433 | Little, 434 | Little, 435 | Little, 436 | Little, 437 | Little, 438 | Little, 439 | Little, 440 | Little, 441 | Little, 442 | Little, 443 | Little, 444 | Little, 445 | Little, 446 | Little, 447 | Little, 448 | Little, 449 | Little, 450 | Little, 451 | Little, 452 | Little, 453 | Little, 454 | Little, 455 | Little, 456 | Little, 457 | Little, 458 | Little, 459 | Little, 460 | Little, 461 | Little, 462 | Little, 463 | Little, 464 | Little, 465 | Little, 466 | Little, 467 | Little, 468 | Little, 469 | Little, 470 | Little, 471 | Little, 472 | Little, 473 | Little, 474 | Little, 475 | Little, 476 | Little, 477 | Little, 478 | Little, 479 | Little, 480 | Little, 481 | Little, 482 | Little, 483 | Little, 484 | Little, 485 | Little, 486 | Little, 487 | Little, 488 | Little, 489 | Little, 490 | Little, 491 | Little, 492 | Little, 493 | Little, 494 | Little, 495 | Little, 496 | Little, 497 | Little, 498 | Little, 499 | Little, 500 | Little, 501 | Little, 502 | Little, 503 | Little, 504 | Little, 505 | Little, 506 | Little, 507 | Little, 508 | Little, 509 | Little, 510 | Little, 511 | Little, 512 | Little, 513 | Little, 514 | Little, 515 | Little, 516 | Little, 517 | Little, 518 | Little, 519 | Little, 520 | Little, 521 | Little, 522 | Little, 523 | Little, 524 | Little, 525 | Little, 526 | Little, 527 | Little, 528 | Little, 529 | Little, 530 | Little, 531 | Little, 532 | Little, 533 | Little, 534 | Little, 535 | Little, 536 | Little, 537 | Little, 538 | Little, 539 | Little, 540 | Little, 541 | Little, 542 | Little, 543 | Little, 544 | Little, 545 | Little, 546 | Little, 547 | Little, 548 | Little, 549 | Little, 550 | Little, 551 | Little, 552 | Little, 553 | Little, 554 | Little, 555 | Little, 556 | Little, 557 | Little, 558 | Little, 559 | Little, 560 | Little, 561 | Little, 562 | Little, 563 | Little, 564 | Little, 565 | Little, 566 | Little, 567 | Little, 568 | Little, 569 | Little, 570 | Little, 571 | Little, 572 | Little, 573 | Little, 574 | Little, 575 | Little, 576 | Little, 577 | Little, 578 | Little, 579 | Little, 580 | Little, 581 | Little, 582 | Little, 583 | Little, 584 | Little, 585 | Little, 586 | Little, 587 | Little, 588 | Little, 589 | Little, 590 | Little, 591 | Little, 592 | Little, 593 | Little, 594 | Little, 595 | Little, 596 | Little, 597 | Little, 598 | Little, 599 | Little, 600 | Little, 601 | Little, 602 | Little, 603 | Little, 604 | Little, 605 | Little, 606 | Little, 607 | Little, 608 | Little, 609 | Little, 610 | Little, 611 | Little, 612 | Little, 613 | Little, 614 | Little, 615 | Little, 616 | Little, 617 | Little, 618 | Little, 619 | Little, 620 | Little, 621 | Little, 622 | Little, 623 | Little, 624 | Little, 625 | Little, 626 | Little, 627 | Little, 628 | Little, 629 | Little, 630 | Little, 631 | Little, 632 | Little, 633 | Little, 634 | Little, 635 | Little, 636 | Little, 637 | Little, 638 | Little, 639 | Little, 640 | Little, 641 | Little, 642 | ); 643 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------