derive_more-impl-1.0.0/.cargo_vcs_info.json0000644000000001420000000000100142660ustar { "git": { "sha1": "d7f5b9e94d024790682f6fc4dcca13941cce64c8" }, "path_in_vcs": "impl" }derive_more-impl-1.0.0/Cargo.toml0000644000000053170000000000100122750ustar # 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.75.0" name = "derive_more-impl" version = "1.0.0" authors = ["Jelte Fennema "] build = false include = [ "src/**/*.rs", "doc/**/*.md", "Cargo.toml", "README.md", "LICENSE", ] autobins = false autoexamples = false autotests = false autobenches = false 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] name = "derive_more_impl" path = "src/lib.rs" 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.45" [dependencies.unicode-xid] version = "0.2.2" optional = true [dev-dependencies.itertools] version = "0.13.0" [build-dependencies.rustc_version] version = "0.4" optional = true [features] add = [] add_assign = [] as_ref = [ "syn/extra-traits", "syn/visit", ] 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_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_from", "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_from = [] try_into = ["syn/extra-traits"] try_unwrap = ["dep:convert_case"] unwrap = ["dep:convert_case"] [badges.github] repository = "JelteF/derive_more" workflow = "CI" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 check-cfg = [ "cfg(ci)", "cfg(nightly)", ] derive_more-impl-1.0.0/Cargo.toml.orig000064400000000000000000000041321046102023000157500ustar 00000000000000[package] name = "derive_more-impl" version = "1.0.0" edition = "2021" rust-version = "1.75.0" description = "Internal implementation of `derive_more` crate" authors = ["Jelte Fennema "] license = "MIT" repository = "https://github.com/JelteF/derive_more" documentation = "https://docs.rs/derive_more" # explicitly no keywords or categories so it cannot be found easily include = [ "src/**/*.rs", "doc/**/*.md", "Cargo.toml", "README.md", "LICENSE", ] [lib] proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" syn = "2.0.45" convert_case = { version = "0.6", optional = true } unicode-xid = { version = "0.2.2", optional = true } [build-dependencies] rustc_version = { version = "0.4", optional = true } [dev-dependencies] derive_more = { path = "..", features = ["full"] } itertools = "0.13.0" [badges] github = { repository = "JelteF/derive_more", workflow = "CI" } [package.metadata.docs.rs] features = ["full"] rustdoc-args = ["--cfg", "docsrs"] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(ci)", "cfg(nightly)"] } [features] default = [] add = [] add_assign = [] as_ref = ["syn/extra-traits", "syn/visit"] constructor = [] debug = ["syn/extra-traits", "dep:unicode-xid"] deref = [] deref_mut = [] display = ["syn/extra-traits", "dep:unicode-xid"] error = ["syn/extra-traits"] from = ["syn/extra-traits"] from_str = [] 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 = [] try_from = [] try_into = ["syn/extra-traits"] try_unwrap = ["dep:convert_case"] unwrap = ["dep:convert_case"] full = [ "add", "add_assign", "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_from", "try_into", "try_unwrap", "unwrap", ] testing-helpers = ["dep:rustc_version"] derive_more-impl-1.0.0/LICENSE000064400000000000000000000020701046102023000140650ustar 00000000000000The MIT License (MIT) Copyright (c) 2016 Jelte Fennema Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. derive_more-impl-1.0.0/README.md000064400000000000000000000006371046102023000143460ustar 00000000000000# `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 derive_more-impl-1.0.0/doc/add.md000064400000000000000000000077621046102023000147140ustar 00000000000000# What `#[derive(Add)]` generates The derived `Add` implementation will allow two structs of the same type to be added together. This is 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`, because an error is returned when two 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 derive_more::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 derive_more::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` 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 derive_more::Add for MixedInts { type Output = Result; fn add(self, rhs: MixedInts) -> Result { 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::BinaryError::Unit( derive_more::UnitError::new("add"), )), _ => Err(derive_more::BinaryError::Mismatch( derive_more::WrongVariantError::new("add"), )), } } } ``` Also note the Unit type that throws an error when adding it to itself. derive_more-impl-1.0.0/doc/add_assign.md000064400000000000000000000027141046102023000162500ustar 00000000000000# 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 derive_more::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 derive_more::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` instead of an `EnumType`. Handling the case where it errors would be hard and maybe impossible. derive_more-impl-1.0.0/doc/as_mut.md000064400000000000000000000135541046102023000154500ustar 00000000000000# 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` 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 derive_more::AsMut 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` implements `AsMut` for. ```rust # use derive_more::AsMut; # #[derive(AsMut)] #[as_mut(forward)] struct SingleFieldForward(Vec); let mut item = SingleFieldForward(vec![]); let _: &mut [i32] = (&mut item).as_mut(); ``` This generates code equivalent to: ```rust # struct SingleFieldForward(Vec); impl derive_more::AsMut for SingleFieldForward where Vec: derive_more::AsMut, { #[inline] fn as_mut(&mut self) -> &mut T { self.0.as_mut() } } ``` Specifying concrete types, to derive impls for, is also supported via `#[as_mut()]` attribute. These types can include both the type of the field itself, and types for which the field type implements `AsMut`. ```rust # use derive_more::AsMut; # #[derive(AsMut)] #[as_mut(str, [u8], String)] struct Types(String); let mut item = Types("test".to_owned()); let _: &mut str = item.as_mut(); let _: &mut [u8] = item.as_mut(); let _: &mut String = item.as_mut();_ ``` > **WARNING**: When either the field type, or the specified conversion type, > contains generic parameters, they are considered as the same type only if > are named string-equally, otherwise are assumed as different types even > when represent the same type in fact (type aliases, for example). > > ```rust > # use derive_more::AsMut; > # > #[derive(AsMut)] > #[as_mut(i32)] // generates `impl> AsMut for Generic` > struct Generic(T); > > #[derive(AsMut)] > #[as_mut(T)] // generates `impl AsMut for Transparent` > struct Transparent(T); > > #[derive(AsMut)] > // #[as_mut(RenamedVec)] // not supported, as types are not named string-equally > struct Foo(Vec); > type RenamedVec = Vec; > > #[derive(AsMut)] > #[as_mut(RenamedString)] // generates `impl AsMut for Bar`, > struct Bar(String); // as generics are not involved > type RenamedString = String; > ``` Generating code like this is not supported: ```rust struct Generic(T); impl AsMut for Generic { fn as_mut(&mut self) -> &mut i32 { &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. ```rust # use derive_more::AsMut; # #[derive(AsMut)] struct MyWrapper { #[as_mut(str)] name: String, #[as_mut] num: i32, valid: bool, } ``` Generates: ```rust # struct MyWrapper { # name: String, # num: i32, # valid: bool, # } impl AsMut for MyWrapper { fn as_mut(&mut self) -> &mut String { self.name.as_mut() } } impl AsMut for MyWrapper { fn as_mut(&mut self) -> &mut i32 { &mut self.num } } ``` ### Tuples (not supported) Only conversions that use a single field are possible with this derive. Something like this wouldn't work, due to the nature of the `AsMut` trait itself: ```rust,compile_fail # use derive_more::AsMut # #[derive(AsMut)] #[as_mut((str, [u8]))] struct MyWrapper(String, Vec) ``` If you need to convert into a tuple of references, consider using the [`Into`](crate::Into) derive with `#[into(ref_mut)]`. ### Skipping Or vice versa: you can exclude a specific field by using `#[as_mut(skip)]` (or `#[as_mut(ignore)]`). Then, implementations will be generated for non-indicated fields. ```rust # use derive_more::AsMut; # #[derive(AsMut)] struct MyWrapper { #[as_mut(skip)] name: String, #[as_mut(ignore)] num: i32, valid: bool, } ``` Generates: ```rust # struct MyWrapper { # name: String, # num: i32, # valid: bool, # } impl AsMut for MyWrapper { fn as_mut(&mut self) -> &mut bool { &mut self.valid } } ``` ### Coherence Note that `AsMut` 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 #[derive(AsMut)] struct MyWrapper { #[as_mut] str1: String, #[as_mut] str2: String, } ``` Similarly, if some field is annotated with `#[as_mut(forward)]`, no other field can be marked. ```rust,compile_fail # use derive_more::AsMut; # // Error! Conflicting implementations of `AsMut` // note: upstream crates may add a new impl of trait `AsMut` // for type `String` in future versions #[derive(AsMut)] struct ForwardWithOther { #[as_mut(forward)] str: String, #[as_mut] number: i32, } ``` Multiple forwarded impls with different concrete types, however, can be used. ```rust # use derive_more::AsMut; # #[derive(AsMut)] struct Types { #[as_mut(str)] str: String, #[as_mut([u8])] vec: Vec, } let mut item = Types { str: "test".to_owned(), vec: vec![0u8], }; let _: &mut str = item.as_mut(); let _: &mut [u8] = item.as_mut(); ``` ## Enums Deriving `AsMut` for enums is not supported. derive_more-impl-1.0.0/doc/as_ref.md000064400000000000000000000133741046102023000154170ustar 00000000000000# 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` 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 derive_more::AsRef 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` implements `AsRef` for. ```rust # use derive_more::AsRef; # #[derive(AsRef)] #[as_ref(forward)] struct SingleFieldForward(Vec); let item = SingleFieldForward(vec![]); let _: &[i32] = (&item).as_ref(); ``` This generates code equivalent to: ```rust # struct SingleFieldForward(Vec); impl derive_more::AsRef for SingleFieldForward where Vec: derive_more::AsRef, { #[inline] fn as_ref(&self) -> &T { self.0.as_ref() } } ``` Specifying concrete types, to derive impls for, is also supported via `#[as_ref()]` attribute. These types can include both the type of the field itself, and types for which the field type implements `AsRef`. ```rust # use derive_more::AsRef; # #[derive(AsRef)] #[as_ref(str, [u8], String)] struct Types(String); let item = Types("test".to_owned()); let _: &str = item.as_ref(); let _: &[u8] = item.as_ref(); let _: &String = item.as_ref(); ``` > **WARNING**: When either the field type, or the specified conversion type, > contains generic parameters, they are considered as the same type only if > are named string-equally, otherwise are assumed as different types even > when represent the same type in fact (type aliases, for example). > > ```rust > # use derive_more::AsRef; > # > #[derive(AsRef)] > #[as_ref(i32)] // generates `impl> AsRef for Generic` > struct Generic(T); > > #[derive(AsRef)] > #[as_ref(T)] // generates `impl AsRef for Transparent` > struct Transparent(T); > > #[derive(AsRef)] > // #[as_ref(RenamedVec)] // not supported, as types are not named string-equally > struct Foo(Vec); > type RenamedVec = Vec; > > #[derive(AsRef)] > #[as_ref(RenamedString)] // generates `impl AsRef for Bar`, > struct Bar(String); // as generics are not involved > type RenamedString = String; > ``` Generating code like this is not supported: ```rust struct Generic(T); impl AsRef for Generic { fn as_ref(&self) -> &i32 { &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. ```rust # use derive_more::AsRef; # #[derive(AsRef)] struct MyWrapper { #[as_ref(str)] name: String, #[as_ref] num: i32, valid: bool, } ``` Generates: ```rust # struct MyWrapper { # name: String, # num: i32, # valid: bool, # } impl AsRef for MyWrapper { fn as_ref(&self) -> &str { self.name.as_ref() } } impl AsRef for MyWrapper { fn as_ref(&self) -> &i32 { &self.num } } ``` ### Tuples (not supported) Only conversions that use a single field are possible with this derive. Something like this wouldn't work, due to the nature of the `AsRef` trait itself: ```rust,compile_fail # use derive_more::AsRef # #[derive(AsRef)] #[as_ref((str, [u8]))] struct MyWrapper(String, Vec) ``` If you need to convert into a tuple of references, consider using the [`Into`](crate::Into) derive with `#[into(ref)]`. ### Skipping Or vice versa: you can exclude a specific field by using `#[as_ref(skip)]` (or `#[as_ref(ignore)]`). Then, implementations will be generated for non-indicated fields. ```rust # use derive_more::AsRef; # #[derive(AsRef)] struct MyWrapper { #[as_ref(skip)] name: String, #[as_ref(ignore)] num: i32, valid: bool, } ``` Generates: ```rust # struct MyWrapper { # name: String, # num: i32, # valid: bool, # } impl AsRef for MyWrapper { fn as_ref(&self) -> &bool { &self.valid } } ``` ### Coherence Note that `AsRef` 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 #[derive(AsRef)] struct MyWrapper { #[as_ref] str1: String, #[as_ref] str2: String, } ``` Similarly, if some field is annotated with `#[as_ref(forward)]`, no other field can be marked. ```rust,compile_fail # use derive_more::AsRef; # // Error! Conflicting implementations of `AsRef` // note: upstream crates may add a new impl of trait `AsRef` // for type `String` in future versions #[derive(AsRef)] struct ForwardWithOther { #[as_ref(forward)] str: String, #[as_ref] number: i32, } ``` Multiple forwarded impls with different concrete types, however, can be used. ```rust # use derive_more::AsRef; # #[derive(AsRef)] struct Types { #[as_ref(str)] str: String, #[as_ref([u8])] vec: Vec, } let item = Types { str: "test".to_owned(), vec: vec![0u8], }; let _: &str = item.as_ref(); let _: &[u8] = item.as_ref(); ``` ## Enums Deriving `AsRef` for enums is not supported. derive_more-impl-1.0.0/doc/constructor.md000064400000000000000000000033221046102023000165350ustar 00000000000000# 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. derive_more-impl-1.0.0/doc/debug.md000064400000000000000000000140521046102023000152400ustar 00000000000000# 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)]` (or `#[debug(ignore)]`) attribute to skip formatting struct field or enum variant; - `#[debug("...", args...)]` to specify custom formatting either for the whole struct or enum variant, or its particular field; - `#[debug(bounds(...))]` to impose additional custom trait bounds. ## The format of the format You supply a format by placing an attribute on a struct or enum variant, or its particular field: `#[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 struct or enum variant, with members of tuple structs being named with a leading underscore and their index, i.e. `_0`, `_1`, `_2`, etc. Due to ownership/lifetime limitations the member variables are all references to the fields, except when used directly in the format string. For most purposes this detail doesn't matter, but it is quite important when using `Pointer` formatting. If you don't use the `{field:p}` syntax, you have to dereference once to get the address of the field itself, instead of the address of the reference to the field: ```rust use derive_more::Debug; #[derive(Debug)] #[debug("{field:p} {:p}", *field)] struct RefInt<'a> { field: &'a i32, } let a = &123; assert_eq!(format!("{:?}", RefInt{field: &a}), format!("{a:p} {:p}", a)); ``` ### 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: ::Type, #[debug("{c:?}")] c: Vec, #[debug("{d:p}")] d: &'a T1, #[debug(skip)] // or #[debug(ignore)] e: T4, } trait Trait { type Type; } ``` The following where clauses would be generated: - `T1: Display` - `::Type: Display` - `Vec: Debug` - `&'a T1: Pointer` ### 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 { #[debug("{}", a.my_function())] a: T, #[debug("{}", b.to_string().len())] b: U, #[debug("{c}")] c: V, #[debug(skip)] // or #[debug(ignore)] d: F, } trait MyTrait { fn my_function(&self) -> i32; } ``` ### Transparency If the top-level `#[debug("...", args...)]` attribute (the one for a whole struct or variant) is specified and can be trivially substituted with a transparent delegation call to the inner type, then all the additional [formatting parameters][1] do work as expected: ```rust use derive_more::Debug; #[derive(Debug)] #[debug("{_0:o}")] // the same as calling `Octal::fmt()` struct MyOctalInt(i32); // so, additional formatting parameters do work transparently assert_eq!(format!("{:03?}", MyOctalInt(9)), "011"); #[derive(Debug)] #[debug("{_0:02b}")] // cannot be trivially substituted with `Binary::fmt()`, struct MyBinaryInt(i32); // because of specified formatting parameters // so, additional formatting parameters have no effect assert_eq!(format!("{:07?}", MyBinaryInt(2)), "10"); ``` If, for some reason, transparency in trivial cases is not desired, it may be suppressed explicitly either with the [`format_args!()`] macro usage: ```rust use derive_more::Debug; #[derive(Debug)] #[debug("{}", format_args!("{_0:o}"))] // `format_args!()` obscures the inner type struct MyOctalInt(i32); // so, additional formatting parameters have no effect assert_eq!(format!("{:07?}", MyOctalInt(9)), "11"); ``` Or by adding [formatting parameters][1] which cause no visual effects: ```rust use derive_more::Debug; #[derive(Debug)] #[debug("{_0:^o}")] // `^` is centering, but in absence of additional width has no effect struct MyOctalInt(i32); // and so, additional formatting parameters have no effect assert_eq!(format!("{:07?}", MyOctalInt(9)), "11"); ``` ## 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)] #[debug("{_0} = {_1}")] struct StructFormat(&'static str, u8); #[derive(Debug)] enum E { Skipped { x: u32, #[debug(skip)] // or #[debug(ignore)] y: u32, }, Binary { #[debug("{i:b}")] i: i8, }, Path(#[debug("{}", _0.display())] PathBuf), #[debug("{_0}")] EnumFormat(bool) } assert_eq!(format!("{:?}", MyInt(-2)), "MyInt(-2)"); assert_eq!(format!("{:?}", MyIntHex(-255)), "MyIntHex(ffffff01)"); assert_eq!(format!("{:?}", StructFormat("answer", 42)), "answer = 42"); 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)"); assert_eq!(format!("{:?}", E::EnumFormat(true)), "true"); ``` [`format!()`]: https://doc.rust-lang.org/stable/std/macro.format.html [`format_args!()`]: https://doc.rust-lang.org/stable/std/macro.format_args.html [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#formatting-parameters derive_more-impl-1.0.0/doc/deref.md000064400000000000000000000035461046102023000152450ustar 00000000000000# 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); // You can specify the field you want to derive `Deref` for. #[derive(Deref)] struct CoolVec { cool: bool, #[deref] vec: Vec, } 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, } ``` Code like this will be generated: ```rust # struct CoolVec { # cool: bool, # vec: Vec, # } impl derive_more::Deref for CoolVec { type Target = Vec; #[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); ``` Code like this will be generated: ```rust # struct MyBoxedInt(Box); impl derive_more::Deref for MyBoxedInt { type Target = as derive_more::Deref>::Target; #[inline] fn deref(&self) -> &Self::Target { as derive_more::Deref>::deref(&self.0) } } ``` ## Enums Deriving `Deref` is not supported for enums. derive_more-impl-1.0.0/doc/deref_mut.md000064400000000000000000000052321046102023000161240ustar 00000000000000# 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); // You can specify the field you want to derive DerefMut for #[derive(Deref, DerefMut)] struct CoolVec { cool: bool, #[deref] #[deref_mut] vec: Vec, } 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, } ``` Code like this will be generated: ```rust # use ::core::ops::Deref; # struct CoolVec { # cool: bool, # vec: Vec, # } # impl Deref for CoolVec { # type Target = Vec; # #[inline] # fn deref(&self) -> &Self::Target { # &self.vec # } # } impl derive_more::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); ``` When deriving a forwarded `DerefMut` for a struct: ```rust # use ::core::ops::Deref; # struct MyBoxedInt(Box); # impl Deref for MyBoxedInt { # type Target = as Deref>::Target; # #[inline] # fn deref(&self) -> &Self::Target { # as Deref>::deref(&self.0) # } # } impl derive_more::DerefMut for MyBoxedInt { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { as derive_more::DerefMut>::deref_mut(&mut self.0) } } ``` ## Enums Deriving `DerefMut` is not supported for enums. derive_more-impl-1.0.0/doc/display.md000064400000000000000000000202101046102023000156100ustar 00000000000000# 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 variables available in the arguments is `self` and each member of the struct or enum variant, with members of tuple structs being named with a leading underscore and their index, i.e. `_0`, `_1`, `_2`, etc. Due to ownership/lifetime limitations the member variables are all references to the fields, except when used directly in the format string. For most purposes this detail doesn't matter, but it is quite important when using `Pointer` formatting. If you don't use the `{field:p}` syntax, you have to dereference once to get the address of the field itself, instead of the address of the reference to the field: ```rust # use derive_more::Display; # #[derive(Display)] #[display("{field:p} {:p}", *field)] struct RefInt<'a> { field: &'a i32, } let a = &123; assert_eq!(format!("{}", RefInt{field: &a}), format!("{a:p} {:p}", a)); ``` For enums you can also specify a shared format on the enum itself instead of the variant. This format is used for each of the variants, and can be customized per variant by including the special `{_variant}` placeholder in this shared format, which is then replaced by the format string that's provided on the variant. ### 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. Bounds can only be inferred this way if a field is used directly in the interpolation. E.g., for a structure `Foo` defined like this: ```rust # use derive_more::Display; # # trait Trait { type Type; } # #[derive(Display)] #[display("{a} {b} {c:?} {d:p}")] struct Foo<'a, T1, T2: Trait, T3> { a: T1, b: ::Type, c: Vec, d: &'a T1, } ``` The following where clauses would be generated: * `T1: Display` * `::Type: Display` * `Vec: Debug` * `&'a T1: Pointer` ### 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`. `#[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 the required trait bounds of the expression. Either in the struct/enum definition, or via `#[display(bound(...))]` attribute. Explicitly specified bounds are added to the inferred ones. Note how no `V: Display` bound is necessary, because it's inferred already. ```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 { a: T, b: U, c: V, } ``` ### Transparency If the `#[display("...", args...)]` attribute is omitted, the implementation transparently delegates to the format of the inner type, so all the additional [formatting parameters][1] do work as expected: ```rust # use derive_more::Display; # #[derive(Display)] struct MyInt(i32); assert_eq!(format!("{:03}", MyInt(7)), "007"); ``` If the `#[display("...", args...)]` attribute is specified and can be trivially substituted with a transparent delegation call to the inner type, then additional [formatting parameters][1] will work too: ```rust # use derive_more::Display; # #[derive(Display)] #[display("{_0:o}")] // the same as calling `Octal::fmt()` struct MyOctalInt(i32); // so, additional formatting parameters do work transparently assert_eq!(format!("{:03}", MyOctalInt(9)), "011"); #[derive(Display)] #[display("{_0:02b}")] // cannot be trivially substituted with `Binary::fmt()`, struct MyBinaryInt(i32); // because of specified formatting parameters // so, additional formatting parameters have no effect assert_eq!(format!("{:07}", MyBinaryInt(2)), "10"); ``` If, for some reason, transparency in trivial cases is not desired, it may be suppressed explicitly either with the [`format_args!()`] macro usage: ```rust # use derive_more::Display; # #[derive(Display)] #[display("{}", format_args!("{_0:o}"))] // `format_args!()` obscures the inner type struct MyOctalInt(i32); // so, additional formatting parameters have no effect assert_eq!(format!("{:07}", MyOctalInt(9)), "11"); ``` Or by adding [formatting parameters][1] which cause no visual effects: ```rust # use derive_more::Display; # #[derive(Display)] #[display("{_0:^o}")] // `^` is centering, but in absence of additional width has no effect struct MyOctalInt(i32); // and so, additional formatting parameters have no effect assert_eq!(format!("{:07}", MyOctalInt(9)), "11"); ``` ## 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)] #[display("Enum E: {_variant}")] enum E { Uint(u32), #[display("I am B {:b}", i)] Binary { i: i8, }, #[display("I am C {}", _0.display())] Path(PathBuf), } #[derive(Display)] #[display("Enum E2: {_0:?}")] enum E2 { Uint(u32), String(&'static str, &'static str), } #[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(), "Enum E: 2"); assert_eq!(E::Binary { i: -2 }.to_string(), "Enum E: I am B 11111110"); assert_eq!(E::Path("abc".into()).to_string(), "Enum E: I am C abc"); assert_eq!(E2::Uint(2).to_string(), "Enum E2: 2"); assert_eq!(E2::String("shown", "ignored").to_string(), "Enum E2: \"shown\""); 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"); ``` [`format_args!()`]: https://doc.rust-lang.org/stable/std/macro.format_args.html [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#formatting-parameters derive_more-impl-1.0.0/doc/error.md000064400000000000000000000116511046102023000153050ustar 00000000000000# 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, or wait until Rust 1.81 when `Error` in `core` is expected to be stabilized. 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))] // Nightly requires enabling this feature: // #![feature(error_generic_member_access)] # #[cfg(not(nightly))] fn main() {} # #[cfg(nightly)] fn main() { # use core::error::{request_ref, request_value, Error as __}; # use std::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!(request_ref::(&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!(request_ref::(&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()); # } ``` derive_more-impl-1.0.0/doc/from.md000064400000000000000000000101051046102023000151100ustar 00000000000000# 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()]`. ```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()]` 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 `#[from(ignore)]`) 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)] // or #[from(ignore)] 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()); ``` derive_more-impl-1.0.0/doc/from_str.md000064400000000000000000000053111046102023000160030ustar 00000000000000# 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 derive_more::FromStr for MyInt { type Err = ::Err; fn from_str(src: &str) -> Result { 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 derive_more::FromStr for Point1D { type Err = ::Err; fn from_str(src: &str) -> Result { 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 derive_more::FromStr for EnumNoFields { type Err = derive_more::FromStrError; fn from_str(src: &str) -> Result { Ok(match src.to_lowercase().as_str() { "foo" => EnumNoFields::Foo, "bar" => EnumNoFields::Bar, "baz" => EnumNoFields::Baz, _ => return Err(derive_more::FromStrError::new("EnumNoFields")), }) } } ``` derive_more-impl-1.0.0/doc/index.md000064400000000000000000000024351046102023000152630ustar 00000000000000# 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); // You can specify the field you want to derive Index for #[derive(Index)] struct Numbers { #[index] numbers: Vec, 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, useless: bool, } ``` Code like this will be generated: ```rust # struct Numbers { # numbers: Vec, # useless: bool, # } impl<__IdxT> derive_more::Index<__IdxT> for Numbers where Vec: derive_more::Index<__IdxT>, { type Output = as derive_more::Index<__IdxT>>::Output; #[inline] fn index(&self, idx: __IdxT) -> &Self::Output { as derive_more::Index<__IdxT>>::index(&self.numbers, idx) } } ``` ## Enums Deriving `Index` is not supported for enums. derive_more-impl-1.0.0/doc/index_mut.md000064400000000000000000000035111046102023000161440ustar 00000000000000# 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); #[derive(Index, IndexMut)] struct Numbers { #[index] #[index_mut] numbers: Vec, 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, useless: bool, } ``` Code like this will be generated to implement `IndexMut`: ```rust # use ::core::ops::Index; # struct Numbers { # numbers: Vec, # useless: bool, # } # impl<__IdxT> Index<__IdxT> for Numbers # where # Vec: Index<__IdxT>, # { # type Output = as Index<__IdxT>>::Output; # #[inline] # fn index(&self, idx: __IdxT) -> &Self::Output { # as Index<__IdxT>>::index(&self.numbers, idx) # } # } impl<__IdxT> derive_more::IndexMut<__IdxT> for Numbers where Vec: derive_more::IndexMut<__IdxT>, { #[inline] fn index_mut(&mut self, idx: __IdxT) -> &mut Self::Output { as derive_more::IndexMut<__IdxT>>::index_mut(&mut self.numbers, idx) } } ``` ## Enums Deriving `IndexMut` is not supported for enums. derive_more-impl-1.0.0/doc/into.md000064400000000000000000000107451046102023000151300ustar 00000000000000# 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()]`. ```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"), >::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)]` (or `#[into(ignore)]`) attribute. ```rust # use std::marker::PhantomData; # # use derive_more::Into; # # struct Gram; # #[derive(Debug, Into, PartialEq)] #[into(i32, i64, i128)] struct Mass { value: i32, #[into(skip)] // or #[into(ignore)] _unit: PhantomData, } assert_eq!(5, Mass::::new(5).into()); assert_eq!(5_i64, Mass::::new(5).into()); assert_eq!(5_i128, Mass::::new(5).into()); # # impl Mass { # fn new(value: i32) -> Self { # Self { # value, # _unit: PhantomData, # } # } # } ``` ### Fields The `#[into]` attribute can also be applied to specific fields of a struct. ```rust # use derive_more::Into; # #[derive(Into)] struct Data { id: i32, #[into] raw: f64 } assert_eq!(42.0, Data { id: 1, raw: 42.0 }.into()); ``` In such cases, no conversion into a tuple of all fields is generated, unless an explicit struct attribute is present. ```rust # use derive_more::Into; # #[derive(Into)] #[into] struct Data { id: i32, #[into] raw: f64 } assert_eq!(42.0, Data { id: 1, raw: 42.0 }.into()); assert_eq!((1, 42.0), Data { id: 1, raw: 42.0 }.into()); ``` The `#[into()]` syntax can be used on fields as well. ```rust # use std::marker::PhantomData; # use derive_more::Into; # struct Whatever; # #[derive(Into, Clone)] #[into(owned, ref((u8, str)), ref_mut)] struct Foo { #[into(owned(u64), ref)] a: u8, b: String, #[into(skip)] _c: PhantomData, } let mut foo = Foo { a: 1, b: "string".to_owned(), _c: PhantomData }; assert_eq!((1_u8, "string".to_owned()), foo.clone().into()); assert_eq!((&1_u8, "string"), <(&u8, &str)>::from(&foo)); assert_eq!((&mut 1_u8, &mut "string".to_owned()), <(&mut u8, &mut String)>::from(&mut foo)); assert_eq!(1_u64, foo.clone().into()); assert_eq!(&1_u8, <&u8>::from(&foo)); ``` Fields, having specific conversions into them, can also be skipped for top-level tuple conversions. ```rust # use derive_more::Into; #[derive(Into)] #[into(ref((str, f64)))] struct Foo { #[into(ref)] #[into(skip)] a: u8, b: String, c: f64, } let foo = Foo { a: 1, b: "string".to_owned(), c: 3.0 }; assert_eq!(("string", &3.0), (&foo).into()); assert_eq!(&1_u8, <&u8>::from(&foo)); ``` ## 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 derive_more-impl-1.0.0/doc/into_iterator.md000064400000000000000000000054001046102023000170310ustar 00000000000000# 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); // You can specify the field you want to derive `IntoIterator` for #[derive(IntoIterator)] struct Numbers { #[into_iterator(owned, ref, ref_mut)] numbers: Vec, 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, useless: bool, } ``` Code like this will be generated: ```rust # struct Numbers { # numbers: Vec, # useless: bool, # } impl derive_more::IntoIterator for Numbers { type Item = as derive_more::IntoIterator>::Item; type IntoIter = as derive_more::IntoIterator>::IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { as derive_more::IntoIterator>::into_iter(self.numbers) } } impl<'__deriveMoreLifetime> derive_more::IntoIterator for &'__deriveMoreLifetime Numbers { type Item = <&'__deriveMoreLifetime Vec as derive_more::IntoIterator>::Item; type IntoIter = <&'__deriveMoreLifetime Vec as derive_more::IntoIterator>::IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { <&'__deriveMoreLifetime Vec as derive_more::IntoIterator>::into_iter(&self.numbers) } } impl<'__deriveMoreLifetime> derive_more::IntoIterator for &'__deriveMoreLifetime mut Numbers { type Item = <&'__deriveMoreLifetime mut Vec as derive_more::IntoIterator>::Item; type IntoIter = <&'__deriveMoreLifetime mut Vec as derive_more::IntoIterator>::IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { <&'__deriveMoreLifetime mut Vec as derive_more::IntoIterator>::into_iter( &mut self.numbers, ) } } ``` ## Enums Deriving `IntoIterator` is not supported for enums. derive_more-impl-1.0.0/doc/is_variant.md000064400000000000000000000016241046102023000163120ustar 00000000000000# 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 { Just(T), Nothing } assert!(Maybe::<()>::Nothing.is_nothing()); assert!(!Maybe::<()>::Nothing.is_just()); ``` ### What is generated? The derive in the above example generates code like this: ```rust # enum Maybe { # Just(T), # Nothing # } impl Maybe{ #[must_use] pub const fn is_just(&self) -> bool { matches!(self, Self::Just(..)) } #[must_use] pub const fn is_nothing(&self) -> bool { matches!(self, Self::Nothing) } } ``` derive_more-impl-1.0.0/doc/mul.md000064400000000000000000000065571046102023000147620ustar 00000000000000# 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> derive_more::Mul<__RhsT> for MyInt where i32: derive_more::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: Copy> derive_more::Mul<__RhsT> for MyInts where i32: derive_more::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> derive_more::Mul<__RhsT> for Point1D where i32: derive_more::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: Copy> derive_more::Mul<__RhsT> for Point2D where i32: derive_more::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. derive_more-impl-1.0.0/doc/mul_assign.md000064400000000000000000000041371046102023000163160ustar 00000000000000# 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: Copy> derive_more::MulAssign<__RhsT> for MyInts where i32: derive_more::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: Copy> derive_more::MulAssign<__RhsT> for Point2D where i32: derive_more::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` instead of an `EnumType`. Handling the case where it errors would be hard and maybe impossible. derive_more-impl-1.0.0/doc/not.md000064400000000000000000000065751046102023000147650ustar 00000000000000# 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 derive_more::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 derive_more::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 derive_more::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`. 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 derive_more::Not for EnumWithUnit { type Output = Result; fn not(self) -> Result { match self { EnumWithUnit::SmallInt(__0) => Ok(EnumWithUnit::SmallInt(__0.not())), EnumWithUnit::Unit => Err(derive_more::UnitError::new("not")), } } } ``` derive_more-impl-1.0.0/doc/sum.md000064400000000000000000000035121046102023000147550ustar 00000000000000# 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 # use ::core::ops::Add; # struct MyInts(i32, i64); # impl 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 derive_more::Sum for MyInts { #[inline] fn sum>(iter: I) -> Self { iter.fold( MyInts( derive_more::core::iter::empty::().sum(), derive_more::core::iter::empty::().sum(), ), derive_more::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. derive_more-impl-1.0.0/doc/try_from.md000064400000000000000000000021131046102023000160060ustar 00000000000000# What `#[derive(TryFrom)]` generates Derive `TryFrom` allows you to convert enum discriminants into their corresponding variants. ## Enums By default, a `TryFrom` is generated, matching the [type of the discriminant](https://doc.rust-lang.org/reference/items/enumerations.html#discriminants). The type can be changed with a `#[repr(u/i*)]` attribute, e.g., `#[repr(u8)]` or `#[repr(i32)]`. Only field-less variants can be constructed from their variant, therefore the `TryFrom` implementation will return an error for a discriminant representing a variant with fields. ```rust # use derive_more::TryFrom; # #[derive(TryFrom, Debug, PartialEq)] #[try_from(repr)] #[repr(u32)] enum Enum { ImplicitZero, ExplicitFive = 5, FieldSix(usize), EmptySeven{}, } assert_eq!(Enum::ImplicitZero, Enum::try_from(0).unwrap()); assert_eq!(Enum::ExplicitFive, Enum::try_from(5).unwrap()); assert_eq!(Enum::EmptySeven{}, Enum::try_from(7).unwrap()); // Variants with fields are not supported, as the value for their fields would be undefined. assert!(Enum::try_from(6).is_err()); ``` derive_more-impl-1.0.0/doc/try_into.md000064400000000000000000000115461046102023000160260ustar 00000000000000# 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 derive_more::TryFrom for (i32) { type Error = &'static str; fn try_from(value: MixedInts) -> Result { match value { MixedInts::SmallInt(__0) => Ok(__0), _ => Err("Only SmallInt can be converted to i32"), } } } impl derive_more::TryFrom for (i64) { type Error = &'static str; fn try_from(value: MixedInts) -> Result { match value { MixedInts::BigInt(__0) => Ok(__0), _ => Err("Only BigInt can be converted to i64"), } } } impl derive_more::TryFrom for (i32, i32) { type Error = &'static str; fn try_from(value: MixedInts) -> Result { match value { MixedInts::TwoSmallInts(__0, __1) => Ok((__0, __1)), _ => Err("Only TwoSmallInts can be converted to (i32, i32)"), } } } impl derive_more::TryFrom for (i64, i64) { type Error = &'static str; fn try_from(value: MixedInts) -> Result { match value { MixedInts::NamedSmallInts { x: __0, y: __1 } => Ok((__0, __1)), _ => Err("Only NamedSmallInts can be converted to (i64, i64)"), } } } impl derive_more::TryFrom for (u32) { type Error = &'static str; fn try_from(value: MixedInts) -> Result { 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 derive_more::TryFrom for (i32) { type Error = &'static str; fn try_from(value: EnumWithUnit) -> Result { match value { EnumWithUnit::SmallInt(__0) => Ok(__0), _ => Err("Only SmallInt can be converted to i32"), } } } impl derive_more::TryFrom for () { type Error = &'static str; fn try_from(value: EnumWithUnit) -> Result { match value { EnumWithUnit::Unit => Ok(()), _ => Err("Only Unit can be converted to ()"), } } } ``` derive_more-impl-1.0.0/doc/try_unwrap.md000064400000000000000000000054711046102023000163710ustar 00000000000000# 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>` 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 { 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 { # Just(T), # Nothing, # } # impl Maybe { pub fn try_unwrap_nothing(self) -> Result<(), TryUnwrapError> { 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> { 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 */)")), } } } ``` derive_more-impl-1.0.0/doc/unwrap.md000064400000000000000000000034621046102023000154710ustar 00000000000000# 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 { 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 { # Just(T), # Nothing, # } # impl Maybe { 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!(), } } } ``` derive_more-impl-1.0.0/src/add_assign_like.rs000064400000000000000000000027771046102023000173330ustar 00000000000000use crate::add_helpers::{struct_exprs, tuple_exprs}; use crate::utils::{add_extra_ty_param_bound_op, named_to_vec, unnamed_to_vec}; use proc_macro2::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 derive_more::#trait_ident for #input_type #ty_generics #where_clause { #[inline] #[track_caller] fn #method_ident(&mut self, rhs: #input_type #ty_generics) { #( #exprs; )* } } } } derive_more-impl-1.0.0/src/add_helpers.rs000064400000000000000000000015031046102023000164670ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::{Field, Ident, Index}; pub fn tuple_exprs(fields: &[&Field], method_ident: &Ident) -> Vec { let mut exprs = vec![]; for i in 0..fields.len() { let i = Index::from(i); // generates `self.0.add(rhs.0)` let expr = quote! { self.#i.#method_ident(rhs.#i) }; exprs.push(expr); } exprs } pub fn struct_exprs(fields: &[&Field], method_ident: &Ident) -> Vec { let mut exprs = vec![]; for field in fields { // It's safe to unwrap because struct fields always have an identifier let field_id = field.ident.as_ref().unwrap(); // generates `x: self.x.add(rhs.x)` let expr = quote! { self.#field_id.#method_ident(rhs.#field_id) }; exprs.push(expr) } exprs } derive_more-impl-1.0.0/src/add_like.rs000064400000000000000000000134061046102023000157560ustar 00000000000000use crate::add_helpers::{struct_exprs, tuple_exprs}; use crate::utils::{ add_extra_type_param_bound_op_output, field_idents, named_to_vec, numbered_vars, unnamed_to_vec, }; use proc_macro2::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! { derive_more::core::result::Result<#input_type #ty_generics, derive_more::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] #[track_caller] fn #method_ident(self, rhs: #input_type #ty_generics) -> #output_type { #block } } } } fn tuple_content( input_type: &T, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { let exprs = tuple_exprs(fields, method_ident); quote! { #input_type(#(#exprs),*) } } fn struct_content( input_type: &Ident, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { // It's safe to unwrap because struct fields always have an identifier let exprs = struct_exprs(fields, method_ident); let field_names = field_idents(fields); quote! { #input_type{#(#field_names: #exprs),*} } } #[allow(clippy::cognitive_complexity)] fn enum_content( input_type: &Ident, data_enum: &DataEnum, method_ident: &Ident, ) -> TokenStream { let mut matches = vec![]; let mut method_iter = iter::repeat(method_ident); for variant in &data_enum.variants { let subtype = &variant.ident; let subtype = quote! { #input_type::#subtype }; match variant.fields { Fields::Unnamed(ref fields) => { // The 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),*)) => { derive_more::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),*}) => { derive_more::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) => derive_more::core::result::Result::Err( derive_more::BinaryError::Unit( derive_more::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! { _ => derive_more::core::result::Result::Err(derive_more::BinaryError::Mismatch( derive_more::WrongVariantError::new(#operation_name) )) }); } quote! { match (self, rhs) { #(#matches),* } } } derive_more-impl-1.0.0/src/as/mod.rs000064400000000000000000000245641046102023000154130ustar 00000000000000//! Implementations of [`AsRef`]/[`AsMut`] derive macros. pub(crate) mod r#mut; pub(crate) mod r#ref; use std::{borrow::Cow, iter}; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{parse_quote, spanned::Spanned, Token}; use crate::utils::{ attr::{self, ParseMultiple as _}, Either, GenericsSearch, Spanning, }; /// Expands an [`AsRef`]/[`AsMut`] derive macro. pub fn expand( input: &syn::DeriveInput, trait_info: ExpansionCtx<'_>, ) -> syn::Result { let (trait_ident, attr_name, _) = trait_info; let data = match &input.data { syn::Data::Struct(data) => Ok(data), syn::Data::Enum(e) => Err(syn::Error::new( e.enum_token.span(), format!("`{trait_ident}` cannot be derived for enums"), )), syn::Data::Union(u) => Err(syn::Error::new( u.union_token.span(), format!("`{trait_ident}` cannot be derived for unions"), )), }?; let expansions = if let Some(attr) = StructAttribute::parse_attrs(&input.attrs, attr_name)? { if data.fields.len() != 1 { return Err(syn::Error::new( if data.fields.is_empty() { data.struct_token.span } else { data.fields.span() }, format!( "`#[{attr_name}(...)]` attribute can only be placed on structs with exactly \ one field", ), )); } let field = data.fields.iter().next().unwrap(); if FieldAttribute::parse_attrs(&field.attrs, attr_name)?.is_some() { return Err(syn::Error::new( field.span(), format!("`#[{attr_name}(...)]` cannot be placed on both struct and its field"), )); } vec![Expansion { trait_info, ident: &input.ident, generics: &input.generics, field, field_index: 0, conversions: Some(attr.into_inner()), }] } else { let attrs = data .fields .iter() .map(|field| FieldAttribute::parse_attrs(&field.attrs, attr_name)) .collect::>>()?; let present_attrs = attrs.iter().filter_map(Option::as_ref).collect::>(); let all = present_attrs .iter() .all(|attr| matches!(attr.item, FieldAttribute::Skip(_))); if !all { if let Some(skip_attr) = present_attrs.iter().find_map(|attr| { if let FieldAttribute::Skip(skip) = &attr.item { Some(attr.as_ref().map(|_| skip)) } else { None } }) { return Err(syn::Error::new( skip_attr.span(), format!( "`#[{attr_name}({})]` cannot be used in the same struct with other \ `#[{attr_name}(...)]` attributes", skip_attr.name(), ), )); } } if all { data.fields .iter() .enumerate() .zip(attrs) .filter_map(|((i, field), attr)| { attr.is_none().then_some(Expansion { trait_info, ident: &input.ident, generics: &input.generics, field, field_index: i, conversions: None, }) }) .collect() } else { data.fields .iter() .enumerate() .zip(attrs) .filter_map(|((i, field), attr)| match attr.map(Spanning::into_inner) { Some( attr @ (FieldAttribute::Empty(_) | FieldAttribute::Forward(_) | FieldAttribute::Types(_)), ) => Some(Expansion { trait_info, ident: &input.ident, generics: &input.generics, field, field_index: i, conversions: attr.into(), }), Some(FieldAttribute::Skip(_)) => unreachable!(), None => None, }) .collect() } }; Ok(expansions .into_iter() .map(ToTokens::into_token_stream) .collect()) } /// Type alias for an expansion context: /// - [`syn::Ident`] of the derived trait. /// - [`syn::Ident`] of the derived trait method. /// - Optional `mut` token indicating [`AsMut`] expansion. /// /// [`syn::Ident`]: struct@syn::Ident type ExpansionCtx<'a> = (&'a syn::Ident, &'a syn::Ident, Option<&'a Token![mut]>); /// Expansion of a macro for generating [`AsRef`]/[`AsMut`] implementations for a single field of a /// struct. struct Expansion<'a> { /// [`ExpansionCtx`] of the derived trait. trait_info: ExpansionCtx<'a>, /// [`syn::Ident`] of the struct. /// /// [`syn::Ident`]: struct@syn::Ident ident: &'a syn::Ident, /// [`syn::Generics`] of the struct. generics: &'a syn::Generics, /// [`syn::Field`] of the struct. field: &'a syn::Field, /// Index of the [`syn::Field`]. field_index: usize, /// Attribute specifying which conversions should be generated. conversions: Option, } impl<'a> ToTokens for Expansion<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let field_ty = &self.field.ty; let field_ident = self.field.ident.as_ref().map_or_else( || Either::Right(syn::Index::from(self.field_index)), Either::Left, ); let (trait_ident, method_ident, mut_) = &self.trait_info; let ty_ident = &self.ident; let field_ref = quote! { & #mut_ self.#field_ident }; let generics_search = GenericsSearch { types: self.generics.type_params().map(|p| &p.ident).collect(), lifetimes: self .generics .lifetimes() .map(|p| &p.lifetime.ident) .collect(), consts: self.generics.const_params().map(|p| &p.ident).collect(), }; let field_contains_generics = generics_search.any_in(field_ty); let is_blanket = matches!(&self.conversions, Some(attr::Conversion::Forward(_))); let return_tys = match &self.conversions { Some(attr::Conversion::Forward(_)) => { Either::Left(iter::once(Cow::Owned(parse_quote! { __AsT }))) } Some(attr::Conversion::Types(tys)) => { Either::Right(tys.0.iter().map(Cow::Borrowed)) } None => Either::Left(iter::once(Cow::Borrowed(field_ty))), }; for return_ty in return_tys { /// Kind of a generated implementation, chosen based on attribute arguments. enum ImplKind { /// Returns a reference to a field. Direct, /// Forwards `as_ref`/`as_mut` call on a field. Forwarded, /// Uses autoref-based specialization to determine whether to use direct or /// forwarded implementation, based on whether the field and the return type match. /// /// Doesn't work when generics are involved. Specialized, } let impl_kind = if is_blanket { ImplKind::Forwarded } else if field_ty == return_ty.as_ref() { ImplKind::Direct } else if field_contains_generics || generics_search.any_in(&return_ty) { ImplKind::Forwarded } else { ImplKind::Specialized }; let trait_ty = quote! { derive_more::#trait_ident <#return_ty> }; let generics = match &impl_kind { ImplKind::Forwarded => { let mut generics = self.generics.clone(); generics .make_where_clause() .predicates .push(parse_quote! { #field_ty: #trait_ty }); if is_blanket { generics .params .push(parse_quote! { #return_ty: ?derive_more::core::marker::Sized }); } Cow::Owned(generics) } ImplKind::Direct | ImplKind::Specialized => { Cow::Borrowed(self.generics) } }; let (impl_gens, _, where_clause) = generics.split_for_impl(); let (_, ty_gens, _) = self.generics.split_for_impl(); let body = match &impl_kind { ImplKind::Direct => Cow::Borrowed(&field_ref), ImplKind::Forwarded => Cow::Owned(quote! { <#field_ty as #trait_ty>::#method_ident(#field_ref) }), ImplKind::Specialized => Cow::Owned(quote! { use derive_more::__private::ExtractRef as _; let conv = as derive_more::core::default::Default>::default(); (&&conv).__extract_ref(#field_ref) }), }; quote! { #[automatically_derived] impl #impl_gens #trait_ty for #ty_ident #ty_gens #where_clause { #[inline] fn #method_ident(& #mut_ self) -> & #mut_ #return_ty { #body } } } .to_tokens(tokens); } } } /// Representation of an [`AsRef`]/[`AsMut`] derive macro struct container attribute. /// /// ```rust,ignore /// #[as_ref(forward)] /// #[as_ref()] /// ``` type StructAttribute = attr::Conversion; /// Representation of an [`AsRef`]/[`AsMut`] derive macro field attribute. /// /// ```rust,ignore /// #[as_ref] /// #[as_ref(skip)] #[as_ref(ignore)] /// #[as_ref(forward)] /// #[as_ref()] /// ``` type FieldAttribute = attr::FieldConversion; derive_more-impl-1.0.0/src/as/mut.rs000064400000000000000000000007651046102023000154360ustar 00000000000000//! Implementation of an [`AsMut`] derive macro. use proc_macro2::TokenStream; use quote::format_ident; use syn::Token; /// Expands an [`AsMut`] derive macro. pub(crate) fn expand( input: &syn::DeriveInput, trait_name: &'static str, ) -> syn::Result { let trait_ident = format_ident!("{trait_name}"); let method_ident = format_ident!("as_mut"); let mutability = ::default(); super::expand(input, (&trait_ident, &method_ident, Some(&mutability))) } derive_more-impl-1.0.0/src/as/ref.rs000064400000000000000000000006511046102023000153770ustar 00000000000000//! Implementation of an [`AsRef`] derive macro. use proc_macro2::TokenStream; use quote::format_ident; /// Expands an [`AsRef`] derive macro. pub(crate) fn expand( input: &syn::DeriveInput, trait_name: &'static str, ) -> syn::Result { let trait_ident = format_ident!("{trait_name}"); let method_ident = format_ident!("as_ref"); super::expand(input, (&trait_ident, &method_ident, None)) } derive_more-impl-1.0.0/src/constructor.rs000064400000000000000000000037061046102023000166110ustar 00000000000000use crate::utils::{ field_idents, get_field_types, named_to_vec, numbered_vars, unnamed_to_vec, }; use proc_macro2::TokenStream; use quote::quote; use syn::{Data, DeriveInput, Field, Fields, Ident}; /// Provides the hook to expand `#[derive(Constructor)]` into an implementation of `Constructor` pub fn expand(input: &DeriveInput, _: &str) -> TokenStream { let input_type = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let ((body, vars), fields) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { let field_vec = unnamed_to_vec(fields); (tuple_body(input_type, &field_vec), field_vec) } Fields::Named(ref fields) => { let field_vec = named_to_vec(fields); (struct_body(input_type, &field_vec), field_vec) } Fields::Unit => (struct_body(input_type, &[]), vec![]), }, _ => panic!("Only structs can derive a constructor"), }; let original_types = &get_field_types(&fields); quote! { #[allow(missing_docs)] #[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) { let vars = &numbered_vars(fields.len(), ""); (quote! { #return_type(#(#vars),*) }, vars.clone()) } fn struct_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec) { let field_names: &Vec = &field_idents(fields).iter().map(|f| (**f).clone()).collect(); let vars = field_names; let ret_vars = field_names.clone(); (quote! { #return_type{#(#field_names: #vars),*} }, ret_vars) } derive_more-impl-1.0.0/src/deref.rs000064400000000000000000000030041046102023000153000ustar 00000000000000use crate::utils::{add_extra_where_clauses, SingleFieldData, State}; use proc_macro2::TokenStream; use quote::quote; use syn::{parse::Result, DeriveInput}; /// Provides the hook to expand `#[derive(Deref)]` into an implementation of `Deref` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_forward( input, trait_name, 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 } } }) } derive_more-impl-1.0.0/src/deref_mut.rs000064400000000000000000000025421046102023000161730ustar 00000000000000use crate::utils::{add_extra_where_clauses, SingleFieldData, State}; use proc_macro2::TokenStream; use quote::quote; use syn::{parse::Result, DeriveInput}; /// Provides the hook to expand `#[derive(DerefMut)]` into an implementation of `DerefMut` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_forward(input, trait_name, "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 } } }) } derive_more-impl-1.0.0/src/error.rs000064400000000000000000000343371046102023000153610ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::{spanned::Spanned as _, Error, Result}; use crate::utils::{ self, AttrParams, DeriveType, FullMetaInfo, HashSet, MetaInfo, MultiFieldData, State, }; pub fn expand( input: &syn::DeriveInput, trait_name: &'static str, ) -> Result { let syn::DeriveInput { ident, generics, .. } = input; let state = State::with_attr_params( input, trait_name, 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| { // Not using `#[inline]` here on purpose, since this is almost never part // of a hot codepath. quote! { fn source(&self) -> Option<&(dyn derive_more::Error + 'static)> { use derive_more::__private::AsDynError; #source } } }); let provide = provide.map(|provide| { // Not using `#[inline]` here on purpose, since this is almost never part // of a hot codepath. quote! { fn provide<'_request>( &'_request self, request: &mut derive_more::core::error::Request<'_request>, ) { #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: derive_more::core::fmt::Debug + derive_more::core::fmt::Display }, ); } if !bounds.is_empty() { let bounds = bounds.iter(); generics = utils::add_extra_where_clauses( &generics, quote! { where #( #bounds: derive_more::core::fmt::Debug + derive_more::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, state: &State, ) -> Result<(HashSet, Option, Option)> { 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, state: &State, ) -> Result<(HashSet, Option, Option)> { 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, 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, backtrace: Option, bounds: HashSet, } impl<'input, 'state> ParsedFields<'input, 'state> { fn new(data: MultiFieldData<'input, 'state>) -> Self { Self { data, source: None, backtrace: None, bounds: HashSet::default(), } } } impl<'input, 'state> ParsedFields<'input, 'state> { fn render_source_as_struct(&self) -> Option { let source = self.source?; let ident = &self.data.members[source]; Some(render_some(quote! { #ident })) } fn render_source_as_enum_variant_match_arm(&self) -> Option { let source = self.source?; let pattern = self.data.matcher(&[source], &[quote! { source }]); let expr = render_some(quote! { source }); Some(quote! { #pattern => #expr }) } fn render_provide_as_struct(&self) -> Option { 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, request); } }); let backtrace_provider = self .source .filter(|source| *source == backtrace) .is_none() .then(|| { let backtrace_expr = &self.data.members[backtrace]; quote! { request.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 { 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, request); } }) } Some(source) => { let pattern = self.data.matcher( &[source, backtrace], &[quote! { source }, quote! { backtrace }], ); Some(quote! { #pattern => { request.provide_ref::<::std::backtrace::Backtrace>(backtrace); derive_more::Error::provide(source, request); } }) } None => { let pattern = self.data.matcher(&[backtrace], &[quote! { backtrace }]); Some(quote! { #pattern => { request.provide_ref::<::std::backtrace::Backtrace>(backtrace); } }) } } } } fn render_some(expr: T) -> TokenStream where T: quote::ToTokens, { quote! { Some(#expr.as_dyn_error()) } } fn parse_fields<'input, 'state>( type_params: &HashSet, state: &'state State<'input>, ) -> Result> { let mut parsed_fields = match state.derive_type { DeriveType::Named => { parse_fields_impl(state, |attr, field, _| { // Unwrapping is safe, cause fields in named struct // always have an ident let ident = field.ident.as_ref().unwrap(); match attr { "source" => ident == "source", "backtrace" => { ident == "backtrace" || is_type_path_ends_with_segment(&field.ty, "Backtrace") } _ => unreachable!(), } }) } DeriveType::Unnamed => { let mut parsed_fields = parse_fields_impl(state, |attr, field, len| match attr { "source" => { len == 1 && !is_type_path_ends_with_segment(&field.ty, "Backtrace") } "backtrace" => { is_type_path_ends_with_segment(&field.ty, "Backtrace") } _ => unreachable!(), })?; parsed_fields.source = parsed_fields .source .or_else(|| infer_source_field(&state.fields, &parsed_fields)); Ok(parsed_fields) } _ => unreachable!(), }?; if let Some(source) = parsed_fields.source { add_bound_if_type_parameter_used_in_type( &mut parsed_fields.bounds, type_params, &state.fields[source].ty, ); } Ok(parsed_fields) } /// Checks if `ty` is [`syn::Type::Path`] and ends with segment matching `tail` /// and doesn't contain any generic parameters. fn is_type_path_ends_with_segment(ty: &syn::Type, tail: &str) -> bool { let 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 { // if we have exactly two fields if fields.len() != 2 { return None; } // no source field was specified/inferred if parsed_fields.source.is_some() { return None; } // but one of the fields was specified/inferred as backtrace field if let Some(backtrace) = parsed_fields.backtrace { // then infer *other field* as source field let source = (backtrace + 1) % 2; // unless it was explicitly marked as non-source if parsed_fields.data.infos[source].info.source != Some(false) { return Some(source); } } None } fn parse_fields_impl<'input, 'state, P>( state: &'state State<'input>, is_valid_default_field_for_attr: P, ) -> Result> where P: Fn(&str, &syn::Field, usize) -> bool, { let MultiFieldData { fields, infos, .. } = state.enabled_fields_data(); let iter = fields .iter() .zip(infos.iter().map(|info| &info.info)) .enumerate() .map(|(index, (field, info))| (index, *field, info)); let source = parse_field_impl( &is_valid_default_field_for_attr, state.fields.len(), iter.clone(), "source", |info| info.source, )?; let backtrace = parse_field_impl( &is_valid_default_field_for_attr, state.fields.len(), iter.clone(), "backtrace", |info| info.backtrace, )?; let mut parsed_fields = ParsedFields::new(state.enabled_fields_data()); if let Some((index, _, _)) = source { parsed_fields.source = Some(index); } if let Some((index, _, _)) = backtrace { parsed_fields.backtrace = Some(index); } Ok(parsed_fields) } fn parse_field_impl<'a, P, V>( is_valid_default_field_for_attr: &P, len: usize, iter: impl Iterator + Clone, attr: &str, value: V, ) -> Result> where P: Fn(&str, &syn::Field, usize) -> bool, V: Fn(&MetaInfo) -> Option, { let explicit_fields = iter .clone() .filter(|(_, _, info)| 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, error_msg: &str, ) -> Result> { 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, type_params: &HashSet, ty: &syn::Type, ) { if let Some(ty) = utils::get_if_type_parameter_used_in_type(type_params, ty) { bounds.insert(ty); } } derive_more-impl-1.0.0/src/fmt/debug.rs000064400000000000000000000347431046102023000161050ustar 00000000000000//! Implementation of a [`fmt::Debug`] derive macro. //! //! [`fmt::Debug`]: std::fmt::Debug use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{parse_quote, spanned::Spanned as _, Ident}; use crate::utils::{ attr::{self, ParseMultiple as _}, Either, Spanning, }; use super::{ trait_name_to_attribute_name, ContainerAttributes, ContainsGenericsExt as _, FieldsExt as _, FmtAttribute, }; /// Expands a [`fmt::Debug`] derive macro. /// /// [`fmt::Debug`]: std::fmt::Debug pub fn expand(input: &syn::DeriveInput, _: &str) -> syn::Result { let attr_name = format_ident!("{}", trait_name_to_attribute_name("Debug")); let attrs = ContainerAttributes::parse_attrs(&input.attrs, &attr_name)? .map(Spanning::into_inner) .unwrap_or_default(); let ident = &input.ident; let type_params = input .generics .params .iter() .filter_map(|p| match p { syn::GenericParam::Type(t) => Some(&t.ident), syn::GenericParam::Const(..) | syn::GenericParam::Lifetime(..) => None, }) .collect::>(); let (bounds, body) = match &input.data { syn::Data::Struct(s) => { expand_struct(attrs, ident, s, &type_params, &attr_name) } syn::Data::Enum(e) => expand_enum(attrs, e, &type_params, &attr_name), syn::Data::Union(_) => { return Err(syn::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 derive_more::Debug for #ident #ty_gens #where_clause { #[inline] fn fmt( &self, __derive_more_f: &mut derive_more::core::fmt::Formatter<'_> ) -> derive_more::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, type_params: &[&syn::Ident], attr_name: &syn::Ident, ) -> syn::Result<(Vec, TokenStream)> { let s = Expansion { attr: &attrs, fields: &s.fields, type_params, ident, attr_name, }; s.validate_attrs()?; 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( mut attrs: ContainerAttributes, e: &syn::DataEnum, type_params: &[&syn::Ident], attr_name: &syn::Ident, ) -> syn::Result<(Vec, TokenStream)> { if let Some(enum_fmt) = attrs.fmt.as_ref() { return Err(syn::Error::new_spanned( enum_fmt, format!( "`#[{attr_name}(\"...\", ...)]` attribute is not allowed on enum, place it on its \ variants instead", ), )); } let (bounds, match_arms) = e.variants.iter().try_fold( (Vec::new(), TokenStream::new()), |(mut bounds, mut arms), variant| { let ident = &variant.ident; attrs.fmt = variant .attrs .iter() .filter(|attr| attr.path().is_ident("debug")) .try_fold(None, |mut attrs, attr| { let attr = attr.parse_args::()?; attrs.replace(attr).map_or(Ok(()), |dup| { Err(syn::Error::new( dup.span(), format!( "multiple `#[{attr_name}(\"...\", ...)]` attributes aren't allowed", ), )) })?; Ok::<_, syn::Error>(attrs) })?; let v = Expansion { attr: &attrs, fields: &variant.fields, type_params, ident, attr_name, }; v.validate_attrs()?; 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)) } /// Representation of a [`fmt::Debug`] derive macro field attribute. /// /// ```rust,ignore /// #[debug(skip)] /// #[debug("", )] /// ``` /// /// [`fmt::Debug`]: std::fmt::Debug type FieldAttribute = Either; /// 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, /// Type parameters in this struct or enum. type_params: &'a [&'a syn::Ident], /// Name of the attributes, considered by this macro. attr_name: &'a syn::Ident, } impl<'a> Expansion<'a> { /// Validates attributes of this [`Expansion`] to be consistent. fn validate_attrs(&self) -> syn::Result<()> { if self.attr.fmt.is_some() { for field_attr in self .fields .iter() .map(|f| FieldAttribute::parse_attrs(&f.attrs, self.attr_name)) { if let Some(FieldAttribute::Right(fmt_attr)) = field_attr?.map(Spanning::into_inner) { return Err(syn::Error::new_spanned( fmt_attr, "`#[debug(...)]` attributes are not allowed on fields when \ `#[debug(\"...\", ...)]` is specified on struct or variant", )); } } } Ok(()) } /// Generates [`Debug::fmt()`] implementation for a struct or an enum variant. /// /// [`Debug::fmt()`]: std::fmt::Debug::fmt() fn generate_body(&self) -> syn::Result { if let Some(fmt) = &self.attr.fmt { return Ok(if let Some((expr, trait_ident)) = fmt.transparent_call() { let expr = if self.fields.fmt_args_idents().any(|field| expr == field) { quote! { #expr } } else { quote! { &(#expr) } }; quote! { derive_more::core::fmt::#trait_ident::fmt(#expr, __derive_more_f) } } else { let deref_args = fmt.additional_deref_args(self.fields); quote! { derive_more::core::write!(__derive_more_f, #fmt, #(#deref_args),*) } }); }; match self.fields { syn::Fields::Unit => { let ident = self.ident.to_string(); Ok(quote! { derive_more::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, self.attr_name, )? .map(Spanning::into_inner) { Some(FieldAttribute::Left(_skip)) => { exhaustive = false; Ok::<_, syn::Error>(out) } Some(FieldAttribute::Right(fmt_attr)) => { let deref_args = fmt_attr.additional_deref_args(self.fields); Ok(quote! { derive_more::__private::DebugTuple::field( #out, &derive_more::core::format_args!(#fmt_attr, #(#deref_args),*), ) }) } 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 derive_more::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, self.attr_name)? .map(Spanning::into_inner) { Some(FieldAttribute::Left(_skip)) => { exhaustive = false; Ok::<_, syn::Error>(out) } Some(FieldAttribute::Right(fmt_attr)) => { let deref_args = fmt_attr.additional_deref_args(self.fields); Ok(quote! { derive_more::core::fmt::DebugStruct::field( #out, #field_str, &derive_more::core::format_args!( #fmt_attr, #(#deref_args),* ), ) }) } None => Ok(quote! { derive_more::core::fmt::DebugStruct::field( #out, #field_str, &#field_ident ) }), } })?; Ok(if exhaustive { quote! { derive_more::core::fmt::DebugStruct::finish(#out) } } else { quote! { derive_more::core::fmt::DebugStruct::finish_non_exhaustive(#out) } }) } } } /// Generates trait bounds for a struct or an enum variant. fn generate_bounds(&self) -> syn::Result> { let mut out = self.attr.bounds.0.clone().into_iter().collect::>(); if let Some(fmt) = self.attr.fmt.as_ref() { out.extend(fmt.bounded_types(self.fields).filter_map( |(ty, trait_name)| { if !ty.contains_generics(self.type_params) { return None; } let trait_ident = format_ident!("{trait_name}"); Some(parse_quote! { #ty: derive_more::core::fmt::#trait_ident }) }, )); Ok(out) } else { self.fields.iter().try_fold(out, |mut out, field| { let ty = &field.ty; if !ty.contains_generics(self.type_params) { return Ok(out); } match FieldAttribute::parse_attrs(&field.attrs, self.attr_name)? .map(Spanning::into_inner) { Some(FieldAttribute::Right(fmt_attr)) => { out.extend(fmt_attr.bounded_types(self.fields).map( |(ty, trait_name)| { let trait_ident = format_ident!("{trait_name}"); parse_quote! { #ty: derive_more::core::fmt::#trait_ident } }, )); } Some(FieldAttribute::Left(_skip)) => {} None => out.extend([parse_quote! { #ty: derive_more::Debug }]), } Ok(out) }) } } } derive_more-impl-1.0.0/src/fmt/display.rs000064400000000000000000000357131046102023000164620ustar 00000000000000//! Implementation of [`fmt::Display`]-like derive macros. #[cfg(doc)] use std::fmt; use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned as _}; use crate::utils::{attr::ParseMultiple as _, Spanning}; use super::{ trait_name_to_attribute_name, ContainerAttributes, ContainsGenericsExt as _, FieldsExt as _, 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 { let trait_name = normalize_trait_name(trait_name); let attr_name = format_ident!("{}", trait_name_to_attribute_name(trait_name)); let attrs = ContainerAttributes::parse_attrs(&input.attrs, &attr_name)? .map(Spanning::into_inner) .unwrap_or_default(); let trait_ident = format_ident!("{trait_name}"); let ident = &input.ident; let type_params = input .generics .params .iter() .filter_map(|p| match p { syn::GenericParam::Type(t) => Some(&t.ident), syn::GenericParam::Const(..) | syn::GenericParam::Lifetime(..) => None, }) .collect::>(); let ctx: ExpansionCtx = (&attrs, &type_params, ident, &trait_ident, &attr_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 derive_more::#trait_ident for #ident #ty_gens #where_clause { fn fmt( &self, __derive_more_f: &mut derive_more::core::fmt::Formatter<'_> ) -> derive_more::core::fmt::Result { #body } } }) } /// Type alias for an expansion context: /// - [`ContainerAttributes`]. /// - Type parameters. Slice of [`syn::Ident`]. /// - Struct/enum/union [`syn::Ident`]. /// - Derived trait [`syn::Ident`]. /// - Attribute name [`syn::Ident`]. /// /// [`syn::Ident`]: struct@syn::Ident type ExpansionCtx<'a> = ( &'a ContainerAttributes, &'a [&'a syn::Ident], &'a syn::Ident, &'a syn::Ident, &'a syn::Ident, ); /// Expands a [`fmt::Display`]-like derive macro for the provided struct. fn expand_struct( s: &syn::DataStruct, (attrs, type_params, ident, trait_ident, _): ExpansionCtx<'_>, ) -> syn::Result<(Vec, TokenStream)> { let s = Expansion { shared_attr: None, attrs, fields: &s.fields, type_params, 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, (container_attrs, type_params, _, trait_ident, attr_name): ExpansionCtx<'_>, ) -> syn::Result<(Vec, TokenStream)> { if let Some(shared_fmt) = &container_attrs.fmt { if shared_fmt .placeholders_by_arg("_variant") .any(|p| p.has_modifiers || p.trait_name != "Display") { // TODO: This limitation can be lifted, by analyzing the `shared_fmt` deeper and using // `&dyn fmt::TraitName` for transparency instead of just `format_args!()` in the // expansion. return Err(syn::Error::new( shared_fmt.span(), "shared format `_variant` placeholder cannot contain format specifiers", )); } } let (bounds, match_arms) = e.variants.iter().try_fold( (Vec::new(), TokenStream::new()), |(mut bounds, mut arms), variant| { let attrs = ContainerAttributes::parse_attrs(&variant.attrs, attr_name)? .map(Spanning::into_inner) .unwrap_or_default(); let ident = &variant.ident; if attrs.fmt.is_none() && variant.fields.is_empty() && attr_name != "display" { return Err(syn::Error::new( e.variants.span(), format!( "implicit formatting of unit enum variant is supported only for `Display` \ macro, use `#[{attr_name}(\"...\")]` to explicitly specify the formatting", ), )); } let v = Expansion { shared_attr: container_attrs.fmt.as_ref(), attrs: &attrs, fields: &variant.fields, type_params, 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, _, _, _, attr_name): ExpansionCtx<'_>, ) -> syn::Result<(Vec, TokenStream)> { let fmt = &attrs.fmt.as_ref().ok_or_else(|| { syn::Error::new( u.fields.span(), format!("unions must have `#[{attr_name}(\"...\", ...)]` attribute"), ) })?; Ok(( attrs.bounds.0.clone().into_iter().collect(), quote! { derive_more::core::write!(__derive_more_f, #fmt) }, )) } /// 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> { /// [`FmtAttribute`] shared between all variants of an enum. /// /// [`None`] for a struct. shared_attr: Option<&'a FmtAttribute>, /// Derive macro [`ContainerAttributes`]. attrs: &'a ContainerAttributes, /// Struct or enum [`syn::Ident`]. /// /// [`syn::Ident`]: struct@syn::Ident ident: &'a syn::Ident, /// Struct or enum [`syn::Fields`]. fields: &'a syn::Fields, /// Type parameters in this struct or enum. type_params: &'a [&'a syn::Ident], /// [`fmt`] trait [`syn::Ident`]. /// /// [`syn::Ident`]: struct@syn::Ident trait_ident: &'a syn::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 { let mut body = TokenStream::new(); // If `shared_attr` is a transparent call, then we consider it being absent. let has_shared_attr = self .shared_attr .map_or(false, |a| a.transparent_call().is_none()); if !has_shared_attr || self .shared_attr .map_or(true, |a| a.contains_arg("_variant")) { body = match &self.attrs.fmt { Some(fmt) => { if has_shared_attr { let deref_args = fmt.additional_deref_args(self.fields); quote! { &derive_more::core::format_args!(#fmt, #(#deref_args),*) } } else if let Some((expr, trait_ident)) = fmt.transparent_call() { let expr = if self.fields.fmt_args_idents().any(|field| expr == field) { quote! { #expr } } else { quote! { &(#expr) } }; quote! { derive_more::core::fmt::#trait_ident::fmt(#expr, __derive_more_f) } } else { let deref_args = fmt.additional_deref_args(self.fields); quote! { derive_more::core::write!(__derive_more_f, #fmt, #(#deref_args),*) } } } None if self.fields.is_empty() => { let ident_str = self.ident.unraw().to_string(); if has_shared_attr { quote! { #ident_str } } else { quote! { __derive_more_f.write_str(#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; if has_shared_attr { let placeholder = trait_name_to_default_placeholder_literal(trait_ident); quote! { &derive_more::core::format_args!(#placeholder, #ident) } } else { quote! { derive_more::core::fmt::#trait_ident::fmt(#ident, __derive_more_f) } } } _ => { return 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), ), )) } }; } if has_shared_attr { if let Some(shared_fmt) = &self.shared_attr { let deref_args = shared_fmt.additional_deref_args(self.fields); let shared_body = quote! { derive_more::core::write!(__derive_more_f, #shared_fmt, #(#deref_args),*) }; body = if body.is_empty() { shared_body } else { quote! { match #body { _variant => #shared_body } } } } } Ok(body) } /// Generates trait bounds for a struct or an enum variant. fn generate_bounds(&self) -> Vec { let mut bounds = vec![]; if self .shared_attr .map_or(true, |a| a.contains_arg("_variant")) { if let Some(fmt) = &self.attrs.fmt { bounds.extend( fmt.bounded_types(self.fields) .filter_map(|(ty, trait_name)| { if !ty.contains_generics(self.type_params) { return None; } let trait_ident = format_ident!("{trait_name}"); Some(parse_quote! { #ty: derive_more::core::fmt::#trait_ident }) }) .chain(self.attrs.bounds.0.clone()), ); } else { bounds.extend(self.fields.iter().next().and_then(|f| { let ty = &f.ty; if !ty.contains_generics(self.type_params) { return None; } let trait_ident = &self.trait_ident; Some(parse_quote! { #ty: derive_more::core::fmt::#trait_ident }) })); }; } if let Some(shared_fmt) = &self.shared_attr { bounds.extend(shared_fmt.bounded_types(self.fields).filter_map( |(ty, trait_name)| { if !ty.contains_generics(self.type_params) { return None; } let trait_ident = format_ident!("{trait_name}"); Some(parse_quote! { #ty: derive_more::core::fmt::#trait_ident }) }, )); } bounds } } /// 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!(), } } /// Matches the provided [`fmt`] trait `name` to its default formatting placeholder. fn trait_name_to_default_placeholder_literal(name: &syn::Ident) -> &'static str { match () { _ if name == "Binary" => "{:b}", _ if name == "Debug" => "{:?}", _ if name == "Display" => "{}", _ if name == "LowerExp" => "{:e}", _ if name == "LowerHex" => "{:x}", _ if name == "Octal" => "{:o}", _ if name == "Pointer" => "{:p}", _ if name == "UpperExp" => "{:E}", _ if name == "UpperHex" => "{:X}", _ => unimplemented!(), } } derive_more-impl-1.0.0/src/fmt/mod.rs000064400000000000000000000656301046102023000155750ustar 00000000000000//! 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::{format_ident, quote, ToTokens}; use syn::{ parse::{Parse, ParseStream}, punctuated::Punctuated, spanned::Spanned as _, token, }; use crate::{ parsing::Expr, utils::{attr, Either, Spanning}, }; /// Representation of a `bound` macro attribute, expressing additional trait bounds. /// /// ```rust,ignore /// #[(bound())] /// #[(bounds())] /// #[(where())] /// ``` #[derive(Debug, Default)] struct BoundsAttribute(Punctuated); impl Parse for BoundsAttribute { fn parse(input: ParseStream<'_>) -> syn::Result { Self::check_legacy_fmt(input)?; let _ = input.parse::().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 argument, expected `bound(...)`", )) } })?; let content; syn::parenthesized!(content in input); content .parse_terminated(syn::WherePredicate::parse, token::Comma) .map(Self) } } 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::() .and_then(|path| fork.parse::().map(|_| path)); match path { Ok(path) if path.is_ident("bound") => fork .parse::() .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(()), } } } /// Representation of a [`fmt`]-like attribute. /// /// ```rust,ignore /// #[("", )] /// ``` /// /// [`fmt`]: std::fmt #[derive(Debug)] struct FmtAttribute { /// Interpolation [`syn::LitStr`]. /// /// [`syn::LitStr`]: struct@syn::LitStr lit: syn::LitStr, /// Optional [`token::Comma`]. /// /// [`token::Comma`]: struct@token::Comma comma: Option, /// Interpolation arguments. args: Punctuated, } impl Parse for FmtAttribute { fn parse(input: ParseStream<'_>) -> syn::Result { Self::check_legacy_fmt(input)?; let mut parsed = Self { lit: input.parse()?, comma: input .peek(token::Comma) .then(|| input.parse()) .transpose()?, args: input.parse_terminated(FmtArgument::parse, token::Comma)?, }; parsed.args.pop_punct(); Ok(parsed) } } impl attr::ParseMultiple for FmtAttribute {} 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); } } impl FmtAttribute { /// Checks whether this [`FmtAttribute`] can be replaced with a transparent delegation (calling /// a formatting trait directly instead of interpolation syntax). /// /// If such transparent call is possible, the returns an [`Ident`] of the delegated trait and /// the [`Expr`] to pass into the call, otherwise [`None`]. /// /// [`Ident`]: struct@syn::Ident fn transparent_call(&self) -> Option<(Expr, syn::Ident)> { // `FmtAttribute` is transparent when: // (1) There is exactly one formatting parameter. let lit = self.lit.value(); let param = parsing::format(&lit).and_then(|(more, p)| more.is_empty().then_some(p))?; // (2) And the formatting parameter doesn't contain any modifiers. if param .spec .map(|s| { s.align.is_some() || s.sign.is_some() || s.alternate.is_some() || s.zero_padding.is_some() || s.width.is_some() || s.precision.is_some() || !s.ty.is_trivial() }) .unwrap_or_default() { return None; } let expr = match param.arg { // (3) And either exactly one positional argument is specified. Some(parsing::Argument::Integer(_)) | None => (self.args.len() == 1) .then(|| self.args.first()) .flatten() .map(|a| a.expr.clone()), // (4) Or the formatting parameter's name refers to some outer binding. Some(parsing::Argument::Identifier(name)) if self.args.is_empty() => { Some(format_ident!("{name}").into()) } // (5) Or exactly one named argument is specified for the formatting parameter's name. Some(parsing::Argument::Identifier(name)) => (self.args.len() == 1) .then(|| self.args.first()) .flatten() .filter(|a| a.alias.as_ref().map(|a| a.0 == name).unwrap_or_default()) .map(|a| a.expr.clone()), }?; let trait_name = param .spec .map(|s| s.ty) .unwrap_or(parsing::Type::Display) .trait_name(); Some((expr, format_ident!("{trait_name}"))) } /// Returns an [`Iterator`] over bounded [`syn::Type`]s (and correspondent trait names) by this /// [`FmtAttribute`]. fn bounded_types<'a>( &'a self, fields: &'a syn::Fields, ) -> impl Iterator { 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)) }) } #[cfg(feature = "display")] /// Checks whether this [`FmtAttribute`] contains an argument with the provided `name` (either /// in its direct [`FmtArgument`]s or inside [`Placeholder`]s). fn contains_arg(&self, name: &str) -> bool { self.placeholders_by_arg(name).next().is_some() } #[cfg(feature = "display")] /// Returns an [`Iterator`] over [`Placeholder`]s using an argument with the provided `name` /// (either in its direct [`FmtArgument`]s of this [`FmtAttribute`] or inside the /// [`Placeholder`] itself). fn placeholders_by_arg<'a>( &'a self, name: &'a str, ) -> impl Iterator + 'a { let placeholders = Placeholder::parse_fmt_string(&self.lit.value()); placeholders.into_iter().filter(move |placeholder| { match &placeholder.arg { Parameter::Named(name) => self .args .iter() .find_map(|a| (a.alias()? == name).then_some(&a.expr)) .map_or(Some(name.clone()), |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())) .map(ToString::to_string), } .as_deref() == Some(name) }) } /// Returns an [`Iterator`] over the additional formatting arguments doing the dereferencing /// replacement in this [`FmtAttribute`] for those [`Placeholder`] representing the provided /// [`syn::Fields`] and requiring it fn additional_deref_args<'fmt: 'ret, 'fields: 'ret, 'ret>( &'fmt self, fields: &'fields syn::Fields, ) -> impl Iterator + 'ret { let used_args = Placeholder::parse_fmt_string(&self.lit.value()) .into_iter() .filter_map(|placeholder| match placeholder.arg { Parameter::Named(name) => Some(name), _ => None, }) .collect::>(); fields.fmt_args_idents().filter_map(move |field_name| { (used_args.iter().any(|arg| field_name == arg) && !self.args.iter().any(|arg| { arg.alias.as_ref().map_or(false, |(n, _)| n == &field_name) })) .then(|| quote! { #field_name = *#field_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::() .and_then(|path| fork.parse::().map(|_| path)); match path { Ok(path) if path.is_ident("fmt") => (|| { let args = fork .parse_terminated( >::parse, token::Comma, ) .ok()? .into_iter() .enumerate() .filter_map(|(i, arg)| match arg { Either::Left(syn::Lit::Str(str)) => Some(if i == 0 { format!("\"{}\"", str.value()) } else { str.value() }), Either::Right(ident) => Some(ident.to_string()), _ => None, }) .collect::>(); (!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(()), } } } /// Representation of a [named parameter][1] (`identifier '=' expression`) in a [`FmtAttribute`]. /// /// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#named-parameters #[derive(Debug)] struct FmtArgument { /// `identifier =` [`Ident`]. /// /// [`Ident`]: struct@syn::Ident alias: Option<(syn::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<&syn::Ident> { self.alias.as_ref().map(|(ident, _)| ident) } } impl Parse for FmtArgument { fn parse(input: ParseStream) -> syn::Result { Ok(Self { alias: (input.peek(syn::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> 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, Eq, PartialEq)] struct Placeholder { /// Formatting argument (either named or positional) to be used by this [`Placeholder`]. arg: Parameter, /// Indicator whether this [`Placeholder`] has any formatting modifiers. has_modifiers: bool, /// 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 { 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, has_modifiers: format .spec .map(|s| { s.align.is_some() || s.sign.is_some() || s.alternate.is_some() || s.zero_padding.is_some() || s.width.is_some() || s.precision.is_some() || !s.ty.is_trivial() }) .unwrap_or_default(), trait_name: ty.trait_name(), } }) .collect() } } /// Representation of a [`fmt::Display`]-like derive macro attributes placed on a container (struct /// or enum variant). /// /// ```rust,ignore /// #[("", )] /// #[(bound())] /// ``` /// /// `#[(...)]` can be specified only once, while multiple `#[(bound(...))]` /// are allowed. /// /// [`fmt::Display`]: std::fmt::Display #[derive(Debug, Default)] struct ContainerAttributes { /// Interpolation [`FmtAttribute`]. fmt: Option, /// Addition trait bounds. bounds: BoundsAttribute, } impl Parse for ContainerAttributes { fn parse(input: ParseStream<'_>) -> syn::Result { // We do check `FmtAttribute::check_legacy_fmt` eagerly here, because `Either` will swallow // any error of the `Either::Left` if the `Either::Right` succeeds. FmtAttribute::check_legacy_fmt(input)?; >::parse(input).map(|v| match v { Either::Left(fmt) => Self { bounds: BoundsAttribute::default(), fmt: Some(fmt), }, Either::Right(bounds) => Self { bounds, fmt: None }, }) } } impl attr::ParseMultiple for ContainerAttributes { fn merge_attrs( prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { let Spanning { span: prev_span, item: mut prev, } = prev; let Spanning { span: new_span, item: new, } = new; if new.fmt.and_then(|n| prev.fmt.replace(n)).is_some() { return Err(syn::Error::new( new_span, format!("multiple `#[{name}(\"...\", ...)]` attributes aren't allowed"), )); } prev.bounds.0.extend(new.bounds.0); Ok(Spanning::new( prev, prev_span.join(new_span).unwrap_or(prev_span), )) } } /// Matches the provided `trait_name` to appropriate [`FmtAttribute`]'s argument name. fn trait_name_to_attribute_name(trait_name: T) -> &'static str where T: for<'a> PartialEq<&'a str>, { match () { _ if trait_name == "Binary" => "binary", _ if trait_name == "Debug" => "debug", _ 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!(), } } /// Extension of a [`syn::Type`] and a [`syn::Path`] allowing to travers its type parameters. trait ContainsGenericsExt { /// Checks whether this definition contains any of the provided `type_params`. fn contains_generics(&self, type_params: &[&syn::Ident]) -> bool; } impl ContainsGenericsExt for syn::Type { fn contains_generics(&self, type_params: &[&syn::Ident]) -> bool { if type_params.is_empty() { return false; } match self { Self::Path(syn::TypePath { qself, path }) => { if let Some(qself) = qself { if qself.ty.contains_generics(type_params) { return true; } } if let Some(ident) = path.get_ident() { type_params.iter().any(|param| *param == ident) } else { path.contains_generics(type_params) } } Self::Array(syn::TypeArray { elem, .. }) | Self::Group(syn::TypeGroup { elem, .. }) | Self::Paren(syn::TypeParen { elem, .. }) | Self::Ptr(syn::TypePtr { elem, .. }) | Self::Reference(syn::TypeReference { elem, .. }) | Self::Slice(syn::TypeSlice { elem, .. }) => { elem.contains_generics(type_params) } Self::BareFn(syn::TypeBareFn { inputs, output, .. }) => { inputs .iter() .any(|arg| arg.ty.contains_generics(type_params)) || match output { syn::ReturnType::Default => false, syn::ReturnType::Type(_, ty) => { ty.contains_generics(type_params) } } } Self::Tuple(syn::TypeTuple { elems, .. }) => { elems.iter().any(|ty| ty.contains_generics(type_params)) } Self::TraitObject(syn::TypeTraitObject { bounds, .. }) => { bounds.iter().any(|bound| match bound { syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) => { path.contains_generics(type_params) } syn::TypeParamBound::Lifetime(..) | syn::TypeParamBound::Verbatim(..) => false, _ => unimplemented!( "syntax is not supported by `derive_more`, please report a bug", ), }) } Self::ImplTrait(..) | Self::Infer(..) | Self::Macro(..) | Self::Never(..) | Self::Verbatim(..) => false, _ => unimplemented!( "syntax is not supported by `derive_more`, please report a bug", ), } } } impl ContainsGenericsExt for syn::Path { fn contains_generics(&self, type_params: &[&syn::Ident]) -> bool { if type_params.is_empty() { return false; } self.segments .iter() .any(|segment| match &segment.arguments { syn::PathArguments::None => false, syn::PathArguments::AngleBracketed( syn::AngleBracketedGenericArguments { args, .. }, ) => args.iter().any(|generic| match generic { syn::GenericArgument::Type(ty) | syn::GenericArgument::AssocType(syn::AssocType { ty, .. }) => { ty.contains_generics(type_params) } syn::GenericArgument::Lifetime(..) | syn::GenericArgument::Const(..) | syn::GenericArgument::AssocConst(..) | syn::GenericArgument::Constraint(..) => false, _ => unimplemented!( "syntax is not supported by `derive_more`, please report a bug", ), }), syn::PathArguments::Parenthesized( syn::ParenthesizedGenericArguments { inputs, output, .. }, ) => { inputs.iter().any(|ty| ty.contains_generics(type_params)) || match output { syn::ReturnType::Default => false, syn::ReturnType::Type(_, ty) => { ty.contains_generics(type_params) } } } }) } } /// Extension of [`syn::Fields`] providing helpers for a [`FmtAttribute`]. trait FieldsExt { /// Returns an [`Iterator`] over [`syn::Ident`]s representing these [`syn::Fields`] in a /// [`FmtAttribute`] as [`FmtArgument`]s or named [`Placeholder`]s. /// /// [`syn::Ident`]: struct@syn::Ident fn fmt_args_idents(&self) -> impl Iterator + '_; } impl FieldsExt for syn::Fields { fn fmt_args_idents(&self) -> impl Iterator + '_ { self.iter() .enumerate() .map(|(i, f)| f.ident.clone().unwrap_or_else(|| format_ident!("_{i}"))) } } #[cfg(test)] mod fmt_attribute_spec { use itertools::Itertools as _; use quote::ToTokens; use super::FmtAttribute; fn assert<'a>(input: &'a str, parsed: impl AsRef<[&'a str]>) { let parsed = parsed.as_ref(); let attr = syn::parse_str::(&format!("\"\", {}", input)).unwrap(); let fmt_args = attr .args .into_iter() .map(|arg| arg.into_token_stream().to_string()) .collect::>(); 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), has_modifiers: false, trait_name: "Display", }, Placeholder { arg: Parameter::Positional(1), has_modifiers: false, trait_name: "Debug", }, Placeholder { arg: Parameter::Positional(1), has_modifiers: true, trait_name: "Display", }, Placeholder { arg: Parameter::Positional(2), has_modifiers: true, trait_name: "LowerHex", }, Placeholder { arg: Parameter::Named("par".to_owned()), has_modifiers: true, trait_name: "Debug", }, Placeholder { arg: Parameter::Positional(2), has_modifiers: true, trait_name: "Display", }, ], ); } } derive_more-impl-1.0.0/src/fmt/parsing.rs000064400000000000000000001127141046102023000164550ustar 00000000000000//! Parsing of [Rust `fmt` syntax][0]. //! //! [0]: std::fmt#syntax use std::iter; use unicode_xid::UnicodeXID as XID; /// Output of the [`format_string`] parser. #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct FormatString<'a> { pub(crate) formats: Vec>, } /// Output of the [`format`] parser. /// /// [`format`]: fn@format #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub(crate) struct Format<'a> { pub(crate) arg: Option>, pub(crate) spec: Option>, } /// Output of the [`format_spec`] parser. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) struct FormatSpec<'a> { /// Parsed `[[fill]`[`align`]`]`. pub(crate) align: Option<(Option, Align)>, /// Parsed `[`[`sign`]`]`. pub(crate) sign: Option, /// Parsed `['#']` (alternation). pub(crate) alternate: Option, /// Parsed `['0']` (padding with zeros). pub(crate) zero_padding: Option, /// Parsed `[width]`. pub(crate) width: Option>, /// Parsed `['.' `[`precision`]`]`. pub(crate) precision: Option>, /// Parsed [`type`]. /// /// [`type`]: type_ pub(crate) ty: Type, } /// Output of the [`argument`] parser. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum Argument<'a> { Integer(usize), Identifier(&'a str), } /// Output of the [`align`] parser. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum Align { Left, Center, Right, } /// Output of the [`sign`] parser. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum Sign { Plus, Minus, } /// Type for the [`FormatSpec::alternate`]. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) struct Alternate; /// Type for the [`FormatSpec::zero_padding`]. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) struct ZeroPadding; /// Output of the [`precision`] parser. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum Precision<'a> { Count(Count<'a>), Star, } /// Output of the [`count`] parser. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum Count<'a> { Integer(usize), Parameter(Parameter<'a>), } /// Output of the [`type_`] parser. See [formatting traits][0] for more info. /// /// [0]: std::fmt#formatting-traits #[derive(Clone, Copy, Debug, 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 { Self::Display => "Display", Self::Debug | Self::LowerDebug | Self::UpperDebug => "Debug", Self::Octal => "Octal", Self::LowerHex => "LowerHex", Self::UpperHex => "UpperHex", Self::Pointer => "Pointer", Self::Binary => "Binary", Self::LowerExp => "LowerExp", Self::UpperExp => "UpperExp", } } /// Indicates whether this [`Type`] represents a trivial trait call without any modifications. pub(crate) fn is_trivial(&self) -> bool { match self { Self::Display | Self::Debug | Self::Octal | Self::LowerHex | Self::UpperHex | Self::Pointer | Self::Binary | Self::LowerExp | Self::UpperExp => true, Self::LowerDebug | Self::UpperDebug => false, } } } /// Type alias for the `fill` in the [`FormatSpec::align`]. type Fill = char; /// Type alias for the [`FormatSpec::width`]. type Width<'a> = Count<'a>; /// Output of the [`maybe_format`] parser. type MaybeFormat<'a> = Option>; /// 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][0]. /// /// # 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). /// /// [0]: std::fmt#syntax pub(crate) fn format_string(input: &str) -> Option> { 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][0]. /// /// # Grammar /// /// [`maybe_format`]` := '{' '{' | '}' '}' | `[`format`] /// /// # Example /// /// ```text /// {{ /// }} /// {:04} /// {:#?} /// {par:-^#.0$?} /// ``` /// /// [`format`]: fn@format /// [0]: std::fmt#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][0]. /// /// # Grammar /// /// [`format`]` := '{' [`[`argument`]`] [':' `[`format_spec`]`] '}'` /// /// # Example /// /// ```text /// {par} /// {:#?} /// {par:-^#.0$?} /// ``` /// /// [`format`]: fn@format /// [0]: std::fmt#syntax pub(crate) 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][0]. /// /// # Grammar /// /// [`argument`]` := `[`integer`]` | `[`identifier`] /// /// # Example /// /// ```text /// 0 /// ident /// Минск /// ``` /// /// [0]: std::fmt#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][0]. /// /// # Grammar /// /// [`format_spec`]` := [[fill]`[`align`]`][`[`sign`]`]['#']['0'][width]` /// `['.' `[`precision`]`]`[`type`] /// /// # Example /// /// ```text /// ^ /// <^ /// ->+#0width$.precision$x? /// ``` /// /// [`type`]: type_ /// [0]: std::fmt#syntax fn format_spec(input: &str) -> Option<(LeftToParse<'_>, FormatSpec<'_>)> { let (input, align) = optional_result(alt(&mut [ &mut and_then(take_any_char, |(i, fill)| { map(align, |(i, align)| (i, (Some(fill), align)))(i) }), &mut map(align, |(i, align)| (i, (None, align))), ]))(input); let (input, sign) = optional_result(sign)(input); let (input, alternate) = optional_result(map(char('#'), |i| (i, Alternate)))(input); let (input, zero_padding) = optional_result(map( try_seq(&mut [ &mut char('0'), &mut lookahead(check_char(|c| !matches!(c, '$'))), ]), |i| (i, ZeroPadding), ))(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 { align, sign, alternate, zero_padding, width, precision, ty, }, )) } /// Parses an `align` as defined in the [grammar spec][0]. /// /// # Grammar /// /// [`align`]` := '<' | '^' | '>'` /// /// # Example /// /// ```text /// < /// ^ /// > /// ``` /// /// [0]: std::fmt#syntax fn align(input: &str) -> Option<(LeftToParse<'_>, Align)> { alt(&mut [ &mut map(char('<'), |i| (i, Align::Left)), &mut map(char('^'), |i| (i, Align::Center)), &mut map(char('>'), |i| (i, Align::Right)), ])(input) } /// Parses a `sign` as defined in the [grammar spec][0]. /// /// # Grammar /// /// [`sign`]` := '+' | '-'` /// /// # Example /// /// ```text /// + /// - /// ``` /// /// [0]: std::fmt#syntax fn sign(input: &str) -> Option<(LeftToParse<'_>, Sign)> { alt(&mut [ &mut map(char('+'), |i| (i, Sign::Plus)), &mut map(char('-'), |i| (i, Sign::Minus)), ])(input) } /// Parses a `precision` as defined in the [grammar spec][0]. /// /// # Grammar /// /// [`precision`]` := `[`count`]` | '*'` /// /// # Example /// /// ```text /// 0 /// 42$ /// par$ /// * /// ``` /// /// [0]: std::fmt#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][0]. /// /// # Grammar /// /// [`type`]` := '' | '?' | 'x?' | 'X?' | identifier` /// /// # Example /// /// All possible [`Type`]s. /// /// ```text /// ? /// x? /// X? /// o /// x /// X /// p /// b /// e /// E /// ``` /// /// [`type`]: type_ /// [0]: std::fmt#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][0]. /// /// # Grammar /// /// [`count`]` := `[`parameter`]` | `[`integer`] /// /// # Example /// /// ```text /// 0 /// 42$ /// par$ /// ``` /// /// [0]: std::fmt#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][0]. /// /// # Grammar /// /// [`parameter`]` := `[`argument`]` '$'` /// /// # Example /// /// ```text /// 42$ /// par$ /// ``` /// /// [0]: std::fmt#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][0]. /// /// # Grammar /// /// `IDENTIFIER_OR_KEYWORD : XID_Start XID_Continue* | _ XID_Continue+` /// /// See [rust reference][2] for more info. /// /// # Example /// /// ```text /// identifier /// Минск /// ``` /// /// [0]: std::fmt#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][0]. /// /// [0]: std::fmt#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][0]. /// /// [0]: std::fmt#syntax fn text(input: &str) -> Option<(LeftToParse<'_>, &str)> { take_until1(any_char, one_of("{}"))(input) } 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> + '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], ) -> impl FnMut(&'i str) -> Option + '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, mut f: impl FnMut(I) -> O, ) -> impl FnMut(&'i str) -> Option { 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, 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 [`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, mut f: impl FnMut(I) -> Option, ) -> impl FnMut(&'i str) -> Option { 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> { move |input| map(&mut parser, |_| input)(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) { 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> + '_ { 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> { 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> { 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> + '_ { move |input: &str| chars.chars().find_map(|c| char(c)(input)) } /// Parses any [`char`]. /// /// [`char`]: fn@char fn any_char(input: &str) -> Option> { input.chars().next().map(|c| &input[c.len_utf8()..]) } /// Parses any [`char`] and returns it. /// /// [`char`]: fn@char fn take_any_char(input: &str) -> Option<(LeftToParse<'_>, char)> { input.chars().next().map(|c| (&input[c.len_utf8()..], c)) } #[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 { align: None, sign: None, alternate: None, zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:^}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((None, Align::Center)), sign: None, alternate: None, zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:-<}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some('-'), Align::Left)), sign: None, alternate: None, zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{: <}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some(' '), Align::Left)), sign: None, alternate: None, zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:^<}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some('^'), Align::Left)), sign: None, alternate: None, zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:+}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: Some(Sign::Plus), alternate: None, zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:^<-}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some('^'), Align::Left)), sign: Some(Sign::Minus), alternate: None, zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:#}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: None, alternate: Some(Alternate), zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:+#}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: Some(Sign::Plus), alternate: Some(Alternate), zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:-<#}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some('-'), Align::Left)), sign: None, alternate: Some(Alternate), zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:^<-#}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some('^'), Align::Left)), sign: Some(Sign::Minus), alternate: Some(Alternate), zero_padding: None, width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:0}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: None, alternate: None, zero_padding: Some(ZeroPadding), width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:#0}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: None, alternate: Some(Alternate), zero_padding: Some(ZeroPadding), width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:-0}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: Some(Sign::Minus), alternate: None, zero_padding: Some(ZeroPadding), width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:^<0}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some('^'), Align::Left)), sign: None, alternate: None, zero_padding: Some(ZeroPadding), width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:^<+#0}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some('^'), Align::Left)), sign: Some(Sign::Plus), alternate: Some(Alternate), zero_padding: Some(ZeroPadding), width: None, precision: None, ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:1}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: None, alternate: None, zero_padding: None, 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 { align: None, sign: None, alternate: None, zero_padding: None, 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 { align: None, sign: None, alternate: None, zero_padding: None, 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 { align: Some((Some('-'), Align::Center)), sign: Some(Sign::Minus), alternate: Some(Alternate), zero_padding: Some(ZeroPadding), 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 { align: None, sign: None, alternate: None, zero_padding: None, width: None, precision: Some(Precision::Star), ty: Type::Display, }), }], }), ); assert_eq!( format_string("{:.0}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: None, alternate: None, zero_padding: None, 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 { align: None, sign: None, alternate: None, zero_padding: None, 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 { align: None, sign: None, alternate: None, zero_padding: None, 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 { align: Some((Some(' '), Align::Right)), sign: Some(Sign::Plus), alternate: Some(Alternate), zero_padding: None, 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 { align: None, sign: None, alternate: None, zero_padding: None, width: None, precision: None, ty: Type::LowerDebug, }), }], }), ); assert_eq!( format_string("{:E}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: None, sign: None, alternate: None, zero_padding: None, width: None, precision: None, ty: Type::UpperExp, }), }], }), ); assert_eq!( format_string("{: >+#par$.par$X?}"), Some(FormatString { formats: vec![Format { arg: None, spec: Some(FormatSpec { align: Some((Some(' '), Align::Right)), sign: Some(Sign::Plus), alternate: Some(Alternate), zero_padding: None, 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 { align: None, sign: None, alternate: Some(Alternate), zero_padding: None, width: None, precision: None, ty: Type::Debug, }), }, Format { arg: Some(Argument::Identifier("par")), spec: Some(FormatSpec { align: Some((Some('-'), Align::Center)), sign: None, alternate: None, zero_padding: None, 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); } } derive_more-impl-1.0.0/src/from.rs000064400000000000000000000325751046102023000151750ustar 00000000000000//! Implementation of a [`From`] derive macro. use std::{ any::{Any, TypeId}, iter, }; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, ToTokens as _, TokenStreamExt as _}; use syn::{ parse::{Parse, ParseStream}, parse_quote, spanned::Spanned as _, token, }; use crate::utils::{ attr::{self, ParseMultiple as _}, polyfill, Either, Spanning, }; /// Expands a [`From`] derive macro. pub fn expand(input: &syn::DeriveInput, _: &'static str) -> syn::Result { let attr_name = format_ident!("from"); match &input.data { syn::Data::Struct(data) => Expansion { attrs: StructAttribute::parse_attrs_with( &input.attrs, &attr_name, &ConsiderLegacySyntax { fields: &data.fields, }, )? .map(|attr| attr.into_inner().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 attr = VariantAttribute::parse_attrs_with( &variant.attrs, &attr_name, &ConsiderLegacySyntax { fields: &variant.fields, }, )? .map(Spanning::into_inner); if matches!( attr, Some( VariantAttribute::Empty(_) | VariantAttribute::Types(_) | VariantAttribute::Forward(_) ), ) { has_explicit_from = true; } Ok(attr) }) .collect::>>()?; 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(forward)] /// #[from()] /// ``` type StructAttribute = attr::Conversion; /// Representation of a [`From`] derive macro enum variant attribute. /// /// ```rust,ignore /// #[from] /// #[from(skip)] #[from(ignore)] /// #[from(forward)] /// #[from()] /// ``` type VariantAttribute = attr::FieldConversion; /// 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 [`syn::Ident`]. /// /// [`syn::Ident`]: struct@syn::Ident ident: &'a syn::Ident, /// Variant [`syn::Ident`] in case of enum expansion. /// /// [`syn::Ident`]: struct@syn::Ident variant: Option<&'a syn::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::Empty`], [`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 { use crate::utils::FieldsExt as _; let ident = self.ident; let field_tys = self.fields.iter().map(|f| &f.ty).collect::>(); 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.0.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 derive_more::From<#from_ty>>::from( value #( .#index )* ), } }); Ok(quote! { #[automatically_derived] impl #impl_gens derive_more::From<#ty> for #ident #ty_gens #where_clause { #[inline] fn from(value: #ty) -> Self { #ident #( :: #variant )* #init } } }) }) .collect() } (Some(VariantAttribute::Empty(_)), _) | (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 derive_more::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 derive_more::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: derive_more::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 derive_more::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`]. /// /// [`token::Brace`]: struct@token::Brace /// [`token::Paren`]: struct@token::Paren fn expand_fields( &self, mut wrap: impl FnMut( Option<&syn::Ident>, &syn::Type, Option, ) -> 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() } } /// [`attr::Parser`] considering legacy syntax for [`attr::Types`] and emitting [`legacy_error`], if /// any occurs. struct ConsiderLegacySyntax<'a> { /// [`syn::Fields`] of a struct or enum variant, the attribute is parsed for. fields: &'a syn::Fields, } impl attr::Parser for ConsiderLegacySyntax<'_> { fn parse(&self, input: ParseStream<'_>) -> syn::Result { if TypeId::of::() == TypeId::of::() { let ahead = input.fork(); if let Ok(p) = ahead.parse::() { if p.is_ident("types") { return legacy_error(&ahead, input.span(), self.fields); } } } T::parse(input) } } /// Constructs a [`syn::Error`] for legacy syntax: `#[from(types(i32, "&str"))]`. fn legacy_error( tokens: ParseStream<'_>, span: Span, fields: &syn::Fields, ) -> syn::Result { 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::>() .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::>() .join(", ") ))), }) .collect::>() .join(", "); Err(syn::Error::new( span, format!("legacy syntax, remove `types` and use `{types}` instead"), )) } derive_more-impl-1.0.0/src/from_str.rs000064400000000000000000000070121046102023000160510ustar 00000000000000use 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 { 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) -> derive_more::core::result::Result { derive_more::core::result::Result::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) -> derive_more::core::result::Result { 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})") } derive_more-impl-1.0.0/src/index.rs000064400000000000000000000030041046102023000153220ustar 00000000000000use 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 { 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) } } }) } derive_more-impl-1.0.0/src/index_mut.rs000064400000000000000000000027351046102023000162210ustar 00000000000000use 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 { 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) } } }) } derive_more-impl-1.0.0/src/into.rs000064400000000000000000000471271046102023000152020ustar 00000000000000//! Implementation of an [`Into`] derive macro. use std::{ any::{Any, TypeId}, borrow::Cow, iter, slice, }; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, ToTokens as _}; use syn::{ ext::IdentExt as _, parse::{discouraged::Speculative as _, Parse, ParseStream}, punctuated::Punctuated, spanned::Spanned as _, token, }; use crate::utils::{ attr::{self, ParseMultiple as _}, polyfill, Either, FieldsExt, Spanning, }; /// Expands an [`Into`] derive macro. pub fn expand(input: &syn::DeriveInput, _: &'static str) -> syn::Result { let attr_name = format_ident!("into"); 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 struct_attr = StructAttribute::parse_attrs_with( &input.attrs, &attr_name, &ConsiderLegacySyntax { fields: &data.fields, }, )? .map(Spanning::into_inner); let fields_data = data .fields .iter() .enumerate() .map(|(i, f)| { let field_attr = FieldAttribute::parse_attrs_with( &f.attrs, &attr_name, &ConsiderLegacySyntax { fields: slice::from_ref(f), }, )? .map(Spanning::into_inner); let skip = field_attr .as_ref() .map(|attr| attr.skip.is_some()) .unwrap_or(false); let convs = field_attr.and_then(|attr| attr.convs); Ok(((i, f, skip), convs)) }) .collect::>>()?; let (fields, fields_convs): (Vec<_>, Vec<_>) = fields_data.into_iter().unzip(); let struct_attr = struct_attr.or_else(|| { fields_convs .iter() .all(Option::is_none) .then(ConversionsAttribute::default) .map(Either::Right) }); let mut expansions: Vec<_> = fields .iter() .zip(fields_convs) .filter_map(|(&(i, field, _), convs)| { convs.map(|convs| Expansion { input_ident: &input.ident, input_generics: &input.generics, fields: vec![(i, field)], convs, }) }) .collect(); if let Some(attr) = struct_attr { expansions.push(Expansion { input_ident: &input.ident, input_generics: &input.generics, fields: fields .into_iter() .filter_map(|(i, f, skip)| (!skip).then_some((i, f))) .collect(), convs: attr.into(), }); } expansions.into_iter().map(Expansion::expand).collect() } /// Expansion of an [`Into`] derive macro, generating [`From`] implementations for a struct. struct Expansion<'a> { /// [`syn::Ident`] of the struct. /// /// [`syn::Ident`]: struct@syn::Ident input_ident: &'a syn::Ident, /// [`syn::Generics`] of the struct. input_generics: &'a syn::Generics, /// Fields to convert from, along with their indices. fields: Vec<(usize, &'a syn::Field)>, /// Conversions to be generated. convs: ConversionsAttribute, } impl<'a> Expansion<'a> { fn expand(self) -> syn::Result { let Self { input_ident, input_generics, fields, convs, } = self; let fields_idents: Vec<_> = fields .iter() .map(|(i, f)| { f.ident .as_ref() .map_or_else(|| Either::Left(syn::Index::from(*i)), Either::Right) }) .collect(); let fields_tys: Vec<_> = fields.iter().map(|(_, f)| &f.ty).collect(); let fields_tuple = syn::Type::Tuple(syn::TypeTuple { paren_token: token::Paren::default(), elems: fields_tys.iter().cloned().cloned().collect(), }); [ (&convs.owned, false, false), (&convs.r#ref, true, false), (&convs.ref_mut, true, true), ] .into_iter() .filter(|(conv, _, _)| conv.consider_fields_ty || !conv.tys.is_empty()) .map(|(conv, ref_, mut_)| { let lf = ref_.then(|| syn::Lifetime::new("'__derive_more_into", Span::call_site())); let r = ref_.then(token::And::default); let m = mut_.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) }; let (impl_gens, _, where_clause) = gens.split_for_impl(); let (_, ty_gens, _) = input_generics.split_for_impl(); if conv.consider_fields_ty { Either::Left(iter::once(&fields_tuple)) } else { Either::Right(iter::empty()) } .chain(&conv.tys) .map(|out_ty| { let tys: Vec<_> = fields_tys.validate_type(out_ty)?.collect(); Ok(quote! { #[allow(clippy::unused_unit)] #[automatically_derived] impl #impl_gens derive_more::core::convert::From<#r #lf #m #input_ident #ty_gens> for ( #( #r #lf #m #tys ),* ) #where_clause { #[inline] fn from(value: #r #lf #m #input_ident #ty_gens) -> Self { (#( <#r #m #tys as derive_more::core::convert::From<_>>::from( #r #m value. #fields_idents ) ),*) } } }) }) .collect::>() }) .collect() } } /// Representation of an [`Into`] derive macro struct container attribute. /// /// ```rust,ignore /// #[into] /// #[into()] /// #[into(owned(), ref(), ref_mut())] /// ``` type StructAttribute = Either; impl From for ConversionsAttribute { fn from(v: StructAttribute) -> Self { match v { Either::Left(_) => ConversionsAttribute::default(), Either::Right(c) => c, } } } type Untyped = Either>; impl From for FieldAttribute { fn from(v: Untyped) -> Self { match v { Untyped::Left(skip) => Self { skip: Some(skip), convs: None, }, Untyped::Right(c) => Self { skip: None, convs: Some(match c { Either::Left(_empty) => ConversionsAttribute::default(), Either::Right(convs) => convs, }), }, } } } /// Representation of an [`Into`] derive macro field attribute. /// /// ```rust,ignore /// #[into] /// #[into()] /// #[into(owned(), ref(), ref_mut())] /// #[into(skip)] #[into(ignore)] /// ``` #[derive(Clone, Debug)] struct FieldAttribute { skip: Option, convs: Option, } impl Parse for FieldAttribute { fn parse(_: ParseStream<'_>) -> syn::Result { unreachable!("call `attr::ParseMultiple::parse_attr_with()` instead") } } impl attr::ParseMultiple for FieldAttribute { fn parse_attr_with( attr: &syn::Attribute, parser: &P, ) -> syn::Result { Untyped::parse_attr_with(attr, parser).map(Self::from) } fn merge_attrs( prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { let skip = attr::Skip::merge_opt_attrs( prev.clone().map(|v| v.skip).transpose(), new.clone().map(|v| v.skip).transpose(), name, )? .map(Spanning::into_inner); let convs = ConversionsAttribute::merge_opt_attrs( prev.clone().map(|v| v.convs).transpose(), new.clone().map(|v| v.convs).transpose(), name, )? .map(Spanning::into_inner); Ok(Spanning::new( Self { skip, convs }, prev.span.join(new.span).unwrap_or(prev.span), )) } } /// [`Into`] conversions specified by a [`ConversionsAttribute`]. #[derive(Clone, Debug, Default)] struct Conversions { /// Indicator whether these [`Conversions`] should contain a conversion into fields type. consider_fields_ty: bool, /// [`syn::Type`]s explicitly specified in a [`ConversionsAttribute`]. tys: Punctuated, } /// Representation of an [`Into`] derive macro attribute describing specified [`Into`] conversions. /// /// ```rust,ignore /// #[into()] /// #[into(owned(), ref(), ref_mut())] /// ``` #[derive(Clone, Debug)] struct ConversionsAttribute { /// [`syn::Type`]s wrapped into `owned(...)` or simply `#[into(...)]`. owned: Conversions, /// [`syn::Type`]s wrapped into `ref(...)`. r#ref: Conversions, /// [`syn::Type`]s wrapped into `ref_mut(...)`. ref_mut: Conversions, } impl Default for ConversionsAttribute { fn default() -> Self { Self { owned: Conversions { consider_fields_ty: true, tys: Punctuated::new(), }, r#ref: Conversions::default(), ref_mut: Conversions::default(), } } } impl Parse for ConversionsAttribute { fn parse(input: ParseStream<'_>) -> syn::Result { let mut out = Self { owned: Conversions::default(), r#ref: Conversions::default(), ref_mut: Conversions::default(), }; let parse_inner = |ahead, convs: &mut Conversions| { input.advance_to(&ahead); if input.peek(token::Paren) { let inner; syn::parenthesized!(inner in input); convs.tys.extend( inner .parse_terminated(syn::Type::parse, token::Comma)? .into_pairs(), ); } else { convs.consider_fields_ty = true; } if input.peek(token::Comma) { let comma = input.parse::()?; if !convs.tys.empty_or_trailing() { convs.tys.push_punct(comma); } } Ok(()) }; let mut has_wrapped_type = false; let mut top_level_type = None; while !input.is_empty() { let ahead = input.fork(); let res = if ahead.peek(syn::Ident::peek_any) { ahead.call(syn::Ident::parse_any).map(Into::into) } else { ahead.parse::() }; 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 = input.parse::()?; let _ = top_level_type.get_or_insert_with(|| ty.clone()); out.owned.tys.push_value(ty); if input.peek(token::Comma) { out.owned.tys.push_punct(input.parse::()?) } } } } 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) } } } impl attr::ParseMultiple for ConversionsAttribute { fn merge_attrs( prev: Spanning, new: Spanning, _: &syn::Ident, ) -> syn::Result> { let Spanning { span: prev_span, item: mut prev, } = prev; let Spanning { span: new_span, item: new, } = new; prev.owned.tys.extend(new.owned.tys); prev.owned.consider_fields_ty |= new.owned.consider_fields_ty; prev.r#ref.tys.extend(new.r#ref.tys); prev.r#ref.consider_fields_ty |= new.r#ref.consider_fields_ty; prev.ref_mut.tys.extend(new.ref_mut.tys); prev.ref_mut.consider_fields_ty |= new.ref_mut.consider_fields_ty; Ok(Spanning::new( prev, prev_span.join(new_span).unwrap_or(prev_span), )) } } /// [`attr::Parser`] considering legacy syntax and performing [`check_legacy_syntax()`] for a /// [`StructAttribute`] or a [`FieldAttribute`]. struct ConsiderLegacySyntax { /// [`syn::Field`]s the [`StructAttribute`] or [`FieldAttribute`] is parsed for. fields: F, } impl<'a, F> attr::Parser for ConsiderLegacySyntax<&'a F> where F: FieldsExt + ?Sized, &'a F: IntoIterator, { fn parse(&self, input: ParseStream<'_>) -> syn::Result { if TypeId::of::() == TypeId::of::() { check_legacy_syntax(input, self.fields)?; } T::parse(input) } } /// [`Error`]ors for legacy syntax: `#[into(types(i32, "&str"))]`. /// /// [`Error`]: syn::Error fn check_legacy_syntax<'a, F>(tokens: ParseStream<'_>, fields: &'a F) -> syn::Result<()> where F: FieldsExt + ?Sized, &'a F: IntoIterator, { 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::>() .join(", ") ) } else { s } }; let field = match fields.len() { 0 => None, 1 => Some( fields .into_iter() .next() .unwrap_or_else(|| unreachable!("fields.len() == 1")) .ty .to_token_stream() .to_string(), ), _ => Some(format!( "({})", fields .into_iter() .map(|f| f.ty.to_token_stream().to_string()) .collect::>() .join(", ") )), }; let Ok(metas) = tokens.parse_terminated(polyfill::Meta::parse, token::Comma) else { return Ok(()); }; let parse_list = |list: polyfill::MetaList, attrs: &mut Option>| { 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>, 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::>() .join(", "), )), None => None, }; let format = [ format(owned, "owned"), format(ref_, "ref"), format(ref_mut, "ref_mut"), ] .into_iter() .flatten() .collect::>() .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(", "), ), )) } } derive_more-impl-1.0.0/src/into_iterator.rs000064400000000000000000000041271046102023000171040ustar 00000000000000use crate::utils::{ add_extra_generic_param, add_extra_where_clauses, SingleFieldData, State, }; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{parse::Result, DeriveInput}; /// Provides the hook to expand `#[derive(IntoIterator)]` into an implementation of `IntoIterator` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_refs(input, trait_name, "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 (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 generics = add_extra_where_clauses( &input.generics, quote! { where #reference_with_lifetime #field_type: #trait_path }, ); let (_, ty_generics, where_clause) = generics.split_for_impl(); 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) } derive_more-impl-1.0.0/src/is_variant.rs000064400000000000000000000037131046102023000163610ustar 00000000000000use 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 { 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 func = quote! { #[doc = "Returns `true` if this value is of type `"] #[doc = stringify!(#variant_ident)] #[doc = "`. Returns `false` otherwise"] #[inline] #[must_use] pub const fn #fn_name(&self) -> bool { derive_more::core::matches!(self, #enum_name ::#variant_ident #data_pattern) } }; funcs.push(func); } let imp = quote! { #[automatically_derived] impl #imp_generics #enum_name #type_generics #where_clause { #(#funcs)* } }; Ok(imp) } derive_more-impl-1.0.0/src/lib.rs000064400000000000000000000152651046102023000147750ustar 00000000000000#![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_ref")] mod r#as; #[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"))] pub(crate) mod parsing; #[cfg(feature = "sum")] mod sum_like; #[cfg(feature = "try_from")] mod try_from; #[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. // // This trait can be unused if no feature is enabled. We already error in that case but this // warning distracts from the actual error. #[allow(dead_code)] trait Output { fn process(self) -> TokenStream; } impl Output for proc_macro2::TokenStream { fn process(self) -> TokenStream { self.into() } } impl Output for Result { fn process(self) -> TokenStream { match self { Ok(ts) => ts.into(), Err(e) => e.to_compile_error().into(), } } } macro_rules! create_derive( ($feature:literal, $mod_:ident $(:: $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_ref", r#as::r#mut, AsMut, as_mut_derive, as_mut); create_derive!("as_ref", r#as::r#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_from", try_from, TryFrom, try_from_derive, try_from); 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); derive_more-impl-1.0.0/src/mul_assign_like.rs000064400000000000000000000035631046102023000173720ustar 00000000000000use 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 { 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::>(); 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] #[track_caller] fn #method_ident(&mut self, rhs: #scalar_ident) { #( #exprs; )* } } }) } derive_more-impl-1.0.0/src/mul_helpers.rs000064400000000000000000000017111046102023000165350ustar 00000000000000use crate::utils::{add_where_clauses_for_new_ident, MultiFieldData, RefType}; use proc_macro2::TokenStream; use quote::quote; use syn::{Generics, Ident}; pub fn generics_and_exprs( multi_field_data: MultiFieldData, scalar_ident: &Ident, type_where_clauses: TokenStream, ref_type: RefType, ) -> (Generics, Vec) { let MultiFieldData { fields, casted_traits, members, method_ident, .. } = multi_field_data; let reference = ref_type.reference(); let exprs: Vec<_> = casted_traits .iter() .zip(members) .map(|(casted_trait, member)| { quote! { #casted_trait::#method_ident(#reference #member, rhs) } }) .collect(); let new_generics = add_where_clauses_for_new_ident( &multi_field_data.state.input.generics, &fields, scalar_ident, type_where_clauses, true, ); (new_generics, exprs) } derive_more-impl-1.0.0/src/mul_like.rs000064400000000000000000000036611046102023000160250ustar 00000000000000use 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 { 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::>(); 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] #[track_caller] fn #method_ident(self, rhs: #scalar_ident) -> #input_type #ty_generics { #body } } }) } derive_more-impl-1.0.0/src/not_like.rs000064400000000000000000000135321046102023000160260ustar 00000000000000use 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 derive_more::#trait_ident for #input_type #ty_generics #where_clause { type Output = #output_type; #[inline] fn #method_ident(self) -> #output_type { #block } } } } fn tuple_content( input_type: &T, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { let mut exprs = vec![]; for i in 0..fields.len() { let i = Index::from(i); // generates `self.0.add()` let expr = quote! { self.#i.#method_ident() }; exprs.push(expr); } quote! { #input_type(#(#exprs),*) } } fn struct_content( input_type: &Ident, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { let mut exprs = vec![]; for field in fields { // It's safe to unwrap because struct fields always have an identifier let field_id = field.ident.as_ref(); // generates `x: self.x.not()` let expr = quote! { #field_id: self.#field_id.#method_ident() }; exprs.push(expr) } quote! { #input_type{#(#exprs),*} } } fn enum_output_type_and_content( input: &DeriveInput, data_enum: &DataEnum, method_ident: &Ident, ) -> (TokenStream, TokenStream) { let input_type = &input.ident; let (_, ty_generics, _) = input.generics.split_for_impl(); let mut matches = vec![]; let mut method_iter = iter::repeat(method_ident); // If the enum contains unit types that means it can error. let has_unit_type = data_enum.variants.iter().any(|v| v.fields == Fields::Unit); for variant in &data_enum.variants { let subtype = &variant.ident; let subtype = quote! { #input_type::#subtype }; match variant.fields { Fields::Unnamed(ref fields) => { // The 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! { derive_more::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! { derive_more::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 => derive_more::core::result::Result::Err( derive_more::UnitError::new(#operation_name) ) }); } } } let body = quote! { match self { #(#matches),* } }; let output_type = if has_unit_type { quote! { derive_more::core::result::Result<#input_type #ty_generics, derive_more::UnitError> } } else { quote! { #input_type #ty_generics } }; (output_type, body) } derive_more-impl-1.0.0/src/parsing.rs000064400000000000000000000220021046102023000156550ustar 00000000000000//! Common parsing utilities for derive macros. //! //! Fair parsing of [`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::{Spacing, TokenStream}; use quote::ToTokens; use syn::{ buffer::Cursor, parse::{Parse, ParseStream}, }; /// [`syn::Expr`] [`Parse`]ing polyfill. #[derive(Clone, Debug)] pub(crate) enum Expr { /// [`syn::Expr::Path`] of length 1 [`Parse`]ing polyfill. Ident(syn::Ident), /// Every other [`syn::Expr`] variant. Other(TokenStream), } impl Expr { /// Returns a [`syn::Ident`] in case this [`Expr`] is represented only by it. /// /// [`syn::Ident`]: struct@syn::Ident pub(crate) fn ident(&self) -> Option<&syn::Ident> { match self { Self::Ident(ident) => Some(ident), Self::Other(_) => None, } } } impl From for Expr { fn from(ident: syn::Ident) -> Self { Self::Ident(ident) } } impl Parse for Expr { fn parse(input: ParseStream) -> syn::Result { if let Ok(ident) = input.step(|c| { c.ident() .filter(|(_, c)| c.eof() || punct(',')(*c).is_some()) .ok_or_else(|| syn::Error::new(c.span(), "expected `ident(,|eof)`")) }) { Ok(Self::Ident(ident)) } else { input.step(|c| { take_until1( alt([ &mut seq([ &mut path_sep, &mut balanced_pair(punct('<'), punct('>')), ]), &mut seq([ &mut balanced_pair(punct('<'), punct('>')), &mut path_sep, ]), &mut balanced_pair(punct('|'), punct('|')), &mut token_tree, ]), punct(','), )(*c) .map(|(stream, cursor)| (Self::Other(stream), cursor)) .ok_or_else(|| syn::Error::new(c.span(), "failed to parse expression")) }) } } } impl PartialEq for Expr { fn eq(&self, other: &syn::Ident) -> bool { self.ident().map_or(false, |i| i == other) } } 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 [`token::PathSep`]. /// /// [`token::PathSep`]: struct@syn::token::PathSep pub fn path_sep(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( mut parsers: [&mut dyn FnMut(Cursor<'_>) -> ParsingResult<'_>; N], ) -> impl FnMut(Cursor<'_>) -> ParsingResult<'_> + '_ { move |c| { parsers.iter_mut().try_fold( (TokenStream::new(), c), |(mut out, mut c), parser| { let (stream, cursor) = parser(c)?; out.extend(stream); c = cursor; Some((out, c)) }, ) } } /// Tries to execute the first successful parser. pub fn alt( mut parsers: [&mut dyn FnMut(Cursor<'_>) -> ParsingResult<'_>; N], ) -> impl FnMut(Cursor<'_>) -> ParsingResult<'_> + '_ { move |c| parsers.iter_mut().find_map(|parser| parser(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( 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; fn assert<'a, T: Debug + Parse + ToTokens>( input: &'a str, parsed: impl AsRef<[&'a str]>, ) { let parsed = parsed.as_ref(); let punctuated = Punctuated::::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 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::("", []); 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); } } } } } derive_more-impl-1.0.0/src/sum_like.rs000064400000000000000000000040411046102023000160250ustar 00000000000000use 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 { 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! { derive_more::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 }; 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(derive_more::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>(iter: I) -> Self { iter.fold(#identity, #op_path::#op_method_ident) } } }) } derive_more-impl-1.0.0/src/try_from.rs000064400000000000000000000112501046102023000160560ustar 00000000000000//! Implementation of a [`TryFrom`] derive macro. use proc_macro2::{Literal, TokenStream}; use quote::{format_ident, quote, ToTokens}; use syn::spanned::Spanned as _; use crate::utils::{ attr::{self, ParseMultiple as _}, Spanning, }; /// Expands a [`TryFrom`] derive macro. pub fn expand(input: &syn::DeriveInput, _: &'static str) -> syn::Result { match &input.data { syn::Data::Struct(data) => Err(syn::Error::new( data.struct_token.span(), "`TryFrom` cannot be derived for structs", )), syn::Data::Enum(data) => Ok(Expansion { repr: attr::ReprInt::parse_attrs(&input.attrs, &format_ident!("repr"))? .map(Spanning::into_inner) .unwrap_or_default(), attr: ItemAttribute::parse_attrs(&input.attrs, &format_ident!("try_from"))? .map(|attr| { if matches!(attr.item, ItemAttribute::Types(_)) { Err(syn::Error::new( attr.span, "`#[try_from(repr(...))]` attribute is not supported yet", )) } else { Ok(attr.item) } }) .transpose()?, ident: input.ident.clone(), generics: input.generics.clone(), variants: data.variants.clone().into_iter().collect(), } .into_token_stream()), syn::Data::Union(data) => Err(syn::Error::new( data.union_token.span(), "`TryFrom` cannot be derived for unions", )), } } /// Representation of a [`TryFrom`] derive macro struct item attribute. /// /// ```rust,ignore /// #[try_from(repr)] /// #[try_from(repr())] /// ``` type ItemAttribute = attr::ReprConversion; /// Expansion of a macro for generating [`TryFrom`] implementation of an enum. struct Expansion { /// `#[repr(u/i*)]` of the enum. repr: attr::ReprInt, /// [`ItemAttribute`] of the enum. attr: Option, /// [`syn::Ident`] of the enum. /// /// [`syn::Ident`]: struct@syn::Ident ident: syn::Ident, /// [`syn::Generics`] of the enum. generics: syn::Generics, /// [`syn::Variant`]s of the enum. variants: Vec, } impl ToTokens for Expansion { /// Expands [`TryFrom`] implementations for a struct. fn to_tokens(&self, tokens: &mut TokenStream) { if self.attr.is_none() { return; } let ident = &self.ident; let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); let repr_ty = &self.repr.ty(); let mut last_discriminant = quote! { 0 }; let mut inc = 0usize; let (consts, (discriminants, variants)): ( Vec, (Vec, Vec), ) = self .variants .iter() .filter_map( |syn::Variant { ident, fields, discriminant, .. }| { if let Some(d) = discriminant { last_discriminant = d.1.to_token_stream(); inc = 0; } let ret = { let inc = Literal::usize_unsuffixed(inc); fields.is_empty().then_some(( format_ident!("__DISCRIMINANT_{ident}"), ( quote! { #last_discriminant + #inc }, quote! { #ident #fields }, ), )) }; inc += 1; ret }, ) .unzip(); quote! { #[automatically_derived] impl #impl_generics derive_more::TryFrom<#repr_ty #ty_generics> for #ident #where_clause { type Error = derive_more::TryFromReprError<#repr_ty>; #[allow(non_upper_case_globals)] #[inline] fn try_from(val: #repr_ty) -> derive_more::core::result::Result { #( const #consts: #repr_ty = #discriminants; )* match val { #(#consts => derive_more::core::result::Result::Ok(#ident::#variants),)* _ => derive_more::core::result::Result::Err( derive_more::TryFromReprError::new(val) ), } } } }.to_tokens(tokens); } } derive_more-impl-1.0.0/src/try_into.rs000064400000000000000000000105501046102023000160660ustar 00000000000000use crate::utils::{ add_extra_generic_param, numbered_vars, AttrParams, DeriveType, MultiFieldData, State, }; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{DeriveInput, Result}; use crate::utils::HashMap; /// Provides the hook to expand `#[derive(TryInto)]` into an implementation of `TryInto` #[allow(clippy::cognitive_complexity)] pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_attr_params( input, trait_name, "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_data) 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_data { 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::>(); format!("({})", types.join(", ")) }; let variant_names = multi_field_data .iter() .map(|d| { d.variant_name .expect("Somehow there was no variant name") .to_string() }) .collect::>() .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 derive_more::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 #ty_generics>; #[inline] fn try_from( value: #reference_with_lifetime #input_type #ty_generics, ) -> derive_more::core::result::Result { match value { #(#matchers)|* => derive_more::core::result::Result::Ok(#vars), _ => derive_more::core::result::Result::Err( derive_more::TryIntoError::new(value, #variant_names, #output_type), ), } } } }; try_from.to_tokens(&mut tokens) } Ok(tokens) } derive_more-impl-1.0.0/src/try_unwrap.rs000064400000000000000000000143131046102023000164320ustar 00000000000000use crate::utils::{AttrParams, DeriveType, State}; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{DeriveInput, Fields, Ident, Result, Type}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { 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) -> derive_more::core::result::Result< (#(#data_types),*), derive_more::TryUnwrapError > { match self { #pattern => derive_more::core::result::Result::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) -> derive_more::core::result::Result< (#(&#data_types),*), derive_more::TryUnwrapError<&Self> > { match self { #pattern => derive_more::core::result::Result::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) -> derive_more::core::result::Result< (#(&mut #data_types),*), derive_more::TryUnwrapError<&mut Self> > { match self { #pattern => derive_more::core::result::Result::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 => derive_more::core::result::Result::Err(#error) } }); quote! { match val { #(#arms),* } } } derive_more-impl-1.0.0/src/unwrap.rs000064400000000000000000000127511046102023000155400ustar 00000000000000use crate::utils::{AttrParams, DeriveType, State}; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{DeriveInput, Fields, Ident, Result, Type}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { 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),* } } } derive_more-impl-1.0.0/src/utils.rs000064400000000000000000002264261046102023000153720ustar 00000000000000#![cfg_attr( not(all(feature = "add", feature = "mul")), allow(dead_code, 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 = "as_ref", feature = "debug", feature = "display", feature = "from", feature = "into", feature = "try_from", ))] pub(crate) use self::either::Either; #[cfg(any(feature = "from", feature = "into"))] pub(crate) use self::fields_ext::FieldsExt; #[cfg(feature = "as_ref")] pub(crate) use self::generics_search::GenericsSearch; #[cfg(any( feature = "as_ref", feature = "debug", feature = "display", feature = "from", feature = "into", feature = "try_from", ))] pub(crate) use self::spanning::Spanning; #[derive(Clone, Copy, Default)] pub struct DeterministicState; impl std::hash::BuildHasher for DeterministicState { type Hasher = std::collections::hash_map::DefaultHasher; fn build_hasher(&self) -> Self::Hasher { Self::Hasher::default() } } pub type HashMap = std::collections::HashMap; pub type HashSet = std::collections::HashSet; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum RefType { No, Ref, Mut, } impl RefType { pub fn lifetime(self) -> TokenStream { match self { RefType::No => quote! {}, _ => quote! { '__deriveMoreLifetime }, } } pub fn reference(self) -> TokenStream { match self { RefType::No => quote! {}, RefType::Ref => quote! { & }, RefType::Mut => quote! { &mut }, } } pub fn mutability(self) -> TokenStream { match self { RefType::Mut => quote! { mut }, _ => quote! {}, } } pub fn pattern_ref(self) -> TokenStream { match self { RefType::Ref => quote! { ref }, RefType::Mut => quote! { ref mut }, RefType::No => quote! {}, } } pub fn reference_with_lifetime(self) -> TokenStream { if !self.is_ref() { return quote! {}; } let lifetime = self.lifetime(); let mutability = self.mutability(); quote! { &#lifetime #mutability } } pub fn is_ref(self) -> bool { !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 { (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 + '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! { derive_more::core::ops::#trait_ident }; type_param.bounds.push(bound) } generics } pub fn add_extra_ty_param_bound_op<'a>( generics: &'a Generics, trait_ident: &'a Ident, ) -> Generics { add_extra_ty_param_bound(generics, "e! { derive_more::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_generic_param( generics: &Generics, generic_param: TokenStream, ) -> Generics { let generic_param: GenericParam = parse_quote! { #generic_param }; let mut generics = generics.clone(); generics.params.push(generic_param); generics } pub fn add_extra_generic_type_param( generics: &Generics, generic_param: TokenStream, ) -> Generics { let generic_param: GenericParam = parse_quote! { #generic_param }; let lifetimes: Vec = generics.lifetimes().map(|x| x.clone().into()).collect(); let type_params: Vec = generics.type_params().map(|x| x.clone().into()).collect(); let const_params: Vec = generics.const_params().map(|x| x.clone().into()).collect(); let mut generics = generics.clone(); generics.params = Default::default(); generics.params.extend(lifetimes); generics.params.extend(type_params); generics.params.push(generic_param); generics.params.extend(const_params); generics } pub fn add_extra_where_clauses( generics: &Generics, type_where_clauses: TokenStream, ) -> Generics { let mut type_where_clauses: WhereClause = parse_quote! { #type_where_clauses }; let mut new_generics = generics.clone(); if let Some(old_where) = new_generics.where_clause { type_where_clauses.predicates.extend(old_where.predicates) } new_generics.where_clause = Some(type_where_clauses); new_generics } pub fn add_where_clauses_for_new_ident<'a>( generics: &'a Generics, fields: &[&'a Field], type_ident: &Ident, type_where_clauses: TokenStream, sized: bool, ) -> Generics { let generic_param = if fields.len() > 1 { quote! { #type_ident: derive_more::core::marker::Copy } } else if sized { quote! { #type_ident } } else { quote! { #type_ident: ?derive_more::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 method_ident: Ident, pub trait_path: TokenStream, pub trait_path_params: Vec, pub trait_attr: String, pub derive_type: DeriveType, pub fields: Vec<&'input Field>, pub variants: Vec<&'input Variant>, pub variant_states: Vec>, pub variant: Option<&'input Variant>, pub generics: Generics, pub default_info: FullMetaInfo, full_meta_infos: Vec, } #[derive(Default, Clone)] pub struct AttrParams { pub enum_: Vec<&'static str>, pub variant: Vec<&'static str>, pub struct_: Vec<&'static str>, pub field: Vec<&'static str>, } impl AttrParams { pub fn new(params: Vec<&'static str>) -> AttrParams { AttrParams { enum_: params.clone(), struct_: params.clone(), variant: params.clone(), field: params, } } pub fn struct_(params: Vec<&'static str>) -> AttrParams { AttrParams { enum_: vec![], struct_: params, variant: vec![], field: vec![], } } } impl<'input> State<'input> { pub fn new<'arg_input>( input: &'arg_input DeriveInput, trait_name: &'static str, trait_attr: String, ) -> Result> { 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::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::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::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::new_impl(input, trait_name, trait_attr, allowed_attr_params, true) } 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> { 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> = 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() .find_map(|info| info.enabled.map(|_| info)); // Default to enabled true, except when first attribute has explicit // enabling. // // Except for derive Error. // // The way `else` case works is that if any field have any valid // attribute specified, then all fields without any attributes // specified are filtered out from `State::enabled_fields`. // // However, derive Error *infers* fields and there are cases when // one of the fields may have an attribute specified, but another field // would be inferred. So, for derive Error macro we default enabled // to true unconditionally (i.e., even if some fields have attributes // specified). let default_enabled = if trait_name == "Error" { true } else { first_match.map_or(true, |info| !info.enabled.unwrap()) }; let defaults = struct_meta_info.into_full(FullMetaInfo { enabled: default_enabled, forward: false, // Default to owned true, except when first attribute has one of owned, // ref or ref_mut // - not a single attribute means default true // - an attribute, but non of owned, ref or ref_mut means default true // - an attribute, and owned, ref or ref_mut means default false owned: first_match.map_or(true, |info| { info.owned.is_none() && info.ref_.is_none() || info.ref_mut.is_none() }), ref_: false, ref_mut: false, info: MetaInfo::default(), }); let full_meta_infos: Vec<_> = meta_infos .into_iter() .map(|info| info.into_full(defaults.clone())) .collect(); let variant_states: Result> = if derive_type == DeriveType::Enum { variants .iter() .zip(full_meta_infos.iter().cloned()) .map(|(variant, info)| { State::from_variant( input, trait_name, trait_attr.clone(), allowed_attr_params.clone(), variant, info, ) }) .collect() } else { Ok(vec![]) }; let generics = if add_type_bound { add_extra_ty_param_bound(&input.generics, &trait_path) } else { input.generics.clone() }; Ok(State { input, trait_name, method_ident, trait_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> { 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> = 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, method_ident, // input, fields, variants: vec![], variant_states: vec![], variant: Some(variant), derive_type, generics, full_meta_infos, default_info, }) } pub fn add_trait_path_type_param(&mut self, param: TokenStream) { self.trait_path_params.push(param); } pub fn assert_single_enabled_field<'state>( &'state self, ) -> SingleFieldData<'input, 'state> { if self.derive_type == DeriveType::Enum { panic_one_field(self.trait_name, &self.trait_attr); } let data = self.enabled_fields_data(); if data.fields.len() != 1 { panic_one_field(self.trait_name, &self.trait_attr); }; SingleFieldData { input_type: data.input_type, field: data.fields[0], field_type: data.field_types[0], member: data.members[0].clone(), info: data.infos[0].clone(), trait_path: data.trait_path, trait_path_with_params: data.trait_path_with_params.clone(), casted_trait: data.casted_traits[0].clone(), impl_generics: data.impl_generics.clone(), ty_generics: data.ty_generics.clone(), where_clause: data.where_clause, multi_field_data: data, } } pub fn enabled_fields_data<'state>(&'state self) -> MultiFieldData<'input, 'state> { if self.derive_type == DeriveType::Enum { panic!("cannot derive({}) for enum", self.trait_name) } let fields = self.enabled_fields(); let field_idents = self.enabled_fields_idents(); let field_indexes = self.enabled_fields_indexes(); let field_types: Vec<_> = fields.iter().map(|f| &f.ty).collect(); let members: Vec<_> = field_idents .iter() .map(|ident| quote! { self.#ident }) .collect(); let trait_path = &self.trait_path; let trait_path_with_params = if !self.trait_path_params.is_empty() { let params = self.trait_path_params.iter(); quote! { #trait_path<#(#params),*> } } else { self.trait_path.clone() }; let casted_traits: Vec<_> = field_types .iter() .map(|field_type| quote! { <#field_type as #trait_path_with_params> }) .collect(); let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); let input_type = &self.input.ident; let (variant_name, variant_type) = self.variant.map_or_else( || (None, quote! { #input_type }), |v| { let variant_name = &v.ident; (Some(variant_name), quote! { #input_type::#variant_name }) }, ); MultiFieldData { input_type, variant_type, variant_name, variant_info: self.default_info.clone(), fields, field_types, field_indexes, members, infos: self.enabled_infos(), field_idents, method_ident: &self.method_ident, trait_path, trait_path_with_params, casted_traits, impl_generics, ty_generics, where_clause, state: self, } } pub fn enabled_variant_data<'state>( &'state self, ) -> MultiVariantData<'input, 'state> { if self.derive_type != DeriveType::Enum { panic!("can only derive({}) for enum", self.trait_name) } let variants = self.enabled_variants(); MultiVariantData { variants, variant_states: self.enabled_variant_states(), infos: self.enabled_infos(), } } fn enabled_variants(&self) -> Vec<&'input Variant> { self.variants .iter() .zip(self.full_meta_infos.iter().map(|info| info.enabled)) .filter(|(_, ig)| *ig) .map(|(v, _)| *v) .collect() } fn enabled_variant_states(&self) -> Vec<&State<'input>> { self.variant_states .iter() .zip(self.full_meta_infos.iter().map(|info| info.enabled)) .filter(|(_, ig)| *ig) .map(|(v, _)| v) .collect() } pub fn enabled_fields(&self) -> Vec<&'input Field> { self.fields .iter() .zip(self.full_meta_infos.iter().map(|info| info.enabled)) .filter(|(_, ig)| *ig) .map(|(f, _)| *f) .collect() } fn field_idents(&self) -> Vec { if self.derive_type == DeriveType::Named { self.fields .iter() .map(|f| { f.ident .as_ref() .expect("Tried to get field names of a tuple struct") .to_token_stream() }) .collect() } else { let count = self.fields.len(); (0..count) .map(|i| Index::from(i).to_token_stream()) .collect() } } fn enabled_fields_idents(&self) -> Vec { self.field_idents() .into_iter() .zip(self.full_meta_infos.iter().map(|info| info.enabled)) .filter(|(_, ig)| *ig) .map(|(f, _)| f) .collect() } fn enabled_fields_indexes(&self) -> Vec { self.full_meta_infos .iter() .map(|info| info.enabled) .enumerate() .filter(|(_, ig)| *ig) .map(|(i, _)| i) .collect() } fn enabled_infos(&self) -> Vec { self.full_meta_infos .iter() .filter(|info| info.enabled) .cloned() .collect() } } #[derive(Clone)] pub struct SingleFieldData<'input, 'state> { pub input_type: &'input Ident, pub field: &'input Field, pub field_type: &'input Type, pub member: TokenStream, pub info: FullMetaInfo, pub trait_path: &'state TokenStream, pub trait_path_with_params: TokenStream, pub casted_trait: TokenStream, pub impl_generics: ImplGenerics<'state>, pub ty_generics: TypeGenerics<'state>, pub where_clause: Option<&'state WhereClause>, multi_field_data: MultiFieldData<'input, 'state>, } #[derive(Clone)] pub struct MultiFieldData<'input, 'state> { pub input_type: &'input Ident, pub variant_type: TokenStream, pub variant_name: Option<&'input Ident>, pub variant_info: FullMetaInfo, pub fields: Vec<&'input Field>, pub field_types: Vec<&'input Type>, pub field_idents: Vec, pub field_indexes: Vec, pub members: Vec, pub infos: Vec, pub method_ident: &'state Ident, pub trait_path: &'state TokenStream, pub trait_path_with_params: TokenStream, pub casted_traits: Vec, pub impl_generics: ImplGenerics<'state>, pub ty_generics: TypeGenerics<'state>, pub where_clause: Option<&'state WhereClause>, pub state: &'state State<'input>, } pub struct MultiVariantData<'input, 'state> { pub variants: Vec<&'input Variant>, pub variant_states: Vec<&'state State<'input>>, pub infos: Vec, } impl<'input, 'state> MultiFieldData<'input, 'state> { pub fn initializer(&self, initializers: &[T]) -> TokenStream { let MultiFieldData { variant_type, field_idents, .. } = self; if self.state.derive_type == DeriveType::Named { quote! { #variant_type{#(#field_idents: #initializers),*} } } else { quote! { #variant_type(#(#initializers),*) } } } pub fn matcher( &self, indexes: &[usize], bindings: &[T], ) -> TokenStream { let MultiFieldData { variant_type, .. } = self; let full_bindings = (0..self.state.fields.len()).map(|i| { indexes.iter().position(|index| i == *index).map_or_else( || quote! { _ }, |found_index| bindings[found_index].to_token_stream(), ) }); if self.state.derive_type == DeriveType::Named { let field_idents = self.state.field_idents(); quote! { #variant_type{#(#field_idents: #full_bindings),*} } } else { quote! { #variant_type(#(#full_bindings),*) } } } } impl<'input, 'state> SingleFieldData<'input, 'state> { pub fn initializer(&self, initializers: &[T]) -> TokenStream { self.multi_field_data.initializer(initializers) } } fn get_meta_info( trait_attr: &str, attrs: &[Attribute], allowed_attr_params: &[&str], ) -> Result { let mut it = attrs.iter().filter(|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, 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::::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 { if input.fork().parse::().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(&self, ident: &I) -> bool where syn::Ident: PartialEq, { 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 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 { let path = input.parse::()?; 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(&self, parser: F) -> syn::Result { 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 { let path = input.parse::()?; 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 { 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, pub forward: Option, pub owned: Option, pub ref_: Option, pub ref_mut: Option, pub source: Option, pub backtrace: Option, #[cfg(any(feature = "from", feature = "into"))] pub types: HashMap>, } impl MetaInfo { fn into_full(self, defaults: FullMetaInfo) -> FullMetaInfo { FullMetaInfo { enabled: self.enabled.unwrap_or(defaults.enabled), forward: self.forward.unwrap_or(defaults.forward), owned: self.owned.unwrap_or(defaults.owned), ref_: self.ref_.unwrap_or(defaults.ref_), ref_mut: self.ref_mut.unwrap_or(defaults.ref_mut), info: self, } } } impl FullMetaInfo { pub fn ref_types(&self) -> Vec { let mut ref_types = vec![]; if self.owned { ref_types.push(RefType::No); } if self.ref_ { ref_types.push(RefType::Ref); } if self.ref_mut { ref_types.push(RefType::Mut); } ref_types } } pub fn get_if_type_parameter_used_in_type( type_parameters: &HashSet, ty: &syn::Type, ) -> Option { 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, 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 = "as_ref", feature = "debug", feature = "display", feature = "from", feature = "into", feature = "try_from", ))] mod either { use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse::{discouraged::Speculative as _, Parse, ParseStream}; /// Either [`Left`] or [`Right`]. /// /// [`Left`]: Either::Left /// [`Right`]: Either::Right #[derive(Clone, Copy, Debug)] pub(crate) enum Either { /// Left variant. Left(L), /// Right variant. Right(R), } impl Parse for Either where L: Parse, R: Parse, { fn parse(input: ParseStream<'_>) -> syn::Result { let ahead = input.fork(); if let Ok(left) = ahead.parse::() { input.advance_to(&ahead); Ok(Self::Left(left)) } else { input.parse::().map(Self::Right) } } } impl Iterator for Either where L: Iterator, R: Iterator, { type Item = T; fn next(&mut self) -> Option { match self { Self::Left(left) => left.next(), Self::Right(right) => right.next(), } } } impl ToTokens for Either where L: ToTokens, R: ToTokens, { fn to_tokens(&self, tokens: &mut TokenStream) { match self { Self::Left(l) => l.to_tokens(tokens), Self::Right(r) => r.to_tokens(tokens), } } } } #[cfg(any( feature = "as_ref", feature = "debug", feature = "display", feature = "from", feature = "into", feature = "try_from", ))] mod spanning { use std::ops::{Deref, DerefMut}; use proc_macro2::Span; /// Wrapper for non-[`Spanned`] types to hold their [`Span`]. /// /// [`Spanned`]: syn::spanned::Spanned #[derive(Clone, Copy, Debug)] pub(crate) struct Spanning { /// [`Span`] of the `item`. pub(crate) span: Span, /// Item the [`Span`] is held for. pub(crate) item: T, } impl Spanning { /// Creates a new [`Spanning`] `item`, attaching the provided [`Span`] to it. pub(crate) const fn new(item: T, span: Span) -> Self where T: Sized, { Self { span, item } } /// Destructures this [`Spanning`] wrapper returning the underlying `item`. pub fn into_inner(self) -> T where T: Sized, { self.item } /// Returns the [`Span`] contained in this [`Spanning`] wrapper. pub(crate) const fn span(&self) -> Span { self.span } /// Converts this `&`[`Spanning`]`` into [`Spanning`]`<&T>` (moves the reference inside). pub(crate) const fn as_ref(&self) -> Spanning<&T> { Spanning { span: self.span, item: &self.item, } } /// Maps the wrapped `item` with the provided `f`unction, preserving the current [`Span`]. pub(crate) fn map(self, f: impl FnOnce(T) -> U) -> Spanning where T: Sized, { Spanning { span: self.span, item: f(self.item), } } } #[cfg(feature = "into")] impl Spanning> { pub(crate) fn transpose(self) -> Option> { match self.item { Some(item) => Some(Spanning { item, span: self.span, }), None => None, } } } impl Deref for Spanning { type Target = T; fn deref(&self) -> &Self::Target { &self.item } } impl DerefMut for Spanning { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.item } } } #[cfg(any( feature = "as_ref", feature = "debug", feature = "display", feature = "from", feature = "into", feature = "try_from", ))] pub(crate) mod attr { use std::any::Any; use syn::{ parse::{Parse, ParseStream}, spanned::Spanned as _, }; use super::{Either, Spanning}; #[cfg(any( feature = "as_ref", feature = "from", feature = "into", feature = "try_from" ))] pub(crate) use self::empty::Empty; #[cfg(any( feature = "as_ref", feature = "debug", feature = "from", feature = "into", ))] pub(crate) use self::skip::Skip; #[cfg(any(feature = "as_ref", feature = "from", feature = "try_from"))] pub(crate) use self::types::Types; #[cfg(any(feature = "as_ref", feature = "from"))] pub(crate) use self::{ conversion::Conversion, field_conversion::FieldConversion, forward::Forward, }; #[cfg(feature = "try_from")] pub(crate) use self::{repr_conversion::ReprConversion, repr_int::ReprInt}; /// [`Parse`]ing with additional state or metadata. pub(crate) trait Parser { /// [`Parse`]s an item, using additional state or metadata. /// /// Default implementation just calls [`Parse::parse()`] directly. fn parse(&self, input: ParseStream<'_>) -> syn::Result { T::parse(input) } } impl Parser for () {} /// Parsing of a typed attribute from multiple [`syn::Attribute`]s. pub(crate) trait ParseMultiple: Parse + Sized + 'static { /// Parses this attribute from the provided single [`syn::Attribute`] with the provided /// [`Parser`]. /// /// Required, because with [`Parse`] we only able to parse inner attribute tokens, which /// doesn't work for attributes with empty arguments, like `#[attr]`. /// /// Override this method if the default [`syn::Attribute::parse_args_with()`] is not enough. fn parse_attr_with( attr: &syn::Attribute, parser: &P, ) -> syn::Result { attr.parse_args_with(|ps: ParseStream<'_>| parser.parse(ps)) } /// Merges multiple values of this attribute into a single one. /// /// Default implementation only errors, disallowing multiple values of the same attribute. fn merge_attrs( _prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { Err(syn::Error::new( new.span, format!("only single `#[{name}(...)]` attribute is allowed here"), )) } /// Merges multiple [`Option`]al values of this attribute into a single one. /// /// Default implementation uses [`ParseMultiple::merge_attrs()`] when both `prev` and `new` /// are [`Some`]. fn merge_opt_attrs( prev: Option>, new: Option>, name: &syn::Ident, ) -> syn::Result>> { Ok(match (prev, new) { (Some(p), Some(n)) => Some(Self::merge_attrs(p, n, name)?), (Some(p), None) => Some(p), (None, Some(n)) => Some(n), (None, None) => None, }) } /// Parses this attribute from the provided multiple [`syn::Attribute`]s with the provided /// [`Parser`], merging them, and preserving their [`Span`]. /// /// [`Span`]: proc_macro2::Span fn parse_attrs_with( attrs: impl AsRef<[syn::Attribute]>, name: &syn::Ident, parser: &P, ) -> syn::Result>> { attrs .as_ref() .iter() .filter(|attr| attr.path().is_ident(name)) .try_fold(None, |merged, attr| { let parsed = Spanning::new( Self::parse_attr_with(attr, parser)?, attr.span(), ); if let Some(prev) = merged { Self::merge_attrs(prev, parsed, name).map(Some) } else { Ok(Some(parsed)) } }) } /// Parses this attribute from the provided multiple [`syn::Attribute`]s with the default /// [`Parse`], merging them, and preserving their [`Span`]. /// /// [`Span`]: proc_macro2::Span fn parse_attrs( attrs: impl AsRef<[syn::Attribute]>, name: &syn::Ident, ) -> syn::Result>> { Self::parse_attrs_with(attrs, name, &()) } } impl ParseMultiple for Either { fn parse_attr_with( attr: &syn::Attribute, parser: &P, ) -> syn::Result { L::parse_attr_with(attr, parser) .map(Self::Left) .or_else(|_| R::parse_attr_with(attr, parser).map(Self::Right)) } fn merge_attrs( prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { Ok(match (prev.item, new.item) { (Self::Left(p), Self::Left(n)) => { L::merge_attrs(Spanning::new(p, prev.span), Spanning::new(n, new.span), name)? .map(Self::Left) }, (Self::Right(p), Self::Right(n)) => { R::merge_attrs(Spanning::new(p, prev.span), Spanning::new(n, new.span), name)? .map(Self::Right) }, _ => return Err(syn::Error::new( new.span, format!("only single kind of `#[{name}(...)]` attribute is allowed here"), )) }) } } #[cfg(any( feature = "as_ref", feature = "from", feature = "into", feature = "try_from" ))] mod empty { use syn::{ parse::{Parse, ParseStream}, spanned::Spanned as _, }; use super::{ParseMultiple, Parser, Spanning}; /// Representation of an empty attribute, containing no arguments. /// /// ```rust,ignore /// #[] /// ``` #[derive(Clone, Copy, Debug)] pub(crate) struct Empty; impl Parse for Empty { fn parse(input: ParseStream<'_>) -> syn::Result { if input.is_empty() { Ok(Self) } else { Err(syn::Error::new( input.span(), "no attribute arguments allowed here", )) } } } impl ParseMultiple for Empty { fn parse_attr_with( attr: &syn::Attribute, _: &P, ) -> syn::Result { if matches!(attr.meta, syn::Meta::Path(_)) { Ok(Self) } else { Err(syn::Error::new( attr.span(), "no attribute arguments allowed here", )) } } fn merge_attrs( _prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { Err(syn::Error::new( new.span, format!("only single `#[{name}]` attribute is allowed here"), )) } } } #[cfg(any(feature = "as_ref", feature = "from"))] mod forward { use syn::{ parse::{Parse, ParseStream}, spanned::Spanned as _, }; use super::ParseMultiple; /// Representation of a `forward` attribute. /// /// ```rust,ignore /// #[(forward)] /// ``` #[derive(Clone, Copy, Debug)] pub(crate) struct Forward; impl Parse for Forward { fn parse(input: ParseStream<'_>) -> syn::Result { match input.parse::()? { p if p.is_ident("forward") => Ok(Self), p => Err(syn::Error::new(p.span(), "only `forward` allowed here")), } } } impl ParseMultiple for Forward {} } #[cfg(feature = "try_from")] mod repr_int { use proc_macro2::Span; use syn::parse::{Parse, ParseStream}; use super::{ParseMultiple, Parser, Spanning}; /// Representation of a [`#[repr(u/i*)]` Rust attribute][0]. /// /// **NOTE**: Disregards any non-integer representation `#[repr]`s. /// /// ```rust,ignore /// #[repr()] /// ``` /// /// [0]: https://doc.rust-lang.org/reference/type-layout.html#primitive-representations #[derive(Default)] pub(crate) struct ReprInt(Option); impl ReprInt { /// Returns [`syn::Ident`] of the primitive integer type behind this [`ReprInt`] /// attribute. /// /// If there is no explicitly specified primitive integer type, then returns a /// [default `isize` discriminant][0]. /// /// [`syn::Ident`]: struct@syn::Ident /// [0]: https://doc.rust-lang.org/reference/items/enumerations.html#discriminants pub(crate) fn ty(&self) -> syn::Ident { self.0 .as_ref() .cloned() .unwrap_or_else(|| syn::Ident::new("isize", Span::call_site())) } } impl Parse for ReprInt { fn parse(_: ParseStream<'_>) -> syn::Result { unreachable!("call `attr::ParseMultiple::parse_attr_with()` instead") } } impl ParseMultiple for ReprInt { fn parse_attr_with( attr: &syn::Attribute, _: &P, ) -> syn::Result { let mut repr = None; attr.parse_nested_meta(|meta| { if let Some(ident) = meta.path.get_ident() { if matches!( ident.to_string().as_str(), "u8" | "u16" | "u32" | "u64" | "u128" | "usize" | "i8" | "i16" | "i32" | "i64" | "i128" | "isize" ) { repr = Some(ident.clone()); return Ok(()); } } // Ignore all other attributes that could have a body, e.g. `align`. _ = meta.input.parse::(); Ok(()) })?; Ok(Self(repr)) } fn merge_attrs( prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { match (&prev.item.0, &new.item.0) { (Some(_), None) | (None, None) => Ok(prev), (None, Some(_)) => Ok(new), (Some(_), Some(_)) => Err(syn::Error::new( new.span, format!( "only single `#[{name}(u/i*)]` attribute is expected here", ), )), } } } } #[cfg(any( feature = "as_ref", feature = "debug", feature = "display", feature = "from", feature = "into", ))] mod skip { use syn::{ parse::{Parse, ParseStream}, spanned::Spanned as _, }; use super::{ParseMultiple, Spanning}; /// Representation of a `skip`/`ignore` attribute. /// /// ```rust,ignore /// #[(skip)] /// #[(ignore)] /// ``` #[derive(Clone, Copy, Debug)] pub(crate) struct Skip(&'static str); impl Parse for Skip { fn parse(content: ParseStream<'_>) -> syn::Result { match content.parse::()? { p if p.is_ident("skip") => Ok(Self("skip")), p if p.is_ident("ignore") => Ok(Self("ignore")), p => Err(syn::Error::new( p.span(), "only `skip`/`ignore` allowed here", )), } } } impl Skip { /// Returns the concrete name of this attribute (`skip` or `ignore`). pub(crate) const fn name(&self) -> &'static str { self.0 } } impl ParseMultiple for Skip { fn merge_attrs( _: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { Err(syn::Error::new( new.span, format!( "only single `#[{name}(skip)]`/`#[{name}(ignore)]` attribute is allowed \ here", ), )) } } } #[cfg(any(feature = "as_ref", feature = "from", feature = "try_from"))] mod types { use syn::{ parse::{Parse, ParseStream}, punctuated::Punctuated, Token, }; use super::{ParseMultiple, Spanning}; /// Representation of an attribute, containing a comma-separated list of types. /// /// ```rust,ignore /// #[()] /// ``` pub(crate) struct Types(pub(crate) Punctuated); impl Parse for Types { fn parse(input: ParseStream<'_>) -> syn::Result { input .parse_terminated(syn::Type::parse, Token![,]) .map(Self) } } impl ParseMultiple for Types { fn merge_attrs( mut prev: Spanning, new: Spanning, _: &syn::Ident, ) -> syn::Result> { prev.item.0.extend(new.item.0); Ok(Spanning::new( prev.item, prev.span.join(new.span).unwrap_or(prev.span), )) } } } #[cfg(any(feature = "as_ref", feature = "from"))] mod conversion { use syn::parse::{Parse, ParseStream}; use crate::utils::attr; use super::{Either, ParseMultiple, Spanning}; /// Untyped analogue of a [`Conversion`], recreating its type structure via [`Either`]. /// /// Used to piggyback [`Parse`] and [`ParseMultiple`] impls to [`Either`]. type Untyped = Either; /// Representation of an attribute, specifying which conversions should be generated: /// either forwarded via a blanket impl, or direct for concrete specified types. /// /// ```rust,ignore /// #[(forward)] /// #[()] /// ``` pub(crate) enum Conversion { Forward(attr::Forward), Types(attr::Types), } impl From for Conversion { fn from(v: Untyped) -> Self { match v { Untyped::Left(f) => Self::Forward(f), Untyped::Right(t) => Self::Types(t), } } } impl From for Untyped { fn from(v: Conversion) -> Self { match v { Conversion::Forward(f) => Self::Left(f), Conversion::Types(t) => Self::Right(t), } } } impl Parse for Conversion { fn parse(input: ParseStream<'_>) -> syn::Result { Untyped::parse(input).map(Self::from) } } impl ParseMultiple for Conversion { fn parse_attr_with( attr: &syn::Attribute, parser: &P, ) -> syn::Result { Untyped::parse_attr_with(attr, parser).map(Self::from) } fn merge_attrs( prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { Untyped::merge_attrs(prev.map(Into::into), new.map(Into::into), name) .map(|v| v.map(Self::from)) } } } #[cfg(any(feature = "as_ref", feature = "from"))] mod field_conversion { use syn::parse::{Parse, ParseStream}; use crate::utils::attr; use super::{Either, ParseMultiple, Spanning}; /// Untyped analogue of a [`FieldConversion`], recreating its type structure via [`Either`]. /// /// Used to piggyback [`Parse`] and [`ParseMultiple`] impls to [`Either`]. type Untyped = Either>>; /// Representation of an attribute, specifying which conversions should be generated: /// either forwarded via a blanket impl, or direct for concrete specified types. /// /// ```rust,ignore /// #[] /// #[(skip)] #[(ignore)] /// #[(forward)] /// #[()] /// ``` pub(crate) enum FieldConversion { Empty(attr::Empty), Skip(attr::Skip), Forward(attr::Forward), Types(attr::Types), } impl From for FieldConversion { fn from(v: Untyped) -> Self { match v { Untyped::Left(e) => Self::Empty(e), Untyped::Right(Either::Left(s)) => Self::Skip(s), Untyped::Right(Either::Right(Either::Left(f))) => Self::Forward(f), Untyped::Right(Either::Right(Either::Right(t))) => Self::Types(t), } } } impl From for Untyped { fn from(v: FieldConversion) -> Self { match v { FieldConversion::Empty(e) => Self::Left(e), FieldConversion::Skip(s) => Self::Right(Either::Left(s)), FieldConversion::Forward(f) => { Self::Right(Either::Right(Either::Left(f))) } FieldConversion::Types(t) => { Self::Right(Either::Right(Either::Right(t))) } } } } impl From for FieldConversion { fn from(v: attr::Conversion) -> Self { match v { attr::Conversion::Forward(f) => Self::Forward(f), attr::Conversion::Types(t) => Self::Types(t), } } } impl From for Option { fn from(v: FieldConversion) -> Self { match v { FieldConversion::Forward(f) => Some(attr::Conversion::Forward(f)), FieldConversion::Types(t) => Some(attr::Conversion::Types(t)), FieldConversion::Empty(_) | FieldConversion::Skip(_) => None, } } } impl Parse for FieldConversion { fn parse(input: ParseStream<'_>) -> syn::Result { Untyped::parse(input).map(Self::from) } } impl ParseMultiple for FieldConversion { fn parse_attr_with( attr: &syn::Attribute, parser: &P, ) -> syn::Result { Untyped::parse_attr_with(attr, parser).map(Self::from) } fn merge_attrs( prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { Untyped::merge_attrs(prev.map(Into::into), new.map(Into::into), name) .map(|v| v.map(Self::from)) } } } #[cfg(feature = "try_from")] mod repr_conversion { use syn::parse::{Parse, ParseStream}; use crate::utils::attr; use super::{ParseMultiple, Spanning}; /// Representation of an attribute, specifying which `repr`-conversions should be generated: /// either direct into a discriminant, or for concrete specified types forwarding from a /// discriminant. /// /// ```rust,ignore /// #[(repr)] /// #[(repr())] /// ``` pub(crate) enum ReprConversion { Discriminant(attr::Empty), Types(attr::Types), } impl Parse for ReprConversion { fn parse(input: ParseStream<'_>) -> syn::Result { let prefix = syn::Ident::parse(input)?; if prefix != "repr" { return Err(syn::Error::new( prefix.span(), "expected `repr` argument here", )); } if input.is_empty() { Ok(Self::Discriminant(attr::Empty)) } else { let inner; syn::parenthesized!(inner in input); Ok(Self::Types(attr::Types::parse(&inner)?)) } } } impl ParseMultiple for ReprConversion { fn merge_attrs( prev: Spanning, new: Spanning, name: &syn::Ident, ) -> syn::Result> { Ok(match (prev.item, new.item) { (Self::Discriminant(_), Self::Discriminant(_)) => { return Err(syn::Error::new( new.span, format!("only single `#[{name}(repr)]` attribute is allowed here"), )) }, (Self::Types(p), Self::Types(n)) => { attr::Types::merge_attrs( Spanning::new(p, prev.span), Spanning::new(n, new.span), name, )?.map(Self::Types) }, _ => return Err(syn::Error::new( new.span, format!( "only single kind of `#[{name}(repr(...))]` attribute is allowed here", ), )) }) } } } } #[cfg(any(feature = "from", feature = "into"))] mod fields_ext { use std::{cmp, iter}; use quote::ToTokens as _; use syn::{punctuated, spanned::Spanned as _}; 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 Len for [T] { fn len(&self) -> usize { self.len() } } /// [`syn::Fields`] extension. pub(crate) trait FieldsExt: Len { /// Validates the provided [`syn::Type`] against these [`syn::Fields`]. fn validate_type<'t>( &self, ty: &'t syn::Type, ) -> syn::Result< Either, iter::Once<&'t syn::Type>>, > { match ty { syn::Type::Tuple(syn::TypeTuple { elems, .. }) if self.len() > 1 => { match self.len().cmp(&elems.len()) { cmp::Ordering::Greater => { return Err(syn::Error::new( ty.span(), format!( "wrong tuple length: expected {}, found {}. \ Consider adding {} more type{}: `({})`", self.len(), elems.len(), self.len() - elems.len(), if self.len() - elems.len() > 1 { "s" } else { "" }, elems .iter() .map(|ty| ty.into_token_stream().to_string()) .chain( (0..(self.len() - elems.len())) .map(|_| "_".to_string()) ) .collect::>() .join(", "), ), )); } cmp::Ordering::Less => { return Err(syn::Error::new( ty.span(), format!( "wrong tuple length: expected {}, found {}. \ Consider removing last {} type{}: `({})`", self.len(), elems.len(), elems.len() - self.len(), if elems.len() - self.len() > 1 { "s" } else { "" }, elems .iter() .take(self.len()) .map(|ty| ty.into_token_stream().to_string()) .collect::>() .join(", "), ), )); } cmp::Ordering::Equal => {} } } other if self.len() > 1 => { return Err(syn::Error::new( other.span(), format!( "expected tuple: `({}, {})`", other.into_token_stream(), (0..(self.len() - 1)) .map(|_| "_") .collect::>() .join(", "), ), )); } _ => {} } Ok(match ty { syn::Type::Tuple(syn::TypeTuple { elems, .. }) => { Either::Left(elems.iter()) } other => Either::Right(iter::once(other)), }) } } impl FieldsExt for T {} } #[cfg(feature = "as_ref")] mod generics_search { use syn::visit::Visit; use super::HashSet; /// Search of whether some generics (type parameters, lifetime parameters or const parameters) /// are present in some [`syn::Type`]. pub(crate) struct GenericsSearch<'s> { /// Type parameters to look for. pub(crate) types: HashSet<&'s syn::Ident>, /// Lifetime parameters to look for. pub(crate) lifetimes: HashSet<&'s syn::Ident>, /// Const parameters to look for. pub(crate) consts: HashSet<&'s syn::Ident>, } impl<'s> GenericsSearch<'s> { /// Checks the provided [`syn::Type`] to contain anything from this [`GenericsSearch`]. pub(crate) fn any_in(&self, ty: &syn::Type) -> bool { let mut visitor = Visitor { search: self, found: false, }; visitor.visit_type(ty); visitor.found } } /// [`Visit`]or performing a [`GenericsSearch`]. struct Visitor<'s> { /// [`GenericsSearch`] parameters. search: &'s GenericsSearch<'s>, /// Indication whether anything was found for the [`GenericsSearch`] parameters. found: bool, } impl<'s, 'ast> Visit<'ast> for Visitor<'s> { fn visit_type_path(&mut self, tp: &'ast syn::TypePath) { self.found |= tp.path.get_ident().map_or(false, |ident| { self.search.types.contains(ident) || self.search.consts.contains(ident) }); syn::visit::visit_type_path(self, tp) } fn visit_lifetime(&mut self, lf: &'ast syn::Lifetime) { self.found |= self.search.lifetimes.contains(&lf.ident); syn::visit::visit_lifetime(self, lf) } fn visit_expr_path(&mut self, ep: &'ast syn::ExprPath) { self.found |= ep .path .get_ident() .map_or(false, |ident| self.search.consts.contains(ident)); syn::visit::visit_expr_path(self, ep) } } }