darling-0.20.10/.cargo_vcs_info.json0000644000000001360000000000100126140ustar { "git": { "sha1": "84448b81b30dcbe5fd5b687c1beda963a98278e6" }, "path_in_vcs": "" }darling-0.20.10/.gitignore000064400000000000000000000001261046102023000133730ustar 00000000000000/target **/target **/*.rs.bk Cargo.lock .vscode .rls.toml .DS_STORE [._]*.sw? [._]sw? darling-0.20.10/CHANGELOG.md000064400000000000000000000353761046102023000132330ustar 00000000000000# Changelog ## v0.20.10 (July 9, 2024) - Add `#[allow(clippy::manual_unwrap_or_default)]` to all generated impls to avoid causing clippy fails in crates using `darling` [#296](https://github.com/TedDriggs/darling/pull/296) - Properly initialize `attrs` magic field in derived `FromAttributes` impls [#297](https://github.com/TedDriggs/darling/pull/297) ## v0.20.9 (May 15, 2024) - Allow word-form for newtype enum variants whose only field produces a value when `from_none` is called on their type [#249](https://github.com/TedDriggs/darling/issues/249) - Add `FromMeta` impls for the `std::num::NonZero*` types [#288](https://github.com/TedDriggs/darling/pull/288) - Fix panic in number `FromMeta` impls when the parsed value is too large for the receiver type [#289](https://github.com/TedDriggs/darling/issues/289) ## v0.20.8 (February 23, 2024) - Add `#[darling(with = ...)]` support to `attrs` magic field to allow using custom receiver types for `attrs` [#273](https://github.com/TedDriggs/darling/issues/273) ## v0.20.7 (February 22, 2024) - Add `#[darling(flatten)]` to allow forwarding unknown fields to another struct [#146](https://github.com/TedDriggs/darling/issues/146) - Don't suggest names of skipped fields in derived impls [#268](https://github.com/TedDriggs/darling/issues/268) ## v0.20.6 (February 14, 2024) - Fix some missing syn invisible group handling in `FromMeta` impls [#263](https://github.com/TedDriggs/darling/pull/263) - Fix misleading error message on `Error::unexpected_type` so it no longer implies the type was a literal [#264](https://github.com/TedDriggs/darling/pull/264) - Impl `FromMeta` `Vec` of literals, e.g. `LitStr` [#265](https://github.com/TedDriggs/pull/265) ## v0.20.5 (January 30, 2024) - Add `Flag::span` inherent method, as `Flag` can no longer impl `syn::spanned::Spanned` [#242](https://github.com/TedDriggs/darling/issues/242) ## v0.20.4 (January 29, 2024) - Accept bare paths in `#[darling(default = ...)]` [#258](https://github.com/TedDriggs/darling/pull/258) - Add `FromMeta` impl for `PathBuf` [#259](https://github.com/TedDriggs/darling/pull/259) - Improve `FromMeta` implementation for enums [#260](https://github.com/TedDriggs/darling/pull/260) - Properly implement unit arms in `FromMeta::from_list` to provide a consistent API for heterogeneous enums that include a mix of unit, newtype and struct variants - Add `#[darling(word)]` attribute for unit enum variants (See [#63](https://github.com/TedDriggs/darling/issues/63) for details) ## v0.20.3 (July 12, 2023) - Add `FromMeta` impl for `u128` and `i128` [#243](https://github.com/TedDriggs/darling/pull/243) ## v0.20.2 (May 25, 2023) - Allow darling users to omit quotation marks for paths and idents [#236](https://github.com/TedDriggs/darling/pull/236) - Add new util functions for controlling how quotation marks are handled when reading into `Expr` fields [#235](https://github.com/TedDriggs/darling/pull/235) ## v0.20.1 (May 2, 2023) - Add `Clone` impl for `NestedMeta` [#230](https://github.com/TedDriggs/darling/pull/230) ## v0.20.0 (April 27, 2023) - Bump syn to version 2, courtesy of @jonasbb [#227](https://github.com/TedDriggs/darling/issues/227) ### Breaking Changes - Replace all occurrences of syn::NestedMeta with darling::ast::NestedMeta. - Replacement for the deprecated AttributeArgs: ```rust // Before parse_macro_input!(args as AttributeArgs); // After match NestedMeta::parse_meta_list(args) { Ok(v) => v, Err(e) => { return TokenStream::from(Error::from(e).write_errors()); } }; ``` - In GenericParamExt, `LifetimeDef` is now `LifetimeParam`. - In GenericParamExt, `as_lifetime_def` is renamed to `as_lifetime_param`. - Flag and SpannedValue no longer implement `syn::spanned::Spanned`. - The MSRV (minimum supported Rust version) is now 1.56, because of syn. ### Deprecation Warnings In previous versions of `darling`, arbitrary expressions were passed in attributes by wrapping them in quotation marks. v0.20.0 preserves this behavior for `syn::Expr`, but as a result a field expecting a `syn::Expr` cannot accept a string literal - it will incorrectly attempt to parse the contents. If this is an issue for you, please add a comment to [#229](https://github.com/TedDriggs/darling/issues/229). ## v0.14.4 (March 9, 2023) - Add support for child diagnostics when `diagnostics` feature enabled [#224](https://github.com/TedDriggs/darling/issues/224) ## v0.14.3 (February 3, 2023) - Re-export `syn` from `darling` to avoid requiring that consuming crates have a `syn` dependency. - Change ` as FromMeta>` impl to more precisely capture the _value_ span, as opposed to the span of the entire item. - Add `darling::util::{AsShape, Shape, ShapeSet}` to improve "shape" validation for structs and variants. [#222](https://github.com/TedDriggs/issues/222) ## v0.14.2 (October 26, 2022) - Derived impls of `FromMeta` will now error on literals, rather than silently ignoring them. [#193](https://github.com/TedDriggs/darling/pull/193) - Don't include property paths in compile errors when spans are available. [#203](https://github.com/TedDriggs/darling/pull/203) ## v0.14.1 (April 28, 2022) - Fix a bug where using a trait that accepts `#[darling(attributes(...))]` without specifying any attributes would emit code that did not compile. [#183](https://github.com/TedDriggs/darling/issues/183) - Impl `Clone` for `darling::Error` [#184](https://github.com/TedDriggs/darling/pull/184) - Impl `From for syn::Error` [#184](https://github.com/TedDriggs/darling/pull/184) - Add `Error::span` and `Error::explicit_span` methods [#184](https://github.com/TedDriggs/darling/pull/184) ## v0.14.0 (April 13, 2022) - **BREAKING CHANGE:** Remove many trait impls from `util::Flag`. This type had a number of deref and operator impls that made it usable as sort-of-a-boolean. Real-world usage showed this type is more useful if it's able to carry a span for good errors, and that most of those impls were unnecessary. [#179](https://github.com/TedDriggs/darling/pull/179) - Remove need for `#[darling(default)]` on `Option` and `Flag` fields [#161](https://github.com/TedDriggs/darling/issues/161) - Improve validation of enum shapes [#178](https://github.com/TedDriggs/darling/pull/178) - Bump `proc-macro2` dependency to 1.0.37 [#180](https://github.com/TedDriggs/darling/pull/180) - Bump `quote` dependency to 1.0.18 [#180](https://github.com/TedDriggs/darling/pull/180) - Bump `syn` dependency to 1.0.91 [#180](https://github.com/TedDriggs/darling/pull/180) ## v0.13.4 (April 6, 2022) - Impl `FromMeta` for `syn::Visibility` [#173](https://github.com/TedDriggs/darling/pull/173) ## v0.13.3 (April 5, 2022) - Add `error::Accumulator` for dealing with multiple errors [#164](https://github.com/TedDriggs/darling/pull/164) - Impl `FromMeta` for `syn::Type` and its variants [#172](https://github.com/TedDriggs/darling/pulls/172) ## v0.13.2 (March 30, 2022) - Impl `FromMeta` for `syn::ExprPath` [#169](https://github.com/TedDriggs/darling/issues/169) ## v0.13.1 (December 7, 2021) - Add `FromAttributes` trait and macro [#151](https://github.com/TedDriggs/darling/issues/151) ## v0.13.0 (May 20, 2021) - Update darling to 2018 edition [#129](https://github.com/TedDriggs/darling/pull/129) - Error on duplicate fields in `#[darling(...)]` attributes [#130](https://github.com/TedDriggs/darling/pull/130) - Impl `Copy` for `SpannedValue` - Add `SpannedValue::map_ref` ## v0.13.0-beta (April 20, 2021) - Update darling to 2018 edition [#129](https://github.com/TedDriggs/darling/pull/129) - Error on duplicate fields in `#[darling(...)]` attributes [#130](https://github.com/TedDriggs/darling/pull/130) ## v0.12.4 (April 20, 2021) - Add `and_then` to derive macros for `darling` ## v0.12.3 (April 8, 2021) - Fix `FromMeta` impl for `char` not to panic [#126](https://github.com/TedDriggs/darling/pull/126) ## v0.12.2 (February 23, 2021) - Impl `FromMeta` for `HashMap` and `HashMap` ## v0.12.1 (February 22, 2021) - Impl `FromMeta` for `syn::ExprArray` [#122](https://github.com/TedDriggs/darling/pull/122) - Remove use of `unreachable` from `darling::ast::Data` [#123](https://github.com/TedDriggs/darling/pull/123) - Add `darling::ast::Data::try_empty_from` to avoid panics when trying to read a union body [#123](https://github.com/TedDriggs/darling/pull/123) ## v0.12.0 (January 5, 2021) - POSSIBLY BREAKING: Derived impls of `FromDeriveInput`, `FromField`, `FromVariant`, and `FromTypeParam` will now error when encountering an attribute `darling` has been asked to parse that isn't a supported shape. Any crates using `darling` that relied on those attributes being silently ignored could see new errors reported in their dependent crates. [#113](https://github.com/TedDriggs/darling/pull/113) - Impl `syn::spanned::Spanned` for `darling::util::SpannedValue` [#113](https://github.com/TedDriggs/darling/pull/113) - Add `darling::util::parse_attribute_to_meta_list` to provide useful errors during attribute parsing [#113](https://github.com/TedDriggs/darling/pull/113) - Add `impl From for Error` to losslessly propagate `syn` errors [#116](https://github.com/TedDriggs/darling/pull/116) ## v0.11.0 (December 14, 2020) - Bump minor version due to unexpected breaking change [#107](https://github.com/TedDriggs/darling/issues/107) ## v0.10.3 (December 10, 2020) - Add `discriminant` magic field when deriving `FromVariant` [#105](https://github.com/TedDriggs/darling/pull/105) ## v0.10.2 (October 30, 2019) - Bump syn dependency to 1.0.1 [#83](https://github.com/TedDriggs/darling/pull/83) ## v0.10.1 (September 25, 2019) - Fix test compilation errors [#81](https://github.com/TedDriggs/darling/pull/81) ## v0.10.0 (August 15, 2019) - Bump syn and quote to 1.0 [#79](https://github.com/TedDriggs/darling/pull/79) - Increase rust version to 1.31 ## v0.9.0 (March 20, 2019) - Enable "did you mean" suggestions by default - Make `darling_core::{codegen, options}` private [#58](https://github.com/TedDriggs/darling/issues/58) - Fix `Override::as_mut`: [#66](https://github.com/TedDriggs/darling/issues/66) ## v0.8.6 (March 18, 2019) - Added "did you mean" suggestions for unknown fields behind the `suggestions` flag [#60](https://github.com/TedDriggs/issues/60) - Added `Error::unknown_field_with_alts` to support the suggestion use-case. - Added `ast::Fields::len` and `ast::Fields::is_empty` methods. ## v0.8.5 (February 4, 2019) - Accept unquoted positive numeric literals [#52](https://github.com/TedDriggs/issues/52) - Add `FromMeta` to the `syn::Lit` enum and its variants - Improve error message for unexpected literal formats to not say "other" ## v0.8.4 (February 4, 2019) - Use `syn::Error` to provide precise errors before `proc_macro::Diagnostic` is available - Add `diagnostics` feature flag to toggle between stable and unstable error backends - Attach error information in more contexts - Add `allow_unknown_fields` to support parsing the same attribute multiple times for different macros [#51](https://github.com/darling/issues/51) - Proc-macro authors will now see better errors in `darling` attributes ## v0.8.3 (January 21, 2019) - Attach spans to errors in generated trait impls [#37](https://github.com/darling/issues/37) - Attach spans to errors for types with provided bespoke implementations - Deprecate `set_span` from 0.8.2, as spans should never be broadened after being initially set ## v0.8.2 (January 17, 2019) - Add spans to errors to make quality warnings and errors easy in darling. This is blocked on diagnostics stabilizing. - Add `darling::util::SpannedValue` so proc-macro authors can remember position information alongside parsed values. ## v0.8.0 - Update dependency on `syn` to 0.15 [#44](https://github.com/darling/pull/44). Thanks to @hcpl ## v0.7.0 (July 24, 2018) - Update dependencies on `syn` and `proc-macro2` - Add `util::IdentString`, which acts as an Ident or its string equivalent ## v0.6.3 (May 22, 2018) - Add support for `Uses*` traits in where predicates ## v0.6.2 (May 22, 2018) - Add `usage` module for tracking type param and lifetime usage in generic declarations - Add `UsesTypeParams` and `CollectsTypeParams` traits [#37](https://github.com/darling/issues/37) - Add `UsesLifetimes` and `CollectLifetimes` traits [#41](https://github.com/darling/pull/41) - Don't add `FromMeta` bounds to type parameters only used by skipped fields [#40](https://github.com/darling/pull/40) ## v0.6.1 (May 17, 2018) - Fix an issue where the `syn` update broke shape validation [#36](https://github.com/TedDriggs/darling/issues/36) ## v0.6.0 (May 15, 2018) ### Breaking Changes - Renamed `FromMetaItem` to `FromMeta`, and renamed `from_meta_item` method to `from_meta` - Added dedicated `derive(FromMetaItem)` which panics and redirects users to `FromMeta` ## v0.5.0 (May 10, 2018) - Add `ast::Generics` and `ast::GenericParam` to work with generics in a manner similar to `ast::Data` - Add `ast::GenericParamExt` to support alternate representations of generic parameters - Add `util::WithOriginal` to get a parsed representation and syn's own struct for a syntax block - Add `FromGenerics` and `FromGenericParam` traits (without derive support) - Change generated code for `generics` magic field to invoke `FromGenerics` trait during parsing - Add `FromTypeParam` trait [#30](https://github.com/TedDriggs/darling/pull/30). Thanks to @upsuper ## v0.4.0 (April 5, 2018) - Update dependencies on `proc-macro`, `quote`, and `syn` [#26](https://github.com/TedDriggs/darling/pull/26). Thanks to @hcpl ## v0.3.3 (April 2, 2018) **YANKED** ## v0.3.2 (March 13, 2018) - Derive `Default` on `darling::Ignored` (fixes [#25](https://github.com/TedDriggs/darling/issues/25)). ## v0.3.1 (March 7, 2018) - Support proc-macro2/nightly [#24](https://github.com/TedDriggs/darling/pull/24). Thanks to @kdy1 ## v0.3.0 (January 26, 2018) ### Breaking Changes - Update `syn` to 0.12 [#20](https://github.com/TedDriggs/darling/pull/20). Thanks to @Eijebong - Update `quote` to 0.4 [#20](https://github.com/TedDriggs/darling/pull/20). Thanks to @Eijebong - Rename magic field `body` in derived `FromDeriveInput` structs to `data` to stay in sync with `syn` - Rename magic field `data` in derived `FromVariant` structs to `fields` to stay in sync with `syn` ## v0.2.2 (December 5, 2017) - Update `lazy_static` to 1.0 [#15](https://github.com/TedDriggs/darling/pull/16). Thanks to @Eijebong ## v0.2.1 (November 28, 2017) - Add `impl FromMetaItem` for integer types [#15](https://github.com/TedDriggs/darling/pull/15) ## v0.2.0 (June 18, 2017) - Added support for returning multiple errors from parsing [#5](https://github.com/TedDriggs/darling/pull/5) - Derived impls no longer return on first error [#5](https://github.com/TedDriggs/darling/pull/5) - Removed default types for `V` and `F` from `ast::Body` - Enum variants are automatically converted to snake_case [#12](https://github.com/TedDriggs/darling/pull/12) darling-0.20.10/Cargo.lock0000644000000136530000000000100105770ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "darling" version = "0.20.10" dependencies = [ "darling_core", "darling_macro", "proc-macro2", "quote", "rustversion", "syn 2.0.16", "trybuild", ] [[package]] name = "darling_core" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn 2.0.16", ] [[package]] name = "darling_macro" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", "syn 2.0.16", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "itoa" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "once_cell" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "proc-macro2" version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] [[package]] name = "rustversion" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" [[package]] name = "ryu" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "serde" version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" [[package]] name = "serde_derive" version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", "syn 1.0.91", ] [[package]] name = "serde_json" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "syn" version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] [[package]] name = "toml" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] [[package]] name = "trybuild" version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db29f438342820400f2d9acfec0d363e987a38b2950bdb50a7069ed17b2148ee" dependencies = [ "glob", "once_cell", "serde", "serde_derive", "serde_json", "termcolor", "toml", ] [[package]] name = "unicode-ident" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" darling-0.20.10/Cargo.toml0000644000000027270000000000100106220ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56" name = "darling" version = "0.20.10" authors = ["Ted Driggs "] exclude = [ "/.travis.yml", "/publish.sh", "/.github/**", ] description = """ A proc-macro library for reading attributes into structs when implementing custom derives. """ documentation = "https://docs.rs/darling/0.20.10" readme = "README.md" license = "MIT" repository = "https://github.com/TedDriggs/darling" [dependencies.darling_core] version = "=0.20.10" [dependencies.darling_macro] version = "=0.20.10" [dev-dependencies.proc-macro2] version = "1.0.37" [dev-dependencies.quote] version = "1.0.18" [dev-dependencies.syn] version = "2.0.15" [features] default = ["suggestions"] diagnostics = ["darling_core/diagnostics"] suggestions = ["darling_core/suggestions"] [target."cfg(compiletests)".dev-dependencies.rustversion] version = "1.0.9" [target."cfg(compiletests)".dev-dependencies.trybuild] version = "1.0.38" [badges.maintenance] status = "actively-developed" darling-0.20.10/Cargo.toml.orig000064400000000000000000000017001046102023000142710ustar 00000000000000[package] name = "darling" version = "0.20.10" authors = ["Ted Driggs "] repository = "https://github.com/TedDriggs/darling" documentation = "https://docs.rs/darling/0.20.10" description = """ A proc-macro library for reading attributes into structs when implementing custom derives. """ license = "MIT" readme = "README.md" edition = "2021" rust-version = "1.56" exclude = ["/.travis.yml", "/publish.sh", "/.github/**"] [badges] maintenance = { status = "actively-developed" } [dependencies] darling_core = { version = "=0.20.10", path = "core" } darling_macro = { version = "=0.20.10", path = "macro" } [dev-dependencies] proc-macro2 = "1.0.37" quote = "1.0.18" syn = "2.0.15" [target.'cfg(compiletests)'.dev-dependencies] rustversion = "1.0.9" trybuild = "1.0.38" [features] default = ["suggestions"] diagnostics = ["darling_core/diagnostics"] suggestions = ["darling_core/suggestions"] [workspace] members = ["macro", "core"] darling-0.20.10/LICENSE000064400000000000000000000020531046102023000124110ustar 00000000000000MIT 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. darling-0.20.10/README.md000064400000000000000000000214241046102023000126660ustar 00000000000000# Darling [![Build Status](https://github.com/TedDriggs/darling/workflows/CI/badge.svg)](https://github.com/TedDriggs/darling/actions) [![Latest Version](https://img.shields.io/crates/v/darling.svg)](https://crates.io/crates/darling) ![Rustc Version 1.56+](https://img.shields.io/badge/rustc-1.56+-lightgray.svg) `darling` is a crate for proc macro authors, which enables parsing attributes into structs. It is heavily inspired by `serde` both in its internals and in its API. # Benefits - Easy and declarative parsing of macro input - make your proc-macros highly controllable with minimal time investment. - Great validation and errors, no work required. When users of your proc-macro make a mistake, `darling` makes sure they get error markers at the right place in their source, and provides "did you mean" suggestions for misspelled fields. # Usage `darling` provides a set of traits which can be derived or manually implemented. 1. `FromMeta` is used to extract values from a meta-item in an attribute. Implementations are likely reusable for many libraries, much like `FromStr` or `serde::Deserialize`. Trait implementations are provided for primitives, some std types, and some `syn` types. 2. `FromDeriveInput` is implemented or derived by each proc-macro crate which depends on `darling`. This is the root for input parsing; it gets access to the identity, generics, and visibility of the target type, and can specify which attribute names should be parsed or forwarded from the input AST. 3. `FromField` is implemented or derived by each proc-macro crate which depends on `darling`. Structs deriving this trait will get access to the identity (if it exists), type, and visibility of the field. 4. `FromVariant` is implemented or derived by each proc-macro crate which depends on `darling`. Structs deriving this trait will get access to the identity and contents of the variant, which can be transformed the same as any other `darling` input. 5. `FromAttributes` is a lower-level version of the more-specific `FromDeriveInput`, `FromField`, and `FromVariant` traits. Structs deriving this trait get a meta-item extractor and error collection which works for any syntax element, including traits, trait items, and functions. This is useful for non-derive proc macros. ## Additional Modules - `darling::ast` provides generic types for representing the AST. - `darling::usage` provides traits and functions for determining where type parameters and lifetimes are used in a struct or enum. - `darling::util` provides helper types with special `FromMeta` implementations, such as `PathList`. # Example ```rust,ignore use darling::{FromDeriveInput, FromMeta}; #[derive(Default, FromMeta)] #[darling(default)] pub struct Lorem { #[darling(rename = "sit")] ipsum: bool, dolor: Option, } #[derive(FromDeriveInput)] #[darling(attributes(my_crate), forward_attrs(allow, doc, cfg))] pub struct MyTraitOpts { ident: syn::Ident, attrs: Vec, lorem: Lorem, } ``` The above code will then be able to parse this input: ```rust,ignore /// A doc comment which will be available in `MyTraitOpts::attrs`. #[derive(MyTrait)] #[my_crate(lorem(dolor = "Hello", sit))] pub struct ConsumingType; ``` # Attribute Macros Non-derive attribute macros are supported. To parse arguments for attribute macros, derive `FromMeta` on the argument receiver type, then use `darling::ast::NestedMeta::parse_meta_list` to convert the arguments `TokenStream` to a `Vec`, then pass that to the derived `from_list` method on your argument receiver type. This will produce a normal `darling::Result` that can be used the same as a result from parsing a `DeriveInput`. ## Macro Code ```rust,ignore use darling::{Error, FromMeta}; use darling::ast::NestedMeta; use syn::ItemFn; use proc_macro::TokenStream; #[derive(Debug, FromMeta)] struct MacroArgs { #[darling(default)] timeout_ms: Option, path: String, } #[proc_macro_attribute] pub fn your_attr(args: TokenStream, input: TokenStream) -> TokenStream { let attr_args = match NestedMeta::parse_meta_list(args.into()) { Ok(v) => v, Err(e) => { return TokenStream::from(Error::from(e).write_errors()); } }; let _input = syn::parse_macro_input!(input as ItemFn); let _args = match MacroArgs::from_list(&attr_args) { Ok(v) => v, Err(e) => { return TokenStream::from(e.write_errors()); } }; // do things with `args` unimplemented!() } ``` ## Consuming Code ```rust,ignore use your_crate::your_attr; #[your_attr(path = "hello", timeout_ms = 15)] fn do_stuff() { println!("Hello"); } ``` # Features Darling's features are built to work well for real-world projects. - **Defaults**: Supports struct- and field-level defaults, using the same path syntax as `serde`. Additionally, `Option` and `darling::util::Flag` fields are innately optional; you don't need to declare `#[darling(default)]` for those. - **Field Renaming**: Fields can have different names in usage vs. the backing code. - **Auto-populated fields**: Structs deriving `FromDeriveInput` and `FromField` can declare properties named `ident`, `vis`, `ty`, `attrs`, and `generics` to automatically get copies of the matching values from the input AST. `FromDeriveInput` additionally exposes `data` to get access to the body of the deriving type, and `FromVariant` exposes `fields`. - **Transformation of forwarded attributes**: You can add `#[darling(with=path)]` to the `attrs` field to use a custom function to transform the forwarded attributes before they're provided to your struct. The function signature is `fn(Vec) -> darling::Result`, where `T` is the type you declared for the `attrs` field. Returning an error from this function will propagate with all other parsing errors. - **Mapping function**: Use `#[darling(map="path")]` or `#[darling(and_then="path")]` to specify a function that runs on the result of parsing a meta-item field. This can change the return type, which enables you to parse to an intermediate form and convert that to the type you need in your struct. - **Skip fields**: Use `#[darling(skip)]` to mark a field that shouldn't be read from attribute meta-items. - **Multiple-occurrence fields**: Use `#[darling(multiple)]` on a `Vec` field to allow that field to appear multiple times in the meta-item. Each occurrence will be pushed into the `Vec`. - **Span access**: Use `darling::util::SpannedValue` in a struct to get access to that meta item's source code span. This can be used to emit warnings that point at a specific field from your proc macro. In addition, you can use `darling::Error::write_errors` to automatically get precise error location details in most cases. - **"Did you mean" suggestions**: Compile errors from derived darling trait impls include suggestions for misspelled fields. - **Struct flattening**: Use `#[darling(flatten)]` to remove one level of structure when presenting your meta item to users. Fields that are not known to the parent struct will be forwarded to the `flatten` field. ## Shape Validation Some proc-macros only work on structs, while others need enums whose variants are either unit or newtype variants. Darling makes this sort of validation extremely simple. On the receiver that derives `FromDeriveInput`, add `#[darling(supports(...))]` and then list the shapes that your macro should accept. | Name | Description | | ---------------- | ------------------------------------------------------------------------- | | `any` | Accept anything | | `struct_any` | Accept any struct | | `struct_named` | Accept structs with named fields, e.g. `struct Example { field: String }` | | `struct_newtype` | Accept newtype structs, e.g. `struct Example(String)` | | `struct_tuple` | Accept tuple structs, e.g. `struct Example(String, String)` | | `struct_unit` | Accept unit structs, e.g. `struct Example;` | | `enum_any` | Accept any enum | | `enum_named` | Accept enum variants with named fields | | `enum_newtype` | Accept newtype enum variants | | `enum_tuple` | Accept tuple enum variants | | `enum_unit` | Accept unit enum variants | Each one is additive, so listing `#[darling(supports(struct_any, enum_newtype))]` would accept all structs and any enum where every variant is a newtype variant. This can also be used when deriving `FromVariant`, without the `enum_` prefix. darling-0.20.10/clippy.toml000064400000000000000000000001341046102023000135770ustar 00000000000000msrv = "1.56.0" disallowed-names = [] # we want to be able to use placeholder names in testsdarling-0.20.10/compiletests.sh000075500000000000000000000001051046102023000144520ustar 00000000000000RUSTFLAGS="--cfg=compiletests" cargo +1.65.0 test --test compiletestsdarling-0.20.10/examples/automatic_bounds.rs000064400000000000000000000033041046102023000171300ustar 00000000000000use darling::{FromDeriveInput, FromMeta}; #[derive(FromMeta, PartialEq, Eq, Debug)] enum Volume { Whisper, Talk, Shout, } /// A more complex example showing the ability to skip at a field or struct /// level while still tracking which type parameters need to be bounded. /// This can be seen by expanding this example using `cargo expand`. #[derive(FromMeta)] #[allow(dead_code)] enum Emphasis { Constant(Volume), Variable(darling::util::PathList), #[darling(skip)] PerPhoneme(Option), Strided { #[darling(skip)] step: Vec, #[darling(multiple)] volume: Vec, }, } #[derive(FromDeriveInput)] #[darling(attributes(speak))] struct SpeakingOptions { max_volume: U, #[darling(skip, default)] additional_data: Vec, } #[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 Default for SpeakingOptions where Vec: 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 = FromDeriveInput::from_derive_input(&derive_input).unwrap(); assert_eq!(parsed.max_volume, Volume::Shout); assert_eq!(parsed.additional_data.len(), 0); } darling-0.20.10/examples/consume_fields.rs000064400000000000000000000123771046102023000166010ustar 00000000000000// The use of fields in debug print commands does not count as "used", // which causes the fields to trigger an unwanted dead code warning. #![allow(dead_code)] //! This example shows how to do struct and field parsing using darling. use darling::{ast, FromDeriveInput, FromField, FromMeta}; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::parse_str; /// A speaking volume. Deriving `FromMeta` will cause this to be usable /// as a string value for a meta-item key. #[derive(Debug, Clone, Copy, FromMeta)] #[darling(default)] enum Volume { Normal, Whisper, Shout, } impl Default for Volume { fn default() -> Self { Volume::Normal } } /// Support parsing from a full derive input. Unlike FromMeta, this isn't /// composable; each darling-dependent crate should have its own struct to handle /// when its trait is derived. #[derive(Debug, FromDeriveInput)] // This line says that we want to process all attributes declared with `my_trait`, // and that darling should panic if this receiver is given an enum. #[darling(attributes(my_trait), supports(struct_any))] struct MyInputReceiver { /// The struct ident. ident: syn::Ident, /// The type's generics. You'll need these any time your trait is expected /// to work with types that declare generics. generics: syn::Generics, /// Receives the body of the struct or enum. We don't care about /// struct fields because we previously told darling we only accept structs. data: ast::Data<(), MyFieldReceiver>, /// The Input Receiver demands a volume, so use `Volume::Normal` if the /// caller doesn't provide one. #[darling(default)] volume: Volume, } impl ToTokens for MyInputReceiver { fn to_tokens(&self, tokens: &mut TokenStream) { let MyInputReceiver { ref ident, ref generics, ref data, volume, } = *self; let (imp, ty, wher) = generics.split_for_impl(); let fields = data .as_ref() .take_struct() .expect("Should never be enum") .fields; // Generate the format string which shows each field and its name let fmt_string = fields .iter() .enumerate() .map(|(i, f)| { // We have to preformat the ident in this case so we can fall back // to the field index for unnamed fields. It's not easy to read, // unfortunately. format!( "{} = {{}}", f.ident .as_ref() .map(|v| format!("{}", v)) .unwrap_or_else(|| format!("{}", i)) ) }) .collect::>() .join(", "); // Generate the actual values to fill the format string. let field_list = fields .into_iter() .enumerate() .map(|(i, f)| { let field_volume = f.volume.unwrap_or(volume); // This works with named or indexed fields, so we'll fall back to the index so we can // write the output as a key-value pair. let field_ident = f.ident .as_ref() .map(|v| quote!(#v)) .unwrap_or_else(|| { let i = syn::Index::from(i); quote!(#i) }); match field_volume { Volume::Normal => quote!(self.#field_ident), Volume::Shout => { quote!(::std::string::ToString::to_string(&self.#field_ident).to_uppercase()) } Volume::Whisper => { quote!(::std::string::ToString::to_string(&self.#field_ident).to_lowercase()) } } }) .collect::>(); tokens.extend(quote! { impl #imp Speak for #ident #ty #wher { fn speak(&self, writer: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(writer, #fmt_string, #(#field_list),*) } } }); } } #[derive(Debug, FromField)] #[darling(attributes(my_trait))] struct MyFieldReceiver { /// Get the ident of the field. For fields in tuple or newtype structs or /// enum bodies, this can be `None`. ident: Option, /// This magic field name pulls the type from the input. ty: syn::Type, /// We declare this as an `Option` so that during tokenization we can write /// `field.volume.unwrap_or(derive_input.volume)` to facilitate field-level /// overrides of struct-level settings. /// /// Because this field is an `Option`, we don't need to include `#[darling(default)]` volume: Option, } 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 ); } darling-0.20.10/examples/expr_with.rs000064400000000000000000000007421046102023000156040ustar 00000000000000use darling::{util::parse_expr, FromDeriveInput}; use syn::{parse_quote, Expr}; #[derive(FromDeriveInput)] #[darling(attributes(demo))] pub struct Receiver { #[darling(with = parse_expr::preserve_str_literal, map = Some)] example1: Option, } fn main() { let input = Receiver::from_derive_input(&parse_quote! { #[demo(example1 = test::path)] struct Example; }) .unwrap(); assert_eq!(input.example1, Some(parse_quote!(test::path))); } darling-0.20.10/examples/fallible_read.rs000064400000000000000000000054451046102023000163450ustar 00000000000000//! 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` to attempt a recovery in imperative code //! 1. Using the `map` darling meta-item to post-process a field before returning //! 1. Using the `and_then` darling meta-item to post-process the receiver before returning use darling::{FromDeriveInput, FromMeta}; use syn::parse_str; #[derive(Debug, FromDeriveInput)] #[darling(attributes(my_trait), and_then = MyInputReceiver::autocorrect)] pub struct MyInputReceiver { /// This field must be present and a string or else parsing will panic. #[darling(map = MyInputReceiver::make_string_shouty)] name: String, /// If this field fails to parse, the struct can still be built; the field /// will contain the error. The consuming struct can then decide if this /// blocks code generation. If so, panic or fail in `and_then`. frequency: darling::Result, /// 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, } impl MyInputReceiver { /// This function will be called by `darling` _after_ it's finished parsing the /// `name` field but before initializing `name` with the resulting value. It's /// a good place for transforms that are easiest to express on already-built /// types. fn make_string_shouty(s: String) -> String { s.to_uppercase() } /// This function will be called by `darling` _after_ it's finished parsing the /// input but before returning to the caller. This is a good place to initialize /// skipped fields or to perform corrections that don't lend themselves to being /// done elsewhere. fn autocorrect(self) -> darling::Result { let Self { name, frequency, amplitude, } = self; // Amplitude doesn't have a sign, so if we received a negative number then // we'll go ahead and make it positive. let amplitude = match amplitude { Ok(amp) => amp, Err(mi) => (i64::from_meta(&mi)?).unsigned_abs(), }; Ok(Self { name, frequency, amplitude: Ok(amplitude), }) } } fn main() { let input = r#"#[derive(MyTrait)] #[my_trait(name="Jon", amplitude = "-1", frequency = 1)] pub struct Foo;"#; let parsed = parse_str(input).unwrap(); let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); println!( r#" INPUT: {} PARSED AS: {:?} "#, input, receiver ); } darling-0.20.10/examples/heterogeneous_enum_and_word.rs000064400000000000000000000045301046102023000213470ustar 00000000000000//! This example demonstrates: //! //! - The behavior of a derived `FromMeta` implementation for heterogeneous enums //! (i.e. enums that include a mix of unit, newtype and struct variants). //! - Using `#[darling(word)]` to specify a unit variant to use when a receiver field //! is specified without a value (i.e. a unit variant to use for deriving the //! `FromMeta::from_word` method). //! - Using `#[darling(default)]` on a receiver field to fall back to `Default::default()` //! for the enum's value when the receiver field is not specified by the caller. use darling::{Error, FromDeriveInput, FromMeta}; use syn::parse_quote; /// A playback volume. #[derive(Debug, FromMeta, PartialEq, Eq)] enum Volume { Normal, #[darling(word)] Low, High, #[darling(rename = "dB")] Decibels(u8), } impl Default for Volume { fn default() -> Self { Volume::Normal } } #[derive(Debug, FromDeriveInput)] #[darling(attributes(play))] struct PlayReceiver { #[darling(default)] volume: Volume, } fn main() { // `Default::default()` is used when `volume` is not specified. let missing_volume = PlayReceiver::from_derive_input(&parse_quote! { #[play] struct Player; }) .unwrap(); assert_eq!(Volume::Normal, missing_volume.volume); // `#[darling(word)]` unit variant is used when `volume` is specified as a word with no value. let empty_volume = PlayReceiver::from_derive_input(&parse_quote! { #[play(volume)] struct Player; }) .unwrap(); assert_eq!(Volume::Low, empty_volume.volume); // Specified `volume` value is used when provided. let unit_variant_volume = PlayReceiver::from_derive_input(&parse_quote! { #[play(volume(high))] struct Player; }) .unwrap(); assert_eq!(Volume::High, unit_variant_volume.volume); let newtype_volume = PlayReceiver::from_derive_input(&parse_quote! { #[play(volume(dB = 100))] struct Player; }) .unwrap(); assert_eq!(Volume::Decibels(100), newtype_volume.volume); // Multiple `volume` values result in an error. let err = PlayReceiver::from_derive_input(&parse_quote! { #[play(volume(low, dB = 20))] struct Player; }) .unwrap_err(); assert_eq!( err.to_string(), Error::too_many_items(1).at("volume").to_string() ); } darling-0.20.10/examples/shorthand_or_long_field.rs000064400000000000000000000042321046102023000204450ustar 00000000000000//! Example showing potentially-nested meta item parsing with `darling::util::Override`. //! //! Based on https://stackoverflow.com/q/68046070/86381 by https://github.com/peterjoel // The use of fields in debug print commands does not count as "used", // which causes the fields to trigger an unwanted dead code warning. #![allow(dead_code)] use std::borrow::Cow; use darling::{util::Override, FromDeriveInput, FromMeta}; use syn::{Ident, Path}; #[derive(Debug, FromDeriveInput)] #[darling(attributes(myderive))] struct MyDeriveInput { ident: Ident, /// We can infer the right "table" behavior for this derive, but we want the caller to be /// explicit that they're expecting the inference behavior to avoid cluttering some hypothetical /// database. Therefore this field is required, but can take word form or key-value form. /// /// To make this field optional, we could add `#[darling(default)]`, or we could /// wrap it in `Option` if the presence or absence of the word makes a difference. table: Override, } impl MyDeriveInput { fn table(&self) -> Cow<'_, Table> { match &self.table { Override::Explicit(value) => Cow::Borrowed(value), Override::Inherit => Cow::Owned(Table { name: self.ident.to_string(), value: None, }), } } } #[derive(Debug, Clone, FromMeta)] struct Table { name: String, value: Option, } fn from_str(s: &str) -> darling::Result { FromDeriveInput::from_derive_input(&syn::parse_str(s)?) } fn main() { let missing = from_str( r#" #[derive(MyTrait)] struct Foo(u64); "#, ) .unwrap_err(); let short_form = from_str( r#" #[derive(MyTrait)] #[myderive(table)] struct Foo(u64); "#, ) .unwrap(); let long_form = from_str( r#" #[derive(MyTrait)] #[myderive(table(name = "Custom"))] struct Foo(u64); "#, ) .unwrap(); println!("Error when missing: {}", missing); println!("Short form: {:?}", short_form.table()); println!("Long form: {:?}", long_form.table()); } darling-0.20.10/examples/supports_struct.rs000064400000000000000000000023171046102023000170760ustar 00000000000000// The use of fields in debug print commands does not count as "used", // which causes the fields to trigger an unwanted dead code warning. #![allow(dead_code)] use darling::{ast, util, FromDeriveInput, FromField}; use syn::{Ident, Type}; #[derive(Debug, FromField)] #[darling(attributes(lorem))] pub struct LoremField { ident: Option, ty: Type, #[darling(default)] skip: bool, } #[derive(Debug, FromDeriveInput)] #[darling(attributes(lorem), supports(struct_named))] pub struct Lorem { ident: Ident, data: ast::Data, } 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 ); } darling-0.20.10/src/lib.rs000064400000000000000000000126211046102023000133110ustar 00000000000000//! # Darling //! Darling is a tool for declarative attribute parsing in proc macro implementations. //! //! //! ## Design //! Darling takes considerable design inspiration from [`serde`](https://serde.rs). A data structure that can be //! read from any attribute implements `FromMeta` (or has an implementation automatically //! generated using `derive`). Any crate can provide `FromMeta` implementations, even one not //! specifically geared towards proc-macro authors. //! //! Proc-macro crates should provide their own structs which implement or derive `FromDeriveInput`, //! `FromField`, `FromVariant`, `FromGenerics`, _et alia_ to gather settings relevant to their operation. //! //! ## Attributes //! There are a number of attributes that `darling` exposes to enable finer-grained control over the code //! it generates. //! //! * **Field renaming**: You can use `#[darling(rename="new_name")]` on a field to change the name Darling looks for. //! You can also use `#[darling(rename_all="...")]` at the struct or enum level to apply a casing rule to all fields or variants. //! * **Map function**: You can use `#[darling(map="path::to::function")]` to run code on a field before its stored in the struct. //! * **Default values**: You can use `#[darling(default)]` at the type or field level to use that type's default value to fill //! in values not specified by the caller. //! * **Skipped fields**: You can skip a variant or field using `#[darling(skip)]`. Fields marked with this will fall back to //! `Default::default()` for their value, but you can override that with an explicit default or a value from the type-level default. //! //! ## Forwarded Fields //! All derivable traits except `FromMeta` support forwarding some fields from the input AST to the derived struct. //! These fields are matched up by identifier **before** `rename` attribute values are considered, //! allowing you to use their names for your own properties. //! The deriving struct is responsible for making sure the types of fields it chooses to declare are compatible with this table. //! //! A deriving struct is free to include or exclude any of the fields below. //! //! ### `FromDeriveInput` //! |Field name|Type|Meaning| //! |---|---|---| //! |`ident`|`syn::Ident`|The identifier of the passed-in type| //! |`vis`|`syn::Visibility`|The visibility of the passed-in type| //! |`generics`|`T: darling::FromGenerics`|The generics of the passed-in type. This can be `syn::Generics`, `darling::ast::Generics`, or any compatible type.| //! |`data`|`darling::ast::Data`|The body of the passed-in type| //! |`attrs`|`Vec` (or anything, using `#[darling(with = ...)]`)|The forwarded attributes from the passed in type. These are controlled using the `forward_attrs` attribute.| //! //! ### `FromField` //! |Field name|Type|Meaning| //! |---|---|---| //! |`ident`|`Option`|The identifier of the passed-in field, or `None` for tuple fields| //! |`vis`|`syn::Visibility`|The visibility of the passed-in field| //! |`ty`|`syn::Type`|The type of the passed-in field| //! |`attrs`|`Vec` (or anything, using `#[darling(with = ...)]`)|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`|The bounds applied to the type param| //! |`default`|`Option`|The default type of the parameter, if one exists| //! |`attrs`|`Vec` (or anything, using `#[darling(with = ...)]`)|The forwarded attributes from the passed in type param. These are controlled using the `forward_attrs` attribute.| //! //! ### `FromVariant` //! |Field name|Type|Meaning| //! |---|---|---| //! |`ident`|`syn::Ident`|The identifier of the passed-in variant| //! |`discriminant`|`Option`|For a variant such as `Example = 2`, the `2`| //! |`fields`|`darling::ast::Fields where T: FromField`|The fields associated with the variant| //! |`attrs`|`Vec` (or anything, using `#[darling(with = ...)]`)|The forwarded attributes from the passed in variant. These are controlled using the `forward_attrs` attribute.| #![warn(rust_2018_idioms)] #[allow(unused_imports)] #[macro_use] extern crate darling_macro; #[doc(hidden)] pub use darling_macro::*; #[doc(inline)] pub use darling_core::{ FromAttributes, FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam, FromVariant, }; #[doc(inline)] pub use darling_core::{Error, Result}; #[doc(inline)] pub use darling_core::{ast, error, usage, util}; // XXX exported so that `ExtractAttribute::extractor` can convert a path into tokens. // This is likely to change in the future, so only generated code should depend on this export. #[doc(hidden)] pub use darling_core::ToTokens; /// Core/std trait re-exports. This should help produce generated code which doesn't /// depend on `std` unnecessarily, and avoids problems caused by aliasing `std` or any /// of the referenced types. #[doc(hidden)] pub mod export { pub use core::convert::From; pub use core::default::Default; pub use core::option::Option::{self, None, Some}; pub use core::result::Result::{self, Err, Ok}; pub use darling_core::syn; pub use std::string::ToString; pub use std::vec::Vec; pub use crate::ast::NestedMeta; } #[macro_use] mod macros_public; darling-0.20.10/src/macros_public.rs000064400000000000000000000070021046102023000153620ustar 00000000000000//! Macros that should be exported from both `darling_core` and `darling`. //! Note that these are **sym-linked** into the main code, and so cannot declare on items that are exported differently //! in `darling_core` vs. `darling`. /// Generator for `UsesTypeParam` impls that unions the used type parameters of the selected fields. /// /// # Usage /// The macro takes the type implementing the trait as the first argument, then a comma-separated list of /// fields for the rest of its arguments. /// /// The type of each passed-in field must implement `UsesTypeParams`, or the resulting code won't compile. /// /// ```rust /// # extern crate syn; /// # use darling_core::uses_type_params; /// # /// struct MyField { /// ty: syn::Type, /// } /// /// uses_type_params!(MyField, ty); /// /// fn main() { /// // no test run /// } /// ``` /// /// `darling` cannot derive this trait automatically, as it doesn't know which information extracted from /// proc-macro input is meant to constitute "using" the type parameter, but crate consumers should /// implement it by hand or using the macro. #[macro_export] macro_rules! uses_type_params { ($impl_type:ty, $accessor:ident) => { impl $crate::usage::UsesTypeParams for $impl_type { fn uses_type_params<'gen>( &self, options: &$crate::usage::Options, type_set: &'gen $crate::usage::IdentSet ) -> $crate::usage::IdentRefSet<'gen> { self.$accessor.uses_type_params(options, type_set) } } }; ($impl_type:ty, $first:ident, $($field:ident),+) => { impl $crate::usage::UsesTypeParams for $impl_type { fn uses_type_params<'gen>( &self, options: &$crate::usage::Options, type_set: &'gen $crate::usage::IdentSet ) -> $crate::usage::IdentRefSet<'gen> { let mut hits = self.$first.uses_type_params(options, type_set); $( hits.extend(self.$field.uses_type_params(options, type_set)); )* hits } } }; } /// Generator for `UsesLifetimes` impls that unions the used lifetimes of the selected fields. /// /// # Usage /// The macro takes the type implementing the trait as the first argument, then a comma-separated list of /// fields for the rest of its arguments. /// /// The type of each passed-in field must implement `UsesLifetimes`, or the resulting code won't compile. #[macro_export] macro_rules! uses_lifetimes { ($impl_type:ty, $accessor:ident) => { impl $crate::usage::UsesLifetimes for $impl_type { fn uses_lifetimes<'gen>( &self, options: &$crate::usage::Options, type_set: &'gen $crate::usage::LifetimeSet ) -> $crate::usage::LifetimeRefSet<'gen> { self.$accessor.uses_lifetimes(options, type_set) } } }; ($impl_type:ty, $first:ident, $($field:ident),+) => { impl $crate::usage::UsesLifetimes for $impl_type { fn uses_lifetimes<'gen>( &self, options: &$crate::usage::Options, type_set: &'gen $crate::usage::LifetimeSet ) -> $crate::usage::LifetimeRefSet<'gen> { let mut hits = self.$first.uses_lifetimes(options, type_set); $( hits.extend(self.$field.uses_lifetimes(options, type_set)); )* hits } } }; } darling-0.20.10/tests/accrue_errors.rs000064400000000000000000000044571046102023000157640ustar 00000000000000#![allow(dead_code)] //! These tests verify that multiple errors will be collected up from throughout //! the parsing process and returned correctly to the caller. use darling::{ast, FromDeriveInput, FromField, FromMeta}; use syn::parse_quote; #[derive(Debug, FromDeriveInput)] #[darling(attributes(accrue))] struct Lorem { ipsum: String, dolor: Dolor, data: ast::Data<(), LoremField>, } #[derive(Debug, FromMeta)] struct Dolor { sit: bool, } #[derive(Debug, FromField)] #[darling(attributes(accrue))] struct LoremField { ident: Option, 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()); } darling-0.20.10/tests/attrs_with.rs000064400000000000000000000037211046102023000153070ustar 00000000000000use std::collections::BTreeSet; use darling::{util, Error, FromDeriveInput, Result}; use syn::{parse_quote, Attribute}; fn unique_idents(attrs: Vec) -> Result> { let mut errors = Error::accumulator(); let idents = attrs .into_iter() .filter_map(|attr| { let path = attr.path(); errors.handle( path.get_ident() .map(std::string::ToString::to_string) .ok_or_else(|| { Error::custom(format!("`{}` is not an ident", util::path_to_string(path))) .with_span(path) }), ) }) .collect(); errors.finish_with(idents) } #[derive(FromDeriveInput)] #[darling(attributes(a), forward_attrs)] struct Receiver { #[darling(with = unique_idents)] attrs: BTreeSet, other: Option, } #[test] fn succeeds_on_no_attrs() { let di = Receiver::from_derive_input(&parse_quote! { struct Demo; }) .unwrap(); assert!(di.attrs.is_empty()); } #[test] fn succeeds_on_valid_input() { let di = Receiver::from_derive_input(&parse_quote! { #[allow(dead_code)] /// testing #[another] struct Demo; }) .unwrap(); assert_eq!(di.attrs.len(), 3); assert!(di.attrs.contains("allow")); assert!(di.attrs.contains("another")); assert!(di.attrs.contains("doc")); assert_eq!(di.other, None); } #[test] fn errors_combined_with_others() { let e = Receiver::from_derive_input(&parse_quote! { #[path::to::attr(dead_code)] #[a(other = 5)] struct Demo; }) .map(|_| "Should have failed") .unwrap_err(); let error = e.to_string(); assert_eq!(e.len(), 2); // Look for the error on the field `other` assert!(error.contains("at other")); // Look for the invalid path from attrs conversion assert!(error.contains("`path::to::attr`")); } darling-0.20.10/tests/compile-fail/attrs_with_bad_fn.rs000064400000000000000000000004231046102023000211350ustar 00000000000000use darling::FromDeriveInput; use syn::Attribute; fn bad_converter(attrs: Vec) -> Vec { attrs } #[derive(FromDeriveInput)] #[darling(forward_attrs)] struct Receiver { #[darling(with = bad_converter)] attrs: Vec, } fn main() {} darling-0.20.10/tests/compile-fail/attrs_with_bad_fn.stderr000064400000000000000000000013331046102023000220150ustar 00000000000000error[E0308]: mismatched types --> tests/compile-fail/attrs_with_bad_fn.rs:11:22 | 11 | #[darling(with = bad_converter)] | ^^^^^^^^^^^^^ | | | expected `Result<_, Error>`, found `Vec` | arguments to this method are incorrect | = note: expected enum `Result<_, darling::Error>` found struct `Vec` note: method defined here --> core/src/error/mod.rs | | pub fn handle(&mut self, result: Result) -> Option { | ^^^^^^ help: try wrapping the expression in `Ok` | 11 | #[darling(with = Ok(bad_converter))] | +++ + darling-0.20.10/tests/compile-fail/default_expr_wrong_type.rs000064400000000000000000000003431046102023000224140ustar 00000000000000use darling::FromMeta; #[derive(FromMeta)] struct Receiver { #[darling(default = "usize::default")] not_u32: String, #[darling(multiple, default = "usize::default")] also_not_u32: Vec, } fn main() {} darling-0.20.10/tests/compile-fail/default_expr_wrong_type.stderr000064400000000000000000000012071046102023000232730ustar 00000000000000error[E0308]: mismatched types --> tests/compile-fail/default_expr_wrong_type.rs:5:25 | 5 | #[darling(default = "usize::default")] | ^^^^^^^^^^^^^^^^- help: try using a conversion method: `.to_string()` | | | expected `String`, found `usize` error[E0308]: mismatched types --> tests/compile-fail/default_expr_wrong_type.rs:8:35 | 8 | #[darling(multiple, default = "usize::default")] | ^^^^^^^^^^^^^^^^ expected `Vec`, found `usize` | = note: expected struct `Vec` found type `usize` darling-0.20.10/tests/compile-fail/duplicate_word_across_variants.rs000064400000000000000000000002111046102023000237350ustar 00000000000000use darling::FromMeta; #[derive(FromMeta)] enum Choice { #[darling(word)] A, #[darling(word)] B, C, } fn main() {} darling-0.20.10/tests/compile-fail/duplicate_word_across_variants.stderr000064400000000000000000000005411046102023000246220ustar 00000000000000error: `#[darling(word)]` can only be applied to one variant --> tests/compile-fail/duplicate_word_across_variants.rs:5:15 | 5 | #[darling(word)] | ^^^^ error: `#[darling(word)]` can only be applied to one variant --> tests/compile-fail/duplicate_word_across_variants.rs:7:15 | 7 | #[darling(word)] | ^^^^ darling-0.20.10/tests/compile-fail/duplicate_word_on_variant.rs000064400000000000000000000001631046102023000227020ustar 00000000000000use darling::FromMeta; #[derive(FromMeta)] enum Choice { #[darling(word, word)] A, B, } fn main() {} darling-0.20.10/tests/compile-fail/duplicate_word_on_variant.stderr000064400000000000000000000002301046102023000235540ustar 00000000000000error: Duplicate field `word` --> tests/compile-fail/duplicate_word_on_variant.rs:5:21 | 5 | #[darling(word, word)] | ^^^^ darling-0.20.10/tests/compile-fail/flatten_meta_conflicts.rs000064400000000000000000000005131046102023000221630ustar 00000000000000use darling::FromMeta; #[derive(FromMeta)] struct Inner { left: String, right: String, } #[derive(FromMeta)] struct Outer { #[darling(flatten, multiple, with = demo, skip = true)] field: Inner, } #[derive(FromMeta)] struct ThisIsFine { #[darling(flatten, multiple = false)] field: Inner, } fn main() {} darling-0.20.10/tests/compile-fail/flatten_meta_conflicts.stderr000064400000000000000000000012471046102023000230470ustar 00000000000000error: `flatten` and `multiple` cannot be used together --> tests/compile-fail/flatten_meta_conflicts.rs:11:24 | 11 | #[darling(flatten, multiple, with = demo, skip = true)] | ^^^^^^^^ error: `flatten` and `with` cannot be used together --> tests/compile-fail/flatten_meta_conflicts.rs:11:34 | 11 | #[darling(flatten, multiple, with = demo, skip = true)] | ^^^^ error: `flatten` and `skip` cannot be used together --> tests/compile-fail/flatten_meta_conflicts.rs:11:47 | 11 | #[darling(flatten, multiple, with = demo, skip = true)] | ^^^^ darling-0.20.10/tests/compile-fail/flatten_multiple_fields.rs000064400000000000000000000007451046102023000223610ustar 00000000000000//! Test that multiple fields cannot be marked `flatten` at once. use darling::{FromDeriveInput, FromMeta}; #[derive(FromMeta)] struct Inner { left: String, right: String, } #[derive(FromMeta)] pub struct Example { #[darling(flatten)] first: Inner, #[darling(flatten)] last: Inner, } #[derive(FromDeriveInput)] pub struct FdiExample { ident: syn::Ident, #[darling(flatten)] first: Inner, #[darling(flatten)] last: Inner, } fn main() {} darling-0.20.10/tests/compile-fail/flatten_multiple_fields.stderr000064400000000000000000000013271046102023000232350ustar 00000000000000error: `#[darling(flatten)]` can only be applied to one field --> tests/compile-fail/flatten_multiple_fields.rs:13:15 | 13 | #[darling(flatten)] | ^^^^^^^ error: `#[darling(flatten)]` can only be applied to one field --> tests/compile-fail/flatten_multiple_fields.rs:15:15 | 15 | #[darling(flatten)] | ^^^^^^^ error: `#[darling(flatten)]` can only be applied to one field --> tests/compile-fail/flatten_multiple_fields.rs:22:15 | 22 | #[darling(flatten)] | ^^^^^^^ error: `#[darling(flatten)]` can only be applied to one field --> tests/compile-fail/flatten_multiple_fields.rs:24:15 | 24 | #[darling(flatten)] | ^^^^^^^ darling-0.20.10/tests/compile-fail/not_impl_from_meta.rs000064400000000000000000000003431046102023000213270ustar 00000000000000use darling::FromMeta; struct NotImplFm; #[derive(FromMeta)] struct OuterFm { inner: NotImplFm, } #[derive(darling::FromDeriveInput)] #[darling(attributes(hello))] struct OuterFdi { inner: NotImplFm, } fn main() {} darling-0.20.10/tests/compile-fail/not_impl_from_meta.stderr000064400000000000000000000016371046102023000222150ustar 00000000000000error[E0277]: the trait bound `NotImplFm: FromMeta` is not satisfied --> tests/compile-fail/not_impl_from_meta.rs:7:12 | 7 | inner: NotImplFm, | ^^^^^^^^^ the trait `FromMeta` is not implemented for `NotImplFm` | = help: the following other types implement trait `FromMeta`: bool char isize i8 i16 i32 i64 i128 and $N others error[E0277]: the trait bound `NotImplFm: FromMeta` is not satisfied --> tests/compile-fail/not_impl_from_meta.rs:13:12 | 13 | inner: NotImplFm, | ^^^^^^^^^ the trait `FromMeta` is not implemented for `NotImplFm` | = help: the following other types implement trait `FromMeta`: bool char isize i8 i16 i32 i64 i128 and $N others darling-0.20.10/tests/compile-fail/skip_field_not_impl_default.rs000064400000000000000000000004571046102023000232010ustar 00000000000000use darling::FromMeta; #[derive(FromMeta)] struct NoDefault(String); #[derive(FromMeta)] struct Recevier { #[darling(skip)] skipped: NoDefault, #[darling(skip = true)] explicitly_skipped: NoDefault, #[darling(skip = false)] not_skipped_no_problem: NoDefault, } fn main() {} darling-0.20.10/tests/compile-fail/skip_field_not_impl_default.stderr000064400000000000000000000014511046102023000240530ustar 00000000000000error[E0277]: the trait bound `NoDefault: std::default::Default` is not satisfied --> tests/compile-fail/skip_field_not_impl_default.rs:8:15 | 8 | #[darling(skip)] | ^^^^ the trait `std::default::Default` is not implemented for `NoDefault` | help: consider annotating `NoDefault` with `#[derive(Default)]` | 4 + #[derive(Default)] 5 | struct NoDefault(String); | error[E0277]: the trait bound `NoDefault: std::default::Default` is not satisfied --> tests/compile-fail/skip_field_not_impl_default.rs:11:22 | 11 | #[darling(skip = true)] | ^^^^ the trait `std::default::Default` is not implemented for `NoDefault` | help: consider annotating `NoDefault` with `#[derive(Default)]` | 4 + #[derive(Default)] 5 | struct NoDefault(String); | darling-0.20.10/tests/compile-fail/word_on_wrong_variant_type.rs000064400000000000000000000001731046102023000231260ustar 00000000000000use darling::FromMeta; #[derive(FromMeta)] enum Meta { Unit, #[darling(word)] NotUnit(String) } fn main() {} darling-0.20.10/tests/compile-fail/word_on_wrong_variant_type.stderr000064400000000000000000000003111046102023000237770ustar 00000000000000error: Unexpected field: `word`. `#[darling(word)]` can only be applied to a unit variant --> tests/compile-fail/word_on_wrong_variant_type.rs:6:15 | 6 | #[darling(word)] | ^^^^ darling-0.20.10/tests/compiletests.rs000064400000000000000000000006131046102023000156270ustar 00000000000000#![cfg(compiletests)] #[rustversion::stable(1.77)] #[test] fn compile_test() { let t = trybuild::TestCases::new(); t.compile_fail("tests/compile-fail/*.rs"); } #[rustversion::not(stable(1.77))] #[test] fn wrong_rustc_version() { panic!( "This is not the expected version of rustc. Error messages vary across compiler versions so tests may produce spurious errors" ); } darling-0.20.10/tests/computed_bound.rs000064400000000000000000000015151046102023000161250ustar 00000000000000use darling::{FromDeriveInput, FromMeta}; fn parse(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 { 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 = parse( r#" #[derive(Speak)] #[speak(max_volume = "shout")] enum HtmlElement { Div(String) } "#, ); assert_eq!(parsed.max_volume, Volume::Shout); } darling-0.20.10/tests/custom_bound.rs000064400000000000000000000010351046102023000156140ustar 00000000000000#![allow(dead_code)] use std::ops::Add; use darling::{FromDeriveInput, FromMeta}; #[derive(Debug, Clone, FromMeta)] #[darling(bound = "T: FromMeta + Add")] struct Wrapper(pub T); impl Add for Wrapper { type Output = Wrapper<::Output>; fn add(self, rhs: Self) -> Wrapper<::Output> { Wrapper(self.0 + rhs.0) } } #[derive(Debug, FromDeriveInput)] #[darling(attributes(hello), bound = "Wrapper: Add, T: FromMeta")] struct Foo { lorem: Wrapper, } #[test] fn expansion() {} darling-0.20.10/tests/defaults.rs000064400000000000000000000121221046102023000147210ustar 00000000000000use darling::FromDeriveInput; use syn::parse_quote; mod foo { pub mod bar { pub fn init() -> String { String::from("hello") } } } #[derive(FromDeriveInput)] #[darling(attributes(speak))] pub struct SpeakerOpts { #[darling(default = foo::bar::init)] first_word: String, } #[test] fn path_default() { let speaker: SpeakerOpts = FromDeriveInput::from_derive_input(&parse_quote! { struct Foo; }) .expect("Unit struct with no attrs should parse"); assert_eq!(speaker.first_word, "hello"); } /// Tests in this module capture the somewhat-confusing behavior observed when defaults /// are set at both the field and container level. /// /// The general rule is that more-specific declarations preempt less-specific ones; this is /// unsurprising and allows for granular control over what happens when parsing an AST. mod stacked_defaults { use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; fn jane() -> String { "Jane".into() } #[derive(FromMeta)] #[darling(default)] struct PersonName { #[darling(default = "jane")] first: String, #[darling(default)] middle: String, last: String, } impl Default for PersonName { fn default() -> Self { Self { first: "John".into(), middle: "T".into(), last: "Doe".into(), } } } #[derive(FromDeriveInput)] #[darling(attributes(person))] struct Person { #[darling(default)] name: PersonName, age: u8, } #[test] fn name_first_only() { let person = Person::from_derive_input(&parse_quote! { #[person(name(first = "Bill"), age = 5)] struct Foo; }) .unwrap(); assert_eq!(person.name.first, "Bill"); assert_eq!( person.name.middle, "", "Explicit field-level default should preempt container-level default" ); assert_eq!( person.name.last, "Doe", "Absence of a field-level default falls back to container-level default" ); } /// This is the most surprising case. The presence of `name()` means we invoke /// `PersonName::from_list(&[])`. When that finishes parsing each of the zero nested /// items it has received, it will then start filling in missing fields, using the /// explicit field-level defaults for `first` and `middle`, while for `last` it will /// use the `last` field from the container-level default. #[test] fn name_empty_list() { let person = Person::from_derive_input(&parse_quote! { #[person(name(), age = 5)] struct Foo; }) .unwrap(); assert_eq!(person.name.first, "Jane"); assert_eq!(person.name.middle, ""); assert_eq!(person.name.last, "Doe"); } #[test] fn no_name() { let person = Person::from_derive_input(&parse_quote! { #[person(age = 5)] struct Foo; }) .unwrap(); assert_eq!(person.age, 5); assert_eq!( person.name.first, "John", "If `name` is not specified, `Person`'s field-level default should be used" ); assert_eq!(person.name.middle, "T"); assert_eq!(person.name.last, "Doe"); } } mod implicit_default { use darling::{util::Flag, FromDeriveInput}; use syn::parse_quote; // No use of `darling(default)` here at all! // This struct will fill in missing fields using FromMeta::from_none. #[derive(FromDeriveInput)] #[darling(attributes(person))] struct Person { first_name: String, last_name: Option, lefty: Flag, } #[test] fn missing_fields_fill() { let person = Person::from_derive_input(&parse_quote! { #[person(first_name = "James")] struct Foo; }) .unwrap(); assert_eq!(person.first_name, "James"); assert_eq!(person.last_name, None); assert!(!person.lefty.is_present()); } } /// Test that a field-level implicit default using FromMeta::from_none is superseded /// by the parent declaring `#[darling(default)]`. mod overridden_implicit_default { use darling::{util::Flag, FromDeriveInput}; use syn::parse_quote; #[derive(FromDeriveInput)] #[darling(default, attributes(person))] struct Person { first_name: String, last_name: Option, lefty: Flag, } impl Default for Person { fn default() -> Self { Self { first_name: "Jane".into(), last_name: Some("Doe".into()), lefty: Flag::default(), } } } #[test] fn fill_missing() { let person = Person::from_derive_input(&parse_quote!( #[person(last_name = "Archer")] struct Foo; )) .unwrap(); assert_eq!(person.first_name, "Jane"); assert_eq!(person.last_name, Some("Archer".into())); assert!(!person.lefty.is_present()); } } darling-0.20.10/tests/enums_default.rs000064400000000000000000000013641046102023000157530ustar 00000000000000use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(Debug, FromMeta, PartialEq, Eq)] enum Dolor { Sit, #[darling(word)] Amet, } impl Default for Dolor { fn default() -> Self { Dolor::Sit } } #[derive(FromDeriveInput)] #[darling(attributes(hello))] struct Receiver { #[darling(default)] example: Dolor, } #[test] fn missing_meta() { let di = Receiver::from_derive_input(&parse_quote! { #[hello] struct Example; }) .unwrap(); assert_eq!(Dolor::Sit, di.example); } #[test] fn empty_meta() { let di = Receiver::from_derive_input(&parse_quote! { #[hello(example)] struct Example; }) .unwrap(); assert_eq!(Dolor::Amet, di.example); } darling-0.20.10/tests/enums_newtype.rs000064400000000000000000000052611046102023000160220ustar 00000000000000use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(Debug, Default, PartialEq, Eq, FromMeta)] #[darling(default)] pub struct Amet { hello: bool, world: String, } #[derive(Debug, PartialEq, Eq, FromMeta)] #[darling(rename_all = "snake_case")] pub enum Lorem { Ipsum(bool), Dolor(String), OptDolor(Option), Sit(Amet), } #[derive(Debug, PartialEq, Eq, FromDeriveInput)] #[darling(attributes(hello))] pub struct Holder { lorem: Lorem, } impl PartialEq 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 option_literal() { let holder = Holder::from_derive_input(&parse_quote! { #[hello(lorem(opt_dolor = "Hello"))] struct Bar; }) .unwrap(); assert_eq!(holder.lorem, Lorem::OptDolor(Some("Hello".into()))); } /// Make sure newtype variants whose field's type's `from_none` return /// a `Some` can be used in key-value form. #[test] fn option_word_only() { let holder = Holder::from_derive_input(&parse_quote! { #[hello(lorem = "opt_dolor")] struct Bar; }) .unwrap(); assert_eq!(holder.lorem, Lorem::OptDolor(None)); } /// Make sure that newtype variants which don't produce a from_none value /// do not allow the word form. #[test] #[should_panic] fn word_only_fails_for_non_option() { Holder::from_derive_input(&parse_quote! { #[hello(lorem = "dolor")] struct Bar; }) .unwrap(); } #[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(); } darling-0.20.10/tests/enums_struct.rs000064400000000000000000000004451046102023000156520ustar 00000000000000#![allow(dead_code)] //! Test expansion of enums which have struct variants. use darling::FromMeta; #[derive(Debug, FromMeta)] #[darling(rename_all = "snake_case")] enum Message { Hello { user: String, silent: bool }, Ping, Goodbye { user: String }, } #[test] fn expansion() {} darling-0.20.10/tests/enums_unit.rs000064400000000000000000000003601046102023000153010ustar 00000000000000//! Test expansion of enum variants which have no associated data. use darling::FromMeta; #[derive(Debug, FromMeta)] #[darling(rename_all = "snake_case")] enum Pattern { Owned, Immutable, Mutable, } #[test] fn expansion() {} darling-0.20.10/tests/error.rs000064400000000000000000000022731046102023000142510ustar 00000000000000//! In case of bad input, parsing should fail. The error should have locations set in derived implementations. // The use of fields in debug print commands does not count as "used", // which causes the fields to trigger an unwanted dead code warning. #![allow(dead_code)] use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(Debug, FromMeta)] struct Dolor { #[darling(rename = "amet")] sit: bool, world: bool, } #[derive(Debug, FromDeriveInput)] #[darling(from_ident, attributes(hello))] struct Lorem { ident: syn::Ident, ipsum: Dolor, } impl From 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()); } darling-0.20.10/tests/flatten.rs000064400000000000000000000127041046102023000145550ustar 00000000000000use darling::{util::Flag, FromDeriveInput, FromMeta}; use proc_macro2::Ident; use syn::parse_quote; #[derive(FromMeta)] struct Vis { public: Flag, private: Flag, } #[derive(FromDeriveInput)] #[darling(attributes(sample))] struct Example { ident: Ident, label: String, #[darling(flatten)] visibility: Vis, } #[test] fn happy_path() { let di = Example::from_derive_input(&parse_quote! { #[sample(label = "Hello", public)] struct Demo {} }); let parsed = di.unwrap(); assert_eq!(parsed.ident, "Demo"); assert_eq!(&parsed.label, "Hello"); assert!(parsed.visibility.public.is_present()); assert!(!parsed.visibility.private.is_present()); } #[test] fn unknown_field_errors() { let errors = Example::from_derive_input(&parse_quote! { #[sample(label = "Hello", republic)] struct Demo {} }) .map(|_| "Should have failed") .unwrap_err(); assert_eq!(errors.len(), 1); } /// This test demonstrates flatten being used recursively. /// Fields are expected to be consumed by the outermost matching struct. #[test] fn recursive_flattening() { #[derive(FromMeta)] struct Nested2 { above: isize, below: isize, port: Option, } #[derive(FromMeta)] struct Nested1 { port: isize, starboard: isize, #[darling(flatten)] z_axis: Nested2, } #[derive(FromMeta)] struct Nested0 { fore: isize, aft: isize, #[darling(flatten)] cross_section: Nested1, } #[derive(FromDeriveInput)] #[darling(attributes(boat))] struct BoatPosition { #[darling(flatten)] pos: Nested0, } let parsed = BoatPosition::from_derive_input(&parse_quote! { #[boat(fore = 1, aft = 1, port = 10, starboard = 50, above = 20, below = -3)] struct Demo; }) .unwrap(); assert_eq!(parsed.pos.fore, 1); assert_eq!(parsed.pos.aft, 1); assert_eq!(parsed.pos.cross_section.port, 10); assert_eq!(parsed.pos.cross_section.starboard, 50); assert_eq!(parsed.pos.cross_section.z_axis.above, 20); assert_eq!(parsed.pos.cross_section.z_axis.below, -3); // This should be `None` because the `port` field in `Nested1` consumed // the field before the leftovers were passed to `Nested2::from_list`. assert_eq!(parsed.pos.cross_section.z_axis.port, None); } /// This test confirms that a collection - in this case a HashMap - can /// be used with `flatten`. #[test] fn flattening_into_hashmap() { #[derive(FromDeriveInput)] #[darling(attributes(ca))] struct Catchall { hello: String, volume: usize, #[darling(flatten)] others: std::collections::HashMap, } let parsed = Catchall::from_derive_input(&parse_quote! { #[ca(hello = "World", volume = 10, first_name = "Alice", second_name = "Bob")] struct Demo; }) .unwrap(); assert_eq!(parsed.hello, "World"); assert_eq!(parsed.volume, 10); assert_eq!(parsed.others.len(), 2); } #[derive(FromMeta)] #[allow(dead_code)] struct Person { first: String, last: String, parent: Option>, } #[derive(FromDeriveInput)] #[darling(attributes(v))] #[allow(dead_code)] struct Outer { #[darling(flatten)] owner: Person, #[darling(default)] blast: bool, } /// This test makes sure that field names from parent structs are not inappropriately /// offered as alternates for unknown field errors in child structs. /// /// A naive implementation that tried to offer all the flattened fields for "did you mean" /// could inspect all errors returned by the flattened field's `from_list` call and add the /// parent's field names as alternates to all unknown field errors. /// /// THIS WOULD BE INCORRECT. Those unknown field errors may have already come from /// child fields within the flattened struct, where the parent's field names are not valid. #[test] fn do_not_suggest_invalid_alts() { let errors = Outer::from_derive_input(&parse_quote! { #[v(first = "Hello", last = "World", parent(first = "Hi", last = "Earth", blasts = "off"))] struct Demo; }) .map(|_| "Should have failed") .unwrap_err() .to_string(); assert!( !errors.contains("`blast`"), "Should not contain `blast`: {}", errors ); } #[test] #[cfg(feature = "suggestions")] fn suggest_valid_parent_alts() { let errors = Outer::from_derive_input(&parse_quote! { #[v(first = "Hello", bladt = false, last = "World", parent(first = "Hi", last = "Earth"))] struct Demo; }) .map(|_| "Should have failed") .unwrap_err() .to_string(); assert!( errors.contains("`blast`"), "Should contain `blast` as did-you-mean suggestion: {}", errors ); } /// Make sure that flatten works with smart pointer types, e.g. `Box`. /// /// The generated `flatten` impl directly calls `FromMeta::from_list` /// rather than calling `from_meta`, and the default impl of `from_list` /// will return an unsupported format error; this test ensures that the /// smart pointer type is properly forwarding the `from_list` call. #[test] fn flattening_to_box() { #[derive(FromDeriveInput)] #[darling(attributes(v))] struct Example { #[darling(flatten)] items: Box, } let when_omitted = Example::from_derive_input(&parse_quote! { struct Demo; }) .unwrap(); assert!(!when_omitted.items.public.is_present()); } darling-0.20.10/tests/flatten_error_accumulation.rs000064400000000000000000000017711046102023000205340ustar 00000000000000use darling::{util::Flag, Error, FromDeriveInput, FromMeta}; use proc_macro2::Ident; use syn::parse_quote; #[derive(FromMeta)] #[darling(and_then = Self::validate)] struct Vis { public: Flag, private: Flag, } impl Vis { fn validate(self) -> darling::Result { if self.public.is_present() && self.private.is_present() { return Err(Error::custom("Cannot be both public and private")); } Ok(self) } } #[derive(FromDeriveInput)] #[darling(attributes(sample))] #[allow(dead_code)] struct Example { ident: Ident, label: String, volume: usize, #[darling(flatten)] visibility: Vis, } #[test] fn many_errors() { let e = Example::from_derive_input(&parse_quote! { #[sample(volume = 10, public, private)] struct Demo {} }) .map(|_| "Should have failed") .unwrap_err(); // We are expecting an error from the Vis::validate method and an error for the // missing `label` field. assert_eq!(e.len(), 2); } darling-0.20.10/tests/flatten_from_field.rs000064400000000000000000000040201046102023000167330ustar 00000000000000use darling::{ast, util::Ignored, FromDeriveInput, FromField, FromMeta}; use proc_macro2::{Ident, Span}; use syn::parse_quote; #[derive(FromMeta)] struct Vis { #[darling(default)] public: bool, #[darling(default)] private: bool, } #[derive(FromField)] #[darling(attributes(v))] struct Field { ident: Option, example: Option, #[darling(flatten)] visibility: Vis, } #[derive(FromDeriveInput)] #[darling(attributes(v))] struct Input { data: ast::Data, } #[test] fn field_flattens() { let di = Input::from_derive_input(&parse_quote! { struct Demo { #[v(public, example = "world")] hello: String } }) .unwrap(); let fields = di.data.take_struct().unwrap(); let first_field = fields.into_iter().next().unwrap(); assert_eq!( first_field.ident, Some(Ident::new("hello", Span::call_site())) ); assert!(first_field.visibility.public); assert!(!first_field.visibility.private); assert_eq!(first_field.example.unwrap(), "world"); } #[test] fn field_flattens_with_no_field_level_attributes() { let di = Input::from_derive_input(&parse_quote! { struct Demo { hello: String } }) .unwrap(); let fields = di.data.take_struct().unwrap(); let first_field = fields.into_iter().next().unwrap(); assert_eq!( first_field.ident, Some(Ident::new("hello", Span::call_site())) ); assert!(!first_field.visibility.public); assert!(!first_field.visibility.private); assert_eq!(first_field.example, None); } #[test] fn field_flattens_across_attributes() { let di = Input::from_derive_input(&parse_quote! { struct Demo { #[v(public)] #[v(private)] hello: String } }) .unwrap(); let fields = di.data.take_struct().unwrap(); let first_field = fields.into_iter().next().unwrap(); assert!(first_field.visibility.public); assert!(first_field.visibility.private); } darling-0.20.10/tests/forward_attrs_to_from_attributes.rs000064400000000000000000000010461046102023000217710ustar 00000000000000use darling::FromAttributes; use syn::parse_quote; #[derive(Default, darling::FromAttributes)] #[darling(attributes(builder), forward_attrs)] struct Params { default: Option, attrs: Vec, } #[test] fn forward_attrs_with_field() { let input: syn::DeriveInput = parse_quote! { #[doc = "Hello"] #[builder(default = 15)] struct Example; }; let parsed = Params::from_attributes(&input.attrs).unwrap(); assert!(parsed.default.is_some()); assert_eq!(parsed.attrs.len(), 1); } darling-0.20.10/tests/from_generics.rs000064400000000000000000000113531046102023000157410ustar 00000000000000//! Tests for `FromGenerics`, and - indirectly - `FromGenericParam`. //! These tests assume `FromTypeParam` is working and only look at whether the wrappers for magic //! fields are working as expected. use darling::{ ast::{self, GenericParamExt}, util::{Ignored, WithOriginal}, FromDeriveInput, FromTypeParam, Result, }; #[derive(FromDeriveInput)] #[darling(attributes(lorem))] struct MyReceiver { pub generics: ast::Generics>, } #[derive(FromTypeParam)] #[darling(attributes(lorem))] struct MyTypeParam { pub ident: syn::Ident, #[darling(default)] pub foo: bool, pub bar: Option, } fn fdi(src: &str) -> Result { FromDeriveInput::from_derive_input(&syn::parse_str(src).expect("Source parses")) } /// Verify that `ast::Generics` is populated correctly when there is no generics declaration #[test] fn no_generics() { let rec: MyReceiver = fdi("struct Baz;").expect("Input is well-formed"); assert!(rec.generics.where_clause.is_none()); assert_eq!(rec.generics.params.len(), 0); } #[test] #[allow(clippy::bool_assert_comparison)] fn expand_some() { let rec: MyReceiver = fdi(r#" struct Baz< 'a, #[lorem(foo)] T, #[lorem(bar = "x")] U: Eq + ?Sized >(&'a T, U); "#) .expect("Input is well-formed"); assert!(rec.generics.where_clause.is_none()); // Make sure we've preserved the lifetime param, though we don't do anything with it. assert!(rec.generics.params[0].as_lifetime_param().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; "#) .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>, 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; "#) .expect("Input is well-formed"); // Make sure we haven't lost anything in the conversion assert_eq!(rec.generics.parsed.params.len(), 3); assert_eq!(rec.generics.original.params.len(), 3); let parsed_t: &MyTypeParam = rec.generics.parsed.params[1] .as_type_param() .expect("Second argument should be type param"); // Make sure the first type param in each case is T assert_eq!(parsed_t.ident, "T"); assert_eq!( rec.generics .original .type_params() .next() .expect("First type param should exist") .ident, "T" ); // Make sure we actually parsed the first type param assert!(parsed_t.foo); assert!(parsed_t.bar.is_none()); } /// Make sure generics can be ignored #[test] fn ignored() { #[derive(FromDeriveInput)] struct IgnoredReceiver { generics: Ignored, } let rec: IgnoredReceiver = fdi(r#" struct Baz< 'a, #[lorem(foo)] T, #[lorem(bar = "x")] U: Eq + ?Sized >(&'a T, U) where T: Into; "#) .expect("Input is well-formed"); assert_eq!(Ignored, rec.generics); } darling-0.20.10/tests/from_meta.rs000064400000000000000000000047621046102023000150760ustar 00000000000000use darling::{Error, FromMeta}; use syn::parse_quote; #[derive(Debug, FromMeta)] struct Meta { #[darling(default)] meta1: Option, #[darling(default)] meta2: bool, } #[test] fn nested_meta_meta_value() { let meta = Meta::from_list(&[parse_quote! { meta1 = "thefeature" }]) .unwrap(); assert_eq!(meta.meta1, Some("thefeature".to_string())); assert!(!meta.meta2); } #[test] fn nested_meta_meta_bool() { let meta = Meta::from_list(&[parse_quote! { meta2 }]) .unwrap(); assert_eq!(meta.meta1, None); assert!(meta.meta2); } #[test] fn nested_meta_lit_string_errors() { let err = Meta::from_list(&[parse_quote! { "meta2" }]) .unwrap_err(); assert_eq!( err.to_string(), Error::unsupported_format("literal").to_string() ); } #[test] fn nested_meta_lit_integer_errors() { let err = Meta::from_list(&[parse_quote! { 2 }]) .unwrap_err(); assert_eq!( err.to_string(), Error::unsupported_format("literal").to_string() ); } #[test] fn nested_meta_lit_bool_errors() { let err = Meta::from_list(&[parse_quote! { true }]) .unwrap_err(); assert_eq!( err.to_string(), Error::unsupported_format("literal").to_string() ); } /// Tests behavior of FromMeta implementation for enums. mod enum_impl { use darling::{Error, FromMeta}; use syn::parse_quote; /// A playback volume. #[derive(Debug, Clone, Copy, PartialEq, Eq, FromMeta)] enum Volume { Normal, Low, High, #[darling(rename = "dB")] Decibels(u8), } #[test] fn string_for_unit_variant() { let volume = Volume::from_string("low").unwrap(); assert_eq!(volume, Volume::Low); } #[test] fn single_value_list() { let unit_variant = Volume::from_list(&[parse_quote!(high)]).unwrap(); assert_eq!(unit_variant, Volume::High); let newtype_variant = Volume::from_list(&[parse_quote!(dB = 100)]).unwrap(); assert_eq!(newtype_variant, Volume::Decibels(100)); } #[test] fn empty_list_errors() { let err = Volume::from_list(&[]).unwrap_err(); assert_eq!(err.to_string(), Error::too_few_items(1).to_string()); } #[test] fn multiple_values_list_errors() { let err = Volume::from_list(&[parse_quote!(low), parse_quote!(dB = 20)]).unwrap_err(); assert_eq!(err.to_string(), Error::too_many_items(1).to_string()); } } darling-0.20.10/tests/from_type_param.rs000064400000000000000000000026341046102023000163050ustar 00000000000000use darling::FromTypeParam; use syn::{parse_quote, DeriveInput, GenericParam, Ident, TypeParam}; #[derive(FromTypeParam)] #[darling(attributes(lorem), from_ident)] struct Lorem { ident: Ident, bounds: Vec, foo: bool, bar: Option, } impl From for Lorem { fn from(ident: Ident) -> Self { Lorem { ident, foo: false, bar: None, bounds: Default::default(), } } } fn extract_type(param: &GenericParam) -> &TypeParam { match *param { GenericParam::Type(ref ty) => ty, _ => unreachable!("Not a type param"), } } #[test] #[allow(clippy::bool_assert_comparison)] fn expand_many() { let di: DeriveInput = parse_quote! { struct Baz< #[lorem(foo)] T, #[lorem(bar = "x")] U: Eq + ?Sized >(T, U); }; let params = di.generics.params; { let ty = extract_type(¶ms[0]); let lorem = Lorem::from_type_param(ty).unwrap(); assert_eq!(lorem.ident, "T"); assert_eq!(lorem.foo, true); assert_eq!(lorem.bar, None); } { let ty = extract_type(¶ms[1]); let lorem = Lorem::from_type_param(ty).unwrap(); assert_eq!(lorem.ident, "U"); assert_eq!(lorem.foo, false); assert_eq!(lorem.bar, Some("x".to_string())); assert_eq!(lorem.bounds.len(), 2); } } darling-0.20.10/tests/from_type_param_default.rs000064400000000000000000000025731046102023000200130ustar 00000000000000use darling::FromTypeParam; use syn::{parse_quote, DeriveInput, GenericParam, TypeParam}; #[derive(Default, FromTypeParam)] #[darling(attributes(lorem), default)] struct Lorem { foo: bool, bar: Option, default: Option, } fn extract_type(param: &GenericParam) -> &TypeParam { match *param { GenericParam::Type(ref ty) => ty, _ => unreachable!("Not a type param"), } } #[test] #[allow(clippy::bool_assert_comparison)] fn expand_many() { let di: DeriveInput = parse_quote! { struct Baz< #[lorem(foo)] T, #[lorem(bar = "x")] U: Eq + ?Sized, #[lorem(foo = false)] V = (), >(T, U, V); }; let params = di.generics.params; { let ty = extract_type(¶ms[0]); let lorem = Lorem::from_type_param(ty).unwrap(); assert_eq!(lorem.foo, true); assert_eq!(lorem.bar, None); } { let ty = extract_type(¶ms[1]); let lorem = Lorem::from_type_param(ty).unwrap(); assert_eq!(lorem.foo, false); assert_eq!(lorem.bar, Some("x".to_string())); assert!(lorem.default.is_none()); } { let ty = extract_type(¶ms[2]); let lorem = Lorem::from_type_param(ty).unwrap(); assert_eq!(lorem.foo, false); assert_eq!(lorem.bar, None); assert!(lorem.default.is_some()); } } darling-0.20.10/tests/from_variant.rs000064400000000000000000000025361046102023000156110ustar 00000000000000use darling::FromVariant; use syn::{spanned::Spanned, Expr, ExprLit, LitInt}; #[derive(FromVariant)] #[darling(from_ident, attributes(hello))] #[allow(dead_code)] pub struct Lorem { ident: syn::Ident, into: Option, skip: Option, discriminant: Option, fields: darling::ast::Fields, } impl From for Lorem { fn from(ident: syn::Ident) -> Self { Lorem { ident, into: Default::default(), skip: Default::default(), discriminant: None, fields: darling::ast::Style::Unit.into(), } } } #[test] fn discriminant() { let input: syn::DeriveInput = syn::parse_str( r#" pub enum Test { Works = 1, AlsoWorks = 2, } "#, ) .unwrap(); let span = input.span(); if let syn::Data::Enum(enm) = input.data { let lorem = Lorem::from_variant( enm.variants .first() .expect("Hardcoded input has one variant"), ) .expect("FromVariant can process the discriminant"); assert_eq!( lorem.discriminant, Some(Expr::Lit(ExprLit { attrs: vec![], lit: LitInt::new("1", span).into(), })) ) } else { panic!("Data should be enum"); } } darling-0.20.10/tests/generics.rs000064400000000000000000000006531046102023000147170ustar 00000000000000#![allow(dead_code)] use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(Debug, Clone, FromMeta)] struct Wrapper(pub T); #[derive(Debug, FromDeriveInput)] #[darling(attributes(hello))] struct Foo { lorem: Wrapper, } #[test] fn expansion() { let di = parse_quote! { #[hello(lorem = "Hello")] pub struct Foo; }; Foo::::from_derive_input(&di).unwrap(); } darling-0.20.10/tests/happy_path.rs000064400000000000000000000027141046102023000152550ustar 00000000000000use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(Default, FromMeta, PartialEq, Debug)] #[darling(default)] struct Lorem { ipsum: bool, dolor: Option, } #[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()), } } ); } darling-0.20.10/tests/hash_map.rs000064400000000000000000000016401046102023000146750ustar 00000000000000use std::collections::HashMap; use darling::FromMeta; use syn::{parse_quote, Attribute, Path}; #[derive(Debug, FromMeta, PartialEq, Eq)] struct MapValue { name: String, #[darling(default)] option: bool, } #[test] fn parse_map() { let attr: Attribute = parse_quote! { #[foo(first(name = "Hello", option), the::second(name = "Second"))] }; let meta = attr.meta; let map: HashMap = FromMeta::from_meta(&meta).unwrap(); let comparison: HashMap = vec![ ( parse_quote!(first), MapValue { name: "Hello".into(), option: true, }, ), ( parse_quote!(the::second), MapValue { name: "Second".into(), option: false, }, ), ] .into_iter() .collect(); assert_eq!(comparison, map); } darling-0.20.10/tests/multiple.rs000064400000000000000000000011331046102023000147450ustar 00000000000000use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(FromDeriveInput)] #[darling(attributes(hello))] #[allow(dead_code)] struct Lorem { ident: syn::Ident, ipsum: Ipsum, } #[derive(FromMeta)] struct Ipsum { #[darling(multiple)] dolor: Vec, } #[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()] ); } darling-0.20.10/tests/newtype.rs000064400000000000000000000010711046102023000146060ustar 00000000000000//! A newtype struct should be able to derive `FromMeta` if its member implements it. use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(Debug, FromMeta, PartialEq, Eq)] struct Lorem(bool); #[derive(Debug, FromDeriveInput)] #[darling(attributes(newtype))] struct DemoContainer { lorem: Lorem, } #[test] fn generated() { let di = parse_quote! { #[derive(Baz)] #[newtype(lorem = false)] pub struct Foo; }; let c = DemoContainer::from_derive_input(&di).unwrap(); assert_eq!(c.lorem, Lorem(false)); } darling-0.20.10/tests/skip.rs000064400000000000000000000032211046102023000140600ustar 00000000000000//! Test that skipped fields are not read into structs when they appear in input. use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(Debug, PartialEq, Eq, FromDeriveInput)] #[darling(attributes(skip_test))] pub struct Lorem { ipsum: String, #[darling(skip)] dolor: u8, } /// Verify variant-level and field-level skip work correctly for enums. #[derive(Debug, FromMeta)] pub enum Sit { Amet(bool), #[darling(skip)] Foo { hello: bool, }, Bar { hello: bool, #[darling(skip)] world: u8, }, } #[test] fn verify_skipped_field_not_required() { let di = parse_quote! { #[skip_test(ipsum = "Hello")] struct Baz; }; assert_eq!( Lorem::from_derive_input(&di).unwrap(), Lorem { ipsum: "Hello".to_string(), dolor: 0, } ); } /// This test verifies that a skipped field will still prefer an explicit default /// over the default that would come from its field type. It would be incorrect for /// `Defaulting::from_derive_input` to fail here, and it would be wrong for the value /// of `dolor` to be `None`. #[test] fn verify_default_supersedes_from_none() { fn default_dolor() -> Option { Some(2) } #[derive(Debug, PartialEq, Eq, FromDeriveInput)] #[darling(attributes(skip_test))] pub struct Defaulting { #[darling(skip, default = "default_dolor")] dolor: Option, } let di = parse_quote! { #[skip_test] struct Baz; }; assert_eq!( Defaulting::from_derive_input(&di).unwrap(), Defaulting { dolor: Some(2) } ) } darling-0.20.10/tests/split_declaration.rs000064400000000000000000000031601046102023000166140ustar 00000000000000//! When input is split across multiple attributes on one element, //! darling should collapse that into one struct. use darling::{Error, FromDeriveInput}; use syn::parse_quote; #[derive(Debug, FromDeriveInput, PartialEq, Eq)] #[darling(attributes(split))] struct Lorem { foo: String, bar: bool, } #[test] fn split_attributes_accrue_to_instance() { let di = parse_quote! { #[split(foo = "Hello")] #[split(bar)] pub struct Foo; }; let parsed = Lorem::from_derive_input(&di).unwrap(); assert_eq!( parsed, Lorem { foo: "Hello".to_string(), bar: true, } ); } #[test] fn duplicates_across_split_attrs_error() { let di = parse_quote! { #[split(foo = "Hello")] #[split(foo = "World", bar)] pub struct Foo; }; let pr = Lorem::from_derive_input(&di).unwrap_err(); assert!(pr.has_span()); assert_eq!(pr.to_string(), Error::duplicate_field("foo").to_string()); } #[test] fn multiple_errors_accrue_to_instance() { let di = parse_quote! { #[split(foo = "Hello")] #[split(foo = "World")] pub struct Foo; }; let pr = Lorem::from_derive_input(&di); let err: Error = pr.unwrap_err(); assert_eq!(2, err.len()); let mut errs = err.into_iter().peekable(); assert_eq!( errs.peek().unwrap().to_string(), Error::duplicate_field("foo").to_string() ); assert!(errs.next().unwrap().has_span()); assert_eq!( errs.next().unwrap().to_string(), Error::missing_field("bar").to_string() ); assert!(errs.next().is_none()); } darling-0.20.10/tests/suggestions.rs000064400000000000000000000020541046102023000154670ustar 00000000000000#![allow(dead_code)] #![cfg(feature = "suggestions")] use darling::{FromDeriveInput, FromMeta}; use syn::parse_quote; #[derive(Debug, FromDeriveInput)] #[darling(attributes(suggest))] struct Lorem { ipsum: String, dolor: Dolor, // This field is included to make sure that skipped fields aren't suggested. #[darling(skip)] amet: bool, } #[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")); } #[test] fn dont_suggest_skipped_field() { let input: syn::DeriveInput = parse_quote! { #[suggest(ipsum = "Hello", dolor(sit), amt)] pub struct Foo; }; let result = Lorem::from_derive_input(&input).unwrap_err(); assert_eq!(1, result.len()); assert!(!format!("{}", result).contains("amet")); } darling-0.20.10/tests/supports.rs000064400000000000000000000047511046102023000150220ustar 00000000000000use darling::{ast, FromDeriveInput, FromVariant}; #[derive(Debug, FromDeriveInput)] #[darling(attributes(from_variants), supports(enum_any))] pub struct Container { // The second type parameter can be anything that implements FromField, since // FromDeriveInput will produce an error if given a struct. data: ast::Data, } #[derive(Default, Debug, FromVariant)] #[darling(default, attributes(from_variants), supports(newtype, unit))] pub struct Variant { into: Option, skip: Option, } #[derive(Debug, FromDeriveInput)] #[darling(attributes(from_struct), supports(struct_named))] pub struct StructContainer { // The second type parameter can be anything that implements FromVariant, since // FromDeriveInput will produce an error if given an enum. data: ast::Data<(), syn::Field>, } mod source { use syn::{parse_quote, DeriveInput}; pub fn newtype_enum() -> DeriveInput { parse_quote! { enum Hello { World(bool), String(String), } } } pub fn named_field_enum() -> DeriveInput { parse_quote! { enum Hello { Foo(u16), World { name: String }, } } } pub fn empty_enum() -> DeriveInput { parse_quote! { enum Hello {} } } pub fn named_struct() -> DeriveInput { parse_quote! { struct Hello { world: bool, } } } pub fn tuple_struct() -> DeriveInput { parse_quote! { struct Hello(String, bool); } } } #[test] fn enum_newtype_or_unit() { // Should pass let container = Container::from_derive_input(&source::newtype_enum()).unwrap(); assert!(container.data.is_enum()); // Should error Container::from_derive_input(&source::named_field_enum()).unwrap_err(); Container::from_derive_input(&source::named_struct()).unwrap_err(); } #[test] fn struct_named() { // Should pass let container = StructContainer::from_derive_input(&source::named_struct()).unwrap(); assert!(container.data.is_struct()); // Should fail StructContainer::from_derive_input(&source::tuple_struct()).unwrap_err(); StructContainer::from_derive_input(&source::named_field_enum()).unwrap_err(); StructContainer::from_derive_input(&source::newtype_enum()).unwrap_err(); StructContainer::from_derive_input(&source::empty_enum()).unwrap_err(); } darling-0.20.10/tests/unsupported_attributes.rs000064400000000000000000000021551046102023000177550ustar 00000000000000use darling::FromDeriveInput; use syn::{parse_quote, Ident, LitStr, Path}; #[derive(Debug, FromDeriveInput)] #[darling(supports(struct_unit), attributes(bar))] pub struct Bar { pub ident: Ident, pub st: Path, pub file: LitStr, } /// Per [#96](https://github.com/TedDriggs/darling/issues/96), make sure that an /// attribute which isn't a valid meta gets an error. /// Properties can be split across multiple attributes; this test ensures that one /// non-meta attribute does not interfere with the parsing of other, well-formed attributes. #[test] fn non_meta_attribute_does_not_block_others() { let di = parse_quote! { #[derive(Bar)] #[bar(st = RocketEngine: Debug)] #[bar(file = "motors/example_6.csv")] pub struct EstesC6; }; let errors: darling::Error = Bar::from_derive_input(&di).unwrap_err().flatten(); // The number of errors here is 2: // - The parsing error caused by a where-clause body where it doesn't belong // - The missing `st` value because the parsing failure blocked that attribute from // being read. assert_eq!(2, errors.len()); }