diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/derive_more | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/derive_more')
69 files changed, 10772 insertions, 0 deletions
diff --git a/third_party/rust/derive_more/.cargo-checksum.json b/third_party/rust/derive_more/.cargo-checksum.json new file mode 100644 index 0000000000..0e43a2dc29 --- /dev/null +++ b/third_party/rust/derive_more/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"99993087689dc50095d26a01835cb9def2c1cc61fa7bdc3c9bee4b7a6d803547","Cargo.lock":"feafdfaff9f2f5fd890bb7a7a4636bc5c47a723efb66f97019e1b2235b51edd1","Cargo.toml":"522998b49ae7be5c07406b6a167822d76ceb2b3d51ded17228b49c7393b2b699","LICENSE":"8a35369f3ca263b3c62fbb5032947e53b6bfebc6c8a4d1bb982de1c069f6fba5","README.md":"4e29f61e50e888d0635af6866a6d5d7753218dbd76e3d8c9c4a5cc3b62ac4a4d","src/add_assign_like.rs":"f87ed0a7d37a73fcc6b35c43a64c954b97e48d008b199184372646a4c740fe9f","src/add_helpers.rs":"bbd4544b57091ac40bf0a6920fc85e0c90ce750bc4fc2bae3b7656808bc31324","src/add_like.rs":"2e12670d41724b4630a000a0d9aed0f9a94d82ab88ff40ddbf608ac2d8b63677","src/as_mut.rs":"0feebd28cd53f2eab9feb0807a1203359811a6718afd80fa86fe34210dcbd17c","src/as_ref.rs":"0dddd9a8e4671d5bf546c2ab662fbf5e5dcf43657c6445aee84acf1bf0570efc","src/constructor.rs":"c34f5eeaf51a3990fa783826ff1b2669a47e1876ce47eed6891a359db684d37d","src/deref.rs":"a58b91ea3a92c0d51289b2f38a4605c46b3307439eb8a3edc595659de229f37c","src/deref_mut.rs":"6e32cf2ebb3aacff2e88fae8511b1ac09de0c450f2b7b8d87d2c48bd4aceb937","src/display.rs":"ad447f69bfa094438581a62bbd400070685dd27e1e0ac5712a19c078a02787b0","src/error.rs":"bb0cdc3480859eb4ddbae9c5d6540dba96b885ebac8d7d35cd638e7a325177a7","src/from.rs":"cdc16582137aba976044716ebe33b6885fe716ea7fdba87bd748b7678dd587b5","src/from_str.rs":"fd84c4e82f6f78ed39dd3efe243f37d1db2096d6d8bc196e00277ef9b843ccf2","src/index.rs":"64bdb5f51034b0e7d0962a6c4e7781453d08767d693adb7f474f638e2b9c6179","src/index_mut.rs":"035095e24b7a7c11fb6c4951e5fbb094e045435bbfe9fe36ebc78fe28e6cc802","src/into.rs":"71e0e79543b106428918b834cea9df537844fc96adcae9f7fab4271489240478","src/into_iterator.rs":"1a89f60f635ed1f0dda2f740631ca564391cbc9cc20789d0be0f6181d80aaee5","src/is_variant.rs":"d3c001a0653087dedbc5af50b999bd2949c14c361fd8c522b3454481383dc18c","src/lib.rs":"e1a3e90151dff4240740735396f656258c67e75bfbc12693d33a539c3f08b613","src/mul_assign_like.rs":"6c530daebeb72a0df366ea5921bcf75f5aa9723dc0326b5035fe71fd9348cc9a","src/mul_helpers.rs":"7bb577b8866a87bafb8f79843d54416fb0e6eca6bbe22b1523c9eb7347f84b30","src/mul_like.rs":"25fdf3a26909a5f88ec392f00bcf7eeec247dd05a9c6307426383fac133a5e69","src/not_like.rs":"39e928363da3e644b862cc5f37c7211fe3545420749a999cc7f16e0b80a90ce6","src/parsing.rs":"6e5070f2bd77913b17550c151b273b22eb510a443a1a868c9eaa546fcdb7446a","src/sum_like.rs":"63f873934948a951b38391fddc14144806fd419c3f2bf3fb5123476e8ed41e7e","src/try_into.rs":"28266f2c66f881818fd8ffcb5aec211d82bc07b339d45d15b398d2eb6cb3bda9","src/unwrap.rs":"3589d7b7973fb5b2bb7d0cfd5654d6e4778eea5a3285624e40143ec85fa9a83e","src/utils.rs":"15890b955dbc0cb554e35e2339a1e5ffbadcb5ce4345f873f8a2d93a82cd48cb","tests/add.rs":"2c4eda40cd46fb57e9e5502dad61f930ac5f8bd672d6aacf2e35124b20034518","tests/add_assign.rs":"e59d94a1b76afdbeacc869f13e1c296a7939a660bfc23b331811248f2320d944","tests/as_mut.rs":"c9cc54e0d5b434c720cbd44e5def4f11cd28abc807675b96fe30a4b43bdbacd3","tests/as_ref.rs":"7c3caf32cedfd3ff9423c3b3ae4d6479a3df6d1b04ee7d3e8db822d20f226394","tests/boats_display_derive.rs":"23d00ad64b1a16a4e6119424f2e274729282a5acef8e72351fe87c23dcf85b47","tests/constructor.rs":"ca619975d6205cd2817b531373d61a3c2077f6673733ba945496cc33e9fb2299","tests/deref.rs":"936e20c2e3d8a32b5d8531fa462d279ccfaabaa422148790c9db174f3cc190f6","tests/deref_mut.rs":"5d55950e2541b5da33c8ba1351240f3d09d9d63d37a424655d8cc5674a0342ad","tests/display.rs":"c291fc72f2986b268cc76cb5b8cff32f97d807e3442ed9432c95098531323bfd","tests/error/derives_for_enums_with_source.rs":"b6d4c49cc888ec92cfeb24caab1cc3e23ee0d8ff99e098340584f2ef77ec060a","tests/error/derives_for_generic_enums_with_source.rs":"70de37458473bfb158ff6adf4131dd4b2beb259d44c3741b63d1a35652220baf","tests/error/derives_for_generic_structs_with_source.rs":"f017e45e72ad7e95544c95a92257253b3a61cc497180e1a224c4e5dc977fc627","tests/error/derives_for_structs_with_source.rs":"6fc1d1b4a3a6ba5d77837af6ef171f05fca50ab98b3d71351b649a0e689afd5f","tests/error/mod.rs":"b0599240c34d819986202a079b1d628c2f56c8ccd8206e89f7220cc1752a04d7","tests/error/nightly/derives_for_enums_with_backtrace.rs":"106459fb7873e5c38a35f68f6e026abe6d6a67edaed0b8c8106485bb8e67ee4c","tests/error/nightly/derives_for_generic_enums_with_backtrace.rs":"073184bcdb6051d8f8b1651f42c3636f066c80710f53ecfef32436b579c3297b","tests/error/nightly/derives_for_generic_structs_with_backtrace.rs":"5b78ff9c2d5f58c529d591e84b3eaeddc4f945da7508a5c97f3e5e025032abb8","tests/error/nightly/derives_for_structs_with_backtrace.rs":"320d95ba58786b065591807da96d5cfa09c73836d0d2a7dd2ae328abdb348724","tests/error/nightly/mod.rs":"aa12d7075bdbe222a89cf6492e10f59cfadf3658718d3226942b8230eac7f8b3","tests/error_tests.rs":"f37167b7d22f9d98593e8ed66e1c46c17548d7fb6cd125b3adf2409435e4935c","tests/from.rs":"735462d27943bec1305693e9c0cf2b42df5f682ace37c483eac62949e8d030d3","tests/from_str.rs":"ce1aeb1fca38b5d7b05c2229efe5865c0ac57454dcfec657a2645c5472694b25","tests/generics.rs":"ce792b7a1f08718116816bf4e1e78adac79b368871f1838c27d7dbce88321280","tests/index.rs":"e05053cd9f13651a8e00fcd63c85d068f029d9b7a3377ac4bb1ac540c99d06d5","tests/index_mut.rs":"bde985198352a3489c038d92bdff30119901e38db054f95fb582ed85b5e2768f","tests/into.rs":"f7905ce65890a6a3dd444589493269a33210a3632349e1052c7b8da9f48e0dec","tests/into_iterator.rs":"7ae73a51d5ceef8a0e3f97a64e71b85cba64ec857fc02248f33a97a3fc358f84","tests/is_variant.rs":"27d4a4bf0a713ed260681a707b130a89e3cd99d5147923c7ec547d06695cca11","tests/lib.rs":"471f15f790c1a040652d8833094e96e185d4e9c8a9e945b4c7c9a29b2aed025c","tests/mul.rs":"0b07081d99a7bf64113a9d8fac98e9679e9aa58c67c9ff73b43d78a432c52b80","tests/mul_assign.rs":"77d18aad3715dfdae990ae585fa507f6fc9341aba8eb22d72c85ec98be614abc","tests/no_std.rs":"541ad39e31adc570bff4fe9dc520d29faed48d8af74656bcf4456705994a7b01","tests/not.rs":"cb5f9c259abc19905f0fd088f2694d86945c9319b03c347c045c6c3b632f4b64","tests/sum.rs":"4c9bb7487aa323ee9a56eef7c1283b137d43f8f424854c3efc94e01aea18bdb8","tests/try_into.rs":"458feca7461f33ba3aa6cf1c4d6848693ae0acafcf95feec0ea48c9c36c3a167","tests/unwrap.rs":"8c07f8492ff9d186585318276c22174cbe51959333f327e51155a74171a314f1"},"package":"4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"}
\ No newline at end of file diff --git a/third_party/rust/derive_more/CHANGELOG.md b/third_party/rust/derive_more/CHANGELOG.md new file mode 100644 index 0000000000..a04b013f65 --- /dev/null +++ b/third_party/rust/derive_more/CHANGELOG.md @@ -0,0 +1,246 @@ +# 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.10 - 2020-??-?? + +### 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<T>: 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<i32>)`, dereferencing it will result in a `Box<i32>` 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. diff --git a/third_party/rust/derive_more/Cargo.lock b/third_party/rust/derive_more/Cargo.lock new file mode 100644 index 0000000000..4bdc3f32b1 --- /dev/null +++ b/third_party/rust/derive_more/Cargo.lock @@ -0,0 +1,86 @@ +# 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.17" +dependencies = [ + "convert_case", + "peg", + "proc-macro2", + "quote 1.0.10", + "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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +dependencies = [ + "unicode-xid", +] + +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +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 = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +dependencies = [ + "proc-macro2", + "quote 1.0.10", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/third_party/rust/derive_more/Cargo.toml b/third_party/rust/derive_more/Cargo.toml new file mode 100644 index 0000000000..ce083890fd --- /dev/null +++ b/third_party/rust/derive_more/Cargo.toml @@ -0,0 +1,216 @@ +# 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.17" +authors = ["Jelte Fennema <github-tech@jeltef.nl>"] +include = ["src/**/*.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", "tests/**/*.rs"] +autotests = true +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" +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_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"] +[dependencies.convert_case] +version = "0.4" +optional = true + +[dependencies.proc-macro2] +version = "1.0" + +[dependencies.quote] +version = "1.0" + +[dependencies.syn] +version = "1.0.3" +[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" diff --git a/third_party/rust/derive_more/LICENSE b/third_party/rust/derive_more/LICENSE new file mode 100644 index 0000000000..602cf050e2 --- /dev/null +++ b/third_party/rust/derive_more/LICENSE @@ -0,0 +1,21 @@ +The 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. diff --git a/third_party/rust/derive_more/README.md b/third_party/rust/derive_more/README.md new file mode 100644 index 0000000000..507148d01a --- /dev/null +++ b/third_party/rust/derive_more/README.md @@ -0,0 +1,183 @@ +# `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.36+](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://blog.rust-lang.org/2019/07/04/Rust-1.36.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.36 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 diff --git a/third_party/rust/derive_more/src/add_assign_like.rs b/third_party/rust/derive_more/src/add_assign_like.rs new file mode 100644 index 0000000000..60a74328ee --- /dev/null +++ b/third_party/rust/derive_more/src/add_assign_like.rs @@ -0,0 +1,41 @@ +use 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; + )* + } + } + ) +} diff --git a/third_party/rust/derive_more/src/add_helpers.rs b/third_party/rust/derive_more/src/add_helpers.rs new file mode 100644 index 0000000000..34f3d2ad5d --- /dev/null +++ b/third_party/rust/derive_more/src/add_helpers.rs @@ -0,0 +1,28 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{Field, Ident, Index}; + +pub fn tuple_exprs(fields: &[&Field], method_ident: &Ident) -> Vec<TokenStream> { + 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<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().unwrap(); + // generates `x: self.x.add(rhs.x)` + let expr = quote!(self.#field_id.#method_ident(rhs.#field_id)); + exprs.push(expr) + } + exprs +} diff --git a/third_party/rust/derive_more/src/add_like.rs b/third_party/rust/derive_more/src/add_like.rs new file mode 100644 index 0000000000..5d435f6ec3 --- /dev/null +++ b/third_party/rust/derive_more/src/add_like.rs @@ -0,0 +1,139 @@ +use 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<T: ToTokens>( + 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),* + } + ) +} diff --git a/third_party/rust/derive_more/src/as_mut.rs b/third_party/rust/derive_more/src/as_mut.rs new file mode 100644 index 0000000000..83944648f5 --- /dev/null +++ b/third_party/rust/derive_more/src/as_mut.rs @@ -0,0 +1,83 @@ +use 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<TokenStream> { + 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 + } + } + )*}) +} diff --git a/third_party/rust/derive_more/src/as_ref.rs b/third_party/rust/derive_more/src/as_ref.rs new file mode 100644 index 0000000000..4b8ba851d5 --- /dev/null +++ b/third_party/rust/derive_more/src/as_ref.rs @@ -0,0 +1,83 @@ +use 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<TokenStream> { + 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 + } + } + )*}) +} diff --git a/third_party/rust/derive_more/src/constructor.rs b/third_party/rust/derive_more/src/constructor.rs new file mode 100644 index 0000000000..14d488bfd4 --- /dev/null +++ b/third_party/rust/derive_more/src/constructor.rs @@ -0,0 +1,49 @@ +use 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<Ident>) { + let vars = &numbered_vars(fields.len(), ""); + (quote!(#return_type(#(#vars),*)), vars.clone()) +} + +fn struct_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec<Ident>) { + let field_names: &Vec<Ident> = + &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) +} diff --git a/third_party/rust/derive_more/src/deref.rs b/third_party/rust/derive_more/src/deref.rs new file mode 100644 index 0000000000..60e49a76a9 --- /dev/null +++ b/third_party/rust/derive_more/src/deref.rs @@ -0,0 +1,55 @@ +use 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<TokenStream> { + 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 + } + } + }) +} diff --git a/third_party/rust/derive_more/src/deref_mut.rs b/third_party/rust/derive_more/src/deref_mut.rs new file mode 100644 index 0000000000..85d65121b5 --- /dev/null +++ b/third_party/rust/derive_more/src/deref_mut.rs @@ -0,0 +1,48 @@ +use 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<TokenStream> { + 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 + } + } + }) +} diff --git a/third_party/rust/derive_more/src/display.rs b/third_party/rust/derive_more/src/display.rs new file mode 100644 index 0000000000..127531d088 --- /dev/null +++ b/third_party/rust/derive_more/src/display.rs @@ -0,0 +1,888 @@ +use std::{fmt::Display, str::FromStr as _}; + +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{quote, quote_spanned}; +use syn::{ + parse::Parser as _, punctuated::Punctuated, spanned::Spanned as _, Error, Result, +}; + +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<TokenStream> { + 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>(F) + where + F: ::core::ops::Fn(&mut ::core::fmt::Formatter) -> ::core::fmt::Result; + + const _derive_more_DisplayAs_impl: () = { + impl<F> ::core::fmt::Display for _derive_more_DisplayAs<F> + 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<syn::Type, HashSet<syn::TraitBound>>, + /// `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<Ident>, +} + +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<Option<syn::Meta>> { + let mut metas = Vec::new(); + for meta in attrs.iter().filter_map(|attr| attr.parse_meta().ok()) { + let meta_list = match &meta { + syn::Meta::List(meta) => meta, + _ => continue, + }; + + if !meta_list.path.is_ident(self.trait_attr) { + continue; + } + + use syn::{Meta, NestedMeta}; + let meta_nv = match meta_list.nested.first() { + Some(NestedMeta::Meta(Meta::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<HashMap<syn::Type, HashSet<syn::TraitBound>>> { + let span = bounds.span(); + + let input = bounds.value(); + let tokens = TokenStream::from_str(&input)?; + let parser = Punctuated::<syn::GenericParam, syn::Token![,]>::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: &syn::Meta, + outer_enum: bool, + ) -> Result<(TokenStream, bool)> { + let list = match meta { + syn::Meta::List(list) => list, + _ => { + return Err(Error::new(meta.span(), self.get_proper_fmt_syntax())); + } + }; + + match &list.nested[0] { + syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue { + path, + 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] { + syn::NestedMeta::Meta(syn::Meta::NameValue( + syn::MetaNameValue { + path, + 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 { + syn::NestedMeta::Lit(syn::Lit::Str(s)) => s, + syn::NestedMeta::Meta(syn::Meta::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<TokenStream> { + 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<ParseResult> { + 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<TokenStream> = 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 { + syn::Meta::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] { + syn::NestedMeta::Meta(syn::Meta::NameValue(meta)) => meta, + _ => return Err(Error::new(span, self.get_proper_bound_syntax())), + }; + + let extra_bounds = match &meta.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: &syn::Meta, + ) -> HashMap<syn::Type, HashSet<syn::TraitBound>> { + if self.type_params.is_empty() { + return HashMap::default(); + } + + let fields_type_params: HashMap<syn::Path, _> = 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 { + syn::Meta::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 { + syn::NestedMeta::Lit(syn::Lit::Str(ref s)) => { + syn::parse_str(&s.value()).ok().map(|id| (i, id)) + } + syn::NestedMeta::Meta(syn::Meta::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] { + syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue { + path, + 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_insert_with(HashSet::default) + .insert(trait_name_to_trait_bound(pl.trait_name)); + } + } + bounds + }, + ) + } + fn infer_type_params_bounds( + &self, + fields: &syn::Fields, + ) -> HashMap<syn::Type, HashSet<syn::TraitBound>> { + 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<Placeholder> { + 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", + }, + ], + ) + } +} diff --git a/third_party/rust/derive_more/src/error.rs b/third_party/rust/derive_more/src/error.rs new file mode 100644 index 0000000000..5767290523 --- /dev/null +++ b/third_party/rust/derive_more/src/error.rs @@ -0,0 +1,439 @@ +use 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<TokenStream> { + 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<syn::Ident>, + state: &State, +) -> Result<(HashSet<syn::Type>, Option<TokenStream>, Option<TokenStream>)> { + 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<syn::Ident>, + state: &State, +) -> Result<(HashSet<syn::Type>, Option<TokenStream>, Option<TokenStream>)> { + 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.into_iter()); + } + + let render = |match_arms: &mut Vec<TokenStream>| { + 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<usize>, + backtrace: Option<usize>, + bounds: HashSet<syn::Type>, +} + +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<TokenStream> { + 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<TokenStream> { + 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<TokenStream> { + 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<TokenStream> { + let backtrace = self.backtrace?; + let pattern = self.data.matcher(&[backtrace], &[quote!(backtrace)]); + Some(quote!(#pattern => Some(backtrace))) + } +} + +fn render_some<T>(expr: T) -> TokenStream +where + T: quote::ToTokens, +{ + quote!(Some(#expr as &(dyn ::std::error::Error + 'static))) +} + +fn parse_fields<'input, 'state>( + type_params: &HashSet<syn::Ident>, + state: &'state State<'input>, +) -> Result<ParsedFields<'input, 'state>> { + 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<usize> { + // 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<ParsedFields<'input, 'state>> +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<Item = (usize, &'a syn::Field, &'a MetaInfo)> + Clone, + attr: &str, + value: V, +) -> Result<Option<(usize, &'a syn::Field, &'a MetaInfo)>> +where + P: Fn(&str, &syn::Field, usize) -> bool, + V: Fn(&MetaInfo) -> Option<bool>, +{ + 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<Item = (usize, &'a syn::Field, &'a MetaInfo)>, + error_msg: &str, +) -> Result<Option<(usize, &'a syn::Field, &'a MetaInfo)>> { + 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<syn::Type>, + type_params: &HashSet<syn::Ident>, + ty: &syn::Type, +) { + if let Some(ty) = utils::get_if_type_parameter_used_in_type(type_params, ty) { + bounds.insert(ty); + } +} diff --git a/third_party/rust/derive_more/src/from.rs b/third_party/rust/derive_more/src/from.rs new file mode 100644 index 0000000000..56ff5bcf91 --- /dev/null +++ b/third_party/rust/derive_more/src/from.rs @@ -0,0 +1,142 @@ +use 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<TokenStream> { + 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 +} diff --git a/third_party/rust/derive_more/src/from_str.rs b/third_party/rust/derive_more/src/from_str.rs new file mode 100644 index 0000000000..5f26fdd18c --- /dev/null +++ b/third_party/rust/derive_more/src/from_str.rs @@ -0,0 +1,49 @@ +use 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<TokenStream> { + 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<Self, Self::Err> { + Ok(#body) + } + } + }) +} + +fn panic_one_field(trait_name: &str) -> ! { + panic!("Only structs with one field can derive({})", trait_name) +} diff --git a/third_party/rust/derive_more/src/index.rs b/third_party/rust/derive_more/src/index.rs new file mode 100644 index 0000000000..5aea597693 --- /dev/null +++ b/third_party/rust/derive_more/src/index.rs @@ -0,0 +1,50 @@ +use 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<TokenStream> { + 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) + } + } + }) +} diff --git a/third_party/rust/derive_more/src/index_mut.rs b/third_party/rust/derive_more/src/index_mut.rs new file mode 100644 index 0000000000..d2c3688051 --- /dev/null +++ b/third_party/rust/derive_more/src/index_mut.rs @@ -0,0 +1,49 @@ +use 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<TokenStream> { + 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) + } + } + }) +} diff --git a/third_party/rust/derive_more/src/into.rs b/third_party/rust/derive_more/src/into.rs new file mode 100644 index 0000000000..61d820e9b8 --- /dev/null +++ b/third_party/rust/derive_more/src/into.rs @@ -0,0 +1,83 @@ +use 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<TokenStream> { + 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) +} diff --git a/third_party/rust/derive_more/src/into_iterator.rs b/third_party/rust/derive_more/src/into_iterator.rs new file mode 100644 index 0000000000..45183d4588 --- /dev/null +++ b/third_party/rust/derive_more/src/into_iterator.rs @@ -0,0 +1,59 @@ +use 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<TokenStream> { + 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) +} diff --git a/third_party/rust/derive_more/src/is_variant.rs b/third_party/rust/derive_more/src/is_variant.rs new file mode 100644 index 0000000000..3f19298294 --- /dev/null +++ b/third_party/rust/derive_more/src/is_variant.rs @@ -0,0 +1,62 @@ +use 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<TokenStream> { + 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) +} diff --git a/third_party/rust/derive_more/src/lib.rs b/third_party/rust/derive_more/src/lib.rs new file mode 100644 index 0000000000..339e75040d --- /dev/null +++ b/third_party/rust/derive_more/src/lib.rs @@ -0,0 +1,422 @@ +//! # `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.36+](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://blog.rust-lang.org/2019/07/04/Rust-1.36.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.36 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 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<TokenStream, syn::parse::Error>. +trait Output { + fn process(self) -> TokenStream; +} + +impl Output for proc_macro2::TokenStream { + fn process(self) -> TokenStream { + self.into() + } +} + +impl Output for Result<proc_macro2::TokenStream, ParseError> { + 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); diff --git a/third_party/rust/derive_more/src/mul_assign_like.rs b/third_party/rust/derive_more/src/mul_assign_like.rs new file mode 100644 index 0000000000..eaba70daaf --- /dev/null +++ b/third_party/rust/derive_more/src/mul_assign_like.rs @@ -0,0 +1,65 @@ +use 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<TokenStream> { + 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::<HashSet<_>>(); + 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; + )* + } + } + )) +} diff --git a/third_party/rust/derive_more/src/mul_helpers.rs b/third_party/rust/derive_more/src/mul_helpers.rs new file mode 100644 index 0000000000..985d64fe8c --- /dev/null +++ b/third_party/rust/derive_more/src/mul_helpers.rs @@ -0,0 +1,36 @@ +use 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<TokenStream>) { + 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) +} diff --git a/third_party/rust/derive_more/src/mul_like.rs b/third_party/rust/derive_more/src/mul_like.rs new file mode 100644 index 0000000000..734dc0f117 --- /dev/null +++ b/third_party/rust/derive_more/src/mul_like.rs @@ -0,0 +1,62 @@ +use 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<TokenStream> { + 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::<HashSet<_>>(); + 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 + } + } + + )) +} diff --git a/third_party/rust/derive_more/src/not_like.rs b/third_party/rust/derive_more/src/not_like.rs new file mode 100644 index 0000000000..2639c3b675 --- /dev/null +++ b/third_party/rust/derive_more/src/not_like.rs @@ -0,0 +1,166 @@ +use 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<T: ToTokens>( + 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) +} diff --git a/third_party/rust/derive_more/src/parsing.rs b/third_party/rust/derive_more/src/parsing.rs new file mode 100644 index 0000000000..528d4382a2 --- /dev/null +++ b/third_party/rust/derive_more/src/parsing.rs @@ -0,0 +1,883 @@ +use 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<T> { + 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<T> = Result<T, ParseError>; +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, "<character>") + } +} +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<Option<&'input str>> { + #![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<Option<&'input str>> { + #![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<Option<&'input str>> { + #![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<usize> { + #![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<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 { + 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<Vec<&'input str>> { + #![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<usize>, 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<Vec<&'input str>> { + #![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<usize>, 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, + }) +} diff --git a/third_party/rust/derive_more/src/sum_like.rs b/third_party/rust/derive_more/src/sum_like.rs new file mode 100644 index 0000000000..f8f8a86eab --- /dev/null +++ b/third_party/rust/derive_more/src/sum_like.rs @@ -0,0 +1,56 @@ +use 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<TokenStream> { + 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<Output=#input_type#ty_generics> + }; + 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<I: ::core::iter::Iterator<Item = Self>>(iter: I) -> Self { + iter.fold(#identity, #op_path::#op_method_ident) + } + } + )) +} diff --git a/third_party/rust/derive_more/src/try_into.rs b/third_party/rust/derive_more/src/try_into.rs new file mode 100644 index 0000000000..996bcdf458 --- /dev/null +++ b/third_party/rust/derive_more/src/try_into.rs @@ -0,0 +1,122 @@ +use 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<TokenStream> { + 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::<Vec<_>>(); + format!("({})", types.join(", ")) + }; + let variant_names = multi_field_datas + .iter() + .map(|d| { + format!( + "{}", + d.variant_name.expect("Somehow there was no variant name") + ) + }) + .collect::<Vec<_>>() + .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<Self, Self::Error> { + match value { + #(#matchers)|* => ::core::result::Result::Ok(#vars), + _ => ::core::result::Result::Err(#message), + } + } + } + }; + try_from.to_tokens(&mut tokens) + } + Ok(tokens) +} diff --git a/third_party/rust/derive_more/src/unwrap.rs b/third_party/rust/derive_more/src/unwrap.rs new file mode 100644 index 0000000000..e2243d3a2f --- /dev/null +++ b/third_party/rust/derive_more/src/unwrap.rs @@ -0,0 +1,101 @@ +use 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<TokenStream> { + 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")) + } + }); + + // The `track-caller` feature is set by our build script based + // on rustc version detection, as `#[track_caller]` was + // stabilized in a later version (1.46) of Rust than our MSRV (1.36). + let track_caller = if cfg!(feature = "track-caller") { + quote! { #[track_caller] } + } else { + quote! {} + }; + 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) +} diff --git a/third_party/rust/derive_more/src/utils.rs b/third_party/rust/derive_more/src/utils.rs new file mode 100644 index 0000000000..72264701d8 --- /dev/null +++ b/third_party/rust/derive_more/src/utils.rs @@ -0,0 +1,1244 @@ +#![cfg_attr(not(feature = "default"), allow(dead_code), allow(unused_mut))] + +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, Meta, NestedMeta, 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<K, V> = std::collections::HashMap<K, V, DeterministicState>; +pub type HashSet<K> = std::collections::HashSet<K, DeterministicState>; + +#[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<Ident> { + (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<dyn Iterator<Item = &'a Type> + '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<Output=#type_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<GenericParam> = + generics.lifetimes().map(|x| x.clone().into()).collect(); + let type_params: Vec<GenericParam> = + generics.type_params().map(|x| x.clone().into()).collect(); + let const_params: Vec<GenericParam> = + 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 trait_ident: Ident, + pub method_ident: Ident, + pub trait_module: TokenStream, + pub trait_path: TokenStream, + pub trait_path_params: Vec<TokenStream>, + pub trait_attr: String, + pub derive_type: DeriveType, + pub fields: Vec<&'input Field>, + pub variants: Vec<&'input Variant>, + pub variant_states: Vec<State<'input>>, + pub variant: Option<&'input Variant>, + pub generics: Generics, + pub default_info: FullMetaInfo, + full_meta_infos: Vec<FullMetaInfo>, +} + +#[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<'arg_input>> { + 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<'arg_input>> { + 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<'arg_input>> { + 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<'arg_input>> { + 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<'arg_input>> { + 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<State<'arg_input>> { + 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<State<'arg_input>> { + 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<Vec<_>> = 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<Vec<_>> = 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, + trait_ident, + 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<State<'arg_input>> { + 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<Vec<_>> = 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, + trait_ident, + 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(), + field_ident: data.field_idents[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(); + let trait_path = &self.trait_path; + let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); + MultiVariantData { + input_type: &self.input.ident, + variants, + variant_states: self.enabled_variant_states(), + infos: self.enabled_infos(), + trait_path, + impl_generics, + ty_generics, + where_clause, + } + } + + 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<TokenStream> { + 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<TokenStream> { + 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<usize> { + self.full_meta_infos + .iter() + .map(|info| info.enabled) + .enumerate() + .filter(|(_, ig)| *ig) + .map(|(i, _)| i) + .collect() + } + fn enabled_infos(&self) -> Vec<FullMetaInfo> { + 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 field_ident: TokenStream, + 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<TokenStream>, + pub field_indexes: Vec<usize>, + pub members: Vec<TokenStream>, + pub infos: Vec<FullMetaInfo>, + pub method_ident: &'state Ident, + pub trait_path: &'state TokenStream, + pub trait_path_with_params: TokenStream, + pub casted_traits: Vec<TokenStream>, + 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 input_type: &'input Ident, + pub variants: Vec<&'input Variant>, + pub variant_states: Vec<&'state State<'input>>, + pub infos: Vec<FullMetaInfo>, + pub trait_path: &'state TokenStream, + pub impl_generics: ImplGenerics<'state>, + pub ty_generics: TypeGenerics<'state>, + pub where_clause: Option<&'state WhereClause>, +} + +impl<'input, 'state> MultiFieldData<'input, 'state> { + pub fn initializer<T: ToTokens>(&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<T: ToTokens>( + &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<T: ToTokens>(&self, initializers: &[T]) -> TokenStream { + self.multi_field_data.initializer(initializers) + } +} + +fn get_meta_info( + trait_attr: &str, + attrs: &[Attribute], + allowed_attr_params: &[&str], +) -> Result<MetaInfo> { + 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() { + Meta::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(", "), + ), + )); + } + } + Meta::List(list) => list, + Meta::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<NestedMeta, Token![,]>, + 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 { + Meta::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"), + )?; + } + + Meta::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 Meta::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), + )?; + } + } + + Meta::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 } + ), + )) + } + } + } + + Meta::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<bool>, + pub forward: Option<bool>, + pub owned: Option<bool>, + pub ref_: Option<bool>, + pub ref_mut: Option<bool>, + pub source: Option<bool>, + pub backtrace: Option<bool>, + #[cfg(any(feature = "from", feature = "into"))] + pub types: HashMap<RefType, HashSet<syn::Type>>, +} + +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<RefType> { + 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<syn::Type> { + self.info.types.get(&ref_type).cloned().unwrap_or_default() + } +} + +pub fn get_if_type_parameter_used_in_type( + type_parameters: &HashSet<syn::Ident>, + ty: &syn::Type, +) -> Option<syn::Type> { + 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<syn::Ident>, + 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, + } +} diff --git a/third_party/rust/derive_more/tests/add.rs b/third_party/rust/derive_more/tests/add.rs new file mode 100644 index 0000000000..f9ec5a77f3 --- /dev/null +++ b/third_party/rust/derive_more/tests/add.rs @@ -0,0 +1,23 @@ +#![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, +} diff --git a/third_party/rust/derive_more/tests/add_assign.rs b/third_party/rust/derive_more/tests/add_assign.rs new file mode 100644 index 0000000000..32681787ce --- /dev/null +++ b/third_party/rust/derive_more/tests/add_assign.rs @@ -0,0 +1,12 @@ +#![allow(dead_code)] +#[macro_use] +extern crate derive_more; + +#[derive(AddAssign)] +struct MyInts(i32, i32); + +#[derive(AddAssign)] +struct Point2D { + x: i32, + y: i32, +} diff --git a/third_party/rust/derive_more/tests/as_mut.rs b/third_party/rust/derive_more/tests/as_mut.rs new file mode 100644 index 0000000000..e074f8b02f --- /dev/null +++ b/third_party/rust/derive_more/tests/as_mut.rs @@ -0,0 +1,108 @@ +#![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<i32>); + +#[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<usize>); + +#[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<usize>, +} + +#[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<T> { + 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<T> { + #[as_mut] + first: Vec<T>, + #[as_mut] + second: PathBuf, + third: Vec<usize>, +} + +#[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())); +} diff --git a/third_party/rust/derive_more/tests/as_ref.rs b/third_party/rust/derive_more/tests/as_ref.rs new file mode 100644 index 0000000000..1e355d28fb --- /dev/null +++ b/third_party/rust/derive_more/tests/as_ref.rs @@ -0,0 +1,108 @@ +#![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<i32>); + +#[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<usize>); + +#[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<usize>, +} + +#[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<T> { + 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<T, U> { + #[as_ref] + first: Vec<T>, + #[as_ref] + second: [U; 2], + third: Vec<usize>, +} + +#[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())); +} diff --git a/third_party/rust/derive_more/tests/boats_display_derive.rs b/third_party/rust/derive_more/tests/boats_display_derive.rs new file mode 100644 index 0000000000..b64f75df84 --- /dev/null +++ b/third_party/rust/derive_more/tests/boats_display_derive.rs @@ -0,0 +1,57 @@ +// 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."); +} diff --git a/third_party/rust/derive_more/tests/constructor.rs b/third_party/rust/derive_more/tests/constructor.rs new file mode 100644 index 0000000000..07fddb8838 --- /dev/null +++ b/third_party/rust/derive_more/tests/constructor.rs @@ -0,0 +1,21 @@ +#![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, +} diff --git a/third_party/rust/derive_more/tests/deref.rs b/third_party/rust/derive_more/tests/deref.rs new file mode 100644 index 0000000000..8227f88f98 --- /dev/null +++ b/third_party/rust/derive_more/tests/deref.rs @@ -0,0 +1,68 @@ +#![allow(dead_code, unused_imports)] +#[macro_use] +extern crate derive_more; + +#[derive(Deref)] +#[deref(forward)] +struct MyBoxedInt(Box<i32>); + +#[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<i32>, +} + +#[derive(Deref)] +struct GenericVec<T>(Vec<T>); + +#[test] +fn deref_generic() { + let gv = GenericVec(Vec::<i32>::new()); + assert!(gv.is_empty()) +} + +#[derive(Deref)] +struct GenericBox<T>(#[deref(forward)] Box<T>); + +#[test] +fn deref_generic_forward() { + let boxed = GenericBox(Box::new(1i32)); + assert_eq!(*boxed, 1i32); +} diff --git a/third_party/rust/derive_more/tests/deref_mut.rs b/third_party/rust/derive_more/tests/deref_mut.rs new file mode 100644 index 0000000000..51a95e4f29 --- /dev/null +++ b/third_party/rust/derive_more/tests/deref_mut.rs @@ -0,0 +1,124 @@ +#![allow(dead_code, unused_imports)] +#[macro_use] +extern crate derive_more; + +#[derive(DerefMut)] +#[deref_mut(forward)] +struct MyBoxedInt(Box<i32>); +// Deref implementation is needed for DerefMut +impl ::core::ops::Deref for MyBoxedInt { + type Target = <Box<i32> as ::core::ops::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + <Box<i32> 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<i32>, +} +impl ::core::ops::Deref for CoolVec { + type Target = Vec<i32>; + #[inline] + fn deref(&self) -> &Self::Target { + &self.vec + } +} + +#[derive(DerefMut)] +struct GenericVec<T>(Vec<T>); + +impl<T> ::core::ops::Deref for GenericVec<T> { + type Target = Vec<T>; + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[test] +fn deref_mut_generic() { + let mut gv = GenericVec::<i32>(vec![42]); + assert!(gv.get_mut(0).is_some()); +} + +#[derive(DerefMut)] +struct GenericBox<T>(#[deref_mut(forward)] Box<T>); + +impl<T> ::core::ops::Deref for GenericBox<T> +where + Box<T>: ::core::ops::Deref, +{ + type Target = <Box<T> as ::core::ops::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + <Box<T> 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); +} diff --git a/third_party/rust/derive_more/tests/display.rs b/third_party/rust/derive_more/tests/display.rs new file mode 100644 index 0000000000..fae596b849 --- /dev/null +++ b/third_party/rust/derive_more/tests/display.rs @@ -0,0 +1,429 @@ +#![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>(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<T> { + field: T, + } + #[test] + fn named_generic_struct() { + assert_eq!(NamedGenericStruct { field: 1 }.to_string(), "Generic 1"); + } + + #[derive(Display)] + struct AutoNamedGenericStruct<T> { + 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>(T); + #[test] + fn unnamed_generic_struct() { + assert_eq!(UnnamedGenericStruct(2).to_string(), "Generic 2"); + } + + #[derive(Display)] + struct AutoUnnamedGenericStruct<T>(T); + #[test] + fn auto_unnamed_generic_struct() { + assert_eq!(AutoUnnamedGenericStruct(2).to_string(), "2"); + } + + #[derive(Display)] + enum GenericEnum<A, B> { + #[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::<u8, _>(2).to_string(), "Gen::B 2"); + } + + #[derive(Display)] + enum AutoGenericEnum<A, B> { + A { field: A }, + B(B), + } + #[test] + fn auto_generic_enum() { + assert_eq!(AutoGenericEnum::A::<_, u8> { field: 1 }.to_string(), "1"); + assert_eq!(AutoGenericEnum::B::<u8, _>(2).to_string(), "2"); + } + + #[derive(Display)] + #[display(fmt = "{} {} <-> {0:o} {1:#x} <-> {0:?} {1:X?}", a, b)] + struct MultiTraitNamedGenericStruct<A, B> { + 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>(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>(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<T: Trait> { + field: <T as Trait>::Type, + } + + let s = AutoGenericNamedStructAssociated::<Struct> { field: 10 }; + assert_eq!(s.to_string(), "10"); + } + + #[test] + fn auto_generic_unnamed_struct_associated() { + #[derive(Display)] + struct AutoGenericUnnamedStructAssociated<T: Trait>(<T as Trait>::Type); + + let s = AutoGenericUnnamedStructAssociated::<Struct>(10); + assert_eq!(s.to_string(), "10"); + } + + #[test] + fn auto_generic_enum_associated() { + #[derive(Display)] + enum AutoGenericEnumAssociated<T: Trait> { + Enumerator(<T as Trait>::Type), + } + + let e = AutoGenericEnumAssociated::<Struct>::Enumerator(10); + assert_eq!(e.to_string(), "10"); + } + } + + mod complex_type_field_enumerator { + use super::*; + + #[derive(Display)] + struct Struct<T>(T); + + #[test] + fn auto_generic_named_struct_complex() { + #[derive(Display)] + struct AutoGenericNamedStructComplex<T> { + field: Struct<T>, + } + + let s = AutoGenericNamedStructComplex { field: Struct(10) }; + assert_eq!(s.to_string(), "10"); + } + + #[test] + fn auto_generic_unnamed_struct_complex() { + #[derive(Display)] + struct AutoGenericUnnamedStructComplex<T>(Struct<T>); + + let s = AutoGenericUnnamedStructComplex(Struct(10)); + assert_eq!(s.to_string(), "10"); + } + + #[test] + fn auto_generic_enum_complex() { + #[derive(Display)] + enum AutoGenericEnumComplex<T> { + Enumerator(Struct<T>), + } + + 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<T: 'static>(&'static T); + + let s = AutoGenericStaticReference(&10); + assert_eq!(s.to_string(), "10"); + } + } + + mod indirect { + use super::*; + + #[derive(Display)] + struct Struct<T>(T); + + #[test] + fn auto_generic_indirect() { + #[derive(Display)] + struct AutoGenericIndirect<T: 'static>(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>(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>(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>(T1, T2); + + let s = Struct(10, 20); + assert_eq!(s.to_string(), "WHAT 10 EVER 20"); + } + } +} diff --git a/third_party/rust/derive_more/tests/error/derives_for_enums_with_source.rs b/third_party/rust/derive_more/tests/error/derives_for_enums_with_source.rs new file mode 100644 index 0000000000..2513ab60cd --- /dev/null +++ b/third_party/rust/derive_more/tests/error/derives_for_enums_with_source.rs @@ -0,0 +1,249 @@ +use 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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[test] +fn named_explicit_suppresses_implicit() { + let err = TestErr::NamedExplicitSuppressesImplicit { + source: 0, + field: SimpleErr, + }; + + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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()) +} diff --git a/third_party/rust/derive_more/tests/error/derives_for_generic_enums_with_source.rs b/third_party/rust/derive_more/tests/error/derives_for_generic_enums_with_source.rs new file mode 100644 index 0000000000..92f3b3ae9e --- /dev/null +++ b/third_party/rust/derive_more/tests/error/derives_for_generic_enums_with_source.rs @@ -0,0 +1,248 @@ +use super::*; + +derive_display!(TestErr, T, E); +#[derive(Debug, Error)] +enum TestErr<E, T> { + 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::<SimpleErr, i32>::Unit.source().is_none()); +} + +#[test] +fn named_implicit_no_source() { + let err = TestErr::<SimpleErr, _>::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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[test] +fn named_explicit_no_source_redundant() { + let err = TestErr::<SimpleErr, _>::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::<SimpleErr>()); +} + +#[test] +fn named_explicit_suppresses_implicit() { + let err = TestErr::NamedExplicitSuppressesImplicit { + source: 0, + field: SimpleErr, + }; + + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[test] +fn unnamed_implicit_no_source() { + let err = TestErr::<SimpleErr, _>::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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[test] +fn unnamed_explicit_no_source_redundant() { + let err = TestErr::<SimpleErr, _>::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::<SimpleErr>()); +} + +#[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::<SimpleErr, _>::NamedIgnoreRedundant { field: 0 }; + + assert!(err.source().is_none()); +} + +#[test] +fn unnamed_ignore_redundant() { + let err = TestErr::<SimpleErr, _>::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::<SimpleErr, _>::NamedVariantIgnoreRedundant { field: 0 }; + + assert!(err.source().is_none()); +} + +#[test] +fn unnamed_variant_ignore_redundant() { + let err = TestErr::<SimpleErr, _>::UnnamedVariantIgnoreRedundant(0, 0); + + assert!(err.source().is_none()) +} diff --git a/third_party/rust/derive_more/tests/error/derives_for_generic_structs_with_source.rs b/third_party/rust/derive_more/tests/error/derives_for_generic_structs_with_source.rs new file mode 100644 index 0000000000..248e3c97ff --- /dev/null +++ b/third_party/rust/derive_more/tests/error/derives_for_generic_structs_with_source.rs @@ -0,0 +1,245 @@ +use super::*; + +#[test] +fn named_implicit_no_source() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + struct TestErr<T> { + field: T, + } + + assert!(TestErr::<i32>::default().source().is_none()); +} + +#[test] +fn named_implicit_source() { + derive_display!(TestErr, E, T); + #[derive(Default, Debug, Error)] + struct TestErr<E, T> { + source: E, + field: T, + } + + let err = TestErr::<SimpleErr, i32>::default(); + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[test] +fn named_explicit_no_source() { + derive_display!(TestErr, E, T); + #[derive(Default, Debug, Error)] + struct TestErr<E, T> { + #[error(not(source))] + source: E, + field: T, + } + + let err = TestErr::<SimpleErr, i32>::default(); + assert!(err.source().is_none()); +} + +#[test] +fn named_explicit_source() { + derive_display!(TestErr, E, T); + #[derive(Default, Debug, Error)] + struct TestErr<E, T> { + #[error(source)] + explicit_source: E, + field: T, + } + + let err = TestErr::<SimpleErr, i32>::default(); + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[test] +fn named_explicit_no_source_redundant() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + struct TestErr<T> { + #[error(not(source))] + field: T, + } + + assert!(TestErr::<i32>::default().source().is_none()); +} + +#[test] +fn named_explicit_source_redundant() { + derive_display!(TestErr, E, T); + #[derive(Default, Debug, Error)] + struct TestErr<E, T> { + #[error(source)] + source: E, + field: T, + } + + let err = TestErr::<SimpleErr, i32>::default(); + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[test] +fn named_explicit_suppresses_implicit() { + derive_display!(TestErr, E, T); + #[derive(Default, Debug, Error)] + struct TestErr<E, T> { + source: E, + #[error(source)] + field: T, + } + + let err = TestErr::<i32, SimpleErr>::default(); + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[test] +fn unnamed_implicit_no_source() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + struct TestErr<T>(T, T); + + assert!(TestErr::<i32>::default().source().is_none()); +} + +#[test] +fn unnamed_implicit_source() { + derive_display!(TestErr, E); + #[derive(Default, Debug, Error)] + struct TestErr<E>(E); + + let err = TestErr::<SimpleErr>::default(); + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[test] +fn unnamed_explicit_no_source() { + derive_display!(TestErr, E); + #[derive(Default, Debug, Error)] + struct TestErr<E>(#[error(not(source))] E); + + assert!(TestErr::<SimpleErr>::default().source().is_none()); +} + +#[test] +fn unnamed_explicit_source() { + derive_display!(TestErr, E, T); + #[derive(Default, Debug, Error)] + struct TestErr<E, T>(#[error(source)] E, T); + + let err = TestErr::<SimpleErr, i32>::default(); + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[test] +fn unnamed_explicit_no_source_redundant() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + struct TestErr<T>(#[error(not(source))] T, #[error(not(source))] T); + + assert!(TestErr::<i32>::default().source().is_none()); +} + +#[test] +fn unnamed_explicit_source_redundant() { + derive_display!(TestErr, E); + #[derive(Default, Debug, Error)] + struct TestErr<E>(#[error(source)] E); + + let err = TestErr::<SimpleErr>::default(); + assert!(err.source().is_some()); + assert!(err.source().unwrap().is::<SimpleErr>()); +} + +#[test] +fn named_ignore() { + derive_display!(TestErr, E, T); + #[derive(Default, Debug, Error)] + struct TestErr<E, T> { + #[error(ignore)] + source: E, + field: T, + } + + assert!(TestErr::<SimpleErr, i32>::default().source().is_none()); +} + +#[test] +fn unnamed_ignore() { + derive_display!(TestErr, E); + #[derive(Default, Debug, Error)] + struct TestErr<E>(#[error(ignore)] E); + + assert!(TestErr::<SimpleErr>::default().source().is_none()); +} + +#[test] +fn named_ignore_redundant() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + struct TestErr<T> { + #[error(ignore)] + field: T, + } + + assert!(TestErr::<i32>::default().source().is_none()); +} + +#[test] +fn unnamed_ignore_redundant() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + struct TestErr<T>(#[error(ignore)] T, #[error(ignore)] T); + + assert!(TestErr::<i32>::default().source().is_none()); +} + +#[test] +fn named_struct_ignore() { + derive_display!(TestErr, E, T); + #[derive(Default, Debug, Error)] + #[error(ignore)] + struct TestErr<E, T> { + source: E, + field: T, + } + + assert!(TestErr::<SimpleErr, i32>::default().source().is_none()) +} + +#[test] +fn unnamed_struct_ignore() { + derive_display!(TestErr, E); + #[derive(Default, Debug, Error)] + #[error(ignore)] + struct TestErr<E>(E); + + assert!(TestErr::<SimpleErr>::default().source().is_none()) +} + +#[test] +fn named_struct_ignore_redundant() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + #[error(ignore)] + struct TestErr<T> { + field: T, + } + + assert!(TestErr::<i32>::default().source().is_none()) +} + +#[test] +fn unnamed_struct_ignore_redundant() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + #[error(ignore)] + struct TestErr<T>(T, T); + + assert!(TestErr::<i32>::default().source().is_none()) +} diff --git a/third_party/rust/derive_more/tests/error/derives_for_structs_with_source.rs b/third_party/rust/derive_more/tests/error/derives_for_structs_with_source.rs new file mode 100644 index 0000000000..d46bd5ad58 --- /dev/null +++ b/third_party/rust/derive_more/tests/error/derives_for_structs_with_source.rs @@ -0,0 +1,249 @@ +use 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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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::<SimpleErr>()); +} + +#[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()) +} diff --git a/third_party/rust/derive_more/tests/error/mod.rs b/third_party/rust/derive_more/tests/error/mod.rs new file mode 100644 index 0000000000..5d7190d8f7 --- /dev/null +++ b/third_party/rust/derive_more/tests/error/mod.rs @@ -0,0 +1,56 @@ +use 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<T, U> { +/// ... +/// } +/// +/// 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; + +#[cfg(feature = "nightly")] +mod nightly; + +derive_display!(SimpleErr); +#[derive(Default, Debug, Error)] +struct SimpleErr; diff --git a/third_party/rust/derive_more/tests/error/nightly/derives_for_enums_with_backtrace.rs b/third_party/rust/derive_more/tests/error/nightly/derives_for_enums_with_backtrace.rs new file mode 100644 index 0000000000..c4ff4817d6 --- /dev/null +++ b/third_party/rust/derive_more/tests/error/nightly/derives_for_enums_with_backtrace.rs @@ -0,0 +1,272 @@ +use super::*; + +derive_display!(TestErr); +#[derive(Debug, Error)] +enum TestErr { + Unit, + NamedImplicitNoBacktrace { + field: i32, + }, + NamedImplicitBacktraceByFieldName { + backtrace: MyBacktrace, + field: i32, + }, + NamedImplicitBacktraceByFieldType { + implicit_backtrace: Backtrace, + field: i32, + }, + NamedExplicitNoBacktraceByFieldName { + #[error(not(backtrace))] + backtrace: MyBacktrace, + field: i32, + }, + NamedExplicitNoBacktraceByFieldType { + #[error(not(backtrace))] + implicit_backtrace: Backtrace, + field: i32, + }, + NamedExplicitBacktrace { + #[error(backtrace)] + explicit_backtrace: MyBacktrace, + field: i32, + }, + NamedExplicitNoBacktraceRedundant { + #[error(not(backtrace))] + not_backtrace: MyBacktrace, + #[error(not(backtrace))] + field: i32, + }, + NamedExplicitBacktraceByFieldNameRedundant { + #[error(backtrace)] + backtrace: MyBacktrace, + field: i32, + }, + NamedExplicitBacktraceByFieldTypeRedundant { + #[error(backtrace)] + implicit_backtrace: Backtrace, + field: i32, + }, + NamedExplicitSupressesImplicit { + #[error(backtrace)] + not_backtrace: MyBacktrace, + backtrace: Backtrace, + field: i32, + }, + UnnamedImplicitNoBacktrace(i32, i32), + UnnamedImplicitBacktrace(Backtrace, i32, i32), + UnnamedExplicitNoBacktrace(#[error(not(backtrace))] Backtrace, i32), + UnnamedExplicitBacktrace(#[error(backtrace)] MyBacktrace, i32, i32), + UnnamedExplicitNoBacktraceRedundant( + #[error(not(backtrace))] MyBacktrace, + #[error(not(backtrace))] i32, + ), + UnnamedExplicitBacktraceRedundant(#[error(backtrace)] Backtrace, i32, i32), + UnnamedExplicitSupressesImplicit(#[error(backtrace)] MyBacktrace, Backtrace, i32), +} + +impl TestErr { + fn get_stored_backtrace(&self) -> &Backtrace { + match self { + Self::NamedImplicitBacktraceByFieldName { backtrace, .. } => backtrace, + Self::NamedImplicitBacktraceByFieldType { + implicit_backtrace, .. + } => implicit_backtrace, + Self::NamedExplicitBacktrace { + explicit_backtrace, .. + } => explicit_backtrace, + Self::NamedExplicitBacktraceByFieldNameRedundant { backtrace, .. } => { + backtrace + } + Self::NamedExplicitBacktraceByFieldTypeRedundant { + implicit_backtrace, + .. + } => implicit_backtrace, + Self::NamedExplicitSupressesImplicit { not_backtrace, .. } => not_backtrace, + Self::UnnamedImplicitBacktrace(backtrace, _, _) => backtrace, + Self::UnnamedExplicitBacktrace(backtrace, _, _) => backtrace, + Self::UnnamedExplicitBacktraceRedundant(backtrace, _, _) => backtrace, + Self::UnnamedExplicitSupressesImplicit(backtrace, _, _) => backtrace, + _ => panic!("ERROR IN TEST IMPLEMENTATION"), + } + } + + fn get_unused_backtrace(&self) -> &Backtrace { + match self { + Self::NamedExplicitSupressesImplicit { backtrace, .. } => backtrace, + Self::UnnamedExplicitSupressesImplicit(_, backtrace, _) => backtrace, + _ => panic!("ERROR IN TEST IMPLEMENTATION"), + } + } +} + +type MyBacktrace = Backtrace; + +#[test] +fn unit() { + assert!(TestErr::Unit.backtrace().is_none()); +} + +#[test] +fn named_implicit_no_backtrace() { + let err = TestErr::NamedImplicitNoBacktrace { field: 0 }; + + assert!(err.backtrace().is_none()); +} + +#[test] +fn named_implicit_backtrace_by_field_name() { + let err = TestErr::NamedImplicitBacktraceByFieldName { + backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_implicit_backtrace_by_field_type() { + let err = TestErr::NamedImplicitBacktraceByFieldType { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_explicit_no_backtrace_by_field_name() { + let err = TestErr::NamedExplicitNoBacktraceByFieldName { + backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_none()); +} + +#[test] +fn named_explicit_no_backtrace_by_field_type() { + let err = TestErr::NamedExplicitNoBacktraceByFieldType { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_none()); +} + +#[test] +fn named_explicit_backtrace() { + let err = TestErr::NamedExplicitBacktrace { + explicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_explicit_no_backtrace_redundant() { + let err = TestErr::NamedExplicitNoBacktraceRedundant { + not_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_none()); +} + +#[test] +fn named_explicit_backtrace_by_field_name_redundant() { + let err = TestErr::NamedExplicitBacktraceByFieldNameRedundant { + backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_explicit_backtrace_by_field_type_redundant() { + let err = TestErr::NamedExplicitBacktraceByFieldTypeRedundant { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_explicit_supresses_implicit() { + let err = TestErr::NamedExplicitSupressesImplicit { + not_backtrace: Backtrace::force_capture(), + backtrace: (|| Backtrace::force_capture())(), // ensure backtraces are different + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); + assert_bt!(!=, err, .get_unused_backtrace); +} + +#[test] +fn unnamed_implicit_no_backtrace() { + let err = TestErr::UnnamedImplicitNoBacktrace(0, 0); + + assert!(err.backtrace().is_none()); +} + +#[test] +fn unnamed_implicit_backtrace() { + let err = TestErr::UnnamedImplicitBacktrace(Backtrace::force_capture(), 0, 0); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn unnamed_explicit_no_backtrace() { + let err = TestErr::UnnamedExplicitNoBacktrace(Backtrace::force_capture(), 0); + + assert!(err.backtrace().is_none()); +} + +#[test] +fn unnamed_explicit_backtrace() { + let err = TestErr::UnnamedExplicitBacktrace(Backtrace::force_capture(), 0, 0); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn unnamed_explicit_no_backtrace_redundant() { + let err = + TestErr::UnnamedExplicitNoBacktraceRedundant(Backtrace::force_capture(), 0); + + assert!(err.backtrace().is_none()); +} + +#[test] +fn unnamed_explicit_backtrace_redundant() { + let err = + TestErr::UnnamedExplicitBacktraceRedundant(Backtrace::force_capture(), 0, 0); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn unnamed_explicit_supresses_implicit() { + let err = TestErr::UnnamedExplicitSupressesImplicit( + Backtrace::force_capture(), + (|| Backtrace::force_capture())(), // ensure backtraces are different + 0, + ); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); + assert_bt!(!=, err, .get_unused_backtrace); +} diff --git a/third_party/rust/derive_more/tests/error/nightly/derives_for_generic_enums_with_backtrace.rs b/third_party/rust/derive_more/tests/error/nightly/derives_for_generic_enums_with_backtrace.rs new file mode 100644 index 0000000000..8574751d02 --- /dev/null +++ b/third_party/rust/derive_more/tests/error/nightly/derives_for_generic_enums_with_backtrace.rs @@ -0,0 +1,272 @@ +use super::*; + +derive_display!(TestErr, T); +#[derive(Debug, Error)] +enum TestErr<T> { + Unit, + NamedImplicitNoBacktrace { + field: T, + }, + NamedImplicitBacktraceByFieldName { + backtrace: MyBacktrace, + field: T, + }, + NamedImplicitBacktraceByFieldType { + implicit_backtrace: Backtrace, + field: T, + }, + NamedExplicitNoBacktraceByFieldName { + #[error(not(backtrace))] + backtrace: MyBacktrace, + field: T, + }, + NamedExplicitNoBacktraceByFieldType { + #[error(not(backtrace))] + implicit_backtrace: Backtrace, + field: T, + }, + NamedExplicitBacktrace { + #[error(backtrace)] + explicit_backtrace: MyBacktrace, + field: T, + }, + NamedExplicitNoBacktraceRedundant { + #[error(not(backtrace))] + not_backtrace: MyBacktrace, + #[error(not(backtrace))] + field: T, + }, + NamedExplicitBacktraceByFieldNameRedundant { + #[error(backtrace)] + backtrace: MyBacktrace, + field: T, + }, + NamedExplicitBacktraceByFieldTypeRedundant { + #[error(backtrace)] + implicit_backtrace: Backtrace, + field: T, + }, + NamedExplicitSupressesImplicit { + #[error(backtrace)] + not_backtrace: MyBacktrace, + backtrace: Backtrace, + field: T, + }, + UnnamedImplicitNoBacktrace(T, T), + UnnamedImplicitBacktrace(Backtrace, T, T), + UnnamedExplicitNoBacktrace(#[error(not(backtrace))] Backtrace, T), + UnnamedExplicitBacktrace(#[error(backtrace)] MyBacktrace, T, T), + UnnamedExplicitNoBacktraceRedundant( + #[error(not(backtrace))] MyBacktrace, + #[error(not(backtrace))] T, + ), + UnnamedExplicitBacktraceRedundant(#[error(backtrace)] Backtrace, T, T), + UnnamedExplicitSupressesImplicit(#[error(backtrace)] MyBacktrace, Backtrace, T), +} + +impl<T> TestErr<T> { + fn get_stored_backtrace(&self) -> &Backtrace { + match self { + Self::NamedImplicitBacktraceByFieldName { backtrace, .. } => backtrace, + Self::NamedImplicitBacktraceByFieldType { + implicit_backtrace, .. + } => implicit_backtrace, + Self::NamedExplicitBacktrace { + explicit_backtrace, .. + } => explicit_backtrace, + Self::NamedExplicitBacktraceByFieldNameRedundant { backtrace, .. } => { + backtrace + } + Self::NamedExplicitBacktraceByFieldTypeRedundant { + implicit_backtrace, + .. + } => implicit_backtrace, + Self::NamedExplicitSupressesImplicit { not_backtrace, .. } => not_backtrace, + Self::UnnamedImplicitBacktrace(backtrace, _, _) => backtrace, + Self::UnnamedExplicitBacktrace(backtrace, _, _) => backtrace, + Self::UnnamedExplicitBacktraceRedundant(backtrace, _, _) => backtrace, + Self::UnnamedExplicitSupressesImplicit(backtrace, _, _) => backtrace, + _ => panic!("ERROR IN TEST IMPLEMENTATION"), + } + } + + fn get_unused_backtrace(&self) -> &Backtrace { + match self { + Self::NamedExplicitSupressesImplicit { backtrace, .. } => backtrace, + Self::UnnamedExplicitSupressesImplicit(_, backtrace, _) => backtrace, + _ => panic!("ERROR IN TEST IMPLEMENTATION"), + } + } +} + +type MyBacktrace = Backtrace; + +#[test] +fn unit() { + assert!(TestErr::<i32>::Unit.backtrace().is_none()); +} + +#[test] +fn named_implicit_no_backtrace() { + let err = TestErr::NamedImplicitNoBacktrace { field: 0 }; + + assert!(err.backtrace().is_none()); +} + +#[test] +fn named_implicit_backtrace_by_field_name() { + let err = TestErr::NamedImplicitBacktraceByFieldName { + backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_implicit_backtrace_by_field_type() { + let err = TestErr::NamedImplicitBacktraceByFieldType { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_explicit_no_backtrace_by_field_name() { + let err = TestErr::NamedExplicitNoBacktraceByFieldName { + backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_none()); +} + +#[test] +fn named_explicit_no_backtrace_by_field_type() { + let err = TestErr::NamedExplicitNoBacktraceByFieldType { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_none()); +} + +#[test] +fn named_explicit_backtrace() { + let err = TestErr::NamedExplicitBacktrace { + explicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_explicit_no_backtrace_redundant() { + let err = TestErr::NamedExplicitNoBacktraceRedundant { + not_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_none()); +} + +#[test] +fn named_explicit_backtrace_by_field_name_redundant() { + let err = TestErr::NamedExplicitBacktraceByFieldNameRedundant { + backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_explicit_backtrace_by_field_type_redundant() { + let err = TestErr::NamedExplicitBacktraceByFieldTypeRedundant { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn named_explicit_supresses_implicit() { + let err = TestErr::NamedExplicitSupressesImplicit { + not_backtrace: Backtrace::force_capture(), + backtrace: (|| Backtrace::force_capture())(), // ensure backtraces are different + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); + assert_bt!(!=, err, .get_unused_backtrace); +} + +#[test] +fn unnamed_implicit_no_backtrace() { + let err = TestErr::UnnamedImplicitNoBacktrace(0, 0); + + assert!(err.backtrace().is_none()); +} + +#[test] +fn unnamed_implicit_backtrace() { + let err = TestErr::UnnamedImplicitBacktrace(Backtrace::force_capture(), 0, 0); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn unnamed_explicit_no_backtrace() { + let err = TestErr::UnnamedExplicitNoBacktrace(Backtrace::force_capture(), 0); + + assert!(err.backtrace().is_none()); +} + +#[test] +fn unnamed_explicit_backtrace() { + let err = TestErr::UnnamedExplicitBacktrace(Backtrace::force_capture(), 0, 0); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn unnamed_explicit_no_backtrace_redundant() { + let err = + TestErr::UnnamedExplicitNoBacktraceRedundant(Backtrace::force_capture(), 0); + + assert!(err.backtrace().is_none()); +} + +#[test] +fn unnamed_explicit_backtrace_redundant() { + let err = + TestErr::UnnamedExplicitBacktraceRedundant(Backtrace::force_capture(), 0, 0); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); +} + +#[test] +fn unnamed_explicit_supresses_implicit() { + let err = TestErr::UnnamedExplicitSupressesImplicit( + Backtrace::force_capture(), + (|| Backtrace::force_capture())(), // ensure backtraces are different + 0, + ); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, .get_stored_backtrace); + assert_bt!(!=, err, .get_unused_backtrace); +} diff --git a/third_party/rust/derive_more/tests/error/nightly/derives_for_generic_structs_with_backtrace.rs b/third_party/rust/derive_more/tests/error/nightly/derives_for_generic_structs_with_backtrace.rs new file mode 100644 index 0000000000..91df87c82a --- /dev/null +++ b/third_party/rust/derive_more/tests/error/nightly/derives_for_generic_structs_with_backtrace.rs @@ -0,0 +1,275 @@ +use super::*; + +#[test] +fn named_implicit_no_backtrace() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + struct TestErr<T> { + field: T, + } + + assert!(TestErr::<i32>::default().backtrace().is_none()); +} + +#[test] +fn named_implicit_backtrace_by_field_name() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + backtrace: MyBacktrace, + field: T, + } + + type MyBacktrace = Backtrace; + + let err = TestErr { + backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err); +} + +#[test] +fn named_implicit_backtrace_by_field_type() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + implicit_backtrace: Backtrace, + field: T, + } + + let err = TestErr { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err, implicit_backtrace); +} + +#[test] +fn named_explicit_no_backtrace_by_field_name() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + #[error(not(backtrace))] + backtrace: MyBacktrace, + field: T, + } + + type MyBacktrace = Backtrace; + + assert!(TestErr { + backtrace: Backtrace::force_capture(), + field: 0 + } + .backtrace() + .is_none()); +} + +#[test] +fn named_explicit_no_backtrace_by_field_type() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + #[error(not(backtrace))] + implicit_backtrace: Backtrace, + field: T, + } + + assert!(TestErr { + implicit_backtrace: Backtrace::force_capture(), + field: 0 + } + .backtrace() + .is_none()); +} + +#[test] +fn named_explicit_backtrace() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + #[error(backtrace)] + explicit_backtrace: MyBacktrace, + field: T, + } + + type MyBacktrace = Backtrace; + + let err = TestErr { + explicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err, explicit_backtrace); +} + +#[test] +fn named_explicit_no_backtrace_redundant() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + #[error(not(backtrace))] + not_backtrace: MyBacktrace, + #[error(not(backtrace))] + field: T, + } + + type MyBacktrace = Backtrace; + + assert!(TestErr { + not_backtrace: Backtrace::force_capture(), + field: 0 + } + .backtrace() + .is_none()); +} + +#[test] +fn named_explicit_backtrace_by_field_name_redundant() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + #[error(backtrace)] + backtrace: MyBacktrace, + field: T, + } + + type MyBacktrace = Backtrace; + + let err = TestErr { + backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err); +} + +#[test] +fn named_explicit_backtrace_by_field_type_redundant() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + #[error(backtrace)] + implicit_backtrace: Backtrace, + field: T, + } + + let err = TestErr { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err, implicit_backtrace); +} + +#[test] +fn named_explicit_supresses_implicit() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T> { + #[error(backtrace)] + not_backtrace: MyBacktrace, + backtrace: Backtrace, + field: T, + } + + type MyBacktrace = Backtrace; + + let err = TestErr { + not_backtrace: Backtrace::force_capture(), + backtrace: (|| Backtrace::force_capture())(), // ensure backtraces are different + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, not_backtrace); + assert_bt!(!=, err); +} + +#[test] +fn unnamed_implicit_no_backtrace() { + derive_display!(TestErr, T); + #[derive(Default, Debug, Error)] + struct TestErr<T>(T, T); + + assert!(TestErr::<i32>::default().backtrace().is_none()); +} + +#[test] +fn unnamed_implicit_backtrace() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T>(Backtrace, T, T); + + let err = TestErr(Backtrace::force_capture(), 0, 0); + assert!(err.backtrace().is_some()); + assert_bt!(==, err, 0); +} + +#[test] +fn unnamed_explicit_no_backtrace() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T>(#[error(not(backtrace))] Backtrace, T); + + assert!(TestErr(Backtrace::force_capture(), 0).backtrace().is_none()); +} + +#[test] +fn unnamed_explicit_backtrace() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T>(#[error(backtrace)] MyBacktrace, T, T); + + type MyBacktrace = Backtrace; + + let err = TestErr(Backtrace::force_capture(), 0, 0); + assert!(err.backtrace().is_some()); + assert_bt!(==, err, 0); +} + +#[test] +fn unnamed_explicit_no_backtrace_redundant() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T>( + #[error(not(backtrace))] MyBacktrace, + #[error(not(backtrace))] T, + ); + + type MyBacktrace = Backtrace; + + assert!(TestErr(Backtrace::force_capture(), 0).backtrace().is_none()); +} + +#[test] +fn unnamed_explicit_backtrace_redundant() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T>(#[error(backtrace)] Backtrace, T, T); + + let err = TestErr(Backtrace::force_capture(), 0, 0); + assert!(err.backtrace().is_some()); + assert_bt!(==, err, 0); +} + +#[test] +fn unnamed_explicit_supresses_implicit() { + derive_display!(TestErr, T); + #[derive(Debug, Error)] + struct TestErr<T>(#[error(backtrace)] MyBacktrace, Backtrace, T); + + type MyBacktrace = Backtrace; + + let err = TestErr( + Backtrace::force_capture(), + (|| Backtrace::force_capture())(), // ensure backtraces are different + 0, + ); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, 0); + assert_bt!(!=, err, 1); +} diff --git a/third_party/rust/derive_more/tests/error/nightly/derives_for_structs_with_backtrace.rs b/third_party/rust/derive_more/tests/error/nightly/derives_for_structs_with_backtrace.rs new file mode 100644 index 0000000000..18e268f841 --- /dev/null +++ b/third_party/rust/derive_more/tests/error/nightly/derives_for_structs_with_backtrace.rs @@ -0,0 +1,280 @@ +use super::*; + +#[test] +fn unit() { + assert!(SimpleErr.backtrace().is_none()); +} + +#[test] +fn named_implicit_no_backtrace() { + derive_display!(TestErr); + #[derive(Default, Debug, Error)] + struct TestErr { + field: i32, + } + + assert!(TestErr::default().backtrace().is_none()); +} + +#[test] +fn named_implicit_backtrace_by_field_name() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + backtrace: MyBacktrace, + field: i32, + } + + type MyBacktrace = Backtrace; + + let err = TestErr { + backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err); +} + +#[test] +fn named_implicit_backtrace_by_field_type() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + implicit_backtrace: Backtrace, + field: i32, + } + + let err = TestErr { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err, implicit_backtrace); +} + +#[test] +fn named_explicit_no_backtrace_by_field_name() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + #[error(not(backtrace))] + backtrace: MyBacktrace, + field: i32, + } + + type MyBacktrace = Backtrace; + + assert!(TestErr { + backtrace: Backtrace::force_capture(), + field: 0 + } + .backtrace() + .is_none()); +} + +#[test] +fn named_explicit_no_backtrace_by_field_type() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + #[error(not(backtrace))] + implicit_backtrace: Backtrace, + field: i32, + } + + assert!(TestErr { + implicit_backtrace: Backtrace::force_capture(), + field: 0 + } + .backtrace() + .is_none()); +} + +#[test] +fn named_explicit_backtrace() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + #[error(backtrace)] + explicit_backtrace: MyBacktrace, + field: i32, + } + + type MyBacktrace = Backtrace; + + let err = TestErr { + explicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err, explicit_backtrace); +} + +#[test] +fn named_explicit_no_backtrace_redundant() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + #[error(not(backtrace))] + not_backtrace: MyBacktrace, + #[error(not(backtrace))] + field: i32, + } + + type MyBacktrace = Backtrace; + + assert!(TestErr { + not_backtrace: Backtrace::force_capture(), + field: 0 + } + .backtrace() + .is_none()); +} + +#[test] +fn named_explicit_backtrace_by_field_name_redundant() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + #[error(backtrace)] + backtrace: MyBacktrace, + field: i32, + } + + type MyBacktrace = Backtrace; + + let err = TestErr { + backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err); +} + +#[test] +fn named_explicit_backtrace_by_field_type_redundant() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + #[error(backtrace)] + implicit_backtrace: Backtrace, + field: i32, + } + + let err = TestErr { + implicit_backtrace: Backtrace::force_capture(), + field: 0, + }; + assert!(err.backtrace().is_some()); + assert_bt!(==, err, implicit_backtrace); +} + +#[test] +fn named_explicit_supresses_implicit() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr { + #[error(backtrace)] + not_backtrace: MyBacktrace, + backtrace: Backtrace, + field: i32, + } + + type MyBacktrace = Backtrace; + + let err = TestErr { + not_backtrace: Backtrace::force_capture(), + backtrace: (|| Backtrace::force_capture())(), // ensure backtraces are different + field: 0, + }; + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, not_backtrace); + assert_bt!(!=, err); +} + +#[test] +fn unnamed_implicit_no_backtrace() { + derive_display!(TestErr); + #[derive(Default, Debug, Error)] + struct TestErr(i32, i32); + + assert!(TestErr::default().backtrace().is_none()); +} + +#[test] +fn unnamed_implicit_backtrace() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr(Backtrace, i32, i32); + + let err = TestErr(Backtrace::force_capture(), 0, 0); + assert!(err.backtrace().is_some()); + assert_bt!(==, err, 0); +} + +#[test] +fn unnamed_explicit_no_backtrace() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr(#[error(not(backtrace))] Backtrace, i32); + + assert!(TestErr(Backtrace::force_capture(), 0).backtrace().is_none()); +} + +#[test] +fn unnamed_explicit_backtrace() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr(#[error(backtrace)] MyBacktrace, i32, i32); + + type MyBacktrace = Backtrace; + + let err = TestErr(Backtrace::force_capture(), 0, 0); + assert!(err.backtrace().is_some()); + assert_bt!(==, err, 0); +} + +#[test] +fn unnamed_explicit_no_backtrace_redundant() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr( + #[error(not(backtrace))] MyBacktrace, + #[error(not(backtrace))] i32, + ); + + type MyBacktrace = Backtrace; + + assert!(TestErr(Backtrace::force_capture(), 0).backtrace().is_none()); +} + +#[test] +fn unnamed_explicit_backtrace_redundant() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr(#[error(backtrace)] Backtrace, i32, i32); + + let err = TestErr(Backtrace::force_capture(), 0, 0); + assert!(err.backtrace().is_some()); + assert_bt!(==, err, 0); +} + +#[test] +fn unnamed_explicit_supresses_implicit() { + derive_display!(TestErr); + #[derive(Debug, Error)] + struct TestErr(#[error(backtrace)] MyBacktrace, Backtrace, i32); + + type MyBacktrace = Backtrace; + + let err = TestErr( + Backtrace::force_capture(), + (|| Backtrace::force_capture())(), // ensure backtraces are different + 0, + ); + + assert!(err.backtrace().is_some()); + assert_bt!(==, err, 0); + assert_bt!(!=, err, 1); +} diff --git a/third_party/rust/derive_more/tests/error/nightly/mod.rs b/third_party/rust/derive_more/tests/error/nightly/mod.rs new file mode 100644 index 0000000000..57de7ba2ab --- /dev/null +++ b/third_party/rust/derive_more/tests/error/nightly/mod.rs @@ -0,0 +1,85 @@ +use std::backtrace::Backtrace; + +use super::*; + +/// Asserts that backtrace returned by `Error::backtrace` method equals/not-equals +/// backtrace stored in object itself. +/// +/// Comparison is done by converting backtraces to strings +/// and then comparing these strings. +/// +/// ## Syntax +/// +/// * Equals: `assert_bt!(==, ...)` +/// * Not-equals: `assert_bt!(!=, ...)` +/// +/// ### Backtrace Access +/// +/// Shortcut for named-structs with `backtrace` field. +/// Access backtrace as `error.backtrace`. +/// +/// ``` +/// assert_bt!(==, error); +/// ``` +/// +/// Full form for named- and tuple-structs. +/// Access backtrace as `error.some_other_field` and `error.1` respectively. +/// +/// ``` +/// assert_bt!(!=, error, some_other_field); +/// assert_bt!(==, error, 1); +/// ``` +/// +/// Access as a method call. +/// Useful for enums (i.e., you can define a method that will match on enum variants +/// and return backtrace for each variant). +/// Access backtrace as `error.get_stored_backtrace_method()`. +/// +/// ``` +/// assert_bt!(!=, error, .get_stored_backtrace_method); +/// ``` +macro_rules! assert_bt { + (@impl $macro:ident, $error:expr, $backtrace:expr) => { + $macro!($error.backtrace().unwrap().to_string(), $backtrace.to_string()); + }; + (@expand $macro:ident, $error:expr, .$backtrace:ident) => { + assert_bt!(@impl $macro, $error, $error.$backtrace()) + }; + (@expand $macro:ident, $error:expr, $backtrace:tt) => { + assert_bt!(@impl $macro, $error, $error.$backtrace) + }; + (@expand $macro:ident, $error:expr) => { + assert_bt!(@expand $macro, $error, backtrace) + }; + (==, $($args:tt)*) => { + assert_bt!(@expand assert_eq, $($args)*) + }; + (!=, $($args:tt)*) => { + assert_bt!(@expand assert_ne, $($args)*) + }; +} + +mod derives_for_enums_with_backtrace; +mod derives_for_generic_enums_with_backtrace; +mod derives_for_generic_structs_with_backtrace; +mod derives_for_structs_with_backtrace; + +derive_display!(BacktraceErr); +#[derive(Debug)] +struct BacktraceErr { + backtrace: Backtrace, +} + +impl Default for BacktraceErr { + fn default() -> Self { + Self { + backtrace: Backtrace::force_capture(), + } + } +} + +impl Error for BacktraceErr { + fn backtrace(&self) -> Option<&Backtrace> { + Some(&self.backtrace) + } +} diff --git a/third_party/rust/derive_more/tests/error_tests.rs b/third_party/rust/derive_more/tests/error_tests.rs new file mode 100644 index 0000000000..c2798bd148 --- /dev/null +++ b/third_party/rust/derive_more/tests/error_tests.rs @@ -0,0 +1,6 @@ +#![cfg_attr(feature = "nightly", feature(backtrace))] + +#[macro_use] +extern crate derive_more; + +mod error; diff --git a/third_party/rust/derive_more/tests/from.rs b/third_party/rust/derive_more/tests/from.rs new file mode 100644 index 0000000000..63bb102019 --- /dev/null +++ b/third_party/rust/derive_more/tests/from.rs @@ -0,0 +1,187 @@ +#![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()); +} diff --git a/third_party/rust/derive_more/tests/from_str.rs b/third_party/rust/derive_more/tests/from_str.rs new file mode 100644 index 0000000000..4bb0eca636 --- /dev/null +++ b/third_party/rust/derive_more/tests/from_str.rs @@ -0,0 +1,11 @@ +#![allow(dead_code)] +#[macro_use] +extern crate derive_more; + +#[derive(FromStr)] +struct MyInt(i32); + +#[derive(FromStr)] +struct Point1D { + x: i32, +} diff --git a/third_party/rust/derive_more/tests/generics.rs b/third_party/rust/derive_more/tests/generics.rs new file mode 100644 index 0000000000..17af5f397e --- /dev/null +++ b/third_party/rust/derive_more/tests/generics.rs @@ -0,0 +1,123 @@ +#![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: Clone>(T); + +#[derive(Deref, DerefMut)] +struct Wrapped2<T: Clone>(T); + +#[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)] +struct WrappedDouble<T: Clone, U: Clone>(T, U); + +#[derive(From)] +#[from(forward)] +struct WrappedDouble2<T: Clone, U: Clone>(T, U); + +#[cfg(feature = "nightly")] +#[derive( + From, + FromStr, + Display, + Index, + Not, + Add, + Mul, + Sum, + IndexMut, + AddAssign, + MulAssign, + Deref, + DerefMut, + IntoIterator, + Constructor +)] +struct WrappedWithConst<T, const C: u32>(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: Clone> { + t: T, +} + +#[derive(Deref, DerefMut)] +struct Struct2<T: Clone> { + t: T, +} + +#[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)] +struct DoubleStruct<T: Clone, U: Clone> { + t: T, + u: U, +} + +#[derive(From)] +#[from(forward)] +struct DoubleStruct2<T: Clone, U: Clone> { + t: T, + u: U, +} + +#[derive(From, Not, Add)] +enum TupleEnum<T: Clone, U: Clone> { + Tuple(T), + DoubleTuple(T, U), +} + +#[derive(From)] +#[from(forward)] +enum TupleEnum2<T: Clone, U: Clone, X: Clone> { + DoubleTuple(T, U), + TripleTuple(T, U, X), +} + +#[derive(From, Not, Add)] +enum StructEnum<T: Clone, U: Clone> { + Struct { t: T }, + DoubleStruct { t: T, u: U }, +} + +#[derive(From)] +#[from(forward)] +enum StructEnum2<T: Clone, U: Clone, X: Clone> { + DoubleStruct { t: T, u: U }, + TripleStruct { t: T, u: U, x: X }, +} diff --git a/third_party/rust/derive_more/tests/index.rs b/third_party/rust/derive_more/tests/index.rs new file mode 100644 index 0000000000..952223c09b --- /dev/null +++ b/third_party/rust/derive_more/tests/index.rs @@ -0,0 +1,13 @@ +#![allow(dead_code, unused_imports)] +#[macro_use] +extern crate derive_more; + +#[derive(Index)] +struct MyVec(Vec<i32>); + +#[derive(Index)] +struct Numbers { + #[index] + numbers: Vec<i32>, + useless: bool, +} diff --git a/third_party/rust/derive_more/tests/index_mut.rs b/third_party/rust/derive_more/tests/index_mut.rs new file mode 100644 index 0000000000..a053fd332b --- /dev/null +++ b/third_party/rust/derive_more/tests/index_mut.rs @@ -0,0 +1,36 @@ +#![allow(dead_code, unused_imports)] +#[macro_use] +extern crate derive_more; + +#[derive(IndexMut)] +struct MyVec(Vec<i32>); +//Index implementation is required for IndexMut +impl<__IdxT> ::core::ops::Index<__IdxT> for MyVec +where + Vec<i32>: ::core::ops::Index<__IdxT>, +{ + type Output = <Vec<i32> as ::core::ops::Index<__IdxT>>::Output; + #[inline] + fn index(&self, idx: __IdxT) -> &Self::Output { + <Vec<i32> as ::core::ops::Index<__IdxT>>::index(&self.0, idx) + } +} + +#[derive(IndexMut)] +struct Numbers { + #[index_mut] + numbers: Vec<i32>, + useless: bool, +} + +//Index implementation is required for IndexMut +impl<__IdxT> ::core::ops::Index<__IdxT> for Numbers +where + Vec<i32>: ::core::ops::Index<__IdxT>, +{ + type Output = <Vec<i32> as ::core::ops::Index<__IdxT>>::Output; + #[inline] + fn index(&self, idx: __IdxT) -> &Self::Output { + <Vec<i32> as ::core::ops::Index<__IdxT>>::index(&self.numbers, idx) + } +} diff --git a/third_party/rust/derive_more/tests/into.rs b/third_party/rust/derive_more/tests/into.rs new file mode 100644 index 0000000000..075abd1c98 --- /dev/null +++ b/third_party/rust/derive_more/tests/into.rs @@ -0,0 +1,141 @@ +#![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)); +} diff --git a/third_party/rust/derive_more/tests/into_iterator.rs b/third_party/rust/derive_more/tests/into_iterator.rs new file mode 100644 index 0000000000..8c0e48f571 --- /dev/null +++ b/third_party/rust/derive_more/tests/into_iterator.rs @@ -0,0 +1,39 @@ +#![allow(dead_code, unused_imports)] +#[macro_use] +extern crate derive_more; + +#[derive(IntoIterator)] +#[into_iterator(owned, ref, ref_mut)] +struct MyVec(Vec<i32>); + +#[derive(IntoIterator)] +#[into_iterator(owned, ref, ref_mut)] +struct Numbers { + numbers: Vec<i32>, +} + +#[derive(IntoIterator)] +struct Numbers2 { + #[into_iterator(owned, ref, ref_mut)] + numbers: Vec<i32>, + useless: bool, + useless2: bool, +} + +#[derive(IntoIterator)] +struct Numbers3 { + #[into_iterator(ref, ref_mut)] + numbers: Vec<i32>, + 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 = <Vec<i32> as ::core::iter::IntoIterator>::Item; + type IntoIter = <Vec<i32> as ::core::iter::IntoIterator>::IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + <Vec<i32> as ::core::iter::IntoIterator>::into_iter(self.numbers) + } +} diff --git a/third_party/rust/derive_more/tests/is_variant.rs b/third_party/rust/derive_more/tests/is_variant.rs new file mode 100644 index 0000000000..10876a40b3 --- /dev/null +++ b/third_party/rust/derive_more/tests/is_variant.rs @@ -0,0 +1,57 @@ +#![allow(dead_code)] + +#[macro_use] +extern crate derive_more; + +#[derive(IsVariant)] +enum Either<TLeft, TRight> { + Left(TLeft), + Right(TRight), +} + +#[derive(IsVariant)] +enum Maybe<T> { + 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<T> +where + T: Copy, +{ + One(T), + Two, +} +#[derive(IsVariant)] +enum KitchenSink<'a, 'b, T1: Copy, T2: Clone> +where + T2: Into<T1> + '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()); +} diff --git a/third_party/rust/derive_more/tests/lib.rs b/third_party/rust/derive_more/tests/lib.rs new file mode 100644 index 0000000000..27fd53d331 --- /dev/null +++ b/third_party/rust/derive_more/tests/lib.rs @@ -0,0 +1,275 @@ +#[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<i32>); + +#[derive(Eq, PartialEq, Debug)] +#[derive(Deref, DerefMut)] +#[deref(forward)] +#[deref_mut(forward)] +struct MyBoxedInt(Box<i32>); + +#[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) +} diff --git a/third_party/rust/derive_more/tests/mul.rs b/third_party/rust/derive_more/tests/mul.rs new file mode 100644 index 0000000000..192806032d --- /dev/null +++ b/third_party/rust/derive_more/tests/mul.rs @@ -0,0 +1,20 @@ +#![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, +} diff --git a/third_party/rust/derive_more/tests/mul_assign.rs b/third_party/rust/derive_more/tests/mul_assign.rs new file mode 100644 index 0000000000..f8aee3e189 --- /dev/null +++ b/third_party/rust/derive_more/tests/mul_assign.rs @@ -0,0 +1,32 @@ +#![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<T> { + x: i32, + ph: PhantomData<T>, +} diff --git a/third_party/rust/derive_more/tests/no_std.rs b/third_party/rust/derive_more/tests/no_std.rs new file mode 100644 index 0000000000..a6680c38c2 --- /dev/null +++ b/third_party/rust/derive_more/tests/no_std.rs @@ -0,0 +1,74 @@ +#![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: Clone>(T); + +#[derive(Deref, DerefMut)] +struct Wrapped2<T: Clone>(T); + +#[derive(From, Not, Add, Mul, AddAssign, Constructor, Sum)] +struct WrappedDouble<T: Clone, U: Clone>(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, +} diff --git a/third_party/rust/derive_more/tests/not.rs b/third_party/rust/derive_more/tests/not.rs new file mode 100644 index 0000000000..7e3ad8d01e --- /dev/null +++ b/third_party/rust/derive_more/tests/not.rs @@ -0,0 +1,28 @@ +#![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, +} diff --git a/third_party/rust/derive_more/tests/sum.rs b/third_party/rust/derive_more/tests/sum.rs new file mode 100644 index 0000000000..a0b0967bd9 --- /dev/null +++ b/third_party/rust/derive_more/tests/sum.rs @@ -0,0 +1,31 @@ +#[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), + } + } +} diff --git a/third_party/rust/derive_more/tests/try_into.rs b/third_party/rust/derive_more/tests/try_into.rs new file mode 100644 index 0000000000..837c8e9913 --- /dev/null +++ b/third_party/rust/derive_more/tests/try_into.rs @@ -0,0 +1,199 @@ +#![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()); +} diff --git a/third_party/rust/derive_more/tests/unwrap.rs b/third_party/rust/derive_more/tests/unwrap.rs new file mode 100644 index 0000000000..ec84f7de96 --- /dev/null +++ b/third_party/rust/derive_more/tests/unwrap.rs @@ -0,0 +1,62 @@ +#![allow(dead_code)] + +#[macro_use] +extern crate derive_more; + +#[derive(Unwrap)] +enum Either<TLeft, TRight> { + Left(TLeft), + Right(TRight), +} + +#[derive(Unwrap)] +enum Maybe<T> { + 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<T> +where + T: Copy, +{ + One(T), + Two, +} +#[derive(Unwrap)] +enum KitchenSink<'a, 'b, T1: Copy, T2: Clone> +where + T2: Into<T1> + '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() +} |