diff options
Diffstat (limited to 'third_party/rust/derive_more-impl')
59 files changed, 10645 insertions, 0 deletions
diff --git a/third_party/rust/derive_more-impl/.cargo-checksum.json b/third_party/rust/derive_more-impl/.cargo-checksum.json new file mode 100644 index 0000000000..c6cc635852 --- /dev/null +++ b/third_party/rust/derive_more-impl/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"79cc66b8dc35ff10185c05aac941e61cc8ea22ea43d7d606874413470c4de147","LICENSE":"8a35369f3ca263b3c62fbb5032947e53b6bfebc6c8a4d1bb982de1c069f6fba5","README.md":"9ef58c81f6e1e03c19aacdb4cc0e96370497e4566db2c495c15d824f59a948ac","doc/add.md":"3e8764b90f4ccf06e7903f63c6a29af933b65ee8f39975bf83d7028fc14537d7","doc/add_assign.md":"7a67a1d5e147d4a37f9c81ec7c50bd02b5c469c48b39875ad06d92592dadc73d","doc/as_mut.md":"59d4fbfb4dc30502f00aba899d4b6a12da9a114ad9c53fa803ae7103049abf6c","doc/as_ref.md":"892562f3b3c7214932f75ae3e2c2c75615a2f54523fd2275393a5bc0fc1049da","doc/constructor.md":"1efface08ac87ce8f53b0a22dd0af4b812c8de6a7b74679a4305136efb60a968","doc/debug.md":"82bd046725cf487f3ddd32cabe9366205fea8689f63184e12488e6461afe97f4","doc/deref.md":"d91ada503cfc2744aeba89135bcaf8bb75494e8ed4a59e8d523fe4294ae9fa30","doc/deref_mut.md":"8d74d418127ef517baa87da9499ffc3f5a617bbb392b8103011435dd5992950b","doc/display.md":"b340ad60fad4cec93a5ee539a702293fc54f49fcab003b2fb9ce6ec0f21d9ffd","doc/error.md":"650bd28511b68823b5d7578469c4b15920c093555c31a88bef8cd6b6a15853fd","doc/from.md":"3317f1cd37f9b0615329016c10db0b909274117516408e276f65afbcda2e38ae","doc/from_str.md":"f434e28a9c9bac1161af90ea833a1bcea38c52de07cee235750342ecfd76ae2d","doc/index.md":"54c194da4ce8753b2c0a708e5d1efbd1c718f39408c582165fd9298ca9584d49","doc/index_mut.md":"cf8df23ddbedc85b57cbc5a91d0be1408fa2e6ed1c0b91b577bbde5904737e7a","doc/into.md":"9f4207cc211eec76868bf6ca757ad225ce4a3f77418e3e333483f644389c2168","doc/into_iterator.md":"0f31affff9f809d54cd4bfe2ce206e3b6d126f635f0d2afa3ec45e3aee33f6db","doc/is_variant.md":"baa1cef7c8a6d700c410729d4a4e4c25790653cb8453439850ca98787924008f","doc/mul.md":"b6d7851263730b36039ea96947bffea82cae509c31d86c289740b1cead22f6da","doc/mul_assign.md":"32d5db458af1c45c4461650f8f2e32e12a5dab6ed7fa31d2a67f849465ab8945","doc/not.md":"702d0661b9413d4d63815999e0e35ae88dc53428ed9f625e7c4930d47f13af0c","doc/sum.md":"ae064095e5d32ee2f273a033bc5459b06a74add1036f43edd8ac65240195a9f9","doc/try_into.md":"221b3037a686d672bbd2ae22e527931e88e874e88670d5e301db30881c0a0821","doc/try_unwrap.md":"d316d613515e5a704d340659ceead0354e282df136d5286ade5e5b26e638156c","doc/unwrap.md":"d8a5d3393e3da685869f50f9aab8d3ab992e4bb0cd47415b5127f12ae04e0b86","src/add_assign_like.rs":"52fbff906fc8c5e9ac709448a555618f20d31947ce78245684502c84c64f0fb5","src/add_helpers.rs":"fb08a98fa061a64cdf23f8fd8442d9721d32c20427a4b46fa1a4ee5d99e9a609","src/add_like.rs":"4f779f110136975e064851a149471082541cd04e79cbc1f64b06679af2ef6964","src/as_mut.rs":"ce1aaff0318ceedd5aba2f29db97840e7680b13a78b8554eeaf3f34f24560336","src/as_ref.rs":"abec5e9230d787fcf91555400a7e2db5c8da9f54e50994d25ccca94bb19740bf","src/constructor.rs":"11c043caa501f2c21154e1bbe14b247027c813b994162e0f788a29c8a06580f2","src/deref.rs":"43e715383c06844fe555e34f8e4be65ddaa37f7c96da645707ec0a8e3b4217fa","src/deref_mut.rs":"8bea9c9797e51490a31d4138caf3c015a09e74719fcc3a8939509a04709e6468","src/error.rs":"d7dee4d5f4bbcfd40592476da1247d8b47ca4c49996fa53ebbea81e359446005","src/fmt/debug.rs":"8c9691db074499d0b7b1745d3c74cda5ea9504d98ad85f9076799dcfebf95890","src/fmt/display.rs":"9c66c05c79a4cdcf3f27227e3fef7634250c8cc8f160eea56e02448d6e24d08e","src/fmt/mod.rs":"b8be648a76fa1591e3ec1ace29950e0ff573a31797b36399bb7c47bac2d9673e","src/fmt/parsing.rs":"12aabefd35c2575b3d7e65d5871e2e73c898b4b08debc6d6446971d0b170dc04","src/from.rs":"5d950436eb4d169d07b729c15427fec1a75fe78f794addf0542041d20cdc4b7e","src/from_str.rs":"7af011a1a72d362ca61d1790540b803b63ce96e6d418c70c98b7c101a06ac179","src/index.rs":"6604e4c89286cfcb4973335cc8e680e4f2b92d5cfc22e2e88911f867dff65993","src/index_mut.rs":"ed30934c9df2614095877320e1ed046fe4bc6b6c573f3c65c733ce6f9a384424","src/into.rs":"19d5403ca01bd3dcd3588cc0ea87dbb120150cbec7a26e281dd16f8875a2246d","src/into_iterator.rs":"9e43f7aae7b5be51842e7d727ab84d1b959cca6e81762ef6f41fc8d4ae5f96ff","src/is_variant.rs":"d0d55fc32f65c4241ae7eb8f1e3fe9e0943e2a502b23b732e67c972ebdb9a5f3","src/lib.rs":"175336e15f1337347ead1983266a1454f92f1cac92cdd6a68b59e40252bab55a","src/mul_assign_like.rs":"0f3e49242c68f7a4577aa51fa7a2970f324186e6104e1f76107f05e9500c6d29","src/mul_helpers.rs":"10e03b42b1e1c8257c3af3836a711e6cfcb1cf446e9767991ba208acd7f65536","src/mul_like.rs":"eba4316e78417a27aae6c5aa740fdbcadfb9e790fd6e6049ffdf546786ab32f7","src/not_like.rs":"de72bf8dc9db9a15459e3a897ea956b6f37256d182f98278eb0e5c9d4b548aac","src/parsing.rs":"c4ff6dbda866d2baf8a0fac71fac2dfd122b6fa4853916eaf2477e32ab871668","src/sum_like.rs":"c8dfca148fb35252df04ecd30256ecc0b35581c86276709837921b23c78019c1","src/try_into.rs":"e6311bed505b09f790f8a78a8b82187c403ca91be4c4d0a306c3d3c155d1ba89","src/try_unwrap.rs":"1785fd4816188e52361509fb8610dcbbd40c5062ad21ca61f6497315d6977754","src/unwrap.rs":"727ca9a25b0ee0f33b976a0555e37dfd2125aa737c1d5449dcb4adc8e0debd34","src/utils.rs":"65aa7845dff2f4792f9f5df347bf26bbb0ef343fb77ef064d8de4313a6699fdc"},"package":"395aee42a456ecfd4c7034be5011e1a98edcbab2611867c8988a0f40d0bb242a"}
\ No newline at end of file diff --git a/third_party/rust/derive_more-impl/Cargo.toml b/third_party/rust/derive_more-impl/Cargo.toml new file mode 100644 index 0000000000..ff2d5463d1 --- /dev/null +++ b/third_party/rust/derive_more-impl/Cargo.toml @@ -0,0 +1,127 @@ +# 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 = "2021" +rust-version = "1.65.0" +name = "derive_more-impl" +version = "1.0.0-beta.2" +authors = ["Jelte Fennema <github-tech@jeltef.nl>"] +include = [ + "src/**/*.rs", + "doc/**/*.md", + "Cargo.toml", + "README.md", + "LICENSE", +] +description = "Internal implementation of `derive_more` crate" +documentation = "https://docs.rs/derive_more" +readme = "README.md" +license = "MIT" +repository = "https://github.com/JelteF/derive_more" + +[package.metadata.docs.rs] +features = ["full"] +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[lib] +proc-macro = true + +[dependencies.convert_case] +version = "0.6" +optional = true + +[dependencies.proc-macro2] +version = "1.0" + +[dependencies.quote] +version = "1.0" + +[dependencies.syn] +version = "2.0" + +[dependencies.unicode-xid] +version = "0.2.2" +optional = true + +[dev-dependencies.itertools] +version = "0.11.0" + +[build-dependencies.rustc_version] +version = "0.4" +optional = true + +[features] +add = [] +add_assign = [] +as_mut = [] +as_ref = [] +constructor = [] +debug = [ + "syn/extra-traits", + "dep:unicode-xid", +] +default = [] +deref = [] +deref_mut = [] +display = [ + "syn/extra-traits", + "dep:unicode-xid", +] +error = ["syn/extra-traits"] +from = ["syn/extra-traits"] +from_str = [] +full = [ + "add", + "add_assign", + "as_mut", + "as_ref", + "constructor", + "debug", + "deref", + "deref_mut", + "display", + "error", + "from", + "from_str", + "index", + "index_mut", + "into", + "into_iterator", + "is_variant", + "mul", + "mul_assign", + "not", + "sum", + "try_into", + "try_unwrap", + "unwrap", +] +index = [] +index_mut = [] +into = ["syn/extra-traits"] +into_iterator = [] +is_variant = ["dep:convert_case"] +mul = ["syn/extra-traits"] +mul_assign = ["syn/extra-traits"] +not = ["syn/extra-traits"] +sum = [] +testing-helpers = ["dep:rustc_version"] +try_into = ["syn/extra-traits"] +try_unwrap = ["dep:convert_case"] +unwrap = ["dep:convert_case"] + +[badges.github] +repository = "JelteF/derive_more" +workflow = "CI" diff --git a/third_party/rust/derive_more-impl/LICENSE b/third_party/rust/derive_more-impl/LICENSE new file mode 100644 index 0000000000..602cf050e2 --- /dev/null +++ b/third_party/rust/derive_more-impl/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-impl/README.md b/third_party/rust/derive_more-impl/README.md new file mode 100644 index 0000000000..2a7de75214 --- /dev/null +++ b/third_party/rust/derive_more-impl/README.md @@ -0,0 +1,12 @@ +# `derive_more-impl` + +This crate is an implementation detail of the [`derive_more`][crates.io]. If you +found this crate by accident you're probably looking for one of the following +pages of [`derive_more`][crates.io]: +1. [crates.io] +2. [docs.rs] +3. [GitHub] + +[crates.io]: https://crates.io/crates/derive_more +[docs.rs]: https://docs.rs/derive_more/latest/derive_more +[GitHub]: https://github.com/JelteF/derive_more diff --git a/third_party/rust/derive_more-impl/doc/add.md b/third_party/rust/derive_more-impl/doc/add.md new file mode 100644 index 0000000000..5d58996a28 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/add.md @@ -0,0 +1,152 @@ +# What `#[derive(Add)]` generates + +The derived `Add` implementation will allow two structs from the same type to be +added together. This done by adding their respective fields together and +creating a new struct with those values. +For enums each variant can be added in a similar way to another instance of that +same variant. There's one big difference however, it returns a +`Result<EnumType>`, because an error is returned when to different variants are +added together. + + + + +## Tuple structs + +When deriving `Add` for a tuple struct with two fields like this: + +```rust +# use derive_more::Add; +# +#[derive(Add)] +struct MyInts(i32, i32); +``` + +Code like this will be generated: + +```rust +# struct MyInts(i32, i32); +impl ::core::ops::Add for MyInts { + type Output = MyInts; + fn add(self, rhs: MyInts) -> MyInts { + MyInts(self.0.add(rhs.0), self.1.add(rhs.1)) + } +} +``` + +The behaviour is similar with more or less fields. + + + + +## Regular structs + +When deriving `Add` for a regular struct with two fields like this: + +```rust +# use derive_more::Add; +# +#[derive(Add)] +struct Point2D { + x: i32, + y: i32, +} +``` + +Code like this will be generated: + +```rust +# struct Point2D { +# x: i32, +# y: i32, +# } +impl ::core::ops::Add for Point2D { + type Output = Point2D; + fn add(self, rhs: Point2D) -> Point2D { + Point2D { + x: self.x.add(rhs.x), + y: self.y.add(rhs.y), + } + } +} +``` + +The behaviour is similar for more or less fields. + + + + +## Enums + +There's a big difference between the code that is generated for the two struct +types and the one that is generated for enums. The code for enums returns +`Result<EnumType>` instead of an `EnumType` itself. This is because adding an +enum to another enum is only possible if both are the same variant. This makes +the generated code much more complex as well, because this check needs to be +done. For instance when deriving `Add` for an enum like this: + +```rust +# use derive_more::Add; +# +#[derive(Add)] +enum MixedInts { + SmallInt(i32), + BigInt(i64), + TwoSmallInts(i32, i32), + NamedSmallInts { x: i32, y: i32 }, + UnsignedOne(u32), + UnsignedTwo(u32), + Unit, +} +``` + +Code like this will be generated: + +```rust +# enum MixedInts { +# SmallInt(i32), +# BigInt(i64), +# TwoSmallInts(i32, i32), +# NamedSmallInts { x: i32, y: i32 }, +# UnsignedOne(u32), +# UnsignedTwo(u32), +# Unit, +# } +impl ::core::ops::Add for MixedInts { + type Output = Result<MixedInts, ::derive_more::ops::BinaryError>; + fn add(self, rhs: MixedInts) -> Result<MixedInts, ::derive_more::ops::BinaryError> { + match (self, rhs) { + (MixedInts::SmallInt(__l_0), MixedInts::SmallInt(__r_0)) => { + Ok(MixedInts::SmallInt(__l_0.add(__r_0))) + } + (MixedInts::BigInt(__l_0), MixedInts::BigInt(__r_0)) => { + Ok(MixedInts::BigInt(__l_0.add(__r_0))) + } + (MixedInts::TwoSmallInts(__l_0, __l_1), MixedInts::TwoSmallInts(__r_0, __r_1)) => { + Ok(MixedInts::TwoSmallInts(__l_0.add(__r_0), __l_1.add(__r_1))) + } + (MixedInts::NamedSmallInts { x: __l_0, y: __l_1 }, + MixedInts::NamedSmallInts { x: __r_0, y: __r_1 }) => { + Ok(MixedInts::NamedSmallInts { + x: __l_0.add(__r_0), + y: __l_1.add(__r_1), + }) + } + (MixedInts::UnsignedOne(__l_0), MixedInts::UnsignedOne(__r_0)) => { + Ok(MixedInts::UnsignedOne(__l_0.add(__r_0))) + } + (MixedInts::UnsignedTwo(__l_0), MixedInts::UnsignedTwo(__r_0)) => { + Ok(MixedInts::UnsignedTwo(__l_0.add(__r_0))) + } + (MixedInts::Unit, MixedInts::Unit) => Err(::derive_more::ops::BinaryError::Unit( + ::derive_more::ops::UnitError::new("add"), + )), + _ => Err(::derive_more::ops::BinaryError::Mismatch( + ::derive_more::ops::WrongVariantError::new("add"), + )), + } + } +} +``` + +Also note the Unit type that throws an error when adding it to itself. diff --git a/third_party/rust/derive_more-impl/doc/add_assign.md b/third_party/rust/derive_more-impl/doc/add_assign.md new file mode 100644 index 0000000000..04a85a186b --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/add_assign.md @@ -0,0 +1,78 @@ +# What `#[derive(AddAssign)]` generates + +This code is very similar to the code that is generated for `#[derive(Add)]`. +The difference is that it mutates the existing instance instead of creating a +new one. + + + + +## Tuple structs + +When deriving `AddAssign` for a tuple struct with two fields like this: + +```rust +# use derive_more::AddAssign; +# +#[derive(AddAssign)] +struct MyInts(i32, i32); +``` + +Code like this will be generated: + +```rust +# struct MyInts(i32, i32); +impl ::core::ops::AddAssign for MyInts { + fn add_assign(&mut self, rhs: MyInts) { + self.0.add_assign(rhs.0); + self.1.add_assign(rhs.1); + } +} +``` + +The behaviour is similar with more or less fields. + + + + +## Regular structs + +When deriving for a regular struct with two fields like this: + +```rust +# use derive_more::AddAssign; +# +#[derive(AddAssign)] +struct Point2D { + x: i32, + y: i32, +} +``` + +Code like this will be generated: + +```rust +# struct Point2D { +# x: i32, +# y: i32, +# } +impl ::core::ops::AddAssign for Point2D { + fn add_assign(&mut self, rhs: Point2D) { + self.x.add_assign(rhs.x); + self.y.add_assign(rhs.y); + } +} +``` + +The behaviour is similar with more or less fields. + + + + +## Enums + +Deriving `AddAssign` is not (yet) supported for enums. +This is mostly due to the fact that it is not trivial convert the `Add` +derivation code, because that returns a `Result<EnumType>` instead of an +`EnumType`. +Handling the case where it errors would be hard and maybe impossible. diff --git a/third_party/rust/derive_more-impl/doc/as_mut.md b/third_party/rust/derive_more-impl/doc/as_mut.md new file mode 100644 index 0000000000..a1e6127d3a --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/as_mut.md @@ -0,0 +1,129 @@ +# What `#[derive(AsMut)]` generates + +Deriving `AsMut` generates one or more implementations of `AsMut`, each +corresponding to one of the fields of the decorated type. +This allows types which contain some `T` to be passed anywhere that an +`AsMut<T>` is accepted. + + + + +## Newtypes and Structs with One Field + +When `AsMut` is derived for a newtype or struct with one field, a single +implementation is generated to expose the underlying field. + +```rust +# use derive_more::AsMut; +# +#[derive(AsMut)] +struct MyWrapper(String); +``` + +Generates: + +```rust +# struct MyWrapper(String); +impl AsMut<String> for MyWrapper { + fn as_mut(&mut self) -> &mut String { + &mut self.0 + } +} +``` + +It's also possible to use the `#[as_mut(forward)]` attribute to forward +to the `as_mut` implementation of the field. So here `SingleFieldForward` +implements all `AsMut` for all types that `Vec<i32>` implements `AsMut` for. + +```rust +# use derive_more::AsMut; +# +#[derive(AsMut)] +#[as_mut(forward)] +struct SingleFieldForward(Vec<i32>); + +let mut item = SingleFieldForward(vec![]); +let _: &mut [i32] = (&mut item).as_mut(); +``` + +This generates: + +```rust +# struct SingleFieldForward(Vec<i32>); +impl<__AsMutT: ?::core::marker::Sized> ::core::convert::AsMut<__AsMutT> for SingleFieldForward +where + Vec<i32>: ::core::convert::AsMut<__AsMutT>, +{ + #[inline] + fn as_mut(&mut self) -> &mut __AsMutT { + <Vec<i32> as ::core::convert::AsMut<__AsMutT>>::as_mut(&mut self.0) + } +} +``` + + + + +## Structs with Multiple Fields + +When `AsMut` is derived for a struct with more than one field (including tuple +structs), you must also mark one or more fields with the `#[as_mut]` attribute. +An implementation will be generated for each indicated field. +You can also exclude a specific field by using `#[as_mut(ignore)]`. + +```rust +# use derive_more::AsMut; +# +#[derive(AsMut)] +struct MyWrapper { + #[as_mut] + name: String, + #[as_mut] + num: i32, + valid: bool, +} +``` + +Generates: + +```rust +# struct MyWrapper { +# name: String, +# num: i32, +# valid: bool, +# } +impl AsMut<String> for MyWrapper { + fn as_mut(&mut self) -> &mut String { + &mut self.name + } +} + +impl AsMut<i32> for MyWrapper { + fn as_mut(&mut self) -> &mut i32 { + &mut self.num + } +} +``` + +Note that `AsMut<T>` may only be implemented once for any given type `T`. This means any attempt to +mark more than one field of the same type with `#[as_mut]` will result in a compilation error. + +```rust,compile_fail +# use derive_more::AsMut; +# +// Error! Conflicting implementations of AsMut<String> +#[derive(AsMut)] +struct MyWrapper { + #[as_mut] + str1: String, + #[as_mut] + str2: String, +} +``` + + + + +## Enums + +Deriving `AsMut` for enums is not supported. diff --git a/third_party/rust/derive_more-impl/doc/as_ref.md b/third_party/rust/derive_more-impl/doc/as_ref.md new file mode 100644 index 0000000000..112ba15a1c --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/as_ref.md @@ -0,0 +1,130 @@ +# What `#[derive(AsRef)]` generates + +Deriving `AsRef` generates one or more implementations of `AsRef`, each +corresponding to one of the fields of the decorated type. +This allows types which contain some `T` to be passed anywhere that an +`AsRef<T>` is accepted. + + + + +## Newtypes and Structs with One Field + +When `AsRef` is derived for a newtype or struct with one field, a single +implementation is generated to expose the underlying field. + +```rust +# use derive_more::AsRef; +# +#[derive(AsRef)] +struct MyWrapper(String); +``` + +Generates: + +```rust +# struct MyWrapper(String); +impl AsRef<String> for MyWrapper { + fn as_ref(&self) -> &String { + &self.0 + } +} +``` + +It's also possible to use the `#[as_ref(forward)]` attribute to forward +to the `as_ref` implementation of the field. So here `SingleFieldForward` +implements all `AsRef` for all types that `Vec<i32>` implements `AsRef` for. + +```rust +# use derive_more::AsRef; +# +#[derive(AsRef)] +#[as_ref(forward)] +struct SingleFieldForward(Vec<i32>); + +let item = SingleFieldForward(vec![]); +let _: &[i32] = (&item).as_ref(); +``` + +This generates: + +```rust +# struct SingleFieldForward(Vec<i32>); +impl<__AsRefT: ?::core::marker::Sized> ::core::convert::AsRef<__AsRefT> for SingleFieldForward +where + Vec<i32>: ::core::convert::AsRef<__AsRefT>, +{ + #[inline] + fn as_ref(&self) -> &__AsRefT { + <Vec<i32> as ::core::convert::AsRef<__AsRefT>>::as_ref(&self.0) + } +} +``` + + + + +## Structs with Multiple Fields + +When `AsRef` is derived for a struct with more than one field (including tuple +structs), you must also mark one or more fields with the `#[as_ref]` attribute. +An implementation will be generated for each indicated field. +You can also exclude a specific field by using `#[as_ref(ignore)]`. + +```rust +# use derive_more::AsRef; +# +#[derive(AsRef)] +struct MyWrapper { + #[as_ref] + name: String, + #[as_ref] + num: i32, + valid: bool, +} +``` + +Generates: + +```rust +# struct MyWrapper { +# name: String, +# num: i32, +# valid: bool, +# } +impl AsRef<String> for MyWrapper { + fn as_ref(&self) -> &String { + &self.name + } +} + +impl AsRef<i32> for MyWrapper { + fn as_ref(&self) -> &i32 { + &self.num + } +} +``` + +Note that `AsRef<T>` may only be implemented once for any given type `T`. +This means any attempt to mark more than one field of the same type with +`#[as_ref]` will result in a compilation error. + +```rust,compile_fail +# use derive_more::AsRef; +# +// Error! Conflicting implementations of AsRef<String> +#[derive(AsRef)] +struct MyWrapper { + #[as_ref] + str1: String, + #[as_ref] + str2: String, +} +``` + + + + +## Enums + +Deriving `AsRef` for enums is not supported. diff --git a/third_party/rust/derive_more-impl/doc/constructor.md b/third_party/rust/derive_more-impl/doc/constructor.md new file mode 100644 index 0000000000..43f55c06d6 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/constructor.md @@ -0,0 +1,80 @@ +# What `#[derive(Constructor)]` generates + +A common pattern in Rust is to create a static constructor method called +`new`. This method is can then be used to create an instance of a struct. You +can now derive this method by using `#[derive(Constructor)]`, even though +`Constructor` it is not an actual trait. The generated `new` method is very +similar to the `from` method when deriving `From`, except that it takes multiple +arguments instead of a tuple. + + + + +## Tuple structs + +When deriving `Constructor` for a tuple struct with a two fields like this: + +```rust +# use derive_more::Constructor; +# +#[derive(Constructor)] +struct MyInts(i32, i32); +``` + +Code like this will be generated: + +```rust +# struct MyInts(i32, i32); +impl MyInts { + pub const fn new(__0: i32, __1: i32) -> MyInts { + MyInts(__0, __1) + } +} +``` + +The generated code is similar for more or less fields. + + + + +## Regular structs + +For regular structs almost the same code is generated as for tuple structs +except that it assigns the fields differently. + +```rust +# use derive_more::Constructor; +# +#[derive(Constructor)] +struct Point2D { + x: i32, + y: i32, +} +``` + +Code like this will be generated: + +```rust +# struct Point2D { +# x: i32, +# y: i32, +# } +impl Point2D { + pub const fn new(x: i32, y: i32) -> Point2D { + Point2D { x: x, y: y } + } +} +``` + +The generated code is similar for more or less fields. + + + + +## Enums + +Currently `Constructor` cannot be derived for enums. This is because the `new` +method might then need to have a different number of arguments. This is +currently not supported by Rust. So this functionality will not be added until +this [RFC](https://github.com/rust-lang/rfcs/issues/376) (or a similar one) is +accepted and implemented. diff --git a/third_party/rust/derive_more-impl/doc/debug.md b/third_party/rust/derive_more-impl/doc/debug.md new file mode 100644 index 0000000000..b643976d04 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/debug.md @@ -0,0 +1,126 @@ +# What `#[derive(Debug)]` generates + +This derive macro is a clever superset of `Debug` from standard library. Additional features include: +- not imposing redundant trait bounds; +- `#[debug(skip)]` attribute to skip formatting struct field or enum variant; +- `#[debug("...", args...)]` to specify custom formatting for a particular struct or enum variant field; +- `#[debug(bounds(...))]` to impose additional custom trait bounds. + + + + +## The format of the format + +You supply a format by placing an attribute on particular struct or enum variant field (not enum variant itself): +`#[debug("...", args...)]`. The format is exactly like in [`format!()`] or any other [`format_args!()`]-based macros. + +The variables available in the arguments is `self` and each member of the variant, with members of tuple structs being +named with a leading underscore and their index, i.e. `_0`, `_1`, `_2`, etc. + + + + +### Generic data types + +When deriving `Debug` for a generic struct/enum, all generic type arguments _used_ during formatting +are bound by respective formatting trait. + +E.g., for a structure `Foo` defined like this: +```rust +use derive_more::Debug; + +#[derive(Debug)] +struct Foo<'a, T1, T2: Trait, T3, T4> { + #[debug("{a}")] + a: T1, + #[debug("{b}")] + b: <T2 as Trait>::Type, + #[debug("{c:?}")] + c: Vec<T3>, + #[debug("{d:p}")] + d: &'a T1, + #[debug(skip)] + e: T4, +} + +trait Trait { type Type; } +``` + +The following where clauses would be generated: +* `T1: Display + Pointer` +* `<T2 as Trait>::Type: Debug` +* `Bar<T3>: Display` + + + + +### Custom trait bounds + +Sometimes you may want to specify additional trait bounds on your generic type parameters, so that they could be used +during formatting. This can be done with a `#[debug(bound(...))]` attribute. + +`#[debug(bound(...))]` accepts code tokens in a format similar to the format used in angle bracket list (or `where` +clause predicates): `T: MyTrait, U: Trait1 + Trait2`. + +Using `#[debug("...", ...)]` formatting we'll try our best to infer trait bounds, but in more advanced cases this isn't +possible. Our aim is to avoid imposing additional bounds, as they can be added with `#[debug(bound(...))]`. +In the example below, we can infer only that `V: Display`, other bounds have to be supplied by the user: + +```rust +use std::fmt::Display; +use derive_more::Debug; + +#[derive(Debug)] +#[debug(bound(T: MyTrait, U: Display))] +struct MyStruct<T, U, V, F> { + #[debug("{}", a.my_function())] + a: T, + #[debug("{}", b.to_string().len())] + b: U, + #[debug("{c}")] + c: V, + #[debug(skip)] + d: F, +} + +trait MyTrait { fn my_function(&self) -> i32; } +``` + + + + +## Example usage + +```rust +use std::path::PathBuf; +use derive_more::Debug; + +#[derive(Debug)] +struct MyInt(i32); + +#[derive(Debug)] +struct MyIntHex(#[debug("{_0:x}")] i32); + +#[derive(Debug)] +enum E { + Skipped { + x: u32, + #[debug(skip)] + y: u32, + }, + Binary { + #[debug("{i:b}")] + i: i8, + }, + Path(#[debug("{}", _0.display())] PathBuf), +} + +assert_eq!(format!("{:?}", MyInt(-2)), "MyInt(-2)"); +assert_eq!(format!("{:?}", MyIntHex(-255)), "MyIntHex(ffffff01)"); +assert_eq!(format!("{:?}", E::Skipped { x: 10, y: 20 }), "Skipped { x: 10, .. }"); +assert_eq!(format!("{:?}", E::Binary { i: -2 }), "Binary { i: 11111110 }"); +assert_eq!(format!("{:?}", E::Path("abc".into())), "Path(abc)"); +``` + +[`format!()`]: https://doc.rust-lang.org/stable/std/macro.format.html +[`format_args!()`]: https://doc.rust-lang.org/stable/std/macro.format_args.html diff --git a/third_party/rust/derive_more-impl/doc/deref.md b/third_party/rust/derive_more-impl/doc/deref.md new file mode 100644 index 0000000000..f1719e9b16 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/deref.md @@ -0,0 +1,107 @@ +# Using `#[derive(Deref)]` + +Deriving `Deref` only works for a single field of a struct. +It's possible to use it in two ways: + +1. Dereferencing to the field, i.e. like if your type was a reference type. +2. Doing a dereference on the field, for when the field itself is a reference type like `&` and `Box`. + +With `#[deref]` or `#[deref(ignore)]` it's possible to indicate the field that +you want to derive `Deref` for. + + + + +## Example usage + +```rust +# use derive_more::Deref; +# +#[derive(Deref)] +struct Num { + num: i32, +} + +#[derive(Deref)] +#[deref(forward)] +struct MyBoxedInt(Box<i32>); + +// You can specify the field you want to derive `Deref` for. +#[derive(Deref)] +struct CoolVec { + cool: bool, + #[deref] + vec: Vec<i32>, +} + +let num = Num{num: 123}; +let boxed = MyBoxedInt(Box::new(123)); +let cool_vec = CoolVec{cool: true, vec: vec![123]}; +assert_eq!(123, *num); +assert_eq!(123, *boxed); +assert_eq!(vec![123], *cool_vec); +``` + + + + +## Structs + +When deriving a non-forwarded `Deref` for a struct: + +```rust +# use derive_more::Deref; +# +#[derive(Deref)] +struct CoolVec { + cool: bool, + #[deref] + vec: Vec<i32>, +} +``` + +Code like this will be generated: + +```rust +# struct CoolVec { +# cool: bool, +# vec: Vec<i32>, +# } +impl ::core::ops::Deref for CoolVec { + type Target = Vec<i32>; + #[inline] + fn deref(&self) -> &Self::Target { + &self.vec + } +} +``` + +When deriving a forwarded `Deref` for a struct: + +```rust +# use derive_more::Deref; +# +#[derive(Deref)] +#[deref(forward)] +struct MyBoxedInt(Box<i32>); +``` + +Code like this will be generated: + +```rust +# struct MyBoxedInt(Box<i32>); +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) + } +} +``` + + + + +## Enums + +Deriving `Deref` is not supported for enums. diff --git a/third_party/rust/derive_more-impl/doc/deref_mut.md b/third_party/rust/derive_more-impl/doc/deref_mut.md new file mode 100644 index 0000000000..8cde33d0dd --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/deref_mut.md @@ -0,0 +1,130 @@ +# What `#[derive(DerefMut)]` generates + +Deriving `Deref` only works for a single field of a struct. +Furthermore it requires that the type also implements `Deref`, so usually +`Deref` should also be derived. +The resulting implementation of `Deref` will allow you to mutably dereference +the struct its member directly. + +1. Dereferencing to the field, i.e. like if your type was a reference type. +2. Doing a dereference on the field, for when the field itself is a reference + type like `&mut` and `Box`. + +With `#[deref_mut]` or `#[deref_mut(ignore)]` it's possible to indicate the +field that you want to derive `DerefMut` for. + + + + +## Example usage + +```rust +# use derive_more::{Deref, DerefMut}; +# +#[derive(Deref, DerefMut)] +struct Num { + num: i32, +} + +#[derive(Deref, DerefMut)] +#[deref(forward)] +#[deref_mut(forward)] +struct MyBoxedInt(Box<i32>); + +// You can specify the field you want to derive DerefMut for +#[derive(Deref, DerefMut)] +struct CoolVec { + cool: bool, + #[deref] + #[deref_mut] + vec: Vec<i32>, +} + +let mut num = Num{num: 123}; +let mut boxed = MyBoxedInt(Box::new(123)); +let mut cool_vec = CoolVec{cool: true, vec: vec![123]}; +*num += 123; +assert_eq!(246, *num); +*boxed += 1000; +assert_eq!(1123, *boxed); +cool_vec.push(456); +assert_eq!(vec![123, 456], *cool_vec); +``` + + + + +## Structs + +When deriving a non-forwarded `Deref` for a struct: + +```rust +# use derive_more::{Deref, DerefMut}; +# +#[derive(Deref, DerefMut)] +struct CoolVec { + cool: bool, + #[deref] + #[deref_mut] + vec: Vec<i32>, +} +``` + +Code like this will be generated: + +```rust +# struct CoolVec { +# cool: bool, +# vec: Vec<i32>, +# } +# impl ::core::ops::Deref for CoolVec { +# type Target = Vec<i32>; +# #[inline] +# fn deref(&self) -> &Self::Target { +# &self.vec +# } +# } +impl ::core::ops::DerefMut for CoolVec { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.vec + } +} +``` + +When deriving `DerefMut` for a tuple struct with one field: + +```rust +# use derive_more::{Deref, DerefMut}; +# +#[derive(Deref, DerefMut)] +#[deref(forward)] +#[deref_mut(forward)] +struct MyBoxedInt(Box<i32>); +``` + +When deriving a forwarded `DerefMut` for a struct: + +```rust +# struct MyBoxedInt(Box<i32>); +# 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) +# } +# } +impl ::core::ops::DerefMut for MyBoxedInt { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + <Box<i32> as ::core::ops::DerefMut>::deref_mut(&mut self.0) + } +} +``` + + + + +## Enums + +Deriving `DerefMut` is not supported for enums. diff --git a/third_party/rust/derive_more-impl/doc/display.md b/third_party/rust/derive_more-impl/doc/display.md new file mode 100644 index 0000000000..5b616ca4d2 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/display.md @@ -0,0 +1,182 @@ +# What `#[derive(Display)]` generates + +Deriving `Display` will generate a `Display` implementation, with a `fmt` +method that matches `self` and each of its variants. In the case of a struct or union, +only a single variant is available, and it is thus equivalent to a simple `let` statement. +In the case of an enum, each of its variants is matched. + +For each matched variant, a `write!` expression will be generated with +the supplied format, or an automatically inferred one. + +You specify the format on each variant by writing e.g. `#[display("my val: {}", some_val * 2)]`. +For enums, you can either specify it on each variant, or on the enum as a whole. + +For variants that don't have a format specified, it will simply defer to the format of the +inner variable. If there is no such variable, or there is more than 1, an error is generated. + + + + +## The format of the format + +You supply a format by attaching an attribute of the syntax: `#[display("...", args...)]`. +The format supplied is passed verbatim to `write!`. The arguments supplied handled specially, +due to constraints in the syntax of attributes. In the case of an argument being a simple +identifier, it is passed verbatim. If an argument is a string, it is **parsed as an expression**, +and then passed to `write!`. + +The variables available in the arguments is `self` and each member of the variant, +with members of tuple structs being named with a leading underscore and their index, +i.e. `_0`, `_1`, `_2`, etc. + + +### Other formatting traits + +The syntax does not change, but the name of the attribute is the snake case version of the trait. +E.g. `Octal` -> `octal`, `Pointer` -> `pointer`, `UpperHex` -> `upper_hex`. + +Note, that `Debug` has a slightly different API and semantics, described in its docs, and so, +requires a separate `debug` feature. + + +### Generic data types + +When deriving `Display` (or other formatting trait) for a generic struct/enum, all generic type +arguments used during formatting are bound by respective formatting trait. + +E.g., for a structure `Foo` defined like this: +```rust +# use derive_more::Display; +# +# trait Trait { type Type; } +# +#[derive(Display)] +#[display("{} {} {:?} {:p}", a, b, c, d)] +struct Foo<'a, T1, T2: Trait, T3> { + a: T1, + b: <T2 as Trait>::Type, + c: Vec<T3>, + d: &'a T1, +} +``` + +The following where clauses would be generated: +* `T1: Display + Pointer` +* `<T2 as Trait>::Type: Debug` +* `Bar<T3>: Display` + + +### Custom trait bounds + +Sometimes you may want to specify additional trait bounds on your generic type parameters, so that they +could be used during formatting. This can be done with a `#[display(bound(...))]` attribute. + +`#[display(bound(...))]` accepts code tokens in a format similar to the format +used in angle bracket list (or `where` clause predicates): `T: MyTrait, U: Trait1 + Trait2`. + +Only type parameters defined on a struct allowed to appear in bound-string and they can only be bound +by traits, i.e. no lifetime parameters or lifetime bounds allowed in bound-string. + +`#[display("fmt", ...)]` arguments are parsed as an arbitrary Rust expression and passed to generated +`write!` as-is, it's impossible to meaningfully infer any kind of trait bounds for generic type parameters +used this way. That means that you'll **have to** explicitly specify all trait bound used. Either in the +struct/enum definition, or via `#[display(bound(...))]` attribute. + +Note how we have to bound `U` and `V` by `Display` in the following example, as no bound is inferred. +Not even `Display`. + +```rust +# use derive_more::Display; +# +# trait MyTrait { fn my_function(&self) -> i32; } +# +#[derive(Display)] +#[display(bound(T: MyTrait, U: Display))] +#[display("{} {} {}", a.my_function(), b.to_string().len(), c)] +struct MyStruct<T, U, V> { + a: T, + b: U, + c: V, +} +``` + + + + +## Example usage + +```rust +# use std::path::PathBuf; +# +# use derive_more::{Display, Octal, UpperHex}; +# +#[derive(Display)] +struct MyInt(i32); + +#[derive(Display)] +#[display("({x}, {y})")] +struct Point2D { + x: i32, + y: i32, +} + +#[derive(Display)] +enum E { + Uint(u32), + #[display("I am B {:b}", i)] + Binary { + i: i8, + }, + #[display("I am C {}", _0.display())] + Path(PathBuf), +} + +#[derive(Display)] +#[display("Hello there!")] +union U { + i: u32, +} + +#[derive(Octal)] +#[octal("7")] +struct S; + +#[derive(UpperHex)] +#[upper_hex("UpperHex")] +struct UH; + +#[derive(Display)] +struct Unit; + +#[derive(Display)] +struct UnitStruct {} + +#[derive(Display)] +#[display("{}", self.sign())] +struct PositiveOrNegative { + x: i32, +} + +impl PositiveOrNegative { + fn sign(&self) -> &str { + if self.x >= 0 { + "Positive" + } else { + "Negative" + } + } +} + +assert_eq!(MyInt(-2).to_string(), "-2"); +assert_eq!(Point2D { x: 3, y: 4 }.to_string(), "(3, 4)"); +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!(U { i: 2 }.to_string(), "Hello there!"); +assert_eq!(format!("{:o}", S), "7"); +assert_eq!(format!("{:X}", UH), "UpperHex"); +assert_eq!(Unit.to_string(), "Unit"); +assert_eq!(UnitStruct {}.to_string(), "UnitStruct"); +assert_eq!(PositiveOrNegative { x: 1 }.to_string(), "Positive"); +assert_eq!(PositiveOrNegative { x: -1 }.to_string(), "Negative"); +``` diff --git a/third_party/rust/derive_more-impl/doc/error.md b/third_party/rust/derive_more-impl/doc/error.md new file mode 100644 index 0000000000..20ff24cfe4 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/error.md @@ -0,0 +1,150 @@ +# Using `#[derive(Error)]` + +Deriving `Error` will generate an `Error` implementation, that contains +(depending on the type) a `source()` and a `provide()` method. Please note, +at the time of writing `provide()` is only supported on nightly rust. So you +have to use that to make use of it. + +For a struct, these methods always do the same. For an `enum` they have separate +behaviour for each of the variants. The variant is first matched and then the +implementation will do the same as it would have done if the variant was a +struct. + +Usually when you derive `Error` you will also want to [derive `Display`](crate::Display) and +often [`From` as well](crate::From). + + +### When and how does it derive `source()`? + +1. It's a struct/variant with named fields and one is the fields is + called `source`. Then it would return that field as the `source`. +2. It's a tuple struct/variant and there's exactly one field that is not used as + the `backtrace`. So either a tuple struct with one field, or one with two where one + is the `backtrace`. Then it returns this field as the `source`. +3. One of the fields is annotated with `#[error(source)]`. Then it would + return that field as the `source`. + +### When and how does it derive `provide()`? + +1. It's a struct/variant with named fields and one of the fields is + called `backtrace`. Then it would return that field as the `backtrace`. +2. It's a tuple struct/variant and the type of exactly one of the fields is + called `Backtrace`. Then it would return that field as the `backtrace`. +3. One of the fields is annotated with `#[error(backtrace)]`. Then it would + return that field as the `backtrace`. + +### Ignoring fields for derives + +It's possible to ignore a field or a whole enum variant completely for this +derive using the `#[error(ignore)]` attribute. This will ignore it both for +detecting `backtrace` and `source`. It's also possible to mark a field only +ignored for one of these methods by using `#[error(not(backtrace))]` or +`#[error(not(source))]`. + + +### What works in `no_std`? + +If you want to use the `Error` derive on `no_std` environments, then you need to +compile with nightly and enable this feature: +```ignore +#![feature(error_in_core)] +``` + +Backtraces don't work though, because the `Backtrace` type is only available in +`std`. + + + + +## Example usage + +```rust +# #![cfg_attr(nightly, feature(error_generic_member_access, provide_any))] +// Nightly requires enabling these features: +// #![feature(error_generic_member_access, provide_any)] +# #[cfg(not(nightly))] fn main() {} +# #[cfg(nightly)] fn main() { +# use std::{any, error::Error as _, backtrace::Backtrace}; +# +# use derive_more::{Display, Error, From}; + +// std::error::Error requires std::fmt::Debug and std::fmt::Display, +// so we can also use derive_more::Display for fully declarative +// error-type definitions. + +#[derive(Default, Debug, Display, Error)] +struct Simple; + +#[derive(Default, Debug, Display, Error)] +struct WithSource { + source: Simple, +} +#[derive(Default, Debug, Display, Error)] +struct WithExplicitSource { + #[error(source)] + explicit_source: Simple, +} + +#[derive(Default, Debug, Display, Error)] +struct Tuple(Simple); + +#[derive(Default, Debug, Display, Error)] +struct WithoutSource(#[error(not(source))] i32); + +#[derive(Debug, Display, Error)] +#[display("An error with a backtrace")] +struct WithSourceAndBacktrace { + source: Simple, + backtrace: Backtrace, +} + +// derive_more::From fits nicely into this pattern as well +#[derive(Debug, Display, Error, From)] +enum CompoundError { + Simple, + WithSource { + source: Simple, + }, + #[from(ignore)] + WithBacktraceFromSource { + #[error(backtrace)] + source: Simple, + }, + #[display("{source}")] + WithDifferentBacktrace { + source: Simple, + backtrace: Backtrace, + }, + WithExplicitSource { + #[error(source)] + explicit_source: WithSource, + }, + #[from(ignore)] + WithBacktraceFromExplicitSource { + #[error(backtrace, source)] + explicit_source: WithSource, + }, + Tuple(WithExplicitSource), + WithoutSource(#[error(not(source))] Tuple), +} + +assert!(Simple.source().is_none()); +assert!(any::request_ref::<Backtrace>(&Simple).is_none()); +assert!(WithSource::default().source().is_some()); +assert!(WithExplicitSource::default().source().is_some()); +assert!(Tuple::default().source().is_some()); +assert!(WithoutSource::default().source().is_none()); +let with_source_and_backtrace = WithSourceAndBacktrace { + source: Simple, + backtrace: Backtrace::capture(), +}; +assert!(with_source_and_backtrace.source().is_some()); +assert!(any::request_ref::<Backtrace>(&with_source_and_backtrace).is_some()); + +assert!(CompoundError::Simple.source().is_none()); +assert!(CompoundError::from(Simple).source().is_some()); +assert!(CompoundError::from(WithSource::default()).source().is_some()); +assert!(CompoundError::from(WithExplicitSource::default()).source().is_some()); +assert!(CompoundError::from(Tuple::default()).source().is_none()); +# } +``` diff --git a/third_party/rust/derive_more-impl/doc/from.md b/third_party/rust/derive_more-impl/doc/from.md new file mode 100644 index 0000000000..1bc0cb4de3 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/from.md @@ -0,0 +1,188 @@ +# What `#[derive(From)]` generates + +The point of deriving this type is that it makes it easy to create a new +instance of the type by using the `.into()` method on the value(s) that it +should contain. This is done by implementing the `From` trait for the type +that is passed to the derive. + + + + +## Structs + +For structs with a single field you can call `.into()` on the desired content +itself after deriving `From`. + +```rust +# use derive_more::From; +# +#[derive(Debug, From, PartialEq)] +struct Int(i32); + +assert_eq!(Int(2), 2.into()); +``` + +For structs that have multiple fields `.into()` needs to be called on a tuple +containing the desired content for each field. + +```rust +# use derive_more::From; +# +#[derive(Debug, From, PartialEq)] +struct Point(i32, i32); + +assert_eq!(Point(1, 2), (1, 2).into()); +``` + +To specify concrete types to derive convert from use `#[from(<types>)]`. + +```rust +# use std::borrow::Cow; +# +# use derive_more::From; +# +#[derive(Debug, From, PartialEq)] +#[from(Cow<'static, str>, String, &'static str)] +struct Str(Cow<'static, str>); + +assert_eq!(Str("&str".into()), "&str".into()); +assert_eq!(Str("String".into()), "String".to_owned().into()); +assert_eq!(Str("Cow".into()), Cow::Borrowed("Cow").to_owned().into()); + +#[derive(Debug, From, PartialEq)] +#[from((i16, i16), (i32, i32))] +struct Point { + x: i32, + y: i32, +} + +assert_eq!(Point { x: 1_i32, y: 2_i32 }, (1_i16, 2_i16).into()); +assert_eq!(Point { x: 3_i32, y: 4_i32 }, (3_i32, 4_i32).into()); +``` + +Also, you can forward implementation to the inner type, which means deriving `From` for any type, that derives `From` +inner type. + +```rust +# use std::borrow::Cow; +# +# use derive_more::From; +# +#[derive(Debug, From, PartialEq)] +#[from(forward)] +struct Str { + inner: Cow<'static, str>, +} + +assert_eq!(Str { inner: "&str".into() }, "&str".into()); +assert_eq!(Str { inner: "String".into() }, "String".to_owned().into()); +assert_eq!(Str { inner: "Cow".into() }, Cow::Borrowed("Cow").to_owned().into()); +``` + + + + +## Enums + +For enums `.into()` works for each variant as if they were structs. This +includes specifying concrete types via `#[from(<types>)]` or forwarding +implementation with `#[from(forward)]`. + +```rust +# use derive_more::From; +# +#[derive(Debug, From, PartialEq)] +enum IntOrPoint { + Int(i32), + Point { + x: i32, + y: i32, + }, +} + +assert_eq!(IntOrPoint::Int(1), 1.into()); +assert_eq!(IntOrPoint::Point { x: 1, y: 2 }, (1, 2).into()); +``` + +By default, `From` is generated for every enum variant, but you can skip some +variants via `#[from(skip)]` or only concrete fields via `#[from]`. + +```rust +# mod from { +# use derive_more::From; +#[derive(Debug, From, PartialEq)] +enum Int { + #[from] + Derived(i32), + NotDerived(i32), +} +# } + +// Is equivalent to: + +# mod skip { +# use derive_more::From; +#[derive(Debug, From, PartialEq)] +enum Int { + Derived(i32), + #[from(skip)] + NotDerived(i32), +} +# } +``` + + + + +## Example usage + +```rust +# use derive_more::From; +# +// Allow converting from i32 +#[derive(From, PartialEq)] +struct MyInt(i32); + +// Forward from call to the field, so allow converting +// from anything that can be converted into an i64 (so most integers) +#[derive(From, PartialEq)] +#[from(forward)] +struct MyInt64(i64); + +// You can ignore a variant +#[derive(From, PartialEq)] +enum MyEnum { + SmallInt(i32), + NamedBigInt { int: i64 }, + #[from(ignore)] + NoFromImpl(i64), +} + +// Or explicitly annotate the ones you need +#[derive(From, PartialEq)] +enum MyEnum2 { + #[from] + SmallInt(i32), + #[from] + NamedBigInt { int: i64 }, + NoFromImpl(i64), +} + +// And even specify additional conversions for them +#[derive(From, PartialEq)] +enum MyEnum3 { + #[from(i8, i32)] + SmallInt(i32), + #[from(i16, i64)] + NamedBigInt { int: i64 }, + NoFromImpl(i64), +} + +assert!(MyInt(2) == 2.into()); +assert!(MyInt64(6) == 6u8.into()); +assert!(MyEnum::SmallInt(123) == 123i32.into()); +assert!(MyEnum::SmallInt(123) != 123i64.into()); +assert!(MyEnum::NamedBigInt{int: 123} == 123i64.into()); +assert!(MyEnum3::SmallInt(123) == 123i8.into()); +assert!(MyEnum3::NamedBigInt{int: 123} == 123i16.into()); +``` diff --git a/third_party/rust/derive_more-impl/doc/from_str.md b/third_party/rust/derive_more-impl/doc/from_str.md new file mode 100644 index 0000000000..d888e825db --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/from_str.md @@ -0,0 +1,135 @@ +# What `#[derive(FromStr)]` generates + +Deriving `FromStr` only works for enums with no fields +or newtypes, i.e structs with only a single +field. The result is that you will be able to call the `parse()` method on a +string to convert it to your newtype. This only works when the type that is +contained in the type implements `FromStr`. + + + + +## Example usage + +```rust +# use derive_more::FromStr; +# +#[derive(FromStr, Debug, Eq, PartialEq)] +struct MyInt(i32); + +#[derive(FromStr, Debug, Eq, PartialEq)] +struct Point1D{ + x: i32, +} + +assert_eq!(MyInt(5), "5".parse().unwrap()); +assert_eq!(Point1D{x: 100}, "100".parse().unwrap()); +``` + + + + +## Tuple structs + +When deriving `FromStr` for a tuple struct with one field: + +```rust +# use derive_more::FromStr; +# +#[derive(FromStr)] +struct MyInt(i32); +``` + +Code like this will be generated: + +```rust +# struct MyInt(i32); +impl ::core::str::FromStr for MyInt { + type Err = <i32 as ::core::str::FromStr>::Err; + fn from_str(src: &str) -> Result<Self, Self::Err> { + return Ok(MyInt(i32::from_str(src)?)); + } +} +``` + + + + +## Regular structs + +When deriving `FromStr` for a regular struct with one field: + +```rust +# use derive_more::FromStr; +# +#[derive(FromStr)] +struct Point1D { + x: i32, +} +``` + +Code like this will be generated: + +```rust +# struct Point1D { +# x: i32, +# } +impl ::core::str::FromStr for Point1D { + type Err = <i32 as ::core::str::FromStr>::Err; + fn from_str(src: &str) -> Result<Self, Self::Err> { + return Ok(Point1D { + x: i32::from_str(src)?, + }); + } +} +``` + + + + +## Enums + +When deriving `FromStr` for an enums with variants with no fields it will +generate a `from_str` method that converts strings that match the variant name +to the variant. If using a case insensitive match would give a unique variant +(i.e you dont have both a `MyEnum::Foo` and a `MyEnum::foo` variant) then case +insensitive matching will be used, otherwise it will fall back to exact string +matching. + +Since the string may not match any variants an error type is needed, so the +`derive_more::FromStrError` will be used for that purpose. + +e.g. Given the following enum: + +```rust +# use derive_more::FromStr; +# +#[derive(FromStr)] +enum EnumNoFields { + Foo, + Bar, + Baz, +} +``` + +Code like this will be generated: + +```rust +# enum EnumNoFields { +# Foo, +# Bar, +# Baz, +# } +# +impl ::core::str::FromStr for EnumNoFields { + type Err = ::derive_more::FromStrError; + fn from_str(src: &str) -> Result<Self, Self::Err> { + Ok(match src.to_lowercase().as_str() { + "foo" => EnumNoFields::Foo, + "bar" => EnumNoFields::Bar, + "baz" => EnumNoFields::Baz, + _ => return Err(::derive_more::FromStrError::new("EnumNoFields")), + }) + } +} +``` diff --git a/third_party/rust/derive_more-impl/doc/index.md b/third_party/rust/derive_more-impl/doc/index.md new file mode 100644 index 0000000000..c45fb46df5 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/index.md @@ -0,0 +1,74 @@ +# What `#[derive(Index)]` generates + +Deriving `Index` only works for a single field of a struct. +The result is that you will index it's member directly. + +With `#[index]` or `#[index(ignore)]` it's possible to indicate the field that +you want to derive `Index` for. + + + + +## Example usage + +```rust +# use derive_more::Index; +# +#[derive(Index)] +struct MyVec(Vec<i32>); + +// You can specify the field you want to derive Index for +#[derive(Index)] +struct Numbers { + #[index] + numbers: Vec<i32>, + useless: bool, +} + +assert_eq!(5, MyVec(vec![5, 8])[0]); +assert_eq!(200, Numbers { numbers: vec![100, 200], useless: false }[1]); +``` + + + + +## Structs + +When deriving `Index` for a struct: + +```rust +# use derive_more::Index; +# +#[derive(Index)] +struct Numbers { + #[index] + numbers: Vec<i32>, + useless: bool, +} +``` + +Code like this will be generated: + +```rust +# struct Numbers { +# numbers: Vec<i32>, +# useless: bool, +# } +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) + } +} +``` + + + + +## Enums + +Deriving `Index` is not supported for enums. diff --git a/third_party/rust/derive_more-impl/doc/index_mut.md b/third_party/rust/derive_more-impl/doc/index_mut.md new file mode 100644 index 0000000000..ff2347796e --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/index_mut.md @@ -0,0 +1,91 @@ +# What `#[derive(IndexMut)]` generates + +Deriving `IndexMut` only works for a single field of a struct. +Furthermore it requires that the type also implements `Index`, so usually +`Index` should also be derived. +The result is that you will mutably index it's member directly. + +With `#[index_mut]` or `#[index_mut(ignore)]` it's possible to indicate the +field that you want to derive `IndexMut` for. + + + + +## Example usage + +```rust +# use derive_more::{Index, IndexMut}; +# +#[derive(Index, IndexMut)] +struct MyVec(Vec<i32>); + +#[derive(Index, IndexMut)] +struct Numbers { + #[index] + #[index_mut] + numbers: Vec<i32>, + useless: bool, +} + +let mut myvec = MyVec(vec![5, 8]); +myvec[0] = 50; +assert_eq!(50, myvec[0]); + +let mut numbers = Numbers{numbers: vec![100, 200], useless: false}; +numbers[1] = 400; +assert_eq!(400, numbers[1]); +``` + + + + +## Regular structs + +When deriving `IndexMut` for a struct: + +```rust +# use derive_more::{Index, IndexMut}; +# +#[derive(Index, IndexMut)] +struct Numbers { + #[index] + #[index_mut] + numbers: Vec<i32>, + useless: bool, +} +``` + +Code like this will be generated to implement `IndexMut`: + +```rust +# struct Numbers { +# numbers: Vec<i32>, +# useless: bool, +# } +# 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) +# } +# } +impl<__IdxT> ::core::ops::IndexMut<__IdxT> for Numbers +where + Vec<i32>: ::core::ops::IndexMut<__IdxT>, +{ + #[inline] + fn index_mut(&mut self, idx: __IdxT) -> &mut Self::Output { + <Vec<i32> as ::core::ops::IndexMut<__IdxT>>::index_mut(&mut self.numbers, idx) + } +} +``` + + + + +## Enums + +Deriving `IndexMut` is not supported for enums. diff --git a/third_party/rust/derive_more-impl/doc/into.md b/third_party/rust/derive_more-impl/doc/into.md new file mode 100644 index 0000000000..0ca676d9b3 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/into.md @@ -0,0 +1,119 @@ +# What `#[derive(Into)]` generates + +This derive creates the exact opposite of `#[derive(From)]`. +Instead of allowing you to create a new instance of the struct from the values +it should contain, it allows you to extract the values from the struct. One +thing to note is that this derive doesn't actually generate an implementation +for the `Into` trait. Instead, it derives `From` for the values contained in +the struct and thus has an indirect implementation of `Into` as +[recommended by the docs][1]. + + + + +## Structs + +For structs with a single field you can call `.into()` to extract the inner type. + +```rust +# use derive_more::Into; +# +#[derive(Debug, Into, PartialEq)] +struct Int(i32); + +assert_eq!(2, Int(2).into()); +``` + +For structs having multiple fields, `.into()` extracts a tuple containing the +desired content for each field. + +```rust +# use derive_more::Into; +# +#[derive(Debug, Into, PartialEq)] +struct Point(i32, i32); + +assert_eq!((1, 2), Point(1, 2).into()); +``` + +To specify concrete types for deriving conversions into, use `#[into(<types>)]`. + +```rust +# use std::borrow::Cow; +# +# use derive_more::Into; +# +#[derive(Debug, Into, PartialEq)] +#[into(Cow<'static, str>, String)] +struct Str(Cow<'static, str>); + +assert_eq!("String".to_owned(), String::from(Str("String".into()))); +assert_eq!(Cow::Borrowed("Cow"), <Cow<_>>::from(Str("Cow".into()))); + +#[derive(Debug, Into, PartialEq)] +#[into((i64, i64), (i32, i32))] +struct Point { + x: i32, + y: i32, +} + +assert_eq!((1_i64, 2_i64), Point { x: 1_i32, y: 2_i32 }.into()); +assert_eq!((3_i32, 4_i32), Point { x: 3_i32, y: 4_i32 }.into()); +``` + +In addition to converting to owned types, this macro supports deriving into +reference (mutable or not) via `#[into(ref(...))]`/`#[into(ref_mut(...))]`. + +```rust +# use derive_more::Into; +# +#[derive(Debug, Into, PartialEq)] +#[into(owned, ref(i32), ref_mut)] +struct Int(i32); + +assert_eq!(2, Int(2).into()); +assert_eq!(&2, <&i32>::from(&Int(2))); +assert_eq!(&mut 2, <&mut i32>::from(&mut Int(2))); +``` + +In case there are fields, that shouldn't be included in the conversion, use the +`#[into(skip)]` attribute. + +```rust +# use std::marker::PhantomData; +# +# use derive_more::Into; +# +# struct Gram; +# +#[derive(Debug, Into, PartialEq)] +#[into(i32, i64, i128)] +struct Mass<Unit> { + value: i32, + #[into(skip)] + _unit: PhantomData<Unit>, +} + +assert_eq!(5, Mass::<Gram>::new(5).into()); +assert_eq!(5_i64, Mass::<Gram>::new(5).into()); +assert_eq!(5_i128, Mass::<Gram>::new(5).into()); +# +# impl<Unit> Mass<Unit> { +# fn new(value: i32) -> Self { +# Self { +# value, +# _unit: PhantomData, +# } +# } +# } +``` + +## Enums + +Deriving `Into` for enums is not supported as it would not always be successful, +so `TryInto` should be used instead. + + + + +[1]: https://doc.rust-lang.org/core/convert/trait.Into.html diff --git a/third_party/rust/derive_more-impl/doc/into_iterator.md b/third_party/rust/derive_more-impl/doc/into_iterator.md new file mode 100644 index 0000000000..c9abe66c28 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/into_iterator.md @@ -0,0 +1,101 @@ +# Using `#[derive(IntoIterator)]` + +Deriving `IntoIterator` only works for a single field of a struct. +The result is that you will call `.into_iter()` on this field directly. + +With `#[into_iterator]` or `#[into_iterator(ignore)]` it's possible to indicate +the field that you want to derive `IntoIterator` for. + +By using `#[into_iterator(owned, ref, ref_mut)]` it's possible to derive an +`IntoIterator` implementation for reference types as well. +You can pick any combination of `owned`, `ref` and `ref_mut`. +If that's not provided the default is `#[IntoIterator(owned)]`. + + + + +## Example usage + +```rust +# use derive_more::IntoIterator; +# +#[derive(IntoIterator)] +struct MyVec(Vec<i32>); + +// You can specify the field you want to derive `IntoIterator` for +#[derive(IntoIterator)] +struct Numbers { + #[into_iterator(owned, ref, ref_mut)] + numbers: Vec<i32>, + useless: bool, +} + +assert_eq!(Some(5), MyVec(vec![5, 8]).into_iter().next()); + +let mut nums = Numbers{numbers: vec![100, 200], useless: false}; +assert_eq!(Some(&100), (&nums).into_iter().next()); +assert_eq!(Some(&mut 100), (&mut nums).into_iter().next()); +assert_eq!(Some(100), nums.into_iter().next()); +``` + + + + +## Structs + +When deriving `IntoIterator` for a struct: + +```rust +# use derive_more::IntoIterator; +# +#[derive(IntoIterator)] +struct Numbers { + #[into_iterator(owned, ref, ref_mut)] + numbers: Vec<i32>, + useless: bool, +} +``` + +Code like this will be generated: + +```rust +# struct Numbers { +# numbers: Vec<i32>, +# useless: bool, +# } +impl ::core::iter::IntoIterator for Numbers { + 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) + } +} + +impl<'__deriveMoreLifetime> ::core::iter::IntoIterator for &'__deriveMoreLifetime Numbers { + type Item = <&'__deriveMoreLifetime Vec<i32> as ::core::iter::IntoIterator>::Item; + type IntoIter = <&'__deriveMoreLifetime Vec<i32> as ::core::iter::IntoIterator>::IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + <&'__deriveMoreLifetime Vec<i32> as ::core::iter::IntoIterator>::into_iter(&self.numbers) + } +} + +impl<'__deriveMoreLifetime> ::core::iter::IntoIterator for &'__deriveMoreLifetime mut Numbers { + type Item = <&'__deriveMoreLifetime mut Vec<i32> as ::core::iter::IntoIterator>::Item; + type IntoIter = <&'__deriveMoreLifetime mut Vec<i32> as ::core::iter::IntoIterator>::IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + <&'__deriveMoreLifetime mut Vec<i32> as ::core::iter::IntoIterator>::into_iter( + &mut self.numbers, + ) + } +} +``` + + + + +## Enums + +Deriving `IntoIterator` is not supported for enums. diff --git a/third_party/rust/derive_more-impl/doc/is_variant.md b/third_party/rust/derive_more-impl/doc/is_variant.md new file mode 100644 index 0000000000..9e549dc1bd --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/is_variant.md @@ -0,0 +1,43 @@ +# What `#[derive(IsVariant)]` generates + +When an enum is decorated with `#[derive(IsVariant)]`, for each variant `foo` in +the enum, a public instance method `is_foo(&self) -> bool` is generated. If you +don't want the `is_foo` method generated for a variant you can put the +`#[is_variant(ignore)]` attribute on that variant. + + + + +## Example usage + +```rust +# use derive_more::IsVariant; +# +#[derive(IsVariant)] +enum Maybe<T> { + Just(T), + Nothing +} + +assert!(Maybe::<()>::Nothing.is_nothing()); +assert!(!Maybe::<()>::Nothing.is_just()); +``` + + +### What is generated? + +The derive in the above example code generates the following code: +```rust +# enum Maybe<T> { +# Just(T), +# Nothing +# } +impl <T> Maybe<T>{ + pub const fn is_just(&self) -> bool { + match self {Self::Just(..) => true, _ => false} + } + pub const fn is_nothing(&self) -> bool { + match self {Self::Nothing => true, _ => false} + } +} +``` diff --git a/third_party/rust/derive_more-impl/doc/mul.md b/third_party/rust/derive_more-impl/doc/mul.md new file mode 100644 index 0000000000..a1068bef0d --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/mul.md @@ -0,0 +1,148 @@ +# What `#[derive(Mul)]` generates + +Deriving `Mul` is quite different from deriving `Add`. It is not used to +multiply two structs together. Instead it will normally multiply a struct, which +can have multiple fields, with a single primitive type (e.g. a `u64`). A new +struct is then created with all the fields from the previous struct multiplied +by this other value. + +A simple way of explaining the reasoning behind this difference between `Add` +and `Mul` deriving, is looking at arithmetic on meters. +One meter can be added to one meter, to get two meters. Also, one meter times +two would be two meters, but one meter times one meter would be one square meter. +As this second case clearly requires more knowledge about the meaning of the +type in question deriving for this is not implemented. + +NOTE: In case you don't want this behaviour you can add `#[mul(forward)]` in +addition to `#[derive(Mul)]`. This will instead generate a `Mul` implementation +with the same semantics as `Add`. + + + + +## Tuple structs + +When deriving for a tuple struct with a single field (i.e. a newtype) like this: + +```rust +# use derive_more::Mul; +# +#[derive(Mul)] +struct MyInt(i32); +``` + +Code like this will be generated: + +```rust +# struct MyInt(i32); +impl<__RhsT> ::core::ops::Mul<__RhsT> for MyInt + where i32: ::core::ops::Mul<__RhsT, Output = i32> +{ + type Output = MyInt; + fn mul(self, rhs: __RhsT) -> MyInt { + MyInt(self.0.mul(rhs)) + } +} +``` + +The behaviour is slightly different for multiple fields, since the right hand +side of the multiplication now needs the `Copy` trait. +For instance when deriving for a tuple struct with two fields like this: + +```rust +# use derive_more::Mul; +# +#[derive(Mul)] +struct MyInts(i32, i32); +``` + +Code like this will be generated: + +```rust +# struct MyInts(i32, i32); +impl<__RhsT: ::core::marker::Copy> ::core::ops::Mul<__RhsT> for MyInts + where i32: ::core::ops::Mul<__RhsT, Output = i32> +{ + type Output = MyInts; + fn mul(self, rhs: __RhsT) -> MyInts { + MyInts(self.0.mul(rhs), self.1.mul(rhs)) + } +} +``` + +The behaviour is similar with more or less fields. + + + + +## Regular structs + +When deriving `Mul` for a regular struct with a single field like this: + +```rust +# use derive_more::Mul; +# +#[derive(Mul)] +struct Point1D { + x: i32, +} +``` + +Code like this will be generated: + +```rust +# struct Point1D { +# x: i32, +# } +impl<__RhsT> ::core::ops::Mul<__RhsT> for Point1D + where i32: ::core::ops::Mul<__RhsT, Output = i32> +{ + type Output = Point1D; + fn mul(self, rhs: __RhsT) -> Point1D { + Point1D { x: self.x.mul(rhs) } + } +} +``` + +The behaviour is again slightly different when deriving for a struct with multiple +fields, because it still needs the `Copy` as well. +For instance when deriving for a tuple struct with two fields like this: + +```rust +# use derive_more::Mul; +# +#[derive(Mul)] +struct Point2D { + x: i32, + y: i32, +} +``` + +Code like this will be generated: + +```rust +# struct Point2D { +# x: i32, +# y: i32, +# } +impl<__RhsT: ::core::marker::Copy> ::core::ops::Mul<__RhsT> for Point2D + where i32: ::core::ops::Mul<__RhsT, Output = i32> +{ + type Output = Point2D; + fn mul(self, rhs: __RhsT) -> Point2D { + Point2D { + x: self.x.mul(rhs), + y: self.y.mul(rhs), + } + } +} +``` + + + + +## Enums + +Deriving `Mul` for enums is not (yet) supported, except when you use +`#[mul(forward)]`. +Although it shouldn't be impossible no effort has been put into this yet. diff --git a/third_party/rust/derive_more-impl/doc/mul_assign.md b/third_party/rust/derive_more-impl/doc/mul_assign.md new file mode 100644 index 0000000000..e5d9225ef3 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/mul_assign.md @@ -0,0 +1,92 @@ +# What `#[derive(MulAssign)]` generates + +This code is very similar to the code that is generated for `#[derive(Mul)]`. +The difference is that it mutates the existing instance instead of creating a +new one. + +You can add the `#[mul_assign(forward)]` attribute if you don't want the same +semantics as `Mul`. +This will instead generate a `MulAssign` implementation with the same semantics +as `AddAssign`. + + + + +## Tuple structs + +When deriving `MulAssign` for a tuple struct with two fields like this: + +```rust +# use derive_more::MulAssign; +# +#[derive(MulAssign)] +struct MyInts(i32, i32); +``` + +Code like this will be generated: + +```rust +# struct MyInts(i32, i32); +impl<__RhsT: ::core::marker::Copy> ::core::ops::MulAssign<__RhsT> for MyInts + where i32: ::core::ops::MulAssign<__RhsT> +{ + fn mul_assign(&mut self, rhs: __RhsT) { + self.0.mul_assign(rhs); + self.1.mul_assign(rhs); + } +} +``` + +The behaviour is similar with more or less fields, except for the fact that +`__RhsT` does not need to implement `Copy` when only a single field is present. + + + + +## Regular structs + +When deriving `MulAssign` for a regular struct with two fields like this: + +```rust +# use derive_more::MulAssign; +# +#[derive(MulAssign)] +struct Point2D { + x: i32, + y: i32, +} +``` + +Code like this will be generated: + +```rust +# struct Point2D { +# x: i32, +# y: i32, +# } +impl<__RhsT: ::core::marker::Copy> ::core::ops::MulAssign<__RhsT> for Point2D + where i32: ::core::ops::MulAssign<__RhsT> +{ + fn mul_assign(&mut self, rhs: __RhsT) { + self.x.mul_assign(rhs); + self.y.mul_assign(rhs); + } +} +``` + +The behaviour is again similar with more or less fields, except that `Copy` +doesn't have to be implemented for `__Rhst` when the struct has only a single +field. + + + + +## Enums + +Deriving `MulAssign` for enums is not (yet) supported. +This has two reason, the first being that deriving `Mul` is also not implemented +for enums yet. +The second reason is the same as for `AddAssign`. +Even if it would be deriving `Mul` was implemented it would likely return a +`Result<EnumType>` instead of an `EnumType`. +Handling the case where it errors would be hard and maybe impossible. diff --git a/third_party/rust/derive_more-impl/doc/not.md b/third_party/rust/derive_more-impl/doc/not.md new file mode 100644 index 0000000000..9997c085ab --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/not.md @@ -0,0 +1,159 @@ +# What `#[derive(Not)]` generates + +The derived `Not` implementation simply negates all the fields of a +struct and returns that as a new instance of the struct. +For enums all fields of the active variant of the enum are negated and a new +instance of the same variant with these negated fields is returned. + + + + +## Tuple structs + +When deriving for a tuple struct with two fields like this: + +```rust +# use derive_more::Not; +# +#[derive(Not)] +struct MyInts(i32, i32); +``` + +Code like this will be generated: + +```rust +# struct MyInts(i32, i32); +impl ::core::ops::Not for MyInts { + type Output = MyInts; + fn not(self) -> MyInts { + MyInts(self.0.not(), self.1.not()) + } +} +``` + +The behaviour is similar with more or less fields. + + + + +## Regular structs + +When deriving for a regular struct with two fields like this: + +```rust +# use derive_more::Not; +# +#[derive(Not)] +struct Point2D { + x: i32, + y: i32, +} +``` + +Code like this will be generated: + +```rust +# struct Point2D { +# x: i32, +# y: i32, +# } +impl ::core::ops::Not for Point2D { + type Output = Point2D; + fn not(self) -> Point2D { + Point2D { + x: self.x.not(), + y: self.y.not(), + } + } +} +``` + +The behaviour is similar with more or less fields. + + + + +## Enums + +For each enum variant `Not` is derived in a similar way as it would be derived +if it would be its own type. +For instance when deriving `Not` for an enum like this: + +```rust +# use derive_more::Not; +# +#[derive(Not)] +enum MixedInts { + SmallInt(i32), + BigInt(i64), + TwoSmallInts(i32, i32), + NamedSmallInts { x: i32, y: i32 }, + UnsignedOne(u32), + UnsignedTwo(u32), +} +``` + +Code like this will be generated: + +```rust +# enum MixedInts { +# SmallInt(i32), +# BigInt(i64), +# TwoSmallInts(i32, i32), +# NamedSmallInts { x: i32, y: i32 }, +# UnsignedOne(u32), +# UnsignedTwo(u32), +# } +impl ::core::ops::Not for MixedInts { + type Output = MixedInts; + fn not(self) -> MixedInts { + match self { + MixedInts::SmallInt(__0) => MixedInts::SmallInt(__0.not()), + MixedInts::BigInt(__0) => MixedInts::BigInt(__0.not()), + MixedInts::TwoSmallInts(__0, __1) => MixedInts::TwoSmallInts(__0.not(), __1.not()), + MixedInts::NamedSmallInts { x: __0, y: __1 } => { + MixedInts::NamedSmallInts { + x: __0.not(), + y: __1.not(), + } + } + MixedInts::UnsignedOne(__0) => MixedInts::UnsignedOne(__0.not()), + MixedInts::UnsignedTwo(__0) => MixedInts::UnsignedTwo(__0.not()), + } + } +} +``` + +There is one important thing to remember though. +If you add a unit variant to the enum its return type will change from +`EnumType` to `Result<EnumType>`. +This is because Unit cannot have `Not` implemented. +So, when deriving `Not` for an enum like this: + +```rust +# use derive_more::Not; +# +#[derive(Not)] +enum EnumWithUnit { + SmallInt(i32), + Unit, +} +``` + +Code like this will be generated: + +```rust +# enum EnumWithUnit { +# SmallInt(i32), +# Unit, +# } +impl ::core::ops::Not for EnumWithUnit { + type Output = Result<EnumWithUnit, ::derive_more::ops::UnitError>; + fn not(self) -> Result<EnumWithUnit, ::derive_more::ops::UnitError> { + match self { + EnumWithUnit::SmallInt(__0) => Ok(EnumWithUnit::SmallInt(__0.not())), + EnumWithUnit::Unit => Err(::derive_more::ops::UnitError::new("not")), + } + } +} +``` diff --git a/third_party/rust/derive_more-impl/doc/sum.md b/third_party/rust/derive_more-impl/doc/sum.md new file mode 100644 index 0000000000..ffb5ea6be2 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/sum.md @@ -0,0 +1,77 @@ +# Using `#[derive(Sum)]` + +The derived `Sum` implementation will allow an iterator of your type to be +summed together into a new instance of the type with all the fields added +together. Apart from the original types requiring an implementation of `Sum`, it +is also required that your type to implements `Add`. So normally you want to +derive that one as well. + +All this is also true for the `Product`, except that then all the fields are +multiplied and an implementation of `Mul` is required. This is usually the +easiest to implement by adding `#[derive(MulSelf)]`. + + + + +## Example usage + +```rust +# use derive_more::{Add, Sum}; +# +#[derive(Add, Sum, PartialEq)] +struct MyInts(i32, i64); + +let int_vec = vec![MyInts(2, 3), MyInts(4, 5), MyInts(6, 7)]; +assert!(MyInts(12, 15) == int_vec.into_iter().sum()) +``` + + + + +## Structs + +When deriving `Sum` for a struct with two fields its like this: + +```rust +# use derive_more::{Add, Sum}; +# +#[derive(Add, Sum)] +struct MyInts(i32, i64); +``` + +Code like this will be generated for the `Sum` implementation: + +```rust +# struct MyInts(i32, i64); +# 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)) +# } +# } +impl ::core::iter::Sum for MyInts { + #[inline] + fn sum<I: ::core::iter::Iterator<Item = Self>>(iter: I) -> Self { + iter.fold( + MyInts( + ::core::iter::empty::<i32>().sum(), + ::core::iter::empty::<i64>().sum(), + ), + ::core::ops::Add::add, + ) + } +} +``` + +The trick here is that we get the identity struct by calling sum on empty +iterators. +This way we can get the identity for sum (i.e. `0`) and the identity for product +(i.e. `1`). + + + + +## Enums + +Deriving `Sum` for enums is not supported. diff --git a/third_party/rust/derive_more-impl/doc/try_into.md b/third_party/rust/derive_more-impl/doc/try_into.md new file mode 100644 index 0000000000..252a33bf4d --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/try_into.md @@ -0,0 +1,182 @@ +# What `#[derive(TryInto)]` generates + +This derive allows you to convert enum variants into their corresponding +variant types. +One thing to note is that this derive doesn't actually generate an +implementation for the `TryInto` trait. +Instead it derives `TryFrom` for each variant in the enum and thus has an +indirect implementation of `TryInto` as recommended by the +[docs](https://doc.rust-lang.org/core/convert/trait.TryInto.html). + +By using `#[try_into(owned, ref, ref_mut)]` it's possible to derive a `TryInto` +implementation for reference types as well. +You can pick any combination of `owned`, `ref` and `ref_mut`. +If that's not provided the default is `#[try_into(owned)]`. + +With `#[try_into]` or `#[try_into(ignore)]` it's possible to indicate which +variants you want to derive `TryInto` for. + + + + +## Example usage + +```rust +# use derive_more::TryInto; +# +#[derive(TryInto, Clone, Debug)] +#[try_into(owned, ref, ref_mut)] +enum MixedData { + Int(u32), + String(String), +} + +let mixed_string = MixedData::String("foo".to_string()); +let mixed_int1 = MixedData::Int(123); +let mixed_int2 = mixed_int1.clone(); +let mut mixed_int3 = mixed_int1.clone(); + +assert_eq!(123u32, mixed_int1.try_into().unwrap()); + +let int_ref : &u32 = (&mixed_int2).try_into().unwrap(); +assert_eq!(&123u32, int_ref); + +let int_ref_mut : &mut u32 = (&mut mixed_int3).try_into().unwrap(); +assert_eq!(&mut 123u32, int_ref_mut); + +assert_eq!("foo".to_string(), String::try_from(mixed_string.clone()).unwrap()); + +assert!(u32::try_from(mixed_string).is_err()); +``` + + + + +## Structs + +Deriving `TryInto` for structs is not supported because there is no failing +mode. Use `#[derive(Into)]` instead. `TryInto` will automatically get a +blanket implementation through `TryFrom`, automatically derived from `From`, +which `#[derive(Into)]` produces. + + + + +## Enums + +When deriving `TryInto` for an enum, each enum variant gets its own +`TryFrom` implementation. +For instance, when deriving `TryInto` for an enum link this: + +```rust +# use derive_more::TryInto; +# +#[derive(TryInto)] +enum MixedInts { + SmallInt(i32), + BigInt(i64), + TwoSmallInts(i32, i32), + NamedSmallInts { x: i64, y: i64 }, + UnsignedOne(u32), + UnsignedTwo(u32), + #[try_into(ignore)] + NotImportant, +} +``` + +Code like this will be generated: + +```rust +# enum MixedInts { +# SmallInt(i32), +# BigInt(i64), +# TwoSmallInts(i32, i32), +# NamedSmallInts { x: i64, y: i64 }, +# UnsignedOne(u32), +# UnsignedTwo(u32), +# } +impl ::core::convert::TryFrom<MixedInts> for (i32) { + type Error = &'static str; + fn try_from(value: MixedInts) -> Result<Self, Self::Error> { + match value { + MixedInts::SmallInt(__0) => Ok(__0), + _ => Err("Only SmallInt can be converted to i32"), + } + } +} +impl ::core::convert::TryFrom<MixedInts> for (i64) { + type Error = &'static str; + fn try_from(value: MixedInts) -> Result<Self, Self::Error> { + match value { + MixedInts::BigInt(__0) => Ok(__0), + _ => Err("Only BigInt can be converted to i64"), + } + } +} +impl ::core::convert::TryFrom<MixedInts> for (i32, i32) { + type Error = &'static str; + fn try_from(value: MixedInts) -> Result<Self, Self::Error> { + match value { + MixedInts::TwoSmallInts(__0, __1) => Ok((__0, __1)), + _ => Err("Only TwoSmallInts can be converted to (i32, i32)"), + } + } +} +impl ::core::convert::TryFrom<MixedInts> for (i64, i64) { + type Error = &'static str; + fn try_from(value: MixedInts) -> Result<Self, Self::Error> { + match value { + MixedInts::NamedSmallInts { x: __0, y: __1 } => Ok((__0, __1)), + _ => Err("Only NamedSmallInts can be converted to (i64, i64)"), + } + } +} +impl ::core::convert::TryFrom<MixedInts> for (u32) { + type Error = &'static str; + fn try_from(value: MixedInts) -> Result<Self, Self::Error> { + match value { + MixedInts::UnsignedOne(__0) | MixedInts::UnsignedTwo(__0) => Ok(__0), + _ => Err("Only UnsignedOne, UnsignedTwo can be converted to u32"), + } + } +} +``` + +When deriving `TryInto` for an enum with Unit variants like this: + +```rust +# use derive_more::TryInto; +# +#[derive(TryInto)] +enum EnumWithUnit { + SmallInt(i32), + Unit, +} +``` + +Code like this will be generated: + +```rust +# enum EnumWithUnit { +# SmallInt(i32), +# Unit, +# } +impl ::core::convert::TryFrom<EnumWithUnit> for (i32) { + type Error = &'static str; + fn try_from(value: EnumWithUnit) -> Result<Self, Self::Error> { + match value { + EnumWithUnit::SmallInt(__0) => Ok(__0), + _ => Err("Only SmallInt can be converted to i32"), + } + } +} +impl ::core::convert::TryFrom<EnumWithUnit> for () { + type Error = &'static str; + fn try_from(value: EnumWithUnit) -> Result<Self, Self::Error> { + match value { + EnumWithUnit::Unit => Ok(()), + _ => Err("Only Unit can be converted to ()"), + } + } +} +``` diff --git a/third_party/rust/derive_more-impl/doc/try_unwrap.md b/third_party/rust/derive_more-impl/doc/try_unwrap.md new file mode 100644 index 0000000000..f6ec49ee01 --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/try_unwrap.md @@ -0,0 +1,80 @@ +# What `#[derive(TryUnwrap)]` generates + +This works almost like `Unwrap`. +When an enum is decorated with `#[derive(TryUnwrap)]`, for each variant `foo` in the enum, with fields `(a, b, c, ...)` a public instance method `try_unwrap_foo(self) -> Result<(a, b, c, ...), TryUnwrapError<Self>>` is generated. +If you don't want the `try_unwrap_foo` method generated for a variant, you can put the `#[try_unwrap(ignore)]` attribute on that variant. +If you want to treat a reference, you can put the `#[try_unwrap(ref)]` attribute on the enum declaration or that variant, then `try_unwrap_foo_ref(self) -> Result<(&a, &b, &c, ...), TryUnwrapError<&Self>>` will be generated. You can also use mutable references by putting `#[unwrap(ref_mut)]`. +However, unlike `Unwrap`, it does not panic if the conversion fails. Also, values that fail to convert are not dropped but returned as an `Err`. + +## Example usage + +```rust +# use derive_more::TryUnwrap; +# +# #[derive(Debug, PartialEq)] +#[derive(TryUnwrap)] +#[try_unwrap(ref)] +enum Maybe<T> { + Nothing, + Just(T), +} + +fn main() { + assert_eq!(Maybe::Just(1).try_unwrap_just(), Ok(1)); + + // Unlike `Unwrap`, it does not panic. + assert_eq!( + Maybe::<()>::Nothing.try_unwrap_just().map_err(|err| err.input), + Err(Maybe::<()>::Nothing), // and the value is returned! + ); + assert_eq!( + Maybe::Just(2).try_unwrap_nothing().map_err(|err| err.input), + Err(Maybe::Just(2)), + ); + assert_eq!( + Maybe::<()>::Nothing.try_unwrap_just().map_err(|err| err.to_string()), + Err("Attempt to call `Maybe::try_unwrap_just()` on a `Maybe::Nothing` value".into()), + ); + + assert_eq!((&Maybe::Just(42)).try_unwrap_just_ref(), Ok(&42)); +} +``` + +### What is generated? + +The derive in the above example code generates the following code: +```rust +# use derive_more::TryUnwrapError; +# +# enum Maybe<T> { +# Just(T), +# Nothing, +# } +# +impl<T> Maybe<T> { + pub fn try_unwrap_nothing(self) -> Result<(), TryUnwrapError<Self>> { + match self { + Maybe::Nothing => Ok(()), + val @ _ => Err(todo!("TryUnwrapError::new(val, /* omitted */)")), + } + } + pub fn try_unwrap_nothing_ref(&self) -> Result<(), TryUnwrapError<&Self>> { + match self { + Maybe::Nothing => Ok(()), + val @ _ => Err(todo!("TryUnwrapError::new(val, /* omitted */)")), + } + } + pub fn try_unwrap_just(self) -> Result<T, TryUnwrapError<Self>> { + match self { + Maybe::Just(field_0) => Ok(field_0), + val @ _ => Err(todo!("TryUnwrapError::new(val, /* omitted */)")), + } + } + pub fn try_unwrap_just_ref(&self) -> Result<&T, TryUnwrapError<&Self>> { + match self { + Maybe::Just(field_0) => Ok(field_0), + val @ _ => Err(todo!("TryUnwrapError::new(val, /* omitted */)")), + } + } +} +``` diff --git a/third_party/rust/derive_more-impl/doc/unwrap.md b/third_party/rust/derive_more-impl/doc/unwrap.md new file mode 100644 index 0000000000..e1a103476b --- /dev/null +++ b/third_party/rust/derive_more-impl/doc/unwrap.md @@ -0,0 +1,70 @@ +# What `#[derive(Unwrap)]` generates + +When an enum is decorated with `#[derive(Unwrap)]`, for each variant `foo` in the enum, with fields `(a, b, c, ...)` a public instance method `unwrap_foo(self) -> (a, b, c, ...)` is generated. +If you don't want the `unwrap_foo` method generated for a variant, you can put the `#[unwrap(ignore)]` attribute on that variant. +If you want to treat a reference, you can put the `#[unwrap(ref)]` attribute on the enum declaration or that variant, then `unwrap_foo_ref(self) -> (&a, &b, &c, ...)` will be generated. You can also use mutable references by putting `#[unwrap(ref_mut)]`. + + + + +## Example usage + +```rust +# use derive_more::Unwrap; +# +# #[derive(Debug, PartialEq)] +#[derive(Unwrap)] +#[unwrap(ref)] +enum Maybe<T> { + Just(T), + Nothing, +} + +fn main() { + assert_eq!(Maybe::Just(1).unwrap_just(), 1); + + // Panics if variants are different + // assert_eq!(Maybe::<()>::Nothing.unwrap_just(), /* panic */); + // assert_eq!(Maybe::Just(2).unwrap_nothing(), /* panic */); + + assert_eq!((&Maybe::Just(42)).unwrap_just_ref(), &42); +} +``` + + +### What is generated? + +The derive in the above example code generates the following code: +```rust +# enum Maybe<T> { +# Just(T), +# Nothing, +# } +# +impl<T> Maybe<T> { + pub fn unwrap_nothing(self) -> () { + match self { + Maybe::Nothing => (), + _ => panic!(), + } + } + pub fn unwrap_nothing_ref(&self) -> () { + match self { + Maybe::Nothing => (), + _ => panic!(), + } + } + pub fn unwrap_just(self) -> T { + match self { + Maybe::Just(field_0) => field_0, + _ => panic!(), + } + } + pub fn unwrap_just_ref(&self) -> &T { + match self { + Maybe::Just(field_0) => field_0, + _ => panic!(), + } + } +} +``` diff --git a/third_party/rust/derive_more-impl/src/add_assign_like.rs b/third_party/rust/derive_more-impl/src/add_assign_like.rs new file mode 100644 index 0000000000..610ba983e0 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/add_assign_like.rs @@ -0,0 +1,39 @@ +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::TokenStream; +use quote::{format_ident, quote}; +use syn::{Data, DeriveInput, Fields}; + +pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { + let trait_ident = format_ident!("{trait_name}"); + let method_name = trait_name.trim_end_matches("Assign").to_lowercase(); + let method_ident = format_ident!("{method_name}_assign"); + 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! { + #[automatically_derived] + 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-impl/src/add_helpers.rs b/third_party/rust/derive_more-impl/src/add_helpers.rs new file mode 100644 index 0000000000..b9cee1a682 --- /dev/null +++ b/third_party/rust/derive_more-impl/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-impl/src/add_like.rs b/third_party/rust/derive_more-impl/src/add_like.rs new file mode 100644 index 0000000000..58076461ca --- /dev/null +++ b/third_party/rust/derive_more-impl/src/add_like.rs @@ -0,0 +1,153 @@ +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::TokenStream; +use quote::{format_ident, 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 = format_ident!("{trait_name}"); + let method_name = trait_name.to_lowercase(); + let method_ident = format_ident!("{method_name}"); + 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, ::derive_more::ops::BinaryError> + }, + enum_content(input_type, data_enum, &method_ident), + ), + + _ => panic!("Only structs and enums can use derive({trait_name})"), + }; + + quote! { + #[automatically_derived] + impl #impl_generics ::derive_more::#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 pattern 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 pattern 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 operation_name = method_ident.to_string(); + matches.push(quote! { + (#subtype, #subtype) => ::core::result::Result::Err( + ::derive_more::ops::BinaryError::Unit( + ::derive_more::ops::UnitError::new(#operation_name) + ) + ) + }); + } + } + } + + 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 operation_name = method_ident.to_string(); + matches.push(quote! { + _ => ::core::result::Result::Err(::derive_more::ops::BinaryError::Mismatch( + ::derive_more::ops::WrongVariantError::new(#operation_name) + )) + }); + } + quote! { + match (self, rhs) { + #(#matches),* + } + } +} diff --git a/third_party/rust/derive_more-impl/src/as_mut.rs b/third_party/rust/derive_more-impl/src/as_mut.rs new file mode 100644 index 0000000000..1d05adc505 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/as_mut.rs @@ -0,0 +1,81 @@ +use crate::utils::{ + add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State, +}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse::Result, DeriveInput}; + +pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> { + let as_mut_type = format_ident!("__AsMutT"); + let state = State::with_type_bound( + input, + trait_name, + "as_mut".into(), + 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! {#( + #[automatically_derived] + 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-impl/src/as_ref.rs b/third_party/rust/derive_more-impl/src/as_ref.rs new file mode 100644 index 0000000000..71f1259867 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/as_ref.rs @@ -0,0 +1,81 @@ +use crate::utils::{ + add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State, +}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse::Result, DeriveInput}; + +pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> { + let as_ref_type = format_ident!("__AsRefT"); + let state = State::with_type_bound( + input, + trait_name, + "as_ref".into(), + 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! {#( + #[automatically_derived] + 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-impl/src/constructor.rs b/third_party/rust/derive_more-impl/src/constructor.rs new file mode 100644 index 0000000000..284b0643fc --- /dev/null +++ b/third_party/rust/derive_more-impl/src/constructor.rs @@ -0,0 +1,50 @@ +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)] + #[automatically_derived] + impl #impl_generics #input_type #ty_generics #where_clause { + #[inline] + pub const 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-impl/src/deref.rs b/third_party/rust/derive_more-impl/src/deref.rs new file mode 100644 index 0000000000..f87c64cc61 --- /dev/null +++ b/third_party/rust/derive_more-impl/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, + 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! { + #[automatically_derived] + 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-impl/src/deref_mut.rs b/third_party/rust/derive_more-impl/src/deref_mut.rs new file mode 100644 index 0000000000..2d7a79db2a --- /dev/null +++ b/third_party/rust/derive_more-impl/src/deref_mut.rs @@ -0,0 +1,44 @@ +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, "deref_mut".into())?; + 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! { + #[automatically_derived] + 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-impl/src/error.rs b/third_party/rust/derive_more-impl/src/error.rs new file mode 100644 index 0000000000..99771b4d9e --- /dev/null +++ b/third_party/rust/derive_more-impl/src/error.rs @@ -0,0 +1,481 @@ +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, + 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, provide) = 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 ::derive_more::Error + 'static)> { + use ::derive_more::__private::AsDynError; + #source + } + } + }); + + let provide = provide.map(|provide| { + quote! { + fn provide<'_demand>(&'_demand self, demand: &mut ::core::any::Demand<'_demand>) { + #provide + } + } + }); + + let mut generics = generics.clone(); + + if !type_params.is_empty() { + let (_, ty_generics, _) = generics.split_for_impl(); + generics = utils::add_extra_where_clauses( + &generics, + quote! { + where + #ident #ty_generics: ::core::fmt::Debug + ::core::fmt::Display + }, + ); + } + + if !bounds.is_empty() { + let bounds = bounds.iter(); + generics = utils::add_extra_where_clauses( + &generics, + quote! { + where + #(#bounds: ::core::fmt::Debug + ::core::fmt::Display + ::derive_more::Error + 'static),* + }, + ); + } + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let render = quote! { + #[automatically_derived] + impl #impl_generics ::derive_more::Error for #ident #ty_generics #where_clause { + #source + #provide + } + }; + + 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 provide = parsed_fields.render_provide_as_struct(); + + Ok((parsed_fields.bounds, source, provide)) +} + +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 provide_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_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_provide_as_enum_variant_match_arm() { + provide_match_arms.push(expr); + } + + bounds.extend(parsed_fields.bounds.into_iter()); + } + + let render = |match_arms: &mut Vec<TokenStream>, unmatched| { + if !match_arms.is_empty() && match_arms.len() < state.variants.len() { + match_arms.push(quote! { _ => #unmatched }); + } + + (!match_arms.is_empty()).then(|| { + quote! { + match self { + #(#match_arms),* + } + } + }) + }; + + let source = render(&mut source_match_arms, quote! { None }); + let provide = render(&mut provide_match_arms, quote! { () }); + + Ok((bounds, source, provide)) +} + +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_provide_as_struct(&self) -> Option<TokenStream> { + let backtrace = self.backtrace?; + + let source_provider = self.source.map(|source| { + let source_expr = &self.data.members[source]; + quote! { + ::derive_more::Error::provide(&#source_expr, demand); + } + }); + let backtrace_provider = self + .source + .filter(|source| *source == backtrace) + .is_none() + .then(|| { + let backtrace_expr = &self.data.members[backtrace]; + quote! { + demand.provide_ref::<::std::backtrace::Backtrace>(&#backtrace_expr); + } + }); + + (source_provider.is_some() || backtrace_provider.is_some()).then(|| { + quote! { + #backtrace_provider + #source_provider + } + }) + } + + fn render_provide_as_enum_variant_match_arm(&self) -> Option<TokenStream> { + let backtrace = self.backtrace?; + + match self.source { + Some(source) if source == backtrace => { + let pattern = self.data.matcher(&[source], &[quote! { source }]); + Some(quote! { + #pattern => { + ::derive_more::Error::provide(source, demand); + } + }) + } + Some(source) => { + let pattern = self.data.matcher( + &[source, backtrace], + &[quote! { source }, quote! { backtrace }], + ); + Some(quote! { + #pattern => { + demand.provide_ref::<::std::backtrace::Backtrace>(backtrace); + ::derive_more::Error::provide(source, demand); + } + }) + } + None => { + let pattern = self.data.matcher(&[backtrace], &[quote! { backtrace }]); + Some(quote! { + #pattern => { + demand.provide_ref::<::std::backtrace::Backtrace>(backtrace); + } + }) + } + } + } +} + +fn render_some<T>(expr: T) -> TokenStream +where + T: quote::ToTokens, +{ + quote! { Some(#expr.as_dyn_error()) } +} + +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 syn::Type::Path(ty) = ty else { + return false; + }; + + // Unwrapping is safe, cause 'syn::TypePath.path.segments' + // have to have at least one segment + let segment = ty.path.segments.last().unwrap(); + + if !matches!(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)| matches!(value(info), Some(true))); + + 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 `{attr}` attributes specified. \ + Single attribute per struct/enum variant allowed.", + ), + )?; + + 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 Some(item) = iter.next() else { + 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-impl/src/fmt/debug.rs b/third_party/rust/derive_more-impl/src/fmt/debug.rs new file mode 100644 index 0000000000..d1f427e1f6 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/fmt/debug.rs @@ -0,0 +1,373 @@ +//! Implementation of a [`fmt::Debug`] derive macro. +//! +//! [`fmt::Debug`]: std::fmt::Debug + +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use syn::{ + parse::{Error, Parse, ParseStream, Result}, + parse_quote, + spanned::Spanned as _, + Ident, +}; + +use super::{BoundsAttribute, FmtAttribute}; + +/// Expands a [`fmt::Debug`] derive macro. +/// +/// [`fmt::Debug`]: std::fmt::Debug +pub fn expand(input: &syn::DeriveInput, _: &str) -> Result<TokenStream> { + let attrs = ContainerAttributes::parse_attrs(&input.attrs)?; + let ident = &input.ident; + + let (bounds, body) = match &input.data { + syn::Data::Struct(s) => expand_struct(attrs, ident, s), + syn::Data::Enum(e) => expand_enum(attrs, e), + syn::Data::Union(_) => { + return Err(Error::new( + input.span(), + "`Debug` cannot be derived for unions", + )); + } + }?; + + let (impl_gens, ty_gens, where_clause) = { + let (impl_gens, ty_gens, where_clause) = input.generics.split_for_impl(); + let mut where_clause = where_clause + .cloned() + .unwrap_or_else(|| parse_quote! { where }); + where_clause.predicates.extend(bounds); + (impl_gens, ty_gens, where_clause) + }; + + Ok(quote! { + #[automatically_derived] + impl #impl_gens ::core::fmt::Debug for #ident #ty_gens + #where_clause + { + fn fmt( + &self, __derive_more_f: &mut ::core::fmt::Formatter<'_> + ) -> ::core::fmt::Result { + #body + } + } + }) +} + +/// Expands a [`fmt::Debug`] derive macro for the provided struct. +/// +/// [`fmt::Debug`]: std::fmt::Debug +fn expand_struct( + attrs: ContainerAttributes, + ident: &Ident, + s: &syn::DataStruct, +) -> Result<(Vec<syn::WherePredicate>, TokenStream)> { + let s = Expansion { + attr: &attrs, + fields: &s.fields, + ident, + }; + let bounds = s.generate_bounds()?; + let body = s.generate_body()?; + + let vars = s.fields.iter().enumerate().map(|(i, f)| { + let var = f.ident.clone().unwrap_or_else(|| format_ident!("_{i}")); + let member = f + .ident + .clone() + .map_or_else(|| syn::Member::Unnamed(i.into()), syn::Member::Named); + quote! { let #var = &self.#member; } + }); + + let body = quote! { + #( #vars )* + #body + }; + + Ok((bounds, body)) +} + +/// Expands a [`fmt::Debug`] derive macro for the provided enum. +/// +/// [`fmt::Debug`]: std::fmt::Debug +fn expand_enum( + attrs: ContainerAttributes, + e: &syn::DataEnum, +) -> Result<(Vec<syn::WherePredicate>, TokenStream)> { + let (bounds, match_arms) = e.variants.iter().try_fold( + (Vec::new(), TokenStream::new()), + |(mut bounds, mut arms), variant| { + let ident = &variant.ident; + + let v = Expansion { + attr: &attrs, + fields: &variant.fields, + ident, + }; + let arm_body = v.generate_body()?; + bounds.extend(v.generate_bounds()?); + + let fields_idents = + variant.fields.iter().enumerate().map(|(i, f)| { + f.ident.clone().unwrap_or_else(|| format_ident!("_{i}")) + }); + let matcher = match variant.fields { + syn::Fields::Named(_) => { + quote! { Self::#ident { #( #fields_idents ),* } } + } + syn::Fields::Unnamed(_) => { + quote! { Self::#ident ( #( #fields_idents ),* ) } + } + syn::Fields::Unit => quote! { Self::#ident }, + }; + + arms.extend([quote! { #matcher => { #arm_body }, }]); + + Ok::<_, Error>((bounds, arms)) + }, + )?; + + let body = match_arms + .is_empty() + .then(|| quote! { match *self {} }) + .unwrap_or_else(|| quote! { match self { #match_arms } }); + + Ok((bounds, body)) +} + +/// Representation of a [`fmt::Debug`] derive macro container attribute. +/// +/// ```rust,ignore +/// #[debug(bound(<bounds>))] +/// ``` +/// +/// [`fmt::Debug`]: std::fmt::Debug +#[derive(Debug, Default)] +struct ContainerAttributes { + /// Additional trait bounds. + bounds: BoundsAttribute, +} + +impl ContainerAttributes { + /// Parses [`ContainerAttributes`] from the provided [`syn::Attribute`]s. + fn parse_attrs(attrs: impl AsRef<[syn::Attribute]>) -> Result<Self> { + attrs + .as_ref() + .iter() + .filter(|attr| attr.path().is_ident("debug")) + .try_fold(ContainerAttributes::default(), |mut attrs, attr| { + let attr = attr.parse_args::<ContainerAttributes>()?; + attrs.bounds.0.extend(attr.bounds.0); + Ok(attrs) + }) + } +} + +impl Parse for ContainerAttributes { + fn parse(input: ParseStream) -> Result<Self> { + BoundsAttribute::check_legacy_fmt(input)?; + + input.parse().map(|bounds| ContainerAttributes { bounds }) + } +} + +/// Representation of a [`fmt::Debug`] derive macro field attribute. +/// +/// ```rust,ignore +/// #[debug("<fmt_literal>", <fmt_args>)] +/// #[debug(skip)] +/// ``` +/// +/// [`fmt::Debug`]: std::fmt::Debug +enum FieldAttribute { + /// [`fmt`] attribute. + /// + /// [`fmt`]: std::fmt + Fmt(FmtAttribute), + + /// Attribute for skipping field. + Skip, +} + +impl FieldAttribute { + /// Parses [`ContainerAttributes`] from the provided [`syn::Attribute`]s. + fn parse_attrs(attrs: impl AsRef<[syn::Attribute]>) -> Result<Option<Self>> { + Ok(attrs + .as_ref() + .iter() + .filter(|attr| attr.path().is_ident("debug")) + .try_fold(None, |mut attrs, attr| { + let field_attr = attr.parse_args::<FieldAttribute>()?; + if let Some((path, _)) = attrs.replace((attr.path(), field_attr)) { + Err(Error::new( + path.span(), + "only single `#[debug(...)]` attribute is allowed here", + )) + } else { + Ok(attrs) + } + })? + .map(|(_, attr)| attr)) + } +} + +impl Parse for FieldAttribute { + fn parse(input: ParseStream) -> Result<Self> { + FmtAttribute::check_legacy_fmt(input)?; + + if input.peek(syn::LitStr) { + input.parse().map(Self::Fmt) + } else { + let _ = input.parse::<syn::Path>().and_then(|p| { + if ["skip", "ignore"].into_iter().any(|i| p.is_ident(i)) { + Ok(p) + } else { + Err(Error::new( + p.span(), + "unknown attribute, expected `skip` or `ignore`", + )) + } + })?; + Ok(Self::Skip) + } + } +} + +/// Helper struct to generate [`Debug::fmt()`] implementation body and trait +/// bounds for a struct or an enum variant. +/// +/// [`Debug::fmt()`]: std::fmt::Debug::fmt() +#[derive(Debug)] +struct Expansion<'a> { + attr: &'a ContainerAttributes, + + /// Struct or enum [`Ident`](struct@Ident). + ident: &'a Ident, + + /// Struct or enum [`syn::Fields`]. + fields: &'a syn::Fields, +} + +impl<'a> Expansion<'a> { + /// Generates [`Debug::fmt()`] implementation for a struct or an enum variant. + /// + /// [`Debug::fmt()`]: std::fmt::Debug::fmt() + fn generate_body(&self) -> Result<TokenStream> { + match self.fields { + syn::Fields::Unit => { + let ident = self.ident.to_string(); + Ok(quote! { + ::core::fmt::Formatter::write_str( + __derive_more_f, + #ident, + ) + }) + } + syn::Fields::Unnamed(unnamed) => { + let mut exhaustive = true; + let ident_str = self.ident.to_string(); + + let out = quote! { + &mut ::derive_more::__private::debug_tuple( + __derive_more_f, + #ident_str, + ) + }; + let out = unnamed.unnamed.iter().enumerate().try_fold( + out, + |out, (i, field)| match FieldAttribute::parse_attrs(&field.attrs)? { + Some(FieldAttribute::Skip) => { + exhaustive = false; + Ok::<_, Error>(out) + } + Some(FieldAttribute::Fmt(fmt)) => Ok(quote! { + ::derive_more::__private::DebugTuple::field( + #out, + &::core::format_args!(#fmt), + ) + }), + None => { + let ident = format_ident!("_{i}"); + Ok(quote! { + ::derive_more::__private::DebugTuple::field(#out, #ident) + }) + } + }, + )?; + Ok(if exhaustive { + quote! { ::derive_more::__private::DebugTuple::finish(#out) } + } else { + quote! { ::derive_more::__private::DebugTuple::finish_non_exhaustive(#out) } + }) + } + syn::Fields::Named(named) => { + let mut exhaustive = true; + let ident = self.ident.to_string(); + + let out = quote! { + &mut ::core::fmt::Formatter::debug_struct( + __derive_more_f, + #ident, + ) + }; + let out = named.named.iter().try_fold(out, |out, field| { + let field_ident = field.ident.as_ref().unwrap_or_else(|| { + unreachable!("`syn::Fields::Named`"); + }); + let field_str = field_ident.to_string(); + match FieldAttribute::parse_attrs(&field.attrs)? { + Some(FieldAttribute::Skip) => { + exhaustive = false; + Ok::<_, Error>(out) + } + Some(FieldAttribute::Fmt(fmt)) => Ok(quote! { + ::core::fmt::DebugStruct::field( + #out, + #field_str, + &::core::format_args!(#fmt), + ) + }), + None => Ok(quote! { + ::core::fmt::DebugStruct::field(#out, #field_str, #field_ident) + }), + } + })?; + Ok(if exhaustive { + quote! { ::core::fmt::DebugStruct::finish(#out) } + } else { + quote! { ::core::fmt::DebugStruct::finish_non_exhaustive(#out) } + }) + } + } + } + + /// Generates trait bounds for a struct or an enum variant. + fn generate_bounds(&self) -> Result<Vec<syn::WherePredicate>> { + self.fields.iter().try_fold( + self.attr.bounds.0.clone().into_iter().collect::<Vec<_>>(), + |mut out, field| { + let fmt_attr = + FieldAttribute::parse_attrs(&field.attrs)?.and_then(|attr| { + match attr { + FieldAttribute::Fmt(fmt) => Some(fmt), + FieldAttribute::Skip => None, + } + }); + let ty = &field.ty; + + if let Some(attr) = fmt_attr { + out.extend(attr.bounded_types(self.fields).map( + |(ty, trait_name)| { + let trait_name = format_ident!("{trait_name}"); + parse_quote! { #ty: ::core::fmt::#trait_name } + }, + )); + } else { + out.extend([parse_quote! { #ty: ::core::fmt::Debug }]); + } + + Ok(out) + }, + ) + } +} diff --git a/third_party/rust/derive_more-impl/src/fmt/display.rs b/third_party/rust/derive_more-impl/src/fmt/display.rs new file mode 100644 index 0000000000..ff8f928070 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/fmt/display.rs @@ -0,0 +1,377 @@ +//! Implementation of [`fmt::Display`]-like derive macros. + +#[cfg(doc)] +use std::fmt; + +use proc_macro2::{Ident, TokenStream}; +use quote::{format_ident, quote}; +use syn::{ + parse::{Parse, ParseStream}, + parse_quote, + spanned::Spanned as _, +}; + +use super::{BoundsAttribute, FmtAttribute}; + +/// Expands a [`fmt::Display`]-like derive macro. +/// +/// Available macros: +/// - [`Binary`](fmt::Binary) +/// - [`Display`](fmt::Display) +/// - [`LowerExp`](fmt::LowerExp) +/// - [`LowerHex`](fmt::LowerHex) +/// - [`Octal`](fmt::Octal) +/// - [`Pointer`](fmt::Pointer) +/// - [`UpperExp`](fmt::UpperExp) +/// - [`UpperHex`](fmt::UpperHex) +pub fn expand(input: &syn::DeriveInput, trait_name: &str) -> syn::Result<TokenStream> { + let trait_name = normalize_trait_name(trait_name); + + let attrs = Attributes::parse_attrs(&input.attrs, trait_name)?; + let trait_ident = format_ident!("{trait_name}"); + let ident = &input.ident; + + let ctx = (&attrs, ident, &trait_ident, trait_name); + let (bounds, body) = match &input.data { + syn::Data::Struct(s) => expand_struct(s, ctx), + syn::Data::Enum(e) => expand_enum(e, ctx), + syn::Data::Union(u) => expand_union(u, ctx), + }?; + + let (impl_gens, ty_gens, where_clause) = { + let (impl_gens, ty_gens, where_clause) = input.generics.split_for_impl(); + let mut where_clause = where_clause + .cloned() + .unwrap_or_else(|| parse_quote! { where }); + where_clause.predicates.extend(bounds); + (impl_gens, ty_gens, where_clause) + }; + + Ok(quote! { + #[automatically_derived] + impl #impl_gens ::core::fmt::#trait_ident for #ident #ty_gens + #where_clause + { + fn fmt( + &self, __derive_more_f: &mut ::core::fmt::Formatter<'_> + ) -> ::core::fmt::Result { + #body + } + } + }) +} + +/// Type alias for an expansion context: +/// - [`Attributes`]. +/// - Struct/enum/union [`Ident`]. +/// - Derived trait [`Ident`]. +/// - Derived trait `&`[`str`]. +type ExpansionCtx<'a> = (&'a Attributes, &'a Ident, &'a Ident, &'a str); + +/// Expands a [`fmt::Display`]-like derive macro for the provided struct. +fn expand_struct( + s: &syn::DataStruct, + (attrs, ident, trait_ident, _): ExpansionCtx<'_>, +) -> syn::Result<(Vec<syn::WherePredicate>, TokenStream)> { + let s = Expansion { + attrs, + fields: &s.fields, + trait_ident, + ident, + }; + let bounds = s.generate_bounds(); + let body = s.generate_body()?; + + let vars = s.fields.iter().enumerate().map(|(i, f)| { + let var = f.ident.clone().unwrap_or_else(|| format_ident!("_{i}")); + let member = f + .ident + .clone() + .map_or_else(|| syn::Member::Unnamed(i.into()), syn::Member::Named); + quote! { + let #var = &self.#member; + } + }); + + let body = quote! { + #( #vars )* + #body + }; + + Ok((bounds, body)) +} + +/// Expands a [`fmt`]-like derive macro for the provided enum. +fn expand_enum( + e: &syn::DataEnum, + (attrs, _, trait_ident, trait_name): ExpansionCtx<'_>, +) -> syn::Result<(Vec<syn::WherePredicate>, TokenStream)> { + if attrs.fmt.is_some() { + todo!("https://github.com/JelteF/derive_more/issues/142"); + } + + let (bounds, match_arms) = e.variants.iter().try_fold( + (Vec::new(), TokenStream::new()), + |(mut bounds, mut arms), variant| { + let attrs = Attributes::parse_attrs(&variant.attrs, trait_name)?; + let ident = &variant.ident; + + if attrs.fmt.is_none() + && variant.fields.is_empty() + && trait_name != "Display" + { + return Err(syn::Error::new( + e.variants.span(), + format!( + "implicit formatting of unit enum variant is supported \ + only for `Display` macro, use `#[{}(\"...\")]` to \ + explicitly specify the formatting", + trait_name_to_attribute_name(trait_name), + ), + )); + } + + let v = Expansion { + attrs: &attrs, + fields: &variant.fields, + trait_ident, + ident, + }; + let arm_body = v.generate_body()?; + bounds.extend(v.generate_bounds()); + + let fields_idents = + variant.fields.iter().enumerate().map(|(i, f)| { + f.ident.clone().unwrap_or_else(|| format_ident!("_{i}")) + }); + let matcher = match variant.fields { + syn::Fields::Named(_) => { + quote! { Self::#ident { #( #fields_idents ),* } } + } + syn::Fields::Unnamed(_) => { + quote! { Self::#ident ( #( #fields_idents ),* ) } + } + syn::Fields::Unit => quote! { Self::#ident }, + }; + + arms.extend([quote! { #matcher => { #arm_body }, }]); + + Ok::<_, syn::Error>((bounds, arms)) + }, + )?; + + let body = match_arms + .is_empty() + .then(|| quote! { match *self {} }) + .unwrap_or_else(|| quote! { match self { #match_arms } }); + + Ok((bounds, body)) +} + +/// Expands a [`fmt::Display`]-like derive macro for the provided union. +fn expand_union( + u: &syn::DataUnion, + (attrs, _, _, trait_name): ExpansionCtx<'_>, +) -> syn::Result<(Vec<syn::WherePredicate>, TokenStream)> { + let fmt = &attrs.fmt.as_ref().ok_or_else(|| { + syn::Error::new( + u.fields.span(), + format!( + "unions must have `#[{}(\"...\", ...)]` attribute", + trait_name_to_attribute_name(trait_name), + ), + ) + })?; + + Ok(( + attrs.bounds.0.clone().into_iter().collect(), + quote! { ::core::write!(__derive_more_f, #fmt) }, + )) +} + +/// Representation of a [`fmt::Display`]-like derive macro attribute. +/// +/// ```rust,ignore +/// #[<fmt_trait>("<fmt_literal>", <fmt_args>)] +/// #[bound(<bounds>)] +/// ``` +/// +/// `#[<fmt_trait>(...)]` can be specified only once, while multiple +/// `#[<fmt_trait>(bound(...))]` are allowed. +#[derive(Debug, Default)] +struct Attributes { + /// Interpolation [`FmtAttribute`]. + fmt: Option<FmtAttribute>, + + /// Addition trait bounds. + bounds: BoundsAttribute, +} + +impl Attributes { + /// Parses [`Attributes`] from the provided [`syn::Attribute`]s. + fn parse_attrs( + attrs: impl AsRef<[syn::Attribute]>, + trait_name: &str, + ) -> syn::Result<Self> { + attrs + .as_ref() + .iter() + .filter(|attr| attr.path().is_ident(trait_name_to_attribute_name(trait_name))) + .try_fold(Attributes::default(), |mut attrs, attr| { + let attr = attr.parse_args::<Attribute>()?; + match attr { + Attribute::Bounds(more) => { + attrs.bounds.0.extend(more.0); + } + Attribute::Fmt(fmt) => { + attrs.fmt.replace(fmt).map_or(Ok(()), |dup| Err(syn::Error::new( + dup.span(), + format!( + "multiple `#[{}(\"...\", ...)]` attributes aren't allowed", + trait_name_to_attribute_name(trait_name), + ))))?; + } + }; + Ok(attrs) + }) + } +} + +/// Representation of a single [`fmt::Display`]-like derive macro attribute. +#[derive(Debug)] +enum Attribute { + /// [`fmt`] attribute. + Fmt(FmtAttribute), + + /// Addition trait bounds. + Bounds(BoundsAttribute), +} + +impl Parse for Attribute { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + BoundsAttribute::check_legacy_fmt(input)?; + FmtAttribute::check_legacy_fmt(input)?; + + if input.peek(syn::LitStr) { + input.parse().map(Attribute::Fmt) + } else { + input.parse().map(Attribute::Bounds) + } + } +} + +/// Helper struct to generate [`Display::fmt()`] implementation body and trait +/// bounds for a struct or an enum variant. +/// +/// [`Display::fmt()`]: fmt::Display::fmt() +#[derive(Debug)] +struct Expansion<'a> { + /// Derive macro [`Attributes`]. + attrs: &'a Attributes, + + /// Struct or enum [`Ident`]. + ident: &'a Ident, + + /// Struct or enum [`syn::Fields`]. + fields: &'a syn::Fields, + + /// [`fmt`] trait [`Ident`]. + trait_ident: &'a Ident, +} + +impl<'a> Expansion<'a> { + /// Generates [`Display::fmt()`] implementation for a struct or an enum variant. + /// + /// # Errors + /// + /// In case [`FmtAttribute`] is [`None`] and [`syn::Fields`] length is + /// greater than 1. + /// + /// [`Display::fmt()`]: fmt::Display::fmt() + fn generate_body(&self) -> syn::Result<TokenStream> { + match &self.attrs.fmt { + Some(fmt) => Ok(quote! { ::core::write!(__derive_more_f, #fmt) }), + None if self.fields.is_empty() => { + let ident_str = self.ident.to_string(); + Ok(quote! { ::core::write!(__derive_more_f, #ident_str) }) + } + None if self.fields.len() == 1 => { + let field = self + .fields + .iter() + .next() + .unwrap_or_else(|| unreachable!("count() == 1")); + let ident = field.ident.clone().unwrap_or_else(|| format_ident!("_0")); + let trait_ident = self.trait_ident; + Ok(quote! { + ::core::fmt::#trait_ident::fmt(#ident, __derive_more_f) + }) + } + _ => Err(syn::Error::new( + self.fields.span(), + format!( + "struct or enum variant with more than 1 field must have \ + `#[{}(\"...\", ...)]` attribute", + trait_name_to_attribute_name(self.trait_ident), + ), + )), + } + } + + /// Generates trait bounds for a struct or an enum variant. + fn generate_bounds(&self) -> Vec<syn::WherePredicate> { + let Some(fmt) = &self.attrs.fmt else { + return self + .fields + .iter() + .next() + .map(|f| { + let ty = &f.ty; + let trait_ident = &self.trait_ident; + vec![parse_quote! { #ty: ::core::fmt::#trait_ident }] + }) + .unwrap_or_default(); + }; + + fmt.bounded_types(self.fields) + .map(|(ty, trait_name)| { + let tr = format_ident!("{}", trait_name); + parse_quote! { #ty: ::core::fmt::#tr } + }) + .chain(self.attrs.bounds.0.clone()) + .collect() + } +} + +/// Matches the provided `trait_name` to appropriate [`Attribute::Fmt`] argument name. +fn trait_name_to_attribute_name<T>(trait_name: T) -> &'static str +where + T: for<'a> PartialEq<&'a str>, +{ + match () { + _ if trait_name == "Binary" => "binary", + _ if trait_name == "Display" => "display", + _ if trait_name == "LowerExp" => "lower_exp", + _ if trait_name == "LowerHex" => "lower_hex", + _ if trait_name == "Octal" => "octal", + _ if trait_name == "Pointer" => "pointer", + _ if trait_name == "UpperExp" => "upper_exp", + _ if trait_name == "UpperHex" => "upper_hex", + _ => unimplemented!(), + } +} + +/// Matches the provided derive macro `name` to appropriate actual trait name. +fn normalize_trait_name(name: &str) -> &'static str { + match name { + "Binary" => "Binary", + "Display" => "Display", + "LowerExp" => "LowerExp", + "LowerHex" => "LowerHex", + "Octal" => "Octal", + "Pointer" => "Pointer", + "UpperExp" => "UpperExp", + "UpperHex" => "UpperHex", + _ => unimplemented!(), + } +} diff --git a/third_party/rust/derive_more-impl/src/fmt/mod.rs b/third_party/rust/derive_more-impl/src/fmt/mod.rs new file mode 100644 index 0000000000..5727d671f5 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/fmt/mod.rs @@ -0,0 +1,444 @@ +//! Implementations of [`fmt`]-like derive macros. +//! +//! [`fmt`]: std::fmt + +#[cfg(feature = "debug")] +pub(crate) mod debug; +#[cfg(feature = "display")] +pub(crate) mod display; +mod parsing; + +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{ + parse::{Parse, ParseStream}, + punctuated::Punctuated, + spanned::Spanned as _, + token, Ident, +}; + +use crate::parsing::Expr; + +/// Representation of a macro attribute expressing additional trait bounds. +#[derive(Debug, Default)] +struct BoundsAttribute(Punctuated<syn::WherePredicate, syn::token::Comma>); + +impl BoundsAttribute { + /// Errors in case legacy syntax is encountered: `bound = "..."`. + fn check_legacy_fmt(input: ParseStream<'_>) -> syn::Result<()> { + let fork = input.fork(); + + let path = fork + .parse::<syn::Path>() + .and_then(|path| fork.parse::<syn::token::Eq>().map(|_| path)); + match path { + Ok(path) if path.is_ident("bound") => fork + .parse::<syn::Lit>() + .ok() + .and_then(|lit| match lit { + syn::Lit::Str(s) => Some(s.value()), + _ => None, + }) + .map_or(Ok(()), |bound| { + Err(syn::Error::new( + input.span(), + format!("legacy syntax, use `bound({bound})` instead"), + )) + }), + Ok(_) | Err(_) => Ok(()), + } + } +} + +impl Parse for BoundsAttribute { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let _ = input.parse::<syn::Path>().and_then(|p| { + if ["bound", "bounds", "where"] + .into_iter() + .any(|i| p.is_ident(i)) + { + Ok(p) + } else { + Err(syn::Error::new( + p.span(), + "unknown attribute, expected `bound(...)`", + )) + } + })?; + + let content; + syn::parenthesized!(content in input); + + content + .parse_terminated(syn::WherePredicate::parse, token::Comma) + .map(Self) + } +} + +/// Representation of a [`fmt`]-like attribute. +/// +/// [`fmt`]: std::fmt +#[derive(Debug)] +struct FmtAttribute { + /// Interpolation [`syn::LitStr`]. + /// + /// [`syn::LitStr`]: struct@syn::LitStr + lit: syn::LitStr, + + /// Optional [`token::Comma`]. + comma: Option<token::Comma>, + + /// Interpolation arguments. + args: Punctuated<FmtArgument, token::Comma>, +} + +impl FmtAttribute { + /// Returns an [`Iterator`] over bounded [`syn::Type`]s and trait names. + fn bounded_types<'a>( + &'a self, + fields: &'a syn::Fields, + ) -> impl Iterator<Item = (&'a syn::Type, &'static str)> { + let placeholders = Placeholder::parse_fmt_string(&self.lit.value()); + + // We ignore unknown fields, as compiler will produce better error messages. + placeholders.into_iter().filter_map(move |placeholder| { + let name = match placeholder.arg { + Parameter::Named(name) => self + .args + .iter() + .find_map(|a| (a.alias()? == &name).then_some(&a.expr)) + .map_or(Some(name), |expr| expr.ident().map(ToString::to_string))?, + Parameter::Positional(i) => self + .args + .iter() + .nth(i) + .and_then(|a| a.expr.ident().filter(|_| a.alias.is_none()))? + .to_string(), + }; + + let unnamed = name.strip_prefix('_').and_then(|s| s.parse().ok()); + let ty = match (&fields, unnamed) { + (syn::Fields::Unnamed(f), Some(i)) => { + f.unnamed.iter().nth(i).map(|f| &f.ty) + } + (syn::Fields::Named(f), None) => f.named.iter().find_map(|f| { + f.ident.as_ref().filter(|s| **s == name).map(|_| &f.ty) + }), + _ => None, + }?; + + Some((ty, placeholder.trait_name)) + }) + } + + /// Errors in case legacy syntax is encountered: `fmt = "...", (arg),*`. + fn check_legacy_fmt(input: ParseStream<'_>) -> syn::Result<()> { + let fork = input.fork(); + + let path = fork + .parse::<syn::Path>() + .and_then(|path| fork.parse::<syn::token::Eq>().map(|_| path)); + match path { + Ok(path) if path.is_ident("fmt") => (|| { + let args = fork + .parse_terminated(syn::Lit::parse, token::Comma) + .ok()? + .into_iter() + .enumerate() + .filter_map(|(i, lit)| match lit { + syn::Lit::Str(str) => Some(if i == 0 { + format!("\"{}\"", str.value()) + } else { + str.value() + }), + _ => None, + }) + .collect::<Vec<_>>(); + (!args.is_empty()).then_some(args) + })() + .map_or(Ok(()), |fmt| { + Err(syn::Error::new( + input.span(), + format!( + "legacy syntax, remove `fmt =` and use `{}` instead", + fmt.join(", "), + ), + )) + }), + Ok(_) | Err(_) => Ok(()), + } + } +} + +impl Parse for FmtAttribute { + fn parse(input: ParseStream) -> syn::Result<Self> { + Ok(Self { + lit: input.parse()?, + comma: input + .peek(syn::token::Comma) + .then(|| input.parse()) + .transpose()?, + args: input.parse_terminated(FmtArgument::parse, token::Comma)?, + }) + } +} + +impl ToTokens for FmtAttribute { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lit.to_tokens(tokens); + self.comma.to_tokens(tokens); + self.args.to_tokens(tokens); + } +} + +/// Representation of a [named parameter][1] (`identifier '=' expression`) in +/// in a [`FmtAttribute`]. +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#named-parameters +#[derive(Debug)] +struct FmtArgument { + /// `identifier =` [`Ident`]. + alias: Option<(Ident, token::Eq)>, + + /// `expression` [`Expr`]. + expr: Expr, +} + +impl FmtArgument { + /// Returns an `identifier` of the [named parameter][1]. + /// + /// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#named-parameters + fn alias(&self) -> Option<&Ident> { + self.alias.as_ref().map(|(ident, _)| ident) + } +} + +impl Parse for FmtArgument { + fn parse(input: ParseStream) -> syn::Result<Self> { + Ok(Self { + alias: (input.peek(Ident) && input.peek2(token::Eq)) + .then(|| Ok::<_, syn::Error>((input.parse()?, input.parse()?))) + .transpose()?, + expr: input.parse()?, + }) + } +} + +impl ToTokens for FmtArgument { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some((ident, eq)) = &self.alias { + ident.to_tokens(tokens); + eq.to_tokens(tokens); + } + self.expr.to_tokens(tokens); + } +} + +/// Representation of a [parameter][1] used in a [`Placeholder`]. +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#formatting-parameters +#[derive(Debug, Eq, PartialEq)] +enum Parameter { + /// [Positional parameter][1]. + /// + /// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#positional-parameters + Positional(usize), + + /// [Named parameter][1]. + /// + /// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#named-parameters + Named(String), +} + +impl<'a> From<parsing::Argument<'a>> for Parameter { + fn from(arg: parsing::Argument<'a>) -> Self { + match arg { + parsing::Argument::Integer(i) => Self::Positional(i), + parsing::Argument::Identifier(i) => Self::Named(i.to_owned()), + } + } +} + +/// Representation of a formatting placeholder. +#[derive(Debug, PartialEq, Eq)] +struct Placeholder { + /// Formatting argument (either named or positional) to be used by this placeholder. + arg: Parameter, + + /// [Width parameter][1], if present. + /// + /// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#width + width: Option<Parameter>, + + /// [Precision parameter][1], if present. + /// + /// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#precision + precision: Option<Parameter>, + + /// Name of [`std::fmt`] trait to be used for rendering this placeholder. + trait_name: &'static str, +} + +impl Placeholder { + /// Parses [`Placeholder`]s from the provided formatting string. + fn parse_fmt_string(s: &str) -> Vec<Self> { + let mut n = 0; + parsing::format_string(s) + .into_iter() + .flat_map(|f| f.formats) + .map(|format| { + let (maybe_arg, ty) = ( + format.arg, + format.spec.map(|s| s.ty).unwrap_or(parsing::Type::Display), + ); + let position = maybe_arg.map(Into::into).unwrap_or_else(|| { + // Assign "the next argument". + // https://doc.rust-lang.org/stable/std/fmt/index.html#positional-parameters + n += 1; + Parameter::Positional(n - 1) + }); + + Self { + arg: position, + width: format.spec.and_then(|s| match s.width { + Some(parsing::Count::Parameter(arg)) => Some(arg.into()), + _ => None, + }), + precision: format.spec.and_then(|s| match s.precision { + Some(parsing::Precision::Count(parsing::Count::Parameter( + arg, + ))) => Some(arg.into()), + _ => None, + }), + trait_name: ty.trait_name(), + } + }) + .collect() + } +} + +#[cfg(test)] +mod fmt_attribute_spec { + use itertools::Itertools as _; + use quote::ToTokens; + use syn; + + use super::FmtAttribute; + + fn assert<'a>(input: &'a str, parsed: impl AsRef<[&'a str]>) { + let parsed = parsed.as_ref(); + let attr = syn::parse_str::<FmtAttribute>(&format!("\"\", {}", input)).unwrap(); + let fmt_args = attr + .args + .into_iter() + .map(|arg| arg.into_token_stream().to_string()) + .collect::<Vec<String>>(); + fmt_args.iter().zip_eq(parsed).enumerate().for_each( + |(i, (found, expected))| { + assert_eq!( + *expected, found, + "Mismatch at index {i}\n\ + Expected: {parsed:?}\n\ + Found: {fmt_args:?}", + ); + }, + ); + } + + #[test] + fn cases() { + let cases = [ + "ident", + "alias = ident", + "[a , b , c , d]", + "counter += 1", + "async { fut . await }", + "a < b", + "a > b", + "{ let x = (a , b) ; }", + "invoke (a , b)", + "foo as f64", + "| a , b | a + b", + "obj . k", + "for pat in expr { break pat ; }", + "if expr { true } else { false }", + "vector [2]", + "1", + "\"foo\"", + "loop { break i ; }", + "format ! (\"{}\" , q)", + "match n { Some (n) => { } , None => { } }", + "x . foo ::< T > (a , b)", + "x . foo ::< T < [T < T >; if a < b { 1 } else { 2 }] >, { a < b } > (a , b)", + "(a + b)", + "i32 :: MAX", + "1 .. 2", + "& a", + "[0u8 ; N]", + "(a , b , c , d)", + "< Ty as Trait > :: T", + "< Ty < Ty < T >, { a < b } > as Trait < T > > :: T", + ]; + + assert("", []); + for i in 1..4 { + for permutations in cases.into_iter().permutations(i) { + let mut input = permutations.clone().join(","); + assert(&input, &permutations); + input.push(','); + assert(&input, &permutations); + } + } + } +} + +#[cfg(test)] +mod placeholder_parse_fmt_string_spec { + use super::{Parameter, Placeholder}; + + #[test] + fn indicates_position_and_trait_name_for_each_fmt_placeholder() { + let fmt_string = "{},{:?},{{}},{{{1:0$}}}-{2:.1$x}{par:#?}{:width$}"; + assert_eq!( + Placeholder::parse_fmt_string(&fmt_string), + vec![ + Placeholder { + arg: Parameter::Positional(0), + width: None, + precision: None, + trait_name: "Display", + }, + Placeholder { + arg: Parameter::Positional(1), + width: None, + precision: None, + trait_name: "Debug", + }, + Placeholder { + arg: Parameter::Positional(1), + width: Some(Parameter::Positional(0)), + precision: None, + trait_name: "Display", + }, + Placeholder { + arg: Parameter::Positional(2), + width: None, + precision: Some(Parameter::Positional(1)), + trait_name: "LowerHex", + }, + Placeholder { + arg: Parameter::Named("par".to_owned()), + width: None, + precision: None, + trait_name: "Debug", + }, + Placeholder { + arg: Parameter::Positional(2), + width: Some(Parameter::Named("width".to_owned())), + precision: None, + trait_name: "Display", + }, + ], + ); + } +} diff --git a/third_party/rust/derive_more-impl/src/fmt/parsing.rs b/third_party/rust/derive_more-impl/src/fmt/parsing.rs new file mode 100644 index 0000000000..e4586668f0 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/fmt/parsing.rs @@ -0,0 +1,1096 @@ +//! Parsing of [Rust `fmt` syntax][0]. +//! +//! [0]: std::fmt#syntax + +use std::{convert::identity, iter}; + +use unicode_xid::UnicodeXID as XID; + +/// Output of the [`format_string`] parser. +#[derive(Debug, Clone, Eq, PartialEq)] +pub(crate) struct FormatString<'a> { + pub(crate) formats: Vec<Format<'a>>, +} + +/// Output of the [`format`] parser. +/// +/// [`format`]: fn@format +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) struct Format<'a> { + pub(crate) arg: Option<Argument<'a>>, + pub(crate) spec: Option<FormatSpec<'a>>, +} + +/// Output of the [`format_spec`] parser. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) struct FormatSpec<'a> { + pub(crate) width: Option<Width<'a>>, + pub(crate) precision: Option<Precision<'a>>, + pub(crate) ty: Type, +} + +/// Output of the [`argument`] parser. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) enum Argument<'a> { + Integer(usize), + Identifier(&'a str), +} + +/// Output of the [`precision`] parser. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) enum Precision<'a> { + Count(Count<'a>), + Star, +} + +/// Output of the [`count`] parser. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) enum Count<'a> { + Integer(usize), + Parameter(Parameter<'a>), +} + +/// Output of the [`type_`] parser. See [formatting traits][1] for more info. +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#formatting-traits +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) enum Type { + Display, + Debug, + LowerDebug, + UpperDebug, + Octal, + LowerHex, + UpperHex, + Pointer, + Binary, + LowerExp, + UpperExp, +} + +impl Type { + /// Returns trait name of this [`Type`]. + pub(crate) fn trait_name(&self) -> &'static str { + match self { + Type::Display => "Display", + Type::Debug | Type::LowerDebug | Type::UpperDebug => "Debug", + Type::Octal => "Octal", + Type::LowerHex => "LowerHex", + Type::UpperHex => "UpperHex", + Type::Pointer => "Pointer", + Type::Binary => "Binary", + Type::LowerExp => "LowerExp", + Type::UpperExp => "UpperExp", + } + } +} + +/// Type alias for the [`FormatSpec::width`]. +type Width<'a> = Count<'a>; + +/// Output of the [`maybe_format`] parser. +type MaybeFormat<'a> = Option<Format<'a>>; + +/// Output of the [`identifier`] parser. +type Identifier<'a> = &'a str; + +/// Output of the [`parameter`] parser. +type Parameter<'a> = Argument<'a>; + +/// [`str`] left to parse. +/// +/// [`str`]: prim@str +type LeftToParse<'a> = &'a str; + +/// Parses a `format_string` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`format_string`]` := `[`text`]` [`[`maybe_format text`]`] *` +/// +/// # Example +/// +/// ```text +/// Hello +/// Hello, {}! +/// {:?} +/// Hello {people}! +/// {} {} +/// {:04} +/// {par:-^#.0$?} +/// ``` +/// +/// # Return value +/// +/// - [`Some`] in case of successful parse. +/// - [`None`] otherwise (not all characters are consumed by underlying +/// parsers). +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +pub(crate) fn format_string(input: &str) -> Option<FormatString<'_>> { + let (mut input, _) = optional_result(text)(input); + + let formats = iter::repeat(()) + .scan(&mut input, |input, _| { + let (curr, format) = + alt(&mut [&mut maybe_format, &mut map(text, |(i, _)| (i, None))])( + input, + )?; + **input = curr; + Some(format) + }) + .flatten() + .collect(); + + // Should consume all tokens for a successful parse. + input.is_empty().then_some(FormatString { formats }) +} + +/// Parses a `maybe_format` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`maybe_format`]` := '{' '{' | '}' '}' | `[`format`] +/// +/// # Example +/// +/// ```text +/// {{ +/// }} +/// {:04} +/// {:#?} +/// {par:-^#.0$?} +/// ``` +/// +/// [`format`]: fn@format +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn maybe_format(input: &str) -> Option<(LeftToParse<'_>, MaybeFormat<'_>)> { + alt(&mut [ + &mut map(str("{{"), |i| (i, None)), + &mut map(str("}}"), |i| (i, None)), + &mut map(format, |(i, format)| (i, Some(format))), + ])(input) +} + +/// Parses a `format` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`format`]` := '{' [`[`argument`]`] [':' `[`format_spec`]`] '}'` +/// +/// # Example +/// +/// ```text +/// {par} +/// {:#?} +/// {par:-^#.0$?} +/// ``` +/// +/// [`format`]: fn@format +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn format(input: &str) -> Option<(LeftToParse<'_>, Format<'_>)> { + let input = char('{')(input)?; + + let (input, arg) = optional_result(argument)(input); + + let (input, spec) = map_or_else( + char(':'), + |i| Some((i, None)), + map(format_spec, |(i, s)| (i, Some(s))), + )(input)?; + + let input = char('}')(input)?; + + Some((input, Format { arg, spec })) +} + +/// Parses an `argument` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`argument`]` := `[`integer`]` | `[`identifier`] +/// +/// # Example +/// +/// ```text +/// 0 +/// ident +/// Минск +/// ``` +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn argument(input: &str) -> Option<(LeftToParse<'_>, Argument)> { + alt(&mut [ + &mut map(identifier, |(i, ident)| (i, Argument::Identifier(ident))), + &mut map(integer, |(i, int)| (i, Argument::Integer(int))), + ])(input) +} + +/// Parses a `format_spec` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`format_spec`]` := [[fill]align][sign]['#']['0'][width]` +/// `['.' `[`precision`]`]`[`type`] +/// +/// # Example +/// +/// ```text +/// ^ +/// <^ +/// ->+#0width$.precision$x? +/// ``` +/// +/// [`type`]: type_ +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn format_spec(input: &str) -> Option<(LeftToParse<'_>, FormatSpec<'_>)> { + let input = unwrap_or_else( + alt(&mut [ + &mut try_seq(&mut [&mut any_char, &mut one_of("<^>")]), + &mut one_of("<^>"), + ]), + identity, + )(input); + + let input = seq(&mut [ + &mut optional(one_of("+-")), + &mut optional(char('#')), + &mut optional(try_seq(&mut [ + &mut char('0'), + &mut lookahead(check_char(|c| !matches!(c, '$'))), + ])), + ])(input); + + let (input, width) = optional_result(count)(input); + + let (input, precision) = map_or_else( + char('.'), + |i| Some((i, None)), + map(precision, |(i, p)| (i, Some(p))), + )(input)?; + + let (input, ty) = type_(input)?; + + Some(( + input, + FormatSpec { + width, + precision, + ty, + }, + )) +} + +/// Parses a `precision` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`precision`]` := `[`count`]` | '*'` +/// +/// # Example +/// +/// ```text +/// 0 +/// 42$ +/// par$ +/// * +/// ``` +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn precision(input: &str) -> Option<(LeftToParse<'_>, Precision<'_>)> { + alt(&mut [ + &mut map(count, |(i, c)| (i, Precision::Count(c))), + &mut map(char('*'), |i| (i, Precision::Star)), + ])(input) +} + +/// Parses a `type` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`type`]` := '' | '?' | 'x?' | 'X?' | identifier` +/// +/// # Example +/// +/// All possible [`Type`]s. +/// +/// ```text +/// ? +/// x? +/// X? +/// o +/// x +/// X +/// p +/// b +/// e +/// E +/// ``` +/// +/// [`type`]: type_ +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn type_(input: &str) -> Option<(&str, Type)> { + alt(&mut [ + &mut map(str("x?"), |i| (i, Type::LowerDebug)), + &mut map(str("X?"), |i| (i, Type::UpperDebug)), + &mut map(char('?'), |i| (i, Type::Debug)), + &mut map(char('o'), |i| (i, Type::Octal)), + &mut map(char('x'), |i| (i, Type::LowerHex)), + &mut map(char('X'), |i| (i, Type::UpperHex)), + &mut map(char('p'), |i| (i, Type::Pointer)), + &mut map(char('b'), |i| (i, Type::Binary)), + &mut map(char('e'), |i| (i, Type::LowerExp)), + &mut map(char('E'), |i| (i, Type::UpperExp)), + &mut map(lookahead(char('}')), |i| (i, Type::Display)), + ])(input) +} + +/// Parses a `count` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`count`]` := `[`parameter`]` | `[`integer`] +/// +/// # Example +/// +/// ```text +/// 0 +/// 42$ +/// par$ +/// ``` +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn count(input: &str) -> Option<(LeftToParse<'_>, Count<'_>)> { + alt(&mut [ + &mut map(parameter, |(i, p)| (i, Count::Parameter(p))), + &mut map(integer, |(i, int)| (i, Count::Integer(int))), + ])(input) +} + +/// Parses a `parameter` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// [`parameter`]` := `[`argument`]` '$'` +/// +/// # Example +/// +/// ```text +/// 42$ +/// par$ +/// ``` +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn parameter(input: &str) -> Option<(LeftToParse<'_>, Parameter<'_>)> { + and_then(argument, |(i, arg)| map(char('$'), |i| (i, arg))(i))(input) +} + +/// Parses an `identifier` as defined in the [grammar spec][1]. +/// +/// # Grammar +/// +/// `IDENTIFIER_OR_KEYWORD : XID_Start XID_Continue* | _ XID_Continue+` +/// +/// See [rust reference][2] for more info. +/// +/// # Example +/// +/// ```text +/// identifier +/// Минск +/// ``` +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +/// [2]: https://doc.rust-lang.org/reference/identifiers.html +fn identifier(input: &str) -> Option<(LeftToParse<'_>, Identifier<'_>)> { + map( + alt(&mut [ + &mut map( + check_char(XID::is_xid_start), + take_while0(check_char(XID::is_xid_continue)), + ), + &mut and_then(char('_'), take_while1(check_char(XID::is_xid_continue))), + ]), + |(i, _)| (i, &input[..(input.as_bytes().len() - i.as_bytes().len())]), + )(input) +} + +/// Parses an `integer` as defined in the [grammar spec][1]. +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn integer(input: &str) -> Option<(LeftToParse<'_>, usize)> { + and_then( + take_while1(check_char(|c| c.is_ascii_digit())), + |(i, int)| int.parse().ok().map(|int| (i, int)), + )(input) +} + +/// Parses a `text` as defined in the [grammar spec][1]. +/// +/// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax +fn text(input: &str) -> Option<(LeftToParse<'_>, &str)> { + take_until1(any_char, one_of("{}"))(input) +} + +type Parser<'p> = &'p mut dyn FnMut(&str) -> &str; + +/// Applies non-failing parsers in sequence. +fn seq<'p>(parsers: &'p mut [Parser<'p>]) -> impl FnMut(&str) -> LeftToParse<'_> + 'p { + move |input| parsers.iter_mut().fold(input, |i, p| (**p)(i)) +} + +type FallibleParser<'p> = &'p mut dyn FnMut(&str) -> Option<&str>; + +/// Tries to apply parsers in sequence. Returns [`None`] in case one of them +/// returned [`None`]. +fn try_seq<'p>( + parsers: &'p mut [FallibleParser<'p>], +) -> impl FnMut(&str) -> Option<LeftToParse<'_>> + 'p { + move |input| parsers.iter_mut().try_fold(input, |i, p| (**p)(i)) +} + +/// Returns first successful parser or [`None`] in case all of them returned +/// [`None`]. +fn alt<'p, 'i, T: 'i>( + parsers: &'p mut [&'p mut dyn FnMut(&'i str) -> Option<T>], +) -> impl FnMut(&'i str) -> Option<T> + 'p { + move |input| parsers.iter_mut().find_map(|p| (**p)(input)) +} + +/// Maps output of the parser in case it returned [`Some`]. +fn map<'i, I: 'i, O: 'i>( + mut parser: impl FnMut(&'i str) -> Option<I>, + mut f: impl FnMut(I) -> O, +) -> impl FnMut(&'i str) -> Option<O> { + move |input| parser(input).map(&mut f) +} + +/// Maps output of the parser in case it returned [`Some`] or uses `default`. +fn map_or_else<'i, I: 'i, O: 'i>( + mut parser: impl FnMut(&'i str) -> Option<I>, + mut default: impl FnMut(&'i str) -> O, + mut f: impl FnMut(I) -> O, +) -> impl FnMut(&'i str) -> O { + move |input| parser(input).map_or_else(|| default(input), &mut f) +} + +/// Returns the contained [`Some`] value or computes it from a closure. +fn unwrap_or_else<'i, O: 'i>( + mut parser: impl FnMut(&'i str) -> Option<O>, + mut f: impl FnMut(&'i str) -> O, +) -> impl FnMut(&'i str) -> O { + move |input| parser(input).unwrap_or_else(|| f(input)) +} + +/// Returns [`None`] if the parser returned is [`None`], otherwise calls `f` +/// with the wrapped value and returns the result. +fn and_then<'i, I: 'i, O: 'i>( + mut parser: impl FnMut(&'i str) -> Option<I>, + mut f: impl FnMut(I) -> Option<O>, +) -> impl FnMut(&'i str) -> Option<O> { + move |input| parser(input).and_then(&mut f) +} + +/// Checks whether `parser` is successful while not advancing the original +/// `input`. +fn lookahead( + mut parser: impl FnMut(&str) -> Option<&str>, +) -> impl FnMut(&str) -> Option<LeftToParse<'_>> { + move |input| map(&mut parser, |_| input)(input) +} + +/// Makes underlying `parser` optional by returning the original `input` in case +/// it returned [`None`]. +fn optional( + mut parser: impl FnMut(&str) -> Option<&str>, +) -> impl FnMut(&str) -> LeftToParse<'_> { + move |input: &str| parser(input).unwrap_or(input) +} + +/// Makes underlying `parser` optional by returning the original `input` and +/// [`None`] in case it returned [`None`]. +fn optional_result<'i, T: 'i>( + mut parser: impl FnMut(&'i str) -> Option<(&'i str, T)>, +) -> impl FnMut(&'i str) -> (LeftToParse<'i>, Option<T>) { + move |input: &str| { + map_or_else(&mut parser, |i| (i, None), |(i, c)| (i, Some(c)))(input) + } +} + +/// Parses while `parser` is successful. Never fails. +fn take_while0( + mut parser: impl FnMut(&str) -> Option<&str>, +) -> impl FnMut(&str) -> (LeftToParse<'_>, &str) { + move |input| { + let mut cur = input; + while let Some(step) = parser(cur) { + cur = step; + } + ( + cur, + &input[..(input.as_bytes().len() - cur.as_bytes().len())], + ) + } +} + +/// Parses while `parser` is successful. Returns [`None`] in case `parser` never +/// succeeded. +fn take_while1( + mut parser: impl FnMut(&str) -> Option<&str>, +) -> impl FnMut(&str) -> Option<(LeftToParse<'_>, &str)> { + move |input| { + let mut cur = parser(input)?; + while let Some(step) = parser(cur) { + cur = step; + } + Some(( + cur, + &input[..(input.as_bytes().len() - cur.as_bytes().len())], + )) + } +} + +/// Parses with `basic` while `until` returns [`None`]. Returns [`None`] in case +/// `until` succeeded initially or `basic` never succeeded. Doesn't consume +/// [`char`]s parsed by `until`. +/// +/// [`char`]: fn@char +fn take_until1( + mut basic: impl FnMut(&str) -> Option<&str>, + mut until: impl FnMut(&str) -> Option<&str>, +) -> impl FnMut(&str) -> Option<(LeftToParse<'_>, &str)> { + move |input: &str| { + if until(input).is_some() { + return None; + } + let mut cur = basic(input)?; + loop { + if until(cur).is_some() { + break; + } + let Some(b) = basic(cur) else { + break; + }; + cur = b; + } + + Some(( + cur, + &input[..(input.as_bytes().len() - cur.as_bytes().len())], + )) + } +} + +/// Checks whether `input` starts with `s`. +fn str(s: &str) -> impl FnMut(&str) -> Option<LeftToParse<'_>> + '_ { + move |input| input.starts_with(s).then(|| &input[s.as_bytes().len()..]) +} + +/// Checks whether `input` starts with `c`. +fn char(c: char) -> impl FnMut(&str) -> Option<LeftToParse<'_>> { + move |input| input.starts_with(c).then(|| &input[c.len_utf8()..]) +} + +/// Checks whether first [`char`] suits `check`. +/// +/// [`char`]: fn@char +fn check_char( + mut check: impl FnMut(char) -> bool, +) -> impl FnMut(&str) -> Option<LeftToParse<'_>> { + move |input| { + input + .chars() + .next() + .and_then(|c| check(c).then(|| &input[c.len_utf8()..])) + } +} + +/// Checks whether first [`char`] of input is present in `chars`. +/// +/// [`char`]: fn@char +fn one_of(chars: &str) -> impl FnMut(&str) -> Option<LeftToParse<'_>> + '_ { + move |input: &str| chars.chars().find_map(|c| char(c)(input)) +} + +/// Parses any [`char`]. +/// +/// [`char`]: fn@char +fn any_char(input: &str) -> Option<LeftToParse<'_>> { + input.chars().next().map(|c| &input[c.len_utf8()..]) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn text() { + assert_eq!(format_string(""), Some(FormatString { formats: vec![] })); + assert_eq!( + format_string("test"), + Some(FormatString { formats: vec![] }), + ); + assert_eq!( + format_string("Минск"), + Some(FormatString { formats: vec![] }), + ); + assert_eq!(format_string("🦀"), Some(FormatString { formats: vec![] })); + } + + #[test] + fn argument() { + assert_eq!( + format_string("{}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: None, + }], + }), + ); + assert_eq!( + format_string("{0}"), + Some(FormatString { + formats: vec![Format { + arg: Some(Argument::Integer(0)), + spec: None, + }], + }), + ); + assert_eq!( + format_string("{par}"), + Some(FormatString { + formats: vec![Format { + arg: Some(Argument::Identifier("par")), + spec: None, + }], + }), + ); + assert_eq!( + format_string("{Минск}"), + Some(FormatString { + formats: vec![Format { + arg: Some(Argument::Identifier("Минск")), + spec: None, + }], + }), + ); + } + + #[test] + fn spec() { + assert_eq!( + format_string("{:}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:^}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:-<}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{: <}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:^<}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:+}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:^<-}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:#}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:+#}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:-<#}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:^<-#}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:0}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:#0}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:-0}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:^<0}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:^<+#0}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:1}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: Some(Count::Integer(1)), + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:1$}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: Some(Count::Parameter(Argument::Integer(1))), + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:par$}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: Some(Count::Parameter(Argument::Identifier("par"))), + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:-^-#0Минск$}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: Some(Count::Parameter(Argument::Identifier("Минск"))), + precision: None, + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:.*}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: Some(Precision::Star), + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:.0}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: Some(Precision::Count(Count::Integer(0))), + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:.0$}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: Some(Precision::Count(Count::Parameter( + Argument::Integer(0), + ))), + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:.par$}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: Some(Precision::Count(Count::Parameter( + Argument::Identifier("par"), + ))), + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{: >+#2$.par$}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: Some(Count::Parameter(Argument::Integer(2))), + precision: Some(Precision::Count(Count::Parameter( + Argument::Identifier("par"), + ))), + ty: Type::Display, + }), + }], + }), + ); + assert_eq!( + format_string("{:x?}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::LowerDebug, + }), + }], + }), + ); + assert_eq!( + format_string("{:E}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::UpperExp, + }), + }], + }), + ); + assert_eq!( + format_string("{: >+#par$.par$X?}"), + Some(FormatString { + formats: vec![Format { + arg: None, + spec: Some(FormatSpec { + width: Some(Count::Parameter(Argument::Identifier("par"))), + precision: Some(Precision::Count(Count::Parameter( + Argument::Identifier("par"), + ))), + ty: Type::UpperDebug, + }), + }], + }), + ); + } + + #[test] + fn full() { + assert_eq!( + format_string("prefix{{{0:#?}postfix{par:-^par$.a$}}}"), + Some(FormatString { + formats: vec![ + Format { + arg: Some(Argument::Integer(0)), + spec: Some(FormatSpec { + width: None, + precision: None, + ty: Type::Debug, + }), + }, + Format { + arg: Some(Argument::Identifier("par")), + spec: Some(FormatSpec { + width: Some(Count::Parameter(Argument::Identifier("par"))), + precision: Some(Precision::Count(Count::Parameter( + Argument::Identifier("a"), + ))), + ty: Type::Display, + }), + }, + ], + }), + ); + } + + #[test] + fn error() { + assert_eq!(format_string("{"), None); + assert_eq!(format_string("}"), None); + assert_eq!(format_string("{{}"), None); + assert_eq!(format_string("{:x?"), None); + assert_eq!(format_string("{:.}"), None); + assert_eq!(format_string("{:q}"), None); + assert_eq!(format_string("{:par}"), None); + assert_eq!(format_string("{⚙️}"), None); + } +} diff --git a/third_party/rust/derive_more-impl/src/from.rs b/third_party/rust/derive_more-impl/src/from.rs new file mode 100644 index 0000000000..cefab9baac --- /dev/null +++ b/third_party/rust/derive_more-impl/src/from.rs @@ -0,0 +1,478 @@ +//! Implementation of a [`From`] derive macro. + +use std::iter; + +use proc_macro2::{Span, TokenStream}; +use quote::{format_ident, quote, ToTokens as _, TokenStreamExt as _}; +use syn::{ + parse::{discouraged::Speculative as _, Parse, ParseStream}, + parse_quote, + punctuated::Punctuated, + spanned::Spanned as _, + token, Ident, +}; + +use crate::{ + parsing::Type, + utils::{polyfill, Either}, +}; + +/// Expands a [`From`] derive macro. +pub fn expand(input: &syn::DeriveInput, _: &'static str) -> syn::Result<TokenStream> { + match &input.data { + syn::Data::Struct(data) => Expansion { + attrs: StructAttribute::parse_attrs(&input.attrs, &data.fields)? + .map(Into::into) + .as_ref(), + ident: &input.ident, + variant: None, + fields: &data.fields, + generics: &input.generics, + has_explicit_from: false, + } + .expand(), + syn::Data::Enum(data) => { + let mut has_explicit_from = false; + let attrs = data + .variants + .iter() + .map(|variant| { + let attrs = + VariantAttribute::parse_attrs(&variant.attrs, &variant.fields)?; + if matches!( + attrs, + Some( + VariantAttribute::From + | VariantAttribute::Types(_) + | VariantAttribute::Forward + ), + ) { + has_explicit_from = true; + } + Ok(attrs) + }) + .collect::<syn::Result<Vec<_>>>()?; + + data.variants + .iter() + .zip(&attrs) + .map(|(variant, attrs)| { + Expansion { + attrs: attrs.as_ref(), + ident: &input.ident, + variant: Some(&variant.ident), + fields: &variant.fields, + generics: &input.generics, + has_explicit_from, + } + .expand() + }) + .collect() + } + syn::Data::Union(data) => Err(syn::Error::new( + data.union_token.span(), + "`From` cannot be derived for unions", + )), + } +} + +/// Representation of a [`From`] derive macro struct container attribute. +/// +/// ```rust,ignore +/// #[from(<types>)] +/// #[from(forward)] +/// ``` +enum StructAttribute { + /// [`Type`]s to derive [`From`]. + Types(Punctuated<Type, token::Comma>), + + /// Forward [`From`] implementation. + Forward, +} + +impl StructAttribute { + /// Parses a [`StructAttribute`] from the provided [`syn::Attribute`]s. + fn parse_attrs( + attrs: impl AsRef<[syn::Attribute]>, + fields: &syn::Fields, + ) -> syn::Result<Option<Self>> { + Ok(attrs + .as_ref() + .iter() + .filter(|attr| attr.path().is_ident("from")) + .try_fold(None, |attrs, attr| { + let field_attr = attr.parse_args_with(|stream: ParseStream<'_>| { + Self::parse(stream, fields) + })?; + match (attrs, field_attr) { + ( + Some((path, StructAttribute::Types(mut tys))), + StructAttribute::Types(more), + ) => { + tys.extend(more); + Ok(Some((path, StructAttribute::Types(tys)))) + } + (None, field_attr) => Ok(Some((attr.path(), field_attr))), + _ => Err(syn::Error::new( + attr.path().span(), + "only single `#[from(...)]` attribute is allowed here", + )), + } + })? + .map(|(_, attr)| attr)) + } + + /// Parses single [`StructAttribute`]. + fn parse(input: ParseStream<'_>, fields: &syn::Fields) -> syn::Result<Self> { + let ahead = input.fork(); + match ahead.parse::<syn::Path>() { + Ok(p) if p.is_ident("forward") => { + input.advance_to(&ahead); + Ok(Self::Forward) + } + Ok(p) if p.is_ident("types") => legacy_error(&ahead, input.span(), fields), + _ => input + .parse_terminated(Type::parse, token::Comma) + .map(Self::Types), + } + } +} + +/// Representation of a [`From`] derive macro enum variant attribute. +/// +/// ```rust,ignore +/// #[from] +/// #[from(<types>)] +/// #[from(forward)] +/// #[from(skip)] +/// ``` +enum VariantAttribute { + /// Explicitly derive [`From`]. + From, + + /// [`Type`]s to derive [`From`]. + Types(Punctuated<Type, token::Comma>), + + /// Forward [`From`] implementation. + Forward, + + /// Skip variant. + Skip, +} + +impl VariantAttribute { + /// Parses a [`VariantAttribute`] from the provided [`syn::Attribute`]s. + fn parse_attrs( + attrs: impl AsRef<[syn::Attribute]>, + fields: &syn::Fields, + ) -> syn::Result<Option<Self>> { + Ok(attrs + .as_ref() + .iter() + .filter(|attr| attr.path().is_ident("from")) + .try_fold(None, |mut attrs, attr| { + let field_attr = Self::parse_attr(attr, fields)?; + if let Some((path, _)) = attrs.replace((attr.path(), field_attr)) { + Err(syn::Error::new( + path.span(), + "only single `#[from(...)]` attribute is allowed here", + )) + } else { + Ok(attrs) + } + })? + .map(|(_, attr)| attr)) + } + + /// Parses a [`VariantAttribute`] from the single provided [`syn::Attribute`]. + fn parse_attr(attr: &syn::Attribute, fields: &syn::Fields) -> syn::Result<Self> { + if matches!(attr.meta, syn::Meta::Path(_)) { + return Ok(Self::From); + } + + attr.parse_args_with(|input: ParseStream<'_>| { + let ahead = input.fork(); + match ahead.parse::<syn::Path>() { + Ok(p) if p.is_ident("forward") => { + input.advance_to(&ahead); + Ok(Self::Forward) + } + Ok(p) if p.is_ident("skip") || p.is_ident("ignore") => { + input.advance_to(&ahead); + Ok(Self::Skip) + } + Ok(p) if p.is_ident("types") => { + legacy_error(&ahead, input.span(), fields) + } + _ => input + .parse_terminated(Type::parse, token::Comma) + .map(Self::Types), + } + }) + } +} + +impl From<StructAttribute> for VariantAttribute { + fn from(value: StructAttribute) -> Self { + match value { + StructAttribute::Types(tys) => Self::Types(tys), + StructAttribute::Forward => Self::Forward, + } + } +} + +/// Expansion of a macro for generating [`From`] implementation of a struct or +/// enum. +struct Expansion<'a> { + /// [`From`] attributes. + /// + /// As a [`VariantAttribute`] is superset of a [`StructAttribute`], we use + /// it for both derives. + attrs: Option<&'a VariantAttribute>, + + /// Struct or enum [`Ident`]. + ident: &'a Ident, + + /// Variant [`Ident`] in case of enum expansion. + variant: Option<&'a Ident>, + + /// Struct or variant [`syn::Fields`]. + fields: &'a syn::Fields, + + /// Struct or enum [`syn::Generics`]. + generics: &'a syn::Generics, + + /// Indicator whether one of the enum variants has + /// [`VariantAttribute::From`], [`VariantAttribute::Types`] or + /// [`VariantAttribute::Forward`]. + /// + /// Always [`false`] for structs. + has_explicit_from: bool, +} + +impl<'a> Expansion<'a> { + /// Expands [`From`] implementations for a struct or an enum variant. + fn expand(&self) -> syn::Result<TokenStream> { + use crate::utils::FieldsExt as _; + + let ident = self.ident; + let field_tys = self.fields.iter().map(|f| &f.ty).collect::<Vec<_>>(); + let (impl_gens, ty_gens, where_clause) = self.generics.split_for_impl(); + + let skip_variant = self.has_explicit_from + || (self.variant.is_some() && self.fields.is_empty()); + match (self.attrs, skip_variant) { + (Some(VariantAttribute::Types(tys)), _) => { + tys.iter().map(|ty| { + let variant = self.variant.iter(); + + let mut from_tys = self.fields.validate_type(ty)?; + let init = self.expand_fields(|ident, ty, index| { + let ident = ident.into_iter(); + let index = index.into_iter(); + let from_ty = from_tys.next().unwrap_or_else(|| unreachable!()); + quote! { + #( #ident: )* <#ty as ::core::convert::From<#from_ty>>::from( + value #( .#index )* + ), + } + }); + + Ok(quote! { + #[automatically_derived] + impl #impl_gens ::core::convert::From<#ty> + for #ident #ty_gens #where_clause + { + #[inline] + fn from(value: #ty) -> Self { + #ident #( :: #variant )* #init + } + } + }) + }) + .collect() + } + (Some(VariantAttribute::From), _) | (None, false) => { + let variant = self.variant.iter(); + let init = self.expand_fields(|ident, _, index| { + let ident = ident.into_iter(); + let index = index.into_iter(); + quote! { #( #ident: )* value #( . #index )*, } + }); + + Ok(quote! { + #[automatically_derived] + impl #impl_gens ::core::convert::From<(#( #field_tys ),*)> + for #ident #ty_gens #where_clause + { + #[inline] + fn from(value: (#( #field_tys ),*)) -> Self { + #ident #( :: #variant )* #init + } + } + }) + } + (Some(VariantAttribute::Forward), _) => { + let mut i = 0; + let mut gen_idents = Vec::with_capacity(self.fields.len()); + let init = self.expand_fields(|ident, ty, index| { + let ident = ident.into_iter(); + let index = index.into_iter(); + let gen_ident = format_ident!("__FromT{i}"); + let out = quote! { + #( #ident: )* <#ty as ::core::convert::From<#gen_ident>>::from( + value #( .#index )* + ), + }; + gen_idents.push(gen_ident); + i += 1; + out + }); + + let variant = self.variant.iter(); + let generics = { + let mut generics = self.generics.clone(); + for (ty, ident) in field_tys.iter().zip(&gen_idents) { + generics.make_where_clause().predicates.push( + parse_quote! { #ty: ::core::convert::From<#ident> }, + ); + generics + .params + .push(syn::TypeParam::from(ident.clone()).into()); + } + generics + }; + let (impl_gens, _, where_clause) = generics.split_for_impl(); + + Ok(quote! { + #[automatically_derived] + impl #impl_gens ::core::convert::From<(#( #gen_idents ),*)> + for #ident #ty_gens #where_clause + { + #[inline] + fn from(value: (#( #gen_idents ),*)) -> Self { + #ident #(:: #variant)* #init + } + } + }) + } + (Some(VariantAttribute::Skip), _) | (None, true) => { + Ok(TokenStream::new()) + } + } + } + + /// Expands fields initialization wrapped into [`token::Brace`]s in case of + /// [`syn::FieldsNamed`], or [`token::Paren`] in case of + /// [`syn::FieldsUnnamed`]. + fn expand_fields( + &self, + mut wrap: impl FnMut(Option<&Ident>, &syn::Type, Option<syn::Index>) -> TokenStream, + ) -> TokenStream { + let surround = match self.fields { + syn::Fields::Named(_) | syn::Fields::Unnamed(_) => { + Some(|tokens| match self.fields { + syn::Fields::Named(named) => { + let mut out = TokenStream::new(); + named + .brace_token + .surround(&mut out, |out| out.append_all(tokens)); + out + } + syn::Fields::Unnamed(unnamed) => { + let mut out = TokenStream::new(); + unnamed + .paren_token + .surround(&mut out, |out| out.append_all(tokens)); + out + } + syn::Fields::Unit => unreachable!(), + }) + } + syn::Fields::Unit => None, + }; + + surround + .map(|surround| { + surround(if self.fields.len() == 1 { + let field = self + .fields + .iter() + .next() + .unwrap_or_else(|| unreachable!("self.fields.len() == 1")); + wrap(field.ident.as_ref(), &field.ty, None) + } else { + self.fields + .iter() + .enumerate() + .map(|(i, field)| { + wrap(field.ident.as_ref(), &field.ty, Some(i.into())) + }) + .collect() + }) + }) + .unwrap_or_default() + } +} + +/// Constructs a [`syn::Error`] for legacy syntax: `#[from(types(i32, "&str"))]`. +fn legacy_error<T>( + tokens: ParseStream<'_>, + span: Span, + fields: &syn::Fields, +) -> syn::Result<T> { + let content; + syn::parenthesized!(content in tokens); + + let types = content + .parse_terminated(polyfill::NestedMeta::parse, token::Comma)? + .into_iter() + .map(|meta| { + let value = match meta { + polyfill::NestedMeta::Meta(meta) => { + meta.into_token_stream().to_string() + } + polyfill::NestedMeta::Lit(syn::Lit::Str(str)) => str.value(), + polyfill::NestedMeta::Lit(_) => unreachable!(), + }; + if fields.len() > 1 { + format!( + "({})", + fields + .iter() + .map(|_| value.clone()) + .collect::<Vec<_>>() + .join(", "), + ) + } else { + value + } + }) + .chain(match fields.len() { + 0 => Either::Left(iter::empty()), + 1 => Either::Right(iter::once( + fields + .iter() + .next() + .unwrap_or_else(|| unreachable!("fields.len() == 1")) + .ty + .to_token_stream() + .to_string(), + )), + _ => Either::Right(iter::once(format!( + "({})", + fields + .iter() + .map(|f| f.ty.to_token_stream().to_string()) + .collect::<Vec<_>>() + .join(", ") + ))), + }) + .collect::<Vec<_>>() + .join(", "); + + Err(syn::Error::new( + span, + format!("legacy syntax, remove `types` and use `{types}` instead"), + )) +} diff --git a/third_party/rust/derive_more-impl/src/from_str.rs b/third_party/rust/derive_more-impl/src/from_str.rs new file mode 100644 index 0000000000..bc0ec5413a --- /dev/null +++ b/third_party/rust/derive_more-impl/src/from_str.rs @@ -0,0 +1,112 @@ +use crate::utils::{DeriveType, HashMap}; +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, trait_name.to_lowercase())?; + + if state.derive_type == DeriveType::Enum { + Ok(enum_from(input, state, trait_name)) + } else { + Ok(struct_from(&state, trait_name)) + } +} + +pub fn struct_from(state: &State, trait_name: &'static str) -> TokenStream { + // 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); + + quote! { + #[automatically_derived] + 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 enum_from( + input: &DeriveInput, + state: State, + trait_name: &'static str, +) -> TokenStream { + let mut variants_caseinsensitive = HashMap::default(); + for variant_state in state.enabled_variant_data().variant_states { + let variant = variant_state.variant.unwrap(); + if !variant.fields.is_empty() { + panic!("Only enums with no fields can derive({trait_name})") + } + + variants_caseinsensitive + .entry(variant.ident.to_string().to_lowercase()) + .or_insert_with(Vec::new) + .push(variant.ident.clone()); + } + + let input_type = &input.ident; + let input_type_name = input_type.to_string(); + + let mut cases = vec![]; + + // if a case insensitive match is unique match do that + // otherwise do a case sensitive match + for (ref canonical, ref variants) in variants_caseinsensitive { + if variants.len() == 1 { + let variant = &variants[0]; + cases.push(quote! { + #canonical => #input_type::#variant, + }) + } else { + for variant in variants { + let variant_str = variant.to_string(); + cases.push(quote! { + #canonical if(src == #variant_str) => #input_type::#variant, + }) + } + } + } + + let trait_path = state.trait_path; + + quote! { + impl #trait_path for #input_type { + type Err = ::derive_more::FromStrError; + + #[inline] + fn from_str(src: &str) -> ::core::result::Result<Self, Self::Err> { + Ok(match src.to_lowercase().as_str() { + #(#cases)* + _ => return Err(::derive_more::FromStrError::new(#input_type_name)), + }) + } + } + } +} + +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-impl/src/index.rs b/third_party/rust/derive_more-impl/src/index.rs new file mode 100644 index 0000000000..bf4f0d7b19 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/index.rs @@ -0,0 +1,47 @@ +use crate::utils::{add_where_clauses_for_new_ident, SingleFieldData, State}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse::Result, DeriveInput}; + +/// 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 = format_ident!("__IdxT"); + let mut state = + State::with_field_ignore(input, trait_name, 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! { + #[automatically_derived] + 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-impl/src/index_mut.rs b/third_party/rust/derive_more-impl/src/index_mut.rs new file mode 100644 index 0000000000..0e030cf6f5 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/index_mut.rs @@ -0,0 +1,44 @@ +use crate::utils::{add_where_clauses_for_new_ident, SingleFieldData, State}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse::Result, DeriveInput}; + +/// 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 = format_ident!("__IdxT"); + let mut state = State::with_field_ignore(input, trait_name, "index_mut".into())?; + 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! { + #[automatically_derived] + 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-impl/src/into.rs b/third_party/rust/derive_more-impl/src/into.rs new file mode 100644 index 0000000000..91e23bf403 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/into.rs @@ -0,0 +1,448 @@ +//! Implementation of an [`Into`] derive macro. + +use std::{borrow::Cow, iter}; + +use proc_macro2::{Span, TokenStream}; +use quote::{quote, ToTokens as _}; +use syn::{ + ext::IdentExt as _, + parse::{discouraged::Speculative as _, Parse, ParseStream}, + punctuated::Punctuated, + spanned::Spanned as _, + token, Ident, +}; + +use crate::{ + parsing::Type, + utils::{polyfill, Either, FieldsExt as _}, +}; + +/// Expands an [`Into`] derive macro. +pub fn expand(input: &syn::DeriveInput, _: &'static str) -> syn::Result<TokenStream> { + let data = match &input.data { + syn::Data::Struct(data) => Ok(data), + syn::Data::Enum(e) => Err(syn::Error::new( + e.enum_token.span(), + "`Into` cannot be derived for enums", + )), + syn::Data::Union(u) => Err(syn::Error::new( + u.union_token.span(), + "`Into` cannot be derived for unions", + )), + }?; + + let attr = StructAttribute::parse_attrs(&input.attrs, &data.fields)? + .unwrap_or_else(|| StructAttribute { + owned: Some(Punctuated::new()), + r#ref: None, + ref_mut: None, + }); + let ident = &input.ident; + let fields = data + .fields + .iter() + .enumerate() + .filter_map(|(i, f)| match SkipFieldAttribute::parse_attrs(&f.attrs) { + Ok(None) => Some(Ok(( + &f.ty, + f.ident + .as_ref() + .map_or_else(|| Either::Right(syn::Index::from(i)), Either::Left), + ))), + Ok(Some(_)) => None, + Err(e) => Some(Err(e)), + }) + .collect::<syn::Result<Vec<_>>>()?; + let (fields_tys, fields_idents): (Vec<_>, Vec<_>) = fields.into_iter().unzip(); + let (fields_tys, fields_idents) = (&fields_tys, &fields_idents); + + let expand = |tys: Option<Punctuated<_, _>>, r: bool, m: bool| { + let Some(tys) = tys else { + return Either::Left(iter::empty()); + }; + + let lf = + r.then(|| syn::Lifetime::new("'__derive_more_into", Span::call_site())); + let r = r.then(token::And::default); + let m = m.then(token::Mut::default); + + let gens = if let Some(lf) = lf.clone() { + let mut gens = input.generics.clone(); + gens.params.push(syn::LifetimeParam::new(lf).into()); + Cow::Owned(gens) + } else { + Cow::Borrowed(&input.generics) + }; + + Either::Right( + if tys.is_empty() { + Either::Left(iter::once(Type::tuple(fields_tys.clone()))) + } else { + Either::Right(tys.into_iter()) + } + .map(move |ty| { + let tys = fields_tys.validate_type(&ty)?.collect::<Vec<_>>(); + let (impl_gens, _, where_clause) = gens.split_for_impl(); + let (_, ty_gens, _) = input.generics.split_for_impl(); + + Ok(quote! { + #[automatically_derived] + impl #impl_gens ::core::convert::From<#r #lf #m #ident #ty_gens> + for ( #( #r #lf #m #tys ),* ) #where_clause + { + #[inline] + fn from(value: #r #lf #m #ident #ty_gens) -> Self { + (#( + <#r #m #tys as ::core::convert::From<_>>::from( + #r #m value. #fields_idents + ) + ),*) + } + } + }) + }), + ) + }; + + [ + expand(attr.owned, false, false), + expand(attr.r#ref, true, false), + expand(attr.ref_mut, true, true), + ] + .into_iter() + .flatten() + .collect() +} + +/// Representation of an [`Into`] derive macro struct container attribute. +/// +/// ```rust,ignore +/// #[into(<types>)] +/// #[into(owned(<types>), ref(<types>), ref_mut(<types>))] +/// ``` +#[derive(Debug, Default)] +struct StructAttribute { + /// [`Type`]s wrapped into `owned(...)` or simply `#[into(...)]`. + owned: Option<Punctuated<Type, token::Comma>>, + + /// [`Type`]s wrapped into `ref(...)`. + r#ref: Option<Punctuated<Type, token::Comma>>, + + /// [`Type`]s wrapped into `ref_mut(...)`. + ref_mut: Option<Punctuated<Type, token::Comma>>, +} + +impl StructAttribute { + /// Parses a [`StructAttribute`] from the provided [`syn::Attribute`]s. + fn parse_attrs( + attrs: impl AsRef<[syn::Attribute]>, + fields: &syn::Fields, + ) -> syn::Result<Option<Self>> { + fn infer<T>(v: T) -> T + where + T: for<'a> FnOnce(ParseStream<'a>) -> syn::Result<StructAttribute>, + { + v + } + + attrs + .as_ref() + .iter() + .filter(|attr| attr.path().is_ident("into")) + .try_fold(None, |mut attrs, attr| { + let merge = |out: &mut Option<_>, tys| match (out.as_mut(), tys) { + (None, Some(tys)) => { + *out = Some::<Punctuated<_, _>>(tys); + } + (Some(out), Some(tys)) => out.extend(tys), + (Some(_), None) | (None, None) => {} + }; + + let field_attr = + attr.parse_args_with(infer(|stream| Self::parse(stream, fields)))?; + let out = attrs.get_or_insert_with(Self::default); + merge(&mut out.owned, field_attr.owned); + merge(&mut out.r#ref, field_attr.r#ref); + merge(&mut out.ref_mut, field_attr.ref_mut); + + Ok(attrs) + }) + } + + /// Parses a single [`StructAttribute`]. + fn parse(content: ParseStream<'_>, fields: &syn::Fields) -> syn::Result<Self> { + check_legacy_syntax(content, fields)?; + + let mut out = Self::default(); + + let parse_inner = |ahead, types: &mut Option<_>| { + content.advance_to(&ahead); + + let types = types.get_or_insert_with(Punctuated::new); + if content.peek(token::Paren) { + let inner; + syn::parenthesized!(inner in content); + + types.extend( + inner + .parse_terminated(Type::parse, token::Comma)? + .into_pairs(), + ); + } + if content.peek(token::Comma) { + let comma = content.parse::<token::Comma>()?; + if !types.empty_or_trailing() { + types.push_punct(comma); + } + } + + Ok(()) + }; + + let mut has_wrapped_type = false; + let mut top_level_type = None; + + while !content.is_empty() { + let ahead = content.fork(); + let res = if ahead.peek(Ident::peek_any) { + ahead.call(Ident::parse_any).map(Into::into) + } else { + ahead.parse::<syn::Path>() + }; + match res { + Ok(p) if p.is_ident("owned") => { + has_wrapped_type = true; + parse_inner(ahead, &mut out.owned)?; + } + Ok(p) if p.is_ident("ref") => { + has_wrapped_type = true; + parse_inner(ahead, &mut out.r#ref)?; + } + Ok(p) if p.is_ident("ref_mut") => { + has_wrapped_type = true; + parse_inner(ahead, &mut out.ref_mut)?; + } + _ => { + let ty = content.parse::<Type>()?; + let _ = top_level_type.get_or_insert_with(|| ty.clone()); + out.owned.get_or_insert_with(Punctuated::new).push_value(ty); + + if content.peek(token::Comma) { + out.owned + .get_or_insert_with(Punctuated::new) + .push_punct(content.parse::<token::Comma>()?) + } + } + } + } + + if let Some(ty) = top_level_type.filter(|_| has_wrapped_type) { + Err(syn::Error::new( + ty.span(), + format!( + "mixing regular types with wrapped into \ + `owned`/`ref`/`ref_mut` is not allowed, try wrapping \ + this type into `owned({ty}), ref({ty}), ref_mut({ty})`", + ty = ty.into_token_stream(), + ), + )) + } else { + Ok(out) + } + } +} + +/// `#[into(skip)]` field attribute. +struct SkipFieldAttribute; + +impl SkipFieldAttribute { + /// Parses a [`SkipFieldAttribute`] from the provided [`syn::Attribute`]s. + fn parse_attrs(attrs: impl AsRef<[syn::Attribute]>) -> syn::Result<Option<Self>> { + Ok(attrs + .as_ref() + .iter() + .filter(|attr| attr.path().is_ident("into")) + .try_fold(None, |mut attrs, attr| { + let field_attr = attr.parse_args::<SkipFieldAttribute>()?; + if let Some((path, _)) = attrs.replace((attr.path(), field_attr)) { + Err(syn::Error::new( + path.span(), + "only single `#[into(...)]` attribute is allowed here", + )) + } else { + Ok(attrs) + } + })? + .map(|(_, attr)| attr)) + } +} + +impl Parse for SkipFieldAttribute { + fn parse(content: ParseStream) -> syn::Result<Self> { + match content.parse::<syn::Path>()? { + p if p.is_ident("skip") | p.is_ident("ignore") => Ok(Self), + p => Err(syn::Error::new( + p.span(), + format!("expected `skip`, found: `{}`", p.into_token_stream()), + )), + } + } +} + +/// [`Error`]ors for legacy syntax: `#[into(types(i32, "&str"))]`. +fn check_legacy_syntax( + tokens: ParseStream<'_>, + fields: &syn::Fields, +) -> syn::Result<()> { + let span = tokens.span(); + let tokens = tokens.fork(); + + let map_ty = |s: String| { + if fields.len() > 1 { + format!( + "({})", + (0..fields.len()) + .map(|_| s.as_str()) + .collect::<Vec<_>>() + .join(", ") + ) + } else { + s + } + }; + let field = match fields.len() { + 0 => None, + 1 => Some( + fields + .iter() + .next() + .unwrap_or_else(|| unreachable!("fields.len() == 1")) + .ty + .to_token_stream() + .to_string(), + ), + _ => Some(format!( + "({})", + fields + .iter() + .map(|f| f.ty.to_token_stream().to_string()) + .collect::<Vec<_>>() + .join(", ") + )), + }; + + let Ok(metas) = tokens.parse_terminated(polyfill::Meta::parse, token::Comma) else { + return Ok(()); + }; + + let parse_list = |list: polyfill::MetaList, attrs: &mut Option<Vec<_>>| { + if !list.path.is_ident("types") { + return None; + } + for meta in list + .parse_args_with(Punctuated::<_, token::Comma>::parse_terminated) + .ok()? + { + attrs.get_or_insert_with(Vec::new).push(match meta { + polyfill::NestedMeta::Lit(syn::Lit::Str(str)) => str.value(), + polyfill::NestedMeta::Meta(polyfill::Meta::Path(path)) => { + path.into_token_stream().to_string() + } + _ => return None, + }) + } + Some(()) + }; + + let Some((top_level, owned, ref_, ref_mut)) = metas + .into_iter() + .try_fold( + (None, None, None, None), + |(mut top_level, mut owned, mut ref_, mut ref_mut), meta| { + let is = |name| { + matches!(&meta, polyfill::Meta::Path(p) if p.is_ident(name)) + || matches!(&meta, polyfill::Meta::List(list) if list.path.is_ident(name)) + }; + let parse_inner = |meta, attrs: &mut Option<_>| { + match meta { + polyfill::Meta::Path(_) => { + let _ = attrs.get_or_insert_with(Vec::new); + Some(()) + } + polyfill::Meta::List(list) => { + if let polyfill::NestedMeta::Meta(polyfill::Meta::List(list)) = list + .parse_args_with(Punctuated::<_, token::Comma>::parse_terminated) + .ok()? + .pop()? + .into_value() + { + parse_list(list, attrs) + } else { + None + } + } + } + }; + + match meta { + meta if is("owned") => parse_inner(meta, &mut owned), + meta if is("ref") => parse_inner(meta, &mut ref_), + meta if is("ref_mut") => parse_inner(meta, &mut ref_mut), + polyfill::Meta::List(list) => parse_list(list, &mut top_level), + _ => None, + } + .map(|_| (top_level, owned, ref_, ref_mut)) + }, + ) + .filter(|(top_level, owned, ref_, ref_mut)| { + [top_level, owned, ref_, ref_mut] + .into_iter() + .any(|l| l.as_ref().map_or(false, |l| !l.is_empty())) + }) + else { + return Ok(()); + }; + + if [&owned, &ref_, &ref_mut].into_iter().any(Option::is_some) { + let format = |list: Option<Vec<_>>, name: &str| match list { + Some(l) + if top_level.as_ref().map_or(true, Vec::is_empty) && l.is_empty() => + { + Some(name.to_owned()) + } + Some(l) => Some(format!( + "{}({})", + name, + l.into_iter() + .chain(top_level.clone().into_iter().flatten()) + .map(map_ty) + .chain(field.clone()) + .collect::<Vec<_>>() + .join(", "), + )), + None => None, + }; + let format = [ + format(owned, "owned"), + format(ref_, "ref"), + format(ref_mut, "ref_mut"), + ] + .into_iter() + .flatten() + .collect::<Vec<_>>() + .join(", "); + + Err(syn::Error::new( + span, + format!("legacy syntax, use `{format}` instead"), + )) + } else { + Err(syn::Error::new( + span, + format!( + "legacy syntax, remove `types` and use `{}` instead", + top_level.unwrap_or_else(|| unreachable!()).join(", "), + ), + )) + } +} diff --git a/third_party/rust/derive_more-impl/src/into_iterator.rs b/third_party/rust/derive_more-impl/src/into_iterator.rs new file mode 100644 index 0000000000..f10dbf7a0b --- /dev/null +++ b/third_party/rust/derive_more-impl/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, "into_iterator".into())?; + 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! { + #[automatically_derived] + 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-impl/src/is_variant.rs b/third_party/rust/derive_more-impl/src/is_variant.rs new file mode 100644 index 0000000000..123e3fb7bb --- /dev/null +++ b/third_party/rust/derive_more-impl/src/is_variant.rs @@ -0,0 +1,65 @@ +use crate::utils::{AttrParams, DeriveType, State}; +use convert_case::{Case, Casing}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use syn::{DeriveInput, Fields, Result}; + +pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> { + let state = State::with_attr_params( + input, + trait_name, + "is_variant".into(), + 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 = format_ident!( + "is_{}", + variant.ident.to_string().to_case(Case::Snake), + span = variant.ident.span(), + ); + let variant_ident = &variant.ident; + + let data_pattern = match variant.fields { + Fields::Named(_) => quote! { {..} }, + Fields::Unnamed(_) => quote! { (..) }, + Fields::Unit => quote! {}, + }; + let variant_name = stringify!(variant_ident); + let func = quote! { + #[doc = "Returns `true` if this value is of type `"] + #[doc = #variant_name] + #[doc = "`. Returns `false` otherwise"] + pub const fn #fn_name(&self) -> bool { + match self { + #enum_name ::#variant_ident #data_pattern => true, + _ => false + } + } + }; + funcs.push(func); + } + + let imp = quote! { + #[automatically_derived] + impl #imp_generics #enum_name #type_generics #where_clause { + #(#funcs)* + } + }; + + Ok(imp) +} diff --git a/third_party/rust/derive_more-impl/src/lib.rs b/third_party/rust/derive_more-impl/src/lib.rs new file mode 100644 index 0000000000..8cb86b1f1a --- /dev/null +++ b/third_party/rust/derive_more-impl/src/lib.rs @@ -0,0 +1,281 @@ +#![doc = include_str!("../README.md")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![recursion_limit = "128"] +#![cfg_attr(any(not(docsrs), ci), deny(rustdoc::all))] +#![forbid(non_ascii_idents, unsafe_code)] +#![warn(clippy::nonstandard_macro_braces)] + +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 = "error")] +mod error; +#[cfg(any(feature = "debug", feature = "display"))] +mod fmt; +#[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(any( + feature = "debug", + feature = "display", + feature = "from", + feature = "into", +))] +pub(crate) mod parsing; +#[cfg(feature = "sum")] +mod sum_like; +#[cfg(feature = "try_into")] +mod try_into; +#[cfg(feature = "try_unwrap")] +mod try_unwrap; +#[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 $(:: $mod_rest:ident)*, $trait_:ident, $fn_name: ident $(,$attribute:ident)* $(,)?) => { + #[cfg(feature = $feature)] + #[proc_macro_derive($trait_, attributes($($attribute),*))] + #[doc = include_str!(concat!("../doc/", $feature, ".md"))] + pub fn $fn_name(input: TokenStream) -> TokenStream { + let ast = syn::parse(input).unwrap(); + Output::process($mod_$(:: $mod_rest)*::expand(&ast, stringify!($trait_))) + } + } +); + +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!("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!("as_mut", as_mut, AsMut, as_mut_derive, as_mut); + +create_derive!("as_ref", as_ref, AsRef, as_ref_derive, as_ref); + +create_derive!("constructor", constructor, Constructor, constructor_derive); + +create_derive!("debug", fmt::debug, Debug, debug_derive, debug); + +create_derive!("deref", deref, Deref, deref_derive, deref); + +create_derive!( + "deref_mut", + deref_mut, + DerefMut, + deref_mut_derive, + deref_mut, +); + +create_derive!("display", fmt::display, Display, display_derive, display); +create_derive!("display", fmt::display, Binary, binary_derive, binary); +create_derive!("display", fmt::display, Octal, octal_derive, octal); +create_derive!( + "display", + fmt::display, + LowerHex, + lower_hex_derive, + lower_hex, +); +create_derive!( + "display", + fmt::display, + UpperHex, + upper_hex_derive, + upper_hex, +); +create_derive!( + "display", + fmt::display, + LowerExp, + lower_exp_derive, + lower_exp, +); +create_derive!( + "display", + fmt::display, + UpperExp, + upper_exp_derive, + upper_exp, +); +create_derive!("display", fmt::display, Pointer, pointer_derive, pointer); + +create_derive!("error", error, Error, error_derive, error); + +create_derive!("from", from, From, from_derive, from); + +create_derive!("from_str", from_str, FromStr, from_str_derive); + +create_derive!("index", index, Index, index_derive, index); + +create_derive!( + "index_mut", + index_mut, + IndexMut, + index_mut_derive, + index_mut, +); + +create_derive!("into", into, Into, into_derive, into); + +create_derive!( + "into_iterator", + into_iterator, + IntoIterator, + into_iterator_derive, + into_iterator, +); + +create_derive!( + "is_variant", + is_variant, + IsVariant, + is_variant_derive, + is_variant, +); + +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!( + "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!("not", not_like, Not, not_derive); +create_derive!("not", not_like, Neg, neg_derive); + +create_derive!("sum", sum_like, Sum, sum_derive); +create_derive!("sum", sum_like, Product, product_derive); + +create_derive!("try_into", try_into, TryInto, try_into_derive, try_into); + +create_derive!( + "try_unwrap", + try_unwrap, + TryUnwrap, + try_unwrap_derive, + try_unwrap, +); + +create_derive!("unwrap", unwrap, Unwrap, unwrap_derive, unwrap); diff --git a/third_party/rust/derive_more-impl/src/mul_assign_like.rs b/third_party/rust/derive_more-impl/src/mul_assign_like.rs new file mode 100644 index 0000000000..8e3f2cb760 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/mul_assign_like.rs @@ -0,0 +1,63 @@ +use crate::add_assign_like; +use crate::mul_helpers::generics_and_exprs; +use crate::utils::{AttrParams, HashSet, MultiFieldData, RefType, State}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use std::iter; +use syn::{DeriveInput, 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, + method_name, + AttrParams::struct_(vec!["forward"]), + )?; + if state.default_info.forward { + return Ok(add_assign_like::expand(input, trait_name)); + } + let scalar_ident = format_ident!("__RhsT"); + 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! { + #[automatically_derived] + 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-impl/src/mul_helpers.rs b/third_party/rust/derive_more-impl/src/mul_helpers.rs new file mode 100644 index 0000000000..dbc1c6257c --- /dev/null +++ b/third_party/rust/derive_more-impl/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-impl/src/mul_like.rs b/third_party/rust/derive_more-impl/src/mul_like.rs new file mode 100644 index 0000000000..d06372f38a --- /dev/null +++ b/third_party/rust/derive_more-impl/src/mul_like.rs @@ -0,0 +1,61 @@ +use crate::add_like; +use crate::mul_helpers::generics_and_exprs; +use crate::utils::{AttrParams, HashSet, MultiFieldData, RefType, State}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use std::iter; +use syn::{DeriveInput, Result}; + +pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> { + let mut state = State::with_attr_params( + input, + trait_name, + trait_name.to_lowercase(), + AttrParams::struct_(vec!["forward"]), + )?; + if state.default_info.forward { + return Ok(add_like::expand(input, trait_name)); + } + + let scalar_ident = format_ident!("__RhsT"); + 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! { + #[automatically_derived] + 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-impl/src/not_like.rs b/third_party/rust/derive_more-impl/src/not_like.rs new file mode 100644 index 0000000000..6bab7c8ec0 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/not_like.rs @@ -0,0 +1,171 @@ +use crate::utils::{ + add_extra_type_param_bound_op_output, named_to_vec, unnamed_to_vec, +}; +use proc_macro2::TokenStream; +use quote::{format_ident, 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 = format_ident!("{trait_name}"); + let method_name = trait_name.to_lowercase(); + let method_ident = format_ident!("{method_name}"); + 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! { + #[automatically_derived] + 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 pattern 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| format_ident!("__{i}")).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 pattern 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| format_ident!("__{i}")).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 operation_name = method_ident.to_string(); + matches.push(quote! { + #subtype => ::core::result::Result::Err( + ::derive_more::ops::UnitError::new(#operation_name) + ) + }); + } + } + } + + let body = quote! { + match self { + #(#matches),* + } + }; + + let output_type = if has_unit_type { + quote! { ::core::result::Result<#input_type #ty_generics, ::derive_more::ops::UnitError> } + } else { + quote! { #input_type #ty_generics } + }; + + (output_type, body) +} diff --git a/third_party/rust/derive_more-impl/src/parsing.rs b/third_party/rust/derive_more-impl/src/parsing.rs new file mode 100644 index 0000000000..42b66376f5 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/parsing.rs @@ -0,0 +1,469 @@ +//! Common parsing utilities for derive macros. +//! +//! Fair parsing of [`syn::Type`] and [`syn::Expr`] requires [`syn`]'s `full` +//! feature to be enabled, which unnecessary increases compile times. As we +//! don't have complex AST manipulation, usually requiring only understanding +//! where syntax item begins and ends, simpler manual parsing is implemented. + +use proc_macro2::{Delimiter, Spacing, TokenStream}; +use quote::ToTokens; +use syn::{ + buffer::Cursor, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + spanned::Spanned as _, + token, Error, Ident, Result, +}; + +/// [`syn::Type`] [`Parse`]ing polyfill. +#[derive(Clone, Debug)] +pub(crate) enum Type { + /// [`syn::Type::Tuple`] [`Parse`]ing polyfill. + Tuple { + paren: token::Paren, + items: Punctuated<TokenStream, token::Comma>, + }, + + /// Every other [`syn::Type`] variant. + Other(TokenStream), +} + +impl Type { + /// Creates a [`Type::Tuple`] from the provided [`Iterator`] of [`TokenStream`]s. + pub(crate) fn tuple<T: ToTokens>(items: impl IntoIterator<Item = T>) -> Self { + Self::Tuple { + paren: token::Paren::default(), + items: items.into_iter().map(ToTokens::into_token_stream).collect(), + } + } +} + +impl Parse for Type { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|c| { + let outer = *c; + + if let Some((mut cursor, paren_span, next_item)) = + outer.group(Delimiter::Parenthesis) + { + let mut items = Punctuated::new(); + while !cursor.eof() { + let (stream, c) = Self::parse_other(cursor).ok_or_else(|| { + Error::new(cursor.span(), "failed to parse type") + })?; + items.push_value(stream); + cursor = c; + if let Some((p, c)) = punct(',')(cursor) { + items.push_punct(token::Comma(p.span())); + cursor = c; + } + } + // `(Type)` is equivalent to `Type`, so isn't top-level tuple. + if items.len() == 1 && !items.trailing_punct() { + let stream = outer + .token_tree() + .unwrap_or_else(|| unreachable!()) + .0 + .into_token_stream(); + Ok((Type::Other(stream), next_item)) + } else { + Ok(( + Type::Tuple { + paren: token::Paren(paren_span), + items, + }, + next_item, + )) + } + } else { + Self::parse_other(outer) + .map(|(s, c)| (Self::Other(s), c)) + .ok_or_else(|| Error::new(outer.span(), "failed to parse type")) + } + }) + } +} + +impl ToTokens for Type { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Type::Tuple { paren, items } => { + paren.surround(tokens, |tokens| items.to_tokens(tokens)) + } + Type::Other(other) => other.to_tokens(tokens), + } + } +} + +impl Type { + /// Parses a single [`Type::Other`]. + pub fn parse_other(c: Cursor<'_>) -> Option<(TokenStream, Cursor<'_>)> { + take_until1( + alt([&mut balanced_pair(punct('<'), punct('>')), &mut token_tree]), + punct(','), + )(c) + } +} + +/// [`syn::Expr`] [`Parse`]ing polyfill. +#[derive(Debug)] +pub(crate) enum Expr { + /// [`syn::Expr::Path`] of length 1 [`Parse`]ing polyfill. + Ident(Ident), + + /// Every other [`syn::Expr`] variant. + Other(TokenStream), +} + +impl Expr { + /// Returns an [`Ident`] in case this [`Expr`] is represented only by it. + pub(crate) fn ident(&self) -> Option<&Ident> { + match self { + Self::Ident(ident) => Some(ident), + Self::Other(_) => None, + } + } +} + +impl Parse for Expr { + fn parse(input: ParseStream) -> Result<Self> { + if let Ok(ident) = input.step(|c| { + c.ident() + .filter(|(_, c)| c.eof() || punct(',')(*c).is_some()) + .ok_or_else(|| Error::new(c.span(), "expected `ident(,|eof)`")) + }) { + Ok(Self::Ident(ident)) + } else { + input.step(|c| { + take_until1( + alt([ + &mut seq([ + &mut colon2, + &mut balanced_pair(punct('<'), punct('>')), + ]), + &mut seq([ + &mut balanced_pair(punct('<'), punct('>')), + &mut colon2, + ]), + &mut balanced_pair(punct('|'), punct('|')), + &mut token_tree, + ]), + punct(','), + )(*c) + .map(|(stream, cursor)| (Self::Other(stream), cursor)) + .ok_or_else(|| Error::new(c.span(), "failed to parse expression")) + }) + } + } +} + +impl ToTokens for Expr { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Ident(ident) => ident.to_tokens(tokens), + Self::Other(other) => other.to_tokens(tokens), + } + } +} + +/// Result of parsing. +type ParsingResult<'a> = Option<(TokenStream, Cursor<'a>)>; + +/// Tries to parse a [`syn::token::Colon2`]. +pub fn colon2(c: Cursor<'_>) -> ParsingResult<'_> { + seq([ + &mut punct_with_spacing(':', Spacing::Joint), + &mut punct(':'), + ])(c) +} + +/// Tries to parse a [`punct`] with [`Spacing`]. +pub fn punct_with_spacing( + p: char, + spacing: Spacing, +) -> impl FnMut(Cursor<'_>) -> ParsingResult<'_> { + move |c| { + c.punct().and_then(|(punct, c)| { + (punct.as_char() == p && punct.spacing() == spacing) + .then(|| (punct.into_token_stream(), c)) + }) + } +} + +/// Tries to parse a [`Punct`]. +/// +/// [`Punct`]: proc_macro2::Punct +pub fn punct(p: char) -> impl FnMut(Cursor<'_>) -> ParsingResult<'_> { + move |c| { + c.punct().and_then(|(punct, c)| { + (punct.as_char() == p).then(|| (punct.into_token_stream(), c)) + }) + } +} + +/// Tries to parse any [`TokenTree`]. +/// +/// [`TokenTree`]: proc_macro2::TokenTree +pub fn token_tree(c: Cursor<'_>) -> ParsingResult<'_> { + c.token_tree().map(|(tt, c)| (tt.into_token_stream(), c)) +} + +/// Parses until balanced amount of `open` and `close` or eof. +/// +/// [`Cursor`] should be pointing **right after** the first `open`ing. +pub fn balanced_pair( + mut open: impl FnMut(Cursor<'_>) -> ParsingResult<'_>, + mut close: impl FnMut(Cursor<'_>) -> ParsingResult<'_>, +) -> impl FnMut(Cursor<'_>) -> ParsingResult<'_> { + move |c| { + let (mut out, mut c) = open(c)?; + let mut count = 1; + + while count != 0 { + let (stream, cursor) = if let Some(closing) = close(c) { + count -= 1; + closing + } else if let Some(opening) = open(c) { + count += 1; + opening + } else { + let (tt, c) = c.token_tree()?; + (tt.into_token_stream(), c) + }; + out.extend(stream); + c = cursor; + } + + Some((out, c)) + } +} + +/// Tries to execute the provided sequence of `parsers`. +pub fn seq<const N: usize>( + mut parsers: [&mut dyn FnMut(Cursor<'_>) -> ParsingResult<'_>; N], +) -> impl FnMut(Cursor<'_>) -> ParsingResult<'_> + '_ { + move |c| { + parsers + .iter_mut() + .fold(Some((TokenStream::new(), c)), |out, parser| { + let (mut out, mut c) = out?; + let (stream, cursor) = parser(c)?; + out.extend(stream); + c = cursor; + Some((out, c)) + }) + } +} + +/// Tries to execute the first successful parser. +pub fn alt<const N: usize>( + mut parsers: [&mut dyn FnMut(Cursor<'_>) -> ParsingResult<'_>; N], +) -> impl FnMut(Cursor<'_>) -> ParsingResult<'_> + '_ { + move |c| { + parsers + .iter_mut() + .find_map(|parser| parser(c).map(|(s, c)| (s, c))) + } +} + +/// Parses with `basic` while `until` fails. Returns [`None`] in case +/// `until` succeeded initially or `basic` never succeeded. Doesn't consume +/// tokens parsed by `until`. +pub fn take_until1<P, U>( + mut parser: P, + mut until: U, +) -> impl FnMut(Cursor<'_>) -> ParsingResult<'_> +where + P: FnMut(Cursor<'_>) -> ParsingResult<'_>, + U: FnMut(Cursor<'_>) -> ParsingResult<'_>, +{ + move |mut cursor| { + let mut out = TokenStream::new(); + let mut parsed = false; + + loop { + if cursor.eof() || until(cursor).is_some() { + return parsed.then_some((out, cursor)); + } + + let (stream, c) = parser(cursor)?; + out.extend(stream); + cursor = c; + parsed = true; + } + } +} + +#[cfg(test)] +mod spec { + use std::{fmt::Debug, str::FromStr}; + + use itertools::Itertools as _; + use proc_macro2::TokenStream; + use quote::ToTokens; + use syn::{ + parse::{Parse, Parser as _}, + punctuated::Punctuated, + token::Comma, + }; + + use super::{Expr, Type}; + + fn assert<'a, T: Debug + Parse + ToTokens>( + input: &'a str, + parsed: impl AsRef<[&'a str]>, + ) { + let parsed = parsed.as_ref(); + let punctuated = Punctuated::<T, Comma>::parse_terminated + .parse2(TokenStream::from_str(input).unwrap()) + .unwrap(); + + assert_eq!( + parsed.len(), + punctuated.len(), + "Wrong length\n\ + Expected: {parsed:?}\n\ + Found: {punctuated:?}", + ); + + punctuated + .iter() + .map(|ty| ty.to_token_stream().to_string()) + .zip(parsed) + .enumerate() + .for_each(|(i, (found, expected))| { + assert_eq!( + *expected, &found, + "Mismatch at index {i}\n\ + Expected: {parsed:?}\n\ + Found: {punctuated:?}", + ); + }); + } + + mod tuple { + use super::*; + + #[test] + fn zst_is_tuple() { + let zst = "()"; + match syn::parse_str::<Type>(zst).unwrap() { + Type::Tuple { items, .. } => { + assert!(items.is_empty(), "Expected empty tuple, found: {items:?}"); + } + other => panic!("Expected `Type::Tuple {{ .. }}`, found: {other:?}"), + } + } + + #[test] + fn group_not_tuple() { + let group = "(Type)"; + match syn::parse_str::<Type>(group).unwrap() { + Type::Other(tokens) => { + assert_eq!(tokens.to_string(), group); + } + tuple => panic!("Expected `Type::Other(_)`, found: {tuple:?}"), + } + } + + #[test] + fn single_element_tuple() { + let tuple = "(Type,)"; + match syn::parse_str::<Type>(tuple).unwrap() { + Type::Tuple { items, .. } => { + assert_eq!( + items.len(), + 1, + "Expected empty tuple, found: {items:?}", + ); + assert_eq!(items.first().unwrap().to_string(), "Type"); + } + other => panic!("Expected `Type::Tuple {{ .. }}`, found: {other:?}"), + } + } + + #[test] + fn cases() { + let cases = [ + "[Type ; 3]", + "fn (usize) -> bool", + "for <'a > fn (&'a usize) -> bool", + "(Type)", + "path :: to :: Type", + "path :: to :: Generic < Type >", + "< Type as Trait >:: Assoc", + "< Type as Trait >:: Assoc < GAT >", + "* const ()", + "* mut ()", + "& i32", + "&'static str", + "& [str]", + "dyn Trait", + "dyn Trait + Send", + "()", + "(Type ,)", + "(Type , Type)", + "(Type , Type ,)", + ]; + + assert::<Type>("", []); + for i in 1..4 { + for permutations in cases.into_iter().permutations(i) { + let mut input = permutations.join(","); + assert::<Type>(&input, &permutations); + input.push(','); + assert::<Type>(&input, &permutations); + } + } + } + } + + mod expr { + use super::*; + + #[test] + fn cases() { + let cases = [ + "ident", + "[a , b , c , d]", + "counter += 1", + "async { fut . await }", + "a < b", + "a > b", + "{ let x = (a , b) ; }", + "invoke (a , b)", + "foo as f64", + "| a , b | a + b", + "obj . k", + "for pat in expr { break pat ; }", + "if expr { true } else { false }", + "vector [2]", + "1", + "\"foo\"", + "loop { break i ; }", + "format ! (\"{}\" , q)", + "match n { Some (n) => { } , None => { } }", + "x . foo ::< T > (a , b)", + "x . foo ::< T < [T < T >; if a < b { 1 } else { 2 }] >, { a < b } > (a , b)", + "(a + b)", + "i32 :: MAX", + "1 .. 2", + "& a", + "[0u8 ; N]", + "(a , b , c , d)", + "< Ty as Trait > :: T", + "< Ty < Ty < T >, { a < b } > as Trait < T > > :: T", + ]; + + assert::<Expr>("", []); + for i in 1..4 { + for permutations in cases.into_iter().permutations(i) { + let mut input = permutations.clone().join(","); + assert::<Expr>(&input, &permutations); + input.push(','); + assert::<Expr>(&input, &permutations); + } + } + } + } +} diff --git a/third_party/rust/derive_more-impl/src/sum_like.rs b/third_party/rust/derive_more-impl/src/sum_like.rs new file mode 100644 index 0000000000..97d73fce4b --- /dev/null +++ b/third_party/rust/derive_more-impl/src/sum_like.rs @@ -0,0 +1,53 @@ +use crate::utils::{ + add_extra_ty_param_bound, add_extra_where_clauses, MultiFieldData, State, +}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use syn::{DeriveInput, Result}; + +pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> { + let state = State::new(input, trait_name, 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 = format_ident!("{op_trait_name}"); + let op_path = quote! { ::core::ops::#op_trait_ident }; + let op_method_ident = format_ident!("{}", op_trait_name.to_lowercase()); + 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! { + #[automatically_derived] + 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-impl/src/try_into.rs b/third_party/rust/derive_more-impl/src/try_into.rs new file mode 100644 index 0000000000..f3066c1d4a --- /dev/null +++ b/third_party/rust/derive_more-impl/src/try_into.rs @@ -0,0 +1,123 @@ +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, + "try_into".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 { + quote! { #(#original_types)* }.to_string() + } else { + let types = original_types + .iter() + .map(|t| quote! { #t }.to_string()) + .collect::<Vec<_>>(); + format!("({})", types.join(", ")) + }; + let variant_names = multi_field_datas + .iter() + .map(|d| { + d.variant_name + .expect("Somehow there was no variant name") + .to_string() + }) + .collect::<Vec<_>>() + .join(", "); + + 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! { + #[automatically_derived] + impl #impl_generics + ::core::convert::TryFrom<#reference_with_lifetime #input_type #ty_generics> for + (#(#reference_with_lifetime #original_types),*) + #where_clause + { + type Error = ::derive_more::TryIntoError<#reference_with_lifetime #input_type>; + + #[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(::derive_more::TryIntoError::new(value, #variant_names, #output_type)), + } + } + } + }; + try_from.to_tokens(&mut tokens) + } + Ok(tokens) +} diff --git a/third_party/rust/derive_more-impl/src/try_unwrap.rs b/third_party/rust/derive_more-impl/src/try_unwrap.rs new file mode 100644 index 0000000000..67d3793d00 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/try_unwrap.rs @@ -0,0 +1,166 @@ +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, Type}; + +pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> { + let state = State::with_attr_params( + input, + trait_name, + "try_unwrap".into(), + AttrParams { + enum_: vec!["ignore", "owned", "ref", "ref_mut"], + variant: vec!["ignore", "owned", "ref", "ref_mut"], + struct_: vec!["ignore"], + field: vec!["ignore"], + }, + )?; + assert!( + state.derive_type == DeriveType::Enum, + "TryUnwrap can only be derived for enums" + ); + + let enum_name = &input.ident; + let (imp_generics, type_generics, where_clause) = input.generics.split_for_impl(); + + let variant_data = state.enabled_variant_data(); + + let mut funcs = vec![]; + for (variant_state, info) in + Iterator::zip(variant_data.variant_states.iter(), variant_data.infos) + { + let variant = variant_state.variant.unwrap(); + let fn_name = format_ident!( + "try_unwrap_{ident}", + ident = variant.ident.to_string().to_case(Case::Snake), + span = variant.ident.span(), + ); + let ref_fn_name = format_ident!( + "try_unwrap_{ident}_ref", + ident = variant.ident.to_string().to_case(Case::Snake), + span = variant.ident.span(), + ); + let mut_fn_name = format_ident!( + "try_unwrap_{ident}_mut", + ident = variant.ident.to_string().to_case(Case::Snake), + span = variant.ident.span(), + ); + let variant_ident = &variant.ident; + let (data_pattern, ret_value, data_types) = get_field_info(&variant.fields); + let pattern = quote! { #enum_name :: #variant_ident #data_pattern }; + + let (failed_block, failed_block_ref, failed_block_mut) = ( + failed_block(&state, enum_name, &fn_name), + failed_block(&state, enum_name, &ref_fn_name), + failed_block(&state, enum_name, &mut_fn_name), + ); + + let doc_owned = format!( + "Attempts to unwrap this value to the `{enum_name}::{variant_ident}` variant.\n", + ); + let doc_ref = format!( + "Attempts to unwrap this reference to the `{enum_name}::{variant_ident}` variant.\n", + ); + let doc_mut = format!( + "Attempts to unwrap this mutable reference to the `{enum_name}::{variant_ident}` variant.\n", + ); + let doc_else = "Returns a [TryUnwrapError] with the original value if this value is of any other type."; + let func = quote! { + #[inline] + #[track_caller] + #[doc = #doc_owned] + #[doc = #doc_else] + pub fn #fn_name(self) -> Result<(#(#data_types),*), ::derive_more::TryUnwrapError<Self>> { + match self { + #pattern => Ok(#ret_value), + val @ _ => #failed_block, + } + } + }; + + let ref_func = quote! { + #[inline] + #[track_caller] + #[doc = #doc_ref] + #[doc = #doc_else] + pub fn #ref_fn_name(&self) -> Result<(#(&#data_types),*), ::derive_more::TryUnwrapError<&Self>> { + match self { + #pattern => Ok(#ret_value), + val @ _ => #failed_block_ref, + } + } + }; + + let mut_func = quote! { + #[inline] + #[track_caller] + #[doc = #doc_mut] + #[doc = #doc_else] + pub fn #mut_fn_name(&mut self) -> Result<(#(&mut #data_types),*), ::derive_more::TryUnwrapError<&mut Self>> { + match self { + #pattern => Ok(#ret_value), + val @ _ => #failed_block_mut, + } + } + }; + + if info.owned && state.default_info.owned { + funcs.push(func); + } + if info.ref_ && state.default_info.ref_ { + funcs.push(ref_func); + } + if info.ref_mut && state.default_info.ref_mut { + funcs.push(mut_func); + } + } + + let imp = quote! { + #[automatically_derived] + impl #imp_generics #enum_name #type_generics #where_clause { + #(#funcs)* + } + }; + + Ok(imp) +} + +fn get_field_info(fields: &Fields) -> (TokenStream, TokenStream, Vec<&Type>) { + match fields { + Fields::Named(_) => panic!("cannot unwrap anonymous records"), + Fields::Unnamed(ref fields) => { + let (idents, types) = fields + .unnamed + .iter() + .enumerate() + .map(|(n, it)| (format_ident!("field_{n}"), &it.ty)) + .unzip::<_, _, Vec<_>, Vec<_>>(); + (quote! { (#(#idents),*) }, quote! { (#(#idents),*) }, types) + } + Fields::Unit => (quote! {}, quote! { () }, vec![]), + } +} + +fn failed_block(state: &State, enum_name: &Ident, func_name: &Ident) -> TokenStream { + let arms = state + .variant_states + .iter() + .map(|it| it.variant.unwrap()) + .map(|variant| { + let data_pattern = match variant.fields { + Fields::Named(_) => quote! { {..} }, + Fields::Unnamed(_) => quote! { (..) }, + Fields::Unit => quote! {}, + }; + let variant_ident = &variant.ident; + let error = quote! { ::derive_more::TryUnwrapError::<_>::new(val, stringify!(#enum_name), stringify!(#variant_ident), stringify!(#func_name)) }; + quote! { val @ #enum_name :: #variant_ident #data_pattern => Err(#error) } + }); + + quote! { + match val { + #(#arms),* + } + } +} diff --git a/third_party/rust/derive_more-impl/src/unwrap.rs b/third_party/rust/derive_more-impl/src/unwrap.rs new file mode 100644 index 0000000000..02a9010c4c --- /dev/null +++ b/third_party/rust/derive_more-impl/src/unwrap.rs @@ -0,0 +1,169 @@ +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, Type}; + +pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> { + let state = State::with_attr_params( + input, + trait_name, + "unwrap".into(), + AttrParams { + enum_: vec!["ignore", "owned", "ref", "ref_mut"], + variant: vec!["ignore", "owned", "ref", "ref_mut"], + 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 variant_data = state.enabled_variant_data(); + + let mut funcs = vec![]; + for (variant_state, info) in + Iterator::zip(variant_data.variant_states.iter(), variant_data.infos) + { + let variant = variant_state.variant.unwrap(); + let fn_name = format_ident!( + "unwrap_{ident}", + ident = variant.ident.to_string().to_case(Case::Snake), + span = variant.ident.span(), + ); + let ref_fn_name = format_ident!( + "unwrap_{ident}_ref", + ident = variant.ident.to_string().to_case(Case::Snake), + span = variant.ident.span(), + ); + let mut_fn_name = format_ident!( + "unwrap_{ident}_mut", + ident = variant.ident.to_string().to_case(Case::Snake), + span = variant.ident.span(), + ); + let variant_ident = &variant.ident; + let (data_pattern, ret_value, data_types) = get_field_info(&variant.fields); + let pattern = quote! { #enum_name :: #variant_ident #data_pattern }; + + let (failed_block, failed_block_ref, failed_block_mut) = ( + failed_block(&state, enum_name, &fn_name), + failed_block(&state, enum_name, &ref_fn_name), + failed_block(&state, enum_name, &mut_fn_name), + ); + + let doc_owned = format!( + "Unwraps this value to the `{enum_name}::{variant_ident}` variant.\n", + ); + let doc_ref = format!( + "Unwraps this reference to the `{enum_name}::{variant_ident}` variant.\n", + ); + let doc_mut = format!( + "Unwraps this mutable reference to the `{enum_name}::{variant_ident}` variant.\n", + ); + let doc_else = "Panics if this value is of any other type."; + + let func = quote! { + #[inline] + #[track_caller] + #[doc = #doc_owned] + #[doc = #doc_else] + pub fn #fn_name(self) -> (#(#data_types),*) { + match self { + #pattern => #ret_value, + val @ _ => #failed_block, + } + } + }; + + let ref_func = quote! { + #[inline] + #[track_caller] + #[doc = #doc_ref] + #[doc = #doc_else] + pub fn #ref_fn_name(&self) -> (#(&#data_types),*) { + match self { + #pattern => #ret_value, + val @ _ => #failed_block_ref, + } + } + }; + + let mut_func = quote! { + #[inline] + #[track_caller] + #[doc = #doc_mut] + #[doc = #doc_else] + pub fn #mut_fn_name(&mut self) -> (#(&mut #data_types),*) { + match self { + #pattern => #ret_value, + val @ _ => #failed_block_mut, + } + } + }; + + if info.owned && state.default_info.owned { + funcs.push(func); + } + if info.ref_ && state.default_info.ref_ { + funcs.push(ref_func); + } + if info.ref_mut && state.default_info.ref_mut { + funcs.push(mut_func); + } + } + + let imp = quote! { + #[automatically_derived] + impl #imp_generics #enum_name #type_generics #where_clause { + #(#funcs)* + } + }; + + Ok(imp) +} + +fn get_field_info(fields: &Fields) -> (TokenStream, TokenStream, Vec<&Type>) { + match fields { + Fields::Named(_) => panic!("cannot unwrap anonymous records"), + Fields::Unnamed(ref fields) => { + let (idents, types) = fields + .unnamed + .iter() + .enumerate() + .map(|(n, it)| (format_ident!("field_{n}"), &it.ty)) + .unzip::<_, _, Vec<_>, Vec<_>>(); + (quote! { (#(#idents),*) }, quote! { (#(#idents),*) }, types) + } + Fields::Unit => (quote! {}, quote! { () }, vec![]), + } +} + +fn failed_block(state: &State, enum_name: &Ident, fn_name: &Ident) -> TokenStream { + let arms = state + .variant_states + .iter() + .map(|it| it.variant.unwrap()) + .map(|variant| { + let data_pattern = match variant.fields { + Fields::Named(_) => quote! { {..} }, + Fields::Unnamed(_) => quote! { (..) }, + Fields::Unit => quote! {}, + }; + let variant_ident = &variant.ident; + let panic_msg = format!( + "called `{enum_name}::{fn_name}()` on a `{enum_name}::{variant_ident}` value" + ); + quote! { #enum_name :: #variant_ident #data_pattern => panic!(#panic_msg) } + }); + + quote! { + match val { + #(#arms),* + } + } +} diff --git a/third_party/rust/derive_more-impl/src/utils.rs b/third_party/rust/derive_more-impl/src/utils.rs new file mode 100644 index 0000000000..9523591b26 --- /dev/null +++ b/third_party/rust/derive_more-impl/src/utils.rs @@ -0,0 +1,1514 @@ +#![cfg_attr( + not(all(feature = "add", feature = "mul")), + allow(dead_code), + allow(unused_mut) +)] + +use proc_macro2::TokenStream; +use quote::{format_ident, quote, ToTokens}; +use syn::{ + parse_quote, punctuated::Punctuated, spanned::Spanned, Attribute, Data, + DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, GenericParam, + Generics, Ident, ImplGenerics, Index, Result, Token, Type, TypeGenerics, + TypeParamBound, Variant, WhereClause, +}; + +#[cfg(any(feature = "from", feature = "into"))] +pub(crate) use self::{either::Either, fields_ext::FieldsExt}; + +#[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 { + !matches!(self, RefType::No) + } + + pub fn from_attr_name(name: &str) -> Self { + match name { + "owned" => RefType::No, + "ref" => RefType::Ref, + "ref_mut" => RefType::Mut, + _ => panic!("`{name}` is not a `RefType`"), + } + } +} + +pub fn numbered_vars(count: usize, prefix: &str) -> Vec<Ident> { + (0..count).map(|i| format_ident!("__{prefix}{i}")).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({trait_name}) only works when forwarding to a single field. \ + Try putting #[{trait_attr}] or #[{trait_attr}(ignore)] on the fields in the struct", + ) +} + +#[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_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_attr: String, + ) -> Result<State<'arg_input>> { + State::new_impl(input, trait_name, trait_attr, AttrParams::default(), true) + } + + pub fn with_field_ignore<'arg_input>( + input: &'arg_input DeriveInput, + trait_name: &'static str, + trait_attr: String, + ) -> Result<State<'arg_input>> { + State::new_impl( + input, + trait_name, + 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_attr: String, + ) -> Result<State<'arg_input>> { + State::new_impl( + input, + trait_name, + 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_attr: String, + ) -> Result<State<'arg_input>> { + State::new_impl( + input, + trait_name, + 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_attr: String, + allowed_attr_params: AttrParams, + ) -> Result<State<'arg_input>> { + State::new_impl(input, trait_name, trait_attr, allowed_attr_params, true) + } + + pub fn with_type_bound<'arg_input>( + input: &'arg_input DeriveInput, + trait_name: &'static str, + trait_attr: String, + allowed_attr_params: AttrParams, + add_type_bound: bool, + ) -> Result<State<'arg_input>> { + Self::new_impl( + input, + trait_name, + trait_attr, + allowed_attr_params, + add_type_bound, + ) + } + + fn new_impl<'arg_input>( + input: &'arg_input DeriveInput, + trait_name: &'static str, + 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 = format_ident!("{trait_name}"); + let method_ident = format_ident!("{trait_attr}"); + let trait_path = quote! { ::derive_more::#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({trait_name}) for union") + } + }; + 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_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_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_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 = format_ident!("{trait_name}"); + let method_ident = format_ident!("{trait_attr}"); + let trait_path = quote! { ::derive_more::#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_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(|a| { + a.meta + .path() + .segments + .first() + .map(|p| p.ident == trait_attr) + .unwrap_or_default() + }); + + let mut info = MetaInfo::default(); + + let Some(attr) = it.next() else { + return Ok(info); + }; + + if allowed_attr_params.is_empty() { + return Err(Error::new(attr.span(), "Attribute is not allowed here")); + } + + info.enabled = Some(true); + + if let Some(another_attr) = it.next() { + return Err(Error::new( + another_attr.span(), + "Only a single attribute is allowed", + )); + } + + let list = match &attr.meta { + syn::Meta::Path(_) => { + if allowed_attr_params.contains(&"ignore") { + return Ok(info); + } else { + return Err(Error::new( + attr.span(), + format!( + "Empty attribute is not allowed, add one of the following parameters: {}", + allowed_attr_params.join(", "), + ), + )); + } + } + syn::Meta::List(list) => list, + syn::Meta::NameValue(val) => { + return Err(Error::new( + val.span(), + "Attribute doesn't support name-value format here", + )); + } + }; + + parse_punctuated_nested_meta( + &mut info, + &list.parse_args_with(Punctuated::parse_terminated)?, + allowed_attr_params, + None, + )?; + + Ok(info) +} + +fn parse_punctuated_nested_meta( + info: &mut MetaInfo, + meta: &Punctuated<polyfill::Meta, Token![,]>, + allowed_attr_params: &[&str], + wrapper_name: Option<&str>, +) -> Result<()> { + for meta in meta.iter() { + match meta { + polyfill::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.parse_args_with(Punctuated::parse_terminated)?, + allowed_attr_params, + Some("not"), + )?; + } + + polyfill::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.parse_args_with( + Punctuated::<polyfill::NestedMeta, syn::token::Comma>::parse_terminated, + )? { + let typ: syn::Type = match meta { + polyfill::NestedMeta::Meta(meta) => { + let polyfill::Meta::Path(path) = meta else { + return Err(Error::new( + meta.span(), + format!( + "Attribute doesn't support type {}", + quote! { #meta }, + ), + )); + }; + syn::TypePath { + qself: None, + path: path.clone().into(), + } + .into() + } + polyfill::NestedMeta::Lit(syn::Lit::Str(s)) => s.parse()?, + polyfill::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.parse_args_with(Punctuated::parse_terminated)?, + allowed_attr_params, + Some(&attr_name), + )?; + } + } + + polyfill::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 } + ), + )) + } + } + } + } + } + + Ok(()) +} + +// TODO: Remove this eventually, once all macros migrate to +// custom typed attributes parsing. +/// Polyfill for [`syn`] 1.x AST. +pub(crate) mod polyfill { + use proc_macro2::TokenStream; + use quote::ToTokens; + use syn::{ + ext::IdentExt as _, + parse::{Parse, ParseStream, Parser}, + token, Token, + }; + + #[derive(Clone)] + pub(crate) enum PathOrKeyword { + Path(syn::Path), + Keyword(syn::Ident), + } + + impl Parse for PathOrKeyword { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + if input.fork().parse::<syn::Path>().is_ok() { + return input.parse().map(Self::Path); + } + syn::Ident::parse_any(input).map(Self::Keyword) + } + } + + impl ToTokens for PathOrKeyword { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Path(p) => p.to_tokens(tokens), + Self::Keyword(i) => i.to_tokens(tokens), + } + } + } + + impl PathOrKeyword { + pub(crate) fn is_ident<I: ?Sized>(&self, ident: &I) -> bool + where + syn::Ident: PartialEq<I>, + { + match self { + Self::Path(p) => p.is_ident(ident), + Self::Keyword(i) => i == ident, + } + } + + pub fn get_ident(&self) -> Option<&syn::Ident> { + match self { + Self::Path(p) => p.get_ident(), + Self::Keyword(i) => Some(i), + } + } + } + + impl From<PathOrKeyword> for syn::Path { + fn from(p: PathOrKeyword) -> Self { + match p { + PathOrKeyword::Path(p) => p, + PathOrKeyword::Keyword(i) => i.into(), + } + } + } + + #[derive(Clone)] + pub(crate) struct MetaList { + pub(crate) path: PathOrKeyword, + pub(crate) tokens: TokenStream, + } + + impl Parse for MetaList { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let path = input.parse::<PathOrKeyword>()?; + let tokens; + _ = syn::parenthesized!(tokens in input); + Ok(Self { + path, + tokens: tokens.parse()?, + }) + } + } + + impl ToTokens for MetaList { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.path.to_tokens(tokens); + token::Paren::default() + .surround(tokens, |tokens| self.tokens.to_tokens(tokens)) + } + } + + impl MetaList { + pub fn parse_args_with<F: Parser>(&self, parser: F) -> syn::Result<F::Output> { + parser.parse2(self.tokens.clone()) + } + } + + #[derive(Clone)] + pub(crate) enum Meta { + Path(PathOrKeyword), + List(MetaList), + } + + impl Parse for Meta { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let path = input.parse::<PathOrKeyword>()?; + Ok(if input.peek(token::Paren) { + let tokens; + _ = syn::parenthesized!(tokens in input); + Self::List(MetaList { + path, + tokens: tokens.parse()?, + }) + } else { + Self::Path(path) + }) + } + } + + impl ToTokens for Meta { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Path(p) => p.to_tokens(tokens), + Self::List(l) => l.to_tokens(tokens), + } + } + } + + #[derive(Clone)] + pub(crate) enum NestedMeta { + Meta(Meta), + Lit(syn::Lit), + } + + impl Parse for NestedMeta { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + if input.peek(syn::Lit) + && !(input.peek(syn::LitBool) && input.peek2(Token![=])) + { + input.parse().map(Self::Lit) + } else if input.peek(syn::Ident::peek_any) + || input.peek(Token![::]) && input.peek3(syn::Ident::peek_any) + { + input.parse().map(Self::Meta) + } else { + Err(input.error("expected identifier or literal")) + } + } + } + + impl ToTokens for NestedMeta { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Meta(m) => m.to_tokens(tokens), + Self::Lit(l) => l.to_tokens(tokens), + } + } + } +} + +#[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 + } +} + +pub fn get_if_type_parameter_used_in_type( + type_parameters: &HashSet<syn::Ident>, + ty: &syn::Type, +) -> Option<syn::Type> { + is_type_parameter_used_in_type(type_parameters, ty).then(|| match ty { + syn::Type::Reference(syn::TypeReference { elem: ty, .. }) => (**ty).clone(), + ty => ty.clone(), + }) +} + +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, + } +} + +#[cfg(any(feature = "from", feature = "into"))] +mod either { + use proc_macro2::TokenStream; + use quote::ToTokens; + + /// Either [`Left`] or [`Right`]. + /// + /// [`Left`]: Either::Left + /// [`Right`]: Either::Right + pub(crate) enum Either<L, R> { + /// Left variant. + Left(L), + + /// Right variant. + Right(R), + } + + impl<L, R, T> Iterator for Either<L, R> + where + L: Iterator<Item = T>, + R: Iterator<Item = T>, + { + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + match self { + Either::Left(left) => left.next(), + Either::Right(right) => right.next(), + } + } + } + + impl<L, R> ToTokens for Either<L, R> + where + L: ToTokens, + R: ToTokens, + { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Either::Left(l) => l.to_tokens(tokens), + Either::Right(r) => r.to_tokens(tokens), + } + } + } +} + +#[cfg(any(feature = "from", feature = "into"))] +mod fields_ext { + use std::{cmp, iter}; + + use proc_macro2::TokenStream; + use syn::{punctuated, spanned::Spanned as _}; + + use crate::parsing; + + use super::Either; + + /// Abstraction over `.len()` method to use it on type parameters. + pub(crate) trait Len { + /// Returns number of fields. + fn len(&self) -> usize; + } + + impl Len for syn::Fields { + fn len(&self) -> usize { + self.len() + } + } + + impl<T> Len for Vec<T> { + fn len(&self) -> usize { + self.len() + } + } + + /// [`syn::Fields`] extension. + pub(crate) trait FieldsExt: Len { + /// Validates the provided [`parsing::Type`] against these [`syn::Fields`]. + fn validate_type<'t>( + &self, + ty: &'t parsing::Type, + ) -> syn::Result< + Either<punctuated::Iter<'t, TokenStream>, iter::Once<&'t TokenStream>>, + > { + match ty { + parsing::Type::Tuple { items, .. } if self.len() > 1 => { + match self.len().cmp(&items.len()) { + cmp::Ordering::Greater => { + return Err(syn::Error::new( + ty.span(), + format!( + "wrong tuple length: expected {}, found {}. \ + Consider adding {} more type{}: `({})`", + self.len(), + items.len(), + self.len() - items.len(), + if self.len() - items.len() > 1 { + "s" + } else { + "" + }, + items + .iter() + .map(|item| item.to_string()) + .chain( + (0..(self.len() - items.len())) + .map(|_| "_".to_string()) + ) + .collect::<Vec<_>>() + .join(", "), + ), + )); + } + cmp::Ordering::Less => { + return Err(syn::Error::new( + ty.span(), + format!( + "wrong tuple length: expected {}, found {}. \ + Consider removing last {} type{}: `({})`", + self.len(), + items.len(), + items.len() - self.len(), + if items.len() - self.len() > 1 { + "s" + } else { + "" + }, + items + .iter() + .take(self.len()) + .map(ToString::to_string) + .collect::<Vec<_>>() + .join(", "), + ), + )); + } + cmp::Ordering::Equal => {} + } + } + parsing::Type::Other(other) if self.len() > 1 => { + if self.len() > 1 { + return Err(syn::Error::new( + other.span(), + format!( + "expected tuple: `({}, {})`", + other, + (0..(self.len() - 1)) + .map(|_| "_") + .collect::<Vec<_>>() + .join(", "), + ), + )); + } + } + parsing::Type::Tuple { .. } | parsing::Type::Other(_) => {} + } + Ok(match ty { + parsing::Type::Tuple { items, .. } => Either::Left(items.iter()), + parsing::Type::Other(other) => Either::Right(iter::once(other)), + }) + } + } + + impl<T: Len + ?Sized> FieldsExt for T {} +} |