diff options
Diffstat (limited to '')
106 files changed, 10562 insertions, 0 deletions
diff --git a/third_party/rust/darling/.cargo-checksum.json b/third_party/rust/darling/.cargo-checksum.json new file mode 100644 index 0000000000..95e0a2c976 --- /dev/null +++ b/third_party/rust/darling/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"5862340ae98a5452baa54c9bae0434e599321ebf759777a637e67ecd8171bc58","Cargo.lock":"358e47f965ed7e98e7aa4612797847896554ea8684c9e9efdfdb29f565897ea5","Cargo.toml":"7ff906016df3aaecb24b6a7458f2c0b0fa9de338dc817d1e31262a1f9a32c6bf","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","README.md":"70cae7eea991c6920322227d97d1062ed077b59fc5498cc3c9437f1f013030a9","clippy.toml":"0427eea1ddcf872469d073864d37b89728232ff7eb77e0e07f62d7eb1bc8667c","examples/automatic_bounds.rs":"2950c8d33bb40f095decba1990d7d0bcd48dffc6e9b7cefce2fcb3818ecf1d18","examples/consume_fields.rs":"ce436936441f1f6734f47074e6625ebf64f15180b9c126a58e24aaa33613b59c","examples/fallible_read.rs":"1e5f2b69e436d899209dc8a4deec0dbe3e998f10a6632a79c0876c46f68267b4","examples/shorthand_or_long_field.rs":"ec2e2b155fd0803c80f98d0ba94e8419dd7307012ccfb916b8f752925a295d55","examples/supports_struct.rs":"08c5cc46400a0e5cf811c0d254a37b42de94b34cd04ac801069105bc792051f6","src/lib.rs":"0bc8addcbfe6ca39df122ee73b13d91d5622acd37c5241f145332fe7e5b01d01","src/macros_public.rs":"7d2ce0c5026227ef7854db11d7a885ad891255438b2e49bbdfda56fa2f92feec","tests/accrue_errors.rs":"4f0f5be65c5cd639b107a6a14e9fb51573b27cfa9210a2182fa5f450bc1d56db","tests/computed_bound.rs":"aed9c00f2b8373e9426337137207e5b9341d236adef682bd2c9427db9ce1d1ff","tests/custom_bound.rs":"9b823063b7fc6c6b3b23905405ce7f316e8a937d5c67c416b89642e537bf9110","tests/defaults.rs":"6894fded24b2f9d173b11f54bbe3b640946c6eb6f5ff5492369e8cd84fc217ef","tests/enums_newtype.rs":"ed63735b88fdfd9037580d878be895a311c13d7d8083ee3077f5ab61e754eb7c","tests/enums_struct.rs":"36ca3d4996644d566b45c78d8c343c4a74fcaa2eba96b4e012c8a1819eb6f4c6","tests/enums_unit.rs":"7f94f793e6adc265c6cdc4b657aa237da1ab0be03b03bce23d3e2180cd3e8d03","tests/error.rs":"f5f84991472e184e1167f0fe8d5f2cbad3844c4022987c9eff46b4db2bcc804a","tests/from_generics.rs":"f2c1f98f654c4e6ad3606d7b12ea7ea66782950c05da132e8d7f2f7e1bdf3af0","tests/from_meta.rs":"b9c73340c44a53a43d7234c6030d37d1ab7c63ea2ec2ae1f7f09e5f2d65baa6b","tests/from_type_param.rs":"94d2766d5ae11d69750497225d6aa3c2f34b09fbc8c3580d61f077d7bb41265b","tests/from_type_param_default.rs":"e00e2f0c779753f66b95e5c0106451f65cbd6fbc28e676381d276290da6254b6","tests/from_variant.rs":"48046b156f6c5d9b3e9c3d0b36b5eebaba1d417447e3babf81ed9c74bee3bfcb","tests/generics.rs":"0c2830acf511148d71ecd4a8b5aa17f80e377aa89f7fe0fc10f6db34671d034a","tests/happy_path.rs":"c7a540fc1755cef757aa5e6cd202a49a47a2040facb0c05c167ec62f8ebbc557","tests/hash_map.rs":"c30764bf1845ca81bc1d752dbe0de965ba70cfbb1571884a20a873ed7bf26360","tests/multiple.rs":"1362ec057f4796ffabf7161033b561b51f069b818af7bac85fe66935c62038dd","tests/newtype.rs":"b5ecf605652b194372cab6d6fef96a2dd4b63ac24649cb52ca944ef9647512ad","tests/skip.rs":"11b5f190d6eac837d4a44a7dedd1ba9e623b0c7a8bf2bdc92882e1f8a8d2aeac","tests/split_declaration.rs":"019863370414af227144aac13272fc39a1e256a9ed0bd3ca2dbf1114f1a9e1ba","tests/suggestions.rs":"e9f8ab55718a5853411a4606f1be1473b57fc7a2789f622d0ed807fcd8ac5606","tests/supports.rs":"fd27b20893a1b1078eff077d426fea7d715b8decd12ad1e0b940cfbfd4fbbfba","tests/unsupported_attributes.rs":"96333cd6602a6f18f47563d5faa923e423b2c02f2ae0d09a15e2d3514593c38d"},"package":"b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa"}
\ No newline at end of file diff --git a/third_party/rust/darling/CHANGELOG.md b/third_party/rust/darling/CHANGELOG.md new file mode 100644 index 0000000000..f4009a23ab --- /dev/null +++ b/third_party/rust/darling/CHANGELOG.md @@ -0,0 +1,218 @@ +# Changelog + +## v0.14.2 (October 26, 2022) + +- Derived impls of `FromMeta` will now error on literals, rather than silently ignoring them. [#193](https://github.com/TedDriggs/darling/pull/193) +- Don't include property paths in compile errors when spans are available. [#203](https://github.com/TedDriggs/darling/pull/203) + +## v0.14.1 (April 28, 2022) + +- Fix a bug where using a trait that accepts `#[darling(attributes(...))]` without specifying any attributes would emit code that did not compile. [#183](https://github.com/TedDriggs/darling/issues/183) +- Impl `Clone` for `darling::Error` [#184](https://github.com/TedDriggs/darling/pull/184) +- Impl `From<darling::Error> for syn::Error` [#184](https://github.com/TedDriggs/darling/pull/184) +- Add `Error::span` and `Error::explicit_span` methods [#184](https://github.com/TedDriggs/darling/pull/184) + +## v0.14.0 (April 13, 2022) + +- **BREAKING CHANGE:** Remove many trait impls from `util::Flag`. + This type had a number of deref and operator impls that made it usable as sort-of-a-boolean. + Real-world usage showed this type is more useful if it's able to carry a span for good errors, + and that most of those impls were unnecessary. [#179](https://github.com/TedDriggs/darling/pull/179) +- Remove need for `#[darling(default)]` on `Option<T>` and `Flag` fields [#161](https://github.com/TedDriggs/darling/issues/161) +- Improve validation of enum shapes [#178](https://github.com/TedDriggs/darling/pull/178) +- Bump `proc-macro2` dependency to 1.0.37 [#180](https://github.com/TedDriggs/darling/pull/180) +- Bump `quote` dependency to 1.0.18 [#180](https://github.com/TedDriggs/darling/pull/180) +- Bump `syn` dependency to 1.0.91 [#180](https://github.com/TedDriggs/darling/pull/180) + +## v0.13.4 (April 6, 2022) + +- Impl `FromMeta` for `syn::Visibility` [#173](https://github.com/TedDriggs/darling/pull/173) + +## v0.13.3 (April 5, 2022) + +- Add `error::Accumulator` for dealing with multiple errors [#164](https://github.com/TedDriggs/darling/pull/164) +- Impl `FromMeta` for `syn::Type` and its variants [#172](https://github.com/TedDriggs/darling/pulls/172) + +## v0.13.2 (March 30, 2022) + +- Impl `FromMeta` for `syn::ExprPath` [#169](https://github.com/TedDriggs/darling/issues/169) + +## v0.13.1 (December 7, 2021) + +- Add `FromAttributes` trait and macro [#151](https://github.com/TedDriggs/darling/issues/151) + +## v0.13.0 (May 20, 2021) + +- Update darling to 2018 edition [#129](https://github.com/TedDriggs/darling/pull/129) +- Error on duplicate fields in `#[darling(...)]` attributes [#130](https://github.com/TedDriggs/darling/pull/130) +- Impl `Copy` for `SpannedValue<T: Copy>` +- Add `SpannedValue::map_ref` + +## v0.13.0-beta (April 20, 2021) + +- Update darling to 2018 edition [#129](https://github.com/TedDriggs/darling/pull/129) +- Error on duplicate fields in `#[darling(...)]` attributes [#130](https://github.com/TedDriggs/darling/pull/130) + +## v0.12.4 (April 20, 2021) + +- Add `and_then` to derive macros for `darling` + +## v0.12.3 (April 8, 2021) + +- Fix `FromMeta` impl for `char` not to panic [#126](https://github.com/TedDriggs/darling/pull/126) + +## v0.12.2 (February 23, 2021) + +- Impl `FromMeta` for `HashMap<Ident, V>` and `HashMap<Path, V>` + +## v0.12.1 (February 22, 2021) + +- Impl `FromMeta` for `syn::ExprArray` [#122](https://github.com/TedDriggs/darling/pull/122) +- Remove use of `unreachable` from `darling::ast::Data` [#123](https://github.com/TedDriggs/darling/pull/123) +- Add `darling::ast::Data::try_empty_from` to avoid panics when trying to read a union body [#123](https://github.com/TedDriggs/darling/pull/123) + +## v0.12.0 (January 5, 2021) + +- POSSIBLY BREAKING: Derived impls of `FromDeriveInput`, `FromField`, `FromVariant`, and `FromTypeParam` will now error when encountering an attribute `darling` has been asked to parse that isn't a supported shape. + Any crates using `darling` that relied on those attributes being silently ignored could see new errors reported in their dependent crates. [#113](https://github.com/TedDriggs/darling/pull/113) +- Impl `syn::spanned::Spanned` for `darling::util::SpannedValue` [#113](https://github.com/TedDriggs/darling/pull/113) +- Add `darling::util::parse_attribute_to_meta_list` to provide useful errors during attribute parsing [#113](https://github.com/TedDriggs/darling/pull/113) +- Add `impl From<syn::Error> for Error` to losslessly propagate `syn` errors [#116](https://github.com/TedDriggs/darling/pull/116) + +## v0.11.0 (December 14, 2020) + +- Bump minor version due to unexpected breaking change [#107](https://github.com/TedDriggs/darling/issues/107) + +## v0.10.3 (December 10, 2020) + +- Add `discriminant` magic field when deriving `FromVariant` [#105](https://github.com/TedDriggs/darling/pull/105) + +## v0.10.2 (October 30, 2019) + +- Bump syn dependency to 1.0.1 [#83](https://github.com/TedDriggs/darling/pull/83) + +## v0.10.1 (September 25, 2019) + +- Fix test compilation errors [#81](https://github.com/TedDriggs/darling/pull/81) + +## v0.10.0 (August 15, 2019) + +- Bump syn and quote to 1.0 [#79](https://github.com/TedDriggs/darling/pull/79) +- Increase rust version to 1.31 + +## v0.9.0 (March 20, 2019) + +- Enable "did you mean" suggestions by default +- Make `darling_core::{codegen, options}` private [#58](https://github.com/TedDriggs/darling/issues/58) +- Fix `Override::as_mut`: [#66](https://github.com/TedDriggs/darling/issues/66) + +## v0.8.6 (March 18, 2019) + +- Added "did you mean" suggestions for unknown fields behind the `suggestions` flag [#60](https://github.com/TedDriggs/issues/60) +- Added `Error::unknown_field_with_alts` to support the suggestion use-case. +- Added `ast::Fields::len` and `ast::Fields::is_empty` methods. + +## v0.8.5 (February 4, 2019) + +- Accept unquoted positive numeric literals [#52](https://github.com/TedDriggs/issues/52) +- Add `FromMeta` to the `syn::Lit` enum and its variants +- Improve error message for unexpected literal formats to not say "other" + +## v0.8.4 (February 4, 2019) + +- Use `syn::Error` to provide precise errors before `proc_macro::Diagnostic` is available +- Add `diagnostics` feature flag to toggle between stable and unstable error backends +- Attach error information in more contexts +- Add `allow_unknown_fields` to support parsing the same attribute multiple times for different macros [#51](https://github.com/darling/issues/51) +- Proc-macro authors will now see better errors in `darling` attributes + +## v0.8.3 (January 21, 2019) + +- Attach spans to errors in generated trait impls [#37](https://github.com/darling/issues/37) +- Attach spans to errors for types with provided bespoke implementations +- Deprecate `set_span` from 0.8.2, as spans should never be broadened after being initially set + +## v0.8.2 (January 17, 2019) + +- Add spans to errors to make quality warnings and errors easy in darling. This is blocked on diagnostics stabilizing. +- Add `darling::util::SpannedValue` so proc-macro authors can remember position information alongside parsed values. + +## v0.8.0 + +- Update dependency on `syn` to 0.15 [#44](https://github.com/darling/pull/44). Thanks to @hcpl + +## v0.7.0 (July 24, 2018) + +- Update dependencies on `syn` and `proc-macro2` +- Add `util::IdentString`, which acts as an Ident or its string equivalent + +## v0.6.3 (May 22, 2018) + +- Add support for `Uses*` traits in where predicates + +## v0.6.2 (May 22, 2018) + +- Add `usage` module for tracking type param and lifetime usage in generic declarations + - Add `UsesTypeParams` and `CollectsTypeParams` traits [#37](https://github.com/darling/issues/37) + - Add `UsesLifetimes` and `CollectLifetimes` traits [#41](https://github.com/darling/pull/41) +- Don't add `FromMeta` bounds to type parameters only used by skipped fields [#40](https://github.com/darling/pull/40) + +## v0.6.1 (May 17, 2018) + +- Fix an issue where the `syn` update broke shape validation [#36](https://github.com/TedDriggs/darling/issues/36) + +## v0.6.0 (May 15, 2018) + +### Breaking Changes + +- Renamed `FromMetaItem` to `FromMeta`, and renamed `from_meta_item` method to `from_meta` +- Added dedicated `derive(FromMetaItem)` which panics and redirects users to `FromMeta` + +## v0.5.0 (May 10, 2018) + +- Add `ast::Generics` and `ast::GenericParam` to work with generics in a manner similar to `ast::Data` +- Add `ast::GenericParamExt` to support alternate representations of generic parameters +- Add `util::WithOriginal` to get a parsed representation and syn's own struct for a syntax block +- Add `FromGenerics` and `FromGenericParam` traits (without derive support) +- Change generated code for `generics` magic field to invoke `FromGenerics` trait during parsing +- Add `FromTypeParam` trait [#30](https://github.com/TedDriggs/darling/pull/30). Thanks to @upsuper + +## v0.4.0 (April 5, 2018) + +- Update dependencies on `proc-macro`, `quote`, and `syn` [#26](https://github.com/TedDriggs/darling/pull/26). Thanks to @hcpl + +## v0.3.3 (April 2, 2018) + +**YANKED** + +## v0.3.2 (March 13, 2018) + +- Derive `Default` on `darling::Ignored` (fixes [#25](https://github.com/TedDriggs/darling/issues/25)). + +## v0.3.1 (March 7, 2018) + +- Support proc-macro2/nightly [#24](https://github.com/TedDriggs/darling/pull/24). Thanks to @kdy1 + +## v0.3.0 (January 26, 2018) + +### Breaking Changes + +- Update `syn` to 0.12 [#20](https://github.com/TedDriggs/darling/pull/20). Thanks to @Eijebong +- Update `quote` to 0.4 [#20](https://github.com/TedDriggs/darling/pull/20). Thanks to @Eijebong +- Rename magic field `body` in derived `FromDeriveInput` structs to `data` to stay in sync with `syn` +- Rename magic field `data` in derived `FromVariant` structs to `fields` to stay in sync with `syn` + +## v0.2.2 (December 5, 2017) + +- Update `lazy_static` to 1.0 [#15](https://github.com/TedDriggs/darling/pull/16). Thanks to @Eijebong + +## v0.2.1 (November 28, 2017) + +- Add `impl FromMetaItem` for integer types [#15](https://github.com/TedDriggs/darling/pull/15) + +## v0.2.0 (June 18, 2017) + +- Added support for returning multiple errors from parsing [#5](https://github.com/TedDriggs/darling/pull/5) +- Derived impls no longer return on first error [#5](https://github.com/TedDriggs/darling/pull/5) +- Removed default types for `V` and `F` from `ast::Body` +- Enum variants are automatically converted to snake_case [#12](https://github.com/TedDriggs/darling/pull/12) diff --git a/third_party/rust/darling/Cargo.lock b/third_party/rust/darling/Cargo.lock new file mode 100644 index 0000000000..622df35bb6 --- /dev/null +++ b/third_party/rust/darling/Cargo.lock @@ -0,0 +1,92 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "darling" +version = "0.14.2" +dependencies = [ + "darling_core", + "darling_macro", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling_core" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/third_party/rust/darling/Cargo.toml b/third_party/rust/darling/Cargo.toml new file mode 100644 index 0000000000..71cf827dc6 --- /dev/null +++ b/third_party/rust/darling/Cargo.toml @@ -0,0 +1,52 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "darling" +version = "0.14.2" +authors = ["Ted Driggs <ted.driggs@outlook.com>"] +exclude = [ + "/.travis.yml", + "/publish.sh", + "/.github/**", +] +description = """ +A proc-macro library for reading attributes into structs when +implementing custom derives. +""" +documentation = "https://docs.rs/darling/0.14.2" +readme = "README.md" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" + +[dependencies.darling_core] +version = "=0.14.2" + +[dependencies.darling_macro] +version = "=0.14.2" + +[dev-dependencies.proc-macro2] +version = "1.0.37" + +[dev-dependencies.quote] +version = "1.0.18" + +[dev-dependencies.syn] +version = "1.0.91" + +[features] +default = ["suggestions"] +diagnostics = ["darling_core/diagnostics"] +suggestions = ["darling_core/suggestions"] + +[badges.maintenance] +status = "actively-developed" diff --git a/third_party/rust/darling/LICENSE b/third_party/rust/darling/LICENSE new file mode 100644 index 0000000000..0b48eadc9d --- /dev/null +++ b/third_party/rust/darling/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Ted Driggs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/darling/README.md b/third_party/rust/darling/README.md new file mode 100644 index 0000000000..fa66e238ad --- /dev/null +++ b/third_party/rust/darling/README.md @@ -0,0 +1,115 @@ +Darling +======= + +[![Build Status](https://github.com/TedDriggs/darling/workflows/CI/badge.svg)](https://github.com/TedDriggs/darling/actions) +[![Latest Version](https://img.shields.io/crates/v/darling.svg)](https://crates.io/crates/darling) +[![Rustc Version 1.31+](https://img.shields.io/badge/rustc-1.31+-lightgray.svg)](https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html) + +`darling` is a crate for proc macro authors, which enables parsing attributes into structs. It is heavily inspired by `serde` both in its internals and in its API. + +# Benefits +* Easy and declarative parsing of macro input - make your proc-macros highly controllable with minimal time investment. +* Great validation and errors, no work required. When users of your proc-macro make a mistake, `darling` makes sure they get error markers at the right place in their source, and provides "did you mean" suggestions for misspelled fields. + +# Usage +`darling` provides a set of traits which can be derived or manually implemented. + +1. `FromMeta` is used to extract values from a meta-item in an attribute. Implementations are likely reusable for many libraries, much like `FromStr` or `serde::Deserialize`. Trait implementations are provided for primitives, some std types, and some `syn` types. +2. `FromDeriveInput` is implemented or derived by each proc-macro crate which depends on `darling`. This is the root for input parsing; it gets access to the identity, generics, and visibility of the target type, and can specify which attribute names should be parsed or forwarded from the input AST. +3. `FromField` is implemented or derived by each proc-macro crate which depends on `darling`. Structs deriving this trait will get access to the identity (if it exists), type, and visibility of the field. +4. `FromVariant` is implemented or derived by each proc-macro crate which depends on `darling`. Structs deriving this trait will get access to the identity and contents of the variant, which can be transformed the same as any other `darling` input. +5. `FromAttributes` is a lower-level version of the more-specific `FromDeriveInput`, `FromField`, and `FromVariant` traits. Structs deriving this trait get a meta-item extractor and error collection which works for any syntax element, including traits, trait items, and functions. This is useful for non-derive proc macros. + +## Additional Modules +* `darling::ast` provides generic types for representing the AST. +* `darling::usage` provides traits and functions for determining where type parameters and lifetimes are used in a struct or enum. +* `darling::util` provides helper types with special `FromMeta` implementations, such as `IdentList`. + +# Example + +```rust,ignore +#[macro_use] +extern crate darling; +extern crate syn; + +#[derive(Default, FromMeta)] +#[darling(default)] +pub struct Lorem { + #[darling(rename = "sit")] + ipsum: bool, + dolor: Option<String>, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(my_crate), forward_attrs(allow, doc, cfg))] +pub struct MyTraitOpts { + ident: syn::Ident, + attrs: Vec<syn::Attribute>, + lorem: Lorem, +} +``` + +The above code will then be able to parse this input: + +```rust,ignore +/// A doc comment which will be available in `MyTraitOpts::attrs`. +#[derive(MyTrait)] +#[my_crate(lorem(dolor = "Hello", sit))] +pub struct ConsumingType; +``` + +# Attribute Macros +Non-derive attribute macros are supported. +To parse arguments for attribute macros, derive `FromMeta` on the argument receiver type, then pass `&syn::AttributeArgs` to the `from_list` method. +This will produce a normal `darling::Result<T>` that can be used the same as a result from parsing a `DeriveInput`. + +## Macro Code +```rust,ignore +use darling::FromMeta; +use syn::{AttributeArgs, ItemFn}; +use proc_macro::TokenStream; + +#[derive(Debug, FromMeta)] +pub struct MacroArgs { + #[darling(default)] + timeout_ms: Option<u16>, + path: String, +} + +#[proc_macro_attribute] +fn your_attr(args: TokenStream, input: TokenStream) -> TokenStream { + let attr_args = parse_macro_input!(args as AttributeArgs); + let _input = parse_macro_input!(input as ItemFn); + + let _args = match MacroArgs::from_list(&attr_args) { + Ok(v) => v, + Err(e) => { return TokenStream::from(e.write_errors()); } + }; + + // do things with `args` + unimplemented!() +} +``` + +## Consuming Code +```rust,ignore +use your_crate::your_attr; + +#[your_attr(path = "hello", timeout_ms = 15)] +fn do_stuff() { + println!("Hello"); +} +``` + +# Features +Darling's features are built to work well for real-world projects. + +* **Defaults**: Supports struct- and field-level defaults, using the same path syntax as `serde`. + Additionally, `Option<T>` and `darling::util::Flag` fields are innately optional; you don't need to declare `#[darling(default)]` for those. +* **Field Renaming**: Fields can have different names in usage vs. the backing code. +* **Auto-populated fields**: Structs deriving `FromDeriveInput` and `FromField` can declare properties named `ident`, `vis`, `ty`, `attrs`, and `generics` to automatically get copies of the matching values from the input AST. `FromDeriveInput` additionally exposes `data` to get access to the body of the deriving type, and `FromVariant` exposes `fields`. +* **Mapping function**: Use `#[darling(map="path")]` or `#[darling(and_then="path")]` to specify a function that runs on the result of parsing a meta-item field. This can change the return type, which enables you to parse to an intermediate form and convert that to the type you need in your struct. +* **Skip fields**: Use `#[darling(skip)]` to mark a field that shouldn't be read from attribute meta-items. +* **Multiple-occurrence fields**: Use `#[darling(multiple)]` on a `Vec` field to allow that field to appear multiple times in the meta-item. Each occurrence will be pushed into the `Vec`. +* **Span access**: Use `darling::util::SpannedValue` in a struct to get access to that meta item's source code span. This can be used to emit warnings that point at a specific field from your proc macro. In addition, you can use `darling::Error::write_errors` to automatically get precise error location details in most cases. +* **"Did you mean" suggestions**: Compile errors from derived darling trait impls include suggestions for misspelled fields. diff --git a/third_party/rust/darling/clippy.toml b/third_party/rust/darling/clippy.toml new file mode 100644 index 0000000000..830589baba --- /dev/null +++ b/third_party/rust/darling/clippy.toml @@ -0,0 +1,2 @@ +msrv = "1.31.0" +blacklisted-names = [] # we want to be able to use placeholder names in tests
\ No newline at end of file diff --git a/third_party/rust/darling/examples/automatic_bounds.rs b/third_party/rust/darling/examples/automatic_bounds.rs new file mode 100644 index 0000000000..8312afed4c --- /dev/null +++ b/third_party/rust/darling/examples/automatic_bounds.rs @@ -0,0 +1,73 @@ +use darling::{FromDeriveInput, FromMeta}; + +#[derive(FromMeta, PartialEq, Eq, Debug)] +enum Volume { + Whisper, + Talk, + Shout, +} + +/// A more complex example showing the ability to skip at a field or struct +/// level while still tracking which type parameters need to be bounded. +/// This can be seen by expanding this example using `cargo expand`. +#[derive(FromMeta)] +#[allow(dead_code)] +enum Emphasis<T> { + Constant(Volume), + Variable(darling::util::PathList), + #[darling(skip)] + PerPhoneme(Option<T>), + Strided { + #[darling(skip)] + step: Vec<T>, + #[darling(multiple)] + volume: Vec<Volume>, + }, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +struct SpeakingOptions<T, U> { + max_volume: U, + #[darling(skip, default)] + additional_data: Vec<T>, +} + +#[derive(Default)] +struct Phoneme { + #[allow(dead_code)] + first: String, +} + +// This is probably the holy grail for `darling`'s own internal use-case: +// Auto-apply `Default` bound to skipped *field* types in `where` clause. +impl<T, U> Default for SpeakingOptions<T, U> +where + Vec<T>: Default, + U: Default, +{ + fn default() -> Self { + Self { + max_volume: Default::default(), + additional_data: Default::default(), + } + } +} + +fn main() { + let derive_input = syn::parse_str( + r#" + #[derive(Speak)] + #[speak(max_volume = "shout")] + enum HtmlElement { + Div(String) + } + "#, + ) + .unwrap(); + + let parsed: SpeakingOptions<Phoneme, Volume> = + FromDeriveInput::from_derive_input(&derive_input).unwrap(); + assert_eq!(parsed.max_volume, Volume::Shout); + assert_eq!(parsed.additional_data.len(), 0); +} diff --git a/third_party/rust/darling/examples/consume_fields.rs b/third_party/rust/darling/examples/consume_fields.rs new file mode 100644 index 0000000000..f5cd435b90 --- /dev/null +++ b/third_party/rust/darling/examples/consume_fields.rs @@ -0,0 +1,175 @@ +// The use of fields in debug print commands does not count as "used", +// which causes the fields to trigger an unwanted dead code warning. +#![allow(dead_code)] + +//! This example shows how to do struct and field parsing using darling. + +use darling::{ast, FromDeriveInput, FromField, FromMeta}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::parse_str; + +/// A speaking volume. Deriving `FromMeta` will cause this to be usable +/// as a string value for a meta-item key. +#[derive(Debug, Clone, Copy, FromMeta)] +#[darling(default)] +enum Volume { + Normal, + Whisper, + Shout, +} + +impl Default for Volume { + fn default() -> Self { + Volume::Normal + } +} + +/// Support parsing from a full derive input. Unlike FromMeta, this isn't +/// composable; each darling-dependent crate should have its own struct to handle +/// when its trait is derived. +#[derive(Debug, FromDeriveInput)] +// This line says that we want to process all attributes declared with `my_trait`, +// and that darling should panic if this receiver is given an enum. +#[darling(attributes(my_trait), supports(struct_any))] +struct MyInputReceiver { + /// The struct ident. + ident: syn::Ident, + + /// The type's generics. You'll need these any time your trait is expected + /// to work with types that declare generics. + generics: syn::Generics, + + /// Receives the body of the struct or enum. We don't care about + /// struct fields because we previously told darling we only accept structs. + data: ast::Data<(), MyFieldReceiver>, + + /// The Input Receiver demands a volume, so use `Volume::Normal` if the + /// caller doesn't provide one. + #[darling(default)] + volume: Volume, +} + +impl ToTokens for MyInputReceiver { + fn to_tokens(&self, tokens: &mut TokenStream) { + let MyInputReceiver { + ref ident, + ref generics, + ref data, + volume, + } = *self; + + let (imp, ty, wher) = generics.split_for_impl(); + let fields = data + .as_ref() + .take_struct() + .expect("Should never be enum") + .fields; + + // Generate the format string which shows each field and its name + let fmt_string = fields + .iter() + .enumerate() + .map(|(i, f)| { + // We have to preformat the ident in this case so we can fall back + // to the field index for unnamed fields. It's not easy to read, + // unfortunately. + format!( + "{} = {{}}", + f.ident + .as_ref() + .map(|v| format!("{}", v)) + .unwrap_or_else(|| format!("{}", i)) + ) + }) + .collect::<Vec<_>>() + .join(", "); + + // Generate the actual values to fill the format string. + let field_list = fields + .into_iter() + .enumerate() + .map(|(i, f)| { + let field_volume = f.volume.unwrap_or(volume); + + // This works with named or indexed fields, so we'll fall back to the index so we can + // write the output as a key-value pair. + let field_ident = f.ident + .as_ref() + .map(|v| quote!(#v)) + .unwrap_or_else(|| { + let i = syn::Index::from(i); + quote!(#i) + }); + + match field_volume { + Volume::Normal => quote!(self.#field_ident), + Volume::Shout => { + quote!(::std::string::ToString::to_string(&self.#field_ident).to_uppercase()) + } + Volume::Whisper => { + quote!(::std::string::ToString::to_string(&self.#field_ident).to_lowercase()) + } + } + }) + .collect::<Vec<_>>(); + + tokens.extend(quote! { + impl #imp Speak for #ident #ty #wher { + fn speak(&self, writer: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(writer, #fmt_string, #(#field_list),*) + } + } + }); + } +} + +#[derive(Debug, FromField)] +#[darling(attributes(my_trait))] +struct MyFieldReceiver { + /// Get the ident of the field. For fields in tuple or newtype structs or + /// enum bodies, this can be `None`. + ident: Option<syn::Ident>, + + /// This magic field name pulls the type from the input. + ty: syn::Type, + + /// We declare this as an `Option` so that during tokenization we can write + /// `field.volume.unwrap_or(derive_input.volume)` to facilitate field-level + /// overrides of struct-level settings. + /// + /// Because this field is an `Option`, we don't need to include `#[darling(default)]` + volume: Option<Volume>, +} + +fn main() { + let input = r#"#[derive(MyTrait)] +#[my_trait(volume = "shout")] +pub struct Foo { + #[my_trait(volume = "whisper")] + bar: bool, + + baz: i64, +}"#; + + let parsed = parse_str(input).unwrap(); + let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); + let tokens = quote!(#receiver); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + +EMITS: + +{} + "#, + input, receiver, tokens + ); +} diff --git a/third_party/rust/darling/examples/fallible_read.rs b/third_party/rust/darling/examples/fallible_read.rs new file mode 100644 index 0000000000..850465e82d --- /dev/null +++ b/third_party/rust/darling/examples/fallible_read.rs @@ -0,0 +1,85 @@ +//! This example demonstrates techniques for performing custom error handling +//! in a derive-input receiver. +//! +//! 1. Using `darling::Result` as a carrier to preserve the error for later display +//! 1. Using `Result<T, syn::Meta>` to attempt a recovery in imperative code +//! 1. Using the `map` darling meta-item to post-process a field before returning +//! 1. Using the `and_then` darling meta-item to post-process the receiver before returning + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_str; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(my_trait), and_then = "MyInputReceiver::autocorrect")] +pub struct MyInputReceiver { + /// This field must be present and a string or else parsing will panic. + #[darling(map = "MyInputReceiver::make_string_shouty")] + name: String, + + /// If this field fails to parse, the struct can still be built; the field + /// will contain the error. The consuming struct can then decide if this + /// blocks code generation. If so, panic or fail in `and_then`. + frequency: darling::Result<i64>, + + /// If this field fails to parse, the struct can still be built; the field + /// will contain an `Err` with the original `syn::Meta`. This can be used + /// for alternate parsing attempts before panicking. + amplitude: Result<u64, syn::Meta>, +} + +impl MyInputReceiver { + /// This function will be called by `darling` _after_ it's finished parsing the + /// `name` field but before initializing `name` with the resulting value. It's + /// a good place for transforms that are easiest to express on already-built + /// types. + fn make_string_shouty(s: String) -> String { + s.to_uppercase() + } + + /// This function will be called by `darling` _after_ it's finished parsing the + /// input but before returning to the caller. This is a good place to initialize + /// skipped fields or to perform corrections that don't lend themselves to being + /// done elsewhere. + fn autocorrect(self) -> darling::Result<Self> { + let Self { + name, + frequency, + amplitude, + } = self; + + // Amplitude doesn't have a sign, so if we received a negative number then + // we'll go ahead and make it positive. + let amplitude = match amplitude { + Ok(amp) => amp, + Err(mi) => (i64::from_meta(&mi)?).abs() as u64, + }; + + Ok(Self { + name, + frequency, + amplitude: Ok(amplitude), + }) + } +} + +fn main() { + let input = r#"#[derive(MyTrait)] +#[my_trait(name="Jon", amplitude = "-1", frequency = 1)] +pub struct Foo;"#; + + let parsed = parse_str(input).unwrap(); + let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + "#, + input, receiver + ); +} diff --git a/third_party/rust/darling/examples/shorthand_or_long_field.rs b/third_party/rust/darling/examples/shorthand_or_long_field.rs new file mode 100644 index 0000000000..750d83efbc --- /dev/null +++ b/third_party/rust/darling/examples/shorthand_or_long_field.rs @@ -0,0 +1,79 @@ +//! Example showing potentially-nested meta item parsing with `darling::util::Override`. +//! +//! Based on https://stackoverflow.com/q/68046070/86381 by https://github.com/peterjoel + +// The use of fields in debug print commands does not count as "used", +// which causes the fields to trigger an unwanted dead code warning. +#![allow(dead_code)] + +use std::borrow::Cow; + +use darling::{util::Override, FromDeriveInput, FromMeta}; +use syn::{Ident, Path}; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(myderive))] +struct MyDeriveInput { + ident: Ident, + /// We can infer the right "table" behavior for this derive, but we want the caller to be + /// explicit that they're expecting the inference behavior to avoid cluttering some hypothetical + /// database. Therefore this field is required, but can take word form or key-value form. + /// + /// To make this field optional, we could add `#[darling(default)]`, or we could + /// wrap it in `Option` if the presence or absence of the word makes a difference. + table: Override<Table>, +} + +impl MyDeriveInput { + fn table(&self) -> Cow<'_, Table> { + match &self.table { + Override::Explicit(value) => Cow::Borrowed(value), + Override::Inherit => Cow::Owned(Table { + name: self.ident.to_string(), + value: None, + }), + } + } +} + +#[derive(Debug, Clone, FromMeta)] +struct Table { + name: String, + value: Option<Path>, +} + +fn from_str(s: &str) -> darling::Result<MyDeriveInput> { + FromDeriveInput::from_derive_input(&syn::parse_str(s)?) +} + +fn main() { + let missing = from_str( + r#" + #[derive(MyTrait)] + struct Foo(u64); + "#, + ) + .unwrap_err(); + + let short_form = from_str( + r#" + #[derive(MyTrait)] + #[myderive(table)] + struct Foo(u64); + "#, + ) + .unwrap(); + + let long_form = from_str( + r#" + #[derive(MyTrait)] + #[myderive(table(name = "Custom"))] + struct Foo(u64); + "#, + ) + .unwrap(); + + println!("Error when missing: {}", missing); + println!("Short form: {:?}", short_form.table()); + println!("Long form: {:?}", long_form.table()); +} diff --git a/third_party/rust/darling/examples/supports_struct.rs b/third_party/rust/darling/examples/supports_struct.rs new file mode 100644 index 0000000000..97a5bb9c05 --- /dev/null +++ b/third_party/rust/darling/examples/supports_struct.rs @@ -0,0 +1,61 @@ +// The use of fields in debug print commands does not count as "used", +// which causes the fields to trigger an unwanted dead code warning. +#![allow(dead_code)] + +use darling::{ast, util, FromDeriveInput, FromField}; +use syn::{Ident, Type}; + +#[derive(Debug, FromField)] +#[darling(attributes(lorem))] +pub struct LoremField { + ident: Option<Ident>, + ty: Type, + #[darling(default)] + skip: bool, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(lorem), supports(struct_named))] +pub struct Lorem { + ident: Ident, + data: ast::Data<util::Ignored, LoremField>, +} + +fn main() { + let good_input = r#"#[derive(Lorem)] +pub struct Foo { + #[lorem(skip)] + bar: bool, + + baz: i64, +}"#; + + let bad_input = r#"#[derive(Lorem)] + pub struct BadFoo(String, u32);"#; + + let parsed = syn::parse_str(good_input).unwrap(); + let receiver = Lorem::from_derive_input(&parsed).unwrap(); + let wrong_shape_parsed = syn::parse_str(bad_input).unwrap(); + let wrong_shape = Lorem::from_derive_input(&wrong_shape_parsed).expect_err("Shape was wrong"); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + +BAD INPUT: + +{} + +PRODUCED ERROR: + +{} + "#, + good_input, receiver, bad_input, wrong_shape + ); +} diff --git a/third_party/rust/darling/src/lib.rs b/third_party/rust/darling/src/lib.rs new file mode 100644 index 0000000000..c84a55ce59 --- /dev/null +++ b/third_party/rust/darling/src/lib.rs @@ -0,0 +1,107 @@ +//! # Darling +//! Darling is a tool for declarative attribute parsing in proc macro implementations. +//! +//! +//! ## Design +//! Darling takes considerable design inspiration from [`serde`](https://serde.rs). A data structure that can be +//! read from any attribute implements `FromMeta` (or has an implementation automatically +//! generated using `derive`). Any crate can provide `FromMeta` implementations, even one not +//! specifically geared towards proc-macro authors. +//! +//! Proc-macro crates should provide their own structs which implement or derive `FromDeriveInput`, +//! `FromField`, `FromVariant`, `FromGenerics`, _et alia_ to gather settings relevant to their operation. +//! +//! ## Attributes +//! There are a number of attributes that `darling` exposes to enable finer-grained control over the code +//! it generates. +//! +//! * **Field renaming**: You can use `#[darling(rename="new_name")]` on a field to change the name Darling looks for. +//! You can also use `#[darling(rename_all="...")]` at the struct or enum level to apply a casing rule to all fields or variants. +//! * **Map function**: You can use `#[darling(map="path::to::function")]` to run code on a field before its stored in the struct. +//! * **Default values**: You can use `#[darling(default)]` at the type or field level to use that type's default value to fill +//! in values not specified by the caller. +//! * **Skipped fields**: You can skip a variant or field using `#[darling(skip)]`. Fields marked with this will fall back to +//! `Default::default()` for their value, but you can override that with an explicit default or a value from the type-level default. +//! +//! ## Forwarded Fields +//! All derivable traits except `FromMeta` support forwarding some fields from the input AST to the derived struct. +//! These fields are matched up by identifier **before** `rename` attribute values are considered, +//! allowing you to use their names for your own properties. +//! The deriving struct is responsible for making sure the types of fields it chooses to declare are compatible with this table. +//! +//! A deriving struct is free to include or exclude any of the fields below. +//! +//! ### `FromDeriveInput` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in type| +//! |`vis`|`syn::Visibility`|The visibility of the passed-in type| +//! |`generics`|`T: darling::FromGenerics`|The generics of the passed-in type. This can be `syn::Generics`, `darling::ast::Generics`, or any compatible type.| +//! |`data`|`darling::ast::Data`|The body of the passed-in type| +//! |`attrs`|`Vec<syn::Attribute>`|The forwarded attributes from the passed in type. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromField` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`Option<syn::Ident>`|The identifier of the passed-in field, or `None` for tuple fields| +//! |`vis`|`syn::Visibility`|The visibility of the passed-in field| +//! |`ty`|`syn::Type`|The type of the passed-in field| +//! |`attrs`|`Vec<syn::Attribute>`|The forwarded attributes from the passed in field. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromTypeParam` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in type param| +//! |`bounds`|`Vec<syn::TypeParamBound>`|The bounds applied to the type param| +//! |`default`|`Option<syn::Type>`|The default type of the parameter, if one exists| +//! |`attrs`|`Vec<syn::Attribute>`|The forwarded attributes from the passed in type param. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromVariant` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in variant| +//! |`discriminant`|`Option<syn::Expr>`|For a variant such as `Example = 2`, the `2`| +//! |`fields`|`darling::ast::Fields<T> where T: FromField`|The fields associated with the variant| +//! |`attrs`|`Vec<syn::Attribute>`|The forwarded attributes from the passed in variant. These are controlled using the `forward_attrs` attribute.| + +extern crate core; + +#[allow(unused_imports)] +#[macro_use] +extern crate darling_macro; + +#[doc(hidden)] +pub use darling_macro::*; + +#[doc(inline)] +pub use darling_core::{ + FromAttributes, FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, + FromTypeParam, FromVariant, +}; + +#[doc(inline)] +pub use darling_core::{Error, Result}; + +#[doc(inline)] +pub use darling_core::{ast, error, usage, util}; + +// XXX exported so that `ExtractAttribute::extractor` can convert a path into tokens. +// This is likely to change in the future, so only generated code should depend on this export. +#[doc(hidden)] +pub use darling_core::ToTokens; + +/// Core/std trait re-exports. This should help produce generated code which doesn't +/// depend on `std` unnecessarily, and avoids problems caused by aliasing `std` or any +/// of the referenced types. +#[doc(hidden)] +pub mod export { + pub use core::convert::From; + pub use core::default::Default; + pub use core::option::Option::{self, None, Some}; + pub use core::result::Result::{self, Err, Ok}; + pub use std::string::ToString; + pub use std::vec::Vec; +} + +#[macro_use] +mod macros_public; diff --git a/third_party/rust/darling/src/macros_public.rs b/third_party/rust/darling/src/macros_public.rs new file mode 100644 index 0000000000..c264fcc2a8 --- /dev/null +++ b/third_party/rust/darling/src/macros_public.rs @@ -0,0 +1,96 @@ +//! Macros that should be exported from both `darling_core` and `darling`. +//! Note that these are **sym-linked** into the main code, and so cannot declare on items that are exported differently +//! in `darling_core` vs. `darling`. + +/// Generator for `UsesTypeParam` impls that unions the used type parameters of the selected fields. +/// +/// # Usage +/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of +/// fields for the rest of its arguments. +/// +/// The type of each passed-in field must implement `UsesTypeParams`, or the resulting code won't compile. +/// +/// ```rust +/// # extern crate syn; +/// # use darling_core::uses_type_params; +/// # +/// struct MyField { +/// ty: syn::Type, +/// } +/// +/// uses_type_params!(MyField, ty); +/// +/// fn main() { +/// // no test run +/// } +/// ``` +/// +/// `darling` cannot derive this trait automatically, as it doesn't know which information extracted from +/// proc-macro input is meant to constitute "using" the type parameter, but crate consumers should +/// implement it by hand or using the macro. +#[macro_export] +macro_rules! uses_type_params { + ($impl_type:ty, $accessor:ident) => { + impl $crate::usage::UsesTypeParams for $impl_type { + fn uses_type_params<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::IdentSet + ) -> $crate::usage::IdentRefSet<'gen> { + self.$accessor.uses_type_params(options, type_set) + } + } + }; + ($impl_type:ty, $first:ident, $($field:ident),+) => { + impl $crate::usage::UsesTypeParams for $impl_type { + fn uses_type_params<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::IdentSet + ) -> $crate::usage::IdentRefSet<'gen> { + let mut hits = self.$first.uses_type_params(options, type_set); + $( + hits.extend(self.$field.uses_type_params(options, type_set)); + )* + hits + } + } + }; +} + +/// Generator for `UsesLifetimes` impls that unions the used lifetimes of the selected fields. +/// +/// # Usage +/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of +/// fields for the rest of its arguments. +/// +/// The type of each passed-in field must implement `UsesLifetimes`, or the resulting code won't compile. +#[macro_export] +macro_rules! uses_lifetimes { + ($impl_type:ty, $accessor:ident) => { + impl $crate::usage::UsesLifetimes for $impl_type { + fn uses_lifetimes<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::LifetimeSet + ) -> $crate::usage::LifetimeRefSet<'gen> { + self.$accessor.uses_lifetimes(options, type_set) + } + } + }; + ($impl_type:ty, $first:ident, $($field:ident),+) => { + impl $crate::usage::UsesLifetimes for $impl_type { + fn uses_lifetimes<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::LifetimeSet + ) -> $crate::usage::LifetimeRefSet<'gen> { + let mut hits = self.$first.uses_lifetimes(options, type_set); + $( + hits.extend(self.$field.uses_lifetimes(options, type_set)); + )* + hits + } + } + }; +} diff --git a/third_party/rust/darling/tests/accrue_errors.rs b/third_party/rust/darling/tests/accrue_errors.rs new file mode 100644 index 0000000000..e8799c43cb --- /dev/null +++ b/third_party/rust/darling/tests/accrue_errors.rs @@ -0,0 +1,102 @@ +#![allow(dead_code)] +//! These tests verify that multiple errors will be collected up from throughout +//! the parsing process and returned correctly to the caller. + +use darling::{ast, FromDeriveInput, FromField, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(accrue))] +struct Lorem { + ipsum: String, + dolor: Dolor, + data: ast::Data<(), LoremField>, +} + +#[derive(Debug, FromMeta)] +struct Dolor { + sit: bool, +} + +#[derive(Debug, FromField)] +#[darling(attributes(accrue))] +struct LoremField { + ident: Option<syn::Ident>, + aliased_as: syn::Ident, +} + +#[test] +fn bad_type_and_missing_fields() { + let input = parse_quote! { + #[accrue(ipsum = true, dolor(amet = "Hi"))] + pub struct NonConforming { + foo: () + } + }; + + let s_result: ::darling::Error = Lorem::from_derive_input(&input).unwrap_err(); + let err = s_result.flatten(); + println!("{}", err); + assert_eq!(3, err.len()); +} + +#[test] +fn body_only_issues() { + let input = parse_quote! { + #[accrue(ipsum = "Hello", dolor(sit))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Lorem::from_derive_input(&input).unwrap_err(); + println!("{:?}", s_err); + assert_eq!(2, s_err.len()); +} + +#[derive(Debug, FromMeta)] +enum Week { + Monday, + Tuesday { morning: bool, afternoon: String }, + Wednesday(Dolor), +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(accrue))] +struct Month { + schedule: Week, +} + +#[test] +fn error_in_enum_fields() { + let input = parse_quote! { + #[accrue(schedule(tuesday(morning = "yes")))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Month::from_derive_input(&input).unwrap_err(); + assert_eq!(2, s_err.len()); + let err = s_err.flatten(); + // TODO add tests to check location path is correct + println!("{}", err); +} + +#[test] +fn error_in_newtype_variant() { + let input = parse_quote! { + #[accrue(schedule(wednesday(sit = "yes")))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Month::from_derive_input(&input).unwrap_err(); + assert_eq!(1, s_err.len()); + println!("{}", s_err); + println!("{}", s_err.flatten()); +} diff --git a/third_party/rust/darling/tests/computed_bound.rs b/third_party/rust/darling/tests/computed_bound.rs new file mode 100644 index 0000000000..abdb1022c1 --- /dev/null +++ b/third_party/rust/darling/tests/computed_bound.rs @@ -0,0 +1,42 @@ +use darling::{FromDeriveInput, FromMeta}; + +fn parse<T: FromDeriveInput>(src: &str) -> T { + let ast = syn::parse_str(src).unwrap(); + FromDeriveInput::from_derive_input(&ast).unwrap() +} + +#[derive(FromMeta, PartialEq, Eq, Debug)] +enum Volume { + Whisper, + Talk, + Shout, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +struct SpeakingOptions<T: Default, U> { + max_volume: U, + #[darling(skip)] + #[allow(dead_code)] + additional_data: T, +} + +#[derive(Default)] +struct Phoneme { + #[allow(dead_code)] + first: String, +} + +#[test] +fn skipped_field() { + let parsed: SpeakingOptions<Phoneme, Volume> = parse( + r#" + #[derive(Speak)] + #[speak(max_volume = "shout")] + enum HtmlElement { + Div(String) + } + "#, + ); + assert_eq!(parsed.max_volume, Volume::Shout); +} diff --git a/third_party/rust/darling/tests/custom_bound.rs b/third_party/rust/darling/tests/custom_bound.rs new file mode 100644 index 0000000000..312f147805 --- /dev/null +++ b/third_party/rust/darling/tests/custom_bound.rs @@ -0,0 +1,25 @@ +#![allow(dead_code)] + +use std::ops::Add; + +use darling::{FromDeriveInput, FromMeta}; + +#[derive(Debug, Clone, FromMeta)] +#[darling(bound = "T: FromMeta + Add")] +struct Wrapper<T>(pub T); + +impl<T: Add> Add for Wrapper<T> { + type Output = Wrapper<<T as Add>::Output>; + fn add(self, rhs: Self) -> Wrapper<<T as Add>::Output> { + Wrapper(self.0 + rhs.0) + } +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(hello), bound = "Wrapper<T>: Add, T: FromMeta")] +struct Foo<T> { + lorem: Wrapper<T>, +} + +#[test] +fn expansion() {} diff --git a/third_party/rust/darling/tests/defaults.rs b/third_party/rust/darling/tests/defaults.rs new file mode 100644 index 0000000000..05ab1ed1db --- /dev/null +++ b/third_party/rust/darling/tests/defaults.rs @@ -0,0 +1,189 @@ +use darling::FromDeriveInput; +use syn::parse_quote; + +mod foo { + pub mod bar { + pub fn init() -> String { + String::from("hello") + } + } +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +pub struct SpeakerOpts { + #[darling(default = "foo::bar::init")] + first_word: String, +} + +#[test] +fn path_default() { + let speaker: SpeakerOpts = FromDeriveInput::from_derive_input(&parse_quote! { + struct Foo; + }) + .expect("Unit struct with no attrs should parse"); + + assert_eq!(speaker.first_word, "hello"); +} + +/// Tests in this module capture the somewhat-confusing behavior observed when defaults +/// are set at both the field and container level. +/// +/// The general rule is that more-specific declarations preempt less-specific ones; this is +/// unsurprising and allows for granular control over what happens when parsing an AST. +mod stacked_defaults { + use darling::{FromDeriveInput, FromMeta}; + use syn::parse_quote; + + fn jane() -> String { + "Jane".into() + } + + #[derive(FromMeta)] + #[darling(default)] + struct PersonName { + #[darling(default = "jane")] + first: String, + #[darling(default)] + middle: String, + last: String, + } + + impl Default for PersonName { + fn default() -> Self { + Self { + first: "John".into(), + middle: "T".into(), + last: "Doe".into(), + } + } + } + + #[derive(FromDeriveInput)] + #[darling(attributes(person))] + struct Person { + #[darling(default)] + name: PersonName, + age: u8, + } + + #[test] + fn name_first_only() { + let person = Person::from_derive_input(&parse_quote! { + #[person(name(first = "Bill"), age = 5)] + struct Foo; + }) + .unwrap(); + + assert_eq!(person.name.first, "Bill"); + assert_eq!( + person.name.middle, "", + "Explicit field-level default should preempt container-level default" + ); + assert_eq!( + person.name.last, "Doe", + "Absence of a field-level default falls back to container-level default" + ); + } + + /// This is the most surprising case. The presence of `name()` means we invoke + /// `PersonName::from_list(&[])`. When that finishes parsing each of the zero nested + /// items it has received, it will then start filling in missing fields, using the + /// explicit field-level defaults for `first` and `middle`, while for `last` it will + /// use the `last` field from the container-level default. + #[test] + fn name_empty_list() { + let person = Person::from_derive_input(&parse_quote! { + #[person(name(), age = 5)] + struct Foo; + }) + .unwrap(); + + assert_eq!(person.name.first, "Jane"); + assert_eq!(person.name.middle, ""); + assert_eq!(person.name.last, "Doe"); + } + + #[test] + fn no_name() { + let person = Person::from_derive_input(&parse_quote! { + #[person(age = 5)] + struct Foo; + }) + .unwrap(); + + assert_eq!(person.age, 5); + assert_eq!( + person.name.first, "John", + "If `name` is not specified, `Person`'s field-level default should be used" + ); + assert_eq!(person.name.middle, "T"); + assert_eq!(person.name.last, "Doe"); + } +} + +mod implicit_default { + use darling::{util::Flag, FromDeriveInput}; + use syn::parse_quote; + + // No use of `darling(default)` here at all! + // This struct will fill in missing fields using FromMeta::from_none. + #[derive(FromDeriveInput)] + #[darling(attributes(person))] + struct Person { + first_name: String, + last_name: Option<String>, + lefty: Flag, + } + + #[test] + fn missing_fields_fill() { + let person = Person::from_derive_input(&parse_quote! { + #[person(first_name = "James")] + struct Foo; + }) + .unwrap(); + + assert_eq!(person.first_name, "James"); + assert_eq!(person.last_name, None); + assert!(!person.lefty.is_present()); + } +} + +/// Test that a field-level implicit default using FromMeta::from_none is superseded +/// by the parent declaring `#[darling(default)]`. +mod overridden_implicit_default { + use darling::{util::Flag, FromDeriveInput}; + use syn::parse_quote; + + #[derive(FromDeriveInput)] + #[darling(default, attributes(person))] + struct Person { + first_name: String, + last_name: Option<String>, + lefty: Flag, + } + + impl Default for Person { + fn default() -> Self { + Self { + first_name: "Jane".into(), + last_name: Some("Doe".into()), + lefty: Flag::default(), + } + } + } + + #[test] + fn fill_missing() { + let person = Person::from_derive_input(&parse_quote!( + #[person(last_name = "Archer")] + struct Foo; + )) + .unwrap(); + + assert_eq!(person.first_name, "Jane"); + assert_eq!(person.last_name, Some("Archer".into())); + assert!(!person.lefty.is_present()); + } +} diff --git a/third_party/rust/darling/tests/enums_newtype.rs b/third_party/rust/darling/tests/enums_newtype.rs new file mode 100644 index 0000000000..c2c4ec933f --- /dev/null +++ b/third_party/rust/darling/tests/enums_newtype.rs @@ -0,0 +1,90 @@ +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, Default, PartialEq, Eq, FromMeta)] +#[darling(default)] +pub struct Amet { + hello: bool, + world: String, +} + +#[derive(Debug, PartialEq, Eq, FromMeta)] +#[darling(rename_all = "snake_case")] +pub enum Lorem { + Ipsum(bool), + Dolor(String), + Sit(Amet), +} + +#[derive(Debug, PartialEq, Eq, FromDeriveInput)] +#[darling(attributes(hello))] +pub struct Holder { + lorem: Lorem, +} + +impl PartialEq<Lorem> for Holder { + fn eq(&self, other: &Lorem) -> bool { + self.lorem == *other + } +} + +#[test] +fn bool_word() { + let di = parse_quote! { + #[hello(lorem(ipsum))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Ipsum(true)); +} + +#[test] +fn bool_literal() { + let di = parse_quote! { + #[hello(lorem(ipsum = false))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Ipsum(false)); +} + +#[test] +fn string_literal() { + let di = parse_quote! { + #[hello(lorem(dolor = "Hello"))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Dolor("Hello".to_string())); +} + +#[test] +fn struct_nested() { + let di = parse_quote! { + #[hello(lorem(sit(world = "Hello", hello = false)))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!( + pr, + Lorem::Sit(Amet { + hello: false, + world: "Hello".to_string(), + }) + ); +} + +#[test] +#[should_panic] +fn format_mismatch() { + let di = parse_quote! { + #[hello(lorem(dolor(world = "Hello", hello = false)))] + pub struct Bar; + }; + + Holder::from_derive_input(&di).unwrap(); +} diff --git a/third_party/rust/darling/tests/enums_struct.rs b/third_party/rust/darling/tests/enums_struct.rs new file mode 100644 index 0000000000..cae4cd5cdc --- /dev/null +++ b/third_party/rust/darling/tests/enums_struct.rs @@ -0,0 +1,15 @@ +#![allow(dead_code)] + +//! Test expansion of enums which have struct variants. + +use darling::FromMeta; +#[derive(Debug, FromMeta)] +#[darling(rename_all = "snake_case")] +enum Message { + Hello { user: String, silent: bool }, + Ping, + Goodbye { user: String }, +} + +#[test] +fn expansion() {} diff --git a/third_party/rust/darling/tests/enums_unit.rs b/third_party/rust/darling/tests/enums_unit.rs new file mode 100644 index 0000000000..34e0135657 --- /dev/null +++ b/third_party/rust/darling/tests/enums_unit.rs @@ -0,0 +1,14 @@ +//! Test expansion of enum variants which have no associated data. + +use darling::FromMeta; + +#[derive(Debug, FromMeta)] +#[darling(rename_all = "snake_case")] +enum Pattern { + Owned, + Immutable, + Mutable, +} + +#[test] +fn expansion() {} diff --git a/third_party/rust/darling/tests/error.rs b/third_party/rust/darling/tests/error.rs new file mode 100644 index 0000000000..7274e40894 --- /dev/null +++ b/third_party/rust/darling/tests/error.rs @@ -0,0 +1,54 @@ +//! In case of bad input, parsing should fail. The error should have locations set in derived implementations. + +// The use of fields in debug print commands does not count as "used", +// which causes the fields to trigger an unwanted dead code warning. +#![allow(dead_code)] + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromMeta)] +struct Dolor { + #[darling(rename = "amet")] + sit: bool, + world: bool, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(from_ident, attributes(hello))] +struct Lorem { + ident: syn::Ident, + ipsum: Dolor, +} + +impl From<syn::Ident> for Lorem { + fn from(ident: syn::Ident) -> Self { + Lorem { + ident, + ipsum: Dolor { + sit: false, + world: true, + }, + } + } +} + +#[test] +fn parsing_fail() { + let di = parse_quote! { + #[hello(ipsum(amet = "yes", world = false))] + pub struct Foo; + }; + + println!("{}", Lorem::from_derive_input(&di).unwrap_err()); +} + +#[test] +fn missing_field() { + let di = parse_quote! { + #[hello(ipsum(amet = true))] + pub struct Foo; + }; + + println!("{}", Lorem::from_derive_input(&di).unwrap_err()); +} diff --git a/third_party/rust/darling/tests/from_generics.rs b/third_party/rust/darling/tests/from_generics.rs new file mode 100644 index 0000000000..5cdd697d6e --- /dev/null +++ b/third_party/rust/darling/tests/from_generics.rs @@ -0,0 +1,175 @@ +//! Tests for `FromGenerics`, and - indirectly - `FromGenericParam`. +//! These tests assume `FromTypeParam` is working and only look at whether the wrappers for magic +//! fields are working as expected. + +use darling::{ + ast::{self, GenericParamExt}, + util::{Ignored, WithOriginal}, + FromDeriveInput, FromTypeParam, Result, +}; + +#[derive(FromDeriveInput)] +#[darling(attributes(lorem))] +struct MyReceiver { + pub generics: ast::Generics<ast::GenericParam<MyTypeParam>>, +} + +#[derive(FromTypeParam)] +#[darling(attributes(lorem))] +struct MyTypeParam { + pub ident: syn::Ident, + #[darling(default)] + pub foo: bool, + pub bar: Option<String>, +} + +fn fdi<T: FromDeriveInput>(src: &str) -> Result<T> { + FromDeriveInput::from_derive_input(&syn::parse_str(src).expect("Source parses")) +} + +/// Verify that `ast::Generics` is populated correctly when there is no generics declaration +#[test] +fn no_generics() { + let rec: MyReceiver = fdi("struct Baz;").expect("Input is well-formed"); + assert!(rec.generics.where_clause.is_none()); + assert_eq!(rec.generics.params.len(), 0); +} + +#[test] +#[allow(clippy::bool_assert_comparison)] +fn expand_some() { + let rec: MyReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U); + "#) + .expect("Input is well-formed"); + assert!(rec.generics.where_clause.is_none()); + + // Make sure we've preserved the lifetime def, though we don't do anything with it. + assert!(rec.generics.params[0].as_lifetime_def().is_some()); + + let mut ty_param_iter = rec.generics.type_params(); + + let first = ty_param_iter + .next() + .expect("type_params should not be empty"); + assert!(first.bar.is_none()); + assert!(first.foo); + assert_eq!(first.ident, "T"); + + let second = ty_param_iter + .next() + .expect("type_params should have a second value"); + assert_eq!( + second + .bar + .as_ref() + .expect("Second type param should set bar"), + "x" + ); + assert_eq!(second.foo, false); + assert_eq!(second.ident, "U"); +} + +/// Verify ≤0.4.1 behavior - where `generics` had to be `syn::Generics` - keeps working. +#[test] +fn passthrough() { + #[derive(FromDeriveInput)] + struct PassthroughReceiver { + pub generics: syn::Generics, + } + + let rec: PassthroughReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U); + "#) + .expect("Input is well-formed"); + + let mut type_param_iter = rec.generics.type_params(); + assert!(type_param_iter.next().is_some()); +} + +/// Verify that `where_clause` is passed through when it exists. +/// As of 0.4.1, there is no `FromWhereClause` trait, so other types aren't supported +/// for that field. +#[test] +fn where_clause() { + let rec: MyReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into<String>; + "#) + .expect("Input is well-formed"); + + assert!(rec.generics.where_clause.is_some()); +} + +/// Test that `WithOriginal` works for generics. +#[test] +fn with_original() { + #[derive(FromDeriveInput)] + struct WorigReceiver { + generics: WithOriginal<ast::Generics<ast::GenericParam<MyTypeParam>>, syn::Generics>, + } + + let rec: WorigReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into<String>; + "#) + .expect("Input is well-formed"); + + // Make sure we haven't lost anything in the conversion + assert_eq!(rec.generics.parsed.params.len(), 3); + assert_eq!(rec.generics.original.params.len(), 3); + + let parsed_t: &MyTypeParam = rec.generics.parsed.params[1] + .as_type_param() + .expect("Second argument should be type param"); + + // Make sure the first type param in each case is T + assert_eq!(parsed_t.ident, "T"); + assert_eq!( + rec.generics + .original + .type_params() + .next() + .expect("First type param should exist") + .ident, + "T" + ); + + // Make sure we actually parsed the first type param + assert!(parsed_t.foo); + assert!(parsed_t.bar.is_none()); +} + +/// Make sure generics can be ignored +#[test] +fn ignored() { + #[derive(FromDeriveInput)] + struct IgnoredReceiver { + generics: Ignored, + } + + let rec: IgnoredReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into<String>; + "#) + .expect("Input is well-formed"); + + assert_eq!(Ignored, rec.generics); +} diff --git a/third_party/rust/darling/tests/from_meta.rs b/third_party/rust/darling/tests/from_meta.rs new file mode 100644 index 0000000000..3e7278cec8 --- /dev/null +++ b/third_party/rust/darling/tests/from_meta.rs @@ -0,0 +1,66 @@ +use darling::{Error, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromMeta)] +struct Meta { + #[darling(default)] + meta1: Option<String>, + #[darling(default)] + meta2: bool, +} + +#[test] +fn nested_meta_meta_value() { + let meta = Meta::from_list(&[parse_quote! { + meta1 = "thefeature" + }]) + .unwrap(); + assert_eq!(meta.meta1, Some("thefeature".to_string())); + assert!(!meta.meta2); +} + +#[test] +fn nested_meta_meta_bool() { + let meta = Meta::from_list(&[parse_quote! { + meta2 + }]) + .unwrap(); + assert_eq!(meta.meta1, None); + assert!(meta.meta2); +} + +#[test] +fn nested_meta_lit_string_errors() { + let err = Meta::from_list(&[parse_quote! { + "meta2" + }]) + .unwrap_err(); + assert_eq!( + err.to_string(), + Error::unsupported_format("literal").to_string() + ); +} + +#[test] +fn nested_meta_lit_integer_errors() { + let err = Meta::from_list(&[parse_quote! { + 2 + }]) + .unwrap_err(); + assert_eq!( + err.to_string(), + Error::unsupported_format("literal").to_string() + ); +} + +#[test] +fn nested_meta_lit_bool_errors() { + let err = Meta::from_list(&[parse_quote! { + true + }]) + .unwrap_err(); + assert_eq!( + err.to_string(), + Error::unsupported_format("literal").to_string() + ); +} diff --git a/third_party/rust/darling/tests/from_type_param.rs b/third_party/rust/darling/tests/from_type_param.rs new file mode 100644 index 0000000000..50ec3061e9 --- /dev/null +++ b/third_party/rust/darling/tests/from_type_param.rs @@ -0,0 +1,59 @@ +use darling::FromTypeParam; +use syn::{parse_quote, DeriveInput, GenericParam, Ident, TypeParam}; + +#[derive(FromTypeParam)] +#[darling(attributes(lorem), from_ident)] +struct Lorem { + ident: Ident, + bounds: Vec<syn::TypeParamBound>, + foo: bool, + bar: Option<String>, +} + +impl From<Ident> for Lorem { + fn from(ident: Ident) -> Self { + Lorem { + ident, + foo: false, + bar: None, + bounds: Default::default(), + } + } +} + +fn extract_type(param: &GenericParam) -> &TypeParam { + match *param { + GenericParam::Type(ref ty) => ty, + _ => unreachable!("Not a type param"), + } +} + +#[test] +#[allow(clippy::bool_assert_comparison)] +fn expand_many() { + let di: DeriveInput = parse_quote! { + struct Baz< + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(T, U); + }; + + let params = di.generics.params; + + { + let ty = extract_type(¶ms[0]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.ident, "T"); + assert_eq!(lorem.foo, true); + assert_eq!(lorem.bar, None); + } + + { + let ty = extract_type(¶ms[1]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.ident, "U"); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, Some("x".to_string())); + assert_eq!(lorem.bounds.len(), 2); + } +} diff --git a/third_party/rust/darling/tests/from_type_param_default.rs b/third_party/rust/darling/tests/from_type_param_default.rs new file mode 100644 index 0000000000..9d65665bb9 --- /dev/null +++ b/third_party/rust/darling/tests/from_type_param_default.rs @@ -0,0 +1,53 @@ +use darling::FromTypeParam; +use syn::{parse_quote, DeriveInput, GenericParam, TypeParam}; + +#[derive(Default, FromTypeParam)] +#[darling(attributes(lorem), default)] +struct Lorem { + foo: bool, + bar: Option<String>, + default: Option<syn::Type>, +} + +fn extract_type(param: &GenericParam) -> &TypeParam { + match *param { + GenericParam::Type(ref ty) => ty, + _ => unreachable!("Not a type param"), + } +} + +#[test] +#[allow(clippy::bool_assert_comparison)] +fn expand_many() { + let di: DeriveInput = parse_quote! { + struct Baz< + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized, + #[lorem(foo = false)] V = (), + >(T, U, V); + }; + let params = di.generics.params; + + { + let ty = extract_type(¶ms[0]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, true); + assert_eq!(lorem.bar, None); + } + + { + let ty = extract_type(¶ms[1]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, Some("x".to_string())); + assert!(lorem.default.is_none()); + } + + { + let ty = extract_type(¶ms[2]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, None); + assert!(lorem.default.is_some()); + } +} diff --git a/third_party/rust/darling/tests/from_variant.rs b/third_party/rust/darling/tests/from_variant.rs new file mode 100644 index 0000000000..e89b8ff7f5 --- /dev/null +++ b/third_party/rust/darling/tests/from_variant.rs @@ -0,0 +1,57 @@ +use darling::FromVariant; +use syn::{spanned::Spanned, Expr, ExprLit, LitInt}; + +#[derive(FromVariant)] +#[darling(from_ident, attributes(hello))] +#[allow(dead_code)] +pub struct Lorem { + ident: syn::Ident, + into: Option<bool>, + skip: Option<bool>, + discriminant: Option<syn::Expr>, + fields: darling::ast::Fields<syn::Type>, +} + +impl From<syn::Ident> for Lorem { + fn from(ident: syn::Ident) -> Self { + Lorem { + ident, + into: Default::default(), + skip: Default::default(), + discriminant: None, + fields: darling::ast::Style::Unit.into(), + } + } +} + +#[test] +fn discriminant() { + let input: syn::DeriveInput = syn::parse_str( + r#" + pub enum Test { + Works = 1, + AlsoWorks = 2, + } + "#, + ) + .unwrap(); + + let span = input.span(); + if let syn::Data::Enum(enm) = input.data { + let lorem = Lorem::from_variant( + enm.variants + .first() + .expect("Hardcoded input has one variant"), + ) + .expect("FromVariant can process the discriminant"); + assert_eq!( + lorem.discriminant, + Some(Expr::Lit(ExprLit { + attrs: vec![], + lit: LitInt::new("1", span).into(), + })) + ) + } else { + panic!("Data should be enum"); + } +} diff --git a/third_party/rust/darling/tests/generics.rs b/third_party/rust/darling/tests/generics.rs new file mode 100644 index 0000000000..ba65781fe3 --- /dev/null +++ b/third_party/rust/darling/tests/generics.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, Clone, FromMeta)] +struct Wrapper<T>(pub T); + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(hello))] +struct Foo<T> { + lorem: Wrapper<T>, +} + +#[test] +fn expansion() { + let di = parse_quote! { + #[hello(lorem = "Hello")] + pub struct Foo; + }; + + Foo::<String>::from_derive_input(&di).unwrap(); +} diff --git a/third_party/rust/darling/tests/happy_path.rs b/third_party/rust/darling/tests/happy_path.rs new file mode 100644 index 0000000000..a56aee75fc --- /dev/null +++ b/third_party/rust/darling/tests/happy_path.rs @@ -0,0 +1,69 @@ +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Default, FromMeta, PartialEq, Debug)] +#[darling(default)] +struct Lorem { + ipsum: bool, + dolor: Option<String>, +} + +#[derive(FromDeriveInput, PartialEq, Debug)] +#[darling(attributes(darling_demo))] +struct Core { + ident: syn::Ident, + vis: syn::Visibility, + generics: syn::Generics, + lorem: Lorem, +} + +#[derive(FromDeriveInput, PartialEq, Debug)] +#[darling(attributes(darling_demo))] +struct TraitCore { + ident: syn::Ident, + generics: syn::Generics, + lorem: Lorem, +} + +#[test] +fn simple() { + let di = parse_quote! { + #[derive(Foo)] + #[darling_demo(lorem(ipsum))] + pub struct Bar; + }; + + assert_eq!( + Core::from_derive_input(&di).unwrap(), + Core { + ident: parse_quote!(Bar), + vis: parse_quote!(pub), + generics: Default::default(), + lorem: Lorem { + ipsum: true, + dolor: None, + }, + } + ); +} + +#[test] +fn trait_type() { + let di = parse_quote! { + #[derive(Foo)] + #[darling_demo(lorem(dolor = "hello"))] + pub struct Bar; + }; + + assert_eq!( + TraitCore::from_derive_input(&di).unwrap(), + TraitCore { + ident: parse_quote!(Bar), + generics: Default::default(), + lorem: Lorem { + ipsum: false, + dolor: Some("hello".to_owned()), + } + } + ); +} diff --git a/third_party/rust/darling/tests/hash_map.rs b/third_party/rust/darling/tests/hash_map.rs new file mode 100644 index 0000000000..5d9a0114ed --- /dev/null +++ b/third_party/rust/darling/tests/hash_map.rs @@ -0,0 +1,42 @@ +use std::collections::HashMap; + +use darling::FromMeta; +use syn::{parse_quote, Attribute, Path}; + +#[derive(Debug, FromMeta, PartialEq, Eq)] +struct MapValue { + name: String, + #[darling(default)] + option: bool, +} + +#[test] +fn parse_map() { + let attr: Attribute = parse_quote! { + #[foo(first(name = "Hello", option), the::second(name = "Second"))] + }; + + let meta = attr.parse_meta().unwrap(); + let map: HashMap<Path, MapValue> = FromMeta::from_meta(&meta).unwrap(); + + let comparison: HashMap<Path, MapValue> = vec![ + ( + parse_quote!(first), + MapValue { + name: "Hello".into(), + option: true, + }, + ), + ( + parse_quote!(the::second), + MapValue { + name: "Second".into(), + option: false, + }, + ), + ] + .into_iter() + .collect(); + + assert_eq!(comparison, map); +} diff --git a/third_party/rust/darling/tests/multiple.rs b/third_party/rust/darling/tests/multiple.rs new file mode 100644 index 0000000000..b2243e62b6 --- /dev/null +++ b/third_party/rust/darling/tests/multiple.rs @@ -0,0 +1,30 @@ +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(FromDeriveInput)] +#[darling(attributes(hello))] +#[allow(dead_code)] +struct Lorem { + ident: syn::Ident, + ipsum: Ipsum, +} + +#[derive(FromMeta)] +struct Ipsum { + #[darling(multiple)] + dolor: Vec<String>, +} + +#[test] +fn expand_many() { + let di = parse_quote! { + #[hello(ipsum(dolor = "Hello", dolor = "World"))] + pub struct Baz; + }; + + let lorem: Lorem = Lorem::from_derive_input(&di).unwrap(); + assert_eq!( + lorem.ipsum.dolor, + vec!["Hello".to_string(), "World".to_string()] + ); +} diff --git a/third_party/rust/darling/tests/newtype.rs b/third_party/rust/darling/tests/newtype.rs new file mode 100644 index 0000000000..10d0238882 --- /dev/null +++ b/third_party/rust/darling/tests/newtype.rs @@ -0,0 +1,26 @@ +//! A newtype struct should be able to derive `FromMeta` if its member implements it. + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromMeta, PartialEq, Eq)] +struct Lorem(bool); + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(newtype))] +struct DemoContainer { + lorem: Lorem, +} + +#[test] +fn generated() { + let di = parse_quote! { + #[derive(Baz)] + #[newtype(lorem = false)] + pub struct Foo; + }; + + let c = DemoContainer::from_derive_input(&di).unwrap(); + + assert_eq!(c.lorem, Lorem(false)); +} diff --git a/third_party/rust/darling/tests/skip.rs b/third_party/rust/darling/tests/skip.rs new file mode 100644 index 0000000000..f930ca5d31 --- /dev/null +++ b/third_party/rust/darling/tests/skip.rs @@ -0,0 +1,74 @@ +//! Test that skipped fields are not read into structs when they appear in input. + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, PartialEq, Eq, FromDeriveInput)] +#[darling(attributes(skip_test))] +pub struct Lorem { + ipsum: String, + + #[darling(skip)] + dolor: u8, +} + +/// Verify variant-level and field-level skip work correctly for enums. +#[derive(Debug, FromMeta)] +pub enum Sit { + Amet(bool), + + #[darling(skip)] + Foo { + hello: bool, + }, + + Bar { + hello: bool, + #[darling(skip)] + world: u8, + }, +} + +#[test] +fn verify_skipped_field_not_required() { + let di = parse_quote! { + #[skip_test(ipsum = "Hello")] + struct Baz; + }; + + assert_eq!( + Lorem::from_derive_input(&di).unwrap(), + Lorem { + ipsum: "Hello".to_string(), + dolor: 0, + } + ); +} + +/// This test verifies that a skipped field will still prefer an explicit default +/// over the default that would come from its field type. It would be incorrect for +/// `Defaulting::from_derive_input` to fail here, and it would be wrong for the value +/// of `dolor` to be `None`. +#[test] +fn verify_default_supersedes_from_none() { + fn default_dolor() -> Option<u8> { + Some(2) + } + + #[derive(Debug, PartialEq, Eq, FromDeriveInput)] + #[darling(attributes(skip_test))] + pub struct Defaulting { + #[darling(skip, default = "default_dolor")] + dolor: Option<u8>, + } + + let di = parse_quote! { + #[skip_test] + struct Baz; + }; + + assert_eq!( + Defaulting::from_derive_input(&di).unwrap(), + Defaulting { dolor: Some(2) } + ) +} diff --git a/third_party/rust/darling/tests/split_declaration.rs b/third_party/rust/darling/tests/split_declaration.rs new file mode 100644 index 0000000000..8db11d0f03 --- /dev/null +++ b/third_party/rust/darling/tests/split_declaration.rs @@ -0,0 +1,67 @@ +//! When input is split across multiple attributes on one element, +//! darling should collapse that into one struct. + +use darling::{Error, FromDeriveInput}; +use syn::parse_quote; + +#[derive(Debug, FromDeriveInput, PartialEq, Eq)] +#[darling(attributes(split))] +struct Lorem { + foo: String, + bar: bool, +} + +#[test] +fn split_attributes_accrue_to_instance() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(bar)] + pub struct Foo; + }; + + let parsed = Lorem::from_derive_input(&di).unwrap(); + assert_eq!( + parsed, + Lorem { + foo: "Hello".to_string(), + bar: true, + } + ); +} + +#[test] +fn duplicates_across_split_attrs_error() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(foo = "World", bar)] + pub struct Foo; + }; + + let pr = Lorem::from_derive_input(&di).unwrap_err(); + assert!(pr.has_span()); + assert_eq!(pr.to_string(), Error::duplicate_field("foo").to_string()); +} + +#[test] +fn multiple_errors_accrue_to_instance() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(foo = "World")] + pub struct Foo; + }; + + let pr = Lorem::from_derive_input(&di); + let err: Error = pr.unwrap_err(); + assert_eq!(2, err.len()); + let mut errs = err.into_iter().peekable(); + assert_eq!( + errs.peek().unwrap().to_string(), + Error::duplicate_field("foo").to_string() + ); + assert!(errs.next().unwrap().has_span()); + assert_eq!( + errs.next().unwrap().to_string(), + Error::missing_field("bar").to_string() + ); + assert!(errs.next().is_none()); +} diff --git a/third_party/rust/darling/tests/suggestions.rs b/third_party/rust/darling/tests/suggestions.rs new file mode 100644 index 0000000000..5baf76ca6c --- /dev/null +++ b/third_party/rust/darling/tests/suggestions.rs @@ -0,0 +1,29 @@ +#![allow(dead_code)] +#![cfg(feature = "suggestions")] + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(suggest))] +struct Lorem { + ipsum: String, + dolor: Dolor, +} + +#[derive(Debug, FromMeta)] +struct Dolor { + sit: bool, +} + +#[test] +fn suggest_dolor() { + let input: syn::DeriveInput = parse_quote! { + #[suggest(ipsum = "Hello", dolorr(sit))] + pub struct Foo; + }; + + let result = Lorem::from_derive_input(&input).unwrap_err(); + assert_eq!(2, result.len()); + assert!(format!("{}", result).contains("Did you mean")); +} diff --git a/third_party/rust/darling/tests/supports.rs b/third_party/rust/darling/tests/supports.rs new file mode 100644 index 0000000000..d6c7556722 --- /dev/null +++ b/third_party/rust/darling/tests/supports.rs @@ -0,0 +1,90 @@ +use darling::{ast, FromDeriveInput, FromVariant}; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(from_variants), supports(enum_any))] +pub struct Container { + // The second type parameter can be anything that implements FromField, since + // FromDeriveInput will produce an error if given a struct. + data: ast::Data<Variant, ()>, +} + +#[derive(Default, Debug, FromVariant)] +#[darling(default, attributes(from_variants), supports(newtype, unit))] +pub struct Variant { + into: Option<bool>, + skip: Option<bool>, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(from_struct), supports(struct_named))] +pub struct StructContainer { + // The second type parameter can be anything that implements FromVariant, since + // FromDeriveInput will produce an error if given an enum. + data: ast::Data<(), syn::Field>, +} + +mod source { + use syn::{parse_quote, DeriveInput}; + + pub fn newtype_enum() -> DeriveInput { + parse_quote! { + enum Hello { + World(bool), + String(String), + } + } + } + + pub fn named_field_enum() -> DeriveInput { + parse_quote! { + enum Hello { + Foo(u16), + World { + name: String + }, + } + } + } + + pub fn empty_enum() -> DeriveInput { + parse_quote! { + enum Hello {} + } + } + + pub fn named_struct() -> DeriveInput { + parse_quote! { + struct Hello { + world: bool, + } + } + } + + pub fn tuple_struct() -> DeriveInput { + parse_quote! { struct Hello(String, bool); } + } +} + +#[test] +fn enum_newtype_or_unit() { + // Should pass + let container = Container::from_derive_input(&source::newtype_enum()).unwrap(); + assert!(container.data.is_enum()); + + // Should error + Container::from_derive_input(&source::named_field_enum()).unwrap_err(); + Container::from_derive_input(&source::named_struct()).unwrap_err(); +} + +#[test] +fn struct_named() { + // Should pass + let container = StructContainer::from_derive_input(&source::named_struct()).unwrap(); + assert!(container.data.is_struct()); + + // Should fail + StructContainer::from_derive_input(&source::tuple_struct()).unwrap_err(); + StructContainer::from_derive_input(&source::named_field_enum()).unwrap_err(); + StructContainer::from_derive_input(&source::newtype_enum()).unwrap_err(); + StructContainer::from_derive_input(&source::empty_enum()).unwrap_err(); +} diff --git a/third_party/rust/darling/tests/unsupported_attributes.rs b/third_party/rust/darling/tests/unsupported_attributes.rs new file mode 100644 index 0000000000..14edf2c858 --- /dev/null +++ b/third_party/rust/darling/tests/unsupported_attributes.rs @@ -0,0 +1,49 @@ +use darling::FromDeriveInput; +use syn::{parse_quote, Ident, LitStr, Path}; + +#[derive(Debug, FromDeriveInput)] +#[darling(supports(struct_unit), attributes(bar))] +pub struct Bar { + pub ident: Ident, + pub st: Path, + pub file: LitStr, +} + +/// Per [#96](https://github.com/TedDriggs/darling/issues/96), make sure that an +/// attribute which isn't a valid meta gets an error. +#[test] +fn non_meta_attribute_gets_own_error() { + let di = parse_quote! { + #[derive(Bar)] + #[bar(file = "motors/example_6.csv", st = RocketEngine)] + pub struct EstesC6; + }; + + let errors: darling::Error = Bar::from_derive_input(&di).unwrap_err().flatten(); + // The number of errors here is 1 for the bad attribute + 2 for the missing fields + assert_eq!(3, errors.len()); + // Make sure one of the errors propagates the syn error + assert!(errors + .into_iter() + .any(|e| e.to_string().contains("expected lit"))); +} + +/// Properties can be split across multiple attributes; this test ensures that one +/// non-meta attribute does not interfere with the parsing of other, well-formed attributes. +#[test] +fn non_meta_attribute_does_not_block_others() { + let di = parse_quote! { + #[derive(Bar)] + #[bar(st = RocketEngine)] + #[bar(file = "motors/example_6.csv")] + pub struct EstesC6; + }; + + let errors: darling::Error = Bar::from_derive_input(&di).unwrap_err().flatten(); + // The number of errors here is 1 for the bad attribute + 1 for the missing "st" field + assert_eq!(2, errors.len()); + // Make sure one of the errors propagates the syn error + assert!(errors + .into_iter() + .any(|e| e.to_string().contains("expected lit"))); +} diff --git a/third_party/rust/darling_core/.cargo-checksum.json b/third_party/rust/darling_core/.cargo-checksum.json new file mode 100644 index 0000000000..08c4fee0e7 --- /dev/null +++ b/third_party/rust/darling_core/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"bc81b127cb5c7103c11930aa0fecb58eaa093922c85479237f0dca5798ffbf64","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/ast/data.rs":"1dc6d1fd1b6d0644ad7393e5aaa1cd2eab4a084f49d3152bf177b1123122fda7","src/ast/generics.rs":"8e1bd81128116d54fe3c8de1a307cb6c9d1ecafa263fd77897719648e0d4b8af","src/ast/mod.rs":"58a58eeb1db7682e5994732cc8eb04088f6ca662805460ef443cf089e5c24e2c","src/codegen/attr_extractor.rs":"cb9390702e9aac39257b9159759b1be4eba6f1b4a2f818c3d55b95a404ee425a","src/codegen/default_expr.rs":"7b906c51b13e3606b93ce06544189d9db800d7d4d9de8c5423f1fe6cff5de047","src/codegen/error.rs":"4fa7f579aeccb749d529c0f4102c9373435ae23bf78ccc24ac517edb7dbca8ba","src/codegen/field.rs":"8e31b17155a46a5481e0f6333a0d0c7d390eaedd993b8d04a0f118376177881b","src/codegen/from_attributes_impl.rs":"c9e5a536b7aea0443b878c4a60a2e778abd7f0e338fbab02a376dcedfab7079a","src/codegen/from_derive_impl.rs":"e7ef2b4f159d5aaf18effe8fada5572130037d869673ec97a79fd150e1eb09fc","src/codegen/from_field.rs":"e58f77ad653d3cb9e92a1244724de051f712743bc9ccb62a950e50aa1c09a230","src/codegen/from_meta_impl.rs":"f1ef1450a873f708ca1489dff6ff26ea1e284329c6b852ee82e624f0900f3203","src/codegen/from_type_param.rs":"bd67303e2345ee91cd4b34bac6149559e83146d10139b510f0648b6478f1a8ff","src/codegen/from_variant_impl.rs":"8a4fe34c96a0dd58e763712456070b7e1ccd330b8626181dfdac0c27e4a3e182","src/codegen/mod.rs":"77b194876541e8ced86efebb534fc8a4f70c06d92c8b493aa90ef936bcc14273","src/codegen/outer_from_impl.rs":"9e40b80dbc6c025610e367f7c55adac0f114c4fe4ca82c1a64be3a91861e365e","src/codegen/postfix_transform.rs":"68f9b52cbedb17748ce2ff74e2876b7d7e8b1e348d435537f2d9957abb801efa","src/codegen/trait_impl.rs":"6a4d283fc45e9625894e91e788cdc19cd8c4e682c8df9a7ce5420c4a2461a723","src/codegen/variant.rs":"4e446a1dace51ee5ce61d53380b7b64168fbe433071a2408e95c8d5d25377f19","src/codegen/variant_data.rs":"610b2a6d195ca292a4a1f6a2b27302fa50d4b19b5495e25fd8a0ca235f0640eb","src/derive.rs":"d35f35233eea28bc66bf6f738358415d650741560ca56f8deaee9465b3e88b2a","src/error/kind.rs":"941dadb461aacf18758ab4919e7d7f12cb057dbe8deaca475afd2d30f63849da","src/error/mod.rs":"716cb5e7014949dbf34961a98c95c9acf120a8597ef61157a54b3523f6d9fd2f","src/from_attributes.rs":"9c98a34eccdb66526711793d6d00bd5216de1d0e9d3755133996242a27efe272","src/from_derive_input.rs":"a60aba72ebd4deddd6bb9919995652f90aafdf88f6109c00c1a1c4459e439049","src/from_field.rs":"1e22b7750843b6a018fe75ae1510fb9252343be99ab02d2093881421e87d867d","src/from_generic_param.rs":"bdabc80f49212501e6e3574c7e6c03b4e453d0fe241ac46d465a5f004381f4c9","src/from_generics.rs":"b0a156179b2d1d88467183649afc97405403b01a7fdae39e4df8392f6b9f500c","src/from_meta.rs":"97a5656950ea0d912f085e9299fb505fa0461c13e0a0c82999ec1f0c909d02b4","src/from_type_param.rs":"0c8930a42e1f0720429aa968f97f938e207460232dd2169cbf8efec12e7c6f5a","src/from_variant.rs":"dd27ffef65ceea0e68809afde7df82d3751cdedc248773062637aa8c146da6e7","src/lib.rs":"d10554edafa9995821c54b02be4fde5316753a19cf8ca8d7a4be321172804cf7","src/macros_private.rs":"ef249cd9ca593aac423b4242df1c39c31610438da094c21562d74a7e5823c700","src/macros_public.rs":"7d2ce0c5026227ef7854db11d7a885ad891255438b2e49bbdfda56fa2f92feec","src/options/core.rs":"c5753d2045a5d69f20d07a4ba4c241aed5664bfdf695c8fd410f6b34ebb85a72","src/options/forward_attrs.rs":"c6a960f74957854eabd5a5c87a15dbee897ea9a2f48d0094fbaec110f3a785cf","src/options/from_attributes.rs":"f73c4dc53cced30e60812a4247f3252ea0630618b1d162058cce0bd1666c43c9","src/options/from_derive.rs":"79b765e4d457888b1249a4326a117884c786a5f9fbc5203b17086663cadb04dc","src/options/from_field.rs":"006e127a648d9ad095fa92ffc6f9e106fdc1a784dd82be88dc73ed80198fd429","src/options/from_meta.rs":"1a543110dc4ab2e716a914bafced9e1f4035794613117708fc9f37a1036bcf75","src/options/from_type_param.rs":"c6f907d3bceef3a918822b75e019f520650d66c523acc2ffac37d03016234659","src/options/from_variant.rs":"6b426a453710f6e3d40d8fbdce4dbb8aa6470c98f8d385654f0eae98ab7e4be3","src/options/input_field.rs":"fd730ffc4b4f6d5bba09bfdf0b57414d3a592dea052e5e56b1c6299d05651b2e","src/options/input_variant.rs":"bfb524a0fd4c4e13eb23af0c4d714987d5dd6d28572b9fb60bee7c3aa4eff50f","src/options/mod.rs":"16b46698a4aece171ce53b092768e84aa5bbc240b2ee8213a3cfed93a27414c8","src/options/outer_from.rs":"ee173f73266997ae2d355cf2397f3ffe3ef13422ca434123fc682f728d7daa73","src/options/shape.rs":"8a7bcb717acd1f97d7f66a1bee906774f098b32d375822e2f30fa65044c76609","src/usage/generics_ext.rs":"b2d15e2ff75c47f43f3ce305b2108e800dd3d89e3a21fadf82bda455837b8090","src/usage/ident_set.rs":"30edb2f0a599284967e3c6b579da31e5f9b15f3dd67bc9a82d6335eb44133df0","src/usage/lifetimes.rs":"c7b5cd7166f319827521dfb70a6f0339a1d9240b8f8d7dea766250a503a81b44","src/usage/mod.rs":"e49adadfa8ffed27299d5bbf3c33e68e2c8c7411f89aef655f77e158be9dd642","src/usage/options.rs":"0491c995aad0d55783b24cce8a4e40f0f4435988c54ce2ded34763ac9b199fcf","src/usage/type_params.rs":"a61f67e398753397b12f65d50feca11b18b20655ab88548bd404a060bcc8b65d","src/util/flag.rs":"3cf473760b0c23d4b2e0144e5da23f858ade7e1b86504827f74dfe123f73c604","src/util/ident_string.rs":"7c3e00e0e3ddbb042d9a3c67a39186861a626dba4afc961e4e8f59a698169399","src/util/ignored.rs":"099c015023b9be0870fb1c4c44ad00f87789ea13da25e2ca952132443e497214","src/util/mod.rs":"ec336ca0386880db33474ac60731be2efda39fb3bce6277c5365c6c0049953ae","src/util/over_ride.rs":"5ce783a1fdfa7281038c03294572956f22efb1ae9b0794728db5b6d9fbcead68","src/util/parse_attribute.rs":"17f7f26ca2f459a3651ef24e85808e5318795c0ec4f719cabc98ccad65e3257a","src/util/path_list.rs":"e110ee62728eae28faaea04e94063def40889b275f70c5ac9b2aeabec80972c4","src/util/path_to_string.rs":"c093354f91ab45e0be3c50d2d4356408f415c910f1569fb9275c5087110736f6","src/util/spanned_value.rs":"9bda584fa88fca803e708e1f041c8cb2449eb812799de4d38b42e98a4759bd4c","src/util/with_original.rs":"56ea20c03d07ebe1a8bc0ed220258f6cee5a3cf7192c0e07601fafda99404062"},"package":"a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f"}
\ No newline at end of file diff --git a/third_party/rust/darling_core/Cargo.toml b/third_party/rust/darling_core/Cargo.toml new file mode 100644 index 0000000000..09319094ca --- /dev/null +++ b/third_party/rust/darling_core/Cargo.toml @@ -0,0 +1,49 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "darling_core" +version = "0.14.2" +authors = ["Ted Driggs <ted.driggs@outlook.com>"] +description = """ +Helper crate for proc-macro library for reading attributes into structs when +implementing custom derives. Use https://crates.io/crates/darling in your code. +""" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" + +[dependencies.fnv] +version = "1.0.7" + +[dependencies.ident_case] +version = "1.0.1" + +[dependencies.proc-macro2] +version = "1.0.37" + +[dependencies.quote] +version = "1.0.18" + +[dependencies.strsim] +version = "0.10.0" +optional = true + +[dependencies.syn] +version = "1.0.91" +features = [ + "full", + "extra-traits", +] + +[features] +diagnostics = [] +suggestions = ["strsim"] diff --git a/third_party/rust/darling_core/LICENSE b/third_party/rust/darling_core/LICENSE new file mode 100644 index 0000000000..0b48eadc9d --- /dev/null +++ b/third_party/rust/darling_core/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Ted Driggs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/darling_core/src/ast/data.rs b/third_party/rust/darling_core/src/ast/data.rs new file mode 100644 index 0000000000..96dd6f35d8 --- /dev/null +++ b/third_party/rust/darling_core/src/ast/data.rs @@ -0,0 +1,477 @@ +use std::{slice, vec}; + +use proc_macro2::{Span, TokenStream}; +use quote::ToTokens; +use syn::spanned::Spanned; + +use crate::usage::{ + self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams, +}; +use crate::{Error, FromField, FromVariant, Result}; + +/// A struct or enum body. +/// +/// `V` is the type which receives any encountered variants, and `F` receives struct fields. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Data<V, F> { + Enum(Vec<V>), + Struct(Fields<F>), +} + +impl<V, F> Data<V, F> { + /// Creates an empty body of the same shape as the passed-in body. + /// + /// # Panics + /// This function will panic if passed `syn::Data::Union`. + pub fn empty_from(src: &syn::Data) -> Self { + match *src { + syn::Data::Enum(_) => Data::Enum(vec![]), + syn::Data::Struct(ref vd) => Data::Struct(Fields::empty_from(&vd.fields)), + syn::Data::Union(_) => panic!("Unions are not supported"), + } + } + + /// Creates an empty body of the same shape as the passed-in body. + /// + /// `darling` does not support unions; calling this function with a union body will return an error. + pub fn try_empty_from(src: &syn::Data) -> Result<Self> { + match *src { + syn::Data::Enum(_) => Ok(Data::Enum(vec![])), + syn::Data::Struct(ref vd) => Ok(Data::Struct(Fields::empty_from(&vd.fields))), + // This deliberately doesn't set a span on the error message, as the error is most useful if + // applied to the call site of the offending macro. Given that the message is very generic, + // putting it on the union keyword ends up being confusing. + syn::Data::Union(_) => Err(Error::custom("Unions are not supported")), + } + } + + /// Creates a new `Data<&'a V, &'a F>` instance from `Data<V, F>`. + pub fn as_ref(&self) -> Data<&V, &F> { + match *self { + Data::Enum(ref variants) => Data::Enum(variants.iter().collect()), + Data::Struct(ref data) => Data::Struct(data.as_ref()), + } + } + + /// Applies a function `V -> U` on enum variants, if this is an enum. + pub fn map_enum_variants<T, U>(self, map: T) -> Data<U, F> + where + T: FnMut(V) -> U, + { + match self { + Data::Enum(v) => Data::Enum(v.into_iter().map(map).collect()), + Data::Struct(f) => Data::Struct(f), + } + } + + /// Applies a function `F -> U` on struct fields, if this is a struct. + pub fn map_struct_fields<T, U>(self, map: T) -> Data<V, U> + where + T: FnMut(F) -> U, + { + match self { + Data::Enum(v) => Data::Enum(v), + Data::Struct(f) => Data::Struct(f.map(map)), + } + } + + /// Applies a function to the `Fields` if this is a struct. + pub fn map_struct<T, U>(self, mut map: T) -> Data<V, U> + where + T: FnMut(Fields<F>) -> Fields<U>, + { + match self { + Data::Enum(v) => Data::Enum(v), + Data::Struct(f) => Data::Struct(map(f)), + } + } + + /// Consumes the `Data`, returning `Fields<F>` if it was a struct. + pub fn take_struct(self) -> Option<Fields<F>> { + match self { + Data::Enum(_) => None, + Data::Struct(f) => Some(f), + } + } + + /// Consumes the `Data`, returning `Vec<V>` if it was an enum. + pub fn take_enum(self) -> Option<Vec<V>> { + match self { + Data::Enum(v) => Some(v), + Data::Struct(_) => None, + } + } + + /// Returns `true` if this instance is `Data::Enum`. + pub fn is_enum(&self) -> bool { + match *self { + Data::Enum(_) => true, + Data::Struct(_) => false, + } + } + + /// Returns `true` if this instance is `Data::Struct`. + pub fn is_struct(&self) -> bool { + !self.is_enum() + } +} + +impl<V: FromVariant, F: FromField> Data<V, F> { + /// Attempt to convert from a `syn::Data` instance. + pub fn try_from(body: &syn::Data) -> Result<Self> { + match *body { + syn::Data::Enum(ref data) => { + let mut errors = Error::accumulator(); + let items = data + .variants + .iter() + .filter_map(|v| errors.handle(FromVariant::from_variant(v))) + .collect(); + + errors.finish_with(Data::Enum(items)) + } + syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)), + // This deliberately doesn't set a span on the error message, as the error is most useful if + // applied to the call site of the offending macro. Given that the message is very generic, + // putting it on the union keyword ends up being confusing. + syn::Data::Union(_) => Err(Error::custom("Unions are not supported")), + } + } +} + +impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> { + fn uses_type_params<'a>( + &self, + options: &usage::Options, + type_set: &'a IdentSet, + ) -> IdentRefSet<'a> { + match *self { + Data::Struct(ref v) => v.uses_type_params(options, type_set), + Data::Enum(ref v) => v.uses_type_params(options, type_set), + } + } +} + +impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> { + fn uses_lifetimes<'a>( + &self, + options: &usage::Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes), + Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes), + } + } +} + +/// Equivalent to `syn::Fields`, but replaces the AST element with a generic. +#[derive(Debug, Clone)] +pub struct Fields<T> { + pub style: Style, + pub fields: Vec<T>, + span: Option<Span>, + __nonexhaustive: (), +} + +impl<T> Fields<T> { + /// Creates a new [`Fields`] struct. + pub fn new(style: Style, fields: Vec<T>) -> Self { + Self { + style, + fields, + span: None, + __nonexhaustive: (), + } + } + + /// Adds a [`Span`] to [`Fields`]. + pub fn with_span(mut self, span: Span) -> Self { + if self.span.is_none() { + self.span = Some(span); + } + self + } + + pub fn empty_from(vd: &syn::Fields) -> Self { + Self::new(vd.into(), Vec::new()) + } + + /// Splits the `Fields` into its style and fields for further processing. + /// Returns an empty `Vec` for `Unit` data. + pub fn split(self) -> (Style, Vec<T>) { + (self.style, self.fields) + } + + /// Returns true if this variant's data makes it a newtype. + pub fn is_newtype(&self) -> bool { + self.style == Style::Tuple && self.len() == 1 + } + + pub fn is_unit(&self) -> bool { + self.style.is_unit() + } + + pub fn is_tuple(&self) -> bool { + self.style.is_tuple() + } + + pub fn is_struct(&self) -> bool { + self.style.is_struct() + } + + pub fn as_ref(&self) -> Fields<&T> { + Fields { + style: self.style, + fields: self.fields.iter().collect(), + span: self.span, + __nonexhaustive: (), + } + } + + pub fn map<F, U>(self, map: F) -> Fields<U> + where + F: FnMut(T) -> U, + { + Fields { + style: self.style, + fields: self.fields.into_iter().map(map).collect(), + span: self.span, + __nonexhaustive: (), + } + } + + pub fn iter(&self) -> slice::Iter<T> { + self.fields.iter() + } + + /// Returns the number of fields in the structure. + pub fn len(&self) -> usize { + self.fields.len() + } + + /// Returns `true` if the `Fields` contains no fields. + pub fn is_empty(&self) -> bool { + self.fields.is_empty() + } +} + +impl<F: FromField> Fields<F> { + pub fn try_from(fields: &syn::Fields) -> Result<Self> { + let mut errors = Error::accumulator(); + let items = { + match &fields { + syn::Fields::Named(fields) => fields + .named + .iter() + .filter_map(|field| { + errors.handle(FromField::from_field(field).map_err(|err| { + // There should always be an ident here, since this is a collection + // of named fields, but `syn` doesn't prevent someone from manually + // constructing an invalid collection so a guard is still warranted. + if let Some(ident) = &field.ident { + err.at(ident) + } else { + err + } + })) + }) + .collect(), + syn::Fields::Unnamed(fields) => fields + .unnamed + .iter() + .filter_map(|field| errors.handle(FromField::from_field(field))) + .collect(), + syn::Fields::Unit => vec![], + } + }; + + errors.finish()?; + + Ok(Self::new(fields.into(), items).with_span(fields.span())) + } +} + +impl<T: ToTokens> ToTokens for Fields<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let fields = &self.fields; + // An unknown Span should be `Span::call_site()`; + // https://docs.rs/syn/1.0.12/syn/spanned/trait.Spanned.html#tymethod.span + let span = self.span.unwrap_or_else(Span::call_site); + + match self.style { + Style::Struct => { + let trailing_comma = { + if fields.is_empty() { + quote!() + } else { + quote!(,) + } + }; + + tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]); + } + Style::Tuple => { + tokens.extend(quote_spanned![span => ( #(#fields),* )]); + } + Style::Unit => {} + } + } +} + +impl<T: PartialEq> PartialEq for Fields<T> { + fn eq(&self, other: &Self) -> bool { + self.style == other.style && self.fields == other.fields + } +} + +impl<T: Eq> Eq for Fields<T> {} + +impl<T> IntoIterator for Fields<T> { + type Item = T; + type IntoIter = vec::IntoIter<T>; + + fn into_iter(self) -> Self::IntoIter { + self.fields.into_iter() + } +} + +impl<T> From<Style> for Fields<T> { + fn from(style: Style) -> Self { + Self::new(style, Vec::new()) + } +} + +impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> { + fn from((style, fields): (Style, U)) -> Self { + style.with_fields(fields) + } +} + +impl<T: UsesTypeParams> UsesTypeParams for Fields<T> { + fn uses_type_params<'a>( + &self, + options: &usage::Options, + type_set: &'a IdentSet, + ) -> IdentRefSet<'a> { + self.fields.uses_type_params(options, type_set) + } +} + +impl<T: UsesLifetimes> UsesLifetimes for Fields<T> { + fn uses_lifetimes<'a>( + &self, + options: &usage::Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + self.fields.uses_lifetimes(options, lifetimes) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Style { + Tuple, + Struct, + Unit, +} + +impl Style { + pub fn is_unit(self) -> bool { + self == Style::Unit + } + + pub fn is_tuple(self) -> bool { + self == Style::Tuple + } + + pub fn is_struct(self) -> bool { + self == Style::Struct + } + + /// Creates a new `Fields` of the specified style with the passed-in fields. + fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> { + Fields::new(self, fields.into()) + } +} + +impl From<syn::Fields> for Style { + fn from(vd: syn::Fields) -> Self { + (&vd).into() + } +} + +impl<'a> From<&'a syn::Fields> for Style { + fn from(vd: &syn::Fields) -> Self { + match *vd { + syn::Fields::Named(_) => Style::Struct, + syn::Fields::Unnamed(_) => Style::Tuple, + syn::Fields::Unit => Style::Unit, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // it is not possible to directly convert a TokenStream into syn::Fields, so you have + // to convert the TokenStream into DeriveInput first and then pass the syn::Fields to + // Fields::try_from. + fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> { + Fields::try_from(&{ + if let syn::Data::Struct(s) = syn::parse2::<syn::DeriveInput>(input).unwrap().data { + s.fields + } else { + panic!(); + } + }) + .unwrap() + } + + #[test] + fn test_style_eq() { + // `Fields` implements `Eq` manually, so it has to be ensured, that all fields of `Fields` + // implement `Eq`, this test would fail, if someone accidentally removed the Eq + // implementation from `Style`. + struct _AssertEq + where + Style: Eq; + } + + #[test] + fn test_fields_to_tokens_struct() { + let reference = quote!( + { + executable: String, + args: Vec<String>, + env: Vec<String>, + index: usize, + optional: Option<String>, + current_dir: String, + } + ); + let input = quote!( + struct ExampleTest #reference + ); + + let fields = token_stream_to_fields(input); + + let mut result = quote!(); + fields.to_tokens(&mut result); + assert_eq!(result.to_string(), reference.to_string()); + } + + #[test] + fn test_fields_to_tokens_tuple() { + let reference = quote!((u64, usize, &'a T)); + let input = quote!( + struct ExampleTest #reference; + ); + + let fields = token_stream_to_fields(input); + + let mut result = quote!(); + fields.to_tokens(&mut result); + assert_eq!(result.to_string(), reference.to_string()); + } +} diff --git a/third_party/rust/darling_core/src/ast/generics.rs b/third_party/rust/darling_core/src/ast/generics.rs new file mode 100644 index 0000000000..0909badce9 --- /dev/null +++ b/third_party/rust/darling_core/src/ast/generics.rs @@ -0,0 +1,190 @@ +//! Types for working with generics + +use std::iter::Iterator; +use std::slice::Iter; + +use crate::{FromGenericParam, FromGenerics, FromTypeParam, Result}; + +/// Extension trait for `GenericParam` to support getting values by variant. +/// +/// # Usage +/// `darling::ast::Generics` needs a way to test its params array in order to iterate over type params. +/// Rather than require callers to use `darling::ast::GenericParam` in all cases, this trait makes that +/// polymorphic. +pub trait GenericParamExt { + /// The type this GenericParam uses to represent type params and their bounds + type TypeParam; + type LifetimeDef; + type ConstParam; + + /// If this GenericParam is a type param, get the underlying value. + fn as_type_param(&self) -> Option<&Self::TypeParam> { + None + } + + /// If this GenericParam is a lifetime, get the underlying value. + fn as_lifetime_def(&self) -> Option<&Self::LifetimeDef> { + None + } + + /// If this GenericParam is a const param, get the underlying value. + fn as_const_param(&self) -> Option<&Self::ConstParam> { + None + } +} + +impl GenericParamExt for syn::GenericParam { + type TypeParam = syn::TypeParam; + type LifetimeDef = syn::LifetimeDef; + type ConstParam = syn::ConstParam; + + fn as_type_param(&self) -> Option<&Self::TypeParam> { + if let syn::GenericParam::Type(ref val) = *self { + Some(val) + } else { + None + } + } + + fn as_lifetime_def(&self) -> Option<&Self::LifetimeDef> { + if let syn::GenericParam::Lifetime(ref val) = *self { + Some(val) + } else { + None + } + } + + fn as_const_param(&self) -> Option<&Self::ConstParam> { + if let syn::GenericParam::Const(ref val) = *self { + Some(val) + } else { + None + } + } +} + +impl GenericParamExt for syn::TypeParam { + type TypeParam = syn::TypeParam; + type LifetimeDef = (); + type ConstParam = (); + + fn as_type_param(&self) -> Option<&Self::TypeParam> { + Some(self) + } +} + +/// A mirror of `syn::GenericParam` which is generic over all its contents. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GenericParam<T = syn::TypeParam, L = syn::LifetimeDef, C = syn::ConstParam> { + Type(T), + Lifetime(L), + Const(C), +} + +impl<T: FromTypeParam> FromTypeParam for GenericParam<T> { + fn from_type_param(type_param: &syn::TypeParam) -> Result<Self> { + Ok(GenericParam::Type(FromTypeParam::from_type_param( + type_param, + )?)) + } +} + +impl<T: FromTypeParam> FromGenericParam for GenericParam<T> { + fn from_generic_param(param: &syn::GenericParam) -> Result<Self> { + Ok(match *param { + syn::GenericParam::Type(ref ty) => { + GenericParam::Type(FromTypeParam::from_type_param(ty)?) + } + syn::GenericParam::Lifetime(ref val) => GenericParam::Lifetime(val.clone()), + syn::GenericParam::Const(ref val) => GenericParam::Const(val.clone()), + }) + } +} + +impl<T, L, C> GenericParamExt for GenericParam<T, L, C> { + type TypeParam = T; + type LifetimeDef = L; + type ConstParam = C; + + fn as_type_param(&self) -> Option<&T> { + if let GenericParam::Type(ref val) = *self { + Some(val) + } else { + None + } + } + + fn as_lifetime_def(&self) -> Option<&L> { + if let GenericParam::Lifetime(ref val) = *self { + Some(val) + } else { + None + } + } + + fn as_const_param(&self) -> Option<&C> { + if let GenericParam::Const(ref val) = *self { + Some(val) + } else { + None + } + } +} + +/// A mirror of the `syn::Generics` type which can contain arbitrary representations +/// of params and where clauses. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Generics<P, W = syn::WhereClause> { + pub params: Vec<P>, + pub where_clause: Option<W>, +} + +impl<P, W> Generics<P, W> { + pub fn type_params(&self) -> TypeParams<'_, P> { + TypeParams(self.params.iter()) + } +} + +impl<P: FromGenericParam> FromGenerics for Generics<P> { + fn from_generics(generics: &syn::Generics) -> Result<Self> { + Ok(Generics { + params: generics + .params + .iter() + .map(FromGenericParam::from_generic_param) + .collect::<Result<Vec<P>>>()?, + where_clause: generics.where_clause.clone(), + }) + } +} + +pub struct TypeParams<'a, P: 'a>(Iter<'a, P>); + +impl<'a, P: GenericParamExt> Iterator for TypeParams<'a, P> { + type Item = &'a <P as GenericParamExt>::TypeParam; + + fn next(&mut self) -> Option<Self::Item> { + let next = self.0.next(); + match next { + None => None, + Some(v) => match v.as_type_param() { + Some(val) => Some(val), + None => self.next(), + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::{GenericParam, Generics}; + use crate::FromGenerics; + + #[test] + fn generics() { + let g: syn::Generics = parse_quote!(<T>); + let deified: Generics<GenericParam<syn::Ident>> = FromGenerics::from_generics(&g).unwrap(); + assert!(deified.params.len() == 1); + assert!(deified.where_clause.is_none()); + } +} diff --git a/third_party/rust/darling_core/src/ast/mod.rs b/third_party/rust/darling_core/src/ast/mod.rs new file mode 100644 index 0000000000..492b26f182 --- /dev/null +++ b/third_party/rust/darling_core/src/ast/mod.rs @@ -0,0 +1,7 @@ +//! Utility types for working with the AST. + +mod data; +mod generics; + +pub use self::data::*; +pub use self::generics::{GenericParam, GenericParamExt, Generics}; diff --git a/third_party/rust/darling_core/src/codegen/attr_extractor.rs b/third_party/rust/darling_core/src/codegen/attr_extractor.rs new file mode 100644 index 0000000000..6ea1805ec0 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/attr_extractor.rs @@ -0,0 +1,115 @@ +use proc_macro2::TokenStream; + +use crate::options::ForwardAttrs; +use crate::util::PathList; + +/// Infrastructure for generating an attribute extractor. +pub trait ExtractAttribute { + /// A set of mutable declarations for all members of the implementing type. + fn local_declarations(&self) -> TokenStream; + + /// Gets the list of attribute names that should be parsed by the extractor. + fn attr_names(&self) -> &PathList; + + fn forwarded_attrs(&self) -> Option<&ForwardAttrs>; + + /// Gets the name used by the generated impl to return to the `syn` item passed as input. + fn param_name(&self) -> TokenStream; + + /// Get the tokens to access a borrowed list of attributes where extraction will take place. + /// + /// By default, this will be `&#input.attrs` where `#input` is `self.param_name()`. + fn attrs_accessor(&self) -> TokenStream { + let input = self.param_name(); + quote!(&#input.attrs) + } + + /// Gets the core from-meta-item loop that should be used on matching attributes. + fn core_loop(&self) -> TokenStream; + + /// Generates the main extraction loop. + fn extractor(&self) -> TokenStream { + let declarations = self.local_declarations(); + + let will_parse_any = !self.attr_names().is_empty(); + let will_fwd_any = self + .forwarded_attrs() + .map(|fa| !fa.is_empty()) + .unwrap_or_default(); + + if !(will_parse_any || will_fwd_any) { + return quote! { + #declarations + }; + } + + let attrs_accessor = self.attrs_accessor(); + + // The block for parsing attributes whose names have been claimed by the target + // struct. If no attributes were claimed, this is a pass-through. + let parse_handled = if will_parse_any { + let attr_names = self.attr_names().to_strings(); + let core_loop = self.core_loop(); + quote!( + #(#attr_names)|* => { + match ::darling::util::parse_attribute_to_meta_list(__attr) { + ::darling::export::Ok(__data) => { + if __data.nested.is_empty() { + continue; + } + + let __items = &__data.nested; + + #core_loop + } + // darling was asked to handle this attribute name, but the actual attribute + // isn't one that darling can work with. This either indicates a typing error + // or some misunderstanding of the meta attribute syntax; in either case, the + // caller should get a useful error. + ::darling::export::Err(__err) => { + __errors.push(__err); + } + } + } + ) + } else { + quote!() + }; + + // Specifies the behavior for unhandled attributes. They will either be silently ignored or + // forwarded to the inner struct for later analysis. + let forward_unhandled = if will_fwd_any { + forwards_to_local(self.forwarded_attrs().unwrap()) + } else { + quote!(_ => continue) + }; + + quote!( + #declarations + use ::darling::ToTokens; + let mut __fwd_attrs: ::darling::export::Vec<::syn::Attribute> = vec![]; + + for __attr in #attrs_accessor { + // Filter attributes based on name + match ::darling::export::ToString::to_string(&__attr.path.clone().into_token_stream()).as_str() { + #parse_handled + #forward_unhandled + } + } + ) + } +} + +fn forwards_to_local(behavior: &ForwardAttrs) -> TokenStream { + let push_command = quote!(__fwd_attrs.push(__attr.clone())); + match *behavior { + ForwardAttrs::All => quote!(_ => #push_command), + ForwardAttrs::Only(ref idents) => { + let names = idents.to_strings(); + quote!( + #(#names)|* => #push_command, + _ => continue, + ) + } + } +} diff --git a/third_party/rust/darling_core/src/codegen/default_expr.rs b/third_party/rust/darling_core/src/codegen/default_expr.rs new file mode 100644 index 0000000000..ed5863582d --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/default_expr.rs @@ -0,0 +1,46 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; +use syn::{Ident, Path}; + +/// This will be in scope during struct initialization after option parsing. +const DEFAULT_STRUCT_NAME: &str = "__default"; + +/// The fallback value for a field or container. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DefaultExpression<'a> { + /// Only valid on fields, `Inherit` indicates that the value should be taken from a pre-constructed + /// fallback object. The value in the variant is the ident of the field. + Inherit(&'a Ident), + Explicit(&'a Path), + Trait, +} + +impl<'a> DefaultExpression<'a> { + pub fn as_declaration(&'a self) -> DefaultDeclaration<'a> { + DefaultDeclaration(self) + } +} + +impl<'a> ToTokens for DefaultExpression<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(match *self { + DefaultExpression::Inherit(ident) => { + let dsn = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site()); + quote!(#dsn.#ident) + } + DefaultExpression::Explicit(path) => quote!(#path()), + DefaultExpression::Trait => quote!(::darling::export::Default::default()), + }); + } +} + +/// Used only by containers, this wrapper type generates code to declare the fallback instance. +pub struct DefaultDeclaration<'a>(&'a DefaultExpression<'a>); + +impl<'a> ToTokens for DefaultDeclaration<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let name = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site()); + let expr = self.0; + tokens.append_all(quote!(let #name: Self = #expr;)); + } +} diff --git a/third_party/rust/darling_core/src/codegen/error.rs b/third_party/rust/darling_core/src/codegen/error.rs new file mode 100644 index 0000000000..2055a82288 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/error.rs @@ -0,0 +1,46 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; + +/// Declares the local variable into which errors will be accumulated. +#[derive(Default)] +pub struct ErrorDeclaration { + __hidden: (), +} + +impl ToTokens for ErrorDeclaration { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(quote! { + let mut __errors = ::darling::Error::accumulator(); + }) + } +} + +/// Returns early if attribute or body parsing has caused any errors. +#[derive(Default)] +pub struct ErrorCheck<'a> { + location: Option<&'a str>, + __hidden: (), +} + +impl<'a> ErrorCheck<'a> { + pub fn with_location(location: &'a str) -> Self { + ErrorCheck { + location: Some(location), + __hidden: (), + } + } +} + +impl<'a> ToTokens for ErrorCheck<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let at_call = if let Some(ref s) = self.location { + quote!(.map_err(|e| e.at(#s))) + } else { + quote!() + }; + + tokens.append_all(quote! { + __errors.finish() #at_call?; + }) + } +} diff --git a/third_party/rust/darling_core/src/codegen/field.rs b/third_party/rust/darling_core/src/codegen/field.rs new file mode 100644 index 0000000000..2ff71f4ee8 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/field.rs @@ -0,0 +1,189 @@ +use std::borrow::Cow; + +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; +use syn::{Ident, Path, Type}; + +use crate::codegen::{DefaultExpression, PostfixTransform}; +use crate::usage::{self, IdentRefSet, IdentSet, UsesTypeParams}; + +/// Properties needed to generate code for a field in all the contexts +/// where one may appear. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Field<'a> { + /// The name presented to the user of the library. This will appear + /// in error messages and will be looked when parsing names. + pub name_in_attr: Cow<'a, String>, + + /// The name presented to the author of the library. This will appear + /// in the setters or temporary variables which contain the values. + pub ident: &'a Ident, + + /// The type of the field in the input. + pub ty: &'a Type, + pub default_expression: Option<DefaultExpression<'a>>, + pub with_path: Cow<'a, Path>, + pub post_transform: Option<&'a PostfixTransform>, + pub skip: bool, + pub multiple: bool, +} + +impl<'a> Field<'a> { + pub fn as_name(&'a self) -> &'a str { + &self.name_in_attr + } + + pub fn as_declaration(&'a self) -> Declaration<'a> { + Declaration(self) + } + + pub fn as_match(&'a self) -> MatchArm<'a> { + MatchArm(self) + } + + pub fn as_initializer(&'a self) -> Initializer<'a> { + Initializer(self) + } + + pub fn as_presence_check(&'a self) -> CheckMissing<'a> { + CheckMissing(self) + } +} + +impl<'a> UsesTypeParams for Field<'a> { + fn uses_type_params<'b>( + &self, + options: &usage::Options, + type_set: &'b IdentSet, + ) -> IdentRefSet<'b> { + self.ty.uses_type_params(options, type_set) + } +} + +/// An individual field during variable declaration in the generated parsing method. +pub struct Declaration<'a>(&'a Field<'a>); + +impl<'a> ToTokens for Declaration<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let field: &Field = self.0; + let ident = field.ident; + let ty = field.ty; + + tokens.append_all(if field.multiple { + // This is NOT mutable, as it will be declared mutable only temporarily. + quote!(let mut #ident: #ty = ::darling::export::Default::default();) + } else { + quote!(let mut #ident: (bool, ::darling::export::Option<#ty>) = (false, None);) + }); + } +} + +/// Represents an individual field in the match. +pub struct MatchArm<'a>(&'a Field<'a>); + +impl<'a> ToTokens for MatchArm<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let field: &Field = self.0; + if !field.skip { + let name_str = &field.name_in_attr; + let ident = field.ident; + let with_path = &field.with_path; + let post_transform = field.post_transform.as_ref(); + + // Errors include the location of the bad input, so we compute that here. + // Fields that take multiple values add the index of the error for convenience, + // while single-value fields only expose the name in the input attribute. + let location = if field.multiple { + // we use the local variable `len` here because location is accessed via + // a closure, and the borrow checker gets very unhappy if we try to immutably + // borrow `#ident` in that closure when it was declared `mut` outside. + quote!(&format!("{}[{}]", #name_str, __len)) + } else { + quote!(#name_str) + }; + + // Add the span immediately on extraction failure, so that it's as specific as possible. + // The behavior of `with_span` makes this safe to do; if the child applied an + // even-more-specific span, our attempt here will not overwrite that and will only cost + // us one `if` check. + let extractor = quote!(#with_path(__inner)#post_transform.map_err(|e| e.with_span(&__inner).at(#location))); + + tokens.append_all(if field.multiple { + quote!( + #name_str => { + // Store the index of the name we're assessing in case we need + // it for error reporting. + let __len = #ident.len(); + if let ::darling::export::Some(__val) = __errors.handle(#extractor) { + #ident.push(__val) + } + } + ) + } else { + quote!( + #name_str => { + if !#ident.0 { + #ident = (true, __errors.handle(#extractor)); + } else { + __errors.push(::darling::Error::duplicate_field(#name_str).with_span(&__inner)); + } + } + ) + }); + } + } +} + +/// Wrapper to generate initialization code for a field. +pub struct Initializer<'a>(&'a Field<'a>); + +impl<'a> ToTokens for Initializer<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let field: &Field = self.0; + let ident = field.ident; + tokens.append_all(if field.multiple { + if let Some(ref expr) = field.default_expression { + quote!(#ident: if !#ident.is_empty() { + #ident + } else { + #expr + }) + } else { + quote!(#ident: #ident) + } + } else if let Some(ref expr) = field.default_expression { + quote!(#ident: match #ident.1 { + ::darling::export::Some(__val) => __val, + ::darling::export::None => #expr, + }) + } else { + quote!(#ident: #ident.1.expect("Uninitialized fields without defaults were already checked")) + }); + } +} + +/// Creates an error if a field has no value and no default. +pub struct CheckMissing<'a>(&'a Field<'a>); + +impl<'a> ToTokens for CheckMissing<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + if !self.0.multiple && self.0.default_expression.is_none() { + let ident = self.0.ident; + let ty = self.0.ty; + let name_in_attr = &self.0.name_in_attr; + + tokens.append_all(quote! { + if !#ident.0 { + match <#ty as ::darling::FromMeta>::from_none() { + ::darling::export::Some(__type_fallback) => { + #ident.1 = ::darling::export::Some(__type_fallback); + } + ::darling::export::None => { + __errors.push(::darling::Error::missing_field(#name_in_attr)) + } + } + } + }) + } + } +} diff --git a/third_party/rust/darling_core/src/codegen/from_attributes_impl.rs b/third_party/rust/darling_core/src/codegen/from_attributes_impl.rs new file mode 100644 index 0000000000..552be0325f --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_attributes_impl.rs @@ -0,0 +1,109 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; + +use crate::{ + ast::Data, + codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}, + options::ForwardAttrs, + util::PathList, +}; + +pub struct FromAttributesImpl<'a> { + pub base: TraitImpl<'a>, + pub attr_names: &'a PathList, +} + +impl ToTokens for FromAttributesImpl<'_> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let ty_ident = self.base.ident; + let input = self.param_name(); + let post_transform = self.base.post_transform_call(); + + if let Data::Struct(ref data) = self.base.data { + if data.is_newtype() { + self.wrap( + quote! { + fn from_attributes(#input: &[::syn::Attribute]) -> ::darling::Result<Self> { + ::darling::export::Ok( + #ty_ident(::darling::FromAttributes::from_attributes(#input)?) + ) #post_transform + } + }, + tokens, + ); + + return; + } + } + + let inits = self.base.initializers(); + let default = self.base.fallback_decl(); + + let grab_attrs = self.extractor(); + + let declare_errors = self.base.declare_errors(); + let require_fields = self.base.require_fields(); + let check_errors = self.base.check_errors(); + + self.wrap( + quote! { + fn from_attributes(#input: &[::syn::Attribute]) -> ::darling::Result<Self> { + #declare_errors + + #grab_attrs + + #require_fields + + #check_errors + + #default + + ::darling::export::Ok(#ty_ident { + #inits + }) #post_transform + } + }, + tokens, + ); + } +} + +impl<'a> ExtractAttribute for FromAttributesImpl<'a> { + fn local_declarations(&self) -> TokenStream { + self.base.local_declarations() + } + + fn attr_names(&self) -> &PathList { + self.attr_names + } + + fn forwarded_attrs(&self) -> Option<&ForwardAttrs> { + None + } + + fn param_name(&self) -> TokenStream { + quote!(__di) + } + + fn attrs_accessor(&self) -> TokenStream { + self.param_name() + } + + fn core_loop(&self) -> TokenStream { + self.base.core_loop() + } +} + +impl<'a> OuterFromImpl<'a> for FromAttributesImpl<'a> { + fn trait_path(&self) -> syn::Path { + path!(::darling::FromAttributes) + } + + fn trait_bound(&self) -> syn::Path { + path!(::darling::FromMeta) + } + + fn base(&'a self) -> &'a TraitImpl<'a> { + &self.base + } +} diff --git a/third_party/rust/darling_core/src/codegen/from_derive_impl.rs b/third_party/rust/darling_core/src/codegen/from_derive_impl.rs new file mode 100644 index 0000000000..42894f5bf8 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_derive_impl.rs @@ -0,0 +1,147 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; + +use crate::{ + ast::Data, + codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}, + options::{ForwardAttrs, Shape}, + util::PathList, +}; + +pub struct FromDeriveInputImpl<'a> { + pub ident: Option<&'a Ident>, + pub generics: Option<&'a Ident>, + pub vis: Option<&'a Ident>, + pub attrs: Option<&'a Ident>, + pub data: Option<&'a Ident>, + pub base: TraitImpl<'a>, + pub attr_names: &'a PathList, + pub forward_attrs: Option<&'a ForwardAttrs>, + pub from_ident: bool, + pub supports: Option<&'a Shape>, +} + +impl<'a> ToTokens for FromDeriveInputImpl<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let ty_ident = self.base.ident; + let input = self.param_name(); + let post_transform = self.base.post_transform_call(); + + if let Data::Struct(ref data) = self.base.data { + if data.is_newtype() { + self.wrap( + quote!{ + fn from_derive_input(#input: &::syn::DeriveInput) -> ::darling::Result<Self> { + ::darling::export::Ok( + #ty_ident(::darling::FromDeriveInput::from_derive_input(#input)?) + ) #post_transform + } + }, + tokens, + ); + + return; + } + } + + let passed_ident = self + .ident + .as_ref() + .map(|i| quote!(#i: #input.ident.clone(),)); + let passed_vis = self.vis.as_ref().map(|i| quote!(#i: #input.vis.clone(),)); + let passed_generics = self + .generics + .as_ref() + .map(|i| quote!(#i: ::darling::FromGenerics::from_generics(&#input.generics)?,)); + let passed_attrs = self.attrs.as_ref().map(|i| quote!(#i: __fwd_attrs,)); + let passed_body = self + .data + .as_ref() + .map(|i| quote!(#i: ::darling::ast::Data::try_from(&#input.data)?,)); + + let supports = self.supports.map(|i| { + quote! { + #i + __errors.handle(__validate_body(&#input.data)); + } + }); + + let inits = self.base.initializers(); + let default = if self.from_ident { + quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());) + } else { + self.base.fallback_decl() + }; + + let grab_attrs = self.extractor(); + + let declare_errors = self.base.declare_errors(); + let require_fields = self.base.require_fields(); + let check_errors = self.base.check_errors(); + + self.wrap( + quote! { + fn from_derive_input(#input: &::syn::DeriveInput) -> ::darling::Result<Self> { + #declare_errors + + #grab_attrs + + #supports + + #require_fields + + #check_errors + + #default + + ::darling::export::Ok(#ty_ident { + #passed_ident + #passed_generics + #passed_vis + #passed_attrs + #passed_body + #inits + }) #post_transform + } + }, + tokens, + ); + } +} + +impl<'a> ExtractAttribute for FromDeriveInputImpl<'a> { + fn attr_names(&self) -> &PathList { + self.attr_names + } + + fn forwarded_attrs(&self) -> Option<&ForwardAttrs> { + self.forward_attrs + } + + fn param_name(&self) -> TokenStream { + quote!(__di) + } + + fn core_loop(&self) -> TokenStream { + self.base.core_loop() + } + + fn local_declarations(&self) -> TokenStream { + self.base.local_declarations() + } +} + +impl<'a> OuterFromImpl<'a> for FromDeriveInputImpl<'a> { + fn trait_path(&self) -> syn::Path { + path!(::darling::FromDeriveInput) + } + + fn trait_bound(&self) -> syn::Path { + path!(::darling::FromMeta) + } + + fn base(&'a self) -> &'a TraitImpl<'a> { + &self.base + } +} diff --git a/third_party/rust/darling_core/src/codegen/from_field.rs b/third_party/rust/darling_core/src/codegen/from_field.rs new file mode 100644 index 0000000000..30e47404bb --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_field.rs @@ -0,0 +1,114 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; + +use crate::{ + codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}, + options::ForwardAttrs, + util::PathList, +}; + +/// `impl FromField` generator. This is used for parsing an individual +/// field and its attributes. +pub struct FromFieldImpl<'a> { + pub ident: Option<&'a Ident>, + pub vis: Option<&'a Ident>, + pub ty: Option<&'a Ident>, + pub attrs: Option<&'a Ident>, + pub base: TraitImpl<'a>, + pub attr_names: &'a PathList, + pub forward_attrs: Option<&'a ForwardAttrs>, + pub from_ident: bool, +} + +impl<'a> ToTokens for FromFieldImpl<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let input = self.param_name(); + + let error_declaration = self.base.declare_errors(); + let require_fields = self.base.require_fields(); + let error_check = self.base.check_errors(); + + let initializers = self.base.initializers(); + + let default = if self.from_ident { + quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());) + } else { + self.base.fallback_decl() + }; + + let passed_ident = self + .ident + .as_ref() + .map(|i| quote!(#i: #input.ident.clone(),)); + let passed_vis = self.vis.as_ref().map(|i| quote!(#i: #input.vis.clone(),)); + let passed_ty = self.ty.as_ref().map(|i| quote!(#i: #input.ty.clone(),)); + let passed_attrs = self.attrs.as_ref().map(|i| quote!(#i: __fwd_attrs,)); + + // Determine which attributes to forward (if any). + let grab_attrs = self.extractor(); + let post_transform = self.base.post_transform_call(); + + self.wrap( + quote! { + fn from_field(#input: &::syn::Field) -> ::darling::Result<Self> { + #error_declaration + + #grab_attrs + + #require_fields + + #error_check + + #default + + ::darling::export::Ok(Self { + #passed_ident + #passed_ty + #passed_vis + #passed_attrs + #initializers + }) #post_transform + + } + }, + tokens, + ); + } +} + +impl<'a> ExtractAttribute for FromFieldImpl<'a> { + fn attr_names(&self) -> &PathList { + self.attr_names + } + + fn forwarded_attrs(&self) -> Option<&ForwardAttrs> { + self.forward_attrs + } + + fn param_name(&self) -> TokenStream { + quote!(__field) + } + + fn core_loop(&self) -> TokenStream { + self.base.core_loop() + } + + fn local_declarations(&self) -> TokenStream { + self.base.local_declarations() + } +} + +impl<'a> OuterFromImpl<'a> for FromFieldImpl<'a> { + fn trait_path(&self) -> syn::Path { + path!(::darling::FromField) + } + + fn trait_bound(&self) -> syn::Path { + path!(::darling::FromMeta) + } + + fn base(&'a self) -> &'a TraitImpl<'a> { + &self.base + } +} diff --git a/third_party/rust/darling_core/src/codegen/from_meta_impl.rs b/third_party/rust/darling_core/src/codegen/from_meta_impl.rs new file mode 100644 index 0000000000..24ccc57a5e --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_meta_impl.rs @@ -0,0 +1,135 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; + +use crate::ast::{Data, Fields, Style}; +use crate::codegen::{Field, OuterFromImpl, TraitImpl, Variant}; + +pub struct FromMetaImpl<'a> { + pub base: TraitImpl<'a>, +} + +impl<'a> ToTokens for FromMetaImpl<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let base = &self.base; + + let impl_block = match base.data { + // Unit structs allow empty bodies only. + Data::Struct(ref vd) if vd.style.is_unit() => { + let ty_ident = base.ident; + quote!( + fn from_word() -> ::darling::Result<Self> { + ::darling::export::Ok(#ty_ident) + } + ) + } + + // Newtype structs proxy to the sole value they contain. + Data::Struct(Fields { + ref fields, + style: Style::Tuple, + .. + }) if fields.len() == 1 => { + let ty_ident = base.ident; + quote!( + fn from_meta(__item: &::syn::Meta) -> ::darling::Result<Self> { + ::darling::FromMeta::from_meta(__item) + .map_err(|e| e.with_span(&__item)) + .map(#ty_ident) + } + ) + } + Data::Struct(Fields { + style: Style::Tuple, + .. + }) => { + panic!("Multi-field tuples are not supported"); + } + Data::Struct(ref data) => { + let inits = data.fields.iter().map(Field::as_initializer); + let declare_errors = base.declare_errors(); + let require_fields = base.require_fields(); + let check_errors = base.check_errors(); + let decls = base.local_declarations(); + let core_loop = base.core_loop(); + let default = base.fallback_decl(); + let post_transform = base.post_transform_call(); + + quote!( + fn from_list(__items: &[::syn::NestedMeta]) -> ::darling::Result<Self> { + + #decls + + #declare_errors + + #core_loop + + #require_fields + + #check_errors + + #default + + ::darling::export::Ok(Self { + #(#inits),* + }) #post_transform + } + ) + } + Data::Enum(ref variants) => { + let unit_arms = variants.iter().map(Variant::as_unit_match_arm); + let struct_arms = variants.iter().map(Variant::as_data_match_arm); + + let unknown_variant_err = if !variants.is_empty() { + let names = variants.iter().map(Variant::as_name); + quote! { + unknown_field_with_alts(__other, &[#(#names),*]) + } + } else { + quote! { + unknown_field(__other) + } + }; + + quote!( + fn from_list(__outer: &[::syn::NestedMeta]) -> ::darling::Result<Self> { + // An enum must have exactly one value inside the parentheses if it's not a unit + // match arm + match __outer.len() { + 0 => ::darling::export::Err(::darling::Error::too_few_items(1)), + 1 => { + if let ::syn::NestedMeta::Meta(ref __nested) = __outer[0] { + match ::darling::util::path_to_string(__nested.path()).as_ref() { + #(#struct_arms)* + __other => ::darling::export::Err(::darling::Error::#unknown_variant_err.with_span(__nested)) + } + } else { + ::darling::export::Err(::darling::Error::unsupported_format("literal")) + } + } + _ => ::darling::export::Err(::darling::Error::too_many_items(1)), + } + } + + fn from_string(lit: &str) -> ::darling::Result<Self> { + match lit { + #(#unit_arms)* + __other => ::darling::export::Err(::darling::Error::unknown_value(__other)) + } + } + ) + } + }; + + self.wrap(impl_block, tokens); + } +} + +impl<'a> OuterFromImpl<'a> for FromMetaImpl<'a> { + fn trait_path(&self) -> syn::Path { + path!(::darling::FromMeta) + } + + fn base(&'a self) -> &'a TraitImpl<'a> { + &self.base + } +} diff --git a/third_party/rust/darling_core/src/codegen/from_type_param.rs b/third_party/rust/darling_core/src/codegen/from_type_param.rs new file mode 100644 index 0000000000..59a0d8ecd5 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_type_param.rs @@ -0,0 +1,113 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; + +use crate::codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}; +use crate::options::ForwardAttrs; +use crate::util::PathList; + +pub struct FromTypeParamImpl<'a> { + pub base: TraitImpl<'a>, + pub ident: Option<&'a Ident>, + pub attrs: Option<&'a Ident>, + pub bounds: Option<&'a Ident>, + pub default: Option<&'a Ident>, + pub attr_names: &'a PathList, + pub forward_attrs: Option<&'a ForwardAttrs>, + pub from_ident: bool, +} + +impl<'a> ToTokens for FromTypeParamImpl<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let input = self.param_name(); + + let error_declaration = self.base.declare_errors(); + let grab_attrs = self.extractor(); + let require_fields = self.base.require_fields(); + let error_check = self.base.check_errors(); + + let default = if self.from_ident { + quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());) + } else { + self.base.fallback_decl() + }; + + let passed_ident = self + .ident + .as_ref() + .map(|i| quote!(#i: #input.ident.clone(),)); + let passed_attrs = self.attrs.as_ref().map(|i| quote!(#i: __fwd_attrs,)); + let passed_bounds = self + .bounds + .as_ref() + .map(|i| quote!(#i: #input.bounds.clone().into_iter().collect::<Vec<_>>(),)); + let passed_default = self + .default + .as_ref() + .map(|i| quote!(#i: #input.default.clone(),)); + let initializers = self.base.initializers(); + + let post_transform = self.base.post_transform_call(); + + self.wrap( + quote! { + fn from_type_param(#input: &::syn::TypeParam) -> ::darling::Result<Self> { + #error_declaration + + #grab_attrs + + #require_fields + + #error_check + + #default + + ::darling::export::Ok(Self { + #passed_ident + #passed_bounds + #passed_default + #passed_attrs + #initializers + }) #post_transform + } + }, + tokens, + ); + } +} + +impl<'a> ExtractAttribute for FromTypeParamImpl<'a> { + fn attr_names(&self) -> &PathList { + self.attr_names + } + + fn forwarded_attrs(&self) -> Option<&ForwardAttrs> { + self.forward_attrs + } + + fn param_name(&self) -> TokenStream { + quote!(__type_param) + } + + fn core_loop(&self) -> TokenStream { + self.base.core_loop() + } + + fn local_declarations(&self) -> TokenStream { + self.base.local_declarations() + } +} + +impl<'a> OuterFromImpl<'a> for FromTypeParamImpl<'a> { + fn trait_path(&self) -> syn::Path { + path!(::darling::FromTypeParam) + } + + fn trait_bound(&self) -> syn::Path { + path!(::darling::FromMeta) + } + + fn base(&'a self) -> &'a TraitImpl<'a> { + &self.base + } +} diff --git a/third_party/rust/darling_core/src/codegen/from_variant_impl.rs b/third_party/rust/darling_core/src/codegen/from_variant_impl.rs new file mode 100644 index 0000000000..d23bb4962f --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_variant_impl.rs @@ -0,0 +1,140 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; + +use crate::codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}; +use crate::options::{DataShape, ForwardAttrs}; +use crate::util::PathList; + +pub struct FromVariantImpl<'a> { + pub base: TraitImpl<'a>, + /// If set, the ident of the field into which the variant ident should be placed. + /// + /// This is one of `darling`'s "magic fields", which allow a type deriving a `darling` + /// trait to get fields from the input `syn` element added to the deriving struct + /// automatically. + pub ident: Option<&'a Ident>, + /// If set, the ident of the field into which the transformed output of the input + /// variant's fields should be placed. + /// + /// This is one of `darling`'s "magic fields". + pub fields: Option<&'a Ident>, + /// If set, the ident of the field into which the forwarded attributes of the input + /// variant should be placed. + /// + /// This is one of `darling`'s "magic fields". + pub attrs: Option<&'a Ident>, + /// If set, the ident of the field into which the discriminant of the input variant + /// should be placed. The receiving field must be an `Option` as not all enums have + /// discriminants. + /// + /// This is one of `darling`'s "magic fields". + pub discriminant: Option<&'a Ident>, + pub attr_names: &'a PathList, + pub forward_attrs: Option<&'a ForwardAttrs>, + pub from_ident: bool, + pub supports: Option<&'a DataShape>, +} + +impl<'a> ToTokens for FromVariantImpl<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let input = self.param_name(); + let extractor = self.extractor(); + let passed_ident = self + .ident + .as_ref() + .map(|i| quote!(#i: #input.ident.clone(),)); + let passed_discriminant = self + .discriminant + .as_ref() + .map(|i| quote!(#i: #input.discriminant.as_ref().map(|(_, expr)| expr.clone()),)); + let passed_attrs = self.attrs.as_ref().map(|i| quote!(#i: __fwd_attrs,)); + let passed_fields = self + .fields + .as_ref() + .map(|i| quote!(#i: ::darling::ast::Fields::try_from(&#input.fields)?,)); + + let inits = self.base.initializers(); + let post_transform = self.base.post_transform_call(); + + let default = if self.from_ident { + quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());) + } else { + self.base.fallback_decl() + }; + + let supports = self.supports.map(|i| { + quote! { + #i + __errors.handle(__validate_data(&#input.fields)); + } + }); + + let error_declaration = self.base.declare_errors(); + let require_fields = self.base.require_fields(); + let error_check = self.base.check_errors(); + + self.wrap( + quote!( + fn from_variant(#input: &::syn::Variant) -> ::darling::Result<Self> { + #error_declaration + + #extractor + + #supports + + #require_fields + + #error_check + + #default + + ::darling::export::Ok(Self { + #passed_ident + #passed_discriminant + #passed_attrs + #passed_fields + #inits + }) #post_transform + } + ), + tokens, + ); + } +} + +impl<'a> ExtractAttribute for FromVariantImpl<'a> { + fn local_declarations(&self) -> TokenStream { + self.base.local_declarations() + } + + fn attr_names(&self) -> &PathList { + self.attr_names + } + + fn forwarded_attrs(&self) -> Option<&ForwardAttrs> { + self.forward_attrs + } + + fn param_name(&self) -> TokenStream { + quote!(__variant) + } + + fn core_loop(&self) -> TokenStream { + self.base.core_loop() + } +} + +impl<'a> OuterFromImpl<'a> for FromVariantImpl<'a> { + fn trait_path(&self) -> syn::Path { + path!(::darling::FromVariant) + } + + fn trait_bound(&self) -> syn::Path { + path!(::darling::FromMeta) + } + + fn base(&'a self) -> &'a TraitImpl<'a> { + &self.base + } +} diff --git a/third_party/rust/darling_core/src/codegen/mod.rs b/third_party/rust/darling_core/src/codegen/mod.rs new file mode 100644 index 0000000000..d2a1546e05 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/mod.rs @@ -0,0 +1,30 @@ +mod attr_extractor; +mod default_expr; +mod error; +mod field; +mod from_attributes_impl; +mod from_derive_impl; +mod from_field; +mod from_meta_impl; +mod from_type_param; +mod from_variant_impl; +mod outer_from_impl; +mod postfix_transform; +mod trait_impl; +mod variant; +mod variant_data; + +pub(in crate::codegen) use self::attr_extractor::ExtractAttribute; +pub use self::default_expr::DefaultExpression; +pub use self::field::Field; +pub use self::from_attributes_impl::FromAttributesImpl; +pub use self::from_derive_impl::FromDeriveInputImpl; +pub use self::from_field::FromFieldImpl; +pub use self::from_meta_impl::FromMetaImpl; +pub use self::from_type_param::FromTypeParamImpl; +pub use self::from_variant_impl::FromVariantImpl; +pub use self::outer_from_impl::OuterFromImpl; +pub use self::postfix_transform::PostfixTransform; +pub use self::trait_impl::TraitImpl; +pub use self::variant::Variant; +pub use self::variant_data::FieldsGen; diff --git a/third_party/rust/darling_core/src/codegen/outer_from_impl.rs b/third_party/rust/darling_core/src/codegen/outer_from_impl.rs new file mode 100644 index 0000000000..29d792c066 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/outer_from_impl.rs @@ -0,0 +1,60 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; +use syn::{GenericParam, Generics, Path, TraitBound, TraitBoundModifier, TypeParamBound}; + +use crate::codegen::TraitImpl; +use crate::usage::IdentSet; + +/// Wrapper for "outer From" traits, such as `FromDeriveInput`, `FromVariant`, and `FromField`. +pub trait OuterFromImpl<'a> { + /// Gets the path of the trait being implemented. + fn trait_path(&self) -> Path; + + fn base(&'a self) -> &'a TraitImpl<'a>; + + fn trait_bound(&self) -> Path { + self.trait_path() + } + + fn wrap<T: ToTokens>(&'a self, body: T, tokens: &mut TokenStream) { + let base = self.base(); + let trayt = self.trait_path(); + let ty_ident = base.ident; + // The type parameters used in non-skipped, non-magic fields. + // These must impl `FromMeta` unless they have custom bounds. + let used = base.used_type_params(); + let generics = compute_impl_bounds(self.trait_bound(), base.generics.clone(), &used); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + tokens.append_all(quote!( + impl #impl_generics #trayt for #ty_ident #ty_generics + #where_clause + { + #body + } + )); + } +} + +fn compute_impl_bounds(bound: Path, mut generics: Generics, applies_to: &IdentSet) -> Generics { + if generics.params.is_empty() { + return generics; + } + + let added_bound = TypeParamBound::Trait(TraitBound { + paren_token: None, + modifier: TraitBoundModifier::None, + lifetimes: None, + path: bound, + }); + + for param in generics.params.iter_mut() { + if let GenericParam::Type(ref mut typ) = *param { + if applies_to.contains(&typ.ident) { + typ.bounds.push(added_bound.clone()); + } + } + } + + generics +} diff --git a/third_party/rust/darling_core/src/codegen/postfix_transform.rs b/third_party/rust/darling_core/src/codegen/postfix_transform.rs new file mode 100644 index 0000000000..917bd99716 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/postfix_transform.rs @@ -0,0 +1,30 @@ +use quote::{ToTokens, TokenStreamExt}; +use syn::{Ident, Path}; + +/// A method invocation applied to a value. +/// +/// This is used for `map` and `and_then` transforms in derivations. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PostfixTransform { + pub(crate) transformer: Ident, + pub(crate) function: Path, +} + +impl PostfixTransform { + pub fn new(transformer: Ident, function: Path) -> Self { + Self { + transformer, + function, + } + } +} + +impl ToTokens for PostfixTransform { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let Self { + transformer, + function, + } = self; + tokens.append_all(quote!(.#transformer(#function))) + } +} diff --git a/third_party/rust/darling_core/src/codegen/trait_impl.rs b/third_party/rust/darling_core/src/codegen/trait_impl.rs new file mode 100644 index 0000000000..4b0ed43f4f --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/trait_impl.rs @@ -0,0 +1,135 @@ +use proc_macro2::TokenStream; +use syn::{Generics, Ident, WherePredicate}; + +use crate::ast::{Data, Fields}; +use crate::codegen::{ + error::{ErrorCheck, ErrorDeclaration}, + DefaultExpression, Field, FieldsGen, PostfixTransform, Variant, +}; +use crate::usage::{CollectTypeParams, IdentSet, Purpose}; + +#[derive(Debug)] +pub struct TraitImpl<'a> { + pub ident: &'a Ident, + pub generics: &'a Generics, + pub data: Data<Variant<'a>, Field<'a>>, + pub default: Option<DefaultExpression<'a>>, + pub post_transform: Option<&'a PostfixTransform>, + pub bound: Option<&'a [WherePredicate]>, + pub allow_unknown_fields: bool, +} + +impl<'a> TraitImpl<'a> { + /// Get all declared type parameters. + pub fn declared_type_params(&self) -> IdentSet { + self.generics + .type_params() + .map(|tp| tp.ident.clone()) + .collect() + } + + /// Get the type parameters which are used by non-skipped, non-magic fields. + /// These type parameters will have a `FromMeta` bound applied to them in emitted + /// code. + pub fn used_type_params(&self) -> IdentSet { + self.type_params_matching(|f| !f.skip, |v| !v.skip) + } + + fn type_params_matching<F, V>(&self, field_filter: F, variant_filter: V) -> IdentSet + where + F: Fn(&&Field) -> bool, + V: Fn(&&Variant) -> bool, + { + let declared = self.declared_type_params(); + match self.data { + Data::Struct(ref v) => self.type_params_in_fields(v, &field_filter, &declared), + Data::Enum(ref v) => { + v.iter() + .filter(variant_filter) + .fold(Default::default(), |mut state, variant| { + state.extend(self.type_params_in_fields( + &variant.data, + &field_filter, + &declared, + )); + state + }) + } + } + } + + /// Get the type parameters of all fields in a set matching some filter + fn type_params_in_fields<'b, F>( + &'b self, + fields: &'b Fields<Field<'a>>, + field_filter: F, + declared: &IdentSet, + ) -> IdentSet + where + F: Fn(&&'b Field) -> bool, + { + fields + .iter() + .filter(field_filter) + .collect_type_params_cloned(&Purpose::BoundImpl.into(), declared) + } +} + +impl<'a> TraitImpl<'a> { + /// Gets the `let` declaration for errors accumulated during parsing. + pub fn declare_errors(&self) -> ErrorDeclaration { + ErrorDeclaration::default() + } + + /// Gets the check which performs an early return if errors occurred during parsing. + pub fn check_errors(&self) -> ErrorCheck { + ErrorCheck::default() + } + + /// Generate local variable declarations for all fields. + pub(in crate::codegen) fn local_declarations(&self) -> TokenStream { + if let Data::Struct(ref vd) = self.data { + let vdr = vd.as_ref().map(Field::as_declaration); + let decls = vdr.fields.as_slice(); + quote!(#(#decls)*) + } else { + quote!() + } + } + + pub(in crate::codegen) fn post_transform_call(&self) -> Option<TokenStream> { + self.post_transform.map(|pt| quote!(#pt)) + } + + /// Generate local variable declaration and initialization for instance from which missing fields will be taken. + pub(in crate::codegen) fn fallback_decl(&self) -> TokenStream { + let default = self.default.as_ref().map(DefaultExpression::as_declaration); + quote!(#default) + } + + pub fn require_fields(&self) -> TokenStream { + if let Data::Struct(ref vd) = self.data { + let check_nones = vd.as_ref().map(Field::as_presence_check); + let checks = check_nones.fields.as_slice(); + quote!(#(#checks)*) + } else { + quote!() + } + } + + pub(in crate::codegen) fn initializers(&self) -> TokenStream { + self.make_field_ctx().initializers() + } + + /// Generate the loop which walks meta items looking for property matches. + pub(in crate::codegen) fn core_loop(&self) -> TokenStream { + self.make_field_ctx().core_loop() + } + + fn make_field_ctx(&'a self) -> FieldsGen<'a> { + match self.data { + Data::Enum(_) => panic!("Core loop on enums isn't supported"), + Data::Struct(ref data) => FieldsGen::new(data, self.allow_unknown_fields), + } + } +} diff --git a/third_party/rust/darling_core/src/codegen/variant.rs b/third_party/rust/darling_core/src/codegen/variant.rs new file mode 100644 index 0000000000..7dc5f87711 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/variant.rs @@ -0,0 +1,158 @@ +use std::borrow::Cow; + +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; +use syn::Ident; + +use crate::ast::Fields; +use crate::codegen::error::{ErrorCheck, ErrorDeclaration}; +use crate::codegen::{Field, FieldsGen}; +use crate::usage::{self, IdentRefSet, IdentSet, UsesTypeParams}; + +/// A variant of the enum which is deriving `FromMeta`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Variant<'a> { + /// The name which will appear in code passed to the `FromMeta` input. + pub name_in_attr: Cow<'a, String>, + + /// The name of the variant which will be returned for a given `name_in_attr`. + pub variant_ident: &'a Ident, + + /// The name of the parent enum type. + pub ty_ident: &'a Ident, + + pub data: Fields<Field<'a>>, + + /// Whether or not the variant should be skipped in the generated code. + pub skip: bool, + + pub allow_unknown_fields: bool, +} + +impl<'a> Variant<'a> { + pub fn as_name(&'a self) -> &'a str { + &self.name_in_attr + } + + pub fn as_unit_match_arm(&'a self) -> UnitMatchArm<'a> { + UnitMatchArm(self) + } + + pub fn as_data_match_arm(&'a self) -> DataMatchArm<'a> { + DataMatchArm(self) + } +} + +impl<'a> UsesTypeParams for Variant<'a> { + fn uses_type_params<'b>( + &self, + options: &usage::Options, + type_set: &'b IdentSet, + ) -> IdentRefSet<'b> { + self.data.uses_type_params(options, type_set) + } +} + +/// Code generator for an enum variant in a unit match position. +/// This is placed in generated `from_string` calls for the parent enum. +/// Value-carrying variants wrapped in this type will emit code to produce an "unsupported format" error. +pub struct UnitMatchArm<'a>(&'a Variant<'a>); + +impl<'a> ToTokens for UnitMatchArm<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let val: &Variant<'a> = self.0; + + if val.skip { + return; + } + + let name_in_attr = &val.name_in_attr; + + if val.data.is_unit() { + let variant_ident = val.variant_ident; + let ty_ident = val.ty_ident; + + tokens.append_all(quote!( + #name_in_attr => ::darling::export::Ok(#ty_ident::#variant_ident), + )); + } else { + tokens.append_all(quote!( + #name_in_attr => ::darling::export::Err(::darling::Error::unsupported_format("literal")), + )); + } + } +} + +/// Code generator for an enum variant in a data-carrying match position. +/// This is placed in generated `from_list` calls for the parent enum. +/// Unit variants wrapped in this type will emit code to produce an "unsupported format" error. +pub struct DataMatchArm<'a>(&'a Variant<'a>); + +impl<'a> ToTokens for DataMatchArm<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let val: &Variant<'a> = self.0; + + if val.skip { + return; + } + + let name_in_attr = &val.name_in_attr; + let variant_ident = val.variant_ident; + let ty_ident = val.ty_ident; + + if val.data.is_unit() { + tokens.append_all(quote!( + #name_in_attr => ::darling::export::Err(::darling::Error::unsupported_format("list")), + )); + + return; + } + + let vdg = FieldsGen::new(&val.data, val.allow_unknown_fields); + + if val.data.is_struct() { + let declare_errors = ErrorDeclaration::default(); + let check_errors = ErrorCheck::with_location(name_in_attr); + let require_fields = vdg.require_fields(); + let decls = vdg.declarations(); + let core_loop = vdg.core_loop(); + let inits = vdg.initializers(); + + tokens.append_all(quote!( + #name_in_attr => { + if let ::syn::Meta::List(ref __data) = *__nested { + let __items = &__data.nested; + + #declare_errors + + #decls + + #core_loop + + #require_fields + + #check_errors + + ::darling::export::Ok(#ty_ident::#variant_ident { + #inits + }) + } else { + ::darling::export::Err(::darling::Error::unsupported_format("non-list")) + } + } + )); + } else if val.data.is_newtype() { + tokens.append_all(quote!( + #name_in_attr => { + ::darling::export::Ok( + #ty_ident::#variant_ident( + ::darling::FromMeta::from_meta(__nested) + .map_err(|e| e.at(#name_in_attr))?) + ) + } + )); + } else { + panic!("Match arms aren't supported for tuple variants yet"); + } + } +} diff --git a/third_party/rust/darling_core/src/codegen/variant_data.rs b/third_party/rust/darling_core/src/codegen/variant_data.rs new file mode 100644 index 0000000000..b1f445048a --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/variant_data.rs @@ -0,0 +1,98 @@ +use proc_macro2::TokenStream; + +use crate::ast::{Fields, Style}; +use crate::codegen::Field; + +pub struct FieldsGen<'a> { + fields: &'a Fields<Field<'a>>, + allow_unknown_fields: bool, +} + +impl<'a> FieldsGen<'a> { + pub fn new(fields: &'a Fields<Field<'a>>, allow_unknown_fields: bool) -> Self { + Self { + fields, + allow_unknown_fields, + } + } + + /// Create declarations for all the fields in the struct. + pub(in crate::codegen) fn declarations(&self) -> TokenStream { + match *self.fields { + Fields { + style: Style::Struct, + ref fields, + .. + } => { + let vdr = fields.iter().map(Field::as_declaration); + quote!(#(#vdr)*) + } + _ => panic!("FieldsGen doesn't support tuples yet"), + } + } + + /// Generate the loop which walks meta items looking for property matches. + pub(in crate::codegen) fn core_loop(&self) -> TokenStream { + let arms = self.fields.as_ref().map(Field::as_match); + + // If we're allowing unknown fields, then handling one is a no-op. + // Otherwise, we're going to push a new spanned error pointing at the field. + let handle_unknown = if self.allow_unknown_fields { + quote!() + } else { + // We can't call `unknown_field_with_alts` with an empty slice, or else it fails to + // infer the type of the slice item. + let err_fn = if arms.is_empty() { + quote!(unknown_field(__other)) + } else { + let names = self.fields.as_ref().map(Field::as_name); + let names = names.iter(); + quote!(unknown_field_with_alts(__other, &[#(#names),*])) + }; + + quote! { + __errors.push(::darling::Error::#err_fn.with_span(__inner)); + } + }; + let arms = arms.iter(); + + quote!( + for __item in __items { + match *__item { + ::syn::NestedMeta::Meta(ref __inner) => { + let __name = ::darling::util::path_to_string(__inner.path()); + match __name.as_str() { + #(#arms)* + __other => { #handle_unknown } + } + } + ::syn::NestedMeta::Lit(ref __inner) => { + __errors.push(::darling::Error::unsupported_format("literal") + .with_span(__inner)); + } + } + } + ) + } + + pub fn require_fields(&self) -> TokenStream { + match *self.fields { + Fields { + style: Style::Struct, + ref fields, + .. + } => { + let checks = fields.iter().map(Field::as_presence_check); + quote!(#(#checks)*) + } + _ => panic!("FieldsGen doesn't support tuples for requirement checks"), + } + } + + pub(in crate::codegen) fn initializers(&self) -> TokenStream { + let inits = self.fields.as_ref().map(Field::as_initializer); + let inits = inits.iter(); + + quote!(#(#inits),*) + } +} diff --git a/third_party/rust/darling_core/src/derive.rs b/third_party/rust/darling_core/src/derive.rs new file mode 100644 index 0000000000..43674aae6b --- /dev/null +++ b/third_party/rust/darling_core/src/derive.rs @@ -0,0 +1,61 @@ +//! Functions to derive `darling`'s traits from well-formed input, without directly depending +//! on `proc_macro`. + +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::DeriveInput; + +use crate::options; + +/// Run an expression which returns a `darling::Result`, then either return the tokenized +/// representation of the `Ok` value, or the tokens of the compiler errors in the `Err` case. +macro_rules! emit_impl_or_error { + ($e:expr) => { + match $e { + Ok(val) => val.into_token_stream(), + Err(err) => err.write_errors(), + } + }; +} + +/// Create tokens for a `darling::FromMeta` impl from a `DeriveInput`. If +/// the input cannot produce a valid impl, the returned tokens will contain +/// compile errors instead. +pub fn from_meta(input: &DeriveInput) -> TokenStream { + emit_impl_or_error!(options::FromMetaOptions::new(input)) +} + +/// Create tokens for a `darling::FromAttributes` impl from a `DeriveInput`. If +/// the input cannot produce a valid impl, the returned tokens will contain +/// compile errors instead. +pub fn from_attributes(input: &DeriveInput) -> TokenStream { + emit_impl_or_error!(options::FromAttributesOptions::new(input)) +} + +/// Create tokens for a `darling::FromDeriveInput` impl from a `DeriveInput`. If +/// the input cannot produce a valid impl, the returned tokens will contain +/// compile errors instead. +pub fn from_derive_input(input: &DeriveInput) -> TokenStream { + emit_impl_or_error!(options::FdiOptions::new(input)) +} + +/// Create tokens for a `darling::FromField` impl from a `DeriveInput`. If +/// the input cannot produce a valid impl, the returned tokens will contain +/// compile errors instead. +pub fn from_field(input: &DeriveInput) -> TokenStream { + emit_impl_or_error!(options::FromFieldOptions::new(input)) +} + +/// Create tokens for a `darling::FromTypeParam` impl from a `DeriveInput`. If +/// the input cannot produce a valid impl, the returned tokens will contain +/// compile errors instead. +pub fn from_type_param(input: &DeriveInput) -> TokenStream { + emit_impl_or_error!(options::FromTypeParamOptions::new(input)) +} + +/// Create tokens for a `darling::FromVariant` impl from a `DeriveInput`. If +/// the input cannot produce a valid impl, the returned tokens will contain +/// compile errors instead. +pub fn from_variant(input: &DeriveInput) -> TokenStream { + emit_impl_or_error!(options::FromVariantOptions::new(input)) +} diff --git a/third_party/rust/darling_core/src/error/kind.rs b/third_party/rust/darling_core/src/error/kind.rs new file mode 100644 index 0000000000..0030e0d6c7 --- /dev/null +++ b/third_party/rust/darling_core/src/error/kind.rs @@ -0,0 +1,198 @@ +use std::fmt; + +use crate::error::Error; + +type DeriveInputShape = String; +type FieldName = String; +type MetaFormat = String; + +#[derive(Debug, Clone)] +// Don't want to publicly commit to ErrorKind supporting equality yet, but +// not having it makes testing very difficult. +#[cfg_attr(test, derive(PartialEq, Eq))] +pub(in crate::error) enum ErrorKind { + /// An arbitrary error message. + Custom(String), + DuplicateField(FieldName), + MissingField(FieldName), + UnsupportedShape(DeriveInputShape), + UnknownField(ErrorUnknownField), + UnexpectedFormat(MetaFormat), + UnexpectedType(String), + UnknownValue(String), + TooFewItems(usize), + TooManyItems(usize), + /// A set of errors. + Multiple(Vec<Error>), + + // TODO make this variant take `!` so it can't exist + #[doc(hidden)] + __NonExhaustive, +} + +impl ErrorKind { + pub fn description(&self) -> &str { + use self::ErrorKind::*; + + match *self { + Custom(ref s) => s, + DuplicateField(_) => "Duplicate field", + MissingField(_) => "Missing field", + UnknownField(_) => "Unexpected field", + UnsupportedShape(_) => "Unsupported shape", + UnexpectedFormat(_) => "Unexpected meta-item format", + UnexpectedType(_) => "Unexpected literal type", + UnknownValue(_) => "Unknown literal value", + TooFewItems(_) => "Too few items", + TooManyItems(_) => "Too many items", + Multiple(_) => "Multiple errors", + __NonExhaustive => unreachable!(), + } + } + + /// Deeply counts the number of errors this item represents. + pub fn len(&self) -> usize { + if let ErrorKind::Multiple(ref items) = *self { + items.iter().map(Error::len).sum() + } else { + 1 + } + } +} + +impl fmt::Display for ErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::ErrorKind::*; + + match *self { + Custom(ref s) => s.fmt(f), + DuplicateField(ref field) => write!(f, "Duplicate field `{}`", field), + MissingField(ref field) => write!(f, "Missing field `{}`", field), + UnknownField(ref field) => field.fmt(f), + UnsupportedShape(ref shape) => write!(f, "Unsupported shape `{}`", shape), + UnexpectedFormat(ref format) => write!(f, "Unexpected meta-item format `{}`", format), + UnexpectedType(ref ty) => write!(f, "Unexpected literal type `{}`", ty), + UnknownValue(ref val) => write!(f, "Unknown literal value `{}`", val), + TooFewItems(ref min) => write!(f, "Too few items: Expected at least {}", min), + TooManyItems(ref max) => write!(f, "Too many items: Expected no more than {}", max), + Multiple(ref items) if items.len() == 1 => items[0].fmt(f), + Multiple(ref items) => { + write!(f, "Multiple errors: (")?; + let mut first = true; + for item in items { + if !first { + write!(f, ", ")?; + } else { + first = false; + } + + item.fmt(f)?; + } + + write!(f, ")") + } + __NonExhaustive => unreachable!(), + } + } +} + +impl From<ErrorUnknownField> for ErrorKind { + fn from(err: ErrorUnknownField) -> Self { + ErrorKind::UnknownField(err) + } +} + +/// An error for an unknown field, with a possible "did-you-mean" suggestion to get +/// the user back on the right track. +#[derive(Clone, Debug)] +// Don't want to publicly commit to ErrorKind supporting equality yet, but +// not having it makes testing very difficult. +#[cfg_attr(test, derive(PartialEq, Eq))] +pub(in crate::error) struct ErrorUnknownField { + name: String, + did_you_mean: Option<String>, +} + +impl ErrorUnknownField { + pub fn new<I: Into<String>>(name: I, did_you_mean: Option<String>) -> Self { + ErrorUnknownField { + name: name.into(), + did_you_mean, + } + } + + pub fn with_alts<'a, T, I>(field: &str, alternates: I) -> Self + where + T: AsRef<str> + 'a, + I: IntoIterator<Item = &'a T>, + { + ErrorUnknownField::new(field, did_you_mean(field, alternates)) + } + + #[cfg(feature = "diagnostics")] + pub fn into_diagnostic(self, span: Option<::proc_macro2::Span>) -> ::proc_macro::Diagnostic { + let base = span + .unwrap_or_else(::proc_macro2::Span::call_site) + .unwrap() + .error(self.top_line()); + match self.did_you_mean { + Some(alt_name) => base.help(format!("did you mean `{}`?", alt_name)), + None => base, + } + } + + #[cfg(feature = "diagnostics")] + fn top_line(&self) -> String { + format!("Unknown field: `{}`", self.name) + } +} + +impl From<String> for ErrorUnknownField { + fn from(name: String) -> Self { + ErrorUnknownField::new(name, None) + } +} + +impl<'a> From<&'a str> for ErrorUnknownField { + fn from(name: &'a str) -> Self { + ErrorUnknownField::new(name, None) + } +} + +impl fmt::Display for ErrorUnknownField { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Unknown field: `{}`", self.name)?; + + if let Some(ref did_you_mean) = self.did_you_mean { + write!(f, ". Did you mean `{}`?", did_you_mean)?; + } + + Ok(()) + } +} + +#[cfg(feature = "suggestions")] +fn did_you_mean<'a, T, I>(field: &str, alternates: I) -> Option<String> +where + T: AsRef<str> + 'a, + I: IntoIterator<Item = &'a T>, +{ + let mut candidate: Option<(f64, &str)> = None; + for pv in alternates { + let confidence = ::strsim::jaro_winkler(field, pv.as_ref()); + if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) + { + candidate = Some((confidence, pv.as_ref())); + } + } + candidate.map(|(_, candidate)| candidate.into()) +} + +#[cfg(not(feature = "suggestions"))] +fn did_you_mean<'a, T, I>(_field: &str, _alternates: I) -> Option<String> +where + T: AsRef<str> + 'a, + I: IntoIterator<Item = &'a T>, +{ + None +} diff --git a/third_party/rust/darling_core/src/error/mod.rs b/third_party/rust/darling_core/src/error/mod.rs new file mode 100644 index 0000000000..cc4b15bb5b --- /dev/null +++ b/third_party/rust/darling_core/src/error/mod.rs @@ -0,0 +1,821 @@ +//! The `darling::Error` type, the multiple error `Accumulator`, and their internals. +//! +//! Error handling is one of the core values of `darling`; creating great errors is hard and +//! never the reason that a proc-macro author started writing their crate. As a result, the +//! `Error` type in `darling` tries to make adding span information, suggestions, and other +//! help content easy when manually implementing `darling` traits, and automatic when deriving +//! them. + +use proc_macro2::{Span, TokenStream}; +use std::error::Error as StdError; +use std::fmt; +use std::iter::{self, Iterator}; +use std::string::ToString; +use std::vec; +use syn::spanned::Spanned; +use syn::{Lit, LitStr, Path}; + +mod kind; + +use crate::util::path_to_string; + +use self::kind::{ErrorKind, ErrorUnknownField}; + +/// An alias of `Result` specific to attribute parsing. +pub type Result<T> = ::std::result::Result<T, Error>; + +/// An error encountered during attribute parsing. +/// +/// Given that most errors darling encounters represent code bugs in dependent crates, +/// the internal structure of the error is deliberately opaque. +/// +/// # Usage +/// Proc-macro expansion happens very infrequently compared to runtime tasks such as +/// deserialization, and it happens in the context of an expensive compilation taks. +/// For that reason, darling prefers not to fail on the first error it encounters, instead +/// doing as much work as it can, accumulating errors into a single report. +/// +/// As a result, `darling::Error` is more of guaranteed-non-empty error collection +/// than a single problem. These errors also have some notion of hierarchy, stemming from +/// the hierarchical nature of darling's input. +/// +/// These characteristics make for great experiences when using darling-powered crates, +/// provided crates using darling adhere to some best practices: +/// +/// 1. Do not attempt to simplify a `darling::Error` into some other error type, such as +/// `syn::Error`. To surface compile errors, instead use `darling::Error::write_errors`. +/// This preserves all span information, suggestions, etc. Wrapping a `darling::Error` in +/// a custom error enum works as-expected and does not force any loss of fidelity. +/// 2. Do not use early return (e.g. the `?` operator) for custom validations. Instead, +/// create an [`error::Accumulator`](Accumulator) to collect errors as they are encountered. Then use +/// [`Accumulator::finish`] to return your validated result; it will give `Ok` if and only if +/// no errors were encountered. This can create very complex custom validation functions; +/// in those cases, split independent "validation chains" out into their own functions to +/// keep the main validator manageable. +/// 3. Use `darling::Error::custom` to create additional errors as-needed, then call `with_span` +/// to ensure those errors appear in the right place. Use `darling::util::SpannedValue` to keep +/// span information around on parsed fields so that custom diagnostics can point to the correct +/// parts of the input AST. +#[derive(Debug, Clone)] +pub struct Error { + kind: ErrorKind, + locations: Vec<String>, + /// The span to highlight in the emitted diagnostic. + span: Option<Span>, +} + +/// Error creation functions +impl Error { + pub(in crate::error) fn new(kind: ErrorKind) -> Self { + Error { + kind, + locations: Vec::new(), + span: None, + } + } + + /// Creates a new error with a custom message. + pub fn custom<T: fmt::Display>(msg: T) -> Self { + Error::new(ErrorKind::Custom(msg.to_string())) + } + + /// Creates a new error for a field that appears twice in the input. + pub fn duplicate_field(name: &str) -> Self { + Error::new(ErrorKind::DuplicateField(name.into())) + } + + /// Creates a new error for a field that appears twice in the input. Helper to avoid repeating + /// the syn::Path to String conversion. + pub fn duplicate_field_path(path: &Path) -> Self { + Error::duplicate_field(&path_to_string(path)) + } + + /// Creates a new error for a non-optional field that does not appear in the input. + pub fn missing_field(name: &str) -> Self { + Error::new(ErrorKind::MissingField(name.into())) + } + + /// Creates a new error for a field name that appears in the input but does not correspond + /// to a known field. + pub fn unknown_field(name: &str) -> Self { + Error::new(ErrorKind::UnknownField(name.into())) + } + + /// Creates a new error for a field name that appears in the input but does not correspond + /// to a known field. Helper to avoid repeating the syn::Path to String conversion. + pub fn unknown_field_path(path: &Path) -> Self { + Error::unknown_field(&path_to_string(path)) + } + + /// Creates a new error for a field name that appears in the input but does not correspond to + /// a known attribute. The second argument is the list of known attributes; if a similar name + /// is found that will be shown in the emitted error message. + pub fn unknown_field_with_alts<'a, T, I>(field: &str, alternates: I) -> Self + where + T: AsRef<str> + 'a, + I: IntoIterator<Item = &'a T>, + { + Error::new(ErrorUnknownField::with_alts(field, alternates).into()) + } + + /// Creates a new error for a struct or variant that does not adhere to the supported shape. + pub fn unsupported_shape(shape: &str) -> Self { + Error::new(ErrorKind::UnsupportedShape(shape.into())) + } + + pub fn unsupported_format(format: &str) -> Self { + Error::new(ErrorKind::UnexpectedFormat(format.into())) + } + + /// Creates a new error for a field which has an unexpected literal type. + pub fn unexpected_type(ty: &str) -> Self { + Error::new(ErrorKind::UnexpectedType(ty.into())) + } + + /// Creates a new error for a field which has an unexpected literal type. This will automatically + /// extract the literal type name from the passed-in `Lit` and set the span to encompass only the + /// literal value. + /// + /// # Usage + /// This is most frequently used in overrides of the `FromMeta::from_value` method. + /// + /// ```rust + /// # // pretend darling_core is darling so the doc example looks correct. + /// # extern crate darling_core as darling; + /// # extern crate syn; + /// + /// use darling::{FromMeta, Error, Result}; + /// use syn::{Lit, LitStr}; + /// + /// pub struct Foo(String); + /// + /// impl FromMeta for Foo { + /// fn from_value(value: &Lit) -> Result<Self> { + /// if let Lit::Str(ref lit_str) = *value { + /// Ok(Foo(lit_str.value())) + /// } else { + /// Err(Error::unexpected_lit_type(value)) + /// } + /// } + /// } + /// + /// # fn main() {} + /// ``` + pub fn unexpected_lit_type(lit: &Lit) -> Self { + Error::unexpected_type(match *lit { + Lit::Str(_) => "string", + Lit::ByteStr(_) => "byte string", + Lit::Byte(_) => "byte", + Lit::Char(_) => "char", + Lit::Int(_) => "int", + Lit::Float(_) => "float", + Lit::Bool(_) => "bool", + Lit::Verbatim(_) => "verbatim", + }) + .with_span(lit) + } + + /// Creates a new error for a value which doesn't match a set of expected literals. + pub fn unknown_value(value: &str) -> Self { + Error::new(ErrorKind::UnknownValue(value.into())) + } + + /// Creates a new error for a list which did not get enough items to proceed. + pub fn too_few_items(min: usize) -> Self { + Error::new(ErrorKind::TooFewItems(min)) + } + + /// Creates a new error when a list got more items than it supports. The `max` argument + /// is the largest number of items the receiver could accept. + pub fn too_many_items(max: usize) -> Self { + Error::new(ErrorKind::TooManyItems(max)) + } + + /// Bundle a set of multiple errors into a single `Error` instance. + /// + /// Usually it will be more convenient to use an [`error::Accumulator`](Accumulator). + /// + /// # Panics + /// This function will panic if `errors.is_empty() == true`. + pub fn multiple(mut errors: Vec<Error>) -> Self { + match errors.len() { + 1 => errors + .pop() + .expect("Error array of length 1 has a first item"), + 0 => panic!("Can't deal with 0 errors"), + _ => Error::new(ErrorKind::Multiple(errors)), + } + } + + /// Creates an error collector, for aggregating multiple errors + /// + /// See [`Accumulator`] for details. + pub fn accumulator() -> Accumulator { + Default::default() + } +} + +impl Error { + /// Create a new error about a literal string that doesn't match a set of known + /// or permissible values. This function can be made public if the API proves useful + /// beyond impls for `syn` types. + pub(crate) fn unknown_lit_str_value(value: &LitStr) -> Self { + Error::unknown_value(&value.value()).with_span(value) + } +} + +/// Error instance methods +#[allow(clippy::len_without_is_empty)] // Error can never be empty +impl Error { + /// Check if this error is associated with a span in the token stream. + pub fn has_span(&self) -> bool { + self.span.is_some() + } + + /// Tie a span to the error if none is already present. This is used in `darling::FromMeta` + /// and other traits to attach errors to the most specific possible location in the input + /// source code. + /// + /// All `darling`-built impls, either from the crate or from the proc macro, will call this + /// when appropriate during parsing, so it should not be necessary to call this unless you have + /// overridden: + /// + /// * `FromMeta::from_meta` + /// * `FromMeta::from_nested_meta` + /// * `FromMeta::from_value` + pub fn with_span<T: Spanned>(mut self, node: &T) -> Self { + if !self.has_span() { + self.span = Some(node.span()); + } + + self + } + + /// Get a span for the error. + /// + /// # Return Value + /// This function will return [`Span::call_site()`](proc_macro2::Span) if [`Self::has_span`] is `false`. + /// To get the span only if one has been explicitly set for `self`, instead use [`Error::explicit_span`]. + pub fn span(&self) -> Span { + self.span.unwrap_or_else(Span::call_site) + } + + /// Get the span for `self`, if one has been set. + pub fn explicit_span(&self) -> Option<Span> { + self.span + } + + /// Recursively converts a tree of errors to a flattened list. + pub fn flatten(self) -> Self { + Error::multiple(self.into_vec()) + } + + fn into_vec(self) -> Vec<Self> { + if let ErrorKind::Multiple(errors) = self.kind { + let mut flat = Vec::new(); + for error in errors { + flat.extend(error.prepend_at(self.locations.clone()).into_vec()); + } + + flat + } else { + vec![self] + } + } + + /// Adds a location to the error, such as a field or variant. + /// Locations must be added in reverse order of specificity. + pub fn at<T: fmt::Display>(mut self, location: T) -> Self { + self.locations.insert(0, location.to_string()); + self + } + + /// Adds a location to the error, such as a field or variant. + /// Locations must be added in reverse order of specificity. This is a helper function to avoid + /// repeating path to string logic. + pub fn at_path(self, path: &Path) -> Self { + self.at(path_to_string(path)) + } + + /// Gets the number of individual errors in this error. + /// + /// This function never returns `0`, as it's impossible to construct + /// a multi-error from an empty `Vec`. + pub fn len(&self) -> usize { + self.kind.len() + } + + /// Adds a location chain to the head of the error's existing locations. + fn prepend_at(mut self, mut locations: Vec<String>) -> Self { + if !locations.is_empty() { + locations.extend(self.locations); + self.locations = locations; + } + + self + } + + /// Gets the location slice. + #[cfg(test)] + pub(crate) fn location(&self) -> Vec<&str> { + self.locations.iter().map(|i| i.as_str()).collect() + } + + /// Write this error and any children as compile errors into a `TokenStream` to + /// be returned by the proc-macro. + /// + /// The behavior of this method will be slightly different if the `diagnostics` feature + /// is enabled: In that case, the diagnostics will be emitted immediately by this call, + /// and an empty `TokenStream` will be returned. + /// + /// Return these tokens unmodified to avoid disturbing the attached span information. + /// + /// # Usage + /// ```rust,ignore + /// // in your proc-macro function + /// let opts = match MyOptions::from_derive_input(&ast) { + /// Ok(val) => val, + /// Err(err) => { + /// return err.write_errors(); + /// } + /// } + /// ``` + pub fn write_errors(self) -> TokenStream { + #[cfg(feature = "diagnostics")] + { + self.emit(); + quote!() + } + + #[cfg(not(feature = "diagnostics"))] + { + syn::Error::from(self).into_compile_error() + } + } + + #[cfg(feature = "diagnostics")] + fn single_to_diagnostic(self) -> ::proc_macro::Diagnostic { + use proc_macro::{Diagnostic, Level}; + + // Delegate to dedicated error formatters when applicable. + // + // If span information is available, don't include the error property path + // since it's redundant and not consistent with native compiler diagnostics. + match self.kind { + ErrorKind::UnknownField(euf) => euf.into_diagnostic(self.span), + _ => match self.span { + Some(span) => span.unwrap().error(self.kind.to_string()), + None => Diagnostic::new(Level::Error, self.to_string()), + }, + } + } + + /// Transform this error and its children into a list of compiler diagnostics + /// and emit them. If the `Error` has associated span information, the diagnostics + /// will identify the correct location in source code automatically. + /// + /// # Stability + /// This is only available on `nightly` until the compiler `proc_macro_diagnostic` + /// feature stabilizes. Until then, it may break at any time. + #[cfg(feature = "diagnostics")] + pub fn emit(self) { + for error in self.flatten() { + error.single_to_diagnostic().emit() + } + } + + /// Transform the error into a compiler diagnostic and - if the diagnostic points to + /// a specific code location - add a spanned help child diagnostic that points to the + /// parent derived trait. + /// + /// This is experimental and therefore not exposed outside the crate. + #[cfg(feature = "diagnostics")] + #[allow(dead_code)] + fn emit_with_macro_help_span(self) { + use proc_macro::Diagnostic; + + for error in self.flatten() { + let needs_help = error.has_span(); + let diagnostic = error.single_to_diagnostic(); + Diagnostic::emit(if needs_help { + diagnostic.span_help( + Span::call_site().unwrap(), + "Encountered as part of this derive-mode-macro", + ) + } else { + diagnostic + }) + } + } +} + +impl StdError for Error { + fn description(&self) -> &str { + self.kind.description() + } + + fn cause(&self) -> Option<&dyn StdError> { + None + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.kind)?; + if !self.locations.is_empty() { + write!(f, " at {}", self.locations.join("/"))?; + } + + Ok(()) + } +} + +impl From<syn::Error> for Error { + fn from(e: syn::Error) -> Self { + // This impl assumes there is nothing but the message and span that needs to be preserved + // from the passed-in error. If this changes at some point, a new ErrorKind should be made + // to hold the syn::Error, and this impl should preserve it unmodified while setting its own + // span to be a copy of the passed-in error. + Self { + span: Some(e.span()), + ..Self::custom(e) + } + } +} + +impl From<Error> for syn::Error { + fn from(e: Error) -> Self { + if e.len() == 1 { + if let Some(span) = e.explicit_span() { + // Don't include the location path if the error has an explicit span, + // since it will be redundant and isn't consistent with how rustc + // exposes errors. + syn::Error::new(span, e.kind) + } else { + // If the error's span is going to be the macro call site, include + // the location information to try and help the user pinpoint the issue. + syn::Error::new(e.span(), e) + } + } else { + let mut syn_errors = e.flatten().into_iter().map(syn::Error::from); + let mut error = syn_errors + .next() + .expect("darling::Error can never be empty"); + + for next_error in syn_errors { + error.combine(next_error); + } + + error + } + } +} + +// Don't want to publicly commit to Error supporting equality yet, but +// not having it makes testing very difficult. Note that spans are not +// considered for equality since that would break testing in most cases. +#[cfg(test)] +impl PartialEq for Error { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind && self.locations == other.locations + } +} + +#[cfg(test)] +impl Eq for Error {} + +impl IntoIterator for Error { + type Item = Error; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + if let ErrorKind::Multiple(errors) = self.kind { + IntoIter { + inner: IntoIterEnum::Multiple(errors.into_iter()), + } + } else { + IntoIter { + inner: IntoIterEnum::Single(iter::once(self)), + } + } + } +} + +enum IntoIterEnum { + Single(iter::Once<Error>), + Multiple(vec::IntoIter<Error>), +} + +impl Iterator for IntoIterEnum { + type Item = Error; + + fn next(&mut self) -> Option<Self::Item> { + match *self { + IntoIterEnum::Single(ref mut content) => content.next(), + IntoIterEnum::Multiple(ref mut content) => content.next(), + } + } +} + +/// An iterator that moves out of an `Error`. +pub struct IntoIter { + inner: IntoIterEnum, +} + +impl Iterator for IntoIter { + type Item = Error; + + fn next(&mut self) -> Option<Error> { + self.inner.next() + } +} + +/// Accumulator for errors, for helping call [`Error::multiple`]. +/// +/// See the docs for [`darling::Error`](Error) for more discussion of error handling with darling. +/// +/// # Panics +/// +/// `Accumulator` panics on drop unless [`finish`](Self::finish), [`finish_with`](Self::finish_with), +/// or [`into_inner`](Self::into_inner) has been called, **even if it contains no errors**. +/// If you want to discard an `Accumulator` that you know to be empty, use `accumulator.finish().unwrap()`. +/// +/// # Example +/// +/// ``` +/// # extern crate darling_core as darling; +/// # struct Thing; +/// # struct Output; +/// # impl Thing { fn validate(self) -> darling::Result<Output> { Ok(Output) } } +/// fn validate_things(inputs: Vec<Thing>) -> darling::Result<Vec<Output>> { +/// let mut errors = darling::Error::accumulator(); +/// +/// let outputs = inputs +/// .into_iter() +/// .filter_map(|thing| errors.handle_in(|| thing.validate())) +/// .collect::<Vec<_>>(); +/// +/// errors.finish()?; +/// Ok(outputs) +/// } +/// ``` +#[derive(Debug)] +#[must_use = "Accumulator will panic on drop if not defused."] +pub struct Accumulator(Option<Vec<Error>>); + +impl Accumulator { + /// Runs a closure, returning the successful value as `Some`, or collecting the error + /// + /// The closure's return type is `darling::Result`, so inside it one can use `?`. + pub fn handle_in<T, F: FnOnce() -> Result<T>>(&mut self, f: F) -> Option<T> { + self.handle(f()) + } + + /// Handles a possible error. + /// + /// Returns a successful value as `Some`, or collects the error and returns `None`. + pub fn handle<T>(&mut self, result: Result<T>) -> Option<T> { + match result { + Ok(y) => Some(y), + Err(e) => { + self.push(e); + None + } + } + } + + /// Stop accumulating errors, producing `Ok` if there are no errors or producing + /// an error with all those encountered by the accumulator. + pub fn finish(self) -> Result<()> { + self.finish_with(()) + } + + /// Bundles the collected errors if there were any, or returns the success value + /// + /// Call this at the end of your input processing. + /// + /// If there were no errors recorded, returns `Ok(success)`. + /// Otherwise calls [`Error::multiple`] and returns the result as an `Err`. + pub fn finish_with<T>(self, success: T) -> Result<T> { + let errors = self.into_inner(); + if errors.is_empty() { + Ok(success) + } else { + Err(Error::multiple(errors)) + } + } + + fn errors(&mut self) -> &mut Vec<Error> { + match &mut self.0 { + Some(errors) => errors, + None => panic!("darling internal error: Accumulator accessed after defuse"), + } + } + + /// Returns the accumulated errors as a `Vec`. + /// + /// This function defuses the drop bomb. + #[must_use = "Accumulated errors should be handled or propagated to the caller"] + pub fn into_inner(mut self) -> Vec<Error> { + match std::mem::replace(&mut self.0, None) { + Some(errors) => errors, + None => panic!("darling internal error: Accumulator accessed after defuse"), + } + } + + /// Add one error to the collection. + pub fn push(&mut self, error: Error) { + self.errors().push(error) + } + + /// Finish the current accumulation, and if there are no errors create a new `Self` so processing may continue. + /// + /// This is shorthand for: + /// + /// ```rust,ignore + /// errors.finish()?; + /// errors = Error::accumulator(); + /// ``` + /// + /// # Drop Behavior + /// This function returns a new [`Accumulator`] in the success case. + /// This new accumulator is "armed" and will detonate if dropped without being finished. + /// + /// # Example + /// + /// ``` + /// # extern crate darling_core as darling; + /// # struct Thing; + /// # struct Output; + /// # impl Thing { fn validate(&self) -> darling::Result<Output> { Ok(Output) } } + /// fn validate(lorem_inputs: &[Thing], ipsum_inputs: &[Thing]) + /// -> darling::Result<(Vec<Output>, Vec<Output>)> { + /// let mut errors = darling::Error::accumulator(); + /// + /// let lorems = lorem_inputs.iter().filter_map(|l| { + /// errors.handle(l.validate()) + /// }).collect(); + /// + /// errors = errors.checkpoint()?; + /// + /// let ipsums = ipsum_inputs.iter().filter_map(|l| { + /// errors.handle(l.validate()) + /// }).collect(); + /// + /// errors.finish_with((lorems, ipsums)) + /// } + /// # validate(&[], &[]).unwrap(); + /// ``` + pub fn checkpoint(self) -> Result<Accumulator> { + // The doc comment says on success we "return the Accumulator for future use". + // Actually, we have consumed it by feeding it to finish so we make a fresh one. + // This is OK since by definition of the success path, it was empty on entry. + self.finish()?; + Ok(Self::default()) + } +} + +impl Default for Accumulator { + fn default() -> Self { + Accumulator(Some(vec![])) + } +} + +impl Extend<Error> for Accumulator { + fn extend<I>(&mut self, iter: I) + where + I: IntoIterator<Item = Error>, + { + self.errors().extend(iter) + } +} + +impl Drop for Accumulator { + fn drop(&mut self) { + // don't try to panic if we are currently unwinding a panic + // otherwise we end up with an unhelful "thread panicked while panicking. aborting." message + if !std::thread::panicking() { + if let Some(errors) = &mut self.0 { + match errors.len() { + 0 => panic!("darling::error::Accumulator dropped without being finished"), + error_count => panic!("darling::error::Accumulator dropped without being finished. {} errors were lost.", error_count) + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::Error; + + #[test] + fn flatten_noop() { + let err = Error::duplicate_field("hello").at("world"); + assert_eq!(err.clone().flatten(), err); + } + + #[test] + fn flatten_simple() { + let err = Error::multiple(vec![ + Error::unknown_field("hello").at("world"), + Error::missing_field("hell_no").at("world"), + ]) + .at("foo") + .flatten(); + + assert!(err.location().is_empty()); + + let mut err_iter = err.into_iter(); + + let first = err_iter.next(); + assert!(first.is_some()); + assert_eq!(first.unwrap().location(), vec!["foo", "world"]); + + let second = err_iter.next(); + assert!(second.is_some()); + + assert_eq!(second.unwrap().location(), vec!["foo", "world"]); + + assert!(err_iter.next().is_none()); + } + + #[test] + fn len_single() { + let err = Error::duplicate_field("hello"); + assert_eq!(1, err.len()); + } + + #[test] + fn len_multiple() { + let err = Error::multiple(vec![ + Error::duplicate_field("hello"), + Error::missing_field("hell_no"), + ]); + assert_eq!(2, err.len()); + } + + #[test] + fn len_nested() { + let err = Error::multiple(vec![ + Error::duplicate_field("hello"), + Error::multiple(vec![ + Error::duplicate_field("hi"), + Error::missing_field("bye"), + Error::multiple(vec![Error::duplicate_field("whatsup")]), + ]), + ]); + + assert_eq!(4, err.len()); + } + + #[test] + fn accum_ok() { + let errs = Error::accumulator(); + assert_eq!("test", errs.finish_with("test").unwrap()); + } + + #[test] + fn accum_errr() { + let mut errs = Error::accumulator(); + errs.push(Error::custom("foo!")); + errs.finish().unwrap_err(); + } + + #[test] + fn accum_into_inner() { + let mut errs = Error::accumulator(); + errs.push(Error::custom("foo!")); + let errs: Vec<_> = errs.into_inner(); + assert_eq!(errs.len(), 1); + } + + #[test] + #[should_panic(expected = "Accumulator dropped")] + fn accum_drop_panic() { + let _errs = Error::accumulator(); + } + + #[test] + #[should_panic(expected = "2 errors")] + fn accum_drop_panic_with_error_count() { + let mut errors = Error::accumulator(); + errors.push(Error::custom("first")); + errors.push(Error::custom("second")); + } + + #[test] + fn accum_checkpoint_error() { + let mut errs = Error::accumulator(); + errs.push(Error::custom("foo!")); + errs.checkpoint().unwrap_err(); + } + + #[test] + #[should_panic(expected = "Accumulator dropped")] + fn accum_checkpoint_drop_panic() { + let mut errs = Error::accumulator(); + errs = errs.checkpoint().unwrap(); + let _ = errs; + } +} diff --git a/third_party/rust/darling_core/src/from_attributes.rs b/third_party/rust/darling_core/src/from_attributes.rs new file mode 100644 index 0000000000..c73f0f2cf4 --- /dev/null +++ b/third_party/rust/darling_core/src/from_attributes.rs @@ -0,0 +1,27 @@ +use syn::Attribute; + +use crate::Result; + +/// Create an instance by parsing a list of attributes. +/// +/// This trait is useful when dealing with items such as traits on traits and impl blocks, +/// for which `darling` does not provide dedicated traits. +pub trait FromAttributes: Sized { + /// Create an instance by parsing a list of attributes. + /// + /// By convention, `FromAttributes` implementations should merge item + /// declarations across attributes, so that the following forms are + /// equivalent: + /// + /// ```rust,ignore + /// #[derive(Serialize)] + /// #[serde(rename_all = "camel_case")] + /// #[serde(borrow)] + /// pub struct SplitExample {} + /// + /// #[derive(Serialize)] + /// #[serde(borrow, rename_all = "camel_case")] + /// pub struct JoinedExample {} + /// ``` + fn from_attributes(attrs: &[Attribute]) -> Result<Self>; +} diff --git a/third_party/rust/darling_core/src/from_derive_input.rs b/third_party/rust/darling_core/src/from_derive_input.rs new file mode 100644 index 0000000000..b5bb86f37e --- /dev/null +++ b/third_party/rust/darling_core/src/from_derive_input.rs @@ -0,0 +1,26 @@ +use syn::DeriveInput; + +use crate::Result; + +/// Creates an instance by parsing an entire proc-macro `derive` input, +/// including the, identity, generics, and visibility of the type. +/// +/// This trait should either be derived or manually implemented by a type +/// in the proc macro crate which is directly using `darling`. It is unlikely +/// that these implementations will be reusable across crates. +pub trait FromDeriveInput: Sized { + /// Create an instance from `syn::DeriveInput`, or return an error. + fn from_derive_input(input: &DeriveInput) -> Result<Self>; +} + +impl FromDeriveInput for () { + fn from_derive_input(_: &DeriveInput) -> Result<Self> { + Ok(()) + } +} + +impl FromDeriveInput for DeriveInput { + fn from_derive_input(input: &DeriveInput) -> Result<Self> { + Ok(input.clone()) + } +} diff --git a/third_party/rust/darling_core/src/from_field.rs b/third_party/rust/darling_core/src/from_field.rs new file mode 100644 index 0000000000..7ce4e55ca2 --- /dev/null +++ b/third_party/rust/darling_core/src/from_field.rs @@ -0,0 +1,38 @@ +use syn::Field; + +use crate::Result; + +/// Creates an instance by parsing an individual field and its attributes. +pub trait FromField: Sized { + fn from_field(field: &Field) -> Result<Self>; +} + +impl FromField for () { + fn from_field(_: &Field) -> Result<Self> { + Ok(()) + } +} + +impl FromField for Field { + fn from_field(field: &Field) -> Result<Self> { + Ok(field.clone()) + } +} + +impl FromField for syn::Type { + fn from_field(field: &Field) -> Result<Self> { + Ok(field.ty.clone()) + } +} + +impl FromField for syn::Visibility { + fn from_field(field: &Field) -> Result<Self> { + Ok(field.vis.clone()) + } +} + +impl FromField for Vec<syn::Attribute> { + fn from_field(field: &Field) -> Result<Self> { + Ok(field.attrs.clone()) + } +} diff --git a/third_party/rust/darling_core/src/from_generic_param.rs b/third_party/rust/darling_core/src/from_generic_param.rs new file mode 100644 index 0000000000..757ad768a8 --- /dev/null +++ b/third_party/rust/darling_core/src/from_generic_param.rs @@ -0,0 +1,19 @@ +use crate::Result; + +/// Creates an instance by parsing a specific `syn::GenericParam`. +/// This can be a type param, a lifetime, or a const param. +pub trait FromGenericParam: Sized { + fn from_generic_param(param: &syn::GenericParam) -> Result<Self>; +} + +impl FromGenericParam for () { + fn from_generic_param(_param: &syn::GenericParam) -> Result<Self> { + Ok(()) + } +} + +impl FromGenericParam for syn::GenericParam { + fn from_generic_param(param: &syn::GenericParam) -> Result<Self> { + Ok(param.clone()) + } +} diff --git a/third_party/rust/darling_core/src/from_generics.rs b/third_party/rust/darling_core/src/from_generics.rs new file mode 100644 index 0000000000..8f687106bb --- /dev/null +++ b/third_party/rust/darling_core/src/from_generics.rs @@ -0,0 +1,27 @@ +use syn::Generics; + +use crate::Result; + +/// Creates an instance by parsing an entire generics declaration, including the +/// `where` clause. +pub trait FromGenerics: Sized { + fn from_generics(generics: &Generics) -> Result<Self>; +} + +impl FromGenerics for () { + fn from_generics(_generics: &Generics) -> Result<Self> { + Ok(()) + } +} + +impl FromGenerics for Generics { + fn from_generics(generics: &Generics) -> Result<Self> { + Ok(generics.clone()) + } +} + +impl<T: FromGenerics> FromGenerics for Result<T> { + fn from_generics(generics: &Generics) -> Result<Self> { + Ok(FromGenerics::from_generics(generics)) + } +} diff --git a/third_party/rust/darling_core/src/from_meta.rs b/third_party/rust/darling_core/src/from_meta.rs new file mode 100644 index 0000000000..3c39af5599 --- /dev/null +++ b/third_party/rust/darling_core/src/from_meta.rs @@ -0,0 +1,851 @@ +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::hash_map::HashMap; +use std::collections::HashSet; +use std::hash::BuildHasher; +use std::rc::Rc; +use std::sync::atomic::AtomicBool; +use std::sync::Arc; + +use syn::{Expr, Lit, Meta, NestedMeta}; + +use crate::{util::path_to_string, Error, Result}; + +/// Create an instance from an item in an attribute declaration. +/// +/// # Implementing `FromMeta` +/// * Do not take a dependency on the `ident` of the passed-in meta item. The ident will be set by the field name of the containing struct. +/// * Implement only the `from_*` methods that you intend to support. The default implementations will return useful errors. +/// +/// # Provided Implementations +/// ## bool +/// +/// * Word with no value specified - becomes `true`. +/// * As a boolean literal, e.g. `foo = true`. +/// * As a string literal, e.g. `foo = "true"`. +/// +/// ## char +/// * As a char literal, e.g. `foo = '#'`. +/// * As a string literal consisting of a single character, e.g. `foo = "#"`. +/// +/// ## String +/// * As a string literal, e.g. `foo = "hello"`. +/// * As a raw string literal, e.g. `foo = r#"hello "world""#`. +/// +/// ## Number +/// * As a string literal, e.g. `foo = "-25"`. +/// * As an unquoted positive value, e.g. `foo = 404`. Negative numbers must be in quotation marks. +/// +/// ## () +/// * Word with no value specified, e.g. `foo`. This is best used with `Option`. +/// See `darling::util::Flag` for a more strongly-typed alternative. +/// +/// ## Option +/// * Any format produces `Some`. +/// +/// ## `Result<T, darling::Error>` +/// * Allows for fallible parsing; will populate the target field with the result of the +/// parse attempt. +pub trait FromMeta: Sized { + fn from_nested_meta(item: &NestedMeta) -> Result<Self> { + (match *item { + NestedMeta::Lit(ref lit) => Self::from_value(lit), + NestedMeta::Meta(ref mi) => Self::from_meta(mi), + }) + .map_err(|e| e.with_span(item)) + } + + /// Create an instance from a `syn::Meta` by dispatching to the format-appropriate + /// trait function. This generally should not be overridden by implementers. + /// + /// # Error Spans + /// If this method is overridden and can introduce errors that weren't passed up from + /// other `from_meta` calls, the override must call `with_span` on the error using the + /// `item` to make sure that the emitted diagnostic points to the correct location in + /// source code. + fn from_meta(item: &Meta) -> Result<Self> { + (match *item { + Meta::Path(_) => Self::from_word(), + Meta::List(ref value) => Self::from_list( + &value + .nested + .iter() + .cloned() + .collect::<Vec<syn::NestedMeta>>()[..], + ), + Meta::NameValue(ref value) => Self::from_value(&value.lit), + }) + .map_err(|e| e.with_span(item)) + } + + /// When a field is omitted from a parent meta-item, `from_none` is used to attempt + /// recovery before a missing field error is generated. + /// + /// **Most types should not override this method.** `darling` already allows field-level + /// missing-field recovery using `#[darling(default)]` and `#[darling(default = "...")]`, + /// and users who add a `String` field to their `FromMeta`-deriving struct would be surprised + /// if they get back `""` instead of a missing field error when that field is omitted. + /// + /// The primary use-case for this is `Option<T>` fields gracefully handlling absence without + /// needing `#[darling(default)]`. + fn from_none() -> Option<Self> { + None + } + + /// Create an instance from the presence of the word in the attribute with no + /// additional options specified. + fn from_word() -> Result<Self> { + Err(Error::unsupported_format("word")) + } + + /// Create an instance from a list of nested meta items. + #[allow(unused_variables)] + fn from_list(items: &[NestedMeta]) -> Result<Self> { + Err(Error::unsupported_format("list")) + } + + /// Create an instance from a literal value of either `foo = "bar"` or `foo("bar")`. + /// This dispatches to the appropriate method based on the type of literal encountered, + /// and generally should not be overridden by implementers. + /// + /// # Error Spans + /// If this method is overridden, the override must make sure to add `value`'s span + /// information to the returned error by calling `with_span(value)` on the `Error` instance. + fn from_value(value: &Lit) -> Result<Self> { + (match *value { + Lit::Bool(ref b) => Self::from_bool(b.value), + Lit::Str(ref s) => Self::from_string(&s.value()), + Lit::Char(ref ch) => Self::from_char(ch.value()), + _ => Err(Error::unexpected_lit_type(value)), + }) + .map_err(|e| e.with_span(value)) + } + + /// Create an instance from a char literal in a value position. + #[allow(unused_variables)] + fn from_char(value: char) -> Result<Self> { + Err(Error::unexpected_type("char")) + } + + /// Create an instance from a string literal in a value position. + #[allow(unused_variables)] + fn from_string(value: &str) -> Result<Self> { + Err(Error::unexpected_type("string")) + } + + /// Create an instance from a bool literal in a value position. + #[allow(unused_variables)] + fn from_bool(value: bool) -> Result<Self> { + Err(Error::unexpected_type("bool")) + } +} + +// FromMeta impls for std and syn types. + +impl FromMeta for () { + fn from_word() -> Result<Self> { + Ok(()) + } +} + +impl FromMeta for bool { + fn from_word() -> Result<Self> { + Ok(true) + } + + #[allow(clippy::wrong_self_convention)] // false positive + fn from_bool(value: bool) -> Result<Self> { + Ok(value) + } + + fn from_string(value: &str) -> Result<Self> { + value.parse().map_err(|_| Error::unknown_value(value)) + } +} + +impl FromMeta for AtomicBool { + fn from_meta(mi: &Meta) -> Result<Self> { + FromMeta::from_meta(mi) + .map(AtomicBool::new) + .map_err(|e| e.with_span(mi)) + } +} + +impl FromMeta for char { + #[allow(clippy::wrong_self_convention)] // false positive + fn from_char(value: char) -> Result<Self> { + Ok(value) + } + + fn from_string(s: &str) -> Result<Self> { + let mut chars = s.chars(); + let char1 = chars.next(); + let char2 = chars.next(); + + if let (Some(char), None) = (char1, char2) { + Ok(char) + } else { + Err(Error::unexpected_type("string")) + } + } +} + +impl FromMeta for String { + fn from_string(s: &str) -> Result<Self> { + Ok(s.to_string()) + } +} + +/// Generate an impl of `FromMeta` that will accept strings which parse to numbers or +/// integer literals. +macro_rules! from_meta_num { + ($ty:ident) => { + impl FromMeta for $ty { + fn from_string(s: &str) -> Result<Self> { + s.parse().map_err(|_| Error::unknown_value(s)) + } + + fn from_value(value: &Lit) -> Result<Self> { + (match *value { + Lit::Str(ref s) => Self::from_string(&s.value()), + Lit::Int(ref s) => Ok(s.base10_parse::<$ty>().unwrap()), + _ => Err(Error::unexpected_lit_type(value)), + }) + .map_err(|e| e.with_span(value)) + } + } + }; +} + +from_meta_num!(u8); +from_meta_num!(u16); +from_meta_num!(u32); +from_meta_num!(u64); +from_meta_num!(usize); +from_meta_num!(i8); +from_meta_num!(i16); +from_meta_num!(i32); +from_meta_num!(i64); +from_meta_num!(isize); + +/// Generate an impl of `FromMeta` that will accept strings which parse to floats or +/// float literals. +macro_rules! from_meta_float { + ($ty:ident) => { + impl FromMeta for $ty { + fn from_string(s: &str) -> Result<Self> { + s.parse().map_err(|_| Error::unknown_value(s)) + } + + fn from_value(value: &Lit) -> Result<Self> { + (match *value { + Lit::Str(ref s) => Self::from_string(&s.value()), + Lit::Float(ref s) => Ok(s.base10_parse::<$ty>().unwrap()), + _ => Err(Error::unexpected_lit_type(value)), + }) + .map_err(|e| e.with_span(value)) + } + } + }; +} + +from_meta_float!(f32); +from_meta_float!(f64); + +/// Parsing support for punctuated. This attempts to preserve span information +/// when available, but also supports parsing strings with the call site as the +/// emitted span. +impl<T: syn::parse::Parse, P: syn::parse::Parse> FromMeta for syn::punctuated::Punctuated<T, P> { + fn from_value(value: &Lit) -> Result<Self> { + if let Lit::Str(ref ident) = *value { + ident + .parse_with(syn::punctuated::Punctuated::parse_terminated) + .map_err(|_| Error::unknown_lit_str_value(ident)) + } else { + Err(Error::unexpected_lit_type(value)) + } + } +} + +/// Adapter from `syn::parse::Parse` to `FromMeta`. +/// +/// This cannot be a blanket impl, due to the `syn::Lit` family's need to handle non-string values. +/// Therefore, we use a macro and a lot of impls. +macro_rules! from_syn_parse { + ($ty:path) => { + impl FromMeta for $ty { + fn from_string(value: &str) -> Result<Self> { + syn::parse_str(value).map_err(|_| Error::unknown_value(value)) + } + + fn from_value(value: &::syn::Lit) -> Result<Self> { + if let ::syn::Lit::Str(ref v) = *value { + v.parse::<$ty>() + .map_err(|_| Error::unknown_lit_str_value(v)) + } else { + Err(Error::unexpected_lit_type(value)) + } + } + } + }; +} + +from_syn_parse!(syn::Ident); +from_syn_parse!(syn::Expr); +from_syn_parse!(syn::ExprArray); +from_syn_parse!(syn::ExprPath); +from_syn_parse!(syn::Path); +from_syn_parse!(syn::Type); +from_syn_parse!(syn::TypeArray); +from_syn_parse!(syn::TypeBareFn); +from_syn_parse!(syn::TypeGroup); +from_syn_parse!(syn::TypeImplTrait); +from_syn_parse!(syn::TypeInfer); +from_syn_parse!(syn::TypeMacro); +from_syn_parse!(syn::TypeNever); +from_syn_parse!(syn::TypeParam); +from_syn_parse!(syn::TypeParen); +from_syn_parse!(syn::TypePath); +from_syn_parse!(syn::TypePtr); +from_syn_parse!(syn::TypeReference); +from_syn_parse!(syn::TypeSlice); +from_syn_parse!(syn::TypeTraitObject); +from_syn_parse!(syn::TypeTuple); +from_syn_parse!(syn::Visibility); +from_syn_parse!(syn::WhereClause); + +macro_rules! from_numeric_array { + ($ty:ident) => { + /// Parsing an unsigned integer array, i.e. `example = "[1, 2, 3, 4]"`. + impl FromMeta for Vec<$ty> { + fn from_value(value: &Lit) -> Result<Self> { + let expr_array = syn::ExprArray::from_value(value)?; + // To meet rust <1.36 borrow checker rules on expr_array.elems + let v = + expr_array + .elems + .iter() + .map(|expr| match expr { + Expr::Lit(lit) => $ty::from_value(&lit.lit), + _ => Err(Error::custom("Expected array of unsigned integers") + .with_span(expr)), + }) + .collect::<Result<Vec<$ty>>>(); + v + } + } + }; +} + +from_numeric_array!(u8); +from_numeric_array!(u16); +from_numeric_array!(u32); +from_numeric_array!(u64); +from_numeric_array!(usize); + +impl FromMeta for syn::Lit { + fn from_value(value: &Lit) -> Result<Self> { + Ok(value.clone()) + } +} + +macro_rules! from_meta_lit { + ($impl_ty:path, $lit_variant:path) => { + impl FromMeta for $impl_ty { + fn from_value(value: &Lit) -> Result<Self> { + if let $lit_variant(ref value) = *value { + Ok(value.clone()) + } else { + Err(Error::unexpected_lit_type(value)) + } + } + } + }; +} + +from_meta_lit!(syn::LitInt, Lit::Int); +from_meta_lit!(syn::LitFloat, Lit::Float); +from_meta_lit!(syn::LitStr, Lit::Str); +from_meta_lit!(syn::LitByte, Lit::Byte); +from_meta_lit!(syn::LitByteStr, Lit::ByteStr); +from_meta_lit!(syn::LitChar, Lit::Char); +from_meta_lit!(syn::LitBool, Lit::Bool); +from_meta_lit!(proc_macro2::Literal, Lit::Verbatim); + +impl FromMeta for syn::Meta { + fn from_meta(value: &syn::Meta) -> Result<Self> { + Ok(value.clone()) + } +} + +impl FromMeta for Vec<syn::WherePredicate> { + fn from_string(value: &str) -> Result<Self> { + syn::WhereClause::from_string(&format!("where {}", value)) + .map(|c| c.predicates.into_iter().collect()) + } + + fn from_value(value: &Lit) -> Result<Self> { + if let syn::Lit::Str(s) = value { + syn::WhereClause::from_value(&syn::Lit::Str(syn::LitStr::new( + &format!("where {}", s.value()), + value.span(), + ))) + .map(|c| c.predicates.into_iter().collect()) + } else { + Err(Error::unexpected_lit_type(value)) + } + } +} + +impl FromMeta for ident_case::RenameRule { + fn from_string(value: &str) -> Result<Self> { + value.parse().map_err(|_| Error::unknown_value(value)) + } +} + +impl<T: FromMeta> FromMeta for Option<T> { + fn from_none() -> Option<Self> { + Some(None) + } + + fn from_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(Some) + } +} + +impl<T: FromMeta> FromMeta for Box<T> { + fn from_none() -> Option<Self> { + T::from_none().map(Box::new) + } + + fn from_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(Box::new) + } +} + +impl<T: FromMeta> FromMeta for Result<T> { + fn from_none() -> Option<Self> { + T::from_none().map(Ok) + } + + fn from_meta(item: &Meta) -> Result<Self> { + Ok(FromMeta::from_meta(item)) + } +} + +/// Parses the meta-item, and in case of error preserves a copy of the input for +/// later analysis. +impl<T: FromMeta> FromMeta for ::std::result::Result<T, Meta> { + fn from_meta(item: &Meta) -> Result<Self> { + T::from_meta(item) + .map(Ok) + .or_else(|_| Ok(Err(item.clone()))) + } +} + +impl<T: FromMeta> FromMeta for Rc<T> { + fn from_none() -> Option<Self> { + T::from_none().map(Rc::new) + } + + fn from_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(Rc::new) + } +} + +impl<T: FromMeta> FromMeta for Arc<T> { + fn from_none() -> Option<Self> { + T::from_none().map(Arc::new) + } + + fn from_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(Arc::new) + } +} + +impl<T: FromMeta> FromMeta for RefCell<T> { + fn from_none() -> Option<Self> { + T::from_none().map(RefCell::new) + } + + fn from_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(RefCell::new) + } +} + +/// Trait to convert from a path into an owned key for a map. +trait KeyFromPath: Sized { + fn from_path(path: &syn::Path) -> Result<Self>; + fn to_display(&self) -> Cow<'_, str>; +} + +impl KeyFromPath for String { + fn from_path(path: &syn::Path) -> Result<Self> { + Ok(path_to_string(path)) + } + + fn to_display(&self) -> Cow<'_, str> { + Cow::Borrowed(self) + } +} + +impl KeyFromPath for syn::Path { + fn from_path(path: &syn::Path) -> Result<Self> { + Ok(path.clone()) + } + + fn to_display(&self) -> Cow<'_, str> { + Cow::Owned(path_to_string(self)) + } +} + +impl KeyFromPath for syn::Ident { + fn from_path(path: &syn::Path) -> Result<Self> { + if path.segments.len() == 1 + && path.leading_colon.is_none() + && path.segments[0].arguments.is_empty() + { + Ok(path.segments[0].ident.clone()) + } else { + Err(Error::custom("Key must be an identifier").with_span(path)) + } + } + + fn to_display(&self) -> Cow<'_, str> { + Cow::Owned(self.to_string()) + } +} + +macro_rules! hash_map { + ($key:ty) => { + impl<V: FromMeta, S: BuildHasher + Default> FromMeta for HashMap<$key, V, S> { + fn from_list(nested: &[syn::NestedMeta]) -> Result<Self> { + // Convert the nested meta items into a sequence of (path, value result) result tuples. + // An outer Err means no (key, value) structured could be found, while an Err in the + // second position of the tuple means that value was rejected by FromMeta. + // + // We defer key conversion into $key so that we don't lose span information in the case + // of String keys; we'll need it for good duplicate key errors later. + let pairs = nested + .iter() + .map(|item| -> Result<(&syn::Path, Result<V>)> { + match *item { + syn::NestedMeta::Meta(ref inner) => { + let path = inner.path(); + Ok(( + path, + FromMeta::from_meta(inner).map_err(|e| e.at_path(&path)), + )) + } + syn::NestedMeta::Lit(_) => Err(Error::unsupported_format("literal")), + } + }); + + let mut errors = Error::accumulator(); + // We need to track seen keys separately from the final map, since a seen key with an + // Err value won't go into the final map but should trigger a duplicate field error. + // + // This is a set of $key rather than Path to avoid the possibility that a key type + // parses two paths of different values to the same key value. + let mut seen_keys = HashSet::with_capacity(nested.len()); + + // The map to return in the Ok case. Its size will always be exactly nested.len(), + // since otherwise ≥1 field had a problem and the entire map is dropped immediately + // when the function returns `Err`. + let mut map = HashMap::with_capacity_and_hasher(nested.len(), Default::default()); + + for item in pairs { + if let Some((path, value)) = errors.handle(item) { + let key: $key = match KeyFromPath::from_path(path) { + Ok(k) => k, + Err(e) => { + errors.push(e); + + // Surface value errors even under invalid keys + errors.handle(value); + + continue; + } + }; + + let already_seen = seen_keys.contains(&key); + + if already_seen { + errors.push(Error::duplicate_field(&key.to_display()).with_span(path)); + } + + match value { + Ok(_) if already_seen => {} + Ok(val) => { + map.insert(key.clone(), val); + } + Err(e) => { + errors.push(e); + } + } + + seen_keys.insert(key); + } + } + + errors.finish_with(map) + } + } + }; +} + +// This is done as a macro rather than a blanket impl to avoid breaking backwards compatibility +// with 0.12.x, while still sharing the same impl. +hash_map!(String); +hash_map!(syn::Ident); +hash_map!(syn::Path); + +/// Tests for `FromMeta` implementations. Wherever the word `ignore` appears in test input, +/// it should not be considered by the parsing. +#[cfg(test)] +mod tests { + use proc_macro2::TokenStream; + + use crate::{Error, FromMeta, Result}; + + /// parse a string as a syn::Meta instance. + fn pm(tokens: TokenStream) -> ::std::result::Result<syn::Meta, String> { + let attribute: syn::Attribute = parse_quote!(#[#tokens]); + attribute.parse_meta().map_err(|_| "Unable to parse".into()) + } + + fn fm<T: FromMeta>(tokens: TokenStream) -> T { + FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input")) + .expect("Tests should pass valid input") + } + + #[test] + fn unit_succeeds() { + fm::<()>(quote!(ignore)); + } + + #[test] + #[allow(clippy::bool_assert_comparison)] + fn bool_succeeds() { + // word format + assert_eq!(fm::<bool>(quote!(ignore)), true); + + // bool literal + assert_eq!(fm::<bool>(quote!(ignore = true)), true); + assert_eq!(fm::<bool>(quote!(ignore = false)), false); + + // string literals + assert_eq!(fm::<bool>(quote!(ignore = "true")), true); + assert_eq!(fm::<bool>(quote!(ignore = "false")), false); + } + + #[test] + fn char_succeeds() { + // char literal + assert_eq!(fm::<char>(quote!(ignore = '😬')), '😬'); + + // string literal + assert_eq!(fm::<char>(quote!(ignore = "😬")), '😬'); + } + + #[test] + fn string_succeeds() { + // cooked form + assert_eq!(&fm::<String>(quote!(ignore = "world")), "world"); + + // raw form + assert_eq!(&fm::<String>(quote!(ignore = r#"world"#)), "world"); + } + + #[test] + #[allow(clippy::float_cmp)] // we want exact equality + fn number_succeeds() { + assert_eq!(fm::<u8>(quote!(ignore = "2")), 2u8); + assert_eq!(fm::<i16>(quote!(ignore = "-25")), -25i16); + assert_eq!(fm::<f64>(quote!(ignore = "1.4e10")), 1.4e10); + } + + #[test] + fn int_without_quotes() { + assert_eq!(fm::<u8>(quote!(ignore = 2)), 2u8); + assert_eq!(fm::<u16>(quote!(ignore = 255)), 255u16); + assert_eq!(fm::<u32>(quote!(ignore = 5000)), 5000u32); + + // Check that we aren't tripped up by incorrect suffixes + assert_eq!(fm::<u32>(quote!(ignore = 5000i32)), 5000u32); + } + + #[test] + #[allow(clippy::float_cmp)] // we want exact equality + fn float_without_quotes() { + assert_eq!(fm::<f32>(quote!(ignore = 2.)), 2.0f32); + assert_eq!(fm::<f32>(quote!(ignore = 2.0)), 2.0f32); + assert_eq!(fm::<f64>(quote!(ignore = 1.4e10)), 1.4e10f64); + } + + #[test] + fn meta_succeeds() { + use syn::Meta; + + assert_eq!( + fm::<Meta>(quote!(hello(world, today))), + pm(quote!(hello(world, today))).unwrap() + ); + } + + #[test] + fn hash_map_succeeds() { + use std::collections::HashMap; + + let comparison = { + let mut c = HashMap::new(); + c.insert("hello".to_string(), true); + c.insert("world".to_string(), false); + c.insert("there".to_string(), true); + c + }; + + assert_eq!( + fm::<HashMap<String, bool>>(quote!(ignore(hello, world = false, there = "true"))), + comparison + ); + } + + /// Check that a `HashMap` cannot have duplicate keys, and that the generated error + /// is assigned a span to correctly target the diagnostic message. + #[test] + fn hash_map_duplicate() { + use std::collections::HashMap; + + let err: Result<HashMap<String, bool>> = + FromMeta::from_meta(&pm(quote!(ignore(hello, hello = false))).unwrap()); + + let err = err.expect_err("Duplicate keys in HashMap should error"); + + assert!(err.has_span()); + assert_eq!(err.to_string(), Error::duplicate_field("hello").to_string()); + } + + #[test] + fn hash_map_multiple_errors() { + use std::collections::HashMap; + + let err = HashMap::<String, bool>::from_meta( + &pm(quote!(ignore(hello, hello = 3, hello = false))).unwrap(), + ) + .expect_err("Duplicates and bad values should error"); + + assert_eq!(err.len(), 3); + let errors = err.into_iter().collect::<Vec<_>>(); + assert!(errors[0].has_span()); + assert!(errors[1].has_span()); + assert!(errors[2].has_span()); + } + + #[test] + fn hash_map_ident_succeeds() { + use std::collections::HashMap; + use syn::parse_quote; + + let comparison = { + let mut c = HashMap::<syn::Ident, bool>::new(); + c.insert(parse_quote!(first), true); + c.insert(parse_quote!(second), false); + c + }; + + assert_eq!( + fm::<HashMap<syn::Ident, bool>>(quote!(ignore(first, second = false))), + comparison + ); + } + + #[test] + fn hash_map_ident_rejects_non_idents() { + use std::collections::HashMap; + + let err: Result<HashMap<syn::Ident, bool>> = + FromMeta::from_meta(&pm(quote!(ignore(first, the::second))).unwrap()); + + err.unwrap_err(); + } + + #[test] + fn hash_map_path_succeeds() { + use std::collections::HashMap; + use syn::parse_quote; + + let comparison = { + let mut c = HashMap::<syn::Path, bool>::new(); + c.insert(parse_quote!(first), true); + c.insert(parse_quote!(the::second), false); + c + }; + + assert_eq!( + fm::<HashMap<syn::Path, bool>>(quote!(ignore(first, the::second = false))), + comparison + ); + } + + /// Tests that fallible parsing will always produce an outer `Ok` (from `fm`), + /// and will accurately preserve the inner contents. + #[test] + fn darling_result_succeeds() { + fm::<Result<()>>(quote!(ignore)).unwrap(); + fm::<Result<()>>(quote!(ignore(world))).unwrap_err(); + } + + /// Test punctuated + #[test] + fn test_punctuated() { + fm::<syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>>(quote!( + ignore = "a: u8, b: Type" + )); + fm::<syn::punctuated::Punctuated<syn::Expr, syn::token::Comma>>(quote!(ignore = "a, b, c")); + } + + #[test] + fn test_expr_array() { + fm::<syn::ExprArray>(quote!(ignore = "[0x1, 0x2]")); + fm::<syn::ExprArray>(quote!(ignore = "[\"Hello World\", \"Test Array\"]")); + } + + #[test] + fn test_expr() { + fm::<syn::Expr>(quote!(ignore = "x + y")); + fm::<syn::Expr>(quote!(ignore = "an_object.method_call()")); + fm::<syn::Expr>(quote!(ignore = "{ a_statement(); in_a_block }")); + } + + #[test] + fn test_expr_path() { + fm::<syn::ExprPath>(quote!(ignore = "std::mem::replace")); + fm::<syn::ExprPath>(quote!(ignore = "x")); + fm::<syn::ExprPath>(quote!(ignore = "example::<Test>")); + } + + #[test] + fn test_number_array() { + assert_eq!( + fm::<Vec<u8>>(quote!(ignore = "[16, 0xff]")), + vec![0x10, 0xff] + ); + assert_eq!( + fm::<Vec<u16>>(quote!(ignore = "[32, 0xffff]")), + vec![0x20, 0xffff] + ); + assert_eq!( + fm::<Vec<u32>>(quote!(ignore = "[48, 0xffffffff]")), + vec![0x30, 0xffffffff] + ); + assert_eq!( + fm::<Vec<u64>>(quote!(ignore = "[64, 0xffffffffffffffff]")), + vec![0x40, 0xffffffffffffffff] + ); + assert_eq!( + fm::<Vec<usize>>(quote!(ignore = "[80, 0xffffffff]")), + vec![0x50, 0xffffffff] + ); + } +} diff --git a/third_party/rust/darling_core/src/from_type_param.rs b/third_party/rust/darling_core/src/from_type_param.rs new file mode 100644 index 0000000000..bea9796c26 --- /dev/null +++ b/third_party/rust/darling_core/src/from_type_param.rs @@ -0,0 +1,32 @@ +use syn::TypeParam; + +use crate::Result; + +/// Creates an instance by parsing an individual type_param and its attributes. +pub trait FromTypeParam: Sized { + fn from_type_param(type_param: &TypeParam) -> Result<Self>; +} + +impl FromTypeParam for () { + fn from_type_param(_: &TypeParam) -> Result<Self> { + Ok(()) + } +} + +impl FromTypeParam for TypeParam { + fn from_type_param(type_param: &TypeParam) -> Result<Self> { + Ok(type_param.clone()) + } +} + +impl FromTypeParam for Vec<syn::Attribute> { + fn from_type_param(type_param: &TypeParam) -> Result<Self> { + Ok(type_param.attrs.clone()) + } +} + +impl FromTypeParam for syn::Ident { + fn from_type_param(type_param: &TypeParam) -> Result<Self> { + Ok(type_param.ident.clone()) + } +} diff --git a/third_party/rust/darling_core/src/from_variant.rs b/third_party/rust/darling_core/src/from_variant.rs new file mode 100644 index 0000000000..50bf6359b6 --- /dev/null +++ b/third_party/rust/darling_core/src/from_variant.rs @@ -0,0 +1,33 @@ +use syn::Variant; + +use crate::Result; + +/// Creates an instance from a specified `syn::Variant`. +pub trait FromVariant: Sized { + /// Create an instance from `syn::Variant`, or return an error. + fn from_variant(variant: &Variant) -> Result<Self>; +} + +impl FromVariant for () { + fn from_variant(_: &Variant) -> Result<Self> { + Ok(()) + } +} + +impl FromVariant for Variant { + fn from_variant(variant: &Variant) -> Result<Self> { + Ok(variant.clone()) + } +} + +impl FromVariant for syn::Ident { + fn from_variant(variant: &Variant) -> Result<Self> { + Ok(variant.ident.clone()) + } +} + +impl FromVariant for Vec<syn::Attribute> { + fn from_variant(variant: &Variant) -> Result<Self> { + Ok(variant.attrs.clone()) + } +} diff --git a/third_party/rust/darling_core/src/lib.rs b/third_party/rust/darling_core/src/lib.rs new file mode 100644 index 0000000000..1656176bea --- /dev/null +++ b/third_party/rust/darling_core/src/lib.rs @@ -0,0 +1,49 @@ +#![recursion_limit = "256"] +#![cfg_attr(feature = "diagnostics", feature(proc_macro_diagnostic))] + +#[macro_use] +extern crate quote; +#[macro_use] +extern crate syn; +extern crate fnv; +extern crate ident_case; +#[cfg(feature = "diagnostics")] +extern crate proc_macro; +extern crate proc_macro2; +#[cfg(feature = "suggestions")] +extern crate strsim; + +#[macro_use] +mod macros_private; +#[macro_use] +mod macros_public; + +pub mod ast; +pub(crate) mod codegen; +pub mod derive; +pub mod error; +mod from_attributes; +mod from_derive_input; +mod from_field; +mod from_generic_param; +mod from_generics; +mod from_meta; +mod from_type_param; +mod from_variant; +pub(crate) mod options; +pub mod usage; +pub mod util; + +pub use self::error::{Error, Result}; +pub use self::from_attributes::FromAttributes; +pub use self::from_derive_input::FromDeriveInput; +pub use self::from_field::FromField; +pub use self::from_generic_param::FromGenericParam; +pub use self::from_generics::FromGenerics; +pub use self::from_meta::FromMeta; +pub use self::from_type_param::FromTypeParam; +pub use self::from_variant::FromVariant; + +// Re-export tokenizer +#[doc(hidden)] +pub use quote::ToTokens; diff --git a/third_party/rust/darling_core/src/macros_private.rs b/third_party/rust/darling_core/src/macros_private.rs new file mode 100644 index 0000000000..65a3cd5750 --- /dev/null +++ b/third_party/rust/darling_core/src/macros_private.rs @@ -0,0 +1,12 @@ +macro_rules! quote { + ($($tt:tt)*) => { + quote_spanned!(::proc_macro2::Span::call_site() => $($tt)*) + }; +} + +macro_rules! path { + ($($path:tt)+) => { + parse_quote!($($path)+) + //stringify!($($path)+).parse().unwrap() + }; +} diff --git a/third_party/rust/darling_core/src/macros_public.rs b/third_party/rust/darling_core/src/macros_public.rs new file mode 100644 index 0000000000..c264fcc2a8 --- /dev/null +++ b/third_party/rust/darling_core/src/macros_public.rs @@ -0,0 +1,96 @@ +//! Macros that should be exported from both `darling_core` and `darling`. +//! Note that these are **sym-linked** into the main code, and so cannot declare on items that are exported differently +//! in `darling_core` vs. `darling`. + +/// Generator for `UsesTypeParam` impls that unions the used type parameters of the selected fields. +/// +/// # Usage +/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of +/// fields for the rest of its arguments. +/// +/// The type of each passed-in field must implement `UsesTypeParams`, or the resulting code won't compile. +/// +/// ```rust +/// # extern crate syn; +/// # use darling_core::uses_type_params; +/// # +/// struct MyField { +/// ty: syn::Type, +/// } +/// +/// uses_type_params!(MyField, ty); +/// +/// fn main() { +/// // no test run +/// } +/// ``` +/// +/// `darling` cannot derive this trait automatically, as it doesn't know which information extracted from +/// proc-macro input is meant to constitute "using" the type parameter, but crate consumers should +/// implement it by hand or using the macro. +#[macro_export] +macro_rules! uses_type_params { + ($impl_type:ty, $accessor:ident) => { + impl $crate::usage::UsesTypeParams for $impl_type { + fn uses_type_params<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::IdentSet + ) -> $crate::usage::IdentRefSet<'gen> { + self.$accessor.uses_type_params(options, type_set) + } + } + }; + ($impl_type:ty, $first:ident, $($field:ident),+) => { + impl $crate::usage::UsesTypeParams for $impl_type { + fn uses_type_params<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::IdentSet + ) -> $crate::usage::IdentRefSet<'gen> { + let mut hits = self.$first.uses_type_params(options, type_set); + $( + hits.extend(self.$field.uses_type_params(options, type_set)); + )* + hits + } + } + }; +} + +/// Generator for `UsesLifetimes` impls that unions the used lifetimes of the selected fields. +/// +/// # Usage +/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of +/// fields for the rest of its arguments. +/// +/// The type of each passed-in field must implement `UsesLifetimes`, or the resulting code won't compile. +#[macro_export] +macro_rules! uses_lifetimes { + ($impl_type:ty, $accessor:ident) => { + impl $crate::usage::UsesLifetimes for $impl_type { + fn uses_lifetimes<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::LifetimeSet + ) -> $crate::usage::LifetimeRefSet<'gen> { + self.$accessor.uses_lifetimes(options, type_set) + } + } + }; + ($impl_type:ty, $first:ident, $($field:ident),+) => { + impl $crate::usage::UsesLifetimes for $impl_type { + fn uses_lifetimes<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::LifetimeSet + ) -> $crate::usage::LifetimeRefSet<'gen> { + let mut hits = self.$first.uses_lifetimes(options, type_set); + $( + hits.extend(self.$field.uses_lifetimes(options, type_set)); + )* + hits + } + } + }; +} diff --git a/third_party/rust/darling_core/src/options/core.rs b/third_party/rust/darling_core/src/options/core.rs new file mode 100644 index 0000000000..e70c198a17 --- /dev/null +++ b/third_party/rust/darling_core/src/options/core.rs @@ -0,0 +1,169 @@ +use ident_case::RenameRule; + +use crate::ast::{Data, Fields, Style}; +use crate::codegen; +use crate::codegen::PostfixTransform; +use crate::options::{DefaultExpression, InputField, InputVariant, ParseAttribute, ParseData}; +use crate::{Error, FromMeta, Result}; + +/// A struct or enum which should have `FromMeta` or `FromDeriveInput` implementations +/// generated. +#[derive(Debug, Clone)] +pub struct Core { + /// The type identifier. + pub ident: syn::Ident, + + /// The type's generics. If the type does not use any generics, this will + /// be an empty instance. + pub generics: syn::Generics, + + /// Controls whether missing properties should cause errors or should be filled by + /// the result of a function call. This can be overridden at the field level. + pub default: Option<DefaultExpression>, + + /// The rule that should be used to rename all fields/variants in the container. + pub rename_rule: RenameRule, + + /// A transform which will be called on `darling::Result<Self>`. It must either be + /// an `FnOnce(T) -> T` when `map` is used, or `FnOnce(T) -> darling::Result<T>` when + /// `and_then` is used. + /// + /// `map` and `and_then` are mutually-exclusive to avoid confusion about the order in + /// which the two are applied. + pub post_transform: Option<codegen::PostfixTransform>, + + /// The body of the _deriving_ type. + pub data: Data<InputVariant, InputField>, + + /// The custom bound to apply to the generated impl + pub bound: Option<Vec<syn::WherePredicate>>, + + /// Whether or not unknown fields should produce an error at compilation time. + pub allow_unknown_fields: Option<bool>, +} + +impl Core { + /// Partially initializes `Core` by reading the identity, generics, and body shape. + pub fn start(di: &syn::DeriveInput) -> Result<Self> { + Ok(Core { + ident: di.ident.clone(), + generics: di.generics.clone(), + data: Data::try_empty_from(&di.data)?, + default: Default::default(), + // See https://github.com/TedDriggs/darling/issues/10: We default to snake_case + // for enums to help authors produce more idiomatic APIs. + rename_rule: if let syn::Data::Enum(_) = di.data { + RenameRule::SnakeCase + } else { + Default::default() + }, + post_transform: Default::default(), + bound: Default::default(), + allow_unknown_fields: Default::default(), + }) + } + + fn as_codegen_default(&self) -> Option<codegen::DefaultExpression<'_>> { + self.default.as_ref().map(|expr| match *expr { + DefaultExpression::Explicit(ref path) => codegen::DefaultExpression::Explicit(path), + DefaultExpression::Inherit | DefaultExpression::Trait => { + codegen::DefaultExpression::Trait + } + }) + } +} + +impl ParseAttribute for Core { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + let path = mi.path(); + + if path.is_ident("default") { + if self.default.is_some() { + return Err(Error::duplicate_field("default").with_span(mi)); + } + + self.default = FromMeta::from_meta(mi)?; + } else if path.is_ident("rename_all") { + // WARNING: This may have been set based on body shape previously, + // so an overwrite may be permissible. + self.rename_rule = FromMeta::from_meta(mi)?; + } else if path.is_ident("map") || path.is_ident("and_then") { + // This unwrap is safe because we just called is_ident above + let transformer = path.get_ident().unwrap().clone(); + + if let Some(post_transform) = &self.post_transform { + if transformer == post_transform.transformer { + return Err(Error::duplicate_field(&transformer.to_string()).with_span(mi)); + } else { + return Err(Error::custom(format!( + "Options `{}` and `{}` are mutually exclusive", + transformer, post_transform.transformer + )) + .with_span(mi)); + } + } + + self.post_transform = + Some(PostfixTransform::new(transformer, FromMeta::from_meta(mi)?)); + } else if path.is_ident("bound") { + self.bound = FromMeta::from_meta(mi)?; + } else if path.is_ident("allow_unknown_fields") { + if self.allow_unknown_fields.is_some() { + return Err(Error::duplicate_field("allow_unknown_fields").with_span(mi)); + } + + self.allow_unknown_fields = FromMeta::from_meta(mi)?; + } else { + return Err(Error::unknown_field_path(path).with_span(mi)); + } + + Ok(()) + } +} + +impl ParseData for Core { + fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> { + let v = InputVariant::from_variant(variant, Some(self))?; + + match self.data { + Data::Enum(ref mut variants) => { + variants.push(v); + Ok(()) + } + Data::Struct(_) => panic!("Core::parse_variant should never be called for a struct"), + } + } + + fn parse_field(&mut self, field: &syn::Field) -> Result<()> { + let f = InputField::from_field(field, Some(self))?; + + match self.data { + Data::Struct(Fields { + style: Style::Unit, .. + }) => panic!("Core::parse_field should not be called on unit"), + Data::Struct(Fields { ref mut fields, .. }) => { + fields.push(f); + Ok(()) + } + Data::Enum(_) => panic!("Core::parse_field should never be called for an enum"), + } + } +} + +impl<'a> From<&'a Core> for codegen::TraitImpl<'a> { + fn from(v: &'a Core) -> Self { + codegen::TraitImpl { + ident: &v.ident, + generics: &v.generics, + data: v + .data + .as_ref() + .map_struct_fields(InputField::as_codegen_field) + .map_enum_variants(|variant| variant.as_codegen_variant(&v.ident)), + default: v.as_codegen_default(), + post_transform: v.post_transform.as_ref(), + bound: v.bound.as_ref().map(|i| i.as_slice()), + allow_unknown_fields: v.allow_unknown_fields.unwrap_or_default(), + } + } +} diff --git a/third_party/rust/darling_core/src/options/forward_attrs.rs b/third_party/rust/darling_core/src/options/forward_attrs.rs new file mode 100644 index 0000000000..c72d009d59 --- /dev/null +++ b/third_party/rust/darling_core/src/options/forward_attrs.rs @@ -0,0 +1,31 @@ +use syn::NestedMeta; + +use crate::util::PathList; +use crate::{FromMeta, Result}; + +/// A rule about which attributes to forward to the generated struct. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ForwardAttrs { + All, + Only(PathList), +} + +impl ForwardAttrs { + /// Returns `true` if this will not forward any attributes. + pub fn is_empty(&self) -> bool { + match *self { + ForwardAttrs::All => false, + ForwardAttrs::Only(ref list) => list.is_empty(), + } + } +} + +impl FromMeta for ForwardAttrs { + fn from_word() -> Result<Self> { + Ok(ForwardAttrs::All) + } + + fn from_list(nested: &[NestedMeta]) -> Result<Self> { + Ok(ForwardAttrs::Only(PathList::from_list(nested)?)) + } +} diff --git a/third_party/rust/darling_core/src/options/from_attributes.rs b/third_party/rust/darling_core/src/options/from_attributes.rs new file mode 100644 index 0000000000..0a133d1b24 --- /dev/null +++ b/third_party/rust/darling_core/src/options/from_attributes.rs @@ -0,0 +1,69 @@ +use quote::ToTokens; + +use crate::{ast::Data, codegen::FromAttributesImpl, Error, Result}; + +use super::{OuterFrom, ParseAttribute, ParseData}; + +/// Receiver for derived `FromAttributes` impls. +pub struct FromAttributesOptions { + // Note: FromAttributes has no behaviors beyond those common + // to all the `OuterFrom` traits. + pub base: OuterFrom, +} + +impl FromAttributesOptions { + pub fn new(di: &syn::DeriveInput) -> Result<Self> { + let opts = (Self { + base: OuterFrom::start(di)?, + }) + .parse_attributes(&di.attrs)? + .parse_body(&di.data)?; + + if !opts.is_newtype() && opts.base.attr_names.is_empty() { + Err(Error::custom( + "FromAttributes without attributes collects nothing", + )) + } else { + Ok(opts) + } + } + + fn is_newtype(&self) -> bool { + if let Data::Struct(ref data) = self.base.container.data { + data.is_newtype() + } else { + false + } + } +} + +impl ParseAttribute for FromAttributesOptions { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + self.base.parse_nested(mi) + } +} + +impl ParseData for FromAttributesOptions { + fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> { + self.base.parse_variant(variant) + } + + fn parse_field(&mut self, field: &syn::Field) -> Result<()> { + self.base.parse_field(field) + } +} + +impl<'a> From<&'a FromAttributesOptions> for FromAttributesImpl<'a> { + fn from(v: &'a FromAttributesOptions) -> Self { + FromAttributesImpl { + base: (&v.base.container).into(), + attr_names: &v.base.attr_names, + } + } +} + +impl ToTokens for FromAttributesOptions { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + FromAttributesImpl::from(self).to_tokens(tokens) + } +} diff --git a/third_party/rust/darling_core/src/options/from_derive.rs b/third_party/rust/darling_core/src/options/from_derive.rs new file mode 100644 index 0000000000..5507451de8 --- /dev/null +++ b/third_party/rust/darling_core/src/options/from_derive.rs @@ -0,0 +1,100 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; + +use crate::codegen::FromDeriveInputImpl; +use crate::options::{OuterFrom, ParseAttribute, ParseData, Shape}; +use crate::{FromMeta, Result}; + +#[derive(Debug)] +pub struct FdiOptions { + pub base: OuterFrom, + + /// The field on the target struct which should receive the type visibility, if any. + pub vis: Option<Ident>, + + /// The field on the target struct which should receive the type generics, if any. + pub generics: Option<Ident>, + + pub data: Option<Ident>, + + pub supports: Option<Shape>, +} + +impl FdiOptions { + pub fn new(di: &syn::DeriveInput) -> Result<Self> { + (FdiOptions { + base: OuterFrom::start(di)?, + vis: Default::default(), + generics: Default::default(), + data: Default::default(), + supports: Default::default(), + }) + .parse_attributes(&di.attrs)? + .parse_body(&di.data) + } +} + +impl ParseAttribute for FdiOptions { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + if mi.path().is_ident("supports") { + self.supports = FromMeta::from_meta(mi)?; + Ok(()) + } else { + self.base.parse_nested(mi) + } + } +} + +impl ParseData for FdiOptions { + fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> { + self.base.parse_variant(variant) + } + + fn parse_field(&mut self, field: &syn::Field) -> Result<()> { + match field + .ident + .as_ref() + .map(|v| v.to_string()) + .as_ref() + .map(|v| v.as_str()) + { + Some("vis") => { + self.vis = field.ident.clone(); + Ok(()) + } + Some("data") => { + self.data = field.ident.clone(); + Ok(()) + } + Some("generics") => { + self.generics = field.ident.clone(); + Ok(()) + } + _ => self.base.parse_field(field), + } + } +} + +impl<'a> From<&'a FdiOptions> for FromDeriveInputImpl<'a> { + fn from(v: &'a FdiOptions) -> Self { + FromDeriveInputImpl { + base: (&v.base.container).into(), + attr_names: &v.base.attr_names, + from_ident: v.base.from_ident, + ident: v.base.ident.as_ref(), + vis: v.vis.as_ref(), + data: v.data.as_ref(), + generics: v.generics.as_ref(), + attrs: v.base.attrs.as_ref(), + forward_attrs: v.base.forward_attrs.as_ref(), + supports: v.supports.as_ref(), + } + } +} + +impl ToTokens for FdiOptions { + fn to_tokens(&self, tokens: &mut TokenStream) { + FromDeriveInputImpl::from(self).to_tokens(tokens) + } +} diff --git a/third_party/rust/darling_core/src/options/from_field.rs b/third_party/rust/darling_core/src/options/from_field.rs new file mode 100644 index 0000000000..fcfab75592 --- /dev/null +++ b/third_party/rust/darling_core/src/options/from_field.rs @@ -0,0 +1,79 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; + +use crate::codegen::FromFieldImpl; +use crate::options::{OuterFrom, ParseAttribute, ParseData}; +use crate::Result; + +#[derive(Debug)] +pub struct FromFieldOptions { + pub base: OuterFrom, + pub vis: Option<Ident>, + pub ty: Option<Ident>, +} + +impl FromFieldOptions { + pub fn new(di: &syn::DeriveInput) -> Result<Self> { + (FromFieldOptions { + base: OuterFrom::start(di)?, + vis: Default::default(), + ty: Default::default(), + }) + .parse_attributes(&di.attrs)? + .parse_body(&di.data) + } +} + +impl ParseAttribute for FromFieldOptions { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + self.base.parse_nested(mi) + } +} + +impl ParseData for FromFieldOptions { + fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> { + self.base.parse_variant(variant) + } + + fn parse_field(&mut self, field: &syn::Field) -> Result<()> { + match field + .ident + .as_ref() + .map(|v| v.to_string()) + .as_ref() + .map(|v| v.as_str()) + { + Some("vis") => { + self.vis = field.ident.clone(); + Ok(()) + } + Some("ty") => { + self.ty = field.ident.clone(); + Ok(()) + } + _ => self.base.parse_field(field), + } + } +} + +impl<'a> From<&'a FromFieldOptions> for FromFieldImpl<'a> { + fn from(v: &'a FromFieldOptions) -> Self { + FromFieldImpl { + ident: v.base.ident.as_ref(), + vis: v.vis.as_ref(), + ty: v.ty.as_ref(), + attrs: v.base.attrs.as_ref(), + base: (&v.base.container).into(), + attr_names: &v.base.attr_names, + forward_attrs: v.base.forward_attrs.as_ref(), + from_ident: v.base.from_ident, + } + } +} + +impl ToTokens for FromFieldOptions { + fn to_tokens(&self, tokens: &mut TokenStream) { + FromFieldImpl::from(self).to_tokens(tokens) + } +} diff --git a/third_party/rust/darling_core/src/options/from_meta.rs b/third_party/rust/darling_core/src/options/from_meta.rs new file mode 100644 index 0000000000..18c2bfa676 --- /dev/null +++ b/third_party/rust/darling_core/src/options/from_meta.rs @@ -0,0 +1,50 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; + +use crate::codegen::FromMetaImpl; +use crate::options::{Core, ParseAttribute, ParseData}; +use crate::Result; + +pub struct FromMetaOptions { + base: Core, +} + +impl FromMetaOptions { + pub fn new(di: &syn::DeriveInput) -> Result<Self> { + (FromMetaOptions { + base: Core::start(di)?, + }) + .parse_attributes(&di.attrs)? + .parse_body(&di.data) + } +} + +impl ParseAttribute for FromMetaOptions { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + self.base.parse_nested(mi) + } +} + +impl ParseData for FromMetaOptions { + fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> { + self.base.parse_variant(variant) + } + + fn parse_field(&mut self, field: &syn::Field) -> Result<()> { + self.base.parse_field(field) + } +} + +impl<'a> From<&'a FromMetaOptions> for FromMetaImpl<'a> { + fn from(v: &'a FromMetaOptions) -> Self { + FromMetaImpl { + base: (&v.base).into(), + } + } +} + +impl ToTokens for FromMetaOptions { + fn to_tokens(&self, tokens: &mut TokenStream) { + FromMetaImpl::from(self).to_tokens(tokens) + } +} diff --git a/third_party/rust/darling_core/src/options/from_type_param.rs b/third_party/rust/darling_core/src/options/from_type_param.rs new file mode 100644 index 0000000000..5ab3241e25 --- /dev/null +++ b/third_party/rust/darling_core/src/options/from_type_param.rs @@ -0,0 +1,79 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::Ident; + +use crate::codegen::FromTypeParamImpl; +use crate::options::{OuterFrom, ParseAttribute, ParseData}; +use crate::Result; + +#[derive(Debug)] +pub struct FromTypeParamOptions { + pub base: OuterFrom, + pub bounds: Option<Ident>, + pub default: Option<Ident>, +} + +impl FromTypeParamOptions { + pub fn new(di: &syn::DeriveInput) -> Result<Self> { + (FromTypeParamOptions { + base: OuterFrom::start(di)?, + bounds: None, + default: None, + }) + .parse_attributes(&di.attrs)? + .parse_body(&di.data) + } +} + +impl ParseAttribute for FromTypeParamOptions { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + self.base.parse_nested(mi) + } +} + +impl ParseData for FromTypeParamOptions { + fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> { + self.base.parse_variant(variant) + } + + fn parse_field(&mut self, field: &syn::Field) -> Result<()> { + match field + .ident + .as_ref() + .map(|v| v.to_string()) + .as_ref() + .map(|v| v.as_str()) + { + Some("bounds") => { + self.bounds = field.ident.clone(); + Ok(()) + } + Some("default") => { + self.default = field.ident.clone(); + Ok(()) + } + _ => self.base.parse_field(field), + } + } +} + +impl<'a> From<&'a FromTypeParamOptions> for FromTypeParamImpl<'a> { + fn from(v: &'a FromTypeParamOptions) -> Self { + FromTypeParamImpl { + base: (&v.base.container).into(), + ident: v.base.ident.as_ref(), + attrs: v.base.attrs.as_ref(), + bounds: v.bounds.as_ref(), + default: v.default.as_ref(), + attr_names: &v.base.attr_names, + forward_attrs: v.base.forward_attrs.as_ref(), + from_ident: v.base.from_ident, + } + } +} + +impl ToTokens for FromTypeParamOptions { + fn to_tokens(&self, tokens: &mut TokenStream) { + FromTypeParamImpl::from(self).to_tokens(tokens) + } +} diff --git a/third_party/rust/darling_core/src/options/from_variant.rs b/third_party/rust/darling_core/src/options/from_variant.rs new file mode 100644 index 0000000000..fabdae17f7 --- /dev/null +++ b/third_party/rust/darling_core/src/options/from_variant.rs @@ -0,0 +1,85 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{DeriveInput, Field, Ident, Meta}; + +use crate::codegen::FromVariantImpl; +use crate::options::{DataShape, OuterFrom, ParseAttribute, ParseData}; +use crate::{FromMeta, Result}; + +#[derive(Debug, Clone)] +pub struct FromVariantOptions { + pub base: OuterFrom, + /// The field on the deriving struct into which the discriminant expression + /// should be placed by the derived `FromVariant` impl. + pub discriminant: Option<Ident>, + pub fields: Option<Ident>, + pub supports: Option<DataShape>, +} + +impl FromVariantOptions { + pub fn new(di: &DeriveInput) -> Result<Self> { + (FromVariantOptions { + base: OuterFrom::start(di)?, + discriminant: Default::default(), + fields: Default::default(), + supports: Default::default(), + }) + .parse_attributes(&di.attrs)? + .parse_body(&di.data) + } +} + +impl<'a> From<&'a FromVariantOptions> for FromVariantImpl<'a> { + fn from(v: &'a FromVariantOptions) -> Self { + FromVariantImpl { + base: (&v.base.container).into(), + ident: v.base.ident.as_ref(), + discriminant: v.discriminant.as_ref(), + fields: v.fields.as_ref(), + attrs: v.base.attrs.as_ref(), + attr_names: &v.base.attr_names, + forward_attrs: v.base.forward_attrs.as_ref(), + from_ident: v.base.from_ident, + supports: v.supports.as_ref(), + } + } +} + +impl ParseAttribute for FromVariantOptions { + fn parse_nested(&mut self, mi: &Meta) -> Result<()> { + if mi.path().is_ident("supports") { + self.supports = FromMeta::from_meta(mi)?; + Ok(()) + } else { + self.base.parse_nested(mi) + } + } +} + +impl ParseData for FromVariantOptions { + fn parse_field(&mut self, field: &Field) -> Result<()> { + match field + .ident + .as_ref() + .map(|v| v.to_string()) + .as_ref() + .map(|v| v.as_str()) + { + Some("discriminant") => { + self.discriminant = field.ident.clone(); + Ok(()) + } + Some("fields") => { + self.fields = field.ident.clone(); + Ok(()) + } + _ => self.base.parse_field(field), + } + } +} + +impl ToTokens for FromVariantOptions { + fn to_tokens(&self, tokens: &mut TokenStream) { + FromVariantImpl::from(self).to_tokens(tokens) + } +} diff --git a/third_party/rust/darling_core/src/options/input_field.rs b/third_party/rust/darling_core/src/options/input_field.rs new file mode 100644 index 0000000000..b9e828c591 --- /dev/null +++ b/third_party/rust/darling_core/src/options/input_field.rs @@ -0,0 +1,175 @@ +use std::borrow::Cow; + +use crate::codegen; +use crate::options::{Core, DefaultExpression, ParseAttribute}; +use crate::{Error, FromMeta, Result}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InputField { + pub ident: syn::Ident, + pub attr_name: Option<String>, + pub ty: syn::Type, + pub default: Option<DefaultExpression>, + pub with: Option<syn::Path>, + + /// If `true`, generated code will not look for this field in the input meta item, + /// instead always falling back to either `InputField::default` or `Default::default`. + pub skip: Option<bool>, + pub post_transform: Option<codegen::PostfixTransform>, + pub multiple: Option<bool>, +} + +impl InputField { + /// Generate a view into this field that can be used for code generation. + pub fn as_codegen_field(&self) -> codegen::Field<'_> { + codegen::Field { + ident: &self.ident, + name_in_attr: self + .attr_name + .as_ref() + .map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed), + ty: &self.ty, + default_expression: self.as_codegen_default(), + with_path: self.with.as_ref().map_or_else( + || Cow::Owned(parse_quote!(::darling::FromMeta::from_meta)), + Cow::Borrowed, + ), + skip: self.skip.unwrap_or_default(), + post_transform: self.post_transform.as_ref(), + multiple: self.multiple.unwrap_or_default(), + } + } + + /// Generate a codegen::DefaultExpression for this field. This requires the field name + /// in the `Inherit` case. + fn as_codegen_default(&self) -> Option<codegen::DefaultExpression<'_>> { + self.default.as_ref().map(|expr| match *expr { + DefaultExpression::Explicit(ref path) => codegen::DefaultExpression::Explicit(path), + DefaultExpression::Inherit => codegen::DefaultExpression::Inherit(&self.ident), + DefaultExpression::Trait => codegen::DefaultExpression::Trait, + }) + } + + fn new(ident: syn::Ident, ty: syn::Type) -> Self { + InputField { + ident, + ty, + attr_name: None, + default: None, + with: None, + skip: None, + post_transform: Default::default(), + multiple: None, + } + } + + pub fn from_field(f: &syn::Field, parent: Option<&Core>) -> Result<Self> { + let ident = f + .ident + .clone() + .unwrap_or_else(|| syn::Ident::new("__unnamed", ::proc_macro2::Span::call_site())); + let ty = f.ty.clone(); + let base = Self::new(ident, ty).parse_attributes(&f.attrs)?; + + Ok(if let Some(container) = parent { + base.with_inherited(container) + } else { + base + }) + } + + /// Apply inherited settings from the container. This is done _after_ parsing + /// to ensure deference to explicit field-level settings. + fn with_inherited(mut self, parent: &Core) -> Self { + // explicit renamings take precedence over rename rules on the container, + // but in the absence of an explicit name we apply the rule. + if self.attr_name.is_none() { + self.attr_name = Some(parent.rename_rule.apply_to_field(self.ident.to_string())); + } + + // Determine the default expression for this field, based on three pieces of information: + // 1. Will we look for this field in the attribute? + // 1. Is there a locally-defined default? + // 1. Did the parent define a default? + self.default = match ( + self.skip.unwrap_or_default(), + self.default.is_some(), + parent.default.is_some(), + ) { + // If we have a default, use it. + (_, true, _) => self.default, + + // If there isn't an explicit default but the struct sets a default, we'll + // inherit from that. + (_, false, true) => Some(DefaultExpression::Inherit), + + // If we're skipping the field and no defaults have been expressed then we should + // use the ::darling::export::Default trait. + (true, false, false) => Some(DefaultExpression::Trait), + + // If we don't have or need a default, then leave it blank. + (false, false, false) => None, + }; + + self + } +} + +impl ParseAttribute for InputField { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + let path = mi.path(); + + if path.is_ident("rename") { + if self.attr_name.is_some() { + return Err(Error::duplicate_field_path(path).with_span(mi)); + } + + self.attr_name = FromMeta::from_meta(mi)?; + } else if path.is_ident("default") { + if self.default.is_some() { + return Err(Error::duplicate_field_path(path).with_span(mi)); + } + self.default = FromMeta::from_meta(mi)?; + } else if path.is_ident("with") { + if self.with.is_some() { + return Err(Error::duplicate_field_path(path).with_span(mi)); + } + + self.with = Some(FromMeta::from_meta(mi)?); + } else if path.is_ident("skip") { + if self.skip.is_some() { + return Err(Error::duplicate_field_path(path).with_span(mi)); + } + + self.skip = FromMeta::from_meta(mi)?; + } else if path.is_ident("map") || path.is_ident("and_then") { + let transformer = path.get_ident().unwrap().clone(); + if let Some(post_transform) = &self.post_transform { + if transformer == post_transform.transformer { + return Err(Error::duplicate_field_path(path).with_span(mi)); + } else { + return Err(Error::custom(format!( + "Options `{}` and `{}` are mutually exclusive", + transformer, post_transform.transformer + )) + .with_span(mi)); + } + } + + self.post_transform = Some(codegen::PostfixTransform::new( + transformer, + FromMeta::from_meta(mi)?, + )); + } else if path.is_ident("multiple") { + if self.multiple.is_some() { + return Err(Error::duplicate_field_path(path).with_span(mi)); + } + + self.multiple = FromMeta::from_meta(mi)?; + } else { + return Err(Error::unknown_field_path(path).with_span(mi)); + } + + Ok(()) + } +} diff --git a/third_party/rust/darling_core/src/options/input_variant.rs b/third_party/rust/darling_core/src/options/input_variant.rs new file mode 100644 index 0000000000..92d6780af2 --- /dev/null +++ b/third_party/rust/darling_core/src/options/input_variant.rs @@ -0,0 +1,104 @@ +use std::borrow::Cow; + +use crate::ast::Fields; +use crate::codegen; +use crate::options::{Core, InputField, ParseAttribute}; +use crate::{Error, FromMeta, Result}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InputVariant { + ident: syn::Ident, + attr_name: Option<String>, + data: Fields<InputField>, + skip: Option<bool>, + /// Whether or not unknown fields are acceptable in this + allow_unknown_fields: Option<bool>, +} + +impl InputVariant { + pub fn as_codegen_variant<'a>(&'a self, ty_ident: &'a syn::Ident) -> codegen::Variant<'a> { + codegen::Variant { + ty_ident, + variant_ident: &self.ident, + name_in_attr: self + .attr_name + .as_ref() + .map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed), + data: self.data.as_ref().map(InputField::as_codegen_field), + skip: self.skip.unwrap_or_default(), + allow_unknown_fields: self.allow_unknown_fields.unwrap_or_default(), + } + } + + pub fn from_variant(v: &syn::Variant, parent: Option<&Core>) -> Result<Self> { + let mut starter = (InputVariant { + ident: v.ident.clone(), + attr_name: Default::default(), + data: Fields::empty_from(&v.fields), + skip: Default::default(), + allow_unknown_fields: None, + }) + .parse_attributes(&v.attrs)?; + + starter.data.fields = match v.fields { + syn::Fields::Unit => vec![], + syn::Fields::Unnamed(ref fields) => { + let mut items = Vec::with_capacity(fields.unnamed.len()); + for item in &fields.unnamed { + items.push(InputField::from_field(item, parent)?); + } + + items + } + syn::Fields::Named(ref fields) => { + let mut items = Vec::with_capacity(fields.named.len()); + for item in &fields.named { + items.push(InputField::from_field(item, parent)?); + } + + items + } + }; + + Ok(if let Some(p) = parent { + starter.with_inherited(p) + } else { + starter + }) + } + + fn with_inherited(mut self, parent: &Core) -> Self { + if self.attr_name.is_none() { + self.attr_name = Some(parent.rename_rule.apply_to_variant(self.ident.to_string())); + } + + if self.allow_unknown_fields.is_none() { + self.allow_unknown_fields = Some(parent.allow_unknown_fields.unwrap_or_default()); + } + + self + } +} + +impl ParseAttribute for InputVariant { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + let path = mi.path(); + if path.is_ident("rename") { + if self.attr_name.is_some() { + return Err(Error::duplicate_field_path(path).with_span(mi)); + } + + self.attr_name = FromMeta::from_meta(mi)?; + } else if path.is_ident("skip") { + if self.skip.is_some() { + return Err(Error::duplicate_field_path(path).with_span(mi)); + } + + self.skip = FromMeta::from_meta(mi)?; + } else { + return Err(Error::unknown_field_path(path).with_span(mi)); + } + + Ok(()) + } +} diff --git a/third_party/rust/darling_core/src/options/mod.rs b/third_party/rust/darling_core/src/options/mod.rs new file mode 100644 index 0000000000..e94ff6e696 --- /dev/null +++ b/third_party/rust/darling_core/src/options/mod.rs @@ -0,0 +1,133 @@ +use crate::{Error, FromMeta, Result}; + +mod core; +mod forward_attrs; +mod from_attributes; +mod from_derive; +mod from_field; +mod from_meta; +mod from_type_param; +mod from_variant; +mod input_field; +mod input_variant; +mod outer_from; +mod shape; + +pub use self::core::Core; +pub use self::forward_attrs::ForwardAttrs; +pub use self::from_attributes::FromAttributesOptions; +pub use self::from_derive::FdiOptions; +pub use self::from_field::FromFieldOptions; +pub use self::from_meta::FromMetaOptions; +pub use self::from_type_param::FromTypeParamOptions; +pub use self::from_variant::FromVariantOptions; +pub use self::input_field::InputField; +pub use self::input_variant::InputVariant; +pub use self::outer_from::OuterFrom; +pub use self::shape::{DataShape, Shape}; + +/// A default/fallback expression encountered in attributes during parsing. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum DefaultExpression { + /// The value should be taken from the `default` instance of the containing struct. + /// This is not valid in container options. + Inherit, + Explicit(syn::Path), + Trait, +} + +#[doc(hidden)] +impl FromMeta for DefaultExpression { + fn from_word() -> Result<Self> { + Ok(DefaultExpression::Trait) + } + + fn from_value(value: &syn::Lit) -> Result<Self> { + syn::Path::from_value(value).map(DefaultExpression::Explicit) + } +} + +/// Middleware for extracting attribute values. Implementers are expected to override +/// `parse_nested` so they can apply individual items to themselves, while `parse_attributes` +/// is responsible for looping through distinct outer attributes and collecting errors. +pub trait ParseAttribute: Sized { + fn parse_attributes(mut self, attrs: &[syn::Attribute]) -> Result<Self> { + let mut errors = Error::accumulator(); + for attr in attrs { + if attr.path == parse_quote!(darling) { + errors.handle(parse_attr(attr, &mut self)); + } + } + + errors.finish_with(self) + } + + /// Read a meta-item, and apply its values to the current instance. + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()>; +} + +fn parse_attr<T: ParseAttribute>(attr: &syn::Attribute, target: &mut T) -> Result<()> { + let mut errors = Error::accumulator(); + match attr.parse_meta().ok() { + Some(syn::Meta::List(data)) => { + for item in data.nested { + if let syn::NestedMeta::Meta(ref mi) = item { + errors.handle(target.parse_nested(mi)); + } else { + panic!("Wasn't able to parse: `{:?}`", item); + } + } + + errors.finish() + } + Some(ref item) => panic!("Wasn't able to parse: `{:?}`", item), + None => panic!("Unable to parse {:?}", attr), + } +} + +/// Middleware for extracting values from the body of the derive input. Implementers are +/// expected to override `parse_field` or `parse_variant` as appropriate for their use-case, +/// while `parse_body` dispatches to the appropriate methods and handles error collection. +pub trait ParseData: Sized { + fn parse_body(mut self, body: &syn::Data) -> Result<Self> { + use syn::{Data, Fields}; + + let mut errors = Error::accumulator(); + + match *body { + Data::Struct(ref data) => match data.fields { + Fields::Unit => {} + Fields::Named(ref fields) => { + for field in &fields.named { + errors.handle(self.parse_field(field)); + } + } + Fields::Unnamed(ref fields) => { + for field in &fields.unnamed { + errors.handle(self.parse_field(field)); + } + } + }, + Data::Enum(ref data) => { + for variant in &data.variants { + errors.handle(self.parse_variant(variant)); + } + } + Data::Union(_) => unreachable!(), + }; + + errors.finish_with(self) + } + + /// Apply the next found variant to the object, returning an error + /// if parsing goes wrong. + fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> { + Err(Error::unsupported_format("enum variant").with_span(variant)) + } + + /// Apply the next found struct field to the object, returning an error + /// if parsing goes wrong. + fn parse_field(&mut self, field: &syn::Field) -> Result<()> { + Err(Error::unsupported_format("struct field").with_span(field)) + } +} diff --git a/third_party/rust/darling_core/src/options/outer_from.rs b/third_party/rust/darling_core/src/options/outer_from.rs new file mode 100644 index 0000000000..499ac6cae7 --- /dev/null +++ b/third_party/rust/darling_core/src/options/outer_from.rs @@ -0,0 +1,82 @@ +use syn::{Field, Ident, Meta}; + +use crate::options::{Core, DefaultExpression, ForwardAttrs, ParseAttribute, ParseData}; +use crate::util::PathList; +use crate::{FromMeta, Result}; + +/// Reusable base for `FromDeriveInput`, `FromVariant`, `FromField`, and other top-level +/// `From*` traits. +#[derive(Debug, Clone)] +pub struct OuterFrom { + /// The field on the target struct which should receive the type identifier, if any. + pub ident: Option<Ident>, + + /// The field on the target struct which should receive the type attributes, if any. + pub attrs: Option<Ident>, + + pub container: Core, + + /// The attribute names that should be searched. + pub attr_names: PathList, + + /// The attribute names that should be forwarded. The presence of the word with no additional + /// filtering will cause _all_ attributes to be cloned and exposed to the struct after parsing. + pub forward_attrs: Option<ForwardAttrs>, + + /// Whether or not the container can be made through conversion from the type `Ident`. + pub from_ident: bool, +} + +impl OuterFrom { + pub fn start(di: &syn::DeriveInput) -> Result<Self> { + Ok(OuterFrom { + container: Core::start(di)?, + attrs: Default::default(), + ident: Default::default(), + attr_names: Default::default(), + forward_attrs: Default::default(), + from_ident: Default::default(), + }) + } +} + +impl ParseAttribute for OuterFrom { + fn parse_nested(&mut self, mi: &Meta) -> Result<()> { + let path = mi.path(); + if path.is_ident("attributes") { + self.attr_names = FromMeta::from_meta(mi)?; + } else if path.is_ident("forward_attrs") { + self.forward_attrs = FromMeta::from_meta(mi)?; + } else if path.is_ident("from_ident") { + // HACK: Declaring that a default is present will cause fields to + // generate correct code, but control flow isn't that obvious. + self.container.default = Some(DefaultExpression::Trait); + self.from_ident = true; + } else { + return self.container.parse_nested(mi); + } + Ok(()) + } +} + +impl ParseData for OuterFrom { + fn parse_field(&mut self, field: &Field) -> Result<()> { + match field + .ident + .as_ref() + .map(|v| v.to_string()) + .as_ref() + .map(|v| v.as_str()) + { + Some("ident") => { + self.ident = field.ident.clone(); + Ok(()) + } + Some("attrs") => { + self.attrs = field.ident.clone(); + Ok(()) + } + _ => self.container.parse_field(field), + } + } +} diff --git a/third_party/rust/darling_core/src/options/shape.rs b/third_party/rust/darling_core/src/options/shape.rs new file mode 100644 index 0000000000..481f9066ec --- /dev/null +++ b/third_party/rust/darling_core/src/options/shape.rs @@ -0,0 +1,271 @@ +//! Types for "shape" validation. This allows types deriving `FromDeriveInput` etc. to declare +//! that they only work on - for example - structs with named fields, or newtype enum variants. + +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; +use syn::{Meta, NestedMeta}; + +use crate::{Error, FromMeta, Result}; + +/// Receiver struct for shape validation. Shape validation allows a deriving type +/// to declare that it only accepts - for example - named structs, or newtype enum +/// variants. +/// +/// # Usage +/// Because `Shape` implements `FromMeta`, the name of the field where it appears is +/// controlled by the struct that declares `Shape` as a member. That field name is +/// shown as `ignore` below. +/// +/// ```rust,ignore +/// #[ignore(any, struct_named, enum_newtype)] +/// ``` +#[derive(Debug, Clone)] +pub struct Shape { + enum_values: DataShape, + struct_values: DataShape, + any: bool, +} + +impl Default for Shape { + fn default() -> Self { + Shape { + enum_values: DataShape::new("enum_"), + struct_values: DataShape::new("struct_"), + any: Default::default(), + } + } +} + +impl FromMeta for Shape { + fn from_list(items: &[NestedMeta]) -> Result<Self> { + let mut new = Shape::default(); + for item in items { + if let NestedMeta::Meta(Meta::Path(ref path)) = *item { + let ident = &path.segments.first().unwrap().ident; + let word = ident.to_string(); + if word == "any" { + new.any = true; + } else if word.starts_with("enum_") { + new.enum_values + .set_word(&word) + .map_err(|e| e.with_span(&ident))?; + } else if word.starts_with("struct_") { + new.struct_values + .set_word(&word) + .map_err(|e| e.with_span(&ident))?; + } else { + return Err(Error::unknown_value(&word).with_span(&ident)); + } + } else { + return Err(Error::unsupported_format("non-word").with_span(item)); + } + } + + Ok(new) + } +} + +impl ToTokens for Shape { + fn to_tokens(&self, tokens: &mut TokenStream) { + let fn_body = if self.any { + quote!(::darling::export::Ok(())) + } else { + let en = &self.enum_values; + let st = &self.struct_values; + + let enum_validation = if en.supports_none() { + let ty = en.prefix.trim_end_matches('_'); + quote!(return ::darling::export::Err(::darling::Error::unsupported_shape(#ty));) + } else { + quote! { + fn validate_variant(data: &::syn::Fields) -> ::darling::Result<()> { + #en + } + + for variant in &data.variants { + validate_variant(&variant.fields)?; + } + + Ok(()) + } + }; + + quote! { + match *__body { + ::syn::Data::Enum(ref data) => { + #enum_validation + } + ::syn::Data::Struct(ref struct_data) => { + let data = &struct_data.fields; + #st + } + ::syn::Data::Union(_) => unreachable!(), + } + } + }; + + tokens.append_all(quote! { + #[allow(unused_variables)] + fn __validate_body(__body: &::syn::Data) -> ::darling::Result<()> { + #fn_body + } + }); + } +} + +/// Receiver for shape information within a struct or enum context. See `Shape` for more information +/// on valid uses of shape validation. +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct DataShape { + /// The kind of shape being described. This can be `struct_` or `enum_`. + prefix: &'static str, + newtype: bool, + named: bool, + tuple: bool, + unit: bool, + any: bool, + /// Control whether the emitted code should be inside a function or not. + /// This is `true` when creating a `Shape` for `FromDeriveInput`, but false + /// when deriving `FromVariant`. + embedded: bool, +} + +impl DataShape { + fn new(prefix: &'static str) -> Self { + DataShape { + prefix, + embedded: true, + ..Default::default() + } + } + + fn supports_none(&self) -> bool { + !(self.any || self.newtype || self.named || self.tuple || self.unit) + } + + fn set_word(&mut self, word: &str) -> Result<()> { + match word.trim_start_matches(self.prefix) { + "newtype" => { + self.newtype = true; + Ok(()) + } + "named" => { + self.named = true; + Ok(()) + } + "tuple" => { + self.tuple = true; + Ok(()) + } + "unit" => { + self.unit = true; + Ok(()) + } + "any" => { + self.any = true; + Ok(()) + } + _ => Err(Error::unknown_value(word)), + } + } +} + +impl FromMeta for DataShape { + fn from_list(items: &[NestedMeta]) -> Result<Self> { + let mut errors = Error::accumulator(); + let mut new = DataShape::default(); + + for item in items { + if let NestedMeta::Meta(Meta::Path(ref path)) = *item { + errors.handle(new.set_word(&path.segments.first().unwrap().ident.to_string())); + } else { + errors.push(Error::unsupported_format("non-word").with_span(item)); + } + } + + errors.finish_with(new) + } +} + +impl ToTokens for DataShape { + fn to_tokens(&self, tokens: &mut TokenStream) { + let body = if self.any { + quote!(::darling::export::Ok(())) + } else if self.supports_none() { + let ty = self.prefix.trim_end_matches('_'); + quote!(::darling::export::Err(::darling::Error::unsupported_shape(#ty))) + } else { + let unit = match_arm("unit", self.unit); + let newtype = match_arm("newtype", self.newtype); + let named = match_arm("named", self.named); + let tuple = match_arm("tuple", self.tuple); + quote! { + match *data { + ::syn::Fields::Unit => #unit, + ::syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => #newtype, + ::syn::Fields::Unnamed(_) => #tuple, + ::syn::Fields::Named(_) => #named, + } + } + }; + + if self.embedded { + body.to_tokens(tokens); + } else { + tokens.append_all(quote! { + fn __validate_data(data: &::syn::Fields) -> ::darling::Result<()> { + #body + } + }); + } + } +} + +fn match_arm(name: &'static str, is_supported: bool) -> TokenStream { + if is_supported { + quote!(::darling::export::Ok(())) + } else { + quote!(::darling::export::Err(::darling::Error::unsupported_shape(#name))) + } +} + +#[cfg(test)] +mod tests { + use proc_macro2::TokenStream; + + use super::Shape; + use crate::FromMeta; + + /// parse a string as a syn::Meta instance. + fn pm(tokens: TokenStream) -> ::std::result::Result<syn::Meta, String> { + let attribute: syn::Attribute = parse_quote!(#[#tokens]); + attribute.parse_meta().map_err(|_| "Unable to parse".into()) + } + + fn fm<T: FromMeta>(tokens: TokenStream) -> T { + FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input")) + .expect("Tests should pass valid input") + } + + #[test] + fn supports_any() { + let decl = fm::<Shape>(quote!(ignore(any))); + assert!(decl.any); + } + + #[test] + fn supports_struct() { + let decl = fm::<Shape>(quote!(ignore(struct_any, struct_newtype))); + assert!(decl.struct_values.any); + assert!(decl.struct_values.newtype); + } + + #[test] + fn supports_mixed() { + let decl = fm::<Shape>(quote!(ignore(struct_newtype, enum_newtype, enum_tuple))); + assert!(decl.struct_values.newtype); + assert!(decl.enum_values.newtype); + assert!(decl.enum_values.tuple); + assert!(!decl.struct_values.any); + } +} diff --git a/third_party/rust/darling_core/src/usage/generics_ext.rs b/third_party/rust/darling_core/src/usage/generics_ext.rs new file mode 100644 index 0000000000..74e514215c --- /dev/null +++ b/third_party/rust/darling_core/src/usage/generics_ext.rs @@ -0,0 +1,24 @@ +use syn::Generics; + +use crate::usage::{IdentSet, LifetimeSet}; + +/// Extension trait for pulling specific generics data from a generics AST representation. +pub trait GenericsExt { + /// Get the set of all lifetimes declared by the syntax element. + /// This does not look for usage of the lifetime; see `UsesLifetimes` for that. + fn declared_lifetimes(&self) -> LifetimeSet; + + /// Get the set of all type parameters declared by the syntax element. + /// This does not look for usage of the type parameter; see `UsesTypeParams` for that. + fn declared_type_params(&self) -> IdentSet; +} + +impl GenericsExt for Generics { + fn declared_lifetimes(&self) -> LifetimeSet { + self.lifetimes().map(|lt| lt.lifetime.clone()).collect() + } + + fn declared_type_params(&self) -> IdentSet { + self.type_params().map(|tp| tp.ident.clone()).collect() + } +} diff --git a/third_party/rust/darling_core/src/usage/ident_set.rs b/third_party/rust/darling_core/src/usage/ident_set.rs new file mode 100644 index 0000000000..e38d332dd0 --- /dev/null +++ b/third_party/rust/darling_core/src/usage/ident_set.rs @@ -0,0 +1,8 @@ +use fnv::FnvHashSet; +use syn::Ident; + +/// A set of idents. +pub type IdentSet = FnvHashSet<Ident>; + +/// A set of references to idents. +pub type IdentRefSet<'a> = FnvHashSet<&'a Ident>; diff --git a/third_party/rust/darling_core/src/usage/lifetimes.rs b/third_party/rust/darling_core/src/usage/lifetimes.rs new file mode 100644 index 0000000000..eb80329674 --- /dev/null +++ b/third_party/rust/darling_core/src/usage/lifetimes.rs @@ -0,0 +1,326 @@ +use fnv::FnvHashSet; +use syn::punctuated::Punctuated; +use syn::{Lifetime, Type}; + +use crate::usage::Options; + +/// A set of lifetimes. +pub type LifetimeSet = FnvHashSet<Lifetime>; + +/// A set of references to lifetimes. +pub type LifetimeRefSet<'a> = FnvHashSet<&'a Lifetime>; + +/// Searcher for finding lifetimes in a syntax tree. +/// This can be used to determine which lifetimes must be emitted in generated code. +pub trait UsesLifetimes { + /// Returns the subset of the queried lifetimes that are used by the implementing syntax element. + /// + /// This method only accounts for direct usage by the element; indirect usage via bounds or `where` + /// predicates are not detected. + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a>; + + /// Find all used lifetimes, then clone them and return that set. + fn uses_lifetimes_cloned(&self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet { + self.uses_lifetimes(options, lifetimes) + .into_iter() + .cloned() + .collect() + } +} + +/// Searcher for finding lifetimes in an iterator. +/// +/// This trait extends iterators, providing a way to turn a filtered list of fields or variants into a set +/// of lifetimes. +pub trait CollectLifetimes { + /// Consume an iterator, accumulating all lifetimes in the elements which occur in `lifetimes`. + fn collect_lifetimes<'a>( + self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a>; + + /// Consume an iterator using `collect_lifetimes`, then clone all found lifetimes and return that set. + fn collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet; +} + +impl<'i, I, T> CollectLifetimes for T +where + T: IntoIterator<Item = &'i I>, + I: 'i + UsesLifetimes, +{ + fn collect_lifetimes<'a>( + self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + self.into_iter() + .fold(Default::default(), |mut state, value| { + state.extend(value.uses_lifetimes(options, lifetimes)); + state + }) + } + + fn collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet { + self.collect_lifetimes(options, lifetimes) + .into_iter() + .cloned() + .collect() + } +} + +impl<T: UsesLifetimes> UsesLifetimes for Vec<T> { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + self.collect_lifetimes(options, lifetimes) + } +} + +impl<T: UsesLifetimes, U> UsesLifetimes for Punctuated<T, U> { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + self.collect_lifetimes(options, lifetimes) + } +} + +impl<T: UsesLifetimes> UsesLifetimes for Option<T> { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + self.as_ref() + .map(|v| v.uses_lifetimes(options, lifetimes)) + .unwrap_or_default() + } +} + +impl UsesLifetimes for Lifetime { + fn uses_lifetimes<'a>(&self, _: &Options, lifetimes: &'a LifetimeSet) -> LifetimeRefSet<'a> { + lifetimes.iter().filter(|lt| *lt == self).collect() + } +} + +uses_lifetimes!(syn::AngleBracketedGenericArguments, args); +uses_lifetimes!(syn::BareFnArg, ty); +uses_lifetimes!(syn::Binding, ty); +uses_lifetimes!(syn::BoundLifetimes, lifetimes); +uses_lifetimes!(syn::Constraint, bounds); +uses_lifetimes!(syn::DataEnum, variants); +uses_lifetimes!(syn::DataStruct, fields); +uses_lifetimes!(syn::DataUnion, fields); +uses_lifetimes!(syn::Field, ty); +uses_lifetimes!(syn::FieldsNamed, named); +uses_lifetimes!(syn::LifetimeDef, lifetime, bounds); +uses_lifetimes!(syn::ParenthesizedGenericArguments, inputs, output); +uses_lifetimes!(syn::Path, segments); +uses_lifetimes!(syn::PathSegment, arguments); +uses_lifetimes!(syn::PredicateEq, lhs_ty, rhs_ty); +uses_lifetimes!(syn::PredicateLifetime, lifetime, bounds); +uses_lifetimes!(syn::PredicateType, lifetimes, bounded_ty, bounds); +uses_lifetimes!(syn::QSelf, ty); +uses_lifetimes!(syn::TraitBound, path, lifetimes); +uses_lifetimes!(syn::TypeArray, elem); +uses_lifetimes!(syn::TypeBareFn, inputs, output); +uses_lifetimes!(syn::TypeGroup, elem); +uses_lifetimes!(syn::TypeImplTrait, bounds); +uses_lifetimes!(syn::TypeParen, elem); +uses_lifetimes!(syn::TypePtr, elem); +uses_lifetimes!(syn::TypeReference, lifetime, elem); +uses_lifetimes!(syn::TypeSlice, elem); +uses_lifetimes!(syn::TypeTuple, elems); +uses_lifetimes!(syn::TypeTraitObject, bounds); +uses_lifetimes!(syn::Variant, fields); + +impl UsesLifetimes for syn::Data { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + syn::Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes), + syn::Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes), + syn::Data::Union(ref v) => v.uses_lifetimes(options, lifetimes), + } + } +} + +impl UsesLifetimes for Type { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + Type::Slice(ref v) => v.uses_lifetimes(options, lifetimes), + Type::Array(ref v) => v.uses_lifetimes(options, lifetimes), + Type::Ptr(ref v) => v.uses_lifetimes(options, lifetimes), + Type::Reference(ref v) => v.uses_lifetimes(options, lifetimes), + Type::BareFn(ref v) => v.uses_lifetimes(options, lifetimes), + Type::Tuple(ref v) => v.uses_lifetimes(options, lifetimes), + Type::Path(ref v) => v.uses_lifetimes(options, lifetimes), + Type::Paren(ref v) => v.uses_lifetimes(options, lifetimes), + Type::Group(ref v) => v.uses_lifetimes(options, lifetimes), + Type::TraitObject(ref v) => v.uses_lifetimes(options, lifetimes), + Type::ImplTrait(ref v) => v.uses_lifetimes(options, lifetimes), + Type::Macro(_) | Type::Verbatim(_) | Type::Infer(_) | Type::Never(_) => { + Default::default() + } + _ => panic!("Unknown syn::Type: {:?}", self), + } + } +} + +impl UsesLifetimes for syn::Fields { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + self.collect_lifetimes(options, lifetimes) + } +} + +impl UsesLifetimes for syn::TypePath { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + let mut hits = self.path.uses_lifetimes(options, lifetimes); + + if options.include_type_path_qself() { + hits.extend(self.qself.uses_lifetimes(options, lifetimes)); + } + + hits + } +} + +impl UsesLifetimes for syn::ReturnType { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + if let syn::ReturnType::Type(_, ref ty) = *self { + ty.uses_lifetimes(options, lifetimes) + } else { + Default::default() + } + } +} + +impl UsesLifetimes for syn::PathArguments { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + syn::PathArguments::None => Default::default(), + syn::PathArguments::AngleBracketed(ref v) => v.uses_lifetimes(options, lifetimes), + syn::PathArguments::Parenthesized(ref v) => v.uses_lifetimes(options, lifetimes), + } + } +} + +impl UsesLifetimes for syn::WherePredicate { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + syn::WherePredicate::Type(ref v) => v.uses_lifetimes(options, lifetimes), + syn::WherePredicate::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), + syn::WherePredicate::Eq(ref v) => v.uses_lifetimes(options, lifetimes), + } + } +} + +impl UsesLifetimes for syn::GenericArgument { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + syn::GenericArgument::Type(ref v) => v.uses_lifetimes(options, lifetimes), + syn::GenericArgument::Binding(ref v) => v.uses_lifetimes(options, lifetimes), + syn::GenericArgument::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), + syn::GenericArgument::Constraint(ref v) => v.uses_lifetimes(options, lifetimes), + syn::GenericArgument::Const(_) => Default::default(), + } + } +} + +impl UsesLifetimes for syn::TypeParamBound { + fn uses_lifetimes<'a>( + &self, + options: &Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + syn::TypeParamBound::Trait(ref v) => v.uses_lifetimes(options, lifetimes), + syn::TypeParamBound::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), + } + } +} + +#[cfg(test)] +mod tests { + use proc_macro2::Span; + use syn::DeriveInput; + + use super::UsesLifetimes; + use crate::usage::GenericsExt; + use crate::usage::Purpose::*; + + #[test] + fn struct_named() { + let input: DeriveInput = parse_quote! { + struct Foo<'a, 'b: 'a> { + parent: &'b Bar, + child: &'a Baz, + } + }; + let omitted = syn::Lifetime::new("'c", Span::call_site()); + + let lifetimes = { + let mut lt = input.generics.declared_lifetimes(); + lt.insert(omitted); + lt + }; + + let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes); + assert_eq!(matches.len(), 2); + } + + #[test] + fn qself() { + let input: DeriveInput = parse_quote! { + struct Foo<'a, 'b: 'a> { + parent: &'b Bar, + child: <Bar<'a> as MyIterator>::Item, + } + }; + let lifetimes = input.generics.declared_lifetimes(); + let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes); + assert_eq!(matches.len(), 1); + + let decl_matches = input.data.uses_lifetimes(&Declare.into(), &lifetimes); + assert_eq!(decl_matches.len(), 2); + } +} diff --git a/third_party/rust/darling_core/src/usage/mod.rs b/third_party/rust/darling_core/src/usage/mod.rs new file mode 100644 index 0000000000..fe8f12fb98 --- /dev/null +++ b/third_party/rust/darling_core/src/usage/mod.rs @@ -0,0 +1,111 @@ +//! Traits and types used for tracking the usage of generic parameters through a proc-macro input. +//! +//! When generating trait impls, libraries often want to automatically figure out which type parameters +//! are used in which fields, and then emit bounds that will produce the most permissive compilable +//! code. +//! +//! # Usage +//! +//! ## Example 1: Filtering +//! This example accepts a proc-macro input, then finds all lifetimes and type parameters used +//! by private fields. +//! +//! ```rust +//! # extern crate darling_core; +//! # extern crate syn; +//! # +//! # // in real-world usage, import from `darling` +//! # use darling_core::usage::{self, CollectLifetimes, CollectTypeParams, GenericsExt, Purpose}; +//! # use syn::{Data, DeriveInput, GenericParam, Generics, Visibility}; +//! # +//! # #[allow(dead_code)] +//! fn process(input: &DeriveInput) -> Generics { +//! let type_params = input.generics.declared_type_params(); +//! let lifetimes = input.generics.declared_lifetimes(); +//! +//! let mut ret_generics = input.generics.clone(); +//! +//! if let Data::Struct(ref body) = input.data { +//! let internal_fields = body +//! .fields +//! .iter() +//! .filter(|field| field.vis == Visibility::Inherited) +//! .collect::<Vec<_>>(); +//! +//! let int_type_params = internal_fields +//! .collect_type_params(&Purpose::BoundImpl.into(), &type_params); +//! +//! // We could reuse the vec from above, but here we'll instead +//! // directly consume the chained iterator. +//! let int_lifetimes = body +//! .fields +//! .iter() +//! .filter(|field| field.vis == Visibility::Inherited) +//! .collect_lifetimes(&Purpose::BoundImpl.into(), &lifetimes); +//! +//! +//! ret_generics.params = ret_generics +//! .params +//! .into_iter() +//! .filter(|gp| { +//! match *gp { +//! GenericParam::Type(ref ty) => int_type_params.contains(&ty.ident), +//! GenericParam::Lifetime(ref lt) => int_lifetimes.contains(<.lifetime), +//! _ => true, +//! } +//! }) +//! .collect(); +//! } +//! +//! ret_generics +//! } +//! +//! # fn main() {} +//! ``` +//! +//! ## Example 2: Integrating with `FromDeriveInput` +//! It is possible to use `darling`'s magic fields feature in tandem with the `usage` feature set. +//! While there is no custom derive for `UsesTypeParams` or `UsesLifetimes`, there are macros to +//! generate impls. +//! +//! ```rust,ignore +//! #![allow(dead_code)] +//! +//! #[derive(FromField)] +//! #[darling(attributes(speak))] +//! struct SpeakerField { +//! ident: Option<syn::Ident>, +//! ty: syn::Type, +//! #[darling(default)] +//! volume: Option<u32>, +//! } +//! +//! uses_type_params!(SpeakerField, ty); +//! uses_lifetimes!(SpeakerField, ty); +//! +//! #[derive(FromDeriveInput)] +//! struct SpeakerOptions { +//! generics: syn::Generics, +//! data: darling::ast::Data<darling::util::Ignored, SpeakerField>, +//! } +//! ``` +//! +//! At this point, you are able to call `uses_type_params` on `SpeakerOptions.data`, or any filtered +//! view of it. `darling` internally uses this in conjunction with the `skip` meta-item to determine +//! which type parameters don't require the `FromMeta` bound in generated impls. +//! +//! **Note:** If you are performing operations referencing generic params in meta-items parsed by `darling`, +//! you should determine if those impact the emitted code and wire up `UsesTypeParams` accordingly for +//! your field/variant. + +mod generics_ext; +mod ident_set; +mod lifetimes; +mod options; +mod type_params; + +pub use self::generics_ext::GenericsExt; +pub use self::ident_set::{IdentRefSet, IdentSet}; +pub use self::lifetimes::{CollectLifetimes, LifetimeRefSet, LifetimeSet, UsesLifetimes}; +pub use self::options::{Options, Purpose}; +pub use self::type_params::{CollectTypeParams, UsesTypeParams}; diff --git a/third_party/rust/darling_core/src/usage/options.rs b/third_party/rust/darling_core/src/usage/options.rs new file mode 100644 index 0000000000..f154881be9 --- /dev/null +++ b/third_party/rust/darling_core/src/usage/options.rs @@ -0,0 +1,58 @@ +/// The goal of tracing generic parameter usage. +/// +/// Not all uses of type parameters imply a need to add bounds to a generated trait impl. +/// For example, a field of type `<Vec<T> as a::b::Trait>::Associated` does not need a +/// `where T: Serialize` bound in `serde`. +/// However, a proc macro that is attempting to generate a helper struct _would_ need to +/// know about this usage, or else the generated code would reference an unknown type `T` +/// and fail to compile. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Purpose { + /// The tracing is being used to generate an `impl` block. + /// + /// Uses such as `syn::TypePath.qself` will _not_ be returned. + BoundImpl, + /// The tracing is being used to generate a new struct or enum. + /// + /// All uses will be returned. + Declare, +} + +/// Control struct for searching type parameters. +/// +/// This acts as the search context, preserving information that might have been +/// kept on a visitor in a different implementation. +/// Trait implementers are required to pass this through on any invocations they make. +/// +/// # Usage +/// For extensibility, `Options` hides all of its fields from consumers. +/// To create an instance, use the `From<Purpose>` trait implementation: +/// +/// ```rust +/// # use darling_core::usage::{Options, Purpose}; +/// let opts: Options = Purpose::BoundImpl.into(); +/// assert!(!opts.include_type_path_qself()); +/// ``` +#[derive(Debug, Clone)] +pub struct Options { + purpose: Purpose, + #[doc(hidden)] + __nonexhaustive: (), +} + +impl From<Purpose> for Options { + fn from(purpose: Purpose) -> Self { + Self { + purpose, + __nonexhaustive: (), + } + } +} + +impl Options { + /// Returns `true` if the implementer of `UseTypeParams` should search + /// `<___ as ...>::...` when looking for type parameter uses. + pub fn include_type_path_qself(&self) -> bool { + self.purpose == Purpose::Declare + } +} diff --git a/third_party/rust/darling_core/src/usage/type_params.rs b/third_party/rust/darling_core/src/usage/type_params.rs new file mode 100644 index 0000000000..b504048e56 --- /dev/null +++ b/third_party/rust/darling_core/src/usage/type_params.rs @@ -0,0 +1,357 @@ +use syn::punctuated::Punctuated; +use syn::{Ident, Type}; + +use crate::usage::{IdentRefSet, IdentSet, Options}; + +/// Searcher for finding type params in a syntax tree. +/// This can be used to determine if a given type parameter needs to be bounded in a generated impl. +pub trait UsesTypeParams { + /// Returns the subset of the queried type parameters that are used by the implementing syntax element. + /// + /// This method only accounts for direct usage by the element; indirect usage via bounds or `where` + /// predicates are not detected. + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a>; + + /// Find all type params using `uses_type_params`, then clone the found values and return the set. + fn uses_type_params_cloned(&self, options: &Options, type_set: &IdentSet) -> IdentSet { + self.uses_type_params(options, type_set) + .into_iter() + .cloned() + .collect() + } +} + +/// Searcher for finding type params in an iterator. +/// +/// This trait extends iterators, providing a way to turn a filtered list of fields or variants into a set +/// of type parameter idents. +pub trait CollectTypeParams { + /// Consume an iterator, accumulating all type parameters in the elements which occur in `type_set`. + fn collect_type_params<'a>(self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a>; + + /// Consume an iterator using `collect_type_params`, then clone all found type params and return that set. + fn collect_type_params_cloned(self, options: &Options, type_set: &IdentSet) -> IdentSet; +} + +impl<'i, T, I> CollectTypeParams for T +where + T: IntoIterator<Item = &'i I>, + I: 'i + UsesTypeParams, +{ + fn collect_type_params<'a>(self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + self.into_iter().fold( + IdentRefSet::with_capacity_and_hasher(type_set.len(), Default::default()), + |state, value| union_in_place(state, value.uses_type_params(options, type_set)), + ) + } + + fn collect_type_params_cloned(self, options: &Options, type_set: &IdentSet) -> IdentSet { + self.collect_type_params(options, type_set) + .into_iter() + .cloned() + .collect() + } +} + +/// Insert the contents of `right` into `left`. +fn union_in_place<'a>(mut left: IdentRefSet<'a>, right: IdentRefSet<'a>) -> IdentRefSet<'a> { + left.extend(right); + + left +} + +impl UsesTypeParams for () { + fn uses_type_params<'a>(&self, _options: &Options, _type_set: &'a IdentSet) -> IdentRefSet<'a> { + Default::default() + } +} + +impl<T: UsesTypeParams> UsesTypeParams for Option<T> { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + self.as_ref() + .map(|v| v.uses_type_params(options, type_set)) + .unwrap_or_default() + } +} + +impl<T: UsesTypeParams> UsesTypeParams for Vec<T> { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + self.collect_type_params(options, type_set) + } +} + +impl<T: UsesTypeParams, U> UsesTypeParams for Punctuated<T, U> { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + self.collect_type_params(options, type_set) + } +} + +uses_type_params!(syn::AngleBracketedGenericArguments, args); +uses_type_params!(syn::BareFnArg, ty); +uses_type_params!(syn::Binding, ty); +uses_type_params!(syn::Constraint, bounds); +uses_type_params!(syn::DataEnum, variants); +uses_type_params!(syn::DataStruct, fields); +uses_type_params!(syn::DataUnion, fields); +uses_type_params!(syn::Field, ty); +uses_type_params!(syn::FieldsNamed, named); +uses_type_params!(syn::ParenthesizedGenericArguments, inputs, output); +uses_type_params!(syn::PredicateEq, lhs_ty, rhs_ty); +uses_type_params!(syn::PredicateType, bounded_ty, bounds); +uses_type_params!(syn::QSelf, ty); +uses_type_params!(syn::TraitBound, path); +uses_type_params!(syn::TypeArray, elem); +uses_type_params!(syn::TypeBareFn, inputs, output); +uses_type_params!(syn::TypeGroup, elem); +uses_type_params!(syn::TypeImplTrait, bounds); +uses_type_params!(syn::TypeParen, elem); +uses_type_params!(syn::TypePtr, elem); +uses_type_params!(syn::TypeReference, elem); +uses_type_params!(syn::TypeSlice, elem); +uses_type_params!(syn::TypeTuple, elems); +uses_type_params!(syn::TypeTraitObject, bounds); +uses_type_params!(syn::Variant, fields); + +impl UsesTypeParams for syn::Data { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + match *self { + syn::Data::Struct(ref v) => v.uses_type_params(options, type_set), + syn::Data::Enum(ref v) => v.uses_type_params(options, type_set), + syn::Data::Union(ref v) => v.uses_type_params(options, type_set), + } + } +} + +impl UsesTypeParams for syn::Fields { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + self.collect_type_params(options, type_set) + } +} + +/// Check if an Ident exactly matches one of the sought-after type parameters. +impl UsesTypeParams for Ident { + fn uses_type_params<'a>(&self, _options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + type_set.iter().filter(|v| *v == self).collect() + } +} + +impl UsesTypeParams for syn::ReturnType { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + if let syn::ReturnType::Type(_, ref ty) = *self { + ty.uses_type_params(options, type_set) + } else { + Default::default() + } + } +} + +impl UsesTypeParams for Type { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + match *self { + Type::Slice(ref v) => v.uses_type_params(options, type_set), + Type::Array(ref v) => v.uses_type_params(options, type_set), + Type::Ptr(ref v) => v.uses_type_params(options, type_set), + Type::Reference(ref v) => v.uses_type_params(options, type_set), + Type::BareFn(ref v) => v.uses_type_params(options, type_set), + Type::Tuple(ref v) => v.uses_type_params(options, type_set), + Type::Path(ref v) => v.uses_type_params(options, type_set), + Type::Paren(ref v) => v.uses_type_params(options, type_set), + Type::Group(ref v) => v.uses_type_params(options, type_set), + Type::TraitObject(ref v) => v.uses_type_params(options, type_set), + Type::ImplTrait(ref v) => v.uses_type_params(options, type_set), + Type::Macro(_) | Type::Verbatim(_) | Type::Infer(_) | Type::Never(_) => { + Default::default() + } + _ => panic!("Unknown syn::Type: {:?}", self), + } + } +} + +impl UsesTypeParams for syn::TypePath { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + let hits = self.path.uses_type_params(options, type_set); + + if options.include_type_path_qself() { + union_in_place(hits, self.qself.uses_type_params(options, type_set)) + } else { + hits + } + } +} + +impl UsesTypeParams for syn::Path { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + // Not sure if this is even possible, but a path with no segments definitely + // can't use type parameters. + if self.segments.is_empty() { + return Default::default(); + } + + // A path segment ident can only match if it is not global and it is the first segment + // in the path. + let ident_hits = if self.leading_colon.is_none() { + self.segments[0].ident.uses_type_params(options, type_set) + } else { + Default::default() + }; + + // Merge ident hit, if any, with all hits from path arguments + self.segments.iter().fold(ident_hits, |state, segment| { + union_in_place(state, segment.arguments.uses_type_params(options, type_set)) + }) + } +} + +impl UsesTypeParams for syn::PathArguments { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + match *self { + syn::PathArguments::None => Default::default(), + syn::PathArguments::AngleBracketed(ref v) => v.uses_type_params(options, type_set), + syn::PathArguments::Parenthesized(ref v) => v.uses_type_params(options, type_set), + } + } +} + +impl UsesTypeParams for syn::WherePredicate { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + match *self { + syn::WherePredicate::Lifetime(_) => Default::default(), + syn::WherePredicate::Type(ref v) => v.uses_type_params(options, type_set), + syn::WherePredicate::Eq(ref v) => v.uses_type_params(options, type_set), + } + } +} + +impl UsesTypeParams for syn::GenericArgument { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + match *self { + syn::GenericArgument::Type(ref v) => v.uses_type_params(options, type_set), + syn::GenericArgument::Binding(ref v) => v.uses_type_params(options, type_set), + syn::GenericArgument::Constraint(ref v) => v.uses_type_params(options, type_set), + syn::GenericArgument::Const(_) | syn::GenericArgument::Lifetime(_) => { + Default::default() + } + } + } +} + +impl UsesTypeParams for syn::TypeParamBound { + fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> { + match *self { + syn::TypeParamBound::Trait(ref v) => v.uses_type_params(options, type_set), + syn::TypeParamBound::Lifetime(_) => Default::default(), + } + } +} + +#[cfg(test)] +mod tests { + use proc_macro2::Span; + use syn::{DeriveInput, Ident}; + + use super::UsesTypeParams; + use crate::usage::IdentSet; + use crate::usage::Purpose::*; + + fn ident_set(idents: Vec<&str>) -> IdentSet { + idents + .into_iter() + .map(|s| Ident::new(s, Span::call_site())) + .collect() + } + + #[test] + fn finds_simple() { + let input: DeriveInput = parse_quote! { struct Foo<T, U>(T, i32, A, U); }; + let generics = ident_set(vec!["T", "U", "X"]); + let matches = input.data.uses_type_params(&BoundImpl.into(), &generics); + assert_eq!(matches.len(), 2); + assert!(matches.contains::<Ident>(&parse_quote!(T))); + assert!(matches.contains::<Ident>(&parse_quote!(U))); + assert!(!matches.contains::<Ident>(&parse_quote!(X))); + assert!(!matches.contains::<Ident>(&parse_quote!(A))); + } + + #[test] + fn finds_named() { + let input: DeriveInput = parse_quote! { + struct Foo<T, U = usize> { + bar: T, + world: U, + } + }; + + let generics = ident_set(vec!["T", "U", "X"]); + + let matches = input.data.uses_type_params(&BoundImpl.into(), &generics); + + assert_eq!(matches.len(), 2); + assert!(matches.contains::<Ident>(&parse_quote!(T))); + assert!(matches.contains::<Ident>(&parse_quote!(U))); + assert!(!matches.contains::<Ident>(&parse_quote!(X))); + assert!(!matches.contains::<Ident>(&parse_quote!(A))); + } + + #[test] + fn finds_as_type_arg() { + let input: DeriveInput = parse_quote! { + struct Foo<T, U> { + bar: T, + world: Vec<U>, + } + }; + + let generics = ident_set(vec!["T", "U", "X"]); + + let matches = input.data.uses_type_params(&BoundImpl.into(), &generics); + + assert_eq!(matches.len(), 2); + assert!(matches.contains::<Ident>(&parse_quote!(T))); + assert!(matches.contains::<Ident>(&parse_quote!(U))); + assert!(!matches.contains::<Ident>(&parse_quote!(X))); + assert!(!matches.contains::<Ident>(&parse_quote!(A))); + } + + #[test] + fn associated_type() { + let input: DeriveInput = + parse_quote! { struct Foo<'a, T> where T: Iterator { peek: T::Item } }; + let generics = ident_set(vec!["T", "INTO"]); + let matches = input.data.uses_type_params(&BoundImpl.into(), &generics); + assert_eq!(matches.len(), 1); + } + + #[test] + fn box_fn_output() { + let input: DeriveInput = parse_quote! { struct Foo<T>(Box<Fn() -> T>); }; + let generics = ident_set(vec!["T"]); + let matches = input.data.uses_type_params(&BoundImpl.into(), &generics); + assert_eq!(matches.len(), 1); + assert!(matches.contains::<Ident>(&parse_quote!(T))); + } + + #[test] + fn box_fn_input() { + let input: DeriveInput = parse_quote! { struct Foo<T>(Box<Fn(&T) -> ()>); }; + let generics = ident_set(vec!["T"]); + let matches = input.data.uses_type_params(&BoundImpl.into(), &generics); + assert_eq!(matches.len(), 1); + assert!(matches.contains::<Ident>(&parse_quote!(T))); + } + + /// Test that `syn::TypePath` is correctly honoring the different modes a + /// search can execute in. + #[test] + fn qself_vec() { + let input: DeriveInput = + parse_quote! { struct Foo<T>(<Vec<T> as a::b::Trait>::AssociatedItem); }; + let generics = ident_set(vec!["T", "U"]); + + let bound_matches = input.data.uses_type_params(&BoundImpl.into(), &generics); + assert_eq!(bound_matches.len(), 0); + + let declare_matches = input.data.uses_type_params(&Declare.into(), &generics); + assert_eq!(declare_matches.len(), 1); + assert!(declare_matches.contains::<Ident>(&parse_quote!(T))); + } +} diff --git a/third_party/rust/darling_core/src/util/flag.rs b/third_party/rust/darling_core/src/util/flag.rs new file mode 100644 index 0000000000..ade88988ab --- /dev/null +++ b/third_party/rust/darling_core/src/util/flag.rs @@ -0,0 +1,100 @@ +use proc_macro2::Span; +use syn::{spanned::Spanned, Meta}; + +use crate::{FromMeta, Result}; + +/// A meta-item that can be present as a word - with no value - or absent. +/// +/// # Defaulting +/// Like `Option`, `Flag` does not require `#[darling(default)]` to be optional. +/// If the caller does not include the property, then an absent `Flag` will be included +/// in the receiver struct. +/// +/// # Spans +/// `Flag` keeps the span where its word was seen. +/// This enables attaching custom error messages to the word, such as in the case of two +/// conflicting flags being present. +/// +/// # Example +/// ```ignore +/// #[derive(FromMeta)] +/// #[darling(and_then = "Self::not_both")] +/// struct Demo { +/// flag_a: Flag, +/// flag_b: Flag, +/// } +/// +/// impl Demo { +/// fn not_both(self) -> Result<Self> { +/// if self.flag_a.is_present() && self.flag_b.is_present() { +/// Err(Error::custom("Cannot set flag_a and flag_b").with_span(self.flag_b)) +/// } else { +/// Ok(self) +/// } +/// } +/// } +/// ``` +/// +/// The above struct would then produce the following error. +/// +/// ```ignore +/// #[example(flag_a, flag_b)] +/// // ^^^^^^ Cannot set flag_a and flag_b +/// ``` +#[derive(Debug, Clone, Copy, Default)] +pub struct Flag(Option<Span>); + +impl Flag { + /// Creates a new `Flag` which corresponds to the presence of a value. + pub fn present() -> Self { + Flag(Some(Span::call_site())) + } + + /// Check if the flag is present. + pub fn is_present(&self) -> bool { + self.0.is_some() + } + + #[deprecated(since = "0.14.0", note = "Use Flag::is_present")] + pub fn is_some(&self) -> bool { + self.is_present() + } +} + +impl FromMeta for Flag { + fn from_none() -> Option<Self> { + Some(Flag(None)) + } + + fn from_meta(mi: &syn::Meta) -> Result<Self> { + if let Meta::Path(p) = mi { + Ok(Flag(Some(p.span()))) + } else { + // The implementation for () will produce an error for all non-path meta items; + // call it to make sure the span behaviors and error messages are the same. + Err(<()>::from_meta(mi).unwrap_err()) + } + } +} + +impl Spanned for Flag { + fn span(&self) -> Span { + self.0.unwrap_or_else(Span::call_site) + } +} + +impl From<Flag> for bool { + fn from(flag: Flag) -> Self { + flag.is_present() + } +} + +impl From<bool> for Flag { + fn from(v: bool) -> Self { + if v { + Flag::present() + } else { + Flag(None) + } + } +} diff --git a/third_party/rust/darling_core/src/util/ident_string.rs b/third_party/rust/darling_core/src/util/ident_string.rs new file mode 100644 index 0000000000..12b8c64ec1 --- /dev/null +++ b/third_party/rust/darling_core/src/util/ident_string.rs @@ -0,0 +1,155 @@ +use std::fmt; +use std::hash::{Hash, Hasher}; + +use proc_macro2::{Span, TokenStream}; +use quote::ToTokens; +use syn::{Ident, Meta}; + +use crate::{FromMeta, Result}; + +/// A wrapper for an `Ident` which also keeps the value as a string. +/// +/// This struct can be used to perform string comparisons and operations. +#[derive(Clone, PartialOrd, Ord)] +pub struct IdentString { + ident: Ident, + string: String, +} + +impl IdentString { + /// Create a new `IdentString`. + pub fn new(ident: Ident) -> Self { + IdentString { + string: ident.to_string(), + ident, + } + } + + /// Get the ident as a `proc_macro2::Ident`. + pub fn as_ident(&self) -> &Ident { + &self.ident + } + + /// Get the ident as a string. + pub fn as_str(&self) -> &str { + &self.string + } + + /// Get the location of this `Ident` in source. + pub fn span(&self) -> Span { + self.ident.span() + } + + /// Apply some transform to the ident's string representation. + /// + /// # Panics + /// This will panic if the transform produces an invalid ident. + pub fn map<F, S>(self, map_fn: F) -> Self + where + F: FnOnce(String) -> S, + S: AsRef<str>, + { + let span = self.span(); + let string = map_fn(self.string); + Ident::new(string.as_ref(), span).into() + } +} + +impl AsRef<Ident> for IdentString { + fn as_ref(&self) -> &Ident { + self.as_ident() + } +} + +impl AsRef<str> for IdentString { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl From<Ident> for IdentString { + fn from(ident: Ident) -> Self { + IdentString::new(ident) + } +} + +impl From<IdentString> for Ident { + fn from(v: IdentString) -> Ident { + v.ident + } +} + +impl From<IdentString> for String { + fn from(v: IdentString) -> String { + v.string + } +} + +impl Eq for IdentString {} + +impl PartialEq for IdentString { + fn eq(&self, rhs: &Self) -> bool { + self.ident == rhs.ident + } +} + +impl PartialEq<String> for IdentString { + fn eq(&self, rhs: &String) -> bool { + self.as_str() == rhs + } +} + +impl<'a> PartialEq<&'a str> for IdentString { + fn eq(&self, rhs: &&str) -> bool { + self.as_str() == *rhs + } +} + +impl Hash for IdentString { + fn hash<H: Hasher>(&self, state: &mut H) { + self.ident.hash(state); + } +} + +impl ToTokens for IdentString { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + } +} + +impl fmt::Debug for IdentString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.ident) + } +} + +impl fmt::Display for IdentString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.ident) + } +} + +impl FromMeta for IdentString { + fn from_meta(item: &Meta) -> Result<Self> { + Ident::from_meta(item).map(IdentString::from) + } +} + +#[cfg(test)] +mod tests { + use super::IdentString; + + #[test] + fn convert() { + let i_str = IdentString::new(parse_quote!(t)); + assert_eq!(i_str.as_str(), "t"); + } + + #[test] + fn map_transform() { + let i = IdentString::new(parse_quote!(my)); + let after = i.map(|v| format!("var_{}", v)); + assert_eq!(after, "var_my"); + assert_eq!(after, String::from("var_my")); + } +} diff --git a/third_party/rust/darling_core/src/util/ignored.rs b/third_party/rust/darling_core/src/util/ignored.rs new file mode 100644 index 0000000000..b74acfdda8 --- /dev/null +++ b/third_party/rust/darling_core/src/util/ignored.rs @@ -0,0 +1,50 @@ +use crate::{ + usage::{self, UsesLifetimes, UsesTypeParams}, + FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam, + FromVariant, Result, +}; + +/// An efficient way of discarding data from a syntax element. +/// +/// All syntax elements will be successfully read into +/// the `Ignored` struct, with all properties discarded. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub struct Ignored; + +macro_rules! ignored { + ($trayt:ident, $method:ident, $syn:path) => { + impl $trayt for Ignored { + fn $method(_: &$syn) -> Result<Self> { + Ok(Ignored) + } + } + }; +} + +ignored!(FromGenericParam, from_generic_param, syn::GenericParam); +ignored!(FromGenerics, from_generics, syn::Generics); +ignored!(FromTypeParam, from_type_param, syn::TypeParam); +ignored!(FromMeta, from_meta, syn::Meta); +ignored!(FromDeriveInput, from_derive_input, syn::DeriveInput); +ignored!(FromField, from_field, syn::Field); +ignored!(FromVariant, from_variant, syn::Variant); + +impl UsesTypeParams for Ignored { + fn uses_type_params<'a>( + &self, + _opts: &usage::Options, + _: &'a usage::IdentSet, + ) -> usage::IdentRefSet<'a> { + Default::default() + } +} + +impl UsesLifetimes for Ignored { + fn uses_lifetimes<'a>( + &self, + _opts: &usage::Options, + _: &'a usage::LifetimeSet, + ) -> usage::LifetimeRefSet<'a> { + Default::default() + } +} diff --git a/third_party/rust/darling_core/src/util/mod.rs b/third_party/rust/darling_core/src/util/mod.rs new file mode 100644 index 0000000000..11f1113a73 --- /dev/null +++ b/third_party/rust/darling_core/src/util/mod.rs @@ -0,0 +1,21 @@ +//! Utility types for attribute parsing. + +mod flag; +mod ident_string; +mod ignored; +mod over_ride; +mod parse_attribute; +mod path_list; +mod path_to_string; +mod spanned_value; +mod with_original; + +pub use self::flag::Flag; +pub use self::ident_string::IdentString; +pub use self::ignored::Ignored; +pub use self::over_ride::Override; +pub use self::parse_attribute::parse_attribute_to_meta_list; +pub use self::path_list::PathList; +pub use self::path_to_string::path_to_string; +pub use self::spanned_value::SpannedValue; +pub use self::with_original::WithOriginal; diff --git a/third_party/rust/darling_core/src/util/over_ride.rs b/third_party/rust/darling_core/src/util/over_ride.rs new file mode 100644 index 0000000000..92ce25a3b6 --- /dev/null +++ b/third_party/rust/darling_core/src/util/over_ride.rs @@ -0,0 +1,147 @@ +use std::fmt; + +use syn::{Lit, NestedMeta}; + +use crate::{FromMeta, Result}; + +use self::Override::*; + +/// A value which can inherit a default value or have an explicit value specified. +/// +/// # Usage +/// This type is meant for attributes like `default` in `darling`, which can take the following forms: +/// +/// * `#[darling(default)]` +/// * `#[darling(default="path::to::fn")]` +/// +/// In a struct collecting input for this attribute, that would be written as: +/// +/// ```rust,ignore +/// use darling::{util::Override, FromField}; +/// #[derive(FromField)] +/// #[darling(attributes(darling))] +/// pub struct Options { +/// default: Option<Override<syn::Path>>, +/// } +/// +/// impl Options { +/// fn hydrate(self) -> Option<syn::Path> { +/// self.default.map(|ov| ov.unwrap_or(syn::parse_path("::Default::default").unwrap())) +/// } +/// } +/// ``` +/// +/// The `word` format (with no associated value), would produce `Override::Inherit`, while a list +/// or value format would produce `Override::Explicit`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Override<T> { + /// Inherit the eventual value from an external source. + Inherit, + + /// Explicitly set the value. + Explicit(T), +} + +impl<T> Override<T> { + /// Converts from `Override<T>` to `Override<&T>`. + /// + /// Produces a new `Override`, containing a reference into the original, leaving the original in place. + pub fn as_ref(&self) -> Override<&T> { + match *self { + Inherit => Inherit, + Explicit(ref val) => Explicit(val), + } + } + + /// Converts from `Override<T>` to `Override<&mut T>`. + /// + /// Produces a new `Override`, containing a mutable reference into the original. + pub fn as_mut(&mut self) -> Override<&mut T> { + match *self { + Inherit => Inherit, + Explicit(ref mut val) => Explicit(val), + } + } + + /// Returns `true` if the override is an `Explicit` value. + pub fn is_explicit(&self) -> bool { + match *self { + Inherit => false, + Explicit(_) => true, + } + } + + /// Converts from `Override<T>` to `Option<T>`. + pub fn explicit(self) -> Option<T> { + match self { + Inherit => None, + Explicit(val) => Some(val), + } + } + + /// Unwraps an override, yielding the content of an `Explicit`. Otherwise, it returns `optb`. + pub fn unwrap_or(self, optb: T) -> T { + match self { + Inherit => optb, + Explicit(val) => val, + } + } + + /// Unwraps an override, yielding the content of an `Explicit`. Otherwise, it calls `op`. + pub fn unwrap_or_else<F>(self, op: F) -> T + where + F: FnOnce() -> T, + { + match self { + Inherit => op(), + Explicit(val) => val, + } + } +} + +impl<T: Default> Override<T> { + /// Returns the contained value or the default value of `T`. + pub fn unwrap_or_default(self) -> T { + self.unwrap_or_else(Default::default) + } +} + +impl<T> Default for Override<T> { + fn default() -> Self { + Inherit + } +} + +impl<T> From<Option<T>> for Override<T> { + fn from(v: Option<T>) -> Self { + match v { + None => Inherit, + Some(val) => Explicit(val), + } + } +} + +impl<T: fmt::Display> fmt::Display for Override<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Inherit => write!(f, "Inherit"), + Explicit(ref val) => write!(f, "Explicit `{}`", val), + } + } +} + +/// Parses a `Meta`. A bare word will produce `Override::Inherit`, while +/// any value will be forwarded to `T::from_meta`. +impl<T: FromMeta> FromMeta for Override<T> { + fn from_word() -> Result<Self> { + Ok(Inherit) + } + + fn from_list(items: &[NestedMeta]) -> Result<Self> { + Ok(Explicit(FromMeta::from_list(items)?)) + } + + fn from_value(lit: &Lit) -> Result<Self> { + Ok(Explicit(FromMeta::from_value(lit)?)) + } +} diff --git a/third_party/rust/darling_core/src/util/parse_attribute.rs b/third_party/rust/darling_core/src/util/parse_attribute.rs new file mode 100644 index 0000000000..8d8be5d7ce --- /dev/null +++ b/third_party/rust/darling_core/src/util/parse_attribute.rs @@ -0,0 +1,73 @@ +use crate::{util::SpannedValue, Error, Result}; +use std::fmt; +use syn::{punctuated::Pair, spanned::Spanned, token, Attribute, Meta, MetaList, Path}; + +/// Try to parse an attribute into a meta list. Path-type meta values are accepted and returned +/// as empty lists with their passed-in path. Name-value meta values and non-meta attributes +/// will cause errors to be returned. +pub fn parse_attribute_to_meta_list(attr: &Attribute) -> Result<MetaList> { + match attr.parse_meta() { + Ok(Meta::List(list)) => Ok(list), + Ok(Meta::NameValue(nv)) => Err(Error::custom(format!( + "Name-value arguments are not supported. Use #[{}(...)]", + DisplayPath(&nv.path) + )) + .with_span(&nv)), + Ok(Meta::Path(path)) => Ok(MetaList { + path, + paren_token: token::Paren(attr.span()), + nested: Default::default(), + }), + Err(e) => Err(Error::custom(format!("Unable to parse attribute: {}", e)) + .with_span(&SpannedValue::new((), e.span()))), + } +} + +struct DisplayPath<'a>(&'a Path); + +impl fmt::Display for DisplayPath<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let path = self.0; + if path.leading_colon.is_some() { + write!(f, "::")?; + } + for segment in path.segments.pairs() { + match segment { + Pair::Punctuated(segment, _) => write!(f, "{}::", segment.ident)?, + Pair::End(segment) => segment.ident.fmt(f)?, + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::parse_attribute_to_meta_list; + use syn::{parse_quote, spanned::Spanned, Ident}; + + #[test] + fn parse_list() { + let meta = parse_attribute_to_meta_list(&parse_quote!(#[bar(baz = 4)])).unwrap(); + assert_eq!(meta.nested.len(), 1); + } + + #[test] + fn parse_path_returns_empty_list() { + let meta = parse_attribute_to_meta_list(&parse_quote!(#[bar])).unwrap(); + assert!(meta.path.is_ident(&Ident::new("bar", meta.path.span()))); + assert!(meta.nested.is_empty()); + } + + #[test] + fn parse_name_value_returns_error() { + parse_attribute_to_meta_list(&parse_quote!(#[bar = 4])).unwrap_err(); + } + + #[test] + fn parse_name_value_error_includes_example() { + let err = parse_attribute_to_meta_list(&parse_quote!(#[bar = 4])).unwrap_err(); + assert!(err.to_string().contains("#[bar(...)]")); + } +} diff --git a/third_party/rust/darling_core/src/util/path_list.rs b/third_party/rust/darling_core/src/util/path_list.rs new file mode 100644 index 0000000000..26c62954bc --- /dev/null +++ b/third_party/rust/darling_core/src/util/path_list.rs @@ -0,0 +1,103 @@ +use std::ops::Deref; + +use syn::{Meta, NestedMeta, Path}; + +use crate::{Error, FromMeta, Result}; + +use super::path_to_string; + +/// A list of `syn::Path` instances. This type is used to extract a list of paths from an +/// attribute. +/// +/// # Usage +/// An `PathList` field on a struct implementing `FromMeta` will turn `#[builder(derive(serde::Debug, Clone))]` into: +/// +/// ```rust,ignore +/// StructOptions { +/// derive: PathList(vec![syn::Path::new("serde::Debug"), syn::Path::new("Clone")]) +/// } +/// ``` +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct PathList(Vec<Path>); + +impl PathList { + /// Create a new list. + pub fn new<T: Into<Path>>(vals: Vec<T>) -> Self { + PathList(vals.into_iter().map(T::into).collect()) + } + + /// Create a new `Vec` containing the string representation of each path. + pub fn to_strings(&self) -> Vec<String> { + self.0.iter().map(path_to_string).collect() + } +} + +impl Deref for PathList { + type Target = Vec<Path>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From<Vec<Path>> for PathList { + fn from(v: Vec<Path>) -> Self { + PathList(v) + } +} + +impl FromMeta for PathList { + fn from_list(v: &[NestedMeta]) -> Result<Self> { + let mut paths = Vec::with_capacity(v.len()); + for nmi in v { + if let NestedMeta::Meta(Meta::Path(ref path)) = *nmi { + paths.push(path.clone()); + } else { + return Err(Error::unexpected_type("non-word").with_span(nmi)); + } + } + + Ok(PathList(paths)) + } +} + +#[cfg(test)] +mod tests { + use super::PathList; + use crate::FromMeta; + use proc_macro2::TokenStream; + use syn::{Attribute, Meta}; + + /// parse a string as a syn::Meta instance. + fn pm(tokens: TokenStream) -> ::std::result::Result<Meta, String> { + let attribute: Attribute = parse_quote!(#[#tokens]); + attribute.parse_meta().map_err(|_| "Unable to parse".into()) + } + + fn fm<T: FromMeta>(tokens: TokenStream) -> T { + FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input")) + .expect("Tests should pass valid input") + } + + #[test] + fn succeeds() { + let paths = fm::<PathList>(quote!(ignore(Debug, Clone, Eq))); + assert_eq!( + paths.to_strings(), + vec![ + String::from("Debug"), + String::from("Clone"), + String::from("Eq") + ] + ); + } + + /// Check that the parser rejects non-word members of the list, and that the error + /// has an associated span. + #[test] + fn fails_non_word() { + let input = PathList::from_meta(&pm(quote!(ignore(Debug, Clone = false))).unwrap()); + let err = input.unwrap_err(); + assert!(err.has_span()); + } +} diff --git a/third_party/rust/darling_core/src/util/path_to_string.rs b/third_party/rust/darling_core/src/util/path_to_string.rs new file mode 100644 index 0000000000..0e0ad99c7a --- /dev/null +++ b/third_party/rust/darling_core/src/util/path_to_string.rs @@ -0,0 +1,36 @@ +/// Transform Rust paths to a readable and comparable string. +/// +/// # Limitations +/// * Leading colons are ignored. +/// * Angle brackets and `as` elements are ignored. +/// +/// # Example +/// ```rust +/// # use darling_core::util::path_to_string; +/// # use syn::parse_quote; +/// assert_eq!(path_to_string(&parse_quote!(a::b)), "a::b"); +/// ``` +pub fn path_to_string(path: &syn::Path) -> String { + path.segments + .iter() + .map(|s| s.ident.to_string()) + .collect::<Vec<String>>() + .join("::") +} + +#[cfg(test)] +mod tests { + use syn::parse_quote; + + use super::path_to_string; + + #[test] + fn simple_ident() { + assert_eq!(path_to_string(&parse_quote!(a)), "a"); + } + + #[test] + fn simple_path() { + assert_eq!(path_to_string(&parse_quote!(a::b)), "a::b"); + } +} diff --git a/third_party/rust/darling_core/src/util/spanned_value.rs b/third_party/rust/darling_core/src/util/spanned_value.rs new file mode 100644 index 0000000000..19db775dc6 --- /dev/null +++ b/third_party/rust/darling_core/src/util/spanned_value.rs @@ -0,0 +1,115 @@ +use proc_macro2::Span; +use std::ops::{Deref, DerefMut}; +use syn::spanned::Spanned; + +use crate::{ + FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam, + FromVariant, Result, +}; + +/// A value and an associated position in source code. The main use case for this is +/// to preserve position information to emit warnings from proc macros. You can use +/// a `SpannedValue<T>` as a field in any struct that implements or derives any of +/// `darling`'s core traits. +/// +/// To access the underlying value, use the struct's `Deref` implementation. +/// +/// # Defaulting +/// This type is meant to be used in conjunction with attribute-extracted options, +/// but the user may not always explicitly set those options in their source code. +/// In this case, using `Default::default()` will create an instance which points +/// to `Span::call_site()`. +#[derive(Debug, Clone, Copy)] +pub struct SpannedValue<T> { + value: T, + span: Span, +} + +impl<T> SpannedValue<T> { + pub fn new(value: T, span: Span) -> Self { + SpannedValue { value, span } + } + + /// Get the source code location referenced by this struct. + pub fn span(&self) -> Span { + self.span + } + + /// Apply a mapping function to a reference to the spanned value. + pub fn map_ref<U>(&self, map_fn: impl FnOnce(&T) -> U) -> SpannedValue<U> { + SpannedValue::new(map_fn(&self.value), self.span) + } +} + +impl<T: Default> Default for SpannedValue<T> { + fn default() -> Self { + SpannedValue::new(Default::default(), Span::call_site()) + } +} + +impl<T> Deref for SpannedValue<T> { + type Target = T; + + fn deref(&self) -> &T { + &self.value + } +} + +impl<T> DerefMut for SpannedValue<T> { + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl<T> AsRef<T> for SpannedValue<T> { + fn as_ref(&self) -> &T { + &self.value + } +} + +impl<T> Spanned for SpannedValue<T> { + fn span(&self) -> Span { + self.span + } +} + +macro_rules! spanned { + ($trayt:ident, $method:ident, $syn:path) => { + impl<T: $trayt> $trayt for SpannedValue<T> { + fn $method(value: &$syn) -> Result<Self> { + Ok(SpannedValue::new( + $trayt::$method(value).map_err(|e| e.with_span(value))?, + value.span(), + )) + } + } + }; +} + +spanned!(FromGenericParam, from_generic_param, syn::GenericParam); +spanned!(FromGenerics, from_generics, syn::Generics); +spanned!(FromTypeParam, from_type_param, syn::TypeParam); +spanned!(FromMeta, from_meta, syn::Meta); +spanned!(FromDeriveInput, from_derive_input, syn::DeriveInput); +spanned!(FromField, from_field, syn::Field); +spanned!(FromVariant, from_variant, syn::Variant); + +impl<T: Spanned> From<T> for SpannedValue<T> { + fn from(value: T) -> Self { + let span = value.span(); + SpannedValue::new(value, span) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use proc_macro2::Span; + + /// Make sure that `SpannedValue` can be seamlessly used as its underlying type. + #[test] + fn deref() { + let test = SpannedValue::new("hello", Span::call_site()); + assert_eq!("hello", test.trim()); + } +} diff --git a/third_party/rust/darling_core/src/util/with_original.rs b/third_party/rust/darling_core/src/util/with_original.rs new file mode 100644 index 0000000000..5aa82f850b --- /dev/null +++ b/third_party/rust/darling_core/src/util/with_original.rs @@ -0,0 +1,35 @@ +use crate::{ + FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam, + FromVariant, Result, +}; + +/// A container to parse some syntax and retain access to the original. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct WithOriginal<T, O> { + pub parsed: T, + pub original: O, +} + +impl<T, O> WithOriginal<T, O> { + pub fn new(parsed: T, original: O) -> Self { + WithOriginal { parsed, original } + } +} + +macro_rules! with_original { + ($trayt:ident, $func:ident, $syn:path) => { + impl<T: $trayt> $trayt for WithOriginal<T, $syn> { + fn $func(value: &$syn) -> Result<Self> { + Ok(WithOriginal::new($trayt::$func(value)?, value.clone())) + } + } + }; +} + +with_original!(FromDeriveInput, from_derive_input, syn::DeriveInput); +with_original!(FromField, from_field, syn::Field); +with_original!(FromGenerics, from_generics, syn::Generics); +with_original!(FromGenericParam, from_generic_param, syn::GenericParam); +with_original!(FromMeta, from_meta, syn::Meta); +with_original!(FromTypeParam, from_type_param, syn::TypeParam); +with_original!(FromVariant, from_variant, syn::Variant); diff --git a/third_party/rust/darling_macro/.cargo-checksum.json b/third_party/rust/darling_macro/.cargo-checksum.json new file mode 100644 index 0000000000..964c467e89 --- /dev/null +++ b/third_party/rust/darling_macro/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"db1237292a12c7e555b72ae0e8afcc0da07a04f7273ee8b8690c49b4b8c2ab4b","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/lib.rs":"1dbd1ed31a7db5ff7995bd1dd494e962645e6ff62b0f88807fe1b6025523f187"},"package":"7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"}
\ No newline at end of file diff --git a/third_party/rust/darling_macro/Cargo.toml b/third_party/rust/darling_macro/Cargo.toml new file mode 100644 index 0000000000..7672f6650c --- /dev/null +++ b/third_party/rust/darling_macro/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "darling_macro" +version = "0.14.2" +authors = ["Ted Driggs <ted.driggs@outlook.com>"] +description = """ +Internal support for a proc-macro library for reading attributes into structs when +implementing custom derives. Use https://crates.io/crates/darling in your code. +""" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" + +[lib] +proc-macro = true + +[dependencies.darling_core] +version = "=0.14.2" + +[dependencies.quote] +version = "1.0.18" + +[dependencies.syn] +version = "1.0.91" diff --git a/third_party/rust/darling_macro/LICENSE b/third_party/rust/darling_macro/LICENSE new file mode 100644 index 0000000000..0b48eadc9d --- /dev/null +++ b/third_party/rust/darling_macro/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Ted Driggs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/darling_macro/src/lib.rs b/third_party/rust/darling_macro/src/lib.rs new file mode 100644 index 0000000000..de9709fb73 --- /dev/null +++ b/third_party/rust/darling_macro/src/lib.rs @@ -0,0 +1,43 @@ +// This is needed for 1.31.0 to keep compiling +extern crate proc_macro; + +use darling_core::{derive, Error}; +use proc_macro::TokenStream; +use syn::parse_macro_input; + +#[proc_macro_derive(FromMeta, attributes(darling))] +pub fn derive_from_meta(input: TokenStream) -> TokenStream { + derive::from_meta(&parse_macro_input!(input)).into() +} + +#[proc_macro_derive(FromMetaItem, attributes(darling))] +pub fn derive_from_meta_item(_input: TokenStream) -> TokenStream { + Error::custom("darling::FromMetaItem has been replaced by darling::FromMeta") + .write_errors() + .into() +} + +#[proc_macro_derive(FromAttributes, attributes(darling))] +pub fn derive_from_attributes(input: TokenStream) -> TokenStream { + derive::from_attributes(&parse_macro_input!(input)).into() +} + +#[proc_macro_derive(FromDeriveInput, attributes(darling))] +pub fn derive_from_input(input: TokenStream) -> TokenStream { + derive::from_derive_input(&parse_macro_input!(input)).into() +} + +#[proc_macro_derive(FromField, attributes(darling))] +pub fn derive_field(input: TokenStream) -> TokenStream { + derive::from_field(&parse_macro_input!(input)).into() +} + +#[proc_macro_derive(FromTypeParam, attributes(darling))] +pub fn derive_type_param(input: TokenStream) -> TokenStream { + derive::from_type_param(&parse_macro_input!(input)).into() +} + +#[proc_macro_derive(FromVariant, attributes(darling))] +pub fn derive_variant(input: TokenStream) -> TokenStream { + derive::from_variant(&parse_macro_input!(input)).into() +} |