derive_more-0.99.18/.cargo_vcs_info.json0000644000000001360000000000100135240ustar { "git": { "sha1": "678a4735bc540b7363c6dadddc4bb273fdf74468" }, "path_in_vcs": "" }derive_more-0.99.18/CHANGELOG.md000064400000000000000000000144711046102023000141340ustar 00000000000000# Change Log All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## 0.99.18 - 2024-06-15 - Update syn to version 2.x - Bump minimum supported rust version to 1.65 ## 0.99.10 - 2020-09-11 ### Improvements - `From` supports additional types for conversion: `#[from(types(u8, u16))]`. ## 0.99.7 - 2020-05-16 ### Fixes - Fix generic derives for `MulAssign` ### Improvements - When specifying specific features of the crate to only enable specific derives, the `extra-traits` feature of `syn` is not always enabled when those the specified features do not require it. This should speed up compile time of `syn` when this feature is not needed. ## 0.99.6 - 2020-05-13 ### Improvements - Make sure output of derives is deterministic, for better support in rust-analyzer ## 0.99.5 - 2020-03-28 ### New features - Support for deriving `Error`!!! (many thanks to @ffuugoo and @tyranron) ### Fixes - Fix generic bounds for `Deref` and `DerefMut` with `forward`, i.e. put `Deref` bound on whole type, so on `where Box: Deref` instead of on `T: Deref`. ([#107](https://github.com/JelteF/derive_more/issues/114)) - The `tests` directory is now correctly included in the crate (requested by Debian package maintainers) ## 0.99.4 - 2020-03-28 Note: This version is yanked, because quickly after release it was found out tests did not run in CI. ## 0.99.3 - 2020-02-19 ### Fixes - Fix generic bounds for `Deref` and `DerefMut` with no `forward`, i.e. no bounds are necessary. ([#107](https://github.com/JelteF/derive_more/issues/114)) ## 0.99.2 - 2019-11-17 ### Fixes - Hotfix for a regression in allowed `Display` derives using `#` flag, such as `{:#b}` ([#107](https://github.com/JelteF/derive_more/issues/107)) ## 0.99.1 - 2019-11-12 ### Fixes - Hotfix for a regression in allowed `From` derives ([#105](https://github.com/JelteF/derive_more/issues/105)) ## 0.99.0 - 2019-11-11 This release is a huge milestone for this library. Lot's of new derives are implemented and a ton of attributes are added for configuration purposes. These attributes will allow future releases to add features/options without breaking backwards compatibility. This is why the next release with breaking changes is planned to be 1.0.0. ### Breaking changes - Requires Rust 1.36+ - When using in a Rust 2015 crate, you should add `extern crate core` to your code. - `no_std` feature is removed, the library now supports `no_std` without having to configure any features. - `Deref` derives now dereference to the type in the newtype. So if you have `MyBox(Box)`, dereferencing it will result in a `Box` not an `i32`. To get the old behaviour of forwarding the dereference you can add the `#[deref(forward)]` attribute on the struct or field. ### New features - Derives for `AsRef`, `AsMut`, `Sum`, `Product`, `IntoIterator`. - Choosing the field of a struct for which to derive the newtype derive. - Ignoring variants of enums when deriving `From`, by using `#[from(ignore)]`. - Add `#[from(forward)]` attribute for `From` derives. This forwards the `from` calls to the fields themselves. So if your field is an `i64` you can call from on an `i32` and it will work. - Add `#[mul(forward)]` and `#[mul_assign(forward)]`, which implement `Mul` and `MulAssign` with the semantics as if they were `Add`/`AddAssign`. - You can use features to cut down compile time of the crate by only compiling the code needed for the derives that you use. (see Cargo.toml for the features, by default they are all on) - Add `#[into(owned, ref, ref_mut)]` and `#[try_into(owned, ref, ref_mut)]` attributes. These cause the `Into` and `TryInto` derives to also implement derives that return references to the inner fields. - Make `no_std` work out of the box - Allow `#[display(fmt="some shared display text for all enum variants {}")]` attribute on enum. - Better bounds inference of `Display` trait. ### Other things - Remove dependency on `regex` to cut down compile time. - Use `syn` 1.0 ## 0.15.0 - 2019-06-08 - Automatic detection of traits needed for `Display` format strings ## 0.14.0 - 2019-02-02 - Added `no_std` support - Suppress `unused_variables` warnings in derives ## 0.13.0 - 2018-10-19 - Updated to `syn` v0.15 - Extended Display-like derives to support custom formats ## 0.12.0 - 2018-09-19 ### Changed - Updated to `syn` v0.14, `quote` v0.6 and `proc-macro2` v0.4 ## 0.11.0 - 2018-05-12 ### Changed - Updated to latest version of `syn` and `quote` ### Fixed - Changed some URLs in the docs so they were correct on crates.io and docs.rs - The `Result` type is now referenced in the derives using its absolute path (`::std::result::Result`) to make sure that the derives don't accidentally use another `Result` type that is in scope. ## 0.10.0 - 2018-03-29 ### Added - Allow deriving of `TryInto` - Allow deriving of `Deref` - Allow deriving of `DerefMut` ## 0.9.0 - 2018-03-18 ### Added - Allow deriving of `Display`, `Binary`, `Octal`, `LowerHex`, `UpperHex`, `LowerExp`, `UpperExp`, `Pointer` - Allow deriving of `Index` - Allow deriving of `IndexMut` ### Fixed - Allow cross crate inlining of derived methods ### Internal changes - Fix most `clippy` warnings ## 0.8.0 - 2018-03-10 ### Added - Allow deriving of `FromStr` ### Changed - Updated to latest version of `syn` and `quote` ## 0.7.1 - 2018-01-25 ### Fixed - Add `#[allow(missing_docs)]` to the Constructor definition ### Internal changes - Run `rustfmt` on the code ## 0.7.0 - 2017-07-25 ### Changed - Changed code to work with newer version of the `syn` library. ## 0.6.2 - 2017-04-23 ### Changed - Deriving `From`, `Into` and `Constructor` now works for empty structs. ## 0.6.1 - 2017-03-08 ### Changed - The `new()` method that is created when deriving `Constructor` is now public. This makes it a lot more useful. ## 0.6.0 - 2017-02-20 ### Added - Derives for `Into`, `Constructor` and `MulAssign`-like ### Changed - `From` is now derived for enum variants with multiple fields. ### Fixed - Derivations now support generics. ## 0.5.0 - 2017-02-02 ### Added - Lots of docs. - Derives for `Neg`-like and `AddAssign`-like. ### Changed - `From` can now be derived for structs with multiple fields. derive_more-0.99.18/Cargo.lock0000644000000042300000000000100114760ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "convert_case" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "derive_more" version = "0.99.18" dependencies = [ "convert_case", "peg", "proc-macro2", "quote 1.0.36", "rustc_version", "syn", ] [[package]] name = "peg" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40df12dde1d836ed2a4c3bfc2799797e3abaf807d97520d28d6e3f3bf41a5f85" dependencies = [ "quote 0.3.15", ] [[package]] name = "proc-macro2" version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] [[package]] name = "semver" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "syn" version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote 1.0.36", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" derive_more-0.99.18/Cargo.toml0000644000000135510000000000100115270ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "derive_more" version = "0.99.18" authors = ["Jelte Fennema "] build = false include = [ "src/**/*.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", "tests/**/*.rs", "examples/**/*.rs", ] autobins = false autoexamples = false autotests = false autobenches = false description = "Adds #[derive(x)] macros for more traits" documentation = "https://jeltef.github.io/derive_more/derive_more/" readme = "README.md" keywords = [ "derive", "Add", "From", "Display", "IntoIterator", ] categories = [ "development-tools", "development-tools::procedural-macro-helpers", "no-std", ] license = "MIT" repository = "https://github.com/JelteF/derive_more" [lib] name = "derive_more" path = "src/lib.rs" proc-macro = true [[example]] name = "deny_missing_docs" path = "examples/deny_missing_docs.rs" required-features = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "mul_assign", "mul", "not", "try_into", "is_variant", ] [[test]] name = "add" path = "tests/add.rs" required-features = ["add"] [[test]] name = "add_assign" path = "tests/add_assign.rs" required-features = ["add_assign"] [[test]] name = "as_mut" path = "tests/as_mut.rs" required-features = ["as_mut"] [[test]] name = "as_ref" path = "tests/as_ref.rs" required-features = ["as_ref"] [[test]] name = "boats_display_derive" path = "tests/boats_display_derive.rs" required-features = ["display"] [[test]] name = "constructor" path = "tests/constructor.rs" required-features = ["constructor"] [[test]] name = "deref" path = "tests/deref.rs" required-features = ["deref"] [[test]] name = "deref_mut" path = "tests/deref_mut.rs" required-features = ["deref_mut"] [[test]] name = "display" path = "tests/display.rs" required-features = ["display"] [[test]] name = "error" path = "tests/error_tests.rs" required-features = ["error"] [[test]] name = "from" path = "tests/from.rs" required-features = ["from"] [[test]] name = "from_str" path = "tests/from_str.rs" required-features = ["from_str"] [[test]] name = "generics" path = "tests/generics.rs" required-features = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "mul_assign", "mul", "not", "try_into", "is_variant", ] [[test]] name = "index" path = "tests/index.rs" required-features = ["index"] [[test]] name = "index_mut" path = "tests/index_mut.rs" required-features = ["index_mut"] [[test]] name = "into" path = "tests/into.rs" required-features = ["into"] [[test]] name = "into_iterator" path = "tests/into_iterator.rs" required-features = ["into_iterator"] [[test]] name = "is_variant" path = "tests/is_variant.rs" required-features = ["is_variant"] [[test]] name = "lib" path = "tests/lib.rs" required-features = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "mul_assign", "mul", "not", "try_into", "is_variant", ] [[test]] name = "mul" path = "tests/mul.rs" required-features = ["mul"] [[test]] name = "mul_assign" path = "tests/mul_assign.rs" required-features = ["mul_assign"] [[test]] name = "no_std" path = "tests/no_std.rs" required-features = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "mul_assign", "mul", "not", "sum", "try_into", "is_variant", ] [[test]] name = "not" path = "tests/not.rs" required-features = ["not"] [[test]] name = "sum" path = "tests/sum.rs" required-features = ["sum"] [[test]] name = "try_into" path = "tests/try_into.rs" required-features = ["try_into"] [[test]] name = "unwrap" path = "tests/unwrap.rs" required-features = ["unwrap"] [dependencies.convert_case] version = "0.4" optional = true [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.syn] version = "2" [build-dependencies.peg] version = "0.5" optional = true [build-dependencies.rustc_version] version = "0.4" optional = true [features] add = [] add_assign = [] as_mut = [] as_ref = [] constructor = [] default = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "error", "from", "from_str", "index", "index_mut", "into", "into_iterator", "iterator", "mul_assign", "mul", "not", "sum", "try_into", "is_variant", "unwrap", ] deref = [] deref_mut = [] display = ["syn/extra-traits"] error = ["syn/extra-traits"] from = ["syn/extra-traits"] from_str = [] generate-parsing-rs = ["peg"] index = [] index_mut = [] into = ["syn/extra-traits"] into_iterator = [] is_variant = ["convert_case"] iterator = [] mul = ["syn/extra-traits"] mul_assign = ["syn/extra-traits"] nightly = [] not = ["syn/extra-traits"] sum = [] testing-helpers = ["rustc_version"] track-caller = [] try_into = ["syn/extra-traits"] unwrap = [ "convert_case", "rustc_version", ] [badges.github] repository = "JelteF/derive_more" workflow = "CI" derive_more-0.99.18/Cargo.toml.orig000064400000000000000000000124201046102023000152020ustar 00000000000000[package] name = "derive_more" version = "0.99.18" description = "Adds #[derive(x)] macros for more traits" authors = ["Jelte Fennema "] license = "MIT" repository = "https://github.com/JelteF/derive_more" documentation = "https://jeltef.github.io/derive_more/derive_more/" edition = "2018" readme = "README.md" keywords = ["derive", "Add", "From", "Display", "IntoIterator"] categories = ["development-tools", "development-tools::procedural-macro-helpers", "no-std"] include = [ "src/**/*.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", "tests/**/*.rs", # debian packaging wants this "examples/**/*.rs", ] autotests = true [lib] name = "derive_more" proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" syn = "2" convert_case = { version = "0.4", optional = true} [build-dependencies] peg = { version = "0.5", optional = true } rustc_version = { version = "0.4", optional = true } [badges] github = { repository = "JelteF/derive_more", workflow = "CI" } [features] nightly = [] add_assign = [] add = [] as_mut = [] as_ref = [] constructor = [] deref = [] deref_mut = [] display = ["syn/extra-traits"] error = ["syn/extra-traits"] from = ["syn/extra-traits"] from_str = [] index = [] index_mut = [] into = ["syn/extra-traits"] into_iterator = [] iterator = [] mul_assign = ["syn/extra-traits"] mul = ["syn/extra-traits"] not = ["syn/extra-traits"] sum = [] try_into = ["syn/extra-traits"] generate-parsing-rs = ["peg"] testing-helpers = ["rustc_version"] is_variant = ["convert_case"] unwrap = ["convert_case", "rustc_version"] # Unused, kept for backwards compatibility track-caller = [] default = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "error", "from", "from_str", "index", "index_mut", "into", "into_iterator", "iterator", "mul_assign", "mul", "not", "sum", "try_into", "is_variant", "unwrap" ] [[test]] name = "add_assign" path = "tests/add_assign.rs" required-features = ["add_assign"] [[test]] name = "add" path = "tests/add.rs" required-features = ["add"] [[test]] name = "as_mut" path = "tests/as_mut.rs" required-features = ["as_mut"] [[test]] name = "as_ref" path = "tests/as_ref.rs" required-features = ["as_ref"] [[test]] name = "boats_display_derive" path = "tests/boats_display_derive.rs" required-features = ["display"] [[test]] name = "constructor" path = "tests/constructor.rs" required-features = ["constructor"] [[test]] name = "deref" path = "tests/deref.rs" required-features = ["deref"] [[test]] name = "deref_mut" path = "tests/deref_mut.rs" required-features = ["deref_mut"] [[test]] name = "display" path = "tests/display.rs" required-features = ["display"] [[test]] name = "error" path = "tests/error_tests.rs" required-features = ["error"] [[test]] name = "from" path = "tests/from.rs" required-features = ["from"] [[test]] name = "from_str" path = "tests/from_str.rs" required-features = ["from_str"] [[test]] name = "index_mut" path = "tests/index_mut.rs" required-features = ["index_mut"] [[test]] name = "index" path = "tests/index.rs" required-features = ["index"] [[test]] name = "into" path = "tests/into.rs" required-features = ["into"] [[test]] name = "into_iterator" path = "tests/into_iterator.rs" required-features = ["into_iterator"] [[test]] name = "mul_assign" path = "tests/mul_assign.rs" required-features = ["mul_assign"] [[test]] name = "mul" path = "tests/mul.rs" required-features = ["mul"] [[test]] name = "not" path = "tests/not.rs" required-features = ["not"] [[test]] name = "sum" path = "tests/sum.rs" required-features = ["sum"] [[test]] name = "try_into" path = "tests/try_into.rs" required-features = ["try_into"] [[test]] name = "is_variant" path = "tests/is_variant.rs" required-features = ["is_variant"] [[test]] name = "unwrap" path = "tests/unwrap.rs" required-features = ["unwrap"] [[test]] name = "no_std" path = "tests/no_std.rs" required-features = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "mul_assign", "mul", "not", "sum", "try_into", "is_variant", ] [[test]] name = "generics" path = "tests/generics.rs" required-features = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "mul_assign", "mul", "not", "try_into", "is_variant", ] [[test]] name = "lib" path = "tests/lib.rs" required-features = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "mul_assign", "mul", "not", "try_into", "is_variant", ] [[example]] name = "deny_missing_docs" path = "examples/deny_missing_docs.rs" required-features = [ "add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "mul_assign", "mul", "not", "try_into", "is_variant", ] derive_more-0.99.18/LICENSE000064400000000000000000000020701046102023000133200ustar 00000000000000The MIT License (MIT) Copyright (c) 2016 Jelte Fennema Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. derive_more-0.99.18/README.md000064400000000000000000000154601046102023000136010ustar 00000000000000# `derive_more` [![Build Status](https://github.com/JelteF/derive_more/workflows/CI/badge.svg)](https://github.com/JelteF/derive_more/actions) [![Latest Version](https://img.shields.io/crates/v/derive_more.svg)](https://crates.io/crates/derive_more) [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://jeltef.github.io/derive_more/derive_more/) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/JelteF/derive_more/master/LICENSE) [![Rust 1.65+](https://img.shields.io/badge/rustc-1.65+-lightgray.svg)](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html) Rust has lots of builtin traits that are implemented for its basic types, such as `Add`, `Not`, `From` or `Display`. However, when wrapping these types inside your own structs or enums you lose the implementations of these traits and are required to recreate them. This is especially annoying when your own structures are very simple, such as when using the commonly advised newtype pattern (e.g. `MyInt(i32)`). This library tries to remove these annoyances and the corresponding boilerplate code. It does this by allowing you to derive lots of commonly used traits for both structs and enums. ## Example code By using this library the following code just works: ```rust extern crate derive_more; use derive_more::{Add, Display, From, Into}; #[derive(PartialEq, From, Add)] struct MyInt(i32); #[derive(PartialEq, From, Into)] struct Point2D { x: i32, y: i32, } #[derive(PartialEq, From, Add, Display)] enum MyEnum { #[display(fmt = "int: {}", _0)] Int(i32), Uint(u32), #[display(fmt = "nothing")] Nothing, } assert!(MyInt(11) == MyInt(5) + 6.into()); assert!((5, 6) == Point2D { x: 5, y: 6 }.into()); assert!(MyEnum::Int(15) == (MyEnum::Int(8) + 7.into()).unwrap()); assert!(MyEnum::Int(15).to_string() == "int: 15"); assert!(MyEnum::Uint(42).to_string() == "42"); assert!(MyEnum::Nothing.to_string() == "nothing"); ``` ## The derivable traits Below are all the traits that you can derive using this library. Some trait derivations are so similar that the further documentation will only show a single one of them. You can recognize these by the "-like" suffix in their name. The trait name before that will be the only one that is used throughout the further documentation. It is important to understand what code gets generated when using one of the derives from this crate. That is why the links below explain what code gets generated for a trait for each group from before. You can use the [`cargo-expand`] utility to see the exact code that is generated for your specific type. This will show you your code with all macros and derives expanded. **NOTE**: You still have to derive each trait separately. So `#[derive(Mul)]` doesn't automatically derive `Div` as well. To derive both you should do `#[derive(Mul, Div)]` ### Conversion traits These are traits that are used to convert automatically between types. 1. [`From`] 2. [`Into`] 3. [`FromStr`] 4. [`TryInto`] 5. [`IntoIterator`] 6. [`AsRef`] 7. [`AsMut`] ### Formatting traits These traits are used for converting a struct to a string in different ways. 1. [`Display`-like], contains `Display`, `DebugCustom`, `Binary`, `Octal`, `LowerHex`, `UpperHex`, `LowerExp`, `UpperExp`, `Pointer` ### Error-handling traits These traits are used to define error-types. 1. [`Error`] ### Operators These are traits that can be used for operator overloading. 1. [`Index`] 2. [`Deref`] 3. [`Not`-like], contains `Not` and `Neg` 4. [`Add`-like], contains `Add`, `Sub`, `BitAnd`, `BitOr`, `BitXor` 5. [`Mul`-like], contains `Mul`, `Div`, `Rem`, `Shr` and `Shl` 3. [`Sum`-like], contains `Sum` and `Product` 6. [`IndexMut`] 7. [`DerefMut`] 8. [`AddAssign`-like], contains `AddAssign`, `SubAssign`, `BitAndAssign`, `BitOrAssign` and `BitXorAssign` 9. [`MulAssign`-like], contains `MulAssign`, `DivAssign`, `RemAssign`, `ShrAssign` and `ShlAssign` ### Static methods These don't derive traits, but derive static methods instead. 1. [`Constructor`], this derives a `new` method that can be used as a constructor. This is very basic if you need more customization for your constructor, check out the [`derive-new`] crate. 2. [`IsVariant`], for each variant `foo` of an enum type, derives a `is_foo` method. 3. [`Unwrap`], for each variant `foo` of an enum type, derives an `unwrap_foo` method. ## Generated code ## Installation This library requires Rust 1.65 or higher and it supports `no_std` out of the box. Then add the following to `Cargo.toml`: ```toml [dependencies] derive_more = "0.99.0" # You can specifiy the types of derives that you need for less time spent # compiling. For the full list of features see this crate its Cargo.toml. default-features = false features = ["from", "add", "iterator"] ``` And this to the top of your Rust file for Rust 2018: ```rust extern crate derive_more; // use the derives that you want in the file use derive_more::{Add, Display, From}; ``` If you're still using Rust 2015 you should add this instead: ```rust extern crate core; #[macro_use] extern crate derive_more; ``` [`cargo-expand`]: https://github.com/dtolnay/cargo-expand [`derive-new`]: https://github.com/nrc/derive-new [`From`]: https://jeltef.github.io/derive_more/derive_more/from.html [`Into`]: https://jeltef.github.io/derive_more/derive_more/into.html [`FromStr`]: https://jeltef.github.io/derive_more/derive_more/from_str.html [`TryInto`]: https://jeltef.github.io/derive_more/derive_more/try_into.html [`IntoIterator`]: https://jeltef.github.io/derive_more/derive_more/into_iterator.html [`AsRef`]: https://jeltef.github.io/derive_more/derive_more/as_ref.html [`AsMut`]: https://jeltef.github.io/derive_more/derive_more/as_mut.html [`Display`-like]: https://jeltef.github.io/derive_more/derive_more/display.html [`Error`]: https://jeltef.github.io/derive_more/derive_more/error.html [`Index`]: https://jeltef.github.io/derive_more/derive_more/index_op.html [`Deref`]: https://jeltef.github.io/derive_more/derive_more/deref.html [`Not`-like]: https://jeltef.github.io/derive_more/derive_more/not.html [`Add`-like]: https://jeltef.github.io/derive_more/derive_more/add.html [`Mul`-like]: https://jeltef.github.io/derive_more/derive_more/mul.html [`Sum`-like]: https://jeltef.github.io/derive_more/derive_more/sum.html [`IndexMut`]: https://jeltef.github.io/derive_more/derive_more/index_mut.html [`DerefMut`]: https://jeltef.github.io/derive_more/derive_more/deref_mut.html [`AddAssign`-like]: https://jeltef.github.io/derive_more/derive_more/add_assign.html [`MulAssign`-like]: https://jeltef.github.io/derive_more/derive_more/mul_assign.html [`Constructor`]: https://jeltef.github.io/derive_more/derive_more/constructor.html [`IsVariant`]: https://jeltef.github.io/derive_more/derive_more/is_variant.html [`Unwrap`]: https://jeltef.github.io/derive_more/derive_more/unwrap.html derive_more-0.99.18/examples/deny_missing_docs.rs000064400000000000000000000010621046102023000201770ustar 00000000000000#![deny(missing_docs)] //! Some docs #[macro_use] extern crate derive_more; fn main() {} /// Some docs #[derive( Add, AddAssign, Constructor, Display, From, FromStr, Into, Mul, MulAssign, Not )] pub struct MyInt(i32); /// Some docs #[derive(Deref, DerefMut)] pub struct MyBoxedInt(Box); /// Some docs #[derive(Index, IndexMut)] pub struct MyVec(Vec); /// Some docs #[allow(dead_code)] #[derive(Clone, Copy, TryInto)] #[derive(IsVariant)] enum MixedInts { SmallInt(i32), NamedBigInt { int: i64 }, } derive_more-0.99.18/src/add_assign_like.rs000064400000000000000000000031041046102023000165470ustar 00000000000000use crate::add_helpers::{struct_exprs, tuple_exprs}; use crate::utils::{add_extra_ty_param_bound_op, named_to_vec, unnamed_to_vec}; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{Data, DeriveInput, Fields, Ident}; pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let trait_ident = Ident::new(trait_name, Span::call_site()); let method_name = trait_name.to_string(); let method_name = method_name.trim_end_matches("Assign"); let method_name = method_name.to_lowercase(); let method_ident = Ident::new(&(method_name + "_assign"), Span::call_site()); let input_type = &input.ident; let generics = add_extra_ty_param_bound_op(&input.generics, &trait_ident); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let exprs = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { tuple_exprs(&unnamed_to_vec(fields), &method_ident) } Fields::Named(ref fields) => { struct_exprs(&named_to_vec(fields), &method_ident) } _ => panic!("Unit structs cannot use derive({})", trait_name), }, _ => panic!("Only structs can use derive({})", trait_name), }; quote!( impl#impl_generics ::core::ops::#trait_ident for #input_type#ty_generics #where_clause { #[inline] fn #method_ident(&mut self, rhs: #input_type#ty_generics) { #(#exprs; )* } } ) } derive_more-0.99.18/src/add_helpers.rs000064400000000000000000000014751046102023000157320ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::{Field, Ident, Index}; pub fn tuple_exprs(fields: &[&Field], method_ident: &Ident) -> Vec { let mut exprs = vec![]; for i in 0..fields.len() { let i = Index::from(i); // generates `self.0.add(rhs.0)` let expr = quote!(self.#i.#method_ident(rhs.#i)); exprs.push(expr); } exprs } pub fn struct_exprs(fields: &[&Field], method_ident: &Ident) -> Vec { let mut exprs = vec![]; for field in fields { // It's safe to unwrap because struct fields always have an identifier let field_id = field.ident.as_ref().unwrap(); // generates `x: self.x.add(rhs.x)` let expr = quote!(self.#field_id.#method_ident(rhs.#field_id)); exprs.push(expr) } exprs } derive_more-0.99.18/src/add_like.rs000064400000000000000000000123261046102023000152110ustar 00000000000000use crate::add_helpers::{struct_exprs, tuple_exprs}; use crate::utils::{ add_extra_type_param_bound_op_output, field_idents, named_to_vec, numbered_vars, unnamed_to_vec, }; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use std::iter; use syn::{Data, DataEnum, DeriveInput, Field, Fields, Ident}; pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let trait_name = trait_name.trim_end_matches("Self"); let trait_ident = Ident::new(trait_name, Span::call_site()); let method_name = trait_name.to_lowercase(); let method_ident = Ident::new(&method_name, Span::call_site()); let input_type = &input.ident; let generics = add_extra_type_param_bound_op_output(&input.generics, &trait_ident); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (output_type, block) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => ( quote!(#input_type#ty_generics), tuple_content(input_type, &unnamed_to_vec(fields), &method_ident), ), Fields::Named(ref fields) => ( quote!(#input_type#ty_generics), struct_content(input_type, &named_to_vec(fields), &method_ident), ), _ => panic!("Unit structs cannot use derive({})", trait_name), }, Data::Enum(ref data_enum) => ( quote!(::core::result::Result<#input_type#ty_generics, &'static str>), enum_content(input_type, data_enum, &method_ident), ), _ => panic!("Only structs and enums can use derive({})", trait_name), }; quote!( impl#impl_generics ::core::ops::#trait_ident for #input_type#ty_generics #where_clause { type Output = #output_type; #[inline] fn #method_ident(self, rhs: #input_type#ty_generics) -> #output_type { #block } } ) } fn tuple_content( input_type: &T, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { let exprs = tuple_exprs(fields, method_ident); quote!(#input_type(#(#exprs),*)) } fn struct_content( input_type: &Ident, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { // It's safe to unwrap because struct fields always have an identifier let exprs = struct_exprs(fields, method_ident); let field_names = field_idents(fields); quote!(#input_type{#(#field_names: #exprs),*}) } #[allow(clippy::cognitive_complexity)] fn enum_content( input_type: &Ident, data_enum: &DataEnum, method_ident: &Ident, ) -> TokenStream { let mut matches = vec![]; let mut method_iter = iter::repeat(method_ident); for variant in &data_enum.variants { let subtype = &variant.ident; let subtype = quote!(#input_type::#subtype); match variant.fields { Fields::Unnamed(ref fields) => { // The patern that is outputted should look like this: // (Subtype(left_vars), TypePath(right_vars)) => Ok(TypePath(exprs)) let size = unnamed_to_vec(fields).len(); let l_vars = &numbered_vars(size, "l_"); let r_vars = &numbered_vars(size, "r_"); let method_iter = method_iter.by_ref(); let matcher = quote! { (#subtype(#(#l_vars),*), #subtype(#(#r_vars),*)) => { ::core::result::Result::Ok(#subtype(#(#l_vars.#method_iter(#r_vars)),*)) } }; matches.push(matcher); } Fields::Named(ref fields) => { // The patern that is outputted should look like this: // (Subtype{a: __l_a, ...}, Subtype{a: __r_a, ...} => { // Ok(Subtype{a: __l_a.add(__r_a), ...}) // } let field_vec = named_to_vec(fields); let size = field_vec.len(); let field_names = &field_idents(&field_vec); let l_vars = &numbered_vars(size, "l_"); let r_vars = &numbered_vars(size, "r_"); let method_iter = method_iter.by_ref(); let matcher = quote! { (#subtype{#(#field_names: #l_vars),*}, #subtype{#(#field_names: #r_vars),*}) => { ::core::result::Result::Ok(#subtype{#(#field_names: #l_vars.#method_iter(#r_vars)),*}) } }; matches.push(matcher); } Fields::Unit => { let message = format!("Cannot {}() unit variants", method_ident); matches.push(quote!((#subtype, #subtype) => ::core::result::Result::Err(#message))); } } } if data_enum.variants.len() > 1 { // In the strange case where there's only one enum variant this is would be an unreachable // match. let message = format!("Trying to {} mismatched enum variants", method_ident); matches.push(quote!(_ => ::core::result::Result::Err(#message))); } quote!( match (self, rhs) { #(#matches),* } ) } derive_more-0.99.18/src/as_mut.rs000064400000000000000000000052431046102023000147450ustar 00000000000000use crate::utils::{ add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State, }; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{parse::Result, DeriveInput, Ident}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let as_mut_type = &Ident::new("__AsMutT", Span::call_site()); let state = State::with_type_bound( input, trait_name, quote!(::core::convert), String::from("as_mut"), AttrParams::ignore_and_forward(), false, )?; let MultiFieldData { fields, input_type, members, infos, trait_path, impl_generics, ty_generics, where_clause, .. } = state.enabled_fields_data(); let sub_items: Vec<_> = infos .iter() .zip(members.iter()) .zip(fields) .map(|((info, member), field)| { let field_type = &field.ty; if info.forward { let trait_path = quote!(#trait_path<#as_mut_type>); let type_where_clauses = quote! { where #field_type: #trait_path }; let new_generics = add_where_clauses_for_new_ident( &input.generics, &[field], as_mut_type, type_where_clauses, false, ); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let casted_trait = quote!(<#field_type as #trait_path>); ( quote!(#casted_trait::as_mut(&mut #member)), quote!(#impl_generics), quote!(#where_clause), quote!(#trait_path), quote!(#as_mut_type), ) } else { ( quote!(&mut #member), quote!(#impl_generics), quote!(#where_clause), quote!(#trait_path<#field_type>), quote!(#field_type), ) } }) .collect(); let bodies = sub_items.iter().map(|i| &i.0); let impl_genericses = sub_items.iter().map(|i| &i.1); let where_clauses = sub_items.iter().map(|i| &i.2); let trait_paths = sub_items.iter().map(|i| &i.3); let return_types = sub_items.iter().map(|i| &i.4); Ok(quote! {#( impl#impl_genericses #trait_paths for #input_type#ty_generics #where_clauses { #[inline] fn as_mut(&mut self) -> &mut #return_types { #bodies } } )*}) } derive_more-0.99.18/src/as_ref.rs000064400000000000000000000052171046102023000147150ustar 00000000000000use crate::utils::{ add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State, }; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{parse::Result, DeriveInput, Ident}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let as_ref_type = &Ident::new("__AsRefT", Span::call_site()); let state = State::with_type_bound( input, trait_name, quote!(::core::convert), String::from("as_ref"), AttrParams::ignore_and_forward(), false, )?; let MultiFieldData { fields, input_type, members, infos, trait_path, impl_generics, ty_generics, where_clause, .. } = state.enabled_fields_data(); let sub_items: Vec<_> = infos .iter() .zip(members.iter()) .zip(fields) .map(|((info, member), field)| { let field_type = &field.ty; if info.forward { let trait_path = quote!(#trait_path<#as_ref_type>); let type_where_clauses = quote! { where #field_type: #trait_path }; let new_generics = add_where_clauses_for_new_ident( &input.generics, &[field], as_ref_type, type_where_clauses, false, ); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let casted_trait = quote!(<#field_type as #trait_path>); ( quote!(#casted_trait::as_ref(&#member)), quote!(#impl_generics), quote!(#where_clause), quote!(#trait_path), quote!(#as_ref_type), ) } else { ( quote!(&#member), quote!(#impl_generics), quote!(#where_clause), quote!(#trait_path<#field_type>), quote!(#field_type), ) } }) .collect(); let bodies = sub_items.iter().map(|i| &i.0); let impl_generics = sub_items.iter().map(|i| &i.1); let where_clauses = sub_items.iter().map(|i| &i.2); let trait_paths = sub_items.iter().map(|i| &i.3); let return_types = sub_items.iter().map(|i| &i.4); Ok(quote! {#( impl#impl_generics #trait_paths for #input_type#ty_generics #where_clauses { #[inline] fn as_ref(&self) -> &#return_types { #bodies } } )*}) } derive_more-0.99.18/src/constructor.rs000064400000000000000000000036261046102023000160450ustar 00000000000000use crate::utils::{ field_idents, get_field_types, named_to_vec, numbered_vars, unnamed_to_vec, }; use proc_macro2::TokenStream; use quote::quote; use syn::{Data, DeriveInput, Field, Fields, Ident}; /// Provides the hook to expand `#[derive(Constructor)]` into an implementation of `Constructor` pub fn expand(input: &DeriveInput, _: &str) -> TokenStream { let input_type = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let ((body, vars), fields) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { let field_vec = unnamed_to_vec(fields); (tuple_body(input_type, &field_vec), field_vec) } Fields::Named(ref fields) => { let field_vec = named_to_vec(fields); (struct_body(input_type, &field_vec), field_vec) } Fields::Unit => (struct_body(input_type, &[]), vec![]), }, _ => panic!("Only structs can derive a constructor"), }; let original_types = &get_field_types(&fields); quote! { #[allow(missing_docs)] impl#impl_generics #input_type#ty_generics #where_clause { #[inline] pub fn new(#(#vars: #original_types),*) -> #input_type#ty_generics { #body } } } } fn tuple_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec) { let vars = &numbered_vars(fields.len(), ""); (quote!(#return_type(#(#vars),*)), vars.clone()) } fn struct_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec) { let field_names: &Vec = &field_idents(fields).iter().map(|f| (**f).clone()).collect(); let vars = field_names; let ret_vars = field_names.clone(); (quote!(#return_type{#(#field_names: #vars),*}), ret_vars) } derive_more-0.99.18/src/deref.rs000064400000000000000000000027711046102023000145450ustar 00000000000000use crate::utils::{add_extra_where_clauses, SingleFieldData, State}; use proc_macro2::TokenStream; use quote::quote; use syn::{parse::Result, DeriveInput}; /// Provides the hook to expand `#[derive(Deref)]` into an implementation of `Deref` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_forward( input, trait_name, quote!(::core::ops), trait_name.to_lowercase(), )?; let SingleFieldData { input_type, field_type, trait_path, casted_trait, ty_generics, member, info, .. } = state.assert_single_enabled_field(); let (target, body, generics) = if info.forward { ( quote!(#casted_trait::Target), quote!(#casted_trait::deref(&#member)), add_extra_where_clauses( &input.generics, quote! { where #field_type: #trait_path }, ), ) } else { ( quote!(#field_type), quote!(&#member), input.generics.clone(), ) }; let (impl_generics, _, where_clause) = generics.split_for_impl(); Ok(quote! { impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { type Target = #target; #[inline] fn deref(&self) -> &Self::Target { #body } } }) } derive_more-0.99.18/src/deref_mut.rs000064400000000000000000000025741046102023000154330ustar 00000000000000use crate::utils::{add_extra_where_clauses, SingleFieldData, State}; use proc_macro2::TokenStream; use quote::quote; use syn::{parse::Result, DeriveInput}; /// Provides the hook to expand `#[derive(DerefMut)]` into an implementation of `DerefMut` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_forward( input, trait_name, quote!(::core::ops), String::from("deref_mut"), )?; let SingleFieldData { input_type, trait_path, casted_trait, ty_generics, field_type, member, info, .. } = state.assert_single_enabled_field(); let (body, generics) = if info.forward { ( quote!(#casted_trait::deref_mut(&mut #member)), add_extra_where_clauses( &input.generics, quote! { where #field_type: #trait_path }, ), ) } else { (quote!(&mut #member), input.generics.clone()) }; let (impl_generics, _, where_clause) = generics.split_for_impl(); Ok(quote! { impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { #body } } }) } derive_more-0.99.18/src/display.rs000064400000000000000000000777351046102023000151410ustar 00000000000000use std::{fmt::Display, str::FromStr as _}; use crate::syn_compat::{AttributeExt as _, NestedMeta, ParsedMeta}; use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, quote_spanned}; use syn::{ parse::Parser as _, punctuated::Punctuated, spanned::Spanned as _, Error, Result, }; use syn::{Expr, ExprLit}; use crate::utils; use utils::{HashMap, HashSet}; /// Provides the hook to expand `#[derive(Display)]` into an implementation of `From` pub fn expand(input: &syn::DeriveInput, trait_name: &str) -> Result { let trait_name = trait_name.trim_end_matches("Custom"); let trait_ident = syn::Ident::new(trait_name, Span::call_site()); let trait_path = "e!(::core::fmt::#trait_ident); let trait_attr = trait_name_to_attribute_name(trait_name); let type_params = input .generics .type_params() .map(|t| t.ident.clone()) .collect(); let ParseResult { arms, bounds, requires_helper, } = State { trait_path, trait_attr, input, type_params, } .get_match_arms_and_extra_bounds()?; let generics = if !bounds.is_empty() { let bounds: Vec<_> = bounds .into_iter() .map(|(ty, trait_names)| { let bounds: Vec<_> = trait_names .into_iter() .map(|bound| quote!(#bound)) .collect(); quote!(#ty: #(#bounds)+*) }) .collect(); let where_clause = quote_spanned!(input.span()=> where #(#bounds),*); utils::add_extra_where_clauses(&input.generics, where_clause) } else { input.generics.clone() }; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let name = &input.ident; let helper_struct = if requires_helper { display_as_helper_struct() } else { TokenStream::new() }; Ok(quote! { impl #impl_generics #trait_path for #name #ty_generics #where_clause { #[allow(unused_variables)] #[inline] fn fmt(&self, _derive_more_display_formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { #helper_struct match self { #arms _ => Ok(()) // This is needed for empty enums } } } }) } fn trait_name_to_attribute_name(trait_name: &str) -> &'static str { match trait_name { "Display" => "display", "Binary" => "binary", "Octal" => "octal", "LowerHex" => "lower_hex", "UpperHex" => "upper_hex", "LowerExp" => "lower_exp", "UpperExp" => "upper_exp", "Pointer" => "pointer", "Debug" => "debug", _ => unimplemented!(), } } fn attribute_name_to_trait_name(attribute_name: &str) -> &'static str { match attribute_name { "display" => "Display", "binary" => "Binary", "octal" => "Octal", "lower_hex" => "LowerHex", "upper_hex" => "UpperHex", "lower_exp" => "LowerExp", "upper_exp" => "UpperExp", "pointer" => "Pointer", _ => unreachable!(), } } fn trait_name_to_trait_bound(trait_name: &str) -> syn::TraitBound { let path_segments_iterator = vec!["core", "fmt", trait_name] .into_iter() .map(|segment| syn::PathSegment::from(Ident::new(segment, Span::call_site()))); syn::TraitBound { lifetimes: None, modifier: syn::TraitBoundModifier::None, paren_token: None, path: syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path_segments_iterator.collect(), }, } } /// Create a helper struct that is required by some `Display` impls. /// /// The struct is necessary in cases where `Display` is derived for an enum /// with an outer `#[display(fmt = "...")]` attribute and if that outer /// format-string contains a single placeholder. In that case, we have to /// format twice: /// /// - we need to format each variant according to its own, optional /// format-string, /// - we then need to insert this formatted variant into the outer /// format-string. /// /// This helper struct solves this as follows: /// - formatting the whole object inserts the helper struct into the outer /// format string, /// - upon being formatted, the helper struct calls an inner closure to produce /// its formatted result, /// - the closure in turn uses the inner, optional format-string to produce its /// result. If there is no inner format-string, it falls back to plain /// `$trait::fmt()`. fn display_as_helper_struct() -> TokenStream { quote! { struct _derive_more_DisplayAs(F) where F: ::core::ops::Fn(&mut ::core::fmt::Formatter) -> ::core::fmt::Result; const _derive_more_DisplayAs_impl: () = { impl ::core::fmt::Display for _derive_more_DisplayAs where F: ::core::ops::Fn(&mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { (self.0)(f) } } }; } } /// Result type of `State::get_match_arms_and_extra_bounds()`. #[derive(Default)] struct ParseResult { /// The match arms destructuring `self`. arms: TokenStream, /// Any trait bounds that may be required. bounds: HashMap>, /// `true` if the Display impl requires the `DisplayAs` helper struct. requires_helper: bool, } struct State<'a, 'b> { trait_path: &'b TokenStream, trait_attr: &'static str, input: &'a syn::DeriveInput, type_params: HashSet, } impl<'a, 'b> State<'a, 'b> { fn get_proper_fmt_syntax(&self) -> impl Display { format!( r#"Proper syntax: #[{}(fmt = "My format", "arg1", "arg2")]"#, self.trait_attr ) } fn get_proper_bound_syntax(&self) -> impl Display { format!( "Proper syntax: #[{}(bound = \"T, U: Trait1 + Trait2, V: Trait3\")]", self.trait_attr ) } fn get_matcher(&self, fields: &syn::Fields) -> TokenStream { match fields { syn::Fields::Unit => TokenStream::new(), syn::Fields::Unnamed(fields) => { let fields: TokenStream = (0..fields.unnamed.len()) .map(|n| { let i = Ident::new(&format!("_{}", n), Span::call_site()); quote!(#i,) }) .collect(); quote!((#fields)) } syn::Fields::Named(fields) => { let fields: TokenStream = fields .named .iter() .map(|f| { let i = f.ident.as_ref().unwrap(); quote!(#i,) }) .collect(); quote!({#fields}) } } } fn find_meta( &self, attrs: &[syn::Attribute], meta_key: &str, ) -> Result> { let mut metas = Vec::new(); for meta in attrs.iter().filter_map(|attr| attr.parse_meta().ok()) { let meta_list = match &meta { ParsedMeta::List(meta) => meta, _ => continue, }; if !meta_list.path.is_ident(self.trait_attr) { continue; } let meta_nv = match meta_list.nested.first() { Some(NestedMeta::Meta(ParsedMeta::NameValue(meta_nv))) => meta_nv, _ => { // If the given attribute is not MetaNameValue, it most likely implies that the // user is writing an incorrect format. For example: // - `#[display()]` // - `#[display("foo")]` // - `#[display(foo)]` return Err(Error::new( meta.span(), format!( r#"The format for this attribute cannot be parsed. Correct format: `#[{}({} = "...")]`"#, self.trait_attr, meta_key ), )); } }; if meta_nv.path.is_ident(meta_key) { metas.push(meta); } } let mut iter = metas.into_iter(); let meta = iter.next(); if iter.next().is_none() { Ok(meta) } else { Err(Error::new(meta.span(), "Too many attributes specified")) } } fn parse_meta_bounds( &self, bounds: &syn::LitStr, ) -> Result>> { let span = bounds.span(); let input = bounds.value(); let tokens = TokenStream::from_str(&input)?; let parser = Punctuated::::parse_terminated; let generic_params = parser .parse2(tokens) .map_err(|error| Error::new(span, error.to_string()))?; if generic_params.is_empty() { return Err(Error::new(span, "No bounds specified")); } let mut bounds = HashMap::default(); for generic_param in generic_params { let type_param = match generic_param { syn::GenericParam::Type(type_param) => type_param, _ => return Err(Error::new(span, "Only trait bounds allowed")), }; if !self.type_params.contains(&type_param.ident) { return Err(Error::new( span, "Unknown generic type argument specified", )); } else if !type_param.attrs.is_empty() { return Err(Error::new(span, "Attributes aren't allowed")); } else if type_param.eq_token.is_some() || type_param.default.is_some() { return Err(Error::new(span, "Default type parameters aren't allowed")); } let ident = type_param.ident.to_string(); let ty = syn::Type::Path(syn::TypePath { qself: None, path: type_param.ident.into(), }); let bounds = bounds.entry(ty).or_insert_with(HashSet::default); for bound in type_param.bounds { let bound = match bound { syn::TypeParamBound::Trait(bound) => bound, _ => return Err(Error::new(span, "Only trait bounds allowed")), }; if bound.lifetimes.is_some() { return Err(Error::new( span, "Higher-rank trait bounds aren't allowed", )); } bounds.insert(bound); } if bounds.is_empty() { return Err(Error::new( span, format!("No bounds specified for type parameter {}", ident), )); } } Ok(bounds) } fn parse_meta_fmt( &self, meta: &ParsedMeta, outer_enum: bool, ) -> Result<(TokenStream, bool)> { let list = match meta { ParsedMeta::List(list) => list, _ => { return Err(Error::new(meta.span(), self.get_proper_fmt_syntax())); } }; match &list.nested[0] { NestedMeta::Meta(ParsedMeta::NameValue(syn::MetaNameValue { path, value: Expr::Lit(ExprLit { lit: syn::Lit::Str(fmt), .. }), .. })) => match path { op if op.segments.first().expect("path shouldn't be empty").ident == "fmt" => { let expected_affix_usage = "outer `enum` `fmt` is an affix spec that expects no args and at most 1 placeholder for inner variant display"; if outer_enum { if list.nested.iter().skip(1).count() != 0 { return Err(Error::new( list.nested[1].span(), expected_affix_usage, )); } // TODO: Check for a single `Display` group? let fmt_string = match &list.nested[0] { NestedMeta::Meta(ParsedMeta::NameValue( syn::MetaNameValue { path, value: Expr::Lit(ExprLit { lit: syn::Lit::Str(s), .. }), .. }, )) if path .segments .first() .expect("path shouldn't be empty") .ident == "fmt" => { s.value() } // This one has been checked already in get_meta_fmt() method. _ => unreachable!(), }; let num_placeholders = Placeholder::parse_fmt_string(&fmt_string).len(); if num_placeholders > 1 { return Err(Error::new( list.nested[1].span(), expected_affix_usage, )); } if num_placeholders == 1 { return Ok((quote_spanned!(fmt.span()=> #fmt), true)); } } let args = list .nested .iter() .skip(1) // skip fmt = "..." .try_fold(TokenStream::new(), |args, arg| { let arg = match arg { NestedMeta::Lit(syn::Lit::Str(s)) => s, NestedMeta::Meta(ParsedMeta::Path(i)) => { return Ok(quote_spanned!(list.span()=> #args #i,)); } _ => { return Err(Error::new( arg.span(), self.get_proper_fmt_syntax(), )) } }; let arg: TokenStream = arg.parse().map_err(|e| Error::new(arg.span(), e))?; Ok(quote_spanned!(list.span()=> #args #arg,)) })?; Ok(( quote_spanned!(meta.span()=> write!(_derive_more_display_formatter, #fmt, #args)), false, )) } _ => Err(Error::new( list.nested[0].span(), self.get_proper_fmt_syntax(), )), }, _ => Err(Error::new( list.nested[0].span(), self.get_proper_fmt_syntax(), )), } } fn infer_fmt(&self, fields: &syn::Fields, name: &Ident) -> Result { let fields = match fields { syn::Fields::Unit => { return Ok(quote!( _derive_more_display_formatter.write_str(stringify!(#name)) )) } syn::Fields::Named(fields) => &fields.named, syn::Fields::Unnamed(fields) => &fields.unnamed, }; if fields.is_empty() { return Ok(quote!( _derive_more_display_formatter.write_str(stringify!(#name)) )); } else if fields.len() > 1 { return Err(Error::new( fields.span(), "Cannot automatically infer format for types with more than 1 field", )); } let trait_path = self.trait_path; if let Some(ident) = &fields.iter().next().as_ref().unwrap().ident { Ok(quote!(#trait_path::fmt(#ident, _derive_more_display_formatter))) } else { Ok(quote!(#trait_path::fmt(_0, _derive_more_display_formatter))) } } fn get_match_arms_and_extra_bounds(&self) -> Result { let result: Result<_> = match &self.input.data { syn::Data::Enum(e) => { match self .find_meta(&self.input.attrs, "fmt") .and_then(|m| m.map(|m| self.parse_meta_fmt(&m, true)).transpose())? { // #[display(fmt = "no placeholder")] on whole enum. Some((fmt, false)) => { e.variants.iter().try_for_each(|v| { if let Some(meta) = self.find_meta(&v.attrs, "fmt")? { Err(Error::new( meta.span(), "`fmt` cannot be used on variant when the whole enum has a format string without a placeholder, maybe you want to add a placeholder?", )) } else { Ok(()) } })?; Ok(ParseResult { arms: quote_spanned!(self.input.span()=> _ => #fmt,), bounds: HashMap::default(), requires_helper: false, }) } // #[display(fmt = "one placeholder: {}")] on whole enum. Some((outer_fmt, true)) => { let fmt: Result = e.variants.iter().try_fold(TokenStream::new(), |arms, v| { let matcher = self.get_matcher(&v.fields); let fmt = if let Some(meta) = self.find_meta(&v.attrs, "fmt")? { self.parse_meta_fmt(&meta, false)?.0 } else { self.infer_fmt(&v.fields, &v.ident)? }; let name = &self.input.ident; let v_name = &v.ident; Ok(quote_spanned!(fmt.span()=> #arms #name::#v_name #matcher => write!( _derive_more_display_formatter, #outer_fmt, _derive_more_DisplayAs(|_derive_more_display_formatter| #fmt) ),)) }); let fmt = fmt?; Ok(ParseResult { arms: quote_spanned!(self.input.span()=> #fmt), bounds: HashMap::default(), requires_helper: true, }) } // No format attribute on whole enum. None => e.variants.iter().try_fold(ParseResult::default(), |result, v| { let ParseResult{ arms, mut bounds, requires_helper } = result; let matcher = self.get_matcher(&v.fields); let name = &self.input.ident; let v_name = &v.ident; let fmt: TokenStream; let these_bounds: HashMap<_, _>; if let Some(meta) = self.find_meta(&v.attrs, "fmt")? { fmt = self.parse_meta_fmt(&meta, false)?.0; these_bounds = self.get_used_type_params_bounds(&v.fields, &meta); } else { fmt = self.infer_fmt(&v.fields, v_name)?; these_bounds = self.infer_type_params_bounds(&v.fields); }; these_bounds.into_iter().for_each(|(ty, trait_names)| { bounds.entry(ty).or_default().extend(trait_names) }); let arms = quote_spanned!(self.input.span()=> #arms #name::#v_name #matcher => #fmt,); Ok(ParseResult{ arms, bounds, requires_helper }) }), } } syn::Data::Struct(s) => { let matcher = self.get_matcher(&s.fields); let name = &self.input.ident; let fmt: TokenStream; let bounds: HashMap<_, _>; if let Some(meta) = self.find_meta(&self.input.attrs, "fmt")? { fmt = self.parse_meta_fmt(&meta, false)?.0; bounds = self.get_used_type_params_bounds(&s.fields, &meta); } else { fmt = self.infer_fmt(&s.fields, name)?; bounds = self.infer_type_params_bounds(&s.fields); } Ok(ParseResult { arms: quote_spanned!(self.input.span()=> #name #matcher => #fmt,), bounds, requires_helper: false, }) } syn::Data::Union(_) => { let meta = self.find_meta(&self.input.attrs, "fmt")?.ok_or_else(|| { Error::new( self.input.span(), "Cannot automatically infer format for unions", ) })?; let fmt = self.parse_meta_fmt(&meta, false)?.0; Ok(ParseResult { arms: quote_spanned!(self.input.span()=> _ => #fmt,), bounds: HashMap::default(), requires_helper: false, }) } }; let mut result = result?; let meta = match self.find_meta(&self.input.attrs, "bound")? { Some(meta) => meta, _ => return Ok(result), }; let span = meta.span(); let meta = match meta { ParsedMeta::List(meta) => meta.nested, _ => return Err(Error::new(span, self.get_proper_bound_syntax())), }; if meta.len() != 1 { return Err(Error::new(span, self.get_proper_bound_syntax())); } let meta = match &meta[0] { NestedMeta::Meta(ParsedMeta::NameValue(meta)) => meta, _ => return Err(Error::new(span, self.get_proper_bound_syntax())), }; let extra_bounds = match &meta.value { Expr::Lit(ExprLit { lit: syn::Lit::Str(extra_bounds), .. }) => extra_bounds, _ => return Err(Error::new(span, self.get_proper_bound_syntax())), }; let extra_bounds = self.parse_meta_bounds(extra_bounds)?; extra_bounds.into_iter().for_each(|(ty, trait_names)| { result.bounds.entry(ty).or_default().extend(trait_names) }); Ok(result) } fn get_used_type_params_bounds( &self, fields: &syn::Fields, meta: &ParsedMeta, ) -> HashMap> { if self.type_params.is_empty() { return HashMap::default(); } let fields_type_params: HashMap = fields .iter() .enumerate() .filter_map(|(i, field)| { utils::get_if_type_parameter_used_in_type(&self.type_params, &field.ty) .map(|ty| { ( field .ident .clone() .unwrap_or_else(|| { Ident::new(&format!("_{}", i), Span::call_site()) }) .into(), ty, ) }) }) .collect(); if fields_type_params.is_empty() { return HashMap::default(); } let list = match meta { ParsedMeta::List(list) => list, // This one has been checked already in get_meta_fmt() method. _ => unreachable!(), }; let fmt_args: HashMap<_, _> = list .nested .iter() .skip(1) // skip fmt = "..." .enumerate() .filter_map(|(i, arg)| match arg { NestedMeta::Lit(syn::Lit::Str(ref s)) => { syn::parse_str(&s.value()).ok().map(|id| (i, id)) } NestedMeta::Meta(ParsedMeta::Path(ref id)) => Some((i, id.clone())), // This one has been checked already in get_meta_fmt() method. _ => unreachable!(), }) .collect(); if fmt_args.is_empty() { return HashMap::default(); } let fmt_string = match &list.nested[0] { NestedMeta::Meta(ParsedMeta::NameValue(syn::MetaNameValue { path, value: Expr::Lit(ExprLit { lit: syn::Lit::Str(s), .. }), .. })) if path .segments .first() .expect("path shouldn't be empty") .ident == "fmt" => { s.value() } // This one has been checked already in get_meta_fmt() method. _ => unreachable!(), }; Placeholder::parse_fmt_string(&fmt_string).into_iter().fold( HashMap::default(), |mut bounds, pl| { if let Some(arg) = fmt_args.get(&pl.position) { if fields_type_params.contains_key(arg) { bounds .entry(fields_type_params[arg].clone()) .or_default() .insert(trait_name_to_trait_bound(pl.trait_name)); } } bounds }, ) } fn infer_type_params_bounds( &self, fields: &syn::Fields, ) -> HashMap> { if self.type_params.is_empty() { return HashMap::default(); } if let syn::Fields::Unit = fields { return HashMap::default(); } // infer_fmt() uses only first field. fields .iter() .take(1) .filter_map(|field| { utils::get_if_type_parameter_used_in_type(&self.type_params, &field.ty) .map(|ty| { ( ty, [trait_name_to_trait_bound(attribute_name_to_trait_name( self.trait_attr, ))] .iter() .cloned() .collect(), ) }) }) .collect() } } /// Representation of formatting placeholder. #[derive(Debug, PartialEq)] struct Placeholder { /// Position of formatting argument to be used for this placeholder. position: usize, /// Name of [`std::fmt`] trait to be used for rendering this placeholder. trait_name: &'static str, } impl Placeholder { /// Parses [`Placeholder`]s from a given formatting string. fn parse_fmt_string(s: &str) -> Vec { let mut n = 0; crate::parsing::all_placeholders(s) .into_iter() .flatten() .map(|m| { let (maybe_arg, maybe_typ) = crate::parsing::format(m).unwrap(); let position = maybe_arg.unwrap_or_else(|| { // Assign "the next argument". // https://doc.rust-lang.org/stable/std/fmt/index.html#positional-parameters n += 1; n - 1 }); let typ = maybe_typ.unwrap_or_default(); let trait_name = match typ { "" => "Display", "?" | "x?" | "X?" => "Debug", "o" => "Octal", "x" => "LowerHex", "X" => "UpperHex", "p" => "Pointer", "b" => "Binary", "e" => "LowerExp", "E" => "UpperExp", _ => unreachable!(), }; Placeholder { position, trait_name, } }) .collect() } } #[cfg(test)] mod regex_maybe_placeholder_spec { #[test] fn parses_placeholders_and_omits_escaped() { let fmt_string = "{}, {:?}, {{}}, {{{1:0$}}}"; let placeholders: Vec<_> = crate::parsing::all_placeholders(&fmt_string) .into_iter() .flatten() .collect(); assert_eq!(placeholders, vec!["{}", "{:?}", "{1:0$}"]); } } #[cfg(test)] mod regex_placeholder_format_spec { #[test] fn detects_type() { for (p, expected) in vec![ ("{}", ""), ("{:?}", "?"), ("{:x?}", "x?"), ("{:X?}", "X?"), ("{:o}", "o"), ("{:x}", "x"), ("{:X}", "X"), ("{:p}", "p"), ("{:b}", "b"), ("{:e}", "e"), ("{:E}", "E"), ("{:.*}", ""), ("{8}", ""), ("{:04}", ""), ("{1:0$}", ""), ("{:width$}", ""), ("{9:>8.*}", ""), ("{2:.1$x}", "x"), ] { let typ = crate::parsing::format(p).unwrap().1.unwrap_or_default(); assert_eq!(typ, expected); } } #[test] fn detects_arg() { for (p, expected) in vec![ ("{}", ""), ("{0:?}", "0"), ("{12:x?}", "12"), ("{3:X?}", "3"), ("{5:o}", "5"), ("{6:x}", "6"), ("{:X}", ""), ("{8}", "8"), ("{:04}", ""), ("{1:0$}", "1"), ("{:width$}", ""), ("{9:>8.*}", "9"), ("{2:.1$x}", "2"), ] { let arg = crate::parsing::format(p) .unwrap() .0 .map(|s| s.to_string()) .unwrap_or_default(); assert_eq!(arg, String::from(expected)); } } } #[cfg(test)] mod placeholder_parse_fmt_string_spec { use super::*; #[test] fn indicates_position_and_trait_name_for_each_fmt_placeholder() { let fmt_string = "{},{:?},{{}},{{{1:0$}}}-{2:.1$x}{0:#?}{:width$}"; assert_eq!( Placeholder::parse_fmt_string(&fmt_string), vec![ Placeholder { position: 0, trait_name: "Display", }, Placeholder { position: 1, trait_name: "Debug", }, Placeholder { position: 1, trait_name: "Display", }, Placeholder { position: 2, trait_name: "LowerHex", }, Placeholder { position: 0, trait_name: "Debug", }, Placeholder { position: 2, trait_name: "Display", }, ], ) } } derive_more-0.99.18/src/error.rs000064400000000000000000000302621046102023000146050ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::{spanned::Spanned as _, Error, Result}; use crate::utils::{ self, AttrParams, DeriveType, FullMetaInfo, HashSet, MetaInfo, MultiFieldData, State, }; pub fn expand( input: &syn::DeriveInput, trait_name: &'static str, ) -> Result { let syn::DeriveInput { ident, generics, .. } = input; let state = State::with_attr_params( input, trait_name, quote!(::std::error), trait_name.to_lowercase(), allowed_attr_params(), )?; let type_params: HashSet<_> = generics .params .iter() .filter_map(|generic| match generic { syn::GenericParam::Type(ty) => Some(ty.ident.clone()), _ => None, }) .collect(); let (bounds, source, backtrace) = match state.derive_type { DeriveType::Named | DeriveType::Unnamed => render_struct(&type_params, &state)?, DeriveType::Enum => render_enum(&type_params, &state)?, }; let source = source.map(|source| { quote! { fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> { #source } } }); let backtrace = backtrace.map(|backtrace| { quote! { fn backtrace(&self) -> Option<&::std::backtrace::Backtrace> { #backtrace } } }); let mut generics = generics.clone(); if !type_params.is_empty() { let generic_parameters = generics.params.iter(); generics = utils::add_extra_where_clauses( &generics, quote! { where #ident<#(#generic_parameters),*>: ::std::fmt::Debug + ::std::fmt::Display }, ); } if !bounds.is_empty() { let bounds = bounds.iter(); generics = utils::add_extra_where_clauses( &generics, quote! { where #(#bounds: ::std::fmt::Debug + ::std::fmt::Display + ::std::error::Error + 'static),* }, ); } let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let render = quote! { impl#impl_generics ::std::error::Error for #ident#ty_generics #where_clause { #source #backtrace } }; Ok(render) } fn render_struct( type_params: &HashSet, state: &State, ) -> Result<(HashSet, Option, Option)> { let parsed_fields = parse_fields(type_params, state)?; let source = parsed_fields.render_source_as_struct(); let backtrace = parsed_fields.render_backtrace_as_struct(); Ok((parsed_fields.bounds, source, backtrace)) } fn render_enum( type_params: &HashSet, state: &State, ) -> Result<(HashSet, Option, Option)> { let mut bounds = HashSet::default(); let mut source_match_arms = Vec::new(); let mut backtrace_match_arms = Vec::new(); for variant in state.enabled_variant_data().variants { let default_info = FullMetaInfo { enabled: true, ..FullMetaInfo::default() }; let state = State::from_variant( state.input, state.trait_name, state.trait_module.clone(), state.trait_attr.clone(), allowed_attr_params(), variant, default_info, )?; let parsed_fields = parse_fields(type_params, &state)?; if let Some(expr) = parsed_fields.render_source_as_enum_variant_match_arm() { source_match_arms.push(expr); } if let Some(expr) = parsed_fields.render_backtrace_as_enum_variant_match_arm() { backtrace_match_arms.push(expr); } bounds.extend(parsed_fields.bounds); } let render = |match_arms: &mut Vec| { if !match_arms.is_empty() && match_arms.len() < state.variants.len() { match_arms.push(quote!(_ => None)); } if !match_arms.is_empty() { let expr = quote! { match self { #(#match_arms),* } }; Some(expr) } else { None } }; let source = render(&mut source_match_arms); let backtrace = render(&mut backtrace_match_arms); Ok((bounds, source, backtrace)) } fn allowed_attr_params() -> AttrParams { AttrParams { enum_: vec!["ignore"], struct_: vec!["ignore"], variant: vec!["ignore"], field: vec!["ignore", "source", "backtrace"], } } struct ParsedFields<'input, 'state> { data: MultiFieldData<'input, 'state>, source: Option, backtrace: Option, bounds: HashSet, } impl<'input, 'state> ParsedFields<'input, 'state> { fn new(data: MultiFieldData<'input, 'state>) -> Self { Self { data, source: None, backtrace: None, bounds: HashSet::default(), } } } impl<'input, 'state> ParsedFields<'input, 'state> { fn render_source_as_struct(&self) -> Option { let source = self.source?; let ident = &self.data.members[source]; Some(render_some(quote!(&#ident))) } fn render_source_as_enum_variant_match_arm(&self) -> Option { let source = self.source?; let pattern = self.data.matcher(&[source], &[quote!(source)]); let expr = render_some(quote!(source)); Some(quote!(#pattern => #expr)) } fn render_backtrace_as_struct(&self) -> Option { let backtrace = self.backtrace?; let backtrace_expr = &self.data.members[backtrace]; Some(quote!(Some(&#backtrace_expr))) } fn render_backtrace_as_enum_variant_match_arm(&self) -> Option { let backtrace = self.backtrace?; let pattern = self.data.matcher(&[backtrace], &[quote!(backtrace)]); Some(quote!(#pattern => Some(backtrace))) } } fn render_some(expr: T) -> TokenStream where T: quote::ToTokens, { quote!(Some(#expr as &(dyn ::std::error::Error + 'static))) } fn parse_fields<'input, 'state>( type_params: &HashSet, state: &'state State<'input>, ) -> Result> { let mut parsed_fields = match state.derive_type { DeriveType::Named => { parse_fields_impl(state, |attr, field, _| { // Unwrapping is safe, cause fields in named struct // always have an ident let ident = field.ident.as_ref().unwrap(); match attr { "source" => ident == "source", "backtrace" => { ident == "backtrace" || is_type_path_ends_with_segment(&field.ty, "Backtrace") } _ => unreachable!(), } }) } DeriveType::Unnamed => { let mut parsed_fields = parse_fields_impl(state, |attr, field, len| match attr { "source" => { len == 1 && !is_type_path_ends_with_segment(&field.ty, "Backtrace") } "backtrace" => { is_type_path_ends_with_segment(&field.ty, "Backtrace") } _ => unreachable!(), })?; parsed_fields.source = parsed_fields .source .or_else(|| infer_source_field(&state.fields, &parsed_fields)); Ok(parsed_fields) } _ => unreachable!(), }?; if let Some(source) = parsed_fields.source { add_bound_if_type_parameter_used_in_type( &mut parsed_fields.bounds, type_params, &state.fields[source].ty, ); } Ok(parsed_fields) } /// Checks if `ty` is [`syn::Type::Path`] and ends with segment matching `tail` /// and doesn't contain any generic parameters. fn is_type_path_ends_with_segment(ty: &syn::Type, tail: &str) -> bool { let ty = match ty { syn::Type::Path(ty) => ty, _ => return false, }; // Unwrapping is safe, cause 'syn::TypePath.path.segments' // have to have at least one segment let segment = ty.path.segments.last().unwrap(); match segment.arguments { syn::PathArguments::None => (), _ => return false, }; segment.ident == tail } fn infer_source_field( fields: &[&syn::Field], parsed_fields: &ParsedFields, ) -> Option { // if we have exactly two fields if fields.len() != 2 { return None; } // no source field was specified/inferred if parsed_fields.source.is_some() { return None; } // but one of the fields was specified/inferred as backtrace field if let Some(backtrace) = parsed_fields.backtrace { // then infer *other field* as source field let source = (backtrace + 1) % 2; // unless it was explicitly marked as non-source if parsed_fields.data.infos[source].info.source != Some(false) { return Some(source); } } None } fn parse_fields_impl<'input, 'state, P>( state: &'state State<'input>, is_valid_default_field_for_attr: P, ) -> Result> where P: Fn(&str, &syn::Field, usize) -> bool, { let MultiFieldData { fields, infos, .. } = state.enabled_fields_data(); let iter = fields .iter() .zip(infos.iter().map(|info| &info.info)) .enumerate() .map(|(index, (field, info))| (index, *field, info)); let source = parse_field_impl( &is_valid_default_field_for_attr, state.fields.len(), iter.clone(), "source", |info| info.source, )?; let backtrace = parse_field_impl( &is_valid_default_field_for_attr, state.fields.len(), iter.clone(), "backtrace", |info| info.backtrace, )?; let mut parsed_fields = ParsedFields::new(state.enabled_fields_data()); if let Some((index, _, _)) = source { parsed_fields.source = Some(index); } if let Some((index, _, _)) = backtrace { parsed_fields.backtrace = Some(index); } Ok(parsed_fields) } fn parse_field_impl<'a, P, V>( is_valid_default_field_for_attr: &P, len: usize, iter: impl Iterator + Clone, attr: &str, value: V, ) -> Result> where P: Fn(&str, &syn::Field, usize) -> bool, V: Fn(&MetaInfo) -> Option, { let explicit_fields = iter.clone().filter(|(_, _, info)| match value(info) { Some(true) => true, _ => false, }); let inferred_fields = iter.filter(|(_, field, info)| match value(info) { None => is_valid_default_field_for_attr(attr, field, len), _ => false, }); let field = assert_iter_contains_zero_or_one_item( explicit_fields, &format!( "Multiple `{}` attributes specified. \ Single attribute per struct/enum variant allowed.", attr ), )?; let field = match field { field @ Some(_) => field, None => assert_iter_contains_zero_or_one_item( inferred_fields, "Conflicting fields found. Consider specifying some \ `#[error(...)]` attributes to resolve conflict.", )?, }; Ok(field) } fn assert_iter_contains_zero_or_one_item<'a>( mut iter: impl Iterator, error_msg: &str, ) -> Result> { let item = match iter.next() { Some(item) => item, None => return Ok(None), }; if let Some((_, field, _)) = iter.next() { return Err(Error::new(field.span(), error_msg)); } Ok(Some(item)) } fn add_bound_if_type_parameter_used_in_type( bounds: &mut HashSet, type_params: &HashSet, ty: &syn::Type, ) { if let Some(ty) = utils::get_if_type_parameter_used_in_type(type_params, ty) { bounds.insert(ty); } } derive_more-0.99.18/src/from.rs000064400000000000000000000121561046102023000144210ustar 00000000000000use std::iter; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use syn::{parse::Result, DeriveInput, Ident, Index}; use crate::utils::{ add_where_clauses_for_new_ident, AttrParams, DeriveType, HashMap, MultiFieldData, RefType, State, }; /// Provides the hook to expand `#[derive(From)]` into an implementation of `From` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_attr_params( input, trait_name, quote!(::core::convert), trait_name.to_lowercase(), AttrParams { enum_: vec!["forward", "ignore"], variant: vec!["forward", "ignore", "types"], struct_: vec!["forward", "types"], field: vec!["forward"], }, )?; if state.derive_type == DeriveType::Enum { Ok(enum_from(input, state)) } else { Ok(struct_from(input, &state)) } } pub fn struct_from(input: &DeriveInput, state: &State) -> TokenStream { let multi_field_data = state.enabled_fields_data(); let MultiFieldData { fields, variant_info, infos, input_type, trait_path, .. } = multi_field_data.clone(); let additional_types = variant_info.additional_types(RefType::No); let mut impls = Vec::with_capacity(additional_types.len() + 1); for explicit_type in iter::once(None).chain(additional_types.iter().map(Some)) { let mut new_generics = input.generics.clone(); let mut initializers = Vec::with_capacity(infos.len()); let mut from_types = Vec::with_capacity(infos.len()); for (i, (info, field)) in infos.iter().zip(fields.iter()).enumerate() { let field_type = &field.ty; let variable = if fields.len() == 1 { quote! { original } } else { let tuple_index = Index::from(i); quote! { original.#tuple_index } }; if let Some(type_) = explicit_type { initializers.push(quote! { <#field_type as #trait_path<#type_>>::from(#variable) }); from_types.push(quote! { #type_ }); } else if info.forward { let type_param = &Ident::new(&format!("__FromT{}", i), Span::call_site()); let sub_trait_path = quote! { #trait_path<#type_param> }; let type_where_clauses = quote! { where #field_type: #sub_trait_path }; new_generics = add_where_clauses_for_new_ident( &new_generics, &[field], type_param, type_where_clauses, true, ); let casted_trait = quote! { <#field_type as #sub_trait_path> }; initializers.push(quote! { #casted_trait::from(#variable) }); from_types.push(quote! { #type_param }); } else { initializers.push(variable); from_types.push(quote! { #field_type }); } } let body = multi_field_data.initializer(&initializers); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let (_, ty_generics, _) = input.generics.split_for_impl(); impls.push(quote! { #[automatically_derived] impl#impl_generics #trait_path<(#(#from_types),*)> for #input_type#ty_generics #where_clause { #[inline] fn from(original: (#(#from_types),*)) -> #input_type#ty_generics { #body } } }); } quote! { #( #impls )* } } fn enum_from(input: &DeriveInput, state: State) -> TokenStream { let mut tokens = TokenStream::new(); let mut variants_per_types = HashMap::default(); for variant_state in state.enabled_variant_data().variant_states { let multi_field_data = variant_state.enabled_fields_data(); let MultiFieldData { field_types, .. } = multi_field_data.clone(); variants_per_types .entry(field_types.clone()) .or_insert_with(Vec::new) .push(variant_state); } for (ref field_types, ref variant_states) in variants_per_types { for variant_state in variant_states { let multi_field_data = variant_state.enabled_fields_data(); let MultiFieldData { variant_info, infos, .. } = multi_field_data.clone(); // If there would be a conflict on a empty tuple derive, ignore the // variants that are not explicitly enabled or have explicitly enabled // or disabled fields if field_types.is_empty() && variant_states.len() > 1 && !std::iter::once(variant_info) .chain(infos) .any(|info| info.info.enabled.is_some()) { continue; } struct_from(input, variant_state).to_tokens(&mut tokens); } } tokens } derive_more-0.99.18/src/from_str.rs000064400000000000000000000027211046102023000153060ustar 00000000000000use crate::utils::{SingleFieldData, State}; use proc_macro2::TokenStream; use quote::quote; use syn::{parse::Result, DeriveInput}; /// Provides the hook to expand `#[derive(FromStr)]` into an implementation of `FromStr` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::new( input, trait_name, quote!(::core::str), trait_name.to_lowercase(), )?; // We cannot set defaults for fields, once we do we can remove this check if state.fields.len() != 1 || state.enabled_fields().len() != 1 { panic_one_field(trait_name); } let single_field_data = state.assert_single_enabled_field(); let SingleFieldData { input_type, field_type, trait_path, casted_trait, impl_generics, ty_generics, where_clause, .. } = single_field_data.clone(); let initializers = [quote!(#casted_trait::from_str(src)?)]; let body = single_field_data.initializer(&initializers); Ok(quote! { impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { type Err = <#field_type as #trait_path>::Err; #[inline] fn from_str(src: &str) -> ::core::result::Result { Ok(#body) } } }) } fn panic_one_field(trait_name: &str) -> ! { panic!("Only structs with one field can derive({})", trait_name) } derive_more-0.99.18/src/index.rs000064400000000000000000000030501046102023000145560ustar 00000000000000use crate::utils::{add_where_clauses_for_new_ident, SingleFieldData, State}; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{parse::Result, DeriveInput, Ident}; /// Provides the hook to expand `#[derive(Index)]` into an implementation of `Index` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let index_type = &Ident::new("__IdxT", Span::call_site()); let mut state = State::with_field_ignore( input, trait_name, quote!(::core::ops), trait_name.to_lowercase(), )?; state.add_trait_path_type_param(quote!(#index_type)); let SingleFieldData { field, field_type, input_type, trait_path_with_params, casted_trait, member, .. } = state.assert_single_enabled_field(); let type_where_clauses = quote! { where #field_type: #trait_path_with_params }; let new_generics = add_where_clauses_for_new_ident( &input.generics, &[field], index_type, type_where_clauses, true, ); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let (_, ty_generics, _) = input.generics.split_for_impl(); Ok(quote! { impl#impl_generics #trait_path_with_params for #input_type#ty_generics #where_clause { type Output = #casted_trait::Output; #[inline] fn index(&self, idx: #index_type) -> &Self::Output { #casted_trait::index(&#member, idx) } } }) } derive_more-0.99.18/src/index_mut.rs000064400000000000000000000030211046102023000154410ustar 00000000000000use crate::utils::{add_where_clauses_for_new_ident, SingleFieldData, State}; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{parse::Result, DeriveInput, Ident}; /// Provides the hook to expand `#[derive(IndexMut)]` into an implementation of `IndexMut` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let index_type = &Ident::new("__IdxT", Span::call_site()); let mut state = State::with_field_ignore( input, trait_name, quote!(::core::ops), String::from("index_mut"), )?; state.add_trait_path_type_param(quote!(#index_type)); let SingleFieldData { field, field_type, input_type, trait_path_with_params, casted_trait, member, .. } = state.assert_single_enabled_field(); let type_where_clauses = quote! { where #field_type: #trait_path_with_params }; let new_generics = add_where_clauses_for_new_ident( &input.generics, &[field], index_type, type_where_clauses, true, ); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let (_, ty_generics, _) = input.generics.split_for_impl(); Ok(quote! { impl#impl_generics #trait_path_with_params for #input_type#ty_generics #where_clause { #[inline] fn index_mut(&mut self, idx: #index_type) -> &mut Self::Output { #casted_trait::index_mut(&mut #member, idx) } } }) } derive_more-0.99.18/src/into.rs000064400000000000000000000057731046102023000144360ustar 00000000000000use std::iter; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{parse::Result, DeriveInput}; use crate::utils::{add_extra_generic_param, AttrParams, MultiFieldData, State}; /// Provides the hook to expand `#[derive(Into)]` into an implementation of `Into` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_attr_params( input, trait_name, quote!(::core::convert), trait_name.to_lowercase(), AttrParams { enum_: vec!["ignore", "owned", "ref", "ref_mut"], variant: vec!["ignore", "owned", "ref", "ref_mut"], struct_: vec!["ignore", "owned", "ref", "ref_mut", "types"], field: vec!["ignore"], }, )?; let MultiFieldData { variant_info, field_types, field_idents, input_type, .. } = state.enabled_fields_data(); let mut tokens = TokenStream::new(); for ref_type in variant_info.ref_types() { let reference = ref_type.reference(); let lifetime = ref_type.lifetime(); let reference_with_lifetime = ref_type.reference_with_lifetime(); let generics_impl; let (_, ty_generics, where_clause) = input.generics.split_for_impl(); let (impl_generics, _, _) = if ref_type.is_ref() { generics_impl = add_extra_generic_param(&input.generics, lifetime); generics_impl.split_for_impl() } else { input.generics.split_for_impl() }; let additional_types = variant_info.additional_types(ref_type); for explicit_type in iter::once(None).chain(additional_types.iter().map(Some)) { let into_types: Vec<_> = field_types .iter() .map(|field_type| { // No, `.unwrap_or()` won't work here, because we use different types. if let Some(type_) = explicit_type { quote! { #reference_with_lifetime #type_ } } else { quote! { #reference_with_lifetime #field_type } } }) .collect(); let initializers = field_idents.iter().map(|field_ident| { if let Some(type_) = explicit_type { quote! { <#reference #type_>::from(#reference original.#field_ident) } } else { quote! { #reference original.#field_ident } } }); (quote! { #[automatically_derived] impl#impl_generics ::core::convert::From<#reference_with_lifetime #input_type#ty_generics> for (#(#into_types),*) #where_clause { #[inline] fn from(original: #reference_with_lifetime #input_type#ty_generics) -> Self { (#(#initializers),*) } } }).to_tokens(&mut tokens); } } Ok(tokens) } derive_more-0.99.18/src/into_iterator.rs000064400000000000000000000041271046102023000163370ustar 00000000000000use crate::utils::{ add_extra_generic_param, add_extra_ty_param_bound_ref, SingleFieldData, State, }; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{parse::Result, DeriveInput}; /// Provides the hook to expand `#[derive(IntoIterator)]` into an implementation of `IntoIterator` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_refs( input, trait_name, quote!(::core::iter), String::from("into_iterator"), )?; let SingleFieldData { input_type, info, field_type, member, trait_path, .. } = state.assert_single_enabled_field(); let mut tokens = TokenStream::new(); for ref_type in info.ref_types() { let reference = ref_type.reference(); let lifetime = ref_type.lifetime(); let reference_with_lifetime = ref_type.reference_with_lifetime(); let generics_impl; let generics = add_extra_ty_param_bound_ref(&input.generics, trait_path, ref_type); let (_, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, _, _) = if ref_type.is_ref() { generics_impl = add_extra_generic_param(&generics, lifetime.clone()); generics_impl.split_for_impl() } else { generics.split_for_impl() }; // let generics = add_extra_ty_param_bound(&input.generics, trait_path); let casted_trait = "e!(<#reference_with_lifetime #field_type as #trait_path>); let into_iterator = quote! { impl#impl_generics #trait_path for #reference_with_lifetime #input_type#ty_generics #where_clause { type Item = #casted_trait::Item; type IntoIter = #casted_trait::IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { #casted_trait::into_iter(#reference #member) } } }; into_iterator.to_tokens(&mut tokens); } Ok(tokens) } derive_more-0.99.18/src/is_variant.rs000064400000000000000000000035031046102023000156110ustar 00000000000000use crate::utils::{AttrParams, DeriveType, State}; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{DeriveInput, Fields, Ident, Result}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_attr_params( input, trait_name, quote!(), String::from("is_variant"), AttrParams { enum_: vec!["ignore"], variant: vec!["ignore"], struct_: vec!["ignore"], field: vec!["ignore"], }, )?; assert!( state.derive_type == DeriveType::Enum, "IsVariant can only be derived for enums" ); let enum_name = &input.ident; let (imp_generics, type_generics, where_clause) = input.generics.split_for_impl(); let mut funcs = vec![]; for variant_state in state.enabled_variant_data().variant_states { let variant = variant_state.variant.unwrap(); let fn_name = Ident::new( &format_ident!("is_{}", variant.ident) .to_string() .to_case(Case::Snake), variant.ident.span(), ); let variant_ident = &variant.ident; let data_pattern = match variant.fields { Fields::Named(_) => quote! { {..} }, Fields::Unnamed(_) => quote! { (..) }, Fields::Unit => quote! {}, }; let func = quote! { pub fn #fn_name(&self) -> bool { match self { #enum_name ::#variant_ident #data_pattern => true, _ => false } } }; funcs.push(func); } let imp = quote! { impl #imp_generics #enum_name #type_generics #where_clause{ #(#funcs)* } }; Ok(imp) } derive_more-0.99.18/src/lib.rs000064400000000000000000000326211046102023000142230ustar 00000000000000//! # `derive_more` //! //! [![Build Status](https://github.com/JelteF/derive_more/workflows/CI/badge.svg)](https://github.com/JelteF/derive_more/actions) //! [![Latest Version](https://img.shields.io/crates/v/derive_more.svg)](https://crates.io/crates/derive_more) //! [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://jeltef.github.io/derive_more/derive_more/) //! [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/JelteF/derive_more/master/LICENSE) //! [![Rust 1.65+](https://img.shields.io/badge/rustc-1.65+-lightgray.svg)](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html) //! //! Rust has lots of builtin traits that are implemented for its basic types, such //! as `Add`, `Not`, `From` or `Display`. //! However, when wrapping these types inside your own structs or enums you lose the //! implementations of these traits and are required to recreate them. //! This is especially annoying when your own structures are very simple, such as //! when using the commonly advised newtype pattern (e.g. `MyInt(i32)`). //! //! This library tries to remove these annoyances and the corresponding boilerplate code. //! It does this by allowing you to derive lots of commonly used traits for both structs and enums. //! //! ## Example code //! //! By using this library the following code just works: //! //! ```rust //! extern crate derive_more; //! use derive_more::{Add, Display, From, Into}; //! //! #[derive(PartialEq, From, Add)] //! struct MyInt(i32); //! //! #[derive(PartialEq, From, Into)] //! struct Point2D { //! x: i32, //! y: i32, //! } //! //! #[derive(PartialEq, From, Add, Display)] //! enum MyEnum { //! #[display(fmt = "int: {}", _0)] //! Int(i32), //! Uint(u32), //! #[display(fmt = "nothing")] //! Nothing, //! } //! //! assert!(MyInt(11) == MyInt(5) + 6.into()); //! assert!((5, 6) == Point2D { x: 5, y: 6 }.into()); //! assert!(MyEnum::Int(15) == (MyEnum::Int(8) + 7.into()).unwrap()); //! assert!(MyEnum::Int(15).to_string() == "int: 15"); //! assert!(MyEnum::Uint(42).to_string() == "42"); //! assert!(MyEnum::Nothing.to_string() == "nothing"); //! ``` //! //! ## The derivable traits //! //! Below are all the traits that you can derive using this library. //! Some trait derivations are so similar that the further documentation will only show a single one //! of them. //! You can recognize these by the "-like" suffix in their name. //! The trait name before that will be the only one that is used throughout the further //! documentation. //! //! It is important to understand what code gets generated when using one of the //! derives from this crate. //! That is why the links below explain what code gets generated for a trait for //! each group from before. //! //! You can use the [`cargo-expand`] utility to see the exact code that is generated //! for your specific type. //! This will show you your code with all macros and derives expanded. //! //! **NOTE**: You still have to derive each trait separately. So `#[derive(Mul)]` doesn't //! automatically derive `Div` as well. To derive both you should do `#[derive(Mul, Div)]` //! //! ### Conversion traits //! //! These are traits that are used to convert automatically between types. //! //! 1. [`From`] //! 2. [`Into`] //! 3. [`FromStr`] //! 4. [`TryInto`] //! 5. [`IntoIterator`] //! 6. [`AsRef`] //! 7. [`AsMut`] //! //! ### Formatting traits //! //! These traits are used for converting a struct to a string in different ways. //! //! 1. [`Display`-like], contains `Display`, `Binary`, `Octal`, `LowerHex`, //! `UpperHex`, `LowerExp`, `UpperExp`, `Pointer` //! //! ### Error-handling traits //! These traits are used to define error-types. //! //! 1. [`Error`] //! //! ### Operators //! //! These are traits that can be used for operator overloading. //! //! 1. [`Index`] //! 2. [`Deref`] //! 3. [`Not`-like], contains `Not` and `Neg` //! 4. [`Add`-like], contains `Add`, `Sub`, `BitAnd`, `BitOr`, `BitXor` //! 5. [`Mul`-like], contains `Mul`, `Div`, `Rem`, `Shr` and `Shl` //! 3. [`Sum`-like], contains `Sum` and `Product` //! 6. [`IndexMut`] //! 7. [`DerefMut`] //! 8. [`AddAssign`-like], contains `AddAssign`, `SubAssign`, `BitAndAssign`, //! `BitOrAssign` and `BitXorAssign` //! 9. [`MulAssign`-like], contains `MulAssign`, `DivAssign`, `RemAssign`, //! `ShrAssign` and `ShlAssign` //! //! ### Static methods //! //! These don't derive traits, but derive static methods instead. //! //! 1. [`Constructor`], this derives a `new` method that can be used as a constructor. //! This is very basic if you need more customization for your constructor, check //! out the [`derive-new`] crate. //! 2. [`IsVariant`], for each variant `foo` of an enum type, derives a `is_foo` method. //! 3. [`Unwrap`], for each variant `foo` of an enum type, derives an `unwrap_foo` method. //! //! ## Generated code //! //! ## Installation //! //! This library requires Rust 1.65 or higher and it supports `no_std` out of the box. //! Then add the following to `Cargo.toml`: //! //! ```toml //! [dependencies] //! derive_more = "0.99.0" //! # You can specifiy the types of derives that you need for less time spent //! # compiling. For the full list of features see this crate its Cargo.toml. //! default-features = false //! features = ["from", "add", "iterator"] //! ``` //! //! And this to the top of your Rust file for Rust 2018: //! //! ```rust //! extern crate derive_more; //! // use the derives that you want in the file //! use derive_more::{Add, Display, From}; //! ``` //! If you're still using Rust 2015 you should add this instead: //! ```rust //! extern crate core; //! #[macro_use] //! extern crate derive_more; //! # fn main(){} //! ``` //! //! [`cargo-expand`]: https://github.com/dtolnay/cargo-expand //! [`derive-new`]: https://github.com/nrc/derive-new //! //! [`From`]: https://jeltef.github.io/derive_more/derive_more/from.html //! [`Into`]: https://jeltef.github.io/derive_more/derive_more/into.html //! [`FromStr`]: https://jeltef.github.io/derive_more/derive_more/from_str.html //! [`TryInto`]: https://jeltef.github.io/derive_more/derive_more/try_into.html //! [`IntoIterator`]: https://jeltef.github.io/derive_more/derive_more/into_iterator.html //! [`AsRef`]: https://jeltef.github.io/derive_more/derive_more/as_ref.html //! [`AsMut`]: https://jeltef.github.io/derive_more/derive_more/as_mut.html //! //! [`Display`-like]: https://jeltef.github.io/derive_more/derive_more/display.html //! //! [`Error`]: https://jeltef.github.io/derive_more/derive_more/error.html //! //! [`Index`]: https://jeltef.github.io/derive_more/derive_more/index_op.html //! [`Deref`]: https://jeltef.github.io/derive_more/derive_more/deref.html //! [`Not`-like]: https://jeltef.github.io/derive_more/derive_more/not.html //! [`Add`-like]: https://jeltef.github.io/derive_more/derive_more/add.html //! [`Mul`-like]: https://jeltef.github.io/derive_more/derive_more/mul.html //! [`Sum`-like]: https://jeltef.github.io/derive_more/derive_more/sum.html //! [`IndexMut`]: https://jeltef.github.io/derive_more/derive_more/index_mut.html //! [`DerefMut`]: https://jeltef.github.io/derive_more/derive_more/deref_mut.html //! [`AddAssign`-like]: https://jeltef.github.io/derive_more/derive_more/add_assign.html //! [`MulAssign`-like]: https://jeltef.github.io/derive_more/derive_more/mul_assign.html //! //! [`Constructor`]: https://jeltef.github.io/derive_more/derive_more/constructor.html //! [`IsVariant`]: https://jeltef.github.io/derive_more/derive_more/is_variant.html //! [`Unwrap`]: https://jeltef.github.io/derive_more/derive_more/unwrap.html #![recursion_limit = "128"] extern crate proc_macro; use proc_macro::TokenStream; use syn::parse::Error as ParseError; mod syn_compat; mod utils; #[cfg(any(feature = "add_assign", feature = "mul_assign"))] mod add_assign_like; #[cfg(any( feature = "add", feature = "add_assign", feature = "mul", feature = "mul_assign", ))] mod add_helpers; #[cfg(any(feature = "add", feature = "mul"))] mod add_like; #[cfg(feature = "as_mut")] mod as_mut; #[cfg(feature = "as_ref")] mod as_ref; #[cfg(feature = "constructor")] mod constructor; #[cfg(feature = "deref")] mod deref; #[cfg(feature = "deref_mut")] mod deref_mut; #[cfg(feature = "display")] mod display; #[cfg(feature = "error")] mod error; #[cfg(feature = "from")] mod from; #[cfg(feature = "from_str")] mod from_str; #[cfg(feature = "index")] mod index; #[cfg(feature = "index_mut")] mod index_mut; #[cfg(feature = "into")] mod into; #[cfg(feature = "into_iterator")] mod into_iterator; #[cfg(feature = "is_variant")] mod is_variant; #[cfg(feature = "mul_assign")] mod mul_assign_like; #[cfg(any(feature = "mul", feature = "mul_assign"))] mod mul_helpers; #[cfg(feature = "mul")] mod mul_like; #[cfg(feature = "not")] mod not_like; #[cfg(feature = "display")] #[allow(ellipsis_inclusive_range_patterns)] #[allow(clippy::all)] mod parsing; #[cfg(feature = "sum")] mod sum_like; #[cfg(feature = "try_into")] mod try_into; #[cfg(feature = "unwrap")] mod unwrap; // This trait describes the possible return types of // the derives. A derive can generally be infallible and // return a TokenStream, or it can be fallible and return // a Result. trait Output { fn process(self) -> TokenStream; } impl Output for proc_macro2::TokenStream { fn process(self) -> TokenStream { self.into() } } impl Output for Result { fn process(self) -> TokenStream { match self { Ok(ts) => ts.into(), Err(e) => e.to_compile_error().into(), } } } macro_rules! create_derive( ($feature:literal, $mod_:ident, $trait_:ident, $fn_name: ident $(,$attribute:ident)* $(,)?) => { #[cfg(feature = $feature)] #[proc_macro_derive($trait_, attributes($($attribute),*))] #[doc(hidden)] pub fn $fn_name(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); Output::process($mod_::expand(&ast, stringify!($trait_))) } } ); create_derive!("from", from, From, from_derive, from); create_derive!("into", into, Into, into_derive, into); create_derive!("constructor", constructor, Constructor, constructor_derive); create_derive!("not", not_like, Not, not_derive); create_derive!("not", not_like, Neg, neg_derive); create_derive!("add", add_like, Add, add_derive); create_derive!("add", add_like, Sub, sub_derive); create_derive!("add", add_like, BitAnd, bit_and_derive); create_derive!("add", add_like, BitOr, bit_or_derive); create_derive!("add", add_like, BitXor, bit_xor_derive); create_derive!("mul", mul_like, Mul, mul_derive, mul); create_derive!("mul", mul_like, Div, div_derive, div); create_derive!("mul", mul_like, Rem, rem_derive, rem); create_derive!("mul", mul_like, Shr, shr_derive, shr); create_derive!("mul", mul_like, Shl, shl_derive, shl); create_derive!("add_assign", add_assign_like, AddAssign, add_assign_derive,); create_derive!("add_assign", add_assign_like, SubAssign, sub_assign_derive,); create_derive!( "add_assign", add_assign_like, BitAndAssign, bit_and_assign_derive, ); create_derive!( "add_assign", add_assign_like, BitOrAssign, bit_or_assign_derive, ); create_derive!( "add_assign", add_assign_like, BitXorAssign, bit_xor_assign_derive, ); create_derive!( "mul_assign", mul_assign_like, MulAssign, mul_assign_derive, mul_assign, ); create_derive!( "mul_assign", mul_assign_like, DivAssign, div_assign_derive, div_assign, ); create_derive!( "mul_assign", mul_assign_like, RemAssign, rem_assign_derive, rem_assign, ); create_derive!( "mul_assign", mul_assign_like, ShrAssign, shr_assign_derive, shr_assign, ); create_derive!( "mul_assign", mul_assign_like, ShlAssign, shl_assign_derive, shl_assign, ); create_derive!("sum", sum_like, Sum, sum_derive); create_derive!("sum", sum_like, Product, product_derive); create_derive!("error", error, Error, error_derive, error); create_derive!("from_str", from_str, FromStr, from_str_derive); create_derive!("display", display, Display, display_derive, display); create_derive!("display", display, Binary, binary_derive, binary); create_derive!("display", display, Octal, octal_derive, octal); create_derive!("display", display, LowerHex, lower_hex_derive, lower_hex); create_derive!("display", display, UpperHex, upper_hex_derive, upper_hex); create_derive!("display", display, LowerExp, lower_exp_derive, lower_exp); create_derive!("display", display, UpperExp, upper_exp_derive, upper_exp); create_derive!("display", display, Pointer, pointer_derive, pointer); create_derive!("display", display, DebugCustom, debug_custom_derive, debug); create_derive!("index", index, Index, index_derive, index); create_derive!( "index_mut", index_mut, IndexMut, index_mut_derive, index_mut, ); create_derive!( "into_iterator", into_iterator, IntoIterator, into_iterator_derive, into_iterator, ); create_derive!("try_into", try_into, TryInto, try_into_derive, try_into); create_derive!("deref", deref, Deref, deref_derive, deref); create_derive!( "deref_mut", deref_mut, DerefMut, deref_mut_derive, deref_mut, ); create_derive!("as_ref", as_ref, AsRef, as_ref_derive, as_ref); create_derive!("as_mut", as_mut, AsMut, as_mut_derive, as_mut); create_derive!( "is_variant", is_variant, IsVariant, is_variant_derive, is_variant ); create_derive!("unwrap", unwrap, Unwrap, unwrap_derive, unwrap); derive_more-0.99.18/src/mul_assign_like.rs000064400000000000000000000036021046102023000166170ustar 00000000000000use crate::add_assign_like; use crate::mul_helpers::generics_and_exprs; use crate::utils::{AttrParams, MultiFieldData, RefType, State}; use proc_macro2::{Span, TokenStream}; use quote::quote; use std::collections::HashSet; use std::iter; use syn::{DeriveInput, Ident, Result}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let method_name = trait_name .to_lowercase() .trim_end_matches("assign") .to_string() + "_assign"; let mut state = State::with_attr_params( input, trait_name, quote!(::core::ops), method_name, AttrParams::struct_(vec!["forward"]), )?; if state.default_info.forward { return Ok(add_assign_like::expand(input, trait_name)); } let scalar_ident = &Ident::new("__RhsT", Span::call_site()); state.add_trait_path_type_param(quote!(#scalar_ident)); let multi_field_data = state.enabled_fields_data(); let MultiFieldData { input_type, field_types, ty_generics, trait_path, trait_path_with_params, method_ident, .. } = multi_field_data.clone(); let tys = field_types.iter().collect::>(); let tys = tys.iter(); let trait_path_iter = iter::repeat(trait_path_with_params); let type_where_clauses = quote! { where #(#tys: #trait_path_iter),* }; let (generics, exprs) = generics_and_exprs( multi_field_data.clone(), scalar_ident, type_where_clauses, RefType::Mut, ); let (impl_generics, _, where_clause) = generics.split_for_impl(); Ok(quote!( impl#impl_generics #trait_path<#scalar_ident> for #input_type#ty_generics #where_clause{ #[inline] fn #method_ident(&mut self, rhs: #scalar_ident) { #(#exprs; )* } } )) } derive_more-0.99.18/src/mul_helpers.rs000064400000000000000000000017051046102023000157730ustar 00000000000000use crate::utils::{add_where_clauses_for_new_ident, MultiFieldData, RefType}; use proc_macro2::TokenStream; use quote::quote; use syn::{Generics, Ident}; pub fn generics_and_exprs( multi_field_data: MultiFieldData, scalar_ident: &Ident, type_where_clauses: TokenStream, ref_type: RefType, ) -> (Generics, Vec) { let MultiFieldData { fields, casted_traits, members, method_ident, .. } = multi_field_data; let reference = ref_type.reference(); let exprs: Vec<_> = casted_traits .iter() .zip(members) .map( |(casted_trait, member)| quote!(#casted_trait::#method_ident(#reference #member, rhs)), ) .collect(); let new_generics = add_where_clauses_for_new_ident( &multi_field_data.state.input.generics, &fields, scalar_ident, type_where_clauses, true, ); (new_generics, exprs) } derive_more-0.99.18/src/mul_like.rs000064400000000000000000000036551046102023000152630ustar 00000000000000use crate::add_like; use crate::mul_helpers::generics_and_exprs; use crate::utils::{AttrParams, MultiFieldData, RefType, State}; use proc_macro2::{Span, TokenStream}; use quote::quote; use std::collections::HashSet; use std::iter; use syn::{DeriveInput, Ident, Result}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let mut state = State::with_attr_params( input, trait_name, quote!(::core::ops), trait_name.to_lowercase(), AttrParams::struct_(vec!["forward"]), )?; if state.default_info.forward { return Ok(add_like::expand(input, trait_name)); } let scalar_ident = &Ident::new("__RhsT", Span::call_site()); state.add_trait_path_type_param(quote!(#scalar_ident)); let multi_field_data = state.enabled_fields_data(); let MultiFieldData { input_type, field_types, ty_generics, trait_path, trait_path_with_params, method_ident, .. } = multi_field_data.clone(); let tys = field_types.iter().collect::>(); let tys = tys.iter(); let scalar_iter = iter::repeat(scalar_ident); let trait_path_iter = iter::repeat(trait_path); let type_where_clauses = quote! { where #(#tys: #trait_path_iter<#scalar_iter, Output=#tys>),* }; let (generics, initializers) = generics_and_exprs( multi_field_data.clone(), scalar_ident, type_where_clauses, RefType::No, ); let body = multi_field_data.initializer(&initializers); let (impl_generics, _, where_clause) = generics.split_for_impl(); Ok(quote!( impl#impl_generics #trait_path_with_params for #input_type#ty_generics #where_clause { type Output = #input_type#ty_generics; #[inline] fn #method_ident(self, rhs: #scalar_ident) -> #input_type#ty_generics { #body } } )) } derive_more-0.99.18/src/not_like.rs000064400000000000000000000133001046102023000152520ustar 00000000000000use crate::utils::{ add_extra_type_param_bound_op_output, named_to_vec, unnamed_to_vec, }; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use std::iter; use syn::{Data, DataEnum, DeriveInput, Field, Fields, Ident, Index}; pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let trait_ident = Ident::new(trait_name, Span::call_site()); let method_name = trait_name.to_lowercase(); let method_ident = &Ident::new(&method_name, Span::call_site()); let input_type = &input.ident; let generics = add_extra_type_param_bound_op_output(&input.generics, &trait_ident); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (output_type, block) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => ( quote!(#input_type#ty_generics), tuple_content(input_type, &unnamed_to_vec(fields), method_ident), ), Fields::Named(ref fields) => ( quote!(#input_type#ty_generics), struct_content(input_type, &named_to_vec(fields), method_ident), ), _ => panic!("Unit structs cannot use derive({})", trait_name), }, Data::Enum(ref data_enum) => { enum_output_type_and_content(input, data_enum, method_ident) } _ => panic!("Only structs and enums can use derive({})", trait_name), }; quote!( impl#impl_generics ::core::ops::#trait_ident for #input_type#ty_generics #where_clause { type Output = #output_type; #[inline] fn #method_ident(self) -> #output_type { #block } } ) } fn tuple_content( input_type: &T, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { let mut exprs = vec![]; for i in 0..fields.len() { let i = Index::from(i); // generates `self.0.add()` let expr = quote!(self.#i.#method_ident()); exprs.push(expr); } quote!(#input_type(#(#exprs),*)) } fn struct_content( input_type: &Ident, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { let mut exprs = vec![]; for field in fields { // It's safe to unwrap because struct fields always have an identifier let field_id = field.ident.as_ref(); // generates `x: self.x.not()` let expr = quote!(#field_id: self.#field_id.#method_ident()); exprs.push(expr) } quote!(#input_type{#(#exprs),*}) } fn enum_output_type_and_content( input: &DeriveInput, data_enum: &DataEnum, method_ident: &Ident, ) -> (TokenStream, TokenStream) { let input_type = &input.ident; let (_, ty_generics, _) = input.generics.split_for_impl(); let mut matches = vec![]; let mut method_iter = iter::repeat(method_ident); // If the enum contains unit types that means it can error. let has_unit_type = data_enum.variants.iter().any(|v| v.fields == Fields::Unit); for variant in &data_enum.variants { let subtype = &variant.ident; let subtype = quote!(#input_type::#subtype); match variant.fields { Fields::Unnamed(ref fields) => { // The patern that is outputted should look like this: // (Subtype(vars)) => Ok(TypePath(exprs)) let size = unnamed_to_vec(fields).len(); let vars: &Vec<_> = &(0..size) .map(|i| Ident::new(&format!("__{}", i), Span::call_site())) .collect(); let method_iter = method_iter.by_ref(); let mut body = quote!(#subtype(#(#vars.#method_iter()),*)); if has_unit_type { body = quote!(::core::result::Result::Ok(#body)) } let matcher = quote! { #subtype(#(#vars),*) => { #body } }; matches.push(matcher); } Fields::Named(ref fields) => { // The patern that is outputted should look like this: // (Subtype{a: __l_a, ...} => { // Ok(Subtype{a: __l_a.neg(__r_a), ...}) // } let field_vec = named_to_vec(fields); let size = field_vec.len(); let field_names: &Vec<_> = &field_vec .iter() .map(|f| f.ident.as_ref().unwrap()) .collect(); let vars: &Vec<_> = &(0..size) .map(|i| Ident::new(&format!("__{}", i), Span::call_site())) .collect(); let method_iter = method_iter.by_ref(); let mut body = quote!(#subtype{#(#field_names: #vars.#method_iter()),*}); if has_unit_type { body = quote!(::core::result::Result::Ok(#body)) } let matcher = quote! { #subtype{#(#field_names: #vars),*} => { #body } }; matches.push(matcher); } Fields::Unit => { let message = format!("Cannot {}() unit variants", method_ident); matches.push(quote!(#subtype => ::core::result::Result::Err(#message))); } } } let body = quote!( match self { #(#matches),* } ); let output_type = if has_unit_type { quote!(::core::result::Result<#input_type#ty_generics, &'static str>) } else { quote!(#input_type#ty_generics) }; (output_type, body) } derive_more-0.99.18/src/parsing.rs000064400000000000000000001267511046102023000151300ustar 00000000000000use self::RuleResult::{Failed, Matched}; fn escape_default(s: &str) -> String { s.chars().flat_map(|c| c.escape_default()).collect() } fn char_range_at(s: &str, pos: usize) -> (char, usize) { let c = &s[pos..].chars().next().unwrap(); let next_pos = pos + c.len_utf8(); (*c, next_pos) } #[derive(Clone)] enum RuleResult { Matched(usize, T), Failed, } #[derive(PartialEq, Eq, Debug, Clone)] pub struct ParseError { pub line: usize, pub column: usize, pub offset: usize, pub expected: ::std::collections::HashSet<&'static str>, } pub type ParseResult = Result; impl ::std::fmt::Display for ParseError { fn fmt( &self, fmt: &mut ::std::fmt::Formatter, ) -> ::std::result::Result<(), ::std::fmt::Error> { write!(fmt, "error at {}:{}: expected ", self.line, self.column)?; if self.expected.len() == 0 { write!(fmt, "EOF")?; } else if self.expected.len() == 1 { write!( fmt, "`{}`", escape_default(self.expected.iter().next().unwrap()) )?; } else { let mut iter = self.expected.iter(); write!(fmt, "one of `{}`", escape_default(iter.next().unwrap()))?; for elem in iter { write!(fmt, ", `{}`", escape_default(elem))?; } } Ok(()) } } impl ::std::error::Error for ParseError { fn description(&self) -> &str { "parse error" } } fn slice_eq( input: &str, state: &mut ParseState, pos: usize, m: &'static str, ) -> RuleResult<()> { #![inline] #![allow(dead_code)] let l = m.len(); if input.len() >= pos + l && &input.as_bytes()[pos..pos + l] == m.as_bytes() { Matched(pos + l, ()) } else { state.mark_failure(pos, m) } } fn slice_eq_case_insensitive( input: &str, state: &mut ParseState, pos: usize, m: &'static str, ) -> RuleResult<()> { #![inline] #![allow(dead_code)] let mut used = 0usize; let mut input_iter = input[pos..].chars().flat_map(|x| x.to_uppercase()); for m_char_upper in m.chars().flat_map(|x| x.to_uppercase()) { used += m_char_upper.len_utf8(); let input_char_result = input_iter.next(); if input_char_result.is_none() || input_char_result.unwrap() != m_char_upper { return state.mark_failure(pos, m); } } Matched(pos + used, ()) } fn any_char(input: &str, state: &mut ParseState, pos: usize) -> RuleResult<()> { #![inline] #![allow(dead_code)] if input.len() > pos { let (_, next) = char_range_at(input, pos); Matched(next, ()) } else { state.mark_failure(pos, "") } } fn pos_to_line(input: &str, pos: usize) -> (usize, usize) { let before = &input[..pos]; let line = before.as_bytes().iter().filter(|&&c| c == b'\n').count() + 1; let col = before.chars().rev().take_while(|&c| c != '\n').count() + 1; (line, col) } impl<'input> ParseState<'input> { fn mark_failure(&mut self, pos: usize, expected: &'static str) -> RuleResult<()> { if self.suppress_fail == 0 { if pos > self.max_err_pos { self.max_err_pos = pos; self.expected.clear(); } if pos == self.max_err_pos { self.expected.insert(expected); } } Failed } } struct ParseState<'input> { max_err_pos: usize, suppress_fail: usize, expected: ::std::collections::HashSet<&'static str>, _phantom: ::std::marker::PhantomData<&'input ()>, } impl<'input> ParseState<'input> { fn new() -> ParseState<'input> { ParseState { max_err_pos: 0, suppress_fail: 0, expected: ::std::collections::HashSet::new(), _phantom: ::std::marker::PhantomData, } } } fn __parse_discard_doubles<'input>( __input: &'input str, __state: &mut ParseState<'input>, __pos: usize, ) -> RuleResult> { #![allow(non_snake_case, unused)] { let __seq_res = { let __choice_res = { let __seq_res = slice_eq(__input, __state, __pos, "{"); match __seq_res { Matched(__pos, _) => slice_eq(__input, __state, __pos, "{"), Failed => Failed, } }; match __choice_res { Matched(__pos, __value) => Matched(__pos, __value), Failed => { let __seq_res = slice_eq(__input, __state, __pos, "}"); match __seq_res { Matched(__pos, _) => slice_eq(__input, __state, __pos, "}"), Failed => Failed, } } } }; match __seq_res { Matched(__pos, _) => Matched(__pos, { None }), Failed => Failed, } } } fn __parse_placeholder_inner<'input>( __input: &'input str, __state: &mut ParseState<'input>, __pos: usize, ) -> RuleResult> { #![allow(non_snake_case, unused)] { let __seq_res = { let str_start = __pos; match { let __seq_res = if __input.len() > __pos { let (__ch, __next) = char_range_at(__input, __pos); match __ch { '{' => Matched(__next, ()), _ => __state.mark_failure(__pos, "[{]"), } } else { __state.mark_failure(__pos, "[{]") }; match __seq_res { Matched(__pos, _) => { let __seq_res = { let mut __repeat_pos = __pos; loop { let __pos = __repeat_pos; let __step_res = { let __seq_res = { __state.suppress_fail += 1; let __assert_res = if __input.len() > __pos { let (__ch, __next) = char_range_at(__input, __pos); match __ch { '{' | '}' => Matched(__next, ()), _ => { __state.mark_failure(__pos, "[{}]") } } } else { __state.mark_failure(__pos, "[{}]") }; __state.suppress_fail -= 1; match __assert_res { Failed => Matched(__pos, ()), Matched(..) => Failed, } }; match __seq_res { Matched(__pos, _) => { any_char(__input, __state, __pos) } Failed => Failed, } }; match __step_res { Matched(__newpos, __value) => { __repeat_pos = __newpos; } Failed => { break; } } } Matched(__repeat_pos, ()) }; match __seq_res { Matched(__pos, _) => { if __input.len() > __pos { let (__ch, __next) = char_range_at(__input, __pos); match __ch { '}' => Matched(__next, ()), _ => __state.mark_failure(__pos, "[}]"), } } else { __state.mark_failure(__pos, "[}]") } } Failed => Failed, } } Failed => Failed, } } { Matched(__newpos, _) => { Matched(__newpos, &__input[str_start..__newpos]) } Failed => Failed, } }; match __seq_res { Matched(__pos, n) => Matched(__pos, { Some(n) }), Failed => Failed, } } } fn __parse_discard_any<'input>( __input: &'input str, __state: &mut ParseState<'input>, __pos: usize, ) -> RuleResult> { #![allow(non_snake_case, unused)] { let __seq_res = any_char(__input, __state, __pos); match __seq_res { Matched(__pos, _) => Matched(__pos, { None }), Failed => Failed, } } } fn __parse_arg<'input>( __input: &'input str, __state: &mut ParseState<'input>, __pos: usize, ) -> RuleResult { #![allow(non_snake_case, unused)] { let __seq_res = { let str_start = __pos; match { let mut __repeat_pos = __pos; let mut __repeat_value = vec![]; loop { let __pos = __repeat_pos; let __step_res = if __input.len() > __pos { let (__ch, __next) = char_range_at(__input, __pos); match __ch { '0'...'9' => Matched(__next, ()), _ => __state.mark_failure(__pos, "[0-9]"), } } else { __state.mark_failure(__pos, "[0-9]") }; match __step_res { Matched(__newpos, __value) => { __repeat_pos = __newpos; __repeat_value.push(__value); } Failed => { break; } } } if __repeat_value.len() >= 1 { Matched(__repeat_pos, ()) } else { Failed } } { Matched(__newpos, _) => { Matched(__newpos, &__input[str_start..__newpos]) } Failed => Failed, } }; match __seq_res { Matched(__pos, n) => Matched(__pos, { n.parse().unwrap() }), Failed => Failed, } } } fn __parse_ty<'input>( __input: &'input str, __state: &mut ParseState<'input>, __pos: usize, ) -> RuleResult<&'input str> { #![allow(non_snake_case, unused)] { let __seq_res = { let str_start = __pos; match { let __choice_res = { let __choice_res = slice_eq(__input, __state, __pos, "x?"); match __choice_res { Matched(__pos, __value) => Matched(__pos, __value), Failed => slice_eq(__input, __state, __pos, "X?"), } }; match __choice_res { Matched(__pos, __value) => Matched(__pos, __value), Failed => { let __choice_res = slice_eq(__input, __state, __pos, "o"); match __choice_res { Matched(__pos, __value) => Matched(__pos, __value), Failed => { let __choice_res = slice_eq(__input, __state, __pos, "x"); match __choice_res { Matched(__pos, __value) => Matched(__pos, __value), Failed => { let __choice_res = slice_eq(__input, __state, __pos, "X"); match __choice_res { Matched(__pos, __value) => { Matched(__pos, __value) } Failed => { let __choice_res = slice_eq( __input, __state, __pos, "p", ); match __choice_res { Matched(__pos, __value) => { Matched(__pos, __value) } Failed => { let __choice_res = slice_eq( __input, __state, __pos, "b", ); match __choice_res { Matched(__pos, __value) => { Matched(__pos, __value) } Failed => { let __choice_res = slice_eq( __input, __state, __pos, "e", ); match __choice_res { Matched( __pos, __value, ) => Matched( __pos, __value, ), Failed => { let __choice_res = slice_eq( __input, __state, __pos, "E", ); match __choice_res { Matched ( __pos , __value ) => Matched ( __pos , __value ) , Failed => slice_eq ( __input , __state , __pos , "?" ) } } } } } } } } } } } } } } } } { Matched(__newpos, _) => { Matched(__newpos, &__input[str_start..__newpos]) } Failed => Failed, } }; match __seq_res { Matched(__pos, n) => Matched(__pos, { n }), Failed => Failed, } } } fn __parse_format_spec<'input>( __input: &'input str, __state: &mut ParseState<'input>, __pos: usize, ) -> RuleResult> { #![allow(non_snake_case, unused)] { let __seq_res = slice_eq(__input, __state, __pos, ":"); match __seq_res { Matched(__pos, _) => { let __seq_res = match { let __seq_res = match { let __seq_res = { __state.suppress_fail += 1; let __assert_res = if __input.len() > __pos { let (__ch, __next) = char_range_at(__input, __pos); match __ch { '<' | '^' | '>' => Matched(__next, ()), _ => __state.mark_failure(__pos, "[<^>]"), } } else { __state.mark_failure(__pos, "[<^>]") }; __state.suppress_fail -= 1; match __assert_res { Failed => Matched(__pos, ()), Matched(..) => Failed, } }; match __seq_res { Matched(__pos, _) => any_char(__input, __state, __pos), Failed => Failed, } } { Matched(__newpos, _) => Matched(__newpos, ()), Failed => Matched(__pos, ()), }; match __seq_res { Matched(__pos, _) => { if __input.len() > __pos { let (__ch, __next) = char_range_at(__input, __pos); match __ch { '<' | '^' | '>' => Matched(__next, ()), _ => __state.mark_failure(__pos, "[<^>]"), } } else { __state.mark_failure(__pos, "[<^>]") } } Failed => Failed, } } { Matched(__newpos, _) => Matched(__newpos, ()), Failed => Matched(__pos, ()), }; match __seq_res { Matched(__pos, _) => { let __seq_res = match { let __choice_res = slice_eq(__input, __state, __pos, "+"); match __choice_res { Matched(__pos, __value) => Matched(__pos, __value), Failed => slice_eq(__input, __state, __pos, "-"), } } { Matched(__newpos, _) => Matched(__newpos, ()), Failed => Matched(__pos, ()), }; match __seq_res { Matched(__pos, _) => { let __seq_res = match slice_eq(__input, __state, __pos, "#") { Matched(__newpos, _) => Matched(__newpos, ()), Failed => Matched(__pos, ()), }; match __seq_res { Matched(__pos, _) => { let __seq_res = match { let __choice_res = { let __seq_res = { let mut __repeat_pos = __pos; let mut __repeat_value = vec![]; loop { let __pos = __repeat_pos; let __step_res = if __input.len() > __pos { let (__ch, __next) = char_range_at( __input, __pos, ); match __ch { 'A'...'Z' | 'a'...'z' | '0'...'9' | '_' => Matched( __next, (), ), _ => __state .mark_failure( __pos, "[A-Za-z0-9_]", ), } } else { __state.mark_failure( __pos, "[A-Za-z0-9_]", ) }; match __step_res { Matched( __newpos, __value, ) => { __repeat_pos = __newpos; __repeat_value .push(__value); } Failed => { break; } } } if __repeat_value.len() >= 1 { Matched(__repeat_pos, ()) } else { Failed } }; match __seq_res { Matched(__pos, _) => slice_eq( __input, __state, __pos, "$", ), Failed => Failed, } }; match __choice_res { Matched(__pos, __value) => { Matched(__pos, __value) } Failed => { let mut __repeat_pos = __pos; let mut __repeat_value = vec![]; loop { let __pos = __repeat_pos; let __step_res = if __input .len() > __pos { let (__ch, __next) = char_range_at( __input, __pos, ); match __ch { '0'...'9' => { Matched(__next, ()) } _ => __state .mark_failure( __pos, "[0-9]", ), } } else { __state.mark_failure( __pos, "[0-9]", ) }; match __step_res { Matched( __newpos, __value, ) => { __repeat_pos = __newpos; __repeat_value .push(__value); } Failed => { break; } } } if __repeat_value.len() >= 1 { Matched(__repeat_pos, ()) } else { Failed } } } } { Matched(__newpos, _) => { Matched(__newpos, ()) } Failed => Matched(__pos, ()), }; match __seq_res { Matched(__pos, _) => { let __seq_res = match slice_eq( __input, __state, __pos, "0", ) { Matched(__newpos, _) => { Matched(__newpos, ()) } Failed => Matched(__pos, ()), }; match __seq_res { Matched(__pos, _) => { let __seq_res = match { let __seq_res = slice_eq( __input, __state, __pos, ".", ); match __seq_res { Matched(__pos, _) => { let __choice_res = { let __seq_res = { let mut __repeat_pos = __pos; let mut __repeat_value = vec![]; loop { let __pos = __repeat_pos ; let __step_res = if __input . len ( ) > __pos { let ( __ch , __next ) = char_range_at ( __input , __pos ) ; match __ch { 'A' ... 'Z' | 'a' ... 'z' | '0' ... '9' | '_' => Matched ( __next , ( ) ) , _ => __state . mark_failure ( __pos , "[A-Za-z0-9_]" ) , } } else { __state . mark_failure ( __pos , "[A-Za-z0-9_]" ) } ; match __step_res { Matched ( __newpos , __value ) => { __repeat_pos = __newpos ; __repeat_value . push ( __value ) ; } , Failed => { break ; } } } if __repeat_value . len ( ) >= 1 { Matched ( __repeat_pos , ( ) ) } else { Failed } }; match __seq_res { Matched ( __pos , _ ) => { slice_eq ( __input , __state , __pos , "$" ) } Failed => Failed , } }; match __choice_res { Matched( __pos, __value, ) => Matched( __pos, __value, ), Failed => { let __choice_res = { let mut __repeat_pos = __pos ; let mut __repeat_value = vec![]; loop { let __pos = __repeat_pos ; let __step_res = if __input . len ( ) > __pos { let ( __ch , __next ) = char_range_at ( __input , __pos ) ; match __ch { '0' ... '9' => Matched ( __next , ( ) ) , _ => __state . mark_failure ( __pos , "[0-9]" ) , } } else { __state . mark_failure ( __pos , "[0-9]" ) } ; match __step_res { Matched ( __newpos , __value ) => { __repeat_pos = __newpos ; __repeat_value . push ( __value ) ; } , Failed => { break ; } } } if __repeat_value . len ( ) >= 1 { Matched ( __repeat_pos , ( ) ) } else { Failed } }; match __choice_res { Matched ( __pos , __value ) => Matched ( __pos , __value ) , Failed => slice_eq ( __input , __state , __pos , "*" ) } } } } Failed => Failed, } } { Matched(__newpos, _) => { Matched(__newpos, ()) } Failed => { Matched(__pos, ()) } }; match __seq_res { Matched(__pos, _) => { let __seq_res = match __parse_ty( __input, __state, __pos, ) { Matched( __newpos, __value, ) => Matched( __newpos, Some( __value, ), ), Failed => { Matched( __pos, None, ) } }; match __seq_res { Matched( __pos, n, ) => Matched( __pos, { n }, ), Failed => Failed, } } Failed => Failed, } } Failed => Failed, } } Failed => Failed, } } Failed => Failed, } } Failed => Failed, } } Failed => Failed, } } Failed => Failed, } } } fn __parse_all_placeholders<'input>( __input: &'input str, __state: &mut ParseState<'input>, __pos: usize, ) -> RuleResult> { #![allow(non_snake_case, unused)] { let __seq_res = { let mut __repeat_pos = __pos; let mut __repeat_value = vec![]; loop { let __pos = __repeat_pos; let __step_res = { let __choice_res = __parse_discard_doubles(__input, __state, __pos); match __choice_res { Matched(__pos, __value) => Matched(__pos, __value), Failed => { let __choice_res = __parse_placeholder_inner(__input, __state, __pos); match __choice_res { Matched(__pos, __value) => Matched(__pos, __value), Failed => __parse_discard_any(__input, __state, __pos), } } } }; match __step_res { Matched(__newpos, __value) => { __repeat_pos = __newpos; __repeat_value.push(__value); } Failed => { break; } } } Matched(__repeat_pos, __repeat_value) }; match __seq_res { Matched(__pos, x) => { Matched(__pos, { x.into_iter().flat_map(|x| x).collect() }) } Failed => Failed, } } } fn __parse_format<'input>( __input: &'input str, __state: &mut ParseState<'input>, __pos: usize, ) -> RuleResult<(Option, Option<&'input str>)> { #![allow(non_snake_case, unused)] { let __seq_res = slice_eq(__input, __state, __pos, "{"); match __seq_res { Matched(__pos, _) => { let __seq_res = match __parse_arg(__input, __state, __pos) { Matched(__newpos, __value) => Matched(__newpos, Some(__value)), Failed => Matched(__pos, None), }; match __seq_res { Matched(__pos, n) => { let __seq_res = match __parse_format_spec(__input, __state, __pos) { Matched(__newpos, __value) => { Matched(__newpos, Some(__value)) } Failed => Matched(__pos, None), }; match __seq_res { Matched(__pos, o) => { let __seq_res = slice_eq(__input, __state, __pos, "}"); match __seq_res { Matched(__pos, _) => { Matched(__pos, { (n, o.and_then(|x| x)) }) } Failed => Failed, } } Failed => Failed, } } Failed => Failed, } } Failed => Failed, } } } pub fn all_placeholders<'input>(__input: &'input str) -> ParseResult> { #![allow(non_snake_case, unused)] let mut __state = ParseState::new(); match __parse_all_placeholders(__input, &mut __state, 0) { Matched(__pos, __value) => { if __pos == __input.len() { return Ok(__value); } } _ => {} } let (__line, __col) = pos_to_line(__input, __state.max_err_pos); Err(ParseError { line: __line, column: __col, offset: __state.max_err_pos, expected: __state.expected, }) } pub fn format<'input>( __input: &'input str, ) -> ParseResult<(Option, Option<&'input str>)> { #![allow(non_snake_case, unused)] let mut __state = ParseState::new(); match __parse_format(__input, &mut __state, 0) { Matched(__pos, __value) => { if __pos == __input.len() { return Ok(__value); } } _ => {} } let (__line, __col) = pos_to_line(__input, __state.max_err_pos); Err(ParseError { line: __line, column: __col, offset: __state.max_err_pos, expected: __state.expected, }) } derive_more-0.99.18/src/sum_like.rs000064400000000000000000000040311046102023000152570ustar 00000000000000use crate::utils::{ add_extra_ty_param_bound, add_extra_where_clauses, MultiFieldData, State, }; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{DeriveInput, Ident, Result}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::new( input, trait_name, quote!(::core::iter), trait_name.to_lowercase(), )?; let multi_field_data = state.enabled_fields_data(); let MultiFieldData { input_type, field_types, trait_path, method_ident, .. } = multi_field_data.clone(); let op_trait_name = if trait_name == "Sum" { "Add" } else { "Mul" }; let op_trait_ident = Ident::new(op_trait_name, Span::call_site()); let op_path = quote!(::core::ops::#op_trait_ident); let op_method_ident = Ident::new(&(op_trait_name.to_lowercase()), Span::call_site()); let has_type_params = input.generics.type_params().next().is_none(); let generics = if has_type_params { input.generics.clone() } else { let (_, ty_generics, _) = input.generics.split_for_impl(); let generics = add_extra_ty_param_bound(&input.generics, trait_path); let operator_where_clause = quote! { where #input_type#ty_generics: #op_path }; add_extra_where_clauses(&generics, operator_where_clause) }; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let initializers: Vec<_> = field_types .iter() .map(|field_type| quote!(#trait_path::#method_ident(::core::iter::empty::<#field_type>()))) .collect(); let identity = multi_field_data.initializer(&initializers); Ok(quote!( impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { #[inline] fn #method_ident>(iter: I) -> Self { iter.fold(#identity, #op_path::#op_method_ident) } } )) } derive_more-0.99.18/src/syn_compat.rs000064400000000000000000000123601046102023000156270ustar 00000000000000//! This module contains things adapted from syn 1.x //! to preserve compatibility. use quote::ToTokens; use syn::ext::IdentExt as _; use syn::parse::{Parse, ParseStream, Parser as _}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::Paren; use syn::{ parenthesized, token, Attribute, Ident, Lit, LitBool, MacroDelimiter, Meta, MetaNameValue, Path, PathSegment, Result, Token, }; pub(crate) trait AttributeExt { fn parse_meta(&self) -> Result; } impl AttributeExt for Attribute { fn parse_meta(&self) -> Result { parse_nested_meta(self.meta.clone()) } } /// [`Meta`] but more like the version from syn 1.x in two important ways: /// * The nested metas in a list are already parsed /// * Paths are allowed to contain keywords. #[derive(Clone)] pub(crate) enum ParsedMeta { Path(Path), List(ParsedMetaList), NameValue(MetaNameValue), } impl Parse for ParsedMeta { fn parse(input: ParseStream) -> Result { let path = input.call(parse_meta_path)?; parse_meta_after_path(path, input) } } impl ParsedMeta { pub(crate) fn path(&self) -> &Path { match self { ParsedMeta::Path(path) => path, ParsedMeta::List(meta) => &meta.path, ParsedMeta::NameValue(meta) => &meta.path, } } } impl ToTokens for ParsedMeta { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { match self { ParsedMeta::Path(p) => p.to_tokens(tokens), ParsedMeta::List(l) => l.to_tokens(tokens), ParsedMeta::NameValue(n) => n.to_tokens(tokens), } } } #[derive(Clone)] pub(crate) struct ParsedMetaList { pub path: Path, pub paren_token: Paren, pub nested: Punctuated, } impl ToTokens for ParsedMetaList { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { self.path.to_tokens(tokens); self.paren_token.surround(tokens, |tokens| { self.nested.to_tokens(tokens); }); } } #[derive(Clone)] pub(crate) enum NestedMeta { Meta(ParsedMeta), Lit(Lit), } impl Parse for NestedMeta { fn parse(input: ParseStream) -> Result { if input.peek(Lit) && !(input.peek(LitBool) && input.peek2(Token![=])) { input.parse().map(NestedMeta::Lit) } else if input.peek(Ident::peek_any) || input.peek(Token![::]) && input.peek3(Ident::peek_any) { input.parse().map(NestedMeta::Meta) } else { Err(input.error("expected identifier or literal")) } } } impl ToTokens for NestedMeta { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { match self { NestedMeta::Meta(meta) => meta.to_tokens(tokens), NestedMeta::Lit(lit) => lit.to_tokens(tokens), } } } fn parse_nested_meta(meta: Meta) -> Result { match meta { Meta::Path(path) => Ok(ParsedMeta::Path(path)), Meta::NameValue(name_value) => Ok(ParsedMeta::NameValue(name_value)), Meta::List(list) => { let MacroDelimiter::Paren(paren_token) = list.delimiter else { return Err(syn::Error::new( list.delimiter.span().span(), "Expected paren", )); }; Ok(ParsedMeta::List(ParsedMetaList { path: list.path, paren_token, nested: Punctuated::parse_terminated.parse2(list.tokens)?, })) } } } // Like Path::parse_mod_style but accepts keywords in the path. fn parse_meta_path(input: ParseStream) -> Result { Ok(Path { leading_colon: input.parse()?, segments: { let mut segments = Punctuated::new(); while input.peek(Ident::peek_any) { let ident = Ident::parse_any(input)?; segments.push_value(PathSegment::from(ident)); if !input.peek(Token![::]) { break; } let punct = input.parse()?; segments.push_punct(punct); } if segments.is_empty() { return Err(input.error("expected path")); } else if segments.trailing_punct() { return Err(input.error("expected path segment")); } segments }, }) } pub(crate) fn parse_meta_after_path( path: Path, input: ParseStream, ) -> Result { if input.peek(token::Paren) { parse_meta_list_after_path(path, input).map(ParsedMeta::List) } else if input.peek(Token![=]) { parse_meta_name_value_after_path(path, input).map(ParsedMeta::NameValue) } else { Ok(ParsedMeta::Path(path)) } } fn parse_meta_list_after_path( path: Path, input: ParseStream, ) -> Result { let content; Ok(ParsedMetaList { path, paren_token: parenthesized!(content in input), nested: content.parse_terminated(NestedMeta::parse, Token![,])?, }) } fn parse_meta_name_value_after_path( path: Path, input: ParseStream, ) -> Result { Ok(MetaNameValue { path, eq_token: input.parse()?, value: input.parse()?, }) } derive_more-0.99.18/src/try_into.rs000064400000000000000000000103231046102023000153170ustar 00000000000000use crate::utils::{ add_extra_generic_param, numbered_vars, AttrParams, DeriveType, MultiFieldData, State, }; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{DeriveInput, Result}; use crate::utils::HashMap; /// Provides the hook to expand `#[derive(TryInto)]` into an implementation of `TryInto` #[allow(clippy::cognitive_complexity)] pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_attr_params( input, trait_name, quote!(::core::convert), String::from("try_into"), AttrParams { enum_: vec!["ignore", "owned", "ref", "ref_mut"], variant: vec!["ignore", "owned", "ref", "ref_mut"], struct_: vec!["ignore", "owned", "ref", "ref_mut"], field: vec!["ignore"], }, )?; assert!( state.derive_type == DeriveType::Enum, "Only enums can derive TryInto" ); let mut variants_per_types = HashMap::default(); for variant_state in state.enabled_variant_data().variant_states { let multi_field_data = variant_state.enabled_fields_data(); let MultiFieldData { variant_info, field_types, .. } = multi_field_data.clone(); for ref_type in variant_info.ref_types() { variants_per_types .entry((ref_type, field_types.clone())) .or_insert_with(Vec::new) .push(multi_field_data.clone()); } } let mut tokens = TokenStream::new(); for ((ref_type, ref original_types), ref multi_field_datas) in variants_per_types { let input_type = &input.ident; let pattern_ref = ref_type.pattern_ref(); let lifetime = ref_type.lifetime(); let reference_with_lifetime = ref_type.reference_with_lifetime(); let mut matchers = vec![]; let vars = &numbered_vars(original_types.len(), ""); for multi_field_data in multi_field_datas { let patterns: Vec<_> = vars.iter().map(|var| quote!(#pattern_ref #var)).collect(); matchers.push( multi_field_data.matcher(&multi_field_data.field_indexes, &patterns), ); } let vars = if vars.len() == 1 { quote!(#(#vars)*) } else { quote!((#(#vars),*)) }; let output_type = if original_types.len() == 1 { format!("{}", quote!(#(#original_types)*)) } else { let types = original_types .iter() .map(|t| format!("{}", quote!(#t))) .collect::>(); format!("({})", types.join(", ")) }; let variant_names = multi_field_datas .iter() .map(|d| { format!( "{}", d.variant_name.expect("Somehow there was no variant name") ) }) .collect::>() .join(", "); let message = format!("Only {} can be converted to {}", variant_names, output_type); let generics_impl; let (_, ty_generics, where_clause) = input.generics.split_for_impl(); let (impl_generics, _, _) = if ref_type.is_ref() { generics_impl = add_extra_generic_param(&input.generics, lifetime.clone()); generics_impl.split_for_impl() } else { input.generics.split_for_impl() }; let try_from = quote! { impl#impl_generics ::core::convert::TryFrom<#reference_with_lifetime #input_type#ty_generics> for (#(#reference_with_lifetime #original_types),*) #where_clause { type Error = &'static str; #[allow(unused_variables)] #[inline] fn try_from(value: #reference_with_lifetime #input_type#ty_generics) -> ::core::result::Result { match value { #(#matchers)|* => ::core::result::Result::Ok(#vars), _ => ::core::result::Result::Err(#message), } } } }; try_from.to_tokens(&mut tokens) } Ok(tokens) } derive_more-0.99.18/src/unwrap.rs000064400000000000000000000062041046102023000147670ustar 00000000000000use crate::utils::{AttrParams, DeriveType, State}; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{DeriveInput, Fields, Ident, Result}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_attr_params( input, trait_name, quote!(), String::from("unwrap"), AttrParams { enum_: vec!["ignore"], variant: vec!["ignore"], struct_: vec!["ignore"], field: vec!["ignore"], }, )?; assert!( state.derive_type == DeriveType::Enum, "Unwrap can only be derived for enums" ); let enum_name = &input.ident; let (imp_generics, type_generics, where_clause) = input.generics.split_for_impl(); let mut funcs = vec![]; for variant_state in state.enabled_variant_data().variant_states { let variant = variant_state.variant.unwrap(); let fn_name = Ident::new( &format_ident!("unwrap_{}", variant.ident) .to_string() .to_case(Case::Snake), variant.ident.span(), ); let variant_ident = &variant.ident; let (data_pattern, ret_value, ret_type) = match variant.fields { Fields::Named(_) => panic!("cannot unwrap anonymous records"), Fields::Unnamed(ref fields) => { let data_pattern = (0..fields.unnamed.len()).fold(vec![], |mut a, n| { a.push(format_ident!("field_{}", n)); a }); let ret_type = &fields.unnamed; ( quote! { (#(#data_pattern),*) }, quote! { (#(#data_pattern),*) }, quote! { (#ret_type) }, ) } Fields::Unit => (quote! {}, quote! { () }, quote! { () }), }; let other_arms = state.variant_states.iter().map(|variant| { variant.variant.unwrap() }).filter(|variant| { &variant.ident != variant_ident }).map(|variant| { let data_pattern = match variant.fields { Fields::Named(_) => quote! { {..} }, Fields::Unnamed(_) => quote! { (..) }, Fields::Unit => quote! {}, }; let variant_ident = &variant.ident; quote! { #enum_name :: #variant_ident #data_pattern => panic!(concat!("called `", stringify!(#enum_name), "::", stringify!(#fn_name), "()` on a `", stringify!(#variant_ident), "` value")) } }); let func = quote! { #[track_caller] pub fn #fn_name(self) -> #ret_type { match self { #enum_name ::#variant_ident #data_pattern => #ret_value, #(#other_arms),* } } }; funcs.push(func); } let imp = quote! { impl #imp_generics #enum_name #type_generics #where_clause{ #(#funcs)* } }; Ok(imp) } derive_more-0.99.18/src/utils.rs000064400000000000000000001156531046102023000146240ustar 00000000000000#![cfg_attr(not(feature = "default"), allow(dead_code), allow(unused_mut))] use crate::syn_compat::{AttributeExt as _, NestedMeta, ParsedMeta}; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use syn::{ parse_quote, punctuated::Punctuated, spanned::Spanned, Attribute, Data, DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, GenericParam, Generics, Ident, ImplGenerics, Index, Result, Token, Type, TypeGenerics, TypeParamBound, Variant, WhereClause, }; #[derive(Clone, Copy, Default)] pub struct DeterministicState; impl std::hash::BuildHasher for DeterministicState { type Hasher = std::collections::hash_map::DefaultHasher; fn build_hasher(&self) -> Self::Hasher { Self::Hasher::default() } } pub type HashMap = std::collections::HashMap; pub type HashSet = std::collections::HashSet; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum RefType { No, Ref, Mut, } impl RefType { pub fn lifetime(self) -> TokenStream { match self { RefType::No => quote!(), _ => quote!('__deriveMoreLifetime), } } pub fn reference(self) -> TokenStream { match self { RefType::No => quote!(), RefType::Ref => quote!(&), RefType::Mut => quote!(&mut), } } pub fn mutability(self) -> TokenStream { match self { RefType::Mut => quote!(mut), _ => quote!(), } } pub fn pattern_ref(self) -> TokenStream { match self { RefType::Ref => quote!(ref), RefType::Mut => quote!(ref mut), RefType::No => quote!(), } } pub fn reference_with_lifetime(self) -> TokenStream { if !self.is_ref() { return quote!(); } let lifetime = self.lifetime(); let mutability = self.mutability(); quote!(&#lifetime #mutability) } pub fn is_ref(self) -> bool { match self { RefType::No => false, _ => true, } } pub fn from_attr_name(name: &str) -> Self { match name { "owned" => RefType::No, "ref" => RefType::Ref, "ref_mut" => RefType::Mut, _ => panic!("'{}' is not a RefType", name), } } } pub fn numbered_vars(count: usize, prefix: &str) -> Vec { (0..count) .map(|i| Ident::new(&format!("__{}{}", prefix, i), Span::call_site())) .collect() } pub fn field_idents<'a>(fields: &'a [&'a Field]) -> Vec<&'a Ident> { fields .iter() .map(|f| { f.ident .as_ref() .expect("Tried to get field names of a tuple struct") }) .collect() } pub fn get_field_types_iter<'a>( fields: &'a [&'a Field], ) -> Box + 'a> { Box::new(fields.iter().map(|f| &f.ty)) } pub fn get_field_types<'a>(fields: &'a [&'a Field]) -> Vec<&'a Type> { get_field_types_iter(fields).collect() } pub fn add_extra_type_param_bound_op_output<'a>( generics: &'a Generics, trait_ident: &'a Ident, ) -> Generics { let mut generics = generics.clone(); for type_param in &mut generics.type_params_mut() { let type_ident = &type_param.ident; let bound: TypeParamBound = parse_quote! { ::core::ops::#trait_ident }; type_param.bounds.push(bound) } generics } pub fn add_extra_ty_param_bound_op<'a>( generics: &'a Generics, trait_ident: &'a Ident, ) -> Generics { add_extra_ty_param_bound(generics, "e!(::core::ops::#trait_ident)) } pub fn add_extra_ty_param_bound<'a>( generics: &'a Generics, bound: &'a TokenStream, ) -> Generics { let mut generics = generics.clone(); let bound: TypeParamBound = parse_quote! { #bound }; for type_param in &mut generics.type_params_mut() { type_param.bounds.push(bound.clone()) } generics } pub fn add_extra_ty_param_bound_ref<'a>( generics: &'a Generics, bound: &'a TokenStream, ref_type: RefType, ) -> Generics { match ref_type { RefType::No => add_extra_ty_param_bound(generics, bound), _ => { let generics = generics.clone(); let idents = generics.type_params().map(|x| &x.ident); let ref_with_lifetime = ref_type.reference_with_lifetime(); add_extra_where_clauses( &generics, quote!( where #(#ref_with_lifetime #idents: #bound),* ), ) } } } pub fn add_extra_generic_param( generics: &Generics, generic_param: TokenStream, ) -> Generics { let generic_param: GenericParam = parse_quote! { #generic_param }; let mut generics = generics.clone(); generics.params.push(generic_param); generics } pub fn add_extra_generic_type_param( generics: &Generics, generic_param: TokenStream, ) -> Generics { let generic_param: GenericParam = parse_quote! { #generic_param }; let lifetimes: Vec = generics.lifetimes().map(|x| x.clone().into()).collect(); let type_params: Vec = generics.type_params().map(|x| x.clone().into()).collect(); let const_params: Vec = generics.const_params().map(|x| x.clone().into()).collect(); let mut generics = generics.clone(); generics.params = Default::default(); generics.params.extend(lifetimes); generics.params.extend(type_params); generics.params.push(generic_param); generics.params.extend(const_params); generics } pub fn add_extra_where_clauses( generics: &Generics, type_where_clauses: TokenStream, ) -> Generics { let mut type_where_clauses: WhereClause = parse_quote! { #type_where_clauses }; let mut new_generics = generics.clone(); if let Some(old_where) = new_generics.where_clause { type_where_clauses.predicates.extend(old_where.predicates) } new_generics.where_clause = Some(type_where_clauses); new_generics } pub fn add_where_clauses_for_new_ident<'a>( generics: &'a Generics, fields: &[&'a Field], type_ident: &Ident, type_where_clauses: TokenStream, sized: bool, ) -> Generics { let generic_param = if fields.len() > 1 { quote!(#type_ident: ::core::marker::Copy) } else if sized { quote!(#type_ident) } else { quote!(#type_ident: ?::core::marker::Sized) }; let generics = add_extra_where_clauses(generics, type_where_clauses); add_extra_generic_type_param(&generics, generic_param) } pub fn unnamed_to_vec(fields: &FieldsUnnamed) -> Vec<&Field> { fields.unnamed.iter().collect() } pub fn named_to_vec(fields: &FieldsNamed) -> Vec<&Field> { fields.named.iter().collect() } fn panic_one_field(trait_name: &str, trait_attr: &str) -> ! { panic!( "derive({}) only works when forwarding to a single field. Try putting #[{}] or #[{}(ignore)] on the fields in the struct", trait_name, trait_attr, trait_attr, ) } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum DeriveType { Unnamed, Named, Enum, } pub struct State<'input> { pub input: &'input DeriveInput, pub trait_name: &'static str, pub method_ident: Ident, pub trait_module: TokenStream, pub trait_path: TokenStream, pub trait_path_params: Vec, pub trait_attr: String, pub derive_type: DeriveType, pub fields: Vec<&'input Field>, pub variants: Vec<&'input Variant>, pub variant_states: Vec>, pub variant: Option<&'input Variant>, pub generics: Generics, pub default_info: FullMetaInfo, full_meta_infos: Vec, } #[derive(Default, Clone)] pub struct AttrParams { pub enum_: Vec<&'static str>, pub variant: Vec<&'static str>, pub struct_: Vec<&'static str>, pub field: Vec<&'static str>, } impl AttrParams { pub fn new(params: Vec<&'static str>) -> AttrParams { AttrParams { enum_: params.clone(), struct_: params.clone(), variant: params.clone(), field: params, } } pub fn struct_(params: Vec<&'static str>) -> AttrParams { AttrParams { enum_: vec![], struct_: params, variant: vec![], field: vec![], } } pub fn ignore_and_forward() -> AttrParams { AttrParams::new(vec!["ignore", "forward"]) } } impl<'input> State<'input> { pub fn new<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_module: TokenStream, trait_attr: String, ) -> Result> { State::new_impl( input, trait_name, trait_module, trait_attr, AttrParams::default(), true, ) } pub fn with_field_ignore<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_module: TokenStream, trait_attr: String, ) -> Result> { State::new_impl( input, trait_name, trait_module, trait_attr, AttrParams::new(vec!["ignore"]), true, ) } pub fn with_field_ignore_and_forward<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_module: TokenStream, trait_attr: String, ) -> Result> { State::new_impl( input, trait_name, trait_module, trait_attr, AttrParams::new(vec!["ignore", "forward"]), true, ) } pub fn with_field_ignore_and_refs<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_module: TokenStream, trait_attr: String, ) -> Result> { State::new_impl( input, trait_name, trait_module, trait_attr, AttrParams::new(vec!["ignore", "owned", "ref", "ref_mut"]), true, ) } pub fn with_attr_params<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_module: TokenStream, trait_attr: String, allowed_attr_params: AttrParams, ) -> Result> { State::new_impl( input, trait_name, trait_module, trait_attr, allowed_attr_params, true, ) } pub fn with_type_bound<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_module: TokenStream, trait_attr: String, allowed_attr_params: AttrParams, add_type_bound: bool, ) -> Result> { Self::new_impl( input, trait_name, trait_module, trait_attr, allowed_attr_params, add_type_bound, ) } fn new_impl<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_module: TokenStream, trait_attr: String, allowed_attr_params: AttrParams, add_type_bound: bool, ) -> Result> { let trait_name = trait_name.trim_end_matches("ToInner"); let trait_ident = Ident::new(trait_name, Span::call_site()); let method_ident = Ident::new(&trait_attr, Span::call_site()); let trait_path = quote!(#trait_module::#trait_ident); let (derive_type, fields, variants): (_, Vec<_>, Vec<_>) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { (DeriveType::Unnamed, unnamed_to_vec(fields), vec![]) } Fields::Named(ref fields) => { (DeriveType::Named, named_to_vec(fields), vec![]) } Fields::Unit => (DeriveType::Named, vec![], vec![]), }, Data::Enum(ref data_enum) => ( DeriveType::Enum, vec![], data_enum.variants.iter().collect(), ), Data::Union(_) => { panic!("cannot derive({}) for union", trait_name) } }; let attrs: Vec<_> = if derive_type == DeriveType::Enum { variants.iter().map(|v| &v.attrs).collect() } else { fields.iter().map(|f| &f.attrs).collect() }; let (allowed_attr_params_outer, allowed_attr_params_inner) = if derive_type == DeriveType::Enum { (&allowed_attr_params.enum_, &allowed_attr_params.variant) } else { (&allowed_attr_params.struct_, &allowed_attr_params.field) }; let struct_meta_info = get_meta_info(&trait_attr, &input.attrs, allowed_attr_params_outer)?; let meta_infos: Result> = attrs .iter() .map(|attrs| get_meta_info(&trait_attr, attrs, allowed_attr_params_inner)) .collect(); let meta_infos = meta_infos?; let first_match = meta_infos .iter() .filter_map(|info| info.enabled.map(|_| info)) .next(); // Default to enabled true, except when first attribute has explicit // enabling. // // Except for derive Error. // // The way `else` case works is that if any field have any valid // attribute specified, then all fields without any attributes // specified are filtered out from `State::enabled_fields`. // // However, derive Error *infers* fields and there are cases when // one of the fields may have an attribute specified, but another field // would be inferred. So, for derive Error macro we default enabled // to true unconditionally (i.e., even if some fields have attributes // specified). let default_enabled = if trait_name == "Error" { true } else { first_match.map_or(true, |info| !info.enabled.unwrap()) }; let defaults = struct_meta_info.into_full(FullMetaInfo { enabled: default_enabled, forward: false, // Default to owned true, except when first attribute has one of owned, // ref or ref_mut // - not a single attribute means default true // - an attribute, but non of owned, ref or ref_mut means default true // - an attribute, and owned, ref or ref_mut means default false owned: first_match.map_or(true, |info| { info.owned.is_none() && info.ref_.is_none() || info.ref_mut.is_none() }), ref_: false, ref_mut: false, info: MetaInfo::default(), }); let full_meta_infos: Vec<_> = meta_infos .into_iter() .map(|info| info.into_full(defaults.clone())) .collect(); let variant_states: Result> = if derive_type == DeriveType::Enum { variants .iter() .zip(full_meta_infos.iter().cloned()) .map(|(variant, info)| { State::from_variant( input, trait_name, trait_module.clone(), trait_attr.clone(), allowed_attr_params.clone(), variant, info, ) }) .collect() } else { Ok(vec![]) }; let generics = if add_type_bound { add_extra_ty_param_bound(&input.generics, &trait_path) } else { input.generics.clone() }; Ok(State { input, trait_name, method_ident, trait_module, trait_path, trait_path_params: vec![], trait_attr, // input, fields, variants, variant_states: variant_states?, variant: None, derive_type, generics, full_meta_infos, default_info: defaults, }) } pub fn from_variant<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_module: TokenStream, trait_attr: String, allowed_attr_params: AttrParams, variant: &'arg_input Variant, default_info: FullMetaInfo, ) -> Result> { let trait_name = trait_name.trim_end_matches("ToInner"); let trait_ident = Ident::new(trait_name, Span::call_site()); let method_ident = Ident::new(&trait_attr, Span::call_site()); let trait_path = quote!(#trait_module::#trait_ident); let (derive_type, fields): (_, Vec<_>) = match variant.fields { Fields::Unnamed(ref fields) => { (DeriveType::Unnamed, unnamed_to_vec(fields)) } Fields::Named(ref fields) => (DeriveType::Named, named_to_vec(fields)), Fields::Unit => (DeriveType::Named, vec![]), }; let meta_infos: Result> = fields .iter() .map(|f| &f.attrs) .map(|attrs| get_meta_info(&trait_attr, attrs, &allowed_attr_params.field)) .collect(); let meta_infos = meta_infos?; let full_meta_infos: Vec<_> = meta_infos .into_iter() .map(|info| info.into_full(default_info.clone())) .collect(); let generics = add_extra_ty_param_bound(&input.generics, &trait_path); Ok(State { input, trait_name, trait_module, trait_path, trait_path_params: vec![], trait_attr, method_ident, // input, fields, variants: vec![], variant_states: vec![], variant: Some(variant), derive_type, generics, full_meta_infos, default_info, }) } pub fn add_trait_path_type_param(&mut self, param: TokenStream) { self.trait_path_params.push(param); } pub fn assert_single_enabled_field<'state>( &'state self, ) -> SingleFieldData<'input, 'state> { if self.derive_type == DeriveType::Enum { panic_one_field(self.trait_name, &self.trait_attr); } let data = self.enabled_fields_data(); if data.fields.len() != 1 { panic_one_field(self.trait_name, &self.trait_attr); }; SingleFieldData { input_type: data.input_type, field: data.fields[0], field_type: data.field_types[0], member: data.members[0].clone(), info: data.infos[0].clone(), trait_path: data.trait_path, trait_path_with_params: data.trait_path_with_params.clone(), casted_trait: data.casted_traits[0].clone(), impl_generics: data.impl_generics.clone(), ty_generics: data.ty_generics.clone(), where_clause: data.where_clause, multi_field_data: data, } } pub fn enabled_fields_data<'state>(&'state self) -> MultiFieldData<'input, 'state> { if self.derive_type == DeriveType::Enum { panic!("cannot derive({}) for enum", self.trait_name) } let fields = self.enabled_fields(); let field_idents = self.enabled_fields_idents(); let field_indexes = self.enabled_fields_indexes(); let field_types: Vec<_> = fields.iter().map(|f| &f.ty).collect(); let members: Vec<_> = field_idents .iter() .map(|ident| quote!(self.#ident)) .collect(); let trait_path = &self.trait_path; let trait_path_with_params = if !self.trait_path_params.is_empty() { let params = self.trait_path_params.iter(); quote!(#trait_path<#(#params),*>) } else { self.trait_path.clone() }; let casted_traits: Vec<_> = field_types .iter() .map(|field_type| quote!(<#field_type as #trait_path_with_params>)) .collect(); let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); let input_type = &self.input.ident; let (variant_name, variant_type) = self.variant.map_or_else( || (None, quote!(#input_type)), |v| { let variant_name = &v.ident; (Some(variant_name), quote!(#input_type::#variant_name)) }, ); MultiFieldData { input_type, variant_type, variant_name, variant_info: self.default_info.clone(), fields, field_types, field_indexes, members, infos: self.enabled_infos(), field_idents, method_ident: &self.method_ident, trait_path, trait_path_with_params, casted_traits, impl_generics, ty_generics, where_clause, state: self, } } pub fn enabled_variant_data<'state>( &'state self, ) -> MultiVariantData<'input, 'state> { if self.derive_type != DeriveType::Enum { panic!("can only derive({}) for enum", self.trait_name) } let variants = self.enabled_variants(); MultiVariantData { variants, variant_states: self.enabled_variant_states(), } } fn enabled_variants(&self) -> Vec<&'input Variant> { self.variants .iter() .zip(self.full_meta_infos.iter().map(|info| info.enabled)) .filter(|(_, ig)| *ig) .map(|(v, _)| *v) .collect() } fn enabled_variant_states(&self) -> Vec<&State<'input>> { self.variant_states .iter() .zip(self.full_meta_infos.iter().map(|info| info.enabled)) .filter(|(_, ig)| *ig) .map(|(v, _)| v) .collect() } pub fn enabled_fields(&self) -> Vec<&'input Field> { self.fields .iter() .zip(self.full_meta_infos.iter().map(|info| info.enabled)) .filter(|(_, ig)| *ig) .map(|(f, _)| *f) .collect() } fn field_idents(&self) -> Vec { if self.derive_type == DeriveType::Named { self.fields .iter() .map(|f| { f.ident .as_ref() .expect("Tried to get field names of a tuple struct") .to_token_stream() }) .collect() } else { let count = self.fields.len(); (0..count) .map(|i| Index::from(i).to_token_stream()) .collect() } } fn enabled_fields_idents(&self) -> Vec { self.field_idents() .into_iter() .zip(self.full_meta_infos.iter().map(|info| info.enabled)) .filter(|(_, ig)| *ig) .map(|(f, _)| f) .collect() } fn enabled_fields_indexes(&self) -> Vec { self.full_meta_infos .iter() .map(|info| info.enabled) .enumerate() .filter(|(_, ig)| *ig) .map(|(i, _)| i) .collect() } fn enabled_infos(&self) -> Vec { self.full_meta_infos .iter() .filter(|info| info.enabled) .cloned() .collect() } } #[derive(Clone)] pub struct SingleFieldData<'input, 'state> { pub input_type: &'input Ident, pub field: &'input Field, pub field_type: &'input Type, pub member: TokenStream, pub info: FullMetaInfo, pub trait_path: &'state TokenStream, pub trait_path_with_params: TokenStream, pub casted_trait: TokenStream, pub impl_generics: ImplGenerics<'state>, pub ty_generics: TypeGenerics<'state>, pub where_clause: Option<&'state WhereClause>, multi_field_data: MultiFieldData<'input, 'state>, } #[derive(Clone)] pub struct MultiFieldData<'input, 'state> { pub input_type: &'input Ident, pub variant_type: TokenStream, pub variant_name: Option<&'input Ident>, pub variant_info: FullMetaInfo, pub fields: Vec<&'input Field>, pub field_types: Vec<&'input Type>, pub field_idents: Vec, pub field_indexes: Vec, pub members: Vec, pub infos: Vec, pub method_ident: &'state Ident, pub trait_path: &'state TokenStream, pub trait_path_with_params: TokenStream, pub casted_traits: Vec, pub impl_generics: ImplGenerics<'state>, pub ty_generics: TypeGenerics<'state>, pub where_clause: Option<&'state WhereClause>, pub state: &'state State<'input>, } pub struct MultiVariantData<'input, 'state> { pub variants: Vec<&'input Variant>, pub variant_states: Vec<&'state State<'input>>, } impl<'input, 'state> MultiFieldData<'input, 'state> { pub fn initializer(&self, initializers: &[T]) -> TokenStream { let MultiFieldData { variant_type, field_idents, .. } = self; if self.state.derive_type == DeriveType::Named { quote!(#variant_type{#(#field_idents: #initializers),*}) } else { quote!(#variant_type(#(#initializers),*)) } } pub fn matcher( &self, indexes: &[usize], bindings: &[T], ) -> TokenStream { let MultiFieldData { variant_type, .. } = self; let full_bindings = (0..self.state.fields.len()).map(|i| { indexes.iter().position(|index| i == *index).map_or_else( || quote!(_), |found_index| bindings[found_index].to_token_stream(), ) }); if self.state.derive_type == DeriveType::Named { let field_idents = self.state.field_idents(); quote!(#variant_type{#(#field_idents: #full_bindings),*}) } else { quote!(#variant_type(#(#full_bindings),*)) } } } impl<'input, 'state> SingleFieldData<'input, 'state> { pub fn initializer(&self, initializers: &[T]) -> TokenStream { self.multi_field_data.initializer(initializers) } } fn get_meta_info( trait_attr: &str, attrs: &[Attribute], allowed_attr_params: &[&str], ) -> Result { let mut it = attrs .iter() .filter_map(|m| m.parse_meta().ok()) .filter(|m| { m.path() .segments .first() .map(|p| p.ident == trait_attr) .unwrap_or_default() }); let mut info = MetaInfo::default(); let meta = if let Some(meta) = it.next() { meta } else { return Ok(info); }; if allowed_attr_params.is_empty() { return Err(Error::new(meta.span(), "Attribute is not allowed here")); } info.enabled = Some(true); if let Some(another_meta) = it.next() { return Err(Error::new( another_meta.span(), "Only a single attribute is allowed", )); } let list = match meta.clone() { ParsedMeta::Path(_) => { if allowed_attr_params.contains(&"ignore") { return Ok(info); } else { return Err(Error::new( meta.span(), format!( "Empty attribute is not allowed, add one of the following parameters: {}", allowed_attr_params.join(", "), ), )); } } ParsedMeta::List(list) => list, ParsedMeta::NameValue(val) => { return Err(Error::new( val.span(), "Attribute doesn't support name-value format here", )); } }; parse_punctuated_nested_meta(&mut info, &list.nested, allowed_attr_params, None)?; Ok(info) } fn parse_punctuated_nested_meta( info: &mut MetaInfo, meta: &Punctuated, allowed_attr_params: &[&str], wrapper_name: Option<&str>, ) -> Result<()> { for meta in meta.iter() { let meta = match meta { NestedMeta::Meta(meta) => meta, NestedMeta::Lit(lit) => { return Err(Error::new( lit.span(), "Attribute doesn't support literals here", )) } }; match meta { ParsedMeta::List(list) if list.path.is_ident("not") => { if wrapper_name.is_some() { // Only single top-level `not` attribute is allowed. return Err(Error::new( list.span(), "Attribute doesn't support multiple multiple or nested `not` parameters", )); } parse_punctuated_nested_meta( info, &list.nested, allowed_attr_params, Some("not"), )?; } ParsedMeta::List(list) => { let path = &list.path; if !allowed_attr_params.iter().any(|param| path.is_ident(param)) { return Err(Error::new( meta.span(), format!( "Attribute nested parameter not supported. \ Supported attribute parameters are: {}", allowed_attr_params.join(", "), ), )); } let mut parse_nested = true; let attr_name = path.get_ident().unwrap().to_string(); match (wrapper_name, attr_name.as_str()) { (None, "owned") => info.owned = Some(true), (None, "ref") => info.ref_ = Some(true), (None, "ref_mut") => info.ref_mut = Some(true), #[cfg(any(feature = "from", feature = "into"))] (None, "types") | (Some("owned"), "types") | (Some("ref"), "types") | (Some("ref_mut"), "types") => { parse_nested = false; for meta in &list.nested { let typ: syn::Type = match meta { NestedMeta::Meta(meta) => { let path = if let ParsedMeta::Path(p) = meta { p } else { return Err(Error::new( meta.span(), format!( "Attribute doesn't support type {}", quote! { #meta }, ), )); }; syn::TypePath { qself: None, path: path.clone(), } .into() } NestedMeta::Lit(syn::Lit::Str(s)) => s.parse()?, NestedMeta::Lit(lit) => return Err(Error::new( lit.span(), "Attribute doesn't support nested literals here", )), }; for ref_type in wrapper_name .map(|n| vec![RefType::from_attr_name(n)]) .unwrap_or_else(|| { vec![RefType::No, RefType::Ref, RefType::Mut] }) { if info .types .entry(ref_type) .or_default() .replace(typ.clone()) .is_some() { return Err(Error::new( typ.span(), format!( "Duplicate type `{}` specified", quote! { #path }, ), )); } } } } _ => { return Err(Error::new( list.span(), format!( "Attribute doesn't support nested parameter `{}` here", quote! { #path }, ), )) } }; if parse_nested { parse_punctuated_nested_meta( info, &list.nested, allowed_attr_params, Some(&attr_name), )?; } } ParsedMeta::Path(path) => { if !allowed_attr_params.iter().any(|param| path.is_ident(param)) { return Err(Error::new( meta.span(), format!( "Attribute parameter not supported. \ Supported attribute parameters are: {}", allowed_attr_params.join(", "), ), )); } let attr_name = path.get_ident().unwrap().to_string(); match (wrapper_name, attr_name.as_str()) { (None, "ignore") => info.enabled = Some(false), (None, "forward") => info.forward = Some(true), (Some("not"), "forward") => info.forward = Some(false), (None, "owned") => info.owned = Some(true), (None, "ref") => info.ref_ = Some(true), (None, "ref_mut") => info.ref_mut = Some(true), (None, "source") => info.source = Some(true), (Some("not"), "source") => info.source = Some(false), (None, "backtrace") => info.backtrace = Some(true), (Some("not"), "backtrace") => info.backtrace = Some(false), _ => { return Err(Error::new( path.span(), format!( "Attribute doesn't support parameter `{}` here", quote! { #path } ), )) } } } ParsedMeta::NameValue(val) => { return Err(Error::new( val.span(), "Attribute doesn't support name-value parameters here", )) } } } Ok(()) } #[derive(Clone, Debug, Default)] pub struct FullMetaInfo { pub enabled: bool, pub forward: bool, pub owned: bool, pub ref_: bool, pub ref_mut: bool, pub info: MetaInfo, } #[derive(Clone, Debug, Default)] pub struct MetaInfo { pub enabled: Option, pub forward: Option, pub owned: Option, pub ref_: Option, pub ref_mut: Option, pub source: Option, pub backtrace: Option, #[cfg(any(feature = "from", feature = "into"))] pub types: HashMap>, } impl MetaInfo { fn into_full(self, defaults: FullMetaInfo) -> FullMetaInfo { FullMetaInfo { enabled: self.enabled.unwrap_or(defaults.enabled), forward: self.forward.unwrap_or(defaults.forward), owned: self.owned.unwrap_or(defaults.owned), ref_: self.ref_.unwrap_or(defaults.ref_), ref_mut: self.ref_mut.unwrap_or(defaults.ref_mut), info: self, } } } impl FullMetaInfo { pub fn ref_types(&self) -> Vec { let mut ref_types = vec![]; if self.owned { ref_types.push(RefType::No); } if self.ref_ { ref_types.push(RefType::Ref); } if self.ref_mut { ref_types.push(RefType::Mut); } ref_types } #[cfg(any(feature = "from", feature = "into"))] pub fn additional_types(&self, ref_type: RefType) -> HashSet { self.info.types.get(&ref_type).cloned().unwrap_or_default() } } pub fn get_if_type_parameter_used_in_type( type_parameters: &HashSet, ty: &syn::Type, ) -> Option { if is_type_parameter_used_in_type(type_parameters, ty) { match ty { syn::Type::Reference(syn::TypeReference { elem: ty, .. }) => { Some((**ty).clone()) } ty => Some(ty.clone()), } } else { None } } pub fn is_type_parameter_used_in_type( type_parameters: &HashSet, ty: &syn::Type, ) -> bool { match ty { syn::Type::Path(ty) => { if let Some(qself) = &ty.qself { if is_type_parameter_used_in_type(type_parameters, &qself.ty) { return true; } } if let Some(segment) = ty.path.segments.first() { if type_parameters.contains(&segment.ident) { return true; } } ty.path.segments.iter().any(|segment| { if let syn::PathArguments::AngleBracketed(arguments) = &segment.arguments { arguments.args.iter().any(|argument| match argument { syn::GenericArgument::Type(ty) => { is_type_parameter_used_in_type(type_parameters, ty) } syn::GenericArgument::Constraint(constraint) => { type_parameters.contains(&constraint.ident) } _ => false, }) } else { false } }) } syn::Type::Reference(ty) => { is_type_parameter_used_in_type(type_parameters, &ty.elem) } _ => false, } } derive_more-0.99.18/tests/add.rs000064400000000000000000000005401046102023000145530ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive(Add)] struct MyInts(i32, i32); #[derive(Add)] struct Point2D { x: i32, y: i32, } #[derive(Add)] enum MixedInts { SmallInt(i32), BigInt(i64), TwoSmallInts(i32, i32), NamedSmallInts { x: i32, y: i32 }, UnsignedOne(u32), UnsignedTwo(u32), Unit, } derive_more-0.99.18/tests/add_assign.rs000064400000000000000000000002541046102023000161210ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive(AddAssign)] struct MyInts(i32, i32); #[derive(AddAssign)] struct Point2D { x: i32, y: i32, } derive_more-0.99.18/tests/as_mut.rs000064400000000000000000000042051046102023000153150ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; use std::path::PathBuf; use std::ptr; #[derive(AsMut)] struct SingleFieldTuple(String); #[test] fn single_field_tuple() { let mut item = SingleFieldTuple(String::from("test")); assert!(ptr::eq(&mut item.0, item.as_mut())); } #[derive(AsMut)] #[as_mut(forward)] struct SingleFieldForward(Vec); #[test] fn single_field_forward() { let mut item = SingleFieldForward(vec![]); let _: &mut [i32] = (&mut item).as_mut(); } #[derive(AsMut)] struct SingleFieldStruct { first: String, } #[test] fn single_field_struct() { let mut item = SingleFieldStruct { first: String::from("test"), }; assert!(ptr::eq(&mut item.first, item.as_mut())); } #[derive(AsMut)] struct MultiFieldTuple(#[as_mut] String, #[as_mut] PathBuf, Vec); #[test] fn multi_field_tuple() { let mut item = MultiFieldTuple(String::from("test"), PathBuf::new(), vec![]); assert!(ptr::eq(&mut item.0, item.as_mut())); assert!(ptr::eq(&mut item.1, item.as_mut())); } #[derive(AsMut)] struct MultiFieldStruct { #[as_mut] first: String, #[as_mut] second: PathBuf, third: Vec, } #[test] fn multi_field_struct() { let mut item = MultiFieldStruct { first: String::from("test"), second: PathBuf::new(), third: vec![], }; assert!(ptr::eq(&mut item.first, item.as_mut())); assert!(ptr::eq(&mut item.second, item.as_mut())); } #[derive(AsMut)] struct SingleFieldGenericStruct { first: T, } #[test] fn single_field_generic_struct() { let mut item = SingleFieldGenericStruct { first: String::from("test"), }; assert!(ptr::eq(&mut item.first, item.as_mut())); } #[derive(AsMut)] struct MultiFieldGenericStruct { #[as_mut] first: Vec, #[as_mut] second: PathBuf, third: Vec, } #[test] fn multi_field_generic_struct() { let mut item = MultiFieldGenericStruct { first: b"test".to_vec(), second: PathBuf::new(), third: vec![], }; assert!(ptr::eq(&mut item.first, item.as_mut())); assert!(ptr::eq(&mut item.second, item.as_mut())); } derive_more-0.99.18/tests/as_ref.rs000064400000000000000000000040751046102023000152710ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; use std::path::PathBuf; use std::ptr; #[derive(AsRef)] struct SingleFieldTuple(String); #[test] fn single_field_tuple() { let item = SingleFieldTuple(String::from("test")); assert!(ptr::eq(&item.0, item.as_ref())); } #[derive(AsRef)] #[as_ref(forward)] struct SingleFieldForward(Vec); #[test] fn single_field_forward() { let item = SingleFieldForward(vec![]); let _: &[i32] = (&item).as_ref(); } #[derive(AsRef)] struct SingleFieldStruct { first: String, } #[test] fn single_field_struct() { let item = SingleFieldStruct { first: String::from("test"), }; assert!(ptr::eq(&item.first, item.as_ref())); } #[derive(AsRef)] struct MultiFieldTuple(#[as_ref] String, #[as_ref] PathBuf, Vec); #[test] fn multi_field_tuple() { let item = MultiFieldTuple(String::from("test"), PathBuf::new(), vec![]); assert!(ptr::eq(&item.0, item.as_ref())); assert!(ptr::eq(&item.1, item.as_ref())); } #[derive(AsRef)] struct MultiFieldStruct { #[as_ref] first: String, #[as_ref] second: PathBuf, third: Vec, } #[test] fn multi_field_struct() { let item = MultiFieldStruct { first: String::from("test"), second: PathBuf::new(), third: vec![], }; assert!(ptr::eq(&item.first, item.as_ref())); assert!(ptr::eq(&item.second, item.as_ref())); } #[derive(AsRef)] struct SingleFieldGenericStruct { first: T, } #[test] fn single_field_generic_struct() { let item = SingleFieldGenericStruct { first: String::from("test"), }; assert!(ptr::eq(&item.first, item.as_ref())); } #[derive(AsRef)] struct MultiFieldGenericStruct { #[as_ref] first: Vec, #[as_ref] second: [U; 2], third: Vec, } #[test] fn multi_field_generic_struct() { let item = MultiFieldGenericStruct { first: b"test".to_vec(), second: [0i32, 1i32], third: vec![], }; assert!(ptr::eq(&item.first, item.as_ref())); assert!(ptr::eq(&item.second, item.as_ref())); } derive_more-0.99.18/tests/boats_display_derive.rs000064400000000000000000000026231046102023000202220ustar 00000000000000// The following code is from https://github.com/withoutboats/display_derive/blob/232a32ee19e262aacbd2c93be5b4ce9e89a5fc30/tests/tests.rs // Written by without boats originally #[macro_use] extern crate derive_more; #[derive(Display)] #[display(fmt = "An error has occurred.")] struct UnitError; #[test] fn unit_struct() { let s = format!("{}", UnitError); assert_eq!(&s[..], "An error has occurred."); } #[derive(Display)] #[display(fmt = "Error code: {}", code)] struct RecordError { code: u32, } #[test] fn record_struct() { let s = format!("{}", RecordError { code: 0 }); assert_eq!(&s[..], "Error code: 0"); } #[derive(Display)] #[display(fmt = "Error code: {}", _0)] struct TupleError(i32); #[test] fn tuple_struct() { let s = format!("{}", TupleError(2)); assert_eq!(&s[..], "Error code: 2"); } #[derive(Display)] enum EnumError { #[display(fmt = "Error code: {}", code)] StructVariant { code: i32 }, #[display(fmt = "Error: {}", _0)] TupleVariant(&'static str), #[display(fmt = "An error has occurred.")] UnitVariant, } #[test] fn enum_error() { let s = format!("{}", EnumError::StructVariant { code: 2 }); assert_eq!(&s[..], "Error code: 2"); let s = format!("{}", EnumError::TupleVariant("foobar")); assert_eq!(&s[..], "Error: foobar"); let s = format!("{}", EnumError::UnitVariant); assert_eq!(&s[..], "An error has occurred."); } derive_more-0.99.18/tests/constructor.rs000064400000000000000000000004651046102023000164160ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive(Constructor)] struct EmptyTuple(); #[derive(Constructor)] struct EmptyStruct {} #[derive(Constructor)] struct EmptyUnit; #[derive(Constructor)] struct MyInts(i32, i32); #[derive(Constructor)] struct Point2D { x: i32, y: i32, } derive_more-0.99.18/tests/deref.rs000064400000000000000000000020021046102023000151030ustar 00000000000000#![allow(dead_code, unused_imports)] #[macro_use] extern crate derive_more; #[derive(Deref)] #[deref(forward)] struct MyBoxedInt(Box); #[derive(Deref)] #[deref(forward)] struct NumRef<'a> { num: &'a i32, } #[derive(Deref)] struct NumRef2<'a> { #[deref(forward)] num: &'a i32, useless: bool, } #[derive(Deref)] #[deref(forward)] struct NumRef3<'a> { num: &'a i32, #[deref(ignore)] useless: bool, } #[derive(Deref)] struct MyInt(i32); #[derive(Deref)] struct Point1D { x: i32, } #[derive(Deref)] struct Point1D2 { x: i32, #[deref(ignore)] useless: bool, } #[derive(Deref)] struct CoolVec { cool: bool, #[deref] vec: Vec, } #[derive(Deref)] struct GenericVec(Vec); #[test] fn deref_generic() { let gv = GenericVec(Vec::::new()); assert!(gv.is_empty()) } #[derive(Deref)] struct GenericBox(#[deref(forward)] Box); #[test] fn deref_generic_forward() { let boxed = GenericBox(Box::new(1i32)); assert_eq!(*boxed, 1i32); } derive_more-0.99.18/tests/deref_mut.rs000064400000000000000000000052151046102023000160010ustar 00000000000000#![allow(dead_code, unused_imports)] #[macro_use] extern crate derive_more; #[derive(DerefMut)] #[deref_mut(forward)] struct MyBoxedInt(Box); // Deref implementation is needed for DerefMut impl ::core::ops::Deref for MyBoxedInt { type Target = as ::core::ops::Deref>::Target; #[inline] fn deref(&self) -> &Self::Target { as ::core::ops::Deref>::deref(&self.0) } } #[derive(DerefMut)] struct NumRef<'a> { #[deref_mut(forward)] num: &'a mut i32, } // Deref implementation is needed for DerefMut impl<'a> ::core::ops::Deref for NumRef<'a> { type Target = <&'a mut i32 as ::core::ops::Deref>::Target; #[inline] fn deref(&self) -> &Self::Target { <&'a mut i32 as ::core::ops::Deref>::deref(&self.num) } } #[derive(DerefMut)] #[deref_mut(forward)] struct NumRef2<'a> { num: &'a mut i32, #[deref_mut(ignore)] useless: bool, } // Deref implementation is needed for DerefMut impl<'a> ::core::ops::Deref for NumRef2<'a> { type Target = <&'a mut i32 as ::core::ops::Deref>::Target; #[inline] fn deref(&self) -> &Self::Target { <&'a mut i32 as ::core::ops::Deref>::deref(&self.num) } } #[derive(DerefMut)] struct MyInt(i32); // Deref implementation is needed for DerefMutToInner impl ::core::ops::Deref for MyInt { type Target = i32; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } #[derive(DerefMut)] struct Point1D { x: i32, } // Deref implementation is needed for DerefMutToInner impl ::core::ops::Deref for Point1D { type Target = i32; #[inline] fn deref(&self) -> &Self::Target { &self.x } } #[derive(DerefMut)] struct CoolVec { cool: bool, #[deref_mut] vec: Vec, } impl ::core::ops::Deref for CoolVec { type Target = Vec; #[inline] fn deref(&self) -> &Self::Target { &self.vec } } #[derive(DerefMut)] struct GenericVec(Vec); impl ::core::ops::Deref for GenericVec { type Target = Vec; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } #[test] fn deref_mut_generic() { let mut gv = GenericVec::(vec![42]); assert!(gv.get_mut(0).is_some()); } #[derive(DerefMut)] struct GenericBox(#[deref_mut(forward)] Box); impl ::core::ops::Deref for GenericBox where Box: ::core::ops::Deref, { type Target = as ::core::ops::Deref>::Target; #[inline] fn deref(&self) -> &Self::Target { as ::core::ops::Deref>::deref(&self.0) } } #[test] fn deref_mut_generic_forward() { let mut boxed = GenericBox(Box::new(1i32)); *boxed = 3; assert_eq!(*boxed, 3i32); } derive_more-0.99.18/tests/display.rs000064400000000000000000000251671046102023000155040ustar 00000000000000#![allow(dead_code, unused_imports)] #[macro_use] extern crate derive_more; use std::path::PathBuf; // Here just to make sure that this doesn't conflict with // the derives in some way use std::fmt::Binary; #[derive(Display, Octal, Binary)] struct MyInt(i32); #[derive(UpperHex)] enum IntEnum { U8(u8), I8(i8), } #[derive(Display)] #[display(fmt = "({}, {})", x, y)] struct Point2D { x: i32, y: i32, } #[derive(Display)] #[display(fmt = "{}", "self.sign()")] struct PositiveOrNegative { x: i32, } impl PositiveOrNegative { fn sign(&self) -> &str { if self.x >= 0 { "Positive" } else { "Negative" } } } #[derive(Display)] #[display(fmt = "{}", message)] struct Error { message: &'static str, backtrace: (), } impl Error { fn new(message: &'static str) -> Self { Self { message, backtrace: (), } } } #[derive(Display)] enum E { Uint(u32), #[display(fmt = "I am B {:b}", i)] Binary { i: i8, }, #[display(fmt = "I am C {}", "_0.display()")] Path(PathBuf), } #[derive(Display)] #[display(fmt = "Java EE")] enum EE { A, B, } #[derive(Display)] #[display(fmt = "Hello there!")] union U { i: u32, } #[derive(Octal)] #[octal(fmt = "7")] struct S; #[derive(UpperHex)] #[upper_hex(fmt = "UpperHex")] struct UH; #[derive(DebugCustom)] #[debug(fmt = "MyDebug")] struct D; #[derive(Display)] struct Unit; #[derive(Display)] struct UnitStruct {} #[derive(Display)] enum EmptyEnum {} #[derive(Display)] #[display(fmt = "Generic")] struct Generic(T); #[derive(Display)] #[display(fmt = "Here's a prefix for {} and a suffix")] enum Affix { A(u32), #[display(fmt = "{} -- {}", wat, stuff)] B { wat: String, stuff: bool, }, } #[derive(Debug, Display)] #[display(fmt = "{:?}", self)] struct DebugStructAsDisplay; #[test] fn check_display() { assert_eq!(MyInt(-2).to_string(), "-2"); assert_eq!(format!("{:b}", MyInt(9)), "1001"); assert_eq!(format!("{:#b}", MyInt(9)), "0b1001"); assert_eq!(format!("{:o}", MyInt(9)), "11"); assert_eq!(format!("{:X}", IntEnum::I8(-1)), "FF"); assert_eq!(format!("{:#X}", IntEnum::U8(255)), "0xFF"); assert_eq!(Point2D { x: 3, y: 4 }.to_string(), "(3, 4)"); assert_eq!(PositiveOrNegative { x: 123 }.to_string(), "Positive"); assert_eq!(PositiveOrNegative { x: 0 }.to_string(), "Positive"); assert_eq!(PositiveOrNegative { x: -465 }.to_string(), "Negative"); assert_eq!(Error::new("Error").to_string(), "Error"); assert_eq!(E::Uint(2).to_string(), "2"); assert_eq!(E::Binary { i: -2 }.to_string(), "I am B 11111110"); assert_eq!(E::Path("abc".into()).to_string(), "I am C abc"); assert_eq!(EE::A.to_string(), "Java EE"); assert_eq!(EE::B.to_string(), "Java EE"); assert_eq!(U { i: 2 }.to_string(), "Hello there!"); assert_eq!(format!("{:o}", S), "7"); assert_eq!(format!("{:X}", UH), "UpperHex"); assert_eq!(format!("{:?}", D), "MyDebug"); assert_eq!(Unit.to_string(), "Unit"); assert_eq!(UnitStruct {}.to_string(), "UnitStruct"); assert_eq!(Generic(()).to_string(), "Generic"); assert_eq!( Affix::A(2).to_string(), "Here's a prefix for 2 and a suffix" ); assert_eq!( Affix::B { wat: "things".to_owned(), stuff: false, } .to_string(), "Here's a prefix for things -- false and a suffix" ); assert_eq!(DebugStructAsDisplay.to_string(), "DebugStructAsDisplay"); } mod generic { #[derive(Display)] #[display(fmt = "Generic {}", field)] struct NamedGenericStruct { field: T, } #[test] fn named_generic_struct() { assert_eq!(NamedGenericStruct { field: 1 }.to_string(), "Generic 1"); } #[derive(Display)] struct AutoNamedGenericStruct { field: T, } #[test] fn auto_named_generic_struct() { assert_eq!(AutoNamedGenericStruct { field: 1 }.to_string(), "1"); } #[derive(Display)] #[display(fmt = "Generic {}", "_0")] struct UnnamedGenericStruct(T); #[test] fn unnamed_generic_struct() { assert_eq!(UnnamedGenericStruct(2).to_string(), "Generic 2"); } #[derive(Display)] struct AutoUnnamedGenericStruct(T); #[test] fn auto_unnamed_generic_struct() { assert_eq!(AutoUnnamedGenericStruct(2).to_string(), "2"); } #[derive(Display)] enum GenericEnum { #[display(fmt = "Gen::A {}", field)] A { field: A }, #[display(fmt = "Gen::B {}", "_0")] B(B), } #[test] fn generic_enum() { assert_eq!(GenericEnum::A::<_, u8> { field: 1 }.to_string(), "Gen::A 1"); assert_eq!(GenericEnum::B::(2).to_string(), "Gen::B 2"); } #[derive(Display)] enum AutoGenericEnum { A { field: A }, B(B), } #[test] fn auto_generic_enum() { assert_eq!(AutoGenericEnum::A::<_, u8> { field: 1 }.to_string(), "1"); assert_eq!(AutoGenericEnum::B::(2).to_string(), "2"); } #[derive(Display)] #[display(fmt = "{} {} <-> {0:o} {1:#x} <-> {0:?} {1:X?}", a, b)] struct MultiTraitNamedGenericStruct { a: A, b: B, } #[test] fn multi_trait_named_generic_struct() { let s = MultiTraitNamedGenericStruct { a: 8u8, b: 255 }; assert_eq!(s.to_string(), "8 255 <-> 10 0xff <-> 8 FF"); } #[derive(Display)] #[display(fmt = "{} {} {{}} {0:o} {1:#x} - {0:>4?} {1:^4X?}", "_0", "_1")] struct MultiTraitUnnamedGenericStruct(A, B); #[test] fn multi_trait_unnamed_generic_struct() { let s = MultiTraitUnnamedGenericStruct(8u8, 255); assert_eq!(s.to_string(), "8 255 {} 10 0xff - 8 FF "); } #[derive(Display)] #[display(fmt = "{}", "3 * 4")] struct UnusedGenericStruct(T); #[test] fn unused_generic_struct() { let s = UnusedGenericStruct(()); assert_eq!(s.to_string(), "12"); } mod associated_type_field_enumerator { use super::*; trait Trait { type Type; } struct Struct; impl Trait for Struct { type Type = i32; } #[test] fn auto_generic_named_struct_associated() { #[derive(Display)] struct AutoGenericNamedStructAssociated { field: ::Type, } let s = AutoGenericNamedStructAssociated:: { field: 10 }; assert_eq!(s.to_string(), "10"); } #[test] fn auto_generic_unnamed_struct_associated() { #[derive(Display)] struct AutoGenericUnnamedStructAssociated(::Type); let s = AutoGenericUnnamedStructAssociated::(10); assert_eq!(s.to_string(), "10"); } #[test] fn auto_generic_enum_associated() { #[derive(Display)] enum AutoGenericEnumAssociated { Enumerator(::Type), } let e = AutoGenericEnumAssociated::::Enumerator(10); assert_eq!(e.to_string(), "10"); } } mod complex_type_field_enumerator { use super::*; #[derive(Display)] struct Struct(T); #[test] fn auto_generic_named_struct_complex() { #[derive(Display)] struct AutoGenericNamedStructComplex { field: Struct, } let s = AutoGenericNamedStructComplex { field: Struct(10) }; assert_eq!(s.to_string(), "10"); } #[test] fn auto_generic_unnamed_struct_complex() { #[derive(Display)] struct AutoGenericUnnamedStructComplex(Struct); let s = AutoGenericUnnamedStructComplex(Struct(10)); assert_eq!(s.to_string(), "10"); } #[test] fn auto_generic_enum_complex() { #[derive(Display)] enum AutoGenericEnumComplex { Enumerator(Struct), } let e = AutoGenericEnumComplex::Enumerator(Struct(10)); assert_eq!(e.to_string(), "10") } } mod reference { use super::*; #[test] fn auto_generic_reference() { #[derive(Display)] struct AutoGenericReference<'a, T>(&'a T); let s = AutoGenericReference(&10); assert_eq!(s.to_string(), "10"); } #[test] fn auto_generic_static_reference() { #[derive(Display)] struct AutoGenericStaticReference(&'static T); let s = AutoGenericStaticReference(&10); assert_eq!(s.to_string(), "10"); } } mod indirect { use super::*; #[derive(Display)] struct Struct(T); #[test] fn auto_generic_indirect() { #[derive(Display)] struct AutoGenericIndirect(Struct<&'static T>); const V: i32 = 10; let s = AutoGenericIndirect(Struct(&V)); assert_eq!(s.to_string(), "10"); } } mod bound { use super::*; #[test] fn simple() { #[derive(Display)] #[display(fmt = "{} {}", _0, _1)] struct Struct(T1, T2); let s = Struct(10, 20); assert_eq!(s.to_string(), "10 20"); } #[test] fn redundant() { #[derive(Display)] #[display(bound = "T1: ::core::fmt::Display, T2: ::core::fmt::Display")] #[display(fmt = "{} {}", _0, _1)] struct Struct(T1, T2); let s = Struct(10, 20); assert_eq!(s.to_string(), "10 20"); } #[test] fn complex() { trait Trait1 { fn function1(&self) -> &'static str; } trait Trait2 { fn function2(&self) -> &'static str; } impl Trait1 for i32 { fn function1(&self) -> &'static str { "WHAT" } } impl Trait2 for i32 { fn function2(&self) -> &'static str { "EVER" } } #[derive(Display)] #[display(bound = "T1: Trait1 + Trait2, T2: Trait1 + Trait2")] #[display(fmt = "{} {} {} {}", "_0.function1()", _0, "_1.function2()", _1)] struct Struct(T1, T2); let s = Struct(10, 20); assert_eq!(s.to_string(), "WHAT 10 EVER 20"); } } } derive_more-0.99.18/tests/error/derives_for_enums_with_source.rs000064400000000000000000000125011046102023000233050ustar 00000000000000use super::*; derive_display!(TestErr); #[derive(Debug, Error)] enum TestErr { Unit, NamedImplicitNoSource { field: i32, }, NamedImplicitSource { source: SimpleErr, field: i32, }, NamedExplicitNoSource { #[error(not(source))] source: SimpleErr, field: i32, }, NamedExplicitSource { #[error(source)] explicit_source: SimpleErr, field: i32, }, NamedExplicitNoSourceRedundant { #[error(not(source))] field: i32, }, NamedExplicitSourceRedundant { #[error(source)] source: SimpleErr, field: i32, }, NamedExplicitSuppressesImplicit { source: i32, #[error(source)] field: SimpleErr, }, UnnamedImplicitNoSource(i32, i32), UnnamedImplicitSource(SimpleErr), UnnamedExplicitNoSource(#[error(not(source))] SimpleErr), UnnamedExplicitSource(#[error(source)] SimpleErr, i32), UnnamedExplicitNoSourceRedundant( #[error(not(source))] i32, #[error(not(source))] i32, ), UnnamedExplicitSourceRedundant(#[error(source)] SimpleErr), NamedIgnore { #[error(ignore)] source: SimpleErr, field: i32, }, UnnamedIgnore(#[error(ignore)] SimpleErr), NamedIgnoreRedundant { #[error(ignore)] field: i32, }, UnnamedIgnoreRedundant(#[error(ignore)] i32, #[error(ignore)] i32), #[error(ignore)] NamedVariantIgnore { source: SimpleErr, field: i32, }, #[error(ignore)] UnnamedVariantIgnore(SimpleErr), #[error(ignore)] NamedVariantIgnoreRedundant { field: i32, }, #[error(ignore)] UnnamedVariantIgnoreRedundant(i32, i32), } #[test] fn unit() { assert!(TestErr::Unit.source().is_none()); } #[test] fn named_implicit_no_source() { let err = TestErr::NamedImplicitNoSource { field: 0 }; assert!(err.source().is_none()); } #[test] fn named_implicit_source() { let err = TestErr::NamedImplicitSource { source: SimpleErr, field: 0, }; assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_no_source() { let err = TestErr::NamedExplicitNoSource { source: SimpleErr, field: 0, }; assert!(err.source().is_none()); } #[test] fn named_explicit_source() { let err = TestErr::NamedExplicitSource { explicit_source: SimpleErr, field: 0, }; assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_no_source_redundant() { let err = TestErr::NamedExplicitNoSourceRedundant { field: 0 }; assert!(err.source().is_none()); } #[test] fn named_explicit_source_redundant() { let err = TestErr::NamedExplicitSourceRedundant { source: SimpleErr, field: 0, }; assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_suppresses_implicit() { let err = TestErr::NamedExplicitSuppressesImplicit { source: 0, field: SimpleErr, }; assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_implicit_no_source() { assert!(TestErr::UnnamedImplicitNoSource(0, 0).source().is_none()); } #[test] fn unnamed_implicit_source() { let err = TestErr::UnnamedImplicitSource(SimpleErr); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_explicit_no_source() { let err = TestErr::UnnamedExplicitNoSource(SimpleErr); assert!(err.source().is_none()); } #[test] fn unnamed_explicit_source() { let err = TestErr::UnnamedExplicitSource(SimpleErr, 0); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_explicit_no_source_redundant() { let err = TestErr::UnnamedExplicitNoSourceRedundant(0, 0); assert!(err.source().is_none()); } #[test] fn unnamed_explicit_source_redundant() { let err = TestErr::UnnamedExplicitSourceRedundant(SimpleErr); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_ignore() { let err = TestErr::NamedIgnore { source: SimpleErr, field: 0, }; assert!(err.source().is_none()); } #[test] fn unnamed_ignore() { let err = TestErr::UnnamedIgnore(SimpleErr); assert!(err.source().is_none()); } #[test] fn named_ignore_redundant() { let err = TestErr::NamedIgnoreRedundant { field: 0 }; assert!(err.source().is_none()); } #[test] fn unnamed_ignore_redundant() { let err = TestErr::UnnamedIgnoreRedundant(0, 0); assert!(err.source().is_none()); } #[test] fn named_variant_ignore() { let err = TestErr::NamedVariantIgnore { source: SimpleErr, field: 0, }; assert!(err.source().is_none()); } #[test] fn unnamed_variant_ignore() { let err = TestErr::UnnamedVariantIgnore(SimpleErr); assert!(err.source().is_none()) } #[test] fn named_variant_ignore_redundant() { let err = TestErr::NamedVariantIgnoreRedundant { field: 0 }; assert!(err.source().is_none()); } #[test] fn unnamed_variant_ignore_redundant() { let err = TestErr::UnnamedVariantIgnoreRedundant(0, 0); assert!(err.source().is_none()) } derive_more-0.99.18/tests/error/derives_for_generic_enums_with_source.rs000064400000000000000000000125761046102023000250150ustar 00000000000000use super::*; derive_display!(TestErr, T, E); #[derive(Debug, Error)] enum TestErr { Unit, NamedImplicitNoSource { field: T, }, NamedImplicitSource { source: E, field: T, }, NamedExplicitNoSource { #[error(not(source))] source: E, field: T, }, NamedExplicitSource { #[error(source)] explicit_source: E, field: T, }, NamedExplicitNoSourceRedundant { #[error(not(source))] field: T, }, NamedExplicitSourceRedundant { #[error(source)] source: E, field: T, }, NamedExplicitSuppressesImplicit { source: T, #[error(source)] field: E, }, UnnamedImplicitNoSource(T, T), UnnamedImplicitSource(E), UnnamedExplicitNoSource(#[error(not(source))] E), UnnamedExplicitSource(#[error(source)] E, T), UnnamedExplicitNoSourceRedundant(#[error(not(source))] T, #[error(not(source))] T), UnnamedExplicitSourceRedundant(#[error(source)] E), NamedIgnore { #[error(ignore)] source: E, field: T, }, UnnamedIgnore(#[error(ignore)] E), NamedIgnoreRedundant { #[error(ignore)] field: T, }, UnnamedIgnoreRedundant(#[error(ignore)] T, #[error(ignore)] T), #[error(ignore)] NamedVariantIgnore { source: E, field: T, }, #[error(ignore)] UnnamedVariantIgnore(E), #[error(ignore)] NamedVariantIgnoreRedundant { field: T, }, #[error(ignore)] UnnamedVariantIgnoreRedundant(T, T), } #[test] fn unit() { assert!(TestErr::::Unit.source().is_none()); } #[test] fn named_implicit_no_source() { let err = TestErr::::NamedImplicitNoSource { field: 0 }; assert!(err.source().is_none()); } #[test] fn named_implicit_source() { let err = TestErr::NamedImplicitSource { source: SimpleErr, field: 0, }; assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_no_source() { let err = TestErr::NamedExplicitNoSource { source: SimpleErr, field: 0, }; assert!(err.source().is_none()); } #[test] fn named_explicit_source() { let err = TestErr::NamedExplicitSource { explicit_source: SimpleErr, field: 0, }; assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_no_source_redundant() { let err = TestErr::::NamedExplicitNoSourceRedundant { field: 0 }; assert!(err.source().is_none()); } #[test] fn named_explicit_source_redundant() { let err = TestErr::NamedExplicitSourceRedundant { source: SimpleErr, field: 0, }; assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_suppresses_implicit() { let err = TestErr::NamedExplicitSuppressesImplicit { source: 0, field: SimpleErr, }; assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_implicit_no_source() { let err = TestErr::::UnnamedImplicitNoSource(0, 0); assert!(err.source().is_none()); } #[test] fn unnamed_implicit_source() { let err = TestErr::<_, i32>::UnnamedImplicitSource(SimpleErr); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_explicit_no_source() { let err = TestErr::<_, i32>::UnnamedExplicitNoSource(SimpleErr); assert!(err.source().is_none()); } #[test] fn unnamed_explicit_source() { let err = TestErr::UnnamedExplicitSource(SimpleErr, 0); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_explicit_no_source_redundant() { let err = TestErr::::UnnamedExplicitNoSourceRedundant(0, 0); assert!(err.source().is_none()); } #[test] fn unnamed_explicit_source_redundant() { let err = TestErr::<_, i32>::UnnamedExplicitSourceRedundant(SimpleErr); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_ignore() { let err = TestErr::NamedIgnore { source: SimpleErr, field: 0, }; assert!(err.source().is_none()); } #[test] fn unnamed_ignore() { let err = TestErr::<_, i32>::UnnamedIgnore(SimpleErr); assert!(err.source().is_none()); } #[test] fn named_ignore_redundant() { let err = TestErr::::NamedIgnoreRedundant { field: 0 }; assert!(err.source().is_none()); } #[test] fn unnamed_ignore_redundant() { let err = TestErr::::UnnamedIgnoreRedundant(0, 0); assert!(err.source().is_none()); } #[test] fn named_variant_ignore() { let err = TestErr::NamedVariantIgnore { source: SimpleErr, field: 0, }; assert!(err.source().is_none()); } #[test] fn unnamed_variant_ignore() { let err = TestErr::<_, i32>::UnnamedVariantIgnore(SimpleErr); assert!(err.source().is_none()) } #[test] fn named_variant_ignore_redundant() { let err = TestErr::::NamedVariantIgnoreRedundant { field: 0 }; assert!(err.source().is_none()); } #[test] fn unnamed_variant_ignore_redundant() { let err = TestErr::::UnnamedVariantIgnoreRedundant(0, 0); assert!(err.source().is_none()) } derive_more-0.99.18/tests/error/derives_for_generic_structs_with_source.rs000064400000000000000000000131401046102023000253610ustar 00000000000000use super::*; #[test] fn named_implicit_no_source() { derive_display!(TestErr, T); #[derive(Default, Debug, Error)] struct TestErr { field: T, } assert!(TestErr::::default().source().is_none()); } #[test] fn named_implicit_source() { derive_display!(TestErr, E, T); #[derive(Default, Debug, Error)] struct TestErr { source: E, field: T, } let err = TestErr::::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_no_source() { derive_display!(TestErr, E, T); #[derive(Default, Debug, Error)] struct TestErr { #[error(not(source))] source: E, field: T, } let err = TestErr::::default(); assert!(err.source().is_none()); } #[test] fn named_explicit_source() { derive_display!(TestErr, E, T); #[derive(Default, Debug, Error)] struct TestErr { #[error(source)] explicit_source: E, field: T, } let err = TestErr::::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_no_source_redundant() { derive_display!(TestErr, T); #[derive(Default, Debug, Error)] struct TestErr { #[error(not(source))] field: T, } assert!(TestErr::::default().source().is_none()); } #[test] fn named_explicit_source_redundant() { derive_display!(TestErr, E, T); #[derive(Default, Debug, Error)] struct TestErr { #[error(source)] source: E, field: T, } let err = TestErr::::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_suppresses_implicit() { derive_display!(TestErr, E, T); #[derive(Default, Debug, Error)] struct TestErr { source: E, #[error(source)] field: T, } let err = TestErr::::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_implicit_no_source() { derive_display!(TestErr, T); #[derive(Default, Debug, Error)] struct TestErr(T, T); assert!(TestErr::::default().source().is_none()); } #[test] fn unnamed_implicit_source() { derive_display!(TestErr, E); #[derive(Default, Debug, Error)] struct TestErr(E); let err = TestErr::::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_explicit_no_source() { derive_display!(TestErr, E); #[derive(Default, Debug, Error)] struct TestErr(#[error(not(source))] E); assert!(TestErr::::default().source().is_none()); } #[test] fn unnamed_explicit_source() { derive_display!(TestErr, E, T); #[derive(Default, Debug, Error)] struct TestErr(#[error(source)] E, T); let err = TestErr::::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_explicit_no_source_redundant() { derive_display!(TestErr, T); #[derive(Default, Debug, Error)] struct TestErr(#[error(not(source))] T, #[error(not(source))] T); assert!(TestErr::::default().source().is_none()); } #[test] fn unnamed_explicit_source_redundant() { derive_display!(TestErr, E); #[derive(Default, Debug, Error)] struct TestErr(#[error(source)] E); let err = TestErr::::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_ignore() { derive_display!(TestErr, E, T); #[derive(Default, Debug, Error)] struct TestErr { #[error(ignore)] source: E, field: T, } assert!(TestErr::::default().source().is_none()); } #[test] fn unnamed_ignore() { derive_display!(TestErr, E); #[derive(Default, Debug, Error)] struct TestErr(#[error(ignore)] E); assert!(TestErr::::default().source().is_none()); } #[test] fn named_ignore_redundant() { derive_display!(TestErr, T); #[derive(Default, Debug, Error)] struct TestErr { #[error(ignore)] field: T, } assert!(TestErr::::default().source().is_none()); } #[test] fn unnamed_ignore_redundant() { derive_display!(TestErr, T); #[derive(Default, Debug, Error)] struct TestErr(#[error(ignore)] T, #[error(ignore)] T); assert!(TestErr::::default().source().is_none()); } #[test] fn named_struct_ignore() { derive_display!(TestErr, E, T); #[derive(Default, Debug, Error)] #[error(ignore)] struct TestErr { source: E, field: T, } assert!(TestErr::::default().source().is_none()) } #[test] fn unnamed_struct_ignore() { derive_display!(TestErr, E); #[derive(Default, Debug, Error)] #[error(ignore)] struct TestErr(E); assert!(TestErr::::default().source().is_none()) } #[test] fn named_struct_ignore_redundant() { derive_display!(TestErr, T); #[derive(Default, Debug, Error)] #[error(ignore)] struct TestErr { field: T, } assert!(TestErr::::default().source().is_none()) } #[test] fn unnamed_struct_ignore_redundant() { derive_display!(TestErr, T); #[derive(Default, Debug, Error)] #[error(ignore)] struct TestErr(T, T); assert!(TestErr::::default().source().is_none()) } derive_more-0.99.18/tests/error/derives_for_structs_with_source.rs000064400000000000000000000125501046102023000236710ustar 00000000000000use super::*; #[test] fn unit() { assert!(SimpleErr.source().is_none()); } #[test] fn named_implicit_no_source() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { field: i32, } assert!(TestErr::default().source().is_none()); } #[test] fn named_implicit_source() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { source: SimpleErr, field: i32, } let err = TestErr::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_no_source() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { #[error(not(source))] source: SimpleErr, field: i32, } assert!(TestErr::default().source().is_none()); } #[test] fn named_explicit_source() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { #[error(source)] explicit_source: SimpleErr, field: i32, } let err = TestErr::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_no_source_redundant() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { #[error(not(source))] field: i32, } assert!(TestErr::default().source().is_none()); } #[test] fn named_explicit_source_redundant() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { #[error(source)] source: SimpleErr, field: i32, } let err = TestErr::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_explicit_suppresses_implicit() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { source: i32, #[error(source)] field: SimpleErr, } let err = TestErr::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_implicit_no_source() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr(i32, i32); assert!(TestErr::default().source().is_none()); } #[test] fn unnamed_implicit_source() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr(SimpleErr); let err = TestErr::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_explicit_no_source() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr(#[error(not(source))] SimpleErr); assert!(TestErr::default().source().is_none()); } #[test] fn unnamed_explicit_source() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr(#[error(source)] SimpleErr, i32); let err = TestErr::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn unnamed_explicit_no_source_redundant() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr(#[error(not(source))] i32, #[error(not(source))] i32); assert!(TestErr::default().source().is_none()); } #[test] fn unnamed_explicit_source_redundant() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr(#[error(source)] SimpleErr); let err = TestErr::default(); assert!(err.source().is_some()); assert!(err.source().unwrap().is::()); } #[test] fn named_ignore() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { #[error(ignore)] source: SimpleErr, field: i32, } assert!(TestErr::default().source().is_none()); } #[test] fn unnamed_ignore() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr(#[error(ignore)] SimpleErr); assert!(TestErr::default().source().is_none()); } #[test] fn named_ignore_redundant() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr { #[error(ignore)] field: i32, } assert!(TestErr::default().source().is_none()); } #[test] fn unnamed_ignore_redundant() { derive_display!(TestErr); #[derive(Default, Debug, Error)] struct TestErr(#[error(ignore)] i32, #[error(ignore)] i32); assert!(TestErr::default().source().is_none()); } #[test] fn named_struct_ignore() { derive_display!(TestErr); #[derive(Default, Debug, Error)] #[error(ignore)] struct TestErr { source: SimpleErr, field: i32, } assert!(TestErr::default().source().is_none()) } #[test] fn unnamed_struct_ignore() { derive_display!(TestErr); #[derive(Default, Debug, Error)] #[error(ignore)] struct TestErr(SimpleErr); assert!(TestErr::default().source().is_none()) } #[test] fn named_struct_ignore_redundant() { derive_display!(TestErr); #[derive(Default, Debug, Error)] #[error(ignore)] struct TestErr { field: i32, } assert!(TestErr::default().source().is_none()) } #[test] fn unnamed_struct_ignore_redundant() { derive_display!(TestErr); #[derive(Default, Debug, Error)] #[error(ignore)] struct TestErr(i32, i32); assert!(TestErr::default().source().is_none()) } derive_more-0.99.18/tests/error/mod.rs000064400000000000000000000022771046102023000157440ustar 00000000000000use std::error::Error; /// Derives `std::fmt::Display` for structs/enums. /// Derived implementation outputs empty string. /// Useful, as a way to formally satisfy `Display` trait bound. /// /// ## Syntax: /// /// For regular structs/enums: /// /// ``` /// enum MyEnum { /// ... /// } /// /// derive_display!(MyEnum); /// ``` /// /// For generic structs/enums: /// /// ``` /// struct MyGenericStruct { /// ... /// } /// /// derive_display!(MyGenericStruct, T, U); /// ``` macro_rules! derive_display { (@fmt) => { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "") } }; ($type:ident) => { impl ::std::fmt::Display for $type { derive_display!(@fmt); } }; ($type:ident, $($type_parameters:ident),*) => { impl<$($type_parameters),*> ::std::fmt::Display for $type<$($type_parameters),*> { derive_display!(@fmt); } }; } mod derives_for_enums_with_source; mod derives_for_generic_enums_with_source; mod derives_for_generic_structs_with_source; mod derives_for_structs_with_source; derive_display!(SimpleErr); #[derive(Default, Debug, Error)] struct SimpleErr; derive_more-0.99.18/tests/error_tests.rs000064400000000000000000000000631046102023000163760ustar 00000000000000#[macro_use] extern crate derive_more; mod error; derive_more-0.99.18/tests/from.rs000064400000000000000000000074511046102023000147760ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; use std::borrow::Cow; #[derive(From)] struct EmptyTuple(); #[derive(From)] struct EmptyStruct {} #[derive(From)] struct EmptyUnit; #[derive(From)] struct MyInt(i32); #[derive(From)] struct MyInts(i32, i32); #[derive(From)] struct Point1D { x: i32, } #[derive(From)] struct Point2D { x: i32, y: i32, } #[derive(From)] enum MixedInts { SmallInt(i32), NamedBigInt { int: i64, }, TwoSmallInts(i32, i32), NamedBigInts { x: i64, y: i64, }, #[from(ignore)] Unsigned(u32), NamedUnsigned { x: u32, }, } #[derive(PartialEq, Eq, Debug)] #[derive(From)] #[from(forward)] struct MyIntForward(u64); #[test] fn forward_struct() { assert_eq!(MyIntForward(42), 42u32.into()); assert_eq!(MyIntForward(42), 42u16.into()); assert_eq!(MyIntForward(42), 42u64.into()); } #[derive(PartialEq, Eq, Debug)] #[derive(From)] enum MixedIntsForward { #[from(forward)] SmallInt(i32), NamedBigInt { int: i64, }, } #[test] fn forward_enum() { assert_eq!(MixedIntsForward::SmallInt(42), 42i32.into()); assert_eq!(MixedIntsForward::SmallInt(42), 42i16.into()); } #[derive(From, PartialEq)] enum AutoIgnore { SmallInt(i32), Uninteresting, Uninteresting2, } #[test] fn auto_ignore_variants() { assert!(AutoIgnore::SmallInt(42) == 42i32.into()); } #[derive(From, PartialEq)] enum AutoIgnoreWithDefaultTrue { #[from(ignore)] SmallInt(i32), Uninteresting, Uninteresting2, } #[derive(From, PartialEq)] enum AutoIgnoreWithForwardFields2 { #[from(forward)] SmallInt(i32), SmallIntIgnore(i32), } #[test] fn auto_ignore_with_forward_field2() { assert!(AutoIgnoreWithForwardFields2::SmallInt(42) == 42i32.into()); assert!(AutoIgnoreWithForwardFields2::SmallInt(42) == 42i16.into()); } #[derive(Debug, Eq, PartialEq)] #[derive(From)] #[from(types(u8, u16, u32))] struct MyIntExplicit(u64); #[test] fn explicit_types_struct() { assert_eq!(MyIntExplicit(42), 42u8.into()); assert_eq!(MyIntExplicit(42), 42u16.into()); assert_eq!(MyIntExplicit(42), 42u32.into()); assert_eq!(MyIntExplicit(42), 42u64.into()); } #[derive(Debug, Eq, PartialEq)] #[derive(From)] #[from(types(i8, i16))] struct MyIntsExplicit(i32, i32); #[test] fn explicit_types_struct_tupled() { assert_eq!(MyIntsExplicit(42, 42), (42i32, 42i32).into()); assert_eq!(MyIntsExplicit(42, 42), (42i8, 42i8).into()); assert_eq!(MyIntsExplicit(42, 42), (42i16, 42i16).into()); } #[derive(Debug, Eq, PartialEq)] #[derive(From)] enum MixedIntsExplicit { #[from(types(i8))] SmallInt(i32), #[from(types(i16, i64))] AnotherInt(i128), NamedBigInt { int: i64, }, } #[test] fn explicit_types_enum() { assert_eq!(MixedIntsExplicit::SmallInt(42), 42i32.into()); assert_eq!(MixedIntsExplicit::SmallInt(42), 42i8.into()); assert_eq!(MixedIntsExplicit::AnotherInt(42), 42i128.into()); assert_eq!(MixedIntsExplicit::AnotherInt(42), 42i64.into()); assert_eq!(MixedIntsExplicit::AnotherInt(42), 42i16.into()); } #[derive(Debug, Eq, PartialEq)] #[derive(From)] #[from(types(i8, i16))] struct Point2DExplicit { x: i32, y: i32, } #[test] fn explicit_types_point_2d() { let expected = Point2DExplicit { x: 42, y: 42 }; assert_eq!(expected, (42i32, 42i32).into()); assert_eq!(expected, (42i8, 42i8).into()); assert_eq!(expected, (42i16, 42i16).into()); } #[derive(Debug, Eq, PartialEq)] #[derive(From)] #[from(types("Cow<'_, str>", "&str"))] struct Name(String); #[test] fn explicit_complex_types_name() { let name = "Eärendil"; let expected = Name(name.to_owned()); assert_eq!(expected, name.to_owned().into()); assert_eq!(expected, name.into()); assert_eq!(expected, Cow::Borrowed(name).into()); } derive_more-0.99.18/tests/from_str.rs000064400000000000000000000002261046102023000156570ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive(FromStr)] struct MyInt(i32); #[derive(FromStr)] struct Point1D { x: i32, } derive_more-0.99.18/tests/generics.rs000064400000000000000000000040071046102023000156240ustar 00000000000000#![allow(dead_code, non_camel_case_types)] #[macro_use] extern crate derive_more; #[derive( From, FromStr, Display, Index, Not, Add, Mul, Sum, IndexMut, AddAssign, MulAssign, Deref, DerefMut, IntoIterator, Constructor )] #[deref(forward)] #[deref_mut(forward)] #[into_iterator(owned, ref, ref_mut)] struct Wrapped(T); #[derive(Deref, DerefMut)] struct Wrapped2(T); #[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)] struct WrappedDouble(T, U); #[derive(From)] #[from(forward)] struct WrappedDouble2(T, U); #[cfg(feature = "nightly")] #[derive( From, FromStr, Display, Index, Not, Add, Mul, Sum, IndexMut, AddAssign, MulAssign, Deref, DerefMut, IntoIterator, Constructor )] struct WrappedWithConst(T); #[derive( From, FromStr, Display, Index, Not, Add, Mul, IndexMut, AddAssign, MulAssign, Deref, DerefMut, IntoIterator, Constructor, Sum )] #[deref(forward)] #[deref_mut(forward)] #[into_iterator(owned, ref, ref_mut)] struct Struct { t: T, } #[derive(Deref, DerefMut)] struct Struct2 { t: T, } #[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)] struct DoubleStruct { t: T, u: U, } #[derive(From)] #[from(forward)] struct DoubleStruct2 { t: T, u: U, } #[derive(From, Not, Add)] enum TupleEnum { Tuple(T), DoubleTuple(T, U), } #[derive(From)] #[from(forward)] enum TupleEnum2 { DoubleTuple(T, U), TripleTuple(T, U, X), } #[derive(From, Not, Add)] enum StructEnum { Struct { t: T }, DoubleStruct { t: T, u: U }, } #[derive(From)] #[from(forward)] enum StructEnum2 { DoubleStruct { t: T, u: U }, TripleStruct { t: T, u: U, x: X }, } derive_more-0.99.18/tests/index.rs000064400000000000000000000003221046102023000151300ustar 00000000000000#![allow(dead_code, unused_imports)] #[macro_use] extern crate derive_more; #[derive(Index)] struct MyVec(Vec); #[derive(Index)] struct Numbers { #[index] numbers: Vec, useless: bool, } derive_more-0.99.18/tests/index_mut.rs000064400000000000000000000016651046102023000160300ustar 00000000000000#![allow(dead_code, unused_imports)] #[macro_use] extern crate derive_more; #[derive(IndexMut)] struct MyVec(Vec); //Index implementation is required for IndexMut impl<__IdxT> ::core::ops::Index<__IdxT> for MyVec where Vec: ::core::ops::Index<__IdxT>, { type Output = as ::core::ops::Index<__IdxT>>::Output; #[inline] fn index(&self, idx: __IdxT) -> &Self::Output { as ::core::ops::Index<__IdxT>>::index(&self.0, idx) } } #[derive(IndexMut)] struct Numbers { #[index_mut] numbers: Vec, useless: bool, } //Index implementation is required for IndexMut impl<__IdxT> ::core::ops::Index<__IdxT> for Numbers where Vec: ::core::ops::Index<__IdxT>, { type Output = as ::core::ops::Index<__IdxT>>::Output; #[inline] fn index(&self, idx: __IdxT) -> &Self::Output { as ::core::ops::Index<__IdxT>>::index(&self.numbers, idx) } } derive_more-0.99.18/tests/into.rs000064400000000000000000000073211046102023000150000ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; use std::borrow::Cow; #[derive(Into)] #[into(owned, ref, ref_mut)] struct EmptyTuple(); #[derive(Into)] #[into(owned, ref, ref_mut)] struct EmptyStruct {} #[derive(Into)] #[into(owned, ref, ref_mut)] struct EmptyUnit; #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Into)] #[into(owned(types(i64, i128)), ref, ref_mut)] struct MyInt(i32); #[test] fn explicit_types_struct_owned_only() { assert_eq!(i32::from(MyInt(42)), 42i32); assert_eq!(<&i32>::from(&MyInt(42)), &42i32); assert_eq!(<&mut i32>::from(&mut MyInt(42)), &mut 42i32); assert_eq!(i64::from(MyInt(42)), 42i64); assert_eq!(i128::from(MyInt(42)), 42i128); } #[derive(Into)] #[into(owned, ref, ref_mut)] struct MyInts(i32, i32); #[derive(Into)] #[into(owned, ref, ref_mut)] struct Point1D { x: i32, } #[derive(Debug, Eq, PartialEq)] #[derive(Into)] #[into(owned, ref, ref_mut)] struct Point2D { x: i32, y: i32, } #[derive(Into)] #[into(owned, ref, ref_mut)] struct Point2DWithIgnored { x: i32, y: i32, #[into(ignore)] useless: bool, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Into)] #[into(owned(types(i64, i128)), ref, ref_mut, types(i32))] struct MyIntExplicit(MyInt); #[test] fn explicit_types_struct_all() { let mut input = MyIntExplicit(MyInt(42)); assert_eq!(MyInt::from(input), MyInt(42)); assert_eq!(<&MyInt>::from(&input), &MyInt(42)); assert_eq!(<&mut MyInt>::from(&mut input), &mut MyInt(42)); assert_eq!(i32::from(input), 42i32); assert_eq!(<&i32>::from(&input), &42i32); assert_eq!(<&mut i32>::from(&mut input), &mut 42i32); assert_eq!(i64::from(input), 42i64); assert_eq!(i128::from(input), 42i128); } #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Into)] #[into(owned(types(i32, i64, i128)), ref(types(i32)), ref_mut(types(i32)))] struct MyIntsExplicit(i32, MyInt, MyIntExplicit); #[test] fn explicit_types_struct_tupled() { let mut input = MyIntsExplicit(42i32, MyInt(42), MyIntExplicit(MyInt(42))); assert_eq!( <(i32, MyInt, MyIntExplicit)>::from(input), (42i32, MyInt(42), MyIntExplicit(MyInt(42))), ); assert_eq!( <(&i32, &MyInt, &MyIntExplicit)>::from(&input), (&42i32, &MyInt(42), &MyIntExplicit(MyInt(42))), ); assert_eq!( <(&mut i32, &mut MyInt, &mut MyIntExplicit)>::from(&mut input), (&mut 42i32, &mut MyInt(42), &mut MyIntExplicit(MyInt(42))), ); assert_eq!(<(i32, i32, i32)>::from(input), (42i32, 42i32, 42i32)); assert_eq!(<(&i32, &i32, &i32)>::from(&input), (&42i32, &42i32, &42i32)); assert_eq!( <(&mut i32, &mut i32, &mut i32)>::from(&mut input), (&mut 42i32, &mut 42i32, &mut 42i32), ); assert_eq!(<(i64, i64, i64)>::from(input), (42i64, 42i64, 42i64)); assert_eq!(<(i128, i128, i128)>::from(input), (42i128, 42i128, 42i128)); } #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Into)] #[into(owned, ref, ref_mut, types(i32))] struct Point2DExplicit { x: MyInt, y: MyInt, } #[test] fn explicit_types_point_2d() { let mut input = Point2DExplicit { x: MyInt(42), y: MyInt(42), }; assert_eq!(<(i32, i32)>::from(input), (42i32, 42i32)); assert_eq!(<(&i32, &i32)>::from(&input), (&42i32, &42i32)); assert_eq!( <(&mut i32, &mut i32)>::from(&mut input), (&mut 42i32, &mut 42i32) ); } #[derive(Clone, Debug, Eq, PartialEq)] #[derive(Into)] #[into(owned(types("Cow<'_, str>")))] struct Name(String); #[test] fn explicit_complex_types_name() { let name = "Ñolofinwë"; let input = Name(name.to_owned()); assert_eq!(String::from(input.clone()), name.to_owned()); assert_eq!(Cow::from(input.clone()), Cow::Borrowed(name)); } derive_more-0.99.18/tests/into_iterator.rs000064400000000000000000000016771046102023000167210ustar 00000000000000#![allow(dead_code, unused_imports)] #[macro_use] extern crate derive_more; #[derive(IntoIterator)] #[into_iterator(owned, ref, ref_mut)] struct MyVec(Vec); #[derive(IntoIterator)] #[into_iterator(owned, ref, ref_mut)] struct Numbers { numbers: Vec, } #[derive(IntoIterator)] struct Numbers2 { #[into_iterator(owned, ref, ref_mut)] numbers: Vec, useless: bool, useless2: bool, } #[derive(IntoIterator)] struct Numbers3 { #[into_iterator(ref, ref_mut)] numbers: Vec, useless: bool, useless2: bool, } // Test that owned is not enabled when ref/ref_mut are enabled without owned impl ::core::iter::IntoIterator for Numbers3 { type Item = as ::core::iter::IntoIterator>::Item; type IntoIter = as ::core::iter::IntoIterator>::IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { as ::core::iter::IntoIterator>::into_iter(self.numbers) } } derive_more-0.99.18/tests/is_variant.rs000064400000000000000000000015621046102023000161670ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive(IsVariant)] enum Either { Left(TLeft), Right(TRight), } #[derive(IsVariant)] enum Maybe { Nothing, Just(T), } #[derive(IsVariant)] enum Color { RGB(u8, u8, u8), CMYK { c: u8, m: u8, y: u8, k: u8 }, } #[derive(IsVariant)] enum Nonsense<'a, T> { Ref(&'a T), NoRef, #[is_variant(ignore)] NoRefIgnored, } #[derive(IsVariant)] enum WithConstraints where T: Copy, { One(T), Two, } #[derive(IsVariant)] enum KitchenSink<'a, 'b, T1: Copy, T2: Clone> where T2: Into + 'b, { Left(&'a T1), Right(&'b T2), OwnBoth { left: T1, right: T2 }, Empty, NeverMind(), NothingToSeeHere {}, } #[test] pub fn test_is_variant() { assert!(Maybe::<()>::Nothing.is_nothing()); assert!(!Maybe::<()>::Nothing.is_just()); } derive_more-0.99.18/tests/lib.rs000064400000000000000000000156611046102023000146030ustar 00000000000000#[macro_use] extern crate derive_more; #[derive(From)] #[derive(Into)] #[derive(Constructor)] #[derive(Eq, PartialEq, Debug, Clone)] #[derive(Add)] #[derive(Mul)] #[derive(Neg)] #[derive(AddAssign)] #[derive(MulAssign)] #[derive(FromStr)] #[derive(Display)] #[derive(Octal)] #[derive(Binary)] #[derive(Deref, DerefMut)] #[into(owned, ref, ref_mut)] struct MyInt(i32); #[derive(Clone, Debug, Eq, PartialEq)] #[derive(Add)] #[derive(Sum)] #[derive(Mul)] #[derive(MulAssign)] #[derive(Product)] #[mul(forward)] #[mul_assign(forward)] struct MyInt2(i32); #[derive(Eq, PartialEq, Debug)] #[derive(Index, IndexMut)] #[derive(Deref, DerefMut)] #[derive(IntoIterator)] #[deref(forward)] #[deref_mut(forward)] #[into_iterator(owned, ref, ref_mut)] struct MyVec(Vec); #[derive(Eq, PartialEq, Debug)] #[derive(Deref, DerefMut)] #[deref(forward)] #[deref_mut(forward)] struct MyBoxedInt(Box); #[derive(Eq, PartialEq, Debug)] #[derive(Not)] #[derive(From)] struct MyBool(bool); #[derive(From)] #[derive(Into)] #[derive(Constructor)] #[derive(Add)] #[derive(Eq, PartialEq, Debug)] #[derive(Mul)] #[derive(AddAssign)] struct MyUInt(u64, u64); #[derive(From)] #[derive(Into)] #[derive(Constructor)] #[derive(FromStr)] #[derive(Eq, PartialEq, Debug)] #[derive(Display)] struct SimpleStruct { int1: u64, } #[derive(From)] #[derive(Constructor)] #[derive(Add, Sub, Mul, Div, Rem, BitAnd, BitOr, BitXor, Shr, Shl)] #[derive(Eq, PartialEq, Debug, Clone, Copy)] #[derive(Into)] #[derive(AddAssign)] #[into(owned, ref, ref_mut)] struct NormalStruct { int1: u64, int2: u64, } #[derive(From)] #[derive(Eq, PartialEq, Debug)] struct NestedInt(MyInt); #[derive(Eq, PartialEq, Debug)] #[derive(From)] #[derive(Add, Sub)] enum SimpleMyIntEnum { Int(i32), #[from(ignore)] _UnsignedOne(u32), _UnsignedTwo(u32), } #[derive(Eq, PartialEq, Debug)] #[derive(From)] #[derive(Neg)] enum SimpleSignedIntEnum { Int(i32), Int2(i16), } #[derive(Eq, PartialEq, Debug)] #[derive(From)] #[derive(Add, Sub)] #[derive(Neg)] enum SimpleEnum { Int(i32), #[from(ignore)] _Ints(i32, i32), LabeledInts { a: i32, b: i32, }, _SomeUnit, } #[derive(Eq, PartialEq, Debug)] #[derive(From)] #[derive(Add, Sub)] enum MyIntEnum { SmallInt(i32), BigInt(i64), TwoInts(i32, i32), Point2D { x: i64, y: i64, }, #[from(ignore)] _UnsignedOne(u32), _UnsignedTwo(u32), #[from(ignore)] _Uints1(u64, u64), _Uints2 { x: u64, y: u64, }, Nothing, } #[derive(Eq, PartialEq, Debug)] #[derive(Add, Mul)] struct DoubleUInt(u32, u32); #[derive(Eq, PartialEq, Debug)] #[derive(Add, Mul)] struct DoubleUIntStruct { x: u32, y: u32, } #[derive(Eq, PartialEq, Debug)] #[derive(From, Into, Constructor)] struct Unit; // Tests that we can forward to a path // containing `$crate` macro_rules! use_dollar_crate { () => { struct Foo; #[derive(From)] enum Bar { First(#[from(forward)] $crate::Foo), } }; } use_dollar_crate!(); #[test] fn main() { let mut myint: MyInt = 5.into(); let _: SimpleMyIntEnum = 5i32.into(); let _: MyIntEnum = 5i32.into(); let _: MyIntEnum = 6i64.into(); let _: MyIntEnum = (5i32, 8i32).into(); let _: MyIntEnum = (5i64, 8i64).into(); let _: MyIntEnum = ().into(); let int_ref: &i32 = (&myint).into(); assert_eq!(int_ref, &5); let int_ref_mut: &mut i32 = (&mut myint).into(); assert_eq!(int_ref_mut, &mut 5); let mut myint: MyInt = 5.into(); let _: Unit = ().into(); assert_eq!((), Unit.into()); assert_eq!(Unit, Unit::new()); assert_eq!(MyInt(5), 5.into()); assert_eq!(Ok(MyInt(5)), "5".parse()); assert_eq!(5, MyInt(5).into()); assert_eq!(MyInt(5), MyInt::new(5)); assert_eq!(-MyInt(5), (-5).into()); assert_eq!("30", format!("{}", MyInt(30))); assert_eq!("36", format!("{:o}", MyInt(30))); assert_eq!("100", format!("{:b}", MyInt(4))); assert_eq!(!MyBool(true), false.into()); assert_eq!(MyIntEnum::SmallInt(5), 5.into()); assert_eq!(SimpleStruct { int1: 5 }, 5.into()); assert_eq!(5u64, SimpleStruct { int1: 5 }.into()); assert_eq!(Ok(SimpleStruct { int1: 5 }), "5".parse()); assert_eq!("5", format!("{}", SimpleStruct { int1: 5 })); assert_eq!(NormalStruct { int1: 5, int2: 6 }, (5, 6).into()); assert_eq!(SimpleStruct { int1: 5 }, SimpleStruct::new(5)); assert_eq!(NormalStruct { int1: 5, int2: 6 }, NormalStruct::new(5, 6)); assert_eq!((5, 6), NormalStruct::new(5, 6).into()); let mut norm_struct = NormalStruct::new(5, 6); let uints_ref: (&u64, &u64) = (&norm_struct).into(); assert_eq!((&5, &6), uints_ref); let uints_ref_mut: (&mut u64, &mut u64) = (&mut norm_struct).into(); assert_eq!((&mut 5, &mut 6), uints_ref_mut); assert_eq!(MyInt(4) + MyInt(1), 5.into()); myint += MyInt(3); assert_eq!(myint, 8.into()); myint *= 5; assert_eq!(myint, 40.into()); assert_eq!(MyInt(4) + MyInt(1), 5.into()); assert_eq!(MyUInt(4, 5) + MyUInt(1, 2), MyUInt(5, 7)); assert_eq!(MyUInt(4, 5), MyUInt::new(4, 5)); assert_eq!((4, 5), MyUInt(4, 5).into()); let mut s1 = NormalStruct { int1: 1, int2: 2 }; let s2 = NormalStruct { int1: 2, int2: 3 }; let s3 = NormalStruct { int1: 3, int2: 5 }; assert_eq!(s1 + s2, s3); assert_eq!(s3 - s2, s1); s1 += s2; assert_eq!(s1, s3); assert_eq!((SimpleMyIntEnum::Int(6) + 5.into()).unwrap(), 11.into()); assert_eq!((SimpleMyIntEnum::Int(6) - 5.into()).unwrap(), 1.into()); assert_eq!((SimpleMyIntEnum::Int(6) - 5.into()).unwrap(), 1.into()); assert_eq!(-SimpleSignedIntEnum::Int(6), (-6i32).into()); assert_eq!( (SimpleEnum::LabeledInts { a: 6, b: 5 } + SimpleEnum::LabeledInts { a: 1, b: 4 }) .unwrap(), SimpleEnum::LabeledInts { a: 7, b: 9 } ); let _ = (MyIntEnum::SmallInt(5) + 6.into()).unwrap(); assert_eq!((-SimpleEnum::Int(5)).unwrap(), (-5).into()); assert_eq!(MyInt(50), MyInt(5) * 10); assert_eq!(DoubleUInt(5, 6) * 10, DoubleUInt(50, 60)); // assert_eq!(DoubleUIntStruct{x:5, y:6} * 10, DoubleUIntStruct{x:50, y:60}); let mut myint = MyInt(5); assert_eq!(5, *myint); *myint = 7; assert_eq!(MyInt(7), myint); let mut my_vec = MyVec(vec![5, 8]); assert_eq!(5, my_vec[0]); assert_eq!(8, my_vec[1]); my_vec[0] = 20; assert_eq!(20, my_vec[0]); assert_eq!((&my_vec).into_iter().next(), Some(&20)); assert_eq!((&mut my_vec).into_iter().next(), Some(&mut 20)); assert_eq!(my_vec.into_iter().next(), Some(20)); let int_vec = vec![MyInt2(2), MyInt2(3)]; assert_eq!(MyInt2(5), int_vec.clone().into_iter().sum()); assert_eq!(MyInt2(6), int_vec.clone().into_iter().product()); let mut myint2 = MyInt2(8); myint2 *= MyInt2(4); assert_eq!(MyInt2(32), myint2); let mut boxed = MyBoxedInt(Box::new(5)); assert_eq!(5, *boxed); *boxed = 7; assert_eq!(MyBoxedInt(Box::new(7)), boxed) } derive_more-0.99.18/tests/mul.rs000064400000000000000000000003621046102023000146220ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive(Mul)] struct MyInt(i32); #[derive(Mul)] struct MyInts(i32, i32); #[derive(Mul)] struct Point1D { x: i32, } #[derive(Mul)] struct Point2D { x: i32, y: i32, } derive_more-0.99.18/tests/mul_assign.rs000064400000000000000000000006771046102023000161770ustar 00000000000000#![allow(dead_code)] use std::marker::PhantomData; #[macro_use] extern crate derive_more; #[derive(MulAssign)] struct MyInt(i32); #[derive(MulAssign)] struct MyInts(i32, i32); #[derive(MulAssign)] #[mul_assign(forward)] struct MyIntForward(i32); #[derive(MulAssign)] struct Point1D { x: i32, } #[derive(MulAssign)] struct Point2D { x: i32, y: i32, } #[derive(MulAssign)] struct MyInt2 { x: i32, ph: PhantomData, } derive_more-0.99.18/tests/no_std.rs000064400000000000000000000022311046102023000153100ustar 00000000000000#![no_std] #![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive( AddAssign, MulAssign, Add, Mul, Not, Index, Display, FromStr, Into, From, IndexMut, Sum, Deref, DerefMut, Constructor )] #[into(owned, ref, ref_mut)] struct MyInts(u64); #[derive(Deref, DerefMut)] #[deref(forward)] #[deref_mut(forward)] struct MyBoxedInt<'a>(&'a mut u64); #[derive( From, FromStr, Display, Index, Not, Add, Mul, Sum, IndexMut, AddAssign, Deref, DerefMut, IntoIterator, Constructor )] #[deref(forward)] #[deref_mut(forward)] #[into_iterator(owned, ref, ref_mut)] struct Wrapped(T); #[derive(Deref, DerefMut)] struct Wrapped2(T); #[derive(From, Not, Add, Mul, AddAssign, Constructor, Sum)] struct WrappedDouble(T, U); #[derive(Add, Not, TryInto)] #[try_into(owned, ref, ref_mut)] enum MixedInts { SmallInt(i32), BigInt(i64), TwoSmallInts(i32, i32), NamedSmallInts { x: i32, y: i32 }, UnsignedOne(u32), UnsignedTwo(u32), } #[derive(Not, Add)] enum EnumWithUnit { SmallInt(i32), Unit, } derive_more-0.99.18/tests/not.rs000064400000000000000000000006311046102023000146240ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive(Not)] struct MyInts(i32, i32); #[derive(Not)] struct Point2D { x: i32, y: i32, } #[derive(Not)] enum MixedInts { SmallInt(i32), BigInt(i64), TwoSmallInts(i32, i32), NamedSmallInts { x: i32, y: i32 }, UnsignedOne(u32), UnsignedTwo(u32), } #[derive(Not)] enum EnumWithUnit { SmallInt(i32), Unit, } derive_more-0.99.18/tests/sum.rs000064400000000000000000000011101046102023000146210ustar 00000000000000#[macro_use] extern crate derive_more; #[derive(Sum)] struct MyInts(i32, i64); // Add implementation is needed for Sum impl ::core::ops::Add for MyInts { type Output = MyInts; #[inline] fn add(self, rhs: MyInts) -> MyInts { MyInts(self.0.add(rhs.0), self.1.add(rhs.1)) } } #[derive(Sum)] struct Point2D { x: i32, y: i32, } impl ::core::ops::Add for Point2D { type Output = Point2D; #[inline] fn add(self, rhs: Point2D) -> Point2D { Point2D { x: self.x.add(rhs.x), y: self.y.add(rhs.y), } } } derive_more-0.99.18/tests/try_into.rs000064400000000000000000000142161046102023000156770ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; use std::convert::{TryFrom, TryInto}; // Ensure that the TryFrom macro is hygenic and doesn't break when `Result` has // been redefined. type Result = (); #[derive(Clone, Copy, TryInto)] #[try_into(owned, ref, ref_mut)] enum MixedInts { SmallInt(i32), NamedBigInt { int: i64, }, UnsignedWithIgnoredField(#[try_into(ignore)] bool, i64), NamedUnsignedWithIgnnoredField { #[try_into(ignore)] useless: bool, x: i64, }, TwoSmallInts(i32, i32), NamedBigInts { x: i64, y: i64, }, Unsigned(u32), NamedUnsigned { x: u32, }, Unit, #[try_into(ignore)] Unit2, } #[test] fn test_try_into() { let mut i = MixedInts::SmallInt(42); assert_eq!(Ok(42i32), i.try_into()); assert_eq!(Ok(&42i32), (&i).try_into()); assert_eq!(Ok(&mut 42i32), (&mut i).try_into()); assert_eq!( i64::try_from(i), Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") ); assert_eq!( <(i32, i32)>::try_from(i), Err("Only TwoSmallInts can be converted to (i32, i32)") ); assert_eq!( <(i64, i64)>::try_from(i), Err("Only NamedBigInts can be converted to (i64, i64)") ); assert_eq!( u32::try_from(i), Err("Only Unsigned, NamedUnsigned can be converted to u32") ); assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); let mut i = MixedInts::NamedBigInt { int: 42 }; assert_eq!( i32::try_from(i), Err("Only SmallInt can be converted to i32") ); assert_eq!(Ok(42i64), i.try_into()); assert_eq!(Ok(&42i64), (&i).try_into()); assert_eq!(Ok(&mut 42i64), (&mut i).try_into()); assert_eq!( <(i32, i32)>::try_from(i), Err("Only TwoSmallInts can be converted to (i32, i32)") ); assert_eq!( <(i64, i64)>::try_from(i), Err("Only NamedBigInts can be converted to (i64, i64)") ); assert_eq!( u32::try_from(i), Err("Only Unsigned, NamedUnsigned can be converted to u32") ); assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); let mut i = MixedInts::TwoSmallInts(42, 64); assert_eq!( i32::try_from(i), Err("Only SmallInt can be converted to i32") ); assert_eq!( i64::try_from(i), Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") ); assert_eq!(Ok((42i32, 64i32)), i.try_into()); assert_eq!(Ok((&42i32, &64i32)), (&i).try_into()); assert_eq!(Ok((&mut 42i32, &mut 64i32)), (&mut i).try_into()); assert_eq!( <(i64, i64)>::try_from(i), Err("Only NamedBigInts can be converted to (i64, i64)") ); assert_eq!( u32::try_from(i), Err("Only Unsigned, NamedUnsigned can be converted to u32") ); assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); let mut i = MixedInts::NamedBigInts { x: 42, y: 64 }; assert_eq!( i32::try_from(i), Err("Only SmallInt can be converted to i32") ); assert_eq!( i64::try_from(i), Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") ); assert_eq!( <(i32, i32)>::try_from(i), Err("Only TwoSmallInts can be converted to (i32, i32)") ); assert_eq!(Ok((42i64, 64i64)), i.try_into()); assert_eq!(Ok((&42i64, &64i64)), (&i).try_into()); assert_eq!(Ok((&mut 42i64, &mut 64i64)), (&mut i).try_into()); assert_eq!( u32::try_from(i), Err("Only Unsigned, NamedUnsigned can be converted to u32") ); assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); let mut i = MixedInts::Unsigned(42); assert_eq!( i32::try_from(i), Err("Only SmallInt can be converted to i32") ); assert_eq!( i64::try_from(i), Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") ); assert_eq!( <(i32, i32)>::try_from(i), Err("Only TwoSmallInts can be converted to (i32, i32)") ); assert_eq!( <(i64, i64)>::try_from(i), Err("Only NamedBigInts can be converted to (i64, i64)") ); assert_eq!(Ok(42u32), i.try_into()); assert_eq!(Ok(&42u32), (&i).try_into()); assert_eq!(Ok(&mut 42u32), (&mut i).try_into()); assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); let mut i = MixedInts::NamedUnsigned { x: 42 }; assert_eq!( i32::try_from(i), Err("Only SmallInt can be converted to i32") ); assert_eq!( i64::try_from(i), Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") ); assert_eq!( i64::try_from(i), Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") ); assert_eq!( <(i32, i32)>::try_from(i), Err("Only TwoSmallInts can be converted to (i32, i32)") ); assert_eq!( <(i64, i64)>::try_from(i), Err("Only NamedBigInts can be converted to (i64, i64)") ); assert_eq!(Ok(42u32), i.try_into()); assert_eq!(Ok(&42u32), (&i).try_into()); assert_eq!(Ok(&mut 42u32), (&mut i).try_into()); assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()")); let i = MixedInts::Unit; assert_eq!( i32::try_from(i), Err("Only SmallInt can be converted to i32") ); assert_eq!( i64::try_from(i), Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64") ); assert_eq!( <(i32, i32)>::try_from(i), Err("Only TwoSmallInts can be converted to (i32, i32)") ); assert_eq!( <(i64, i64)>::try_from(i), Err("Only NamedBigInts can be converted to (i64, i64)") ); assert_eq!( u32::try_from(i), Err("Only Unsigned, NamedUnsigned can be converted to u32") ); assert_eq!(Ok(()), i.try_into()); } derive_more-0.99.18/tests/unwrap.rs000064400000000000000000000015641046102023000153460ustar 00000000000000#![allow(dead_code)] #[macro_use] extern crate derive_more; #[derive(Unwrap)] enum Either { Left(TLeft), Right(TRight), } #[derive(Unwrap)] enum Maybe { Nothing, Just(T), } #[derive(Unwrap)] enum Color { RGB(u8, u8, u8), CMYK(u8, u8, u8, u8), } #[derive(Unwrap)] enum Nonsense<'a, T> { Ref(&'a T), NoRef, #[unwrap(ignore)] NoRefIgnored, } #[derive(Unwrap)] enum WithConstraints where T: Copy, { One(T), Two, } #[derive(Unwrap)] enum KitchenSink<'a, 'b, T1: Copy, T2: Clone> where T2: Into + 'b, { Left(&'a T1), Right(&'b T2), OwnBoth(T1, T2), Empty, NeverMind(), NothingToSeeHere(), } #[test] pub fn test_unwrap() { assert_eq!(Maybe::<()>::Nothing.unwrap_nothing(), ()); } #[test] #[should_panic] pub fn test_unwrap_panic() { Maybe::<()>::Nothing.unwrap_just() }