diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/darling | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
93 files changed, 8788 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..2392782177 --- /dev/null +++ b/third_party/rust/darling/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"9a83b921a832799b871634e4cca8a5c92cb9b901626009fc46c2f480db9e20f2","Cargo.toml":"6fa2ba78e86577539ad3ff71cb44109bf5b500d7b3b1c59f9484b61288546da7","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","README.md":"5b591026cb7c3ed964d46779f323a2b45f89aa18d2bc5f63519126cb3b7efed9","examples/automatic_bounds.rs":"2540e6eb0761755737927a0e01d94956a1e9db04db67ae1aba3110415759fac4","examples/consume_fields.rs":"ebf4bd8baf4e54ccaa926f910957183d6a5b1decaa87ab5ebcca6c8d38b6c6b3","examples/fallible_read.rs":"aa9d1e0aaba8f3eb4580e94e133839f7eb77fca61beed254f3d5e0f6d6981f00","examples/supports_struct.rs":"d69124e09d3d6b8e04a3af07a6af96c5df7cbd3d6953a51657b39088cc2c2de7","src/lib.rs":"07da20edb52c4aba30f2b680b28ca96cf995859566b0db3b1d2e0ee967249a18","src/macros_public.rs":"3ed7eb99f309d9cd600d3a09ff4dcf5cc5d787fb49e8e5ead6bb00e31e5e6793","tests/accrue_errors.rs":"f5ac2d8cb0a12284a845d25b9472c4605aa5e8c1cd66a6dd6ad64f1c749b2caf","tests/computed_bound.rs":"2313da96a250b5948ca06bf86cb7158b55a59eba75334aa8ba27a46b28ede6b5","tests/custom_bound.rs":"4dd3e8fd76734d8f262e857773f53a820229ad6e10fe6fbbbe1f636c7da9eab0","tests/defaults.rs":"b544be90d18be26305a757e8468bf8735356889b59c167294d118e32ee7f82ea","tests/enums_newtype.rs":"a09af70072e566bee1f6cad91675f3553c47333e51a0e389ebb47ae82de776a8","tests/enums_struct.rs":"e0097d7f947cf9e4612c9450c55ea5075c7f6fcbbf8cac7176449d92eebc9343","tests/enums_unit.rs":"8c075d5897b60b58cb71d6306e7fdd80851f5a147ae3010ba70ea100007364a3","tests/error.rs":"465f7634fa23f0076c93a9c5fc16ccde16119b874d64c8dabaf275b6b7ae61f2","tests/from_generics.rs":"79230ad21e8482cf6e6ceb0c74303bc0cdf77fbb951f46a6ba1006ecf1248fd5","tests/from_type_param.rs":"7c97745cdcea18a2d6f51e4da7426055a078287bf9f2c93d487057195efa2b30","tests/from_type_param_default.rs":"80787ef6527e7f76c2aac93b1f35a006a9c5e0df8deed61698eaac1127278021","tests/from_variant.rs":"2e804326302a62b979eae963e88f0a2cdb6a21ee9667407c361d178f8c0aadba","tests/generics.rs":"e08aea8a8de8f03e3c243bde650e250defbe340cef3e4c06935b2b3e46d2a376","tests/happy_path.rs":"c32daa68e2becdc2d6204985a19b437cfb49d7f1680e890578f0760dc9749b77","tests/multiple.rs":"0391be49bab07771d7e37d35fe17f6d9bf1aa6dc57e2c0e5c0912ab8e043128f","tests/newtype.rs":"3f029724467abc7a33aaf7b6a1feb7b6898eba578576afff338e73deb9fd2b3b","tests/skip.rs":"604861aa4d1dfdc4e5f38f8261be19b7240c650eb493b64ce0178f54c24a8d2d","tests/split_declaration.rs":"f509390f88549164af9218f1e5b07564b169a4481a20b738432ffb03c517b599","tests/suggestions.rs":"0afb756949be876aaae76974f119be811c783fb134a54978ff0453c537ff3174","tests/supports.rs":"8564709d7e63b124cda91f7e21c890037200e533d0403ffd7eb075403cf58926"},"package":"3fe629a532efad5526454efb0700f86d5ad7ff001acb37e431c8bf017a432a8e"}
\ 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..7698ba05ee --- /dev/null +++ b/third_party/rust/darling/CHANGELOG.md @@ -0,0 +1,107 @@ +# Changelog + +## 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.toml b/third_party/rust/darling/Cargo.toml new file mode 100644 index 0000000000..0fd6008b56 --- /dev/null +++ b/third_party/rust/darling/Cargo.toml @@ -0,0 +1,45 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "darling" +version = "0.10.1" +authors = ["Ted Driggs <ted.driggs@outlook.com>"] +exclude = ["/.travis.yml", "/publish.sh"] +description = "A proc-macro library for reading attributes into structs when\nimplementing custom derives.\n" +documentation = "https://docs.rs/darling/0.10.1" +readme = "README.md" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" +[dependencies.darling_core] +version = "=0.10.1" + +[dependencies.darling_macro] +version = "=0.10.1" +[dev-dependencies.proc-macro2] +version = "1" + +[dev-dependencies.quote] +version = "1" + +[dev-dependencies.syn] +version = "1" + +[features] +default = ["suggestions"] +diagnostics = ["darling_core/diagnostics"] +suggestions = ["darling_core/suggestions"] +[badges.maintenance] +status = "actively-developed" + +[badges.travis-ci] +repository = "TedDriggs/darling" 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..24e46d93cd --- /dev/null +++ b/third_party/rust/darling/README.md @@ -0,0 +1,113 @@ +Darling +======= + +[![Build Status](https://travis-ci.org/TedDriggs/darling.svg?branch=master)](https://travis-ci.org/TedDriggs/darling) +[![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. + +## 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(from_ident, 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", ipsum))] +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 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`. +* **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")]` 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.
\ 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..73e236bda4 --- /dev/null +++ b/third_party/rust/darling/examples/automatic_bounds.rs @@ -0,0 +1,78 @@ +#[macro_use] +extern crate darling; + +extern crate syn; + +use darling::FromDeriveInput; + +#[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..4b0703f507 --- /dev/null +++ b/third_party/rust/darling/examples/consume_fields.rs @@ -0,0 +1,175 @@ +//! This example shows how to do struct and field parsing using darling. + +#[macro_use] +extern crate darling; +extern crate proc_macro2; +#[macro_use] +extern crate quote; +extern crate syn; + +use darling::ast; +use darling::FromDeriveInput; +use proc_macro2::TokenStream; +use 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(|| 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!(#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. + #[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..c487854336 --- /dev/null +++ b/third_party/rust/darling/examples/fallible_read.rs @@ -0,0 +1,87 @@ +//! 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 the receiver before returning. +#[macro_use] +extern crate darling; + +extern crate syn; + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_str; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(my_trait), map = "MyInputReceiver::autocorrect")] +pub struct MyInputReceiver { + /// This field must be present and a string or else parsing will panic. + 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. Otherwise, recover and proceed. + 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 + /// 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) -> 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) => { + let val: i64 = if let Ok(v) = FromMeta::from_meta(&mi) { + v + } else { + panic!(format!("amplitude should have been an integer")) + }; + + val.abs() as u64 + } + }; + + 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/supports_struct.rs b/third_party/rust/darling/examples/supports_struct.rs new file mode 100644 index 0000000000..dbf8238a9d --- /dev/null +++ b/third_party/rust/darling/examples/supports_struct.rs @@ -0,0 +1,62 @@ +#[macro_use] +extern crate darling; + +extern crate syn; + +use darling::{ast, util, FromDeriveInput}; +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..70035be9d5 --- /dev/null +++ b/third_party/rust/darling/src/lib.rs @@ -0,0 +1,98 @@ +//! # Darling +//! Darling is a tool for declarative attribute parsing in proc macro implementations. +//! +//! +//! ## Design +//! Darling takes considerable design inspiration from [`serde`]. 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`|`syn::Ident`|The identifier of the passed-in field| +//! |`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.| + +extern crate core; +extern crate darling_core; + +#[allow(unused_imports)] +#[macro_use] +extern crate darling_macro; + +#[doc(hidden)] +pub use darling_macro::*; + +#[doc(inline)] +pub use darling_core::{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::vec::Vec; + pub use std::string::ToString; +} + +#[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..a3c5cac98d --- /dev/null +++ b/third_party/rust/darling/src/macros_public.rs @@ -0,0 +1,98 @@ +//! 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; +/// # +/// # #[macro_use] +/// # extern crate darling_core; +/// # +/// 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..9ae8212765 --- /dev/null +++ b/third_party/rust/darling/tests/accrue_errors.rs @@ -0,0 +1,108 @@ +//! These tests verify that multiple errors will be collected up from throughout +//! the parsing process and returned correctly to the caller. + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::ast; +use darling::FromDeriveInput; + +#[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..94fd307b68 --- /dev/null +++ b/third_party/rust/darling/tests/computed_bound.rs @@ -0,0 +1,46 @@ +#[macro_use] +extern crate darling; +extern crate syn; + +use darling::FromDeriveInput; + +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..4266a740e1 --- /dev/null +++ b/third_party/rust/darling/tests/custom_bound.rs @@ -0,0 +1,25 @@ +#[macro_use] +extern crate darling; +extern crate syn; + +use std::ops::Add; + +#[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..c6003ec4ba --- /dev/null +++ b/third_party/rust/darling/tests/defaults.rs @@ -0,0 +1,32 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate quote; +#[macro_use] +extern crate syn; + +use darling::FromDeriveInput; + +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"); +}
\ No newline at end of file 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..0fd12f03fc --- /dev/null +++ b/third_party/rust/darling/tests/enums_newtype.rs @@ -0,0 +1,96 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[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..63ce69058d --- /dev/null +++ b/third_party/rust/darling/tests/enums_struct.rs @@ -0,0 +1,16 @@ +//! Test expansion of enums which have struct variants. + +#[macro_use] +extern crate darling; +extern crate syn; + +#[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..f9eb23f245 --- /dev/null +++ b/third_party/rust/darling/tests/enums_unit.rs @@ -0,0 +1,16 @@ +//! Test expansion of enum variants which have no associated data. + +#[macro_use] +extern crate darling; +extern crate syn; + +#[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..edd72eb1dd --- /dev/null +++ b/third_party/rust/darling/tests/error.rs @@ -0,0 +1,55 @@ +//! In case of bad input, parsing should fail. The error should have locations set in derived implementations. +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[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..2c259ec280 --- /dev/null +++ b/third_party/rust/darling/tests/from_generics.rs @@ -0,0 +1,186 @@ +//! 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. + +#[macro_use] +extern crate darling; +extern crate syn; + +use darling::ast::{self, GenericParamExt}; +use darling::util::{Ignored, WithOriginal}; +use darling::{FromDeriveInput, Result}; + +#[derive(FromDeriveInput)] +#[darling(attributes(lorem))] +struct MyReceiver { + pub ident: syn::Ident, + pub generics: ast::Generics<ast::GenericParam<MyTypeParam>>, +} + +#[derive(FromTypeParam)] +#[darling(attributes(lorem))] +struct MyTypeParam { + pub ident: syn::Ident, + #[darling(default)] + pub foo: bool, + #[darling(default)] + 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] +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 + .iter() + .collect::<Vec<_>>() + .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_type_param.rs b/third_party/rust/darling/tests/from_type_param.rs new file mode 100644 index 0000000000..adaf34dd38 --- /dev/null +++ b/third_party/rust/darling/tests/from_type_param.rs @@ -0,0 +1,65 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromTypeParam; +use syn::{DeriveInput, GenericParam, Ident, TypeParam}; + +#[darling(attributes(lorem), from_ident)] +#[derive(FromTypeParam)] +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] +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..eb0ecc766c --- /dev/null +++ b/third_party/rust/darling/tests/from_type_param_default.rs @@ -0,0 +1,59 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromTypeParam; +use syn::{DeriveInput, GenericParam, TypeParam}; + +#[darling(attributes(lorem), default)] +#[derive(Default, FromTypeParam)] +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] +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..be216cbe52 --- /dev/null +++ b/third_party/rust/darling/tests/from_variant.rs @@ -0,0 +1,27 @@ +#[macro_use] +extern crate darling; +extern crate syn; + +#[derive(FromVariant)] +#[darling(from_ident, attributes(hello))] +#[allow(dead_code)] +pub struct Lorem { + ident: syn::Ident, + into: Option<bool>, + skip: Option<bool>, + 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(), + fields: darling::ast::Style::Unit.into(), + } + } +} + +#[test] +fn expansion() {} diff --git a/third_party/rust/darling/tests/generics.rs b/third_party/rust/darling/tests/generics.rs new file mode 100644 index 0000000000..a83d03e284 --- /dev/null +++ b/third_party/rust/darling/tests/generics.rs @@ -0,0 +1,27 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[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..df1bfadd75 --- /dev/null +++ b/third_party/rust/darling/tests/happy_path.rs @@ -0,0 +1,75 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[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/multiple.rs b/third_party/rust/darling/tests/multiple.rs new file mode 100644 index 0000000000..e705280633 --- /dev/null +++ b/third_party/rust/darling/tests/multiple.rs @@ -0,0 +1,36 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[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..5219d9ad93 --- /dev/null +++ b/third_party/rust/darling/tests/newtype.rs @@ -0,0 +1,32 @@ +//! A newtype struct should be able to derive `FromMeta` if its member implements it. + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[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..b4e0f64dc1 --- /dev/null +++ b/third_party/rust/darling/tests/skip.rs @@ -0,0 +1,52 @@ +//! Test that skipped fields are not read into structs when they appear in input. + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[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, + } + ); +} 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..23d458d173 --- /dev/null +++ b/third_party/rust/darling/tests/split_declaration.rs @@ -0,0 +1,78 @@ +//! When input is split across multiple attributes on one element, +//! darling should collapse that into one struct. + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use std::string::ToString; + +use darling::{Error, FromDeriveInput}; + +#[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..3499e9ed9a --- /dev/null +++ b/third_party/rust/darling/tests/suggestions.rs @@ -0,0 +1,34 @@ +#![cfg(feature = "suggestions")] + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[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..ead3bad3b5 --- /dev/null +++ b/third_party/rust/darling/tests/supports.rs @@ -0,0 +1,85 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::ast; +use darling::FromDeriveInput; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(from_variants), supports(enum_any))] +pub struct Container { + 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 { + data: ast::Data<(), syn::Field>, +} + +mod source { + use syn::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 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 + Container::from_derive_input(&source::newtype_enum()).unwrap(); + + // 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 + StructContainer::from_derive_input(&source::named_struct()).unwrap(); + + // 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(); +} 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..828d6ce066 --- /dev/null +++ b/third_party/rust/darling_core/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"550d5451a115c7cb8118c0a038e12b1b97ddcefeee0303438296b86aacbe84e5","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/ast/data.rs":"73a6b7a679011135dfee25af462163b3fe3f3effdf028c440aa6e3e4b5ff079f","src/ast/generics.rs":"3bdfe1abdbee64f5aaa9b189dc5c58e222568f196ed206e9d6d91ea5f29673e7","src/ast/mod.rs":"58a58eeb1db7682e5994732cc8eb04088f6ca662805460ef443cf089e5c24e2c","src/codegen/attr_extractor.rs":"d49605dbea8e95d64a9859a8beef5cf678390ffc5ba76ec77d69913f650ba974","src/codegen/default_expr.rs":"60f23b77ddf80da70ec92fd0d8cb5a97143535df85eafa0e47943ac797ec46d2","src/codegen/error.rs":"1a415136f93adde7458e39cab91413adc9a64243b718c7b74fdeba748959b5af","src/codegen/field.rs":"82104df8f3e733b23764fd6683e60d24ce62912b8b29a22dadbbc55d6a42f158","src/codegen/from_derive_impl.rs":"7cc03ffcc65e8e06dbf9d469502dc4ddd8772a2177dbf6404ad32d306379f777","src/codegen/from_field.rs":"a77abdb024b9a884dcdfda758ab072f26d5fae12eb67a3deb3dc47c6be2f2390","src/codegen/from_meta_impl.rs":"8fc08e65736efaf82b7aa2ce7e20c1a4235a94840353b860d6e782606c92ce18","src/codegen/from_type_param.rs":"c9cdb902d72f2ec047aeaa5217c2cda551d6cfc570f51ae4420907d6b398d9e7","src/codegen/from_variant_impl.rs":"1b44e10d8a0c43b1dcb7d66d1ced74ffab7f7beaa680031c11cfd4ab1abb39bf","src/codegen/mod.rs":"2dc3ee7f18177b2ef9c27c4f0cabc5bbd49f970abdba28a0539d81c70d81b6e2","src/codegen/outer_from_impl.rs":"41f5b6b4fb9185f88eaab3fbeed8b07e5791d04f265ee3c77e874a869fac7e1a","src/codegen/trait_impl.rs":"94c6f8a190ab2957ddae55745184e056ec5e43e9c552f492a3cb2f387dfb4a6a","src/codegen/variant.rs":"69ee861a63e31feb158611e93d0a355fdd94d6c8f3adc6c550864b7f5906d0ba","src/codegen/variant_data.rs":"bf17078e1bfeb35fae88b6ba124d730a27028ab75a422b247bbe09022c5f84d1","src/derive.rs":"89180c13798b61510a6d266781e065114b75ca0be27e172a24656347b9baf1d3","src/error/kind.rs":"877f025ff72839ede46b8c7460331dac32ec56a7539816820179110381f8d0fb","src/error/mod.rs":"a440321a7d7d76ecdbd100a8a4ac94d231fdf4e58a8758d09c115d6d7e297601","src/from_derive_input.rs":"b2a04fefa4e14684061c819387ea0384297c67c7f50d5d0959aa69ab19075e76","src/from_field.rs":"f667924422ab4ab8d8b16ebfd42f61e74864cfaa80e96b49de5d1e1287e3d1d3","src/from_generic_param.rs":"49c5a8335eb0a9010998c5600c95c89440f7febe03265afb625d818dbc883d92","src/from_generics.rs":"7285b0fd213507e87c1da413cd1bc9eeada485d4a8f9d19630848d02a4d41c4a","src/from_meta.rs":"11cd84155ab7ac2f20eb5eb6b297be3606871bf5ee10fa529cbb6e370fe9ab68","src/from_type_param.rs":"9b611f276871002ade78146266fde3b6f9101b360082681a2fa2dafc16431f84","src/from_variant.rs":"70a23b5b4cb93c7e5a498fe9d16420b9b93bd69c1376d7703bc7cefd9417d159","src/lib.rs":"337ce983fd49548c60bc0d8662f6d279daec1964c79b123453340158d55d39ab","src/macros_private.rs":"ef249cd9ca593aac423b4242df1c39c31610438da094c21562d74a7e5823c700","src/macros_public.rs":"3ed7eb99f309d9cd600d3a09ff4dcf5cc5d787fb49e8e5ead6bb00e31e5e6793","src/options/core.rs":"02659124b387437daf3b7d6c841a07478dc39a5a626e8ac4b7703e48c6675f6d","src/options/forward_attrs.rs":"a8bb729d8096dd467f23d55c5b4f09e1b8f329181b7d63c75b10fb51518277fd","src/options/from_derive.rs":"e3e13549d327169a64e831612c370662d09465e11690a3e8a6d029591dba3c8b","src/options/from_field.rs":"67f338df3ffc270b3baf08b35cbe985802a65c1360c4e540cc5b937f6f08f915","src/options/from_meta.rs":"81a2ae765d390f64fbcbb1d30d40e895d77f8cd4f4c5f7167b1eacb48e066195","src/options/from_type_param.rs":"d3c8add6c8f5f7ee3d4a487c53e1f85002a2da43b943c03d4ce856fa6e7c8453","src/options/from_variant.rs":"6b2d0b37c9f66ff59b2ac74c51bc7c968a44c2f4812baf428ed2f6801a474704","src/options/input_field.rs":"6e09c3432c63130a7def5cd1c4ba2d9ae2f692e58f82224e96f1212f09d2adb5","src/options/input_variant.rs":"94050b9185838296b7eb6ffacf41472cbff63461162b0005ca07c9a792c749ac","src/options/mod.rs":"8fe5c94c3999d210cb024c6f6b181da92a0cc1a4a862e5d46ec49904c6692e11","src/options/outer_from.rs":"648e3005f19b38299284df954b371fba9cea2fab39a6cfd6b54b5437b4200599","src/options/shape.rs":"03ca937d0c158e96337731517b8cfbc839f536e691f2f31713222bd228b49e07","src/usage/generics_ext.rs":"340774fe43033680e6b494c76dd4f558ada7ca4f09e91f9e4d076f125a729fc2","src/usage/ident_set.rs":"30edb2f0a599284967e3c6b579da31e5f9b15f3dd67bc9a82d6335eb44133df0","src/usage/lifetimes.rs":"35546bd524c38cbae2366e59ac2d836fe09af8e59aa99c7992d1e4d725364db7","src/usage/mod.rs":"e49adadfa8ffed27299d5bbf3c33e68e2c8c7411f89aef655f77e158be9dd642","src/usage/options.rs":"0491c995aad0d55783b24cce8a4e40f0f4435988c54ce2ded34763ac9b199fcf","src/usage/type_params.rs":"c46323838a5e1e87a1a75878314a8b1217e8d63d27a5067961c3b908842d248b","src/util/ident_string.rs":"2b7fdbe9664c2e306114ffa830fde9710d849a0240029636cbb244457795b13f","src/util/ignored.rs":"7c979fbef880498ff64efda7396e759d80bf77fb1c7df0313bed8e533a16c0e0","src/util/mod.rs":"9d8fef190513b6ab675a6ea3cf7e2841d2204fd38d8d55b10cc915d583491982","src/util/over_ride.rs":"5750d284d46c6a51522e908b642c8f09cd6e48c91fd25077f24ce75989525560","src/util/path_list.rs":"4d14eef07b6e3a3e69a539c49b3f25d477e79bd55594cd7324fda3b86784b0f5","src/util/spanned_value.rs":"3938cfc5169237cde1f19d65b653e1da8699663d1abfcf005359d48bbcee7d0b","src/util/with_original.rs":"a545b38ba9d624fdc939eb844f001b7fc4102717b1d3683b4cbd0aae00fa7ef2"},"package":"ee54512bec54b41cf2337a22ddfadb53c7d4c738494dc2a186d7b037ad683b85"}
\ 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..c457f1eaa7 --- /dev/null +++ b/third_party/rust/darling_core/Cargo.toml @@ -0,0 +1,42 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "darling_core" +version = "0.10.1" +authors = ["Ted Driggs <ted.driggs@outlook.com>"] +description = "Helper crate for proc-macro library for reading attributes into structs when\nimplementing custom derives. Use https://crates.io/crates/darling in your code.\n" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" +[dependencies.fnv] +version = "1.0.6" + +[dependencies.ident_case] +version = "1.0.0" + +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" + +[dependencies.strsim] +version = "0.9.0" +optional = true + +[dependencies.syn] +version = "1" +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..a0c765c56f --- /dev/null +++ b/third_party/rust/darling_core/src/ast/data.rs @@ -0,0 +1,360 @@ +use std::{slice, vec}; + +use syn; + +use usage::{ + self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams, +}; +use {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. + 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(_) => unreachable!(), + } + } + + /// Creates a new `Data<&'a V, &'a F>` instance from `Data<V, F>`. + pub fn as_ref<'a>(&'a self) -> Data<&'a V, &'a 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 items = Vec::with_capacity(data.variants.len()); + let mut errors = Vec::new(); + for v_result in data.variants.iter().map(FromVariant::from_variant) { + match v_result { + Ok(val) => items.push(val), + Err(err) => errors.push(err), + } + } + + if !errors.is_empty() { + Err(Error::multiple(errors)) + } else { + Ok(Data::Enum(items)) + } + } + syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)), + syn::Data::Union(_) => unreachable!(), + } + } +} + +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, PartialEq, Eq)] +pub struct Fields<T> { + pub style: Style, + pub fields: Vec<T>, +} + +impl<T> Fields<T> { + pub fn empty_from(vd: &syn::Fields) -> Self { + Fields { + style: vd.into(), + fields: 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<'a>(&'a self) -> Fields<&'a T> { + Fields { + style: self.style, + fields: self.fields.iter().collect(), + } + } + + 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(), + } + } + + 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 (items, errors) = match *fields { + syn::Fields::Named(ref fields) => { + let mut items = Vec::with_capacity(fields.named.len()); + let mut errors = Vec::new(); + + for field in &fields.named { + match FromField::from_field(field) { + Ok(val) => items.push(val), + Err(err) => errors.push(if let Some(ref ident) = field.ident { + err.at(ident) + } else { + err + }), + } + } + + (items, errors) + } + syn::Fields::Unnamed(ref fields) => { + let mut items = Vec::with_capacity(fields.unnamed.len()); + let mut errors = Vec::new(); + + for field in &fields.unnamed { + match FromField::from_field(field) { + Ok(val) => items.push(val), + Err(err) => errors.push(if let Some(ref ident) = field.ident { + err.at(ident) + } else { + err + }), + } + } + + (items, errors) + } + syn::Fields::Unit => (vec![], vec![]), + }; + + if !errors.is_empty() { + Err(Error::multiple(errors)) + } else { + Ok(Fields { + style: fields.into(), + fields: items, + }) + } + } +} + +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 { + Fields { + style, + fields: 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 { + style: self, + fields: 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, + } + } +} 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..2619993036 --- /dev/null +++ b/third_party/rust/darling_core/src/ast/generics.rs @@ -0,0 +1,194 @@ +//! Types for working with generics + +use std::iter::Iterator; +use std::slice::Iter; + +use syn; + +use {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<'a>(&'a self) -> TypeParams<'a, 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 syn; + + use super::{GenericParam, Generics}; + use 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..6d128bd97b --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/attr_extractor.rs @@ -0,0 +1,110 @@ +use proc_macro2::TokenStream; + +use options::ForwardAttrs; +use 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; + + /// A set of immutable declarations for all members of the implementing type. + /// This is used in the case where a deriving struct handles no attributes and therefore can + /// never change its default state. + fn immutable_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; + + /// Gets the core from-meta-item loop that should be used on matching attributes. + fn core_loop(&self) -> TokenStream; + + fn declarations(&self) -> TokenStream { + if !self.attr_names().is_empty() { + self.local_declarations() + } else { + self.immutable_declarations() + } + } + + /// Generates the main extraction loop. + fn extractor(&self) -> TokenStream { + let declarations = self.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 input = self.param_name(); + + // 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)|* => { + if let ::darling::export::Ok(::syn::Meta::List(ref __data)) = __attr.parse_meta() { + let __items = &__data.nested; + + #core_loop + } else { + // darling currently only supports list-style + continue + } + } + ) + } 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 &#input.attrs { + // 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..3bafca09d7 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/default_expr.rs @@ -0,0 +1,46 @@ +use proc_macro2::TokenStream; +use quote::{TokenStreamExt, ToTokens}; +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..bfa18d2d33 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/error.rs @@ -0,0 +1,48 @@ +use proc_macro2::TokenStream; +use quote::{TokenStreamExt, ToTokens}; + +/// 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::export::Vec::new(); + }) + } +} + +/// 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!(.at(#s)) + } else { + quote!() + }; + + tokens.append_all(quote! { + if !__errors.is_empty() { + return ::darling::export::Err(::darling::Error::multiple(__errors) #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..ae32f88d5c --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/field.rs @@ -0,0 +1,206 @@ +use std::borrow::Cow; + +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; +use syn::{Ident, Path, Type}; + +use codegen::DefaultExpression; +use 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 map: Option<&'a Path>, + 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, !self.skip) + } + + 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>, bool); + +impl<'a> Declaration<'a> { + /// Creates a new declaration with the given field and mutability. + pub fn new(field: &'a Field<'a>, mutable: bool) -> Self { + Declaration(field, mutable) + } +} + +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; + + let mutable = if self.1 { quote!(mut) } else { quote!() }; + + tokens.append_all(if field.multiple { + // This is NOT mutable, as it will be declared mutable only temporarily. + quote!(let #mutable #ident: #ty = ::darling::export::Default::default();) + } else { + quote!(let #mutable #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; + + // 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 mut extractor = + quote!(#with_path(__inner).map_err(|e| e.with_span(&__inner).at(#location))); + if let Some(ref map) = field.map { + extractor = quote!(#extractor.map(#map)) + } + + 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(); + match #extractor { + ::darling::export::Ok(__val) => { + #ident.push(__val) + } + ::darling::export::Err(__err) => { + __errors.push(__err) + } + } + } + ) + } else { + quote!( + #name_str => { + if !#ident.0 { + match #extractor { + ::darling::export::Ok(__val) => { + #ident = (true, ::darling::export::Some(__val)); + } + ::darling::export::Err(__err) => { + #ident = (true, None); + __errors.push(__err); + } + } + } 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 name_in_attr = &self.0.name_in_attr; + + tokens.append_all(quote! { + if !#ident.0 { + __errors.push(::darling::Error::missing_field(#name_in_attr)); + } + }) + } + } +} 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..2c0a3a162b --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_derive_impl.rs @@ -0,0 +1,146 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{self, Ident}; + +use ast::Data; +use codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}; +use options::{ForwardAttrs, Shape}; +use 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 map = self.base.map_fn(); + + 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)?) + ) #map + } + }, + 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 + __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 + }) #map + } + }, + 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() + } + + fn immutable_declarations(&self) -> TokenStream { + self.base.immutable_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..b714211871 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_field.rs @@ -0,0 +1,115 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{self, Ident}; + +use codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}; +use options::ForwardAttrs; +use 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 map = self.base.map_fn(); + + 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 + }) #map + + } + }, + 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() + } + + fn immutable_declarations(&self) -> TokenStream { + self.base.immutable_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..dbc5056e6d --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_meta_impl.rs @@ -0,0 +1,136 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn; + +use ast::{Data, Fields, Style}; +use 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 map = base.map_fn(); + + 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),* + }) #map + } + ) + } + 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 __nested.path().segments.iter().map(|s| s.ident.to_string()).collect::<Vec<String>>().join("::").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..4936378dfb --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_type_param.rs @@ -0,0 +1,114 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{self, Ident}; + +use codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}; +use options::ForwardAttrs; +use 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 map = self.base.map_fn(); + + 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 + }) #map + } + }, + 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() + } + + fn immutable_declarations(&self) -> TokenStream { + self.base.immutable_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..bbe5a9a12e --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/from_variant_impl.rs @@ -0,0 +1,118 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{self, Ident}; + +use codegen::{ExtractAttribute, OuterFromImpl, TraitImpl}; +use options::{DataShape, ForwardAttrs}; +use util::PathList; + +pub struct FromVariantImpl<'a> { + pub base: TraitImpl<'a>, + pub ident: Option<&'a Ident>, + pub fields: Option<&'a Ident>, + pub attrs: 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_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 map = self.base.map_fn(); + + 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 + __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_attrs + #passed_fields + #inits + }) #map + } + ), + tokens, + ); + } +} + +impl<'a> ExtractAttribute for FromVariantImpl<'a> { + fn local_declarations(&self) -> TokenStream { + self.base.local_declarations() + } + + fn immutable_declarations(&self) -> TokenStream { + self.base.immutable_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..40b8d68a75 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/mod.rs @@ -0,0 +1,29 @@ + +mod attr_extractor; +mod default_expr; +mod error; +mod field; +mod from_meta_impl; +mod from_derive_impl; +mod from_field; +mod from_type_param; +mod from_variant_impl; +mod outer_from_impl; +mod trait_impl; +mod variant; +mod variant_data; + +pub(in codegen) use self::attr_extractor::ExtractAttribute; +pub use self::default_expr::DefaultExpression; +pub use self::field::Field; +pub use self::from_meta_impl::FromMetaImpl; +pub use self::from_derive_impl::FromDeriveInputImpl; +pub use self::from_field::FromFieldImpl; +pub use self::from_type_param::FromTypeParamImpl; +pub use self::from_variant_impl::FromVariantImpl; +pub use self::outer_from_impl::OuterFromImpl; +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..e99c4e1526 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/outer_from_impl.rs @@ -0,0 +1,60 @@ +use proc_macro2::TokenStream; +use quote::{TokenStreamExt, ToTokens}; +use syn::{GenericParam, Generics, Path, TraitBound, TraitBoundModifier, TypeParamBound}; + +use codegen::TraitImpl; +use 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/trait_impl.rs b/third_party/rust/darling_core/src/codegen/trait_impl.rs new file mode 100644 index 0000000000..2f4f4aec63 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/trait_impl.rs @@ -0,0 +1,145 @@ +use proc_macro2::TokenStream; +use syn::{Generics, Ident, Path, WherePredicate}; + +use ast::{Data, Fields}; +use codegen::error::{ErrorCheck, ErrorDeclaration}; +use codegen::field; +use codegen::{DefaultExpression, Field, FieldsGen, Variant}; +use 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 map: Option<&'a Path>, + 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<'b, F, V>(&'b 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 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!() + } + } + + /// Generate immutable variable declarations for all fields. + pub(in codegen) fn immutable_declarations(&self) -> TokenStream { + if let Data::Struct(ref vd) = self.data { + let vdr = vd.as_ref().map(|f| field::Declaration::new(f, false)); + let decls = vdr.fields.as_slice(); + quote!(#(#decls)*) + } else { + quote!() + } + } + + pub(in codegen) fn map_fn(&self) -> Option<TokenStream> { + self.map.as_ref().map(|path| quote!(.map(#path))) + } + + /// Generate local variable declaration and initialization for instance from which missing fields will be taken. + pub(in 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 codegen) fn initializers(&self) -> TokenStream { + self.make_field_ctx().initializers() + } + + /// Generate the loop which walks meta items looking for property matches. + pub(in 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..e982a2e815 --- /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 ast::Fields; +use codegen::error::{ErrorCheck, ErrorDeclaration}; +use codegen::{Field, FieldsGen}; +use 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..392242b266 --- /dev/null +++ b/third_party/rust/darling_core/src/codegen/variant_data.rs @@ -0,0 +1,91 @@ +use proc_macro2::TokenStream; + +use ast::Fields; +use ast::Style; +use 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 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 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 { + if let ::syn::NestedMeta::Meta(ref __inner) = *__item { + let __name = __inner.path().segments.iter().map(|s| s.ident.to_string()).collect::<Vec<String>>().join("::"); + match __name.as_str() { + #(#arms)* + __other => { #handle_unknown } + } + } + } + ) + } + + 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 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..92dce8e1a9 --- /dev/null +++ b/third_party/rust/darling_core/src/derive.rs @@ -0,0 +1,54 @@ +//! 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 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::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..92d4afeb37 --- /dev/null +++ b/third_party/rust/darling_core/src/error/kind.rs @@ -0,0 +1,201 @@ +use std::fmt; + +use error::Error; + +type DeriveInputShape = String; +type FieldName = String; +type MetaFormat = String; + +#[derive(Debug)] +// Don't want to publicly commit to ErrorKind supporting equality yet, but +// not having it makes testing very difficult. +#[cfg_attr(test, derive(Clone, PartialEq, Eq))] +pub(in 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(Debug)] +// Don't want to publicly commit to ErrorKind supporting equality yet, but +// not having it makes testing very difficult. +#[cfg_attr(test, derive(Clone, PartialEq, Eq))] +pub(in 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 to_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())); + } + } + match candidate { + None => None, + Some((_, candidate)) => Some(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..28102a8aca --- /dev/null +++ b/third_party/rust/darling_core/src/error/mod.rs @@ -0,0 +1,520 @@ +//! The `darling::Error` type and its 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 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. +#[derive(Debug)] +#[cfg_attr(test, derive(Clone))] +pub struct Error { + kind: ErrorKind, + locations: Vec<String>, + /// The span to highlight in the emitted diagnostic. + span: Option<Span>, +} + +/// Transform a syn::Path to a readable String +fn path_to_string(path: &syn::Path) -> String { + path.segments.iter().map(|s| s.ident.to_string()).collect::<Vec<String>>().join("::") +} + +/// Error creation functions +impl Error { + pub(in 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. + /// + /// # Panics + /// This function will panic if `errors.is_empty() == true`. + pub fn multiple(mut errors: Vec<Error>) -> Self { + if errors.len() > 1 { + Error::new(ErrorKind::Multiple(errors)) + } else if errors.len() == 1 { + errors + .pop() + .expect("Error array of length 1 has a first item") + } else { + panic!("Can't deal with 0 errors") + } + } +} + +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 +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 + } + + /// 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"))] + { + self.flatten() + .into_iter() + .map(|e| e.single_to_syn_error().to_compile_error()) + .collect() + } + } + + #[cfg(not(feature = "diagnostics"))] + fn single_to_syn_error(self) -> ::syn::Error { + match self.span { + Some(span) => ::syn::Error::new(span, self.kind), + None => ::syn::Error::new(Span::call_site(), self), + } + } + + #[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.to_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<&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(()) + } +} + +// 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() + } +} + +#[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()); + } +} 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..740dd08284 --- /dev/null +++ b/third_party/rust/darling_core/src/from_derive_input.rs @@ -0,0 +1,26 @@ +use syn::DeriveInput; + +use 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..074bdc07af --- /dev/null +++ b/third_party/rust/darling_core/src/from_field.rs @@ -0,0 +1,38 @@ +use syn::{self, Field}; + +use 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..168600c4c4 --- /dev/null +++ b/third_party/rust/darling_core/src/from_generic_param.rs @@ -0,0 +1,21 @@ +use syn; + +use 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..eb6e5c97e0 --- /dev/null +++ b/third_party/rust/darling_core/src/from_generics.rs @@ -0,0 +1,27 @@ +use syn::Generics; + +use 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..5c805393b5 --- /dev/null +++ b/third_party/rust/darling_core/src/from_meta.rs @@ -0,0 +1,500 @@ +use std::cell::RefCell; +use std::collections::hash_map::{Entry, HashMap}; +use std::hash::BuildHasher; +use std::rc::Rc; +use std::sync::atomic::AtomicBool; +use std::sync::Arc; + +use ident_case; +use syn::{self, Lit, Meta, NestedMeta}; + +use {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"`. +/// +/// ## 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)) + } + + /// 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()), + _ => 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) + } + + 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 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 identifiers. This attempts to preserve span information +/// when available, but also supports parsing strings with the call site as the +/// emitted span. +impl FromMeta for syn::Ident { + fn from_string(value: &str) -> Result<Self> { + Ok(syn::Ident::new(value, ::proc_macro2::Span::call_site())) + } + + fn from_value(value: &Lit) -> Result<Self> { + if let Lit::Str(ref ident) = *value { + ident + .parse() + .map_err(|_| Error::unknown_lit_str_value(ident)) + } else { + Err(Error::unexpected_lit_type(value)) + } + } +} + +/// Parsing support for paths. This attempts to preserve span information when available, +/// but also supports parsing strings with the call site as the emitted span. +impl FromMeta for syn::Path { + fn from_string(value: &str) -> Result<Self> { + syn::parse_str(value).map_err(|_| Error::unknown_value(value)) + } + + fn from_value(value: &Lit) -> Result<Self> { + if let Lit::Str(ref path_str) = *value { + path_str + .parse() + .map_err(|_| Error::unknown_lit_str_value(path_str)) + } else { + Err(Error::unexpected_lit_type(value)) + } + } +} + +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 syn::WhereClause { + fn from_string(value: &str) -> Result<Self> { + syn::parse_str(value).map_err(|_| Error::unknown_value(value)) + } +} + +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()) + } +} + +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_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(Some) + } +} + +impl<T: FromMeta> FromMeta for Box<T> { + fn from_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(Box::new) + } +} + +impl<T: FromMeta> FromMeta for Result<T> { + 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_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(Rc::new) + } +} + +impl<T: FromMeta> FromMeta for Arc<T> { + fn from_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(Arc::new) + } +} + +impl<T: FromMeta> FromMeta for RefCell<T> { + fn from_meta(item: &Meta) -> Result<Self> { + FromMeta::from_meta(item).map(RefCell::new) + } +} + +impl<V: FromMeta, S: BuildHasher + Default> FromMeta for HashMap<String, V, S> { + fn from_list(nested: &[syn::NestedMeta]) -> Result<Self> { + let mut map = HashMap::with_capacity_and_hasher(nested.len(), Default::default()); + for item in nested { + if let syn::NestedMeta::Meta(ref inner) = *item { + let path = inner.path(); + let name = path.segments.iter().map(|s| s.ident.to_string()).collect::<Vec<String>>().join("::"); + match map.entry(name) { + Entry::Occupied(_) => { + return Err( + Error::duplicate_field_path(&path).with_span(inner) + ); + } + Entry::Vacant(entry) => { + // In the error case, extend the error's path, but assume the inner `from_meta` + // set the span, and that subsequently we don't have to. + entry.insert(FromMeta::from_meta(inner).map_err(|e| e.at_path(&path))?); + } + } + } + } + + Ok(map) + } +} + +/// 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 syn; + + use {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() { + assert_eq!(fm::<()>(quote!(ignore)), ()); + } + + #[test] + 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 string_succeeds() { + // cooked form + assert_eq!(&fm::<String>(quote!(ignore = "world")), "world"); + + // raw form + assert_eq!(&fm::<String>(quote!(ignore = r#"world"#)), "world"); + } + + #[test] + 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] + 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()); + } + + /// 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(); + } +} 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..cc9c5dac00 --- /dev/null +++ b/third_party/rust/darling_core/src/from_type_param.rs @@ -0,0 +1,32 @@ +use syn::{self, TypeParam}; + +use 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..d4dd5f2ac9 --- /dev/null +++ b/third_party/rust/darling_core/src/from_variant.rs @@ -0,0 +1,33 @@ +use syn::{self, Variant}; + +use 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..6ce361b481 --- /dev/null +++ b/third_party/rust/darling_core/src/lib.rs @@ -0,0 +1,47 @@ +#![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_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 error::{Error, Result}; +pub use from_derive_input::FromDeriveInput; +pub use from_field::FromField; +pub use from_generic_param::FromGenericParam; +pub use from_generics::FromGenerics; +pub use from_meta::FromMeta; +pub use from_type_param::FromTypeParam; +pub use 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..a3c5cac98d --- /dev/null +++ b/third_party/rust/darling_core/src/macros_public.rs @@ -0,0 +1,98 @@ +//! 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; +/// # +/// # #[macro_use] +/// # extern crate darling_core; +/// # +/// 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..2e59071a99 --- /dev/null +++ b/third_party/rust/darling_core/src/options/core.rs @@ -0,0 +1,154 @@ +use ident_case::RenameRule; +use syn; + +use ast::{Data, Fields, Style}; +use codegen; +use options::{DefaultExpression, InputField, InputVariant, ParseAttribute, ParseData}; +use util::Flag; +use {Error, FromMeta, Result}; + +/// A struct or enum which should have `FromMeta` or `FromDeriveInput` implementations +/// generated. +#[derive(Debug, Clone, PartialEq, Eq)] +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, + + /// An infallible function with the signature `FnOnce(T) -> T` which will be called after the + /// target instance is successfully constructed. + pub map: Option<syn::Path>, + + /// 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: Flag, +} + +impl Core { + /// Partially initializes `Core` by reading the identity, generics, and body shape. + pub fn start(di: &syn::DeriveInput) -> Self { + Core { + ident: di.ident.clone(), + generics: di.generics.clone(), + data: Data::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() + }, + map: Default::default(), + bound: Default::default(), + allow_unknown_fields: Default::default(), + } + } + + fn as_codegen_default<'a>(&'a self) -> Option<codegen::DefaultExpression<'a>> { + 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") { + if self.map.is_some() { + return Err(Error::duplicate_field("map").with_span(mi)) + } + + self.map = 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(), + map: v.map.as_ref(), + bound: v.bound.as_ref().map(|i| i.as_slice()), + allow_unknown_fields: v.allow_unknown_fields.into(), + } + } +} 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..eccdb78102 --- /dev/null +++ b/third_party/rust/darling_core/src/options/forward_attrs.rs @@ -0,0 +1,31 @@ +use syn::NestedMeta; + +use util::PathList; +use {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_derive.rs b/third_party/rust/darling_core/src/options/from_derive.rs new file mode 100644 index 0000000000..6c252e68a4 --- /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::{self, Ident}; + +use codegen::FromDeriveInputImpl; +use options::{OuterFrom, ParseAttribute, ParseData, Shape}; +use {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..266d1fa043 --- /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::{self, Ident}; + +use codegen::FromFieldImpl; +use options::{OuterFrom, ParseAttribute, ParseData}; +use 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..d9088562a5 --- /dev/null +++ b/third_party/rust/darling_core/src/options/from_meta.rs @@ -0,0 +1,51 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn; + +use codegen::FromMetaImpl; +use options::{Core, ParseAttribute, ParseData}; +use 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..701ca1b83e --- /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::{self, Ident}; + +use codegen::FromTypeParamImpl; +use options::{OuterFrom, ParseAttribute, ParseData}; +use 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..c5ffe5d0e3 --- /dev/null +++ b/third_party/rust/darling_core/src/options/from_variant.rs @@ -0,0 +1,76 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{DeriveInput, Field, Ident, Meta}; + +use codegen::FromVariantImpl; +use options::{DataShape, OuterFrom, ParseAttribute, ParseData}; +use {FromMeta, Result}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FromVariantOptions { + pub base: OuterFrom, + pub fields: Option<Ident>, + pub supports: Option<DataShape>, +} + +impl FromVariantOptions { + pub fn new(di: &DeriveInput) -> Result<Self> { + (FromVariantOptions { + base: OuterFrom::start(di), + 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(), + 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("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..1b1905a6f3 --- /dev/null +++ b/third_party/rust/darling_core/src/options/input_field.rs @@ -0,0 +1,138 @@ +use std::borrow::Cow; + +use syn; + +use codegen; +use options::{Core, DefaultExpression, ParseAttribute}; +use {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: bool, + pub map: Option<syn::Path>, + pub multiple: bool, +} + +impl InputField { + /// Generate a view into this field that can be used for code generation. + pub fn as_codegen_field<'a>(&'a self) -> codegen::Field<'a> { + 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, + map: self.map.as_ref(), + multiple: self.multiple, + } + } + + /// Generate a codegen::DefaultExpression for this field. This requires the field name + /// in the `Inherit` case. + fn as_codegen_default<'a>(&'a self) -> Option<codegen::DefaultExpression<'a>> { + 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: false, + map: Default::default(), + multiple: false, + } + } + + 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)?; + + if let Some(container) = parent { + base.with_inherited(container) + } else { + Ok(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) -> Result<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, 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, + }; + + Ok(self) + } +} + +impl ParseAttribute for InputField { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + let path = mi.path(); + + if path.is_ident("rename") { + self.attr_name = FromMeta::from_meta(mi)?; + } else if path.is_ident("default") { + self.default = FromMeta::from_meta(mi)?; + } else if path.is_ident("with") { + self.with = Some(FromMeta::from_meta(mi)?); + } else if path.is_ident("skip") { + self.skip = FromMeta::from_meta(mi)?; + } else if path.is_ident("map") { + self.map = Some(FromMeta::from_meta(mi)?); + } else if path.is_ident("multiple") { + 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..08398fe687 --- /dev/null +++ b/third_party/rust/darling_core/src/options/input_variant.rs @@ -0,0 +1,98 @@ +use std::borrow::Cow; + +use syn; + +use ast::Fields; +use codegen; +use options::{Core, InputField, ParseAttribute}; +use {Error, FromMeta, Result}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InputVariant { + ident: syn::Ident, + attr_name: Option<String>, + data: Fields<InputField>, + skip: 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, + 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.is_some()); + } + + self + } +} + +impl ParseAttribute for InputVariant { + fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { + let path = mi.path(); + if path.is_ident("rename") { + self.attr_name = FromMeta::from_meta(mi)?; + Ok(()) + } else if path.is_ident("skip") { + self.skip = FromMeta::from_meta(mi)?; + Ok(()) + } else { + Err(Error::unknown_field_path(&path).with_span(mi)) + } + } +} 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..a884f5afba --- /dev/null +++ b/third_party/rust/darling_core/src/options/mod.rs @@ -0,0 +1,154 @@ +use syn; + +use {Error, FromMeta, Result}; + +mod core; +mod forward_attrs; +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_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) + } +} + +/// Run a parsing task, and if it produces an error push it into `$errors` +macro_rules! collect_error { + ($errors:ident, $task:expr) => { + if let Err(e) = $task { + $errors.push(e); + } + }; +} + +/// 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 = Vec::new(); + for attr in attrs { + if attr.path == parse_quote!(darling) { + collect_error!(errors, parse_attr(attr, &mut self)); + } + } + + if !errors.is_empty() { + Err(Error::multiple(errors)) + } else { + Ok(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 = Vec::new(); + match attr.parse_meta().ok() { + Some(syn::Meta::List(data)) => { + for item in data.nested { + if let syn::NestedMeta::Meta(ref mi) = item { + collect_error!(errors, target.parse_nested(mi)); + } else { + panic!("Wasn't able to parse: `{:?}`", item); + } + } + + if !errors.is_empty() { + Err(Error::multiple(errors)) + } else { + Ok(()) + } + } + 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 = Vec::new(); + + match *body { + Data::Struct(ref data) => match data.fields { + Fields::Unit => {} + Fields::Named(ref fields) => { + for field in &fields.named { + collect_error!(errors, self.parse_field(field)); + } + } + Fields::Unnamed(ref fields) => { + for field in &fields.unnamed { + collect_error!(errors, self.parse_field(field)); + } + } + }, + Data::Enum(ref data) => { + for variant in &data.variants { + collect_error!(errors, self.parse_variant(variant)); + } + } + Data::Union(_) => unreachable!(), + }; + + if !errors.is_empty() { + Err(Error::multiple(errors)) + } else { + Ok(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..ca8f1de684 --- /dev/null +++ b/third_party/rust/darling_core/src/options/outer_from.rs @@ -0,0 +1,82 @@ +use syn::{self, Field, Ident, Meta}; + +use options::{Core, DefaultExpression, ForwardAttrs, ParseAttribute, ParseData}; +use util::PathList; +use {FromMeta, Result}; + +/// Reusable base for `FromDeriveInput`, `FromVariant`, `FromField`, and other top-level +/// `From*` traits. +#[derive(Debug, Clone, PartialEq, Eq)] +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) -> Self { + 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..4cb3f7a9ed --- /dev/null +++ b/third_party/rust/darling_core/src/options/shape.rs @@ -0,0 +1,268 @@ +//! 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 {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; + quote! { + match *__body { + ::syn::Data::Enum(ref data) => { + fn validate_variant(data: &::syn::Fields) -> ::darling::Result<()> { + #en + } + + for variant in &data.variants { + validate_variant(&variant.fields)?; + } + + Ok(()) + } + ::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_left_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 = Vec::new(); + let mut new = DataShape::default(); + + for item in items { + if let NestedMeta::Meta(Meta::Path(ref path)) = *item { + if let Err(e) = new.set_word(&path.segments.first().unwrap().ident.to_string()) { + errors.push(e.with_span(&path)); + } + } else { + errors.push(Error::unsupported_format("non-word").with_span(item)); + } + } + + if !errors.is_empty() { + Err(Error::multiple(errors)) + } else { + Ok(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_right_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 syn; + + use super::Shape; + use 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().or(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_eq!(decl.any, true); + } + + #[test] + fn supports_struct() { + let decl = fm::<Shape>(quote!(ignore(struct_any, struct_newtype))); + assert_eq!(decl.struct_values.any, true); + assert_eq!(decl.struct_values.newtype, true); + } + + #[test] + fn supports_mixed() { + let decl = fm::<Shape>(quote!(ignore(struct_newtype, enum_newtype, enum_tuple))); + assert_eq!(decl.struct_values.newtype, true); + assert_eq!(decl.enum_values.newtype, true); + assert_eq!(decl.enum_values.tuple, true); + assert_eq!(decl.struct_values.any, false); + } +} 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..82af2f5762 --- /dev/null +++ b/third_party/rust/darling_core/src/usage/generics_ext.rs @@ -0,0 +1,24 @@ +use syn::Generics; + +use 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..ef76bc6798 --- /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::{self, Lifetime, Type}; + +use 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::{self, DeriveInput}; + + use super::UsesLifetimes; + use usage::GenericsExt; + use 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..770f4954fb --- /dev/null +++ b/third_party/rust/darling_core/src/usage/type_params.rs @@ -0,0 +1,357 @@ +use syn::punctuated::Punctuated; +use syn::{self, Ident, Type}; + +use 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 usage::IdentSet; + use 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/ident_string.rs b/third_party/rust/darling_core/src/util/ident_string.rs new file mode 100644 index 0000000000..293610e2f6 --- /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 {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..9347fb4331 --- /dev/null +++ b/third_party/rust/darling_core/src/util/ignored.rs @@ -0,0 +1,52 @@ +use syn; + +use usage::{self, UsesLifetimes, UsesTypeParams}; +use { + 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..1058381cdc --- /dev/null +++ b/third_party/rust/darling_core/src/util/mod.rs @@ -0,0 +1,112 @@ +//! Utility types for attribute parsing. + +use std::ops::{BitAnd, BitOr, Deref, Not}; + +use syn; +use {FromMeta, Result}; + +mod ident_string; +mod ignored; +mod over_ride; +mod path_list; +mod with_original; +mod spanned_value; + +pub use self::ident_string::IdentString; +pub use self::ignored::Ignored; +pub use self::over_ride::Override; +pub use self::path_list::PathList; +pub use self::spanned_value::SpannedValue; +pub use self::with_original::WithOriginal; + +/// Marker type equivalent to `Option<()>` for use in attribute parsing. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct Flag(Option<()>); + +impl Flag { + /// Creates a new `Flag` which corresponds to the presence of a value. + pub fn present() -> Self { + Flag(Some(())) + } +} + +impl Deref for Flag { + type Target = Option<()>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl FromMeta for Flag { + fn from_meta(mi: &syn::Meta) -> Result<Self> { + FromMeta::from_meta(mi).map(Flag) + } +} + +impl From<Flag> for bool { + fn from(flag: Flag) -> Self { + flag.is_some() + } +} + +impl From<bool> for Flag { + fn from(v: bool) -> Self { + if v { + Flag::present() + } else { + Flag(None) + } + } +} + +impl From<Option<()>> for Flag { + fn from(v: Option<()>) -> Self { + Flag::from(v.is_some()) + } +} + +impl PartialEq<Option<()>> for Flag { + fn eq(&self, rhs: &Option<()>) -> bool { + self.0 == *rhs + } +} + +impl PartialEq<Flag> for Option<()> { + fn eq(&self, rhs: &Flag) -> bool { + *self == rhs.0 + } +} + +impl PartialEq<bool> for Flag { + fn eq(&self, rhs: &bool) -> bool { + self.is_some() == *rhs + } +} + +impl Not for Flag { + type Output = Self; + + fn not(self) -> Self { + if self.is_some() { + Flag(None) + } else { + Flag::present() + } + } +} + +impl BitAnd for Flag { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self { + (self.into() && rhs.into()).into() + } +} + +impl BitOr for Flag { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + (self.into() || rhs.into()).into() + } +} 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..5223a023d0 --- /dev/null +++ b/third_party/rust/darling_core/src/util/over_ride.rs @@ -0,0 +1,150 @@ +use std::fmt; + +use syn::{Lit, NestedMeta}; + +use {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 +/// # #[macro_use] +/// # extern crate darling; +/// # extern crate syn; +/// use darling::util::Override; +/// #[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<'a>(&'a self) -> Override<&'a 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<'a>(&'a mut self) -> Override<&'a 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/path_list.rs b/third_party/rust/darling_core/src/util/path_list.rs new file mode 100644 index 0000000000..069aa6a177 --- /dev/null +++ b/third_party/rust/darling_core/src/util/path_list.rs @@ -0,0 +1,102 @@ +use std::ops::Deref; +use std::string::ToString; + +use syn::{Meta, NestedMeta, Path}; + +use {Error, FromMeta, Result}; + +/// 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(|p| p.segments.iter().map(|s| s.ident.to_string()).collect::<Vec<String>>().join("::")).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 proc_macro2::TokenStream; + use syn::{Attribute, Meta}; + use FromMeta; + + /// 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/spanned_value.rs b/third_party/rust/darling_core/src/util/spanned_value.rs new file mode 100644 index 0000000000..1ea3dfc703 --- /dev/null +++ b/third_party/rust/darling_core/src/util/spanned_value.rs @@ -0,0 +1,104 @@ +use proc_macro2::Span; +use std::ops::{Deref, DerefMut}; +use syn; +use syn::spanned::Spanned; +use { + 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)] +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 + } +} + +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 + } +} + +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..e53264bb45 --- /dev/null +++ b/third_party/rust/darling_core/src/util/with_original.rs @@ -0,0 +1,35 @@ +use syn; + +use {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..2f56ee886e --- /dev/null +++ b/third_party/rust/darling_macro/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"772583c440b7413dfc8fe74b455978310f5a9b321733c973bdaeb1cd21cfb2ca","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/lib.rs":"88141a58dc13b9001a83ca7559b6213ab44641510b6d642a3280c244ad735cec"},"package":"0cd3e432e52c0810b72898296a69d66b1d78d1517dff6cde7a130557a55a62c1"}
\ 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..61f76a70c3 --- /dev/null +++ b/third_party/rust/darling_macro/Cargo.toml @@ -0,0 +1,30 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "darling_macro" +version = "0.10.1" +authors = ["Ted Driggs <ted.driggs@outlook.com>"] +description = "Internal support for a proc-macro library for reading attributes into structs when\nimplementing custom derives. Use https://crates.io/crates/darling in your code.\n" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" + +[lib] +proc-macro = true +[dependencies.darling_core] +version = "=0.10.1" + +[dependencies.quote] +version = "1" + +[dependencies.syn] +version = "1" 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..629526c553 --- /dev/null +++ b/third_party/rust/darling_macro/src/lib.rs @@ -0,0 +1,41 @@ +extern crate proc_macro; +#[macro_use] +extern crate syn; + +extern crate darling_core; + +use proc_macro::TokenStream; + +use darling_core::{derive, Error}; + +#[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(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() +} |