chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "82a51e0b65b158de02ffb5d753ea4cd03529743b"
},
"path_in_vcs": "core"
}

68
vendor/darling_core/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,68 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "darling_core"
version = "0.20.11"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"

61
vendor/darling_core/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,61 @@
# 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_core"
version = "0.20.11"
authors = ["Ted Driggs <ted.driggs@outlook.com>"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = """
Helper crate for proc-macro library for reading attributes into structs when
implementing custom derives. Use https://crates.io/crates/darling in your code.
"""
readme = false
license = "MIT"
repository = "https://github.com/TedDriggs/darling"
[lib]
name = "darling_core"
path = "src/lib.rs"
[dependencies.fnv]
version = "1.0.7"
[dependencies.ident_case]
version = "1.0.1"
[dependencies.proc-macro2]
version = "1.0.86"
[dependencies.quote]
version = "1.0.18"
[dependencies.strsim]
version = "0.11.1"
optional = true
[dependencies.syn]
version = "2.0.15"
features = [
"full",
"extra-traits",
]
[features]
diagnostics = []
suggestions = ["strsim"]

21
vendor/darling_core/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Ted Driggs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

517
vendor/darling_core/src/ast/data.rs vendored Normal file
View File

@@ -0,0 +1,517 @@
use std::{slice, vec};
use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens};
use syn::ext::IdentExt;
use syn::parse::Parser;
use syn::spanned::Spanned;
use syn::Token;
use crate::usage::{
self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams,
};
use crate::{Error, FromField, FromVariant, Result};
/// A struct or enum body.
///
/// `V` is the type which receives any encountered variants, and `F` receives struct fields.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Data<V, F> {
Enum(Vec<V>),
Struct(Fields<F>),
}
impl<V, F> Data<V, F> {
/// Creates an empty body of the same shape as the passed-in body.
///
/// # Panics
/// This function will panic if passed `syn::Data::Union`.
pub fn empty_from(src: &syn::Data) -> Self {
match *src {
syn::Data::Enum(_) => Data::Enum(vec![]),
syn::Data::Struct(ref vd) => Data::Struct(Fields::empty_from(&vd.fields)),
syn::Data::Union(_) => panic!("Unions are not supported"),
}
}
/// Creates an empty body of the same shape as the passed-in body.
///
/// `darling` does not support unions; calling this function with a union body will return an error.
pub fn try_empty_from(src: &syn::Data) -> Result<Self> {
match *src {
syn::Data::Enum(_) => Ok(Data::Enum(vec![])),
syn::Data::Struct(ref vd) => Ok(Data::Struct(Fields::empty_from(&vd.fields))),
// This deliberately doesn't set a span on the error message, as the error is most useful if
// applied to the call site of the offending macro. Given that the message is very generic,
// putting it on the union keyword ends up being confusing.
syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
}
}
/// Creates a new `Data<&'a V, &'a F>` instance from `Data<V, F>`.
pub fn as_ref(&self) -> Data<&V, &F> {
match *self {
Data::Enum(ref variants) => Data::Enum(variants.iter().collect()),
Data::Struct(ref data) => Data::Struct(data.as_ref()),
}
}
/// Applies a function `V -> U` on enum variants, if this is an enum.
pub fn map_enum_variants<T, U>(self, map: T) -> Data<U, F>
where
T: FnMut(V) -> U,
{
match self {
Data::Enum(v) => Data::Enum(v.into_iter().map(map).collect()),
Data::Struct(f) => Data::Struct(f),
}
}
/// Applies a function `F -> U` on struct fields, if this is a struct.
pub fn map_struct_fields<T, U>(self, map: T) -> Data<V, U>
where
T: FnMut(F) -> U,
{
match self {
Data::Enum(v) => Data::Enum(v),
Data::Struct(f) => Data::Struct(f.map(map)),
}
}
/// Applies a function to the `Fields` if this is a struct.
pub fn map_struct<T, U>(self, mut map: T) -> Data<V, U>
where
T: FnMut(Fields<F>) -> Fields<U>,
{
match self {
Data::Enum(v) => Data::Enum(v),
Data::Struct(f) => Data::Struct(map(f)),
}
}
/// Consumes the `Data`, returning `Fields<F>` if it was a struct.
pub fn take_struct(self) -> Option<Fields<F>> {
match self {
Data::Enum(_) => None,
Data::Struct(f) => Some(f),
}
}
/// Consumes the `Data`, returning `Vec<V>` if it was an enum.
pub fn take_enum(self) -> Option<Vec<V>> {
match self {
Data::Enum(v) => Some(v),
Data::Struct(_) => None,
}
}
/// Returns `true` if this instance is `Data::Enum`.
pub fn is_enum(&self) -> bool {
match *self {
Data::Enum(_) => true,
Data::Struct(_) => false,
}
}
/// Returns `true` if this instance is `Data::Struct`.
pub fn is_struct(&self) -> bool {
!self.is_enum()
}
}
impl<V: FromVariant, F: FromField> Data<V, F> {
/// Attempt to convert from a `syn::Data` instance.
pub fn try_from(body: &syn::Data) -> Result<Self> {
match *body {
syn::Data::Enum(ref data) => {
let mut errors = Error::accumulator();
let items = data
.variants
.iter()
.filter_map(|v| errors.handle(FromVariant::from_variant(v)))
.collect();
errors.finish_with(Data::Enum(items))
}
syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)),
// This deliberately doesn't set a span on the error message, as the error is most useful if
// applied to the call site of the offending macro. Given that the message is very generic,
// putting it on the union keyword ends up being confusing.
syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
}
}
}
impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> {
fn uses_type_params<'a>(
&self,
options: &usage::Options,
type_set: &'a IdentSet,
) -> IdentRefSet<'a> {
match *self {
Data::Struct(ref v) => v.uses_type_params(options, type_set),
Data::Enum(ref v) => v.uses_type_params(options, type_set),
}
}
}
impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> {
fn uses_lifetimes<'a>(
&self,
options: &usage::Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
match *self {
Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes),
Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes),
}
}
}
/// Equivalent to `syn::Fields`, but replaces the AST element with a generic.
#[derive(Debug, Clone)]
pub struct Fields<T> {
pub style: Style,
pub fields: Vec<T>,
span: Option<Span>,
__nonexhaustive: (),
}
impl<T> Fields<T> {
/// Creates a new [`Fields`] struct.
pub fn new(style: Style, fields: Vec<T>) -> Self {
Self {
style,
fields,
span: None,
__nonexhaustive: (),
}
}
/// Adds a [`Span`] to [`Fields`].
pub fn with_span(mut self, span: Span) -> Self {
if self.span.is_none() {
self.span = Some(span);
}
self
}
pub fn empty_from(vd: &syn::Fields) -> Self {
Self::new(vd.into(), Vec::new())
}
/// Splits the `Fields` into its style and fields for further processing.
/// Returns an empty `Vec` for `Unit` data.
pub fn split(self) -> (Style, Vec<T>) {
(self.style, self.fields)
}
/// Returns true if this variant's data makes it a newtype.
pub fn is_newtype(&self) -> bool {
self.style == Style::Tuple && self.len() == 1
}
pub fn is_unit(&self) -> bool {
self.style.is_unit()
}
pub fn is_tuple(&self) -> bool {
self.style.is_tuple()
}
pub fn is_struct(&self) -> bool {
self.style.is_struct()
}
pub fn as_ref(&self) -> Fields<&T> {
Fields {
style: self.style,
fields: self.fields.iter().collect(),
span: self.span,
__nonexhaustive: (),
}
}
pub fn map<F, U>(self, map: F) -> Fields<U>
where
F: FnMut(T) -> U,
{
Fields {
style: self.style,
fields: self.fields.into_iter().map(map).collect(),
span: self.span,
__nonexhaustive: (),
}
}
pub fn iter(&self) -> slice::Iter<'_, T> {
self.fields.iter()
}
/// Returns the number of fields in the structure.
pub fn len(&self) -> usize {
self.fields.len()
}
/// Returns `true` if the `Fields` contains no fields.
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}
impl<F: FromField> Fields<F> {
pub fn try_from(fields: &syn::Fields) -> Result<Self> {
let mut errors = Error::accumulator();
let items = {
match &fields {
syn::Fields::Named(fields) => fields
.named
.iter()
.filter_map(|field| {
errors.handle(FromField::from_field(field).map_err(|err| {
// There should always be an ident here, since this is a collection
// of named fields, but `syn` doesn't prevent someone from manually
// constructing an invalid collection so a guard is still warranted.
if let Some(ident) = &field.ident {
err.at(ident)
} else {
err
}
}))
})
.collect(),
syn::Fields::Unnamed(fields) => fields
.unnamed
.iter()
.filter_map(|field| errors.handle(FromField::from_field(field)))
.collect(),
syn::Fields::Unit => vec![],
}
};
errors.finish()?;
Ok(Self::new(fields.into(), items).with_span(fields.span()))
}
}
impl<T: ToTokens> ToTokens for Fields<T> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let fields = &self.fields;
// An unknown Span should be `Span::call_site()`;
// https://docs.rs/syn/1.0.12/syn/spanned/trait.Spanned.html#tymethod.span
let span = self.span.unwrap_or_else(Span::call_site);
match self.style {
Style::Struct => {
let trailing_comma = {
if fields.is_empty() {
quote!()
} else {
quote!(,)
}
};
tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]);
}
Style::Tuple => {
tokens.extend(quote_spanned![span => ( #(#fields),* )]);
}
Style::Unit => {}
}
}
}
impl<T: PartialEq> PartialEq for Fields<T> {
fn eq(&self, other: &Self) -> bool {
self.style == other.style && self.fields == other.fields
}
}
impl<T: Eq> Eq for Fields<T> {}
impl<T> IntoIterator for Fields<T> {
type Item = T;
type IntoIter = vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<T> From<Style> for Fields<T> {
fn from(style: Style) -> Self {
Self::new(style, Vec::new())
}
}
impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> {
fn from((style, fields): (Style, U)) -> Self {
style.with_fields(fields)
}
}
impl<T: UsesTypeParams> UsesTypeParams for Fields<T> {
fn uses_type_params<'a>(
&self,
options: &usage::Options,
type_set: &'a IdentSet,
) -> IdentRefSet<'a> {
self.fields.uses_type_params(options, type_set)
}
}
impl<T: UsesLifetimes> UsesLifetimes for Fields<T> {
fn uses_lifetimes<'a>(
&self,
options: &usage::Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
self.fields.uses_lifetimes(options, lifetimes)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Style {
Tuple,
Struct,
Unit,
}
impl Style {
pub fn is_unit(self) -> bool {
self == Style::Unit
}
pub fn is_tuple(self) -> bool {
self == Style::Tuple
}
pub fn is_struct(self) -> bool {
self == Style::Struct
}
/// Creates a new `Fields` of the specified style with the passed-in fields.
fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> {
Fields::new(self, fields.into())
}
}
impl From<syn::Fields> for Style {
fn from(vd: syn::Fields) -> Self {
(&vd).into()
}
}
impl From<&syn::Fields> for Style {
fn from(vd: &syn::Fields) -> Self {
match *vd {
syn::Fields::Named(_) => Style::Struct,
syn::Fields::Unnamed(_) => Style::Tuple,
syn::Fields::Unit => Style::Unit,
}
}
}
#[derive(Debug, Clone)]
pub enum NestedMeta {
Meta(syn::Meta),
Lit(syn::Lit),
}
impl NestedMeta {
pub fn parse_meta_list(tokens: TokenStream) -> syn::Result<Vec<Self>> {
syn::punctuated::Punctuated::<NestedMeta, Token![,]>::parse_terminated
.parse2(tokens)
.map(|punctuated| punctuated.into_iter().collect())
}
}
impl syn::parse::Parse for NestedMeta {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
if input.peek(syn::Lit) && !(input.peek(syn::LitBool) && input.peek2(Token![=])) {
input.parse().map(NestedMeta::Lit)
} else if input.peek(syn::Ident::peek_any)
|| input.peek(Token![::]) && input.peek3(syn::Ident::peek_any)
{
input.parse().map(NestedMeta::Meta)
} else {
Err(input.error("expected identifier or literal"))
}
}
}
impl ToTokens for NestedMeta {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
NestedMeta::Meta(meta) => meta.to_tokens(tokens),
NestedMeta::Lit(lit) => lit.to_tokens(tokens),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
// it is not possible to directly convert a TokenStream into syn::Fields, so you have
// to convert the TokenStream into DeriveInput first and then pass the syn::Fields to
// Fields::try_from.
fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> {
Fields::try_from(&{
if let syn::Data::Struct(s) = syn::parse2::<syn::DeriveInput>(input).unwrap().data {
s.fields
} else {
panic!();
}
})
.unwrap()
}
#[test]
fn test_style_eq() {
// `Fields` implements `Eq` manually, so it has to be ensured, that all fields of `Fields`
// implement `Eq`, this test would fail, if someone accidentally removed the Eq
// implementation from `Style`.
struct _AssertEq
where
Style: Eq;
}
#[test]
fn test_fields_to_tokens_struct() {
let reference = quote!(
{
executable: String,
args: Vec<String>,
env: Vec<String>,
index: usize,
optional: Option<String>,
current_dir: String,
}
);
let input = quote!(
struct ExampleTest #reference
);
let fields = token_stream_to_fields(input);
let mut result = quote!();
fields.to_tokens(&mut result);
assert_eq!(result.to_string(), reference.to_string());
}
#[test]
fn test_fields_to_tokens_tuple() {
let reference = quote!((u64, usize, &'a T));
let input = quote!(
struct ExampleTest #reference;
);
let fields = token_stream_to_fields(input);
let mut result = quote!();
fields.to_tokens(&mut result);
assert_eq!(result.to_string(), reference.to_string());
}
}

192
vendor/darling_core/src/ast/generics.rs vendored Normal file
View File

@@ -0,0 +1,192 @@
//! Types for working with generics
use std::iter::Iterator;
use std::slice::Iter;
use crate::{FromGenericParam, FromGenerics, FromTypeParam, Result};
/// Extension trait for `GenericParam` to support getting values by variant.
///
/// # Usage
/// `darling::ast::Generics` needs a way to test its params array in order to iterate over type params.
/// Rather than require callers to use `darling::ast::GenericParam` in all cases, this trait makes that
/// polymorphic.
pub trait GenericParamExt {
/// The type this GenericParam uses to represent type params and their bounds
type TypeParam;
type LifetimeParam;
type ConstParam;
/// If this GenericParam is a type param, get the underlying value.
fn as_type_param(&self) -> Option<&Self::TypeParam> {
None
}
/// If this GenericParam is a lifetime, get the underlying value.
fn as_lifetime_param(&self) -> Option<&Self::LifetimeParam> {
None
}
/// If this GenericParam is a const param, get the underlying value.
fn as_const_param(&self) -> Option<&Self::ConstParam> {
None
}
}
impl GenericParamExt for syn::GenericParam {
type TypeParam = syn::TypeParam;
type LifetimeParam = syn::LifetimeParam;
type ConstParam = syn::ConstParam;
fn as_type_param(&self) -> Option<&Self::TypeParam> {
if let syn::GenericParam::Type(ref val) = *self {
Some(val)
} else {
None
}
}
fn as_lifetime_param(&self) -> Option<&Self::LifetimeParam> {
if let syn::GenericParam::Lifetime(ref val) = *self {
Some(val)
} else {
None
}
}
fn as_const_param(&self) -> Option<&Self::ConstParam> {
if let syn::GenericParam::Const(ref val) = *self {
Some(val)
} else {
None
}
}
}
impl GenericParamExt for syn::TypeParam {
type TypeParam = syn::TypeParam;
type LifetimeParam = ();
type ConstParam = ();
fn as_type_param(&self) -> Option<&Self::TypeParam> {
Some(self)
}
}
/// A mirror of `syn::GenericParam` which is generic over all its contents.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GenericParam<T = syn::TypeParam, L = syn::LifetimeParam, C = syn::ConstParam> {
Type(T),
Lifetime(L),
Const(C),
}
impl<T: FromTypeParam> FromTypeParam for GenericParam<T> {
fn from_type_param(type_param: &syn::TypeParam) -> Result<Self> {
Ok(GenericParam::Type(FromTypeParam::from_type_param(
type_param,
)?))
}
}
impl<T: FromTypeParam> FromGenericParam for GenericParam<T> {
fn from_generic_param(param: &syn::GenericParam) -> Result<Self> {
Ok(match *param {
syn::GenericParam::Type(ref ty) => {
GenericParam::Type(FromTypeParam::from_type_param(ty)?)
}
syn::GenericParam::Lifetime(ref val) => GenericParam::Lifetime(val.clone()),
syn::GenericParam::Const(ref val) => GenericParam::Const(val.clone()),
})
}
}
impl<T, L, C> GenericParamExt for GenericParam<T, L, C> {
type TypeParam = T;
type LifetimeParam = L;
type ConstParam = C;
fn as_type_param(&self) -> Option<&T> {
if let GenericParam::Type(ref val) = *self {
Some(val)
} else {
None
}
}
fn as_lifetime_param(&self) -> Option<&L> {
if let GenericParam::Lifetime(ref val) = *self {
Some(val)
} else {
None
}
}
fn as_const_param(&self) -> Option<&C> {
if let GenericParam::Const(ref val) = *self {
Some(val)
} else {
None
}
}
}
/// A mirror of the `syn::Generics` type which can contain arbitrary representations
/// of params and where clauses.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Generics<P, W = syn::WhereClause> {
pub params: Vec<P>,
pub where_clause: Option<W>,
}
impl<P, W> Generics<P, W> {
pub fn type_params(&self) -> TypeParams<'_, P> {
TypeParams(self.params.iter())
}
}
impl<P: FromGenericParam> FromGenerics for Generics<P> {
fn from_generics(generics: &syn::Generics) -> Result<Self> {
Ok(Generics {
params: generics
.params
.iter()
.map(FromGenericParam::from_generic_param)
.collect::<Result<Vec<P>>>()?,
where_clause: generics.where_clause.clone(),
})
}
}
pub struct TypeParams<'a, P>(Iter<'a, P>);
impl<'a, P: GenericParamExt> Iterator for TypeParams<'a, P> {
type Item = &'a <P as GenericParamExt>::TypeParam;
fn next(&mut self) -> Option<Self::Item> {
let next = self.0.next();
match next {
None => None,
Some(v) => match v.as_type_param() {
Some(val) => Some(val),
None => self.next(),
},
}
}
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::{GenericParam, Generics};
use crate::FromGenerics;
#[test]
fn generics() {
let g: syn::Generics = parse_quote!(<T>);
let deified: Generics<GenericParam<syn::Ident>> = FromGenerics::from_generics(&g).unwrap();
assert!(deified.params.len() == 1);
assert!(deified.where_clause.is_none());
}
}

7
vendor/darling_core/src/ast/mod.rs vendored Normal file
View File

@@ -0,0 +1,7 @@
//! Utility types for working with the AST.
mod data;
mod generics;
pub use self::data::*;
pub use self::generics::{GenericParam, GenericParamExt, Generics};

View File

@@ -0,0 +1,110 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use crate::util::PathList;
use super::ForwardAttrs;
/// Infrastructure for generating an attribute extractor.
pub trait ExtractAttribute {
/// A set of mutable declarations for all members of the implementing type.
fn local_declarations(&self) -> TokenStream;
/// Gets the list of attribute names that should be parsed by the extractor.
fn attr_names(&self) -> &PathList;
fn forward_attrs(&self) -> &ForwardAttrs<'_>;
/// Gets the name used by the generated impl to return to the `syn` item passed as input.
fn param_name(&self) -> TokenStream;
/// Get the tokens to access a borrowed list of attributes where extraction will take place.
///
/// By default, this will be `&#input.attrs` where `#input` is `self.param_name()`.
fn attrs_accessor(&self) -> TokenStream {
let input = self.param_name();
quote!(&#input.attrs)
}
/// Gets the core from-meta-item loop that should be used on matching attributes.
fn core_loop(&self) -> TokenStream;
/// Generates the main extraction loop.
fn extractor(&self) -> TokenStream {
let mut declarations = self.local_declarations();
self.forward_attrs()
.as_declaration()
.to_tokens(&mut declarations);
let will_parse_any = !self.attr_names().is_empty();
// Forwarding requires both that there be some items we would forward,
// and a place that will keep the forwarded items.
let will_fwd_any = self.forward_attrs().will_forward_any();
if !(will_parse_any || will_fwd_any) {
return quote! {
#declarations
};
}
let attrs_accessor = self.attrs_accessor();
// The block for parsing attributes whose names have been claimed by the target
// struct. If no attributes were claimed, this is a pass-through.
let parse_handled = if will_parse_any {
let attr_names = self.attr_names().to_strings();
let core_loop = self.core_loop();
quote!(
#(#attr_names)|* => {
match ::darling::util::parse_attribute_to_meta_list(__attr) {
::darling::export::Ok(__data) => {
match ::darling::export::NestedMeta::parse_meta_list(__data.tokens) {
::darling::export::Ok(ref __items) => {
if __items.is_empty() {
continue;
}
#core_loop
}
::darling::export::Err(__err) => {
__errors.push(__err.into());
}
}
}
// darling was asked to handle this attribute name, but the actual attribute
// isn't one that darling can work with. This either indicates a typing error
// or some misunderstanding of the meta attribute syntax; in either case, the
// caller should get a useful error.
::darling::export::Err(__err) => {
__errors.push(__err);
}
}
}
)
} else {
quote!()
};
let fwd_population = self.forward_attrs().as_value_populator();
// Specifies the behavior for unhandled attributes. They will either be silently ignored or
// forwarded to the inner struct for later analysis.
let forward_unhandled = self.forward_attrs().as_match_arms();
quote!(
#declarations
use ::darling::ToTokens;
for __attr in #attrs_accessor {
// Filter attributes based on name
match ::darling::export::ToString::to_string(&__attr.path().clone().into_token_stream()).as_str() {
#parse_handled
#forward_unhandled
}
}
#fwd_population
)
}
}

View File

@@ -0,0 +1,107 @@
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
use syn::spanned::Spanned;
use crate::options::{ForwardAttrsFilter, ForwardedField};
#[derive(Default)]
pub struct ForwardAttrs<'a> {
pub filter: Option<&'a ForwardAttrsFilter>,
pub field: Option<&'a ForwardedField>,
}
impl ForwardAttrs<'_> {
/// Check if this will forward any attributes; this requires both that
/// there be a filter which can match some attributes and a field to receive them.
pub fn will_forward_any(&self) -> bool {
if let Some(filter) = self.filter {
!filter.is_empty() && self.field.is_some()
} else {
false
}
}
/// Get the field declarations to support attribute forwarding
pub fn as_declaration(&self) -> Option<Declaration<'_>> {
self.field.map(Declaration)
}
/// Get the match arms for attribute matching
pub fn as_match_arms(&self) -> MatchArms<'_> {
MatchArms(self)
}
/// Get the statement that will try to transform forwarded attributes into
/// the result expected by the receiver field.
pub fn as_value_populator(&self) -> Option<ValuePopulator<'_>> {
self.field.map(ValuePopulator)
}
/// Get the field initializer for use when building the deriving struct.
pub fn as_initializer(&self) -> Option<Initializer<'_>> {
self.field.map(Initializer)
}
}
pub struct Declaration<'a>(pub &'a ForwardedField);
impl ToTokens for Declaration<'_> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let ident = &self.0.ident;
tokens.append_all(quote! {
let mut __fwd_attrs: ::darling::export::Vec<::darling::export::syn::Attribute> = vec![];
let mut #ident: ::darling::export::Option<_> = None;
});
}
}
pub struct ValuePopulator<'a>(pub &'a ForwardedField);
impl ToTokens for ValuePopulator<'_> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let ForwardedField { ident, with } = self.0;
let initializer_expr = match with {
Some(with) => quote_spanned!(with.span()=> __errors.handle(#with(__fwd_attrs))),
None => quote!(::darling::export::Some(__fwd_attrs)),
};
tokens.append_all(quote!(#ident = #initializer_expr;));
}
}
pub struct Initializer<'a>(pub &'a ForwardedField);
impl ToTokens for Initializer<'_> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let ident = &self.0.ident;
tokens.append_all(quote!(#ident: #ident.expect("Errors were already checked"),));
}
}
pub struct MatchArms<'a>(&'a ForwardAttrs<'a>);
impl ToTokens for MatchArms<'_> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
if !self.0.will_forward_any() {
tokens.append_all(quote!(_ => continue));
return;
}
let push_command = quote!(__fwd_attrs.push(__attr.clone()));
tokens.append_all(
match self
.0
.filter
.expect("Can only forward attributes if filter is defined")
{
ForwardAttrsFilter::All => quote!(_ => #push_command),
ForwardAttrsFilter::Only(idents) => {
let names = idents.to_strings();
quote! {
#(#names)|* => #push_command,
_ => continue,
}
}
},
);
}
}

View File

@@ -0,0 +1,53 @@
use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
use syn::{spanned::Spanned, Ident, Path};
/// This will be in scope during struct initialization after option parsing.
const DEFAULT_STRUCT_NAME: &str = "__default";
/// The fallback value for a field or container.
#[derive(Debug, Clone)]
pub enum DefaultExpression<'a> {
/// Only valid on fields, `Inherit` indicates that the value should be taken from a pre-constructed
/// fallback object. The value in the variant is the ident of the field.
Inherit(&'a Ident),
Explicit(&'a Path),
Trait {
span: Span,
},
}
impl<'a> DefaultExpression<'a> {
pub fn as_declaration(&'a self) -> DefaultDeclaration<'a> {
DefaultDeclaration(self)
}
}
impl ToTokens for DefaultExpression<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.append_all(match *self {
DefaultExpression::Inherit(ident) => {
let dsn = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site());
quote!(#dsn.#ident)
}
DefaultExpression::Explicit(path) => {
// Use quote_spanned to properly set the span of the parentheses
quote_spanned!(path.span()=>#path())
}
DefaultExpression::Trait { span } => {
quote_spanned!(span=> ::darling::export::Default::default())
}
});
}
}
/// Used only by containers, this wrapper type generates code to declare the fallback instance.
pub struct DefaultDeclaration<'a>(&'a DefaultExpression<'a>);
impl ToTokens for DefaultDeclaration<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let name = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site());
let expr = self.0;
tokens.append_all(quote!(let #name: Self = #expr;));
}
}

View File

@@ -0,0 +1,46 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
/// Declares the local variable into which errors will be accumulated.
#[derive(Default)]
pub struct ErrorDeclaration {
__hidden: (),
}
impl ToTokens for ErrorDeclaration {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.append_all(quote! {
let mut __errors = ::darling::Error::accumulator();
})
}
}
/// Returns early if attribute or body parsing has caused any errors.
#[derive(Default)]
pub struct ErrorCheck<'a> {
location: Option<&'a str>,
__hidden: (),
}
impl<'a> ErrorCheck<'a> {
pub fn with_location(location: &'a str) -> Self {
ErrorCheck {
location: Some(location),
__hidden: (),
}
}
}
impl ToTokens for ErrorCheck<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let at_call = if let Some(ref s) = self.location {
quote!(.map_err(|e| e.at(#s)))
} else {
quote!()
};
tokens.append_all(quote! {
__errors.finish() #at_call?;
})
}
}

274
vendor/darling_core/src/codegen/field.rs vendored Normal file
View File

@@ -0,0 +1,274 @@
use std::borrow::Cow;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
use syn::{spanned::Spanned, Ident, Type};
use crate::codegen::{DefaultExpression, PostfixTransform};
use crate::usage::{self, IdentRefSet, IdentSet, UsesTypeParams};
/// Properties needed to generate code for a field in all the contexts
/// where one may appear.
#[derive(Debug, Clone)]
pub struct Field<'a> {
/// The name presented to the user of the library. This will appear
/// in error messages and will be looked when parsing names.
pub name_in_attr: Cow<'a, String>,
/// The name presented to the author of the library. This will appear
/// in the setters or temporary variables which contain the values.
pub ident: &'a Ident,
/// The type of the field in the input.
pub ty: &'a Type,
pub default_expression: Option<DefaultExpression<'a>>,
/// An expression that will be wrapped in a call to [`core::convert::identity`] and
/// then used for converting a provided value into the field value _before_ postfix
/// transforms are called.
pub with_callable: Cow<'a, syn::Expr>,
pub post_transform: Option<&'a PostfixTransform>,
pub skip: bool,
pub multiple: bool,
/// If set, this field will be given all unclaimed meta items and will
/// not be exposed as a standard named field.
pub flatten: bool,
}
impl<'a> Field<'a> {
/// Get the name of the meta item that should be matched against input and should be used in diagnostics.
///
/// This will be `None` if the field is `skip` or `flatten`, as neither kind of field is addressable
/// by name from the input meta.
pub fn as_name(&'a self) -> Option<&'a str> {
if self.skip || self.flatten {
None
} else {
Some(&self.name_in_attr)
}
}
pub fn as_declaration(&'a self) -> Declaration<'a> {
Declaration(self)
}
pub fn as_flatten_initializer(
&'a self,
parent_field_names: Vec<&'a str>,
) -> FlattenInitializer<'a> {
FlattenInitializer {
field: self,
parent_field_names,
}
}
pub fn as_match(&'a self) -> MatchArm<'a> {
MatchArm(self)
}
pub fn as_initializer(&'a self) -> Initializer<'a> {
Initializer(self)
}
pub fn as_presence_check(&'a self) -> CheckMissing<'a> {
CheckMissing(self)
}
}
impl UsesTypeParams for Field<'_> {
fn uses_type_params<'b>(
&self,
options: &usage::Options,
type_set: &'b IdentSet,
) -> IdentRefSet<'b> {
self.ty.uses_type_params(options, type_set)
}
}
/// An individual field during variable declaration in the generated parsing method.
pub struct Declaration<'a>(&'a Field<'a>);
impl ToTokens for Declaration<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let field = self.0;
let ident = field.ident;
let ty = field.ty;
tokens.append_all(if field.multiple {
// This is NOT mutable, as it will be declared mutable only temporarily.
quote!(let mut #ident: #ty = ::darling::export::Default::default();)
} else {
quote!(let mut #ident: (bool, ::darling::export::Option<#ty>) = (false, None);)
});
// The flatten field additionally needs a place to buffer meta items
// until attribute walking is done, so declare that now.
//
// We expect there can only be one field marked `flatten`, so it shouldn't
// be possible for this to shadow another declaration.
if field.flatten {
tokens.append_all(quote! {
let mut __flatten: Vec<::darling::ast::NestedMeta> = vec![];
});
}
}
}
pub struct FlattenInitializer<'a> {
field: &'a Field<'a>,
parent_field_names: Vec<&'a str>,
}
impl ToTokens for FlattenInitializer<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let Self {
field,
parent_field_names,
} = self;
let ident = field.ident;
let add_parent_fields = if parent_field_names.is_empty() {
None
} else {
Some(quote! {
.map_err(|e| e.add_sibling_alts_for_unknown_field(&[#(#parent_field_names),*]))
})
};
tokens.append_all(quote! {
#ident = (true,
__errors.handle(
::darling::FromMeta::from_list(&__flatten) #add_parent_fields
)
);
});
}
}
/// Represents an individual field in the match.
pub struct MatchArm<'a>(&'a Field<'a>);
impl ToTokens for MatchArm<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let field = self.0;
// Skipped and flattened fields cannot be populated by a meta
// with their name, so they do not have a match arm.
if field.skip || field.flatten {
return;
}
let name_str = &field.name_in_attr;
let ident = field.ident;
let with_callable = &field.with_callable;
let post_transform = field.post_transform.as_ref();
// Errors include the location of the bad input, so we compute that here.
// Fields that take multiple values add the index of the error for convenience,
// while single-value fields only expose the name in the input attribute.
let location = if field.multiple {
// we use the local variable `len` here because location is accessed via
// a closure, and the borrow checker gets very unhappy if we try to immutably
// borrow `#ident` in that closure when it was declared `mut` outside.
quote!(&format!("{}[{}]", #name_str, __len))
} else {
quote!(#name_str)
};
// Give darling's generated code the span of the `with_callable` so that if the target
// type doesn't impl FromMeta, darling's immediate user gets a properly-spanned error.
//
// Within the generated code, add the span immediately on extraction failure, so that it's
// as specific as possible.
// The behavior of `with_span` makes this safe to do; if the child applied an
// even-more-specific span, our attempt here will not overwrite that and will only cost
// us one `if` check.
let extractor = quote_spanned!(with_callable.span()=>
::darling::export::identity::<fn(&::syn::Meta) -> ::darling::Result<_>>(#with_callable)(__inner)
#post_transform
.map_err(|e| e.with_span(&__inner).at(#location))
);
tokens.append_all(if field.multiple {
quote!(
#name_str => {
// Store the index of the name we're assessing in case we need
// it for error reporting.
let __len = #ident.len();
if let ::darling::export::Some(__val) = __errors.handle(#extractor) {
#ident.push(__val)
}
}
)
} else {
quote!(
#name_str => {
if !#ident.0 {
#ident = (true, __errors.handle(#extractor));
} else {
__errors.push(::darling::Error::duplicate_field(#name_str).with_span(&__inner));
}
}
)
});
}
}
/// Wrapper to generate initialization code for a field.
pub struct Initializer<'a>(&'a Field<'a>);
impl ToTokens for Initializer<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let field = self.0;
let ident = field.ident;
tokens.append_all(if field.multiple {
if let Some(ref expr) = field.default_expression {
quote_spanned!(expr.span()=> #ident: if !#ident.is_empty() {
#ident
} else {
#expr
})
} else {
quote!(#ident: #ident)
}
} else if let Some(ref expr) = field.default_expression {
quote_spanned!(expr.span()=> #ident: if let Some(__val) = #ident.1 {
__val
} else {
#expr
})
} else {
quote!(#ident: #ident.1.expect("Uninitialized fields without defaults were already checked"))
});
}
}
/// Creates an error if a field has no value and no default.
pub struct CheckMissing<'a>(&'a Field<'a>);
impl ToTokens for CheckMissing<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
if !self.0.multiple && self.0.default_expression.is_none() {
let ident = self.0.ident;
let ty = self.0.ty;
let name_in_attr = &self.0.name_in_attr;
// If `ty` does not impl FromMeta, the compiler error should point
// at the offending type rather than at the derive-macro call site.
let from_none_call =
quote_spanned!(ty.span()=> <#ty as ::darling::FromMeta>::from_none());
tokens.append_all(quote! {
if !#ident.0 {
match #from_none_call {
::darling::export::Some(__type_fallback) => {
#ident.1 = ::darling::export::Some(__type_fallback);
}
::darling::export::None => {
__errors.push(::darling::Error::missing_field(#name_in_attr))
}
}
}
})
}
}
}

View File

@@ -0,0 +1,113 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use crate::{
ast::Data,
codegen::{ExtractAttribute, OuterFromImpl, TraitImpl},
util::PathList,
};
use super::ForwardAttrs;
pub struct FromAttributesImpl<'a> {
pub base: TraitImpl<'a>,
pub attr_names: &'a PathList,
pub forward_attrs: ForwardAttrs<'a>,
}
impl ToTokens for FromAttributesImpl<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let ty_ident = self.base.ident;
let input = self.param_name();
let post_transform = self.base.post_transform_call();
if let Data::Struct(ref data) = self.base.data {
if data.is_newtype() {
self.wrap(
quote! {
fn from_attributes(#input: &[::darling::export::syn::Attribute]) -> ::darling::Result<Self> {
::darling::export::Ok(
#ty_ident(::darling::FromAttributes::from_attributes(#input)?)
) #post_transform
}
},
tokens,
);
return;
}
}
let passed_attrs = self.forward_attrs.as_initializer();
let inits = self.base.initializers();
let default = self.base.fallback_decl();
let grab_attrs = self.extractor();
let declare_errors = self.base.declare_errors();
let require_fields = self.base.require_fields();
let check_errors = self.base.check_errors();
self.wrap(
quote! {
fn from_attributes(#input: &[::darling::export::syn::Attribute]) -> ::darling::Result<Self> {
#declare_errors
#grab_attrs
#require_fields
#check_errors
#default
::darling::export::Ok(#ty_ident {
#passed_attrs
#inits
}) #post_transform
}
},
tokens,
);
}
}
impl ExtractAttribute for FromAttributesImpl<'_> {
fn local_declarations(&self) -> TokenStream {
self.base.local_declarations()
}
fn attr_names(&self) -> &PathList {
self.attr_names
}
fn forward_attrs(&self) -> &super::ForwardAttrs<'_> {
&self.forward_attrs
}
fn param_name(&self) -> TokenStream {
quote!(__di)
}
fn attrs_accessor(&self) -> TokenStream {
self.param_name()
}
fn core_loop(&self) -> TokenStream {
self.base.core_loop()
}
}
impl<'a> OuterFromImpl<'a> for FromAttributesImpl<'a> {
fn trait_path(&self) -> syn::Path {
path!(::darling::FromAttributes)
}
fn trait_bound(&self) -> syn::Path {
path!(::darling::FromMeta)
}
fn base(&'a self) -> &'a TraitImpl<'a> {
&self.base
}
}

View File

@@ -0,0 +1,152 @@
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens};
use syn::Ident;
use crate::{
ast::Data,
codegen::{ExtractAttribute, OuterFromImpl, TraitImpl},
options::{DeriveInputShapeSet, ForwardedField},
util::PathList,
};
use super::ForwardAttrs;
pub struct FromDeriveInputImpl<'a> {
pub ident: Option<&'a Ident>,
pub generics: Option<&'a Ident>,
pub vis: Option<&'a Ident>,
pub data: Option<&'a ForwardedField>,
pub base: TraitImpl<'a>,
pub attr_names: &'a PathList,
pub forward_attrs: ForwardAttrs<'a>,
pub from_ident: bool,
pub supports: Option<&'a DeriveInputShapeSet>,
}
impl ToTokens for FromDeriveInputImpl<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let ty_ident = self.base.ident;
let input = self.param_name();
let post_transform = self.base.post_transform_call();
if let Data::Struct(ref data) = self.base.data {
if data.is_newtype() {
self.wrap(
quote!{
fn from_derive_input(#input: &::darling::export::syn::DeriveInput) -> ::darling::Result<Self> {
::darling::export::Ok(
#ty_ident(::darling::FromDeriveInput::from_derive_input(#input)?)
) #post_transform
}
},
tokens,
);
return;
}
}
let passed_ident = self
.ident
.as_ref()
.map(|i| quote!(#i: #input.ident.clone(),));
let passed_vis = self.vis.as_ref().map(|i| quote!(#i: #input.vis.clone(),));
let passed_generics = self
.generics
.as_ref()
.map(|i| quote!(#i: ::darling::FromGenerics::from_generics(&#input.generics)?,));
let passed_attrs = self.forward_attrs.as_initializer();
let passed_body = self.data.as_ref().map(|i| {
let ForwardedField { ident, with } = i;
let path = match with {
Some(p) => quote!(#p),
None => quote_spanned!(ident.span()=> ::darling::ast::Data::try_from),
};
quote_spanned!(ident.span()=> #ident: #path(&#input.data)?,)
});
let supports = self.supports.map(|i| {
quote! {
#i
__errors.handle(__validate_body(&#input.data));
}
});
let inits = self.base.initializers();
let default = if self.from_ident {
quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());)
} else {
self.base.fallback_decl()
};
let grab_attrs = self.extractor();
let declare_errors = self.base.declare_errors();
let require_fields = self.base.require_fields();
let check_errors = self.base.check_errors();
self.wrap(
quote! {
fn from_derive_input(#input: &::darling::export::syn::DeriveInput) -> ::darling::Result<Self> {
#declare_errors
#grab_attrs
#supports
#require_fields
#check_errors
#default
::darling::export::Ok(#ty_ident {
#passed_ident
#passed_generics
#passed_vis
#passed_attrs
#passed_body
#inits
}) #post_transform
}
},
tokens,
);
}
}
impl ExtractAttribute for FromDeriveInputImpl<'_> {
fn attr_names(&self) -> &PathList {
self.attr_names
}
fn forward_attrs(&self) -> &ForwardAttrs<'_> {
&self.forward_attrs
}
fn param_name(&self) -> TokenStream {
quote!(__di)
}
fn core_loop(&self) -> TokenStream {
self.base.core_loop()
}
fn local_declarations(&self) -> TokenStream {
self.base.local_declarations()
}
}
impl<'a> OuterFromImpl<'a> for FromDeriveInputImpl<'a> {
fn trait_path(&self) -> syn::Path {
path!(::darling::FromDeriveInput)
}
fn trait_bound(&self) -> syn::Path {
path!(::darling::FromMeta)
}
fn base(&'a self) -> &'a TraitImpl<'a> {
&self.base
}
}

View File

@@ -0,0 +1,114 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::Ident;
use crate::{
codegen::{ExtractAttribute, OuterFromImpl, TraitImpl},
util::PathList,
};
use super::ForwardAttrs;
/// `impl FromField` generator. This is used for parsing an individual
/// field and its attributes.
pub struct FromFieldImpl<'a> {
pub ident: Option<&'a Ident>,
pub vis: Option<&'a Ident>,
pub ty: Option<&'a Ident>,
pub base: TraitImpl<'a>,
pub attr_names: &'a PathList,
pub forward_attrs: ForwardAttrs<'a>,
pub from_ident: bool,
}
impl ToTokens for FromFieldImpl<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let input = self.param_name();
let error_declaration = self.base.declare_errors();
let require_fields = self.base.require_fields();
let error_check = self.base.check_errors();
let initializers = self.base.initializers();
let default = if self.from_ident {
quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());)
} else {
self.base.fallback_decl()
};
let passed_ident = self
.ident
.as_ref()
.map(|i| quote!(#i: #input.ident.clone(),));
let passed_vis = self.vis.as_ref().map(|i| quote!(#i: #input.vis.clone(),));
let passed_ty = self.ty.as_ref().map(|i| quote!(#i: #input.ty.clone(),));
let passed_attrs = self.forward_attrs.as_initializer();
// Determine which attributes to forward (if any).
let grab_attrs = self.extractor();
let post_transform = self.base.post_transform_call();
self.wrap(
quote! {
fn from_field(#input: &::darling::export::syn::Field) -> ::darling::Result<Self> {
#error_declaration
#grab_attrs
#require_fields
#error_check
#default
::darling::export::Ok(Self {
#passed_ident
#passed_ty
#passed_vis
#passed_attrs
#initializers
}) #post_transform
}
},
tokens,
);
}
}
impl ExtractAttribute for FromFieldImpl<'_> {
fn attr_names(&self) -> &PathList {
self.attr_names
}
fn forward_attrs(&self) -> &super::ForwardAttrs<'_> {
&self.forward_attrs
}
fn param_name(&self) -> TokenStream {
quote!(__field)
}
fn core_loop(&self) -> TokenStream {
self.base.core_loop()
}
fn local_declarations(&self) -> TokenStream {
self.base.local_declarations()
}
}
impl<'a> OuterFromImpl<'a> for FromFieldImpl<'a> {
fn trait_path(&self) -> syn::Path {
path!(::darling::FromField)
}
fn trait_bound(&self) -> syn::Path {
path!(::darling::FromMeta)
}
fn base(&'a self) -> &'a TraitImpl<'a> {
&self.base
}
}

View File

@@ -0,0 +1,166 @@
use std::borrow::Cow;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use crate::ast::{Data, Fields, Style};
use crate::codegen::{Field, OuterFromImpl, TraitImpl, Variant};
use crate::util::Callable;
pub struct FromMetaImpl<'a> {
pub base: TraitImpl<'a>,
pub from_word: Option<Cow<'a, Callable>>,
pub from_none: Option<&'a Callable>,
}
impl ToTokens for FromMetaImpl<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let base = &self.base;
let from_word = self.from_word.as_ref().map(|body| {
quote_spanned! {body.span()=>
fn from_word() -> ::darling::Result<Self> {
::darling::export::identity::<fn() -> ::darling::Result<Self>>(#body)()
}
}
});
let from_none = self.from_none.map(|body| {
quote_spanned! {body.span()=>
fn from_none() -> ::darling::export::Option<Self> {
::darling::export::identity::<fn() -> ::darling::export::Option<Self>>(#body)()
}
}
});
let impl_block = match base.data {
// Unit structs allow empty bodies only.
Data::Struct(ref vd) if vd.style.is_unit() => {
let ty_ident = base.ident;
quote!(
fn from_word() -> ::darling::Result<Self> {
::darling::export::Ok(#ty_ident)
}
)
}
// Newtype structs proxy to the sole value they contain.
Data::Struct(Fields {
ref fields,
style: Style::Tuple,
..
}) if fields.len() == 1 => {
let ty_ident = base.ident;
quote!(
fn from_meta(__item: &::darling::export::syn::Meta) -> ::darling::Result<Self> {
::darling::FromMeta::from_meta(__item)
.map_err(|e| e.with_span(&__item))
.map(#ty_ident)
}
)
}
Data::Struct(Fields {
style: Style::Tuple,
..
}) => {
panic!("Multi-field tuples are not supported");
}
Data::Struct(ref data) => {
let inits = data.fields.iter().map(Field::as_initializer);
let declare_errors = base.declare_errors();
let require_fields = base.require_fields();
let check_errors = base.check_errors();
let decls = base.local_declarations();
let core_loop = base.core_loop();
let default = base.fallback_decl();
let post_transform = base.post_transform_call();
quote!(
#from_word
#from_none
fn from_list(__items: &[::darling::export::NestedMeta]) -> ::darling::Result<Self> {
#decls
#declare_errors
#core_loop
#require_fields
#check_errors
#default
::darling::export::Ok(Self {
#(#inits),*
}) #post_transform
}
)
}
Data::Enum(ref variants) => {
let unit_arms = variants.iter().map(Variant::as_unit_match_arm);
let unknown_variant_err = if !variants.is_empty() {
let names = variants.iter().map(Variant::as_name);
quote! {
unknown_field_with_alts(__other, &[#(#names),*])
}
} else {
quote! {
unknown_field(__other)
}
};
let data_variants = variants.iter().map(Variant::as_data_match_arm);
quote!(
fn from_list(__outer: &[::darling::export::NestedMeta]) -> ::darling::Result<Self> {
// An enum must have exactly one value inside the parentheses if it's not a unit
// match arm.
match __outer.len() {
0 => ::darling::export::Err(::darling::Error::too_few_items(1)),
1 => {
if let ::darling::export::NestedMeta::Meta(ref __nested) = __outer[0] {
match ::darling::util::path_to_string(__nested.path()).as_ref() {
#(#data_variants)*
__other => ::darling::export::Err(::darling::Error::#unknown_variant_err.with_span(__nested))
}
} else {
::darling::export::Err(::darling::Error::unsupported_format("literal"))
}
}
_ => ::darling::export::Err(::darling::Error::too_many_items(1)),
}
}
fn from_string(lit: &str) -> ::darling::Result<Self> {
match lit {
#(#unit_arms)*
__other => ::darling::export::Err(::darling::Error::unknown_value(__other))
}
}
#from_word
#from_none
)
}
};
self.wrap(impl_block, tokens);
}
}
impl<'a> OuterFromImpl<'a> for FromMetaImpl<'a> {
fn trait_path(&self) -> syn::Path {
path!(::darling::FromMeta)
}
fn base(&'a self) -> &'a TraitImpl<'a> {
&self.base
}
}

View File

@@ -0,0 +1,111 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::Ident;
use crate::codegen::{ExtractAttribute, ForwardAttrs, OuterFromImpl, TraitImpl};
use crate::util::PathList;
pub struct FromTypeParamImpl<'a> {
pub base: TraitImpl<'a>,
pub ident: Option<&'a Ident>,
pub bounds: Option<&'a Ident>,
pub default: Option<&'a Ident>,
pub attr_names: &'a PathList,
pub forward_attrs: ForwardAttrs<'a>,
pub from_ident: bool,
}
impl ToTokens for FromTypeParamImpl<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let input = self.param_name();
let error_declaration = self.base.declare_errors();
let grab_attrs = self.extractor();
let require_fields = self.base.require_fields();
let error_check = self.base.check_errors();
let default = if self.from_ident {
quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());)
} else {
self.base.fallback_decl()
};
let passed_ident = self
.ident
.as_ref()
.map(|i| quote!(#i: #input.ident.clone(),));
let passed_attrs = self.forward_attrs.as_initializer();
let passed_bounds = self
.bounds
.as_ref()
.map(|i| quote!(#i: #input.bounds.clone().into_iter().collect::<Vec<_>>(),));
let passed_default = self
.default
.as_ref()
.map(|i| quote!(#i: #input.default.clone(),));
let initializers = self.base.initializers();
let post_transform = self.base.post_transform_call();
self.wrap(
quote! {
fn from_type_param(#input: &::darling::export::syn::TypeParam) -> ::darling::Result<Self> {
#error_declaration
#grab_attrs
#require_fields
#error_check
#default
::darling::export::Ok(Self {
#passed_ident
#passed_bounds
#passed_default
#passed_attrs
#initializers
}) #post_transform
}
},
tokens,
);
}
}
impl ExtractAttribute for FromTypeParamImpl<'_> {
fn attr_names(&self) -> &PathList {
self.attr_names
}
fn forward_attrs(&self) -> &ForwardAttrs<'_> {
&self.forward_attrs
}
fn param_name(&self) -> TokenStream {
quote!(__type_param)
}
fn core_loop(&self) -> TokenStream {
self.base.core_loop()
}
fn local_declarations(&self) -> TokenStream {
self.base.local_declarations()
}
}
impl<'a> OuterFromImpl<'a> for FromTypeParamImpl<'a> {
fn trait_path(&self) -> syn::Path {
path!(::darling::FromTypeParam)
}
fn trait_bound(&self) -> syn::Path {
path!(::darling::FromMeta)
}
fn base(&'a self) -> &'a TraitImpl<'a> {
&self.base
}
}

View File

@@ -0,0 +1,134 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::Ident;
use crate::codegen::{ExtractAttribute, ForwardAttrs, OuterFromImpl, TraitImpl};
use crate::options::DataShape;
use crate::util::PathList;
pub struct FromVariantImpl<'a> {
pub base: TraitImpl<'a>,
/// If set, the ident of the field into which the variant ident should be placed.
///
/// This is one of `darling`'s "magic fields", which allow a type deriving a `darling`
/// trait to get fields from the input `syn` element added to the deriving struct
/// automatically.
pub ident: Option<&'a Ident>,
/// If set, the ident of the field into which the transformed output of the input
/// variant's fields should be placed.
///
/// This is one of `darling`'s "magic fields".
pub fields: Option<&'a Ident>,
/// If set, the ident of the field into which the discriminant of the input variant
/// should be placed. The receiving field must be an `Option` as not all enums have
/// discriminants.
///
/// This is one of `darling`'s "magic fields".
pub discriminant: Option<&'a Ident>,
pub attr_names: &'a PathList,
pub forward_attrs: ForwardAttrs<'a>,
pub from_ident: bool,
pub supports: Option<&'a DataShape>,
}
impl ToTokens for FromVariantImpl<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let input = self.param_name();
let extractor = self.extractor();
let passed_ident = self
.ident
.as_ref()
.map(|i| quote!(#i: #input.ident.clone(),));
let passed_discriminant = self
.discriminant
.as_ref()
.map(|i| quote!(#i: #input.discriminant.as_ref().map(|(_, expr)| expr.clone()),));
let passed_attrs = self.forward_attrs.as_initializer();
let passed_fields = self
.fields
.as_ref()
.map(|i| quote!(#i: ::darling::ast::Fields::try_from(&#input.fields)?,));
let inits = self.base.initializers();
let post_transform = self.base.post_transform_call();
let default = if self.from_ident {
quote!(let __default: Self = ::darling::export::From::from(#input.ident.clone());)
} else {
self.base.fallback_decl()
};
let supports = self.supports.map(|i| {
quote! {
__errors.handle(#i.check(&#input.fields));
}
});
let error_declaration = self.base.declare_errors();
let require_fields = self.base.require_fields();
let error_check = self.base.check_errors();
self.wrap(
quote!(
fn from_variant(#input: &::darling::export::syn::Variant) -> ::darling::Result<Self> {
#error_declaration
#extractor
#supports
#require_fields
#error_check
#default
::darling::export::Ok(Self {
#passed_ident
#passed_discriminant
#passed_attrs
#passed_fields
#inits
}) #post_transform
}
),
tokens,
);
}
}
impl ExtractAttribute for FromVariantImpl<'_> {
fn local_declarations(&self) -> TokenStream {
self.base.local_declarations()
}
fn attr_names(&self) -> &PathList {
self.attr_names
}
fn forward_attrs(&self) -> &ForwardAttrs<'_> {
&self.forward_attrs
}
fn param_name(&self) -> TokenStream {
quote!(__variant)
}
fn core_loop(&self) -> TokenStream {
self.base.core_loop()
}
}
impl<'a> OuterFromImpl<'a> for FromVariantImpl<'a> {
fn trait_path(&self) -> syn::Path {
path!(::darling::FromVariant)
}
fn trait_bound(&self) -> syn::Path {
path!(::darling::FromMeta)
}
fn base(&'a self) -> &'a TraitImpl<'a> {
&self.base
}
}

32
vendor/darling_core/src/codegen/mod.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
mod attr_extractor;
mod attrs_field;
mod default_expr;
mod error;
mod field;
mod from_attributes_impl;
mod from_derive_impl;
mod from_field;
mod from_meta_impl;
mod from_type_param;
mod from_variant_impl;
mod outer_from_impl;
mod postfix_transform;
mod trait_impl;
mod variant;
mod variant_data;
pub(in crate::codegen) use self::attr_extractor::ExtractAttribute;
pub use self::attrs_field::ForwardAttrs;
pub use self::default_expr::DefaultExpression;
pub use self::field::Field;
pub use self::from_attributes_impl::FromAttributesImpl;
pub use self::from_derive_impl::FromDeriveInputImpl;
pub use self::from_field::FromFieldImpl;
pub use self::from_meta_impl::FromMetaImpl;
pub use self::from_type_param::FromTypeParamImpl;
pub use self::from_variant_impl::FromVariantImpl;
pub use self::outer_from_impl::OuterFromImpl;
pub use self::postfix_transform::PostfixTransform;
pub use self::trait_impl::TraitImpl;
pub use self::variant::Variant;
pub use self::variant_data::FieldsGen;

View File

@@ -0,0 +1,62 @@
use proc_macro2::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{GenericParam, Generics, Path, TraitBound, TraitBoundModifier, TypeParamBound};
use crate::codegen::TraitImpl;
use crate::usage::IdentSet;
/// Wrapper for "outer From" traits, such as `FromDeriveInput`, `FromVariant`, and `FromField`.
pub trait OuterFromImpl<'a> {
/// Gets the path of the trait being implemented.
fn trait_path(&self) -> Path;
fn base(&'a self) -> &'a TraitImpl<'a>;
fn trait_bound(&self) -> Path {
self.trait_path()
}
fn wrap<T: ToTokens>(&'a self, body: T, tokens: &mut TokenStream) {
let base = self.base();
let trayt = self.trait_path();
let ty_ident = base.ident;
// The type parameters used in non-skipped, non-magic fields.
// These must impl `FromMeta` unless they have custom bounds.
let used = base.used_type_params();
let generics = compute_impl_bounds(self.trait_bound(), base.generics.clone(), &used);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
tokens.append_all(quote!(
#[automatically_derived]
#[allow(clippy::manual_unwrap_or_default)]
impl #impl_generics #trayt for #ty_ident #ty_generics
#where_clause
{
#body
}
));
}
}
fn compute_impl_bounds(bound: Path, mut generics: Generics, applies_to: &IdentSet) -> Generics {
if generics.params.is_empty() {
return generics;
}
let added_bound = TypeParamBound::Trait(TraitBound {
paren_token: None,
modifier: TraitBoundModifier::None,
lifetimes: None,
path: bound,
});
for param in generics.params.iter_mut() {
if let GenericParam::Type(ref mut typ) = *param {
if applies_to.contains(&typ.ident) {
typ.bounds.push(added_bound.clone());
}
}
}
generics
}

View File

@@ -0,0 +1,30 @@
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{Ident, Path};
/// A method invocation applied to a value.
///
/// This is used for `map` and `and_then` transforms in derivations.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PostfixTransform {
pub(crate) transformer: Ident,
pub(crate) function: Path,
}
impl PostfixTransform {
pub fn new(transformer: Ident, function: Path) -> Self {
Self {
transformer,
function,
}
}
}
impl ToTokens for PostfixTransform {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let Self {
transformer,
function,
} = self;
tokens.append_all(quote!(.#transformer(#function)))
}
}

View File

@@ -0,0 +1,145 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Generics, Ident};
use crate::ast::{Data, Fields};
use crate::codegen::{
error::{ErrorCheck, ErrorDeclaration},
DefaultExpression, Field, FieldsGen, PostfixTransform, Variant,
};
use crate::usage::{CollectTypeParams, IdentSet, Purpose};
#[derive(Debug)]
pub struct TraitImpl<'a> {
pub ident: &'a Ident,
pub generics: &'a Generics,
pub data: Data<Variant<'a>, Field<'a>>,
pub default: Option<DefaultExpression<'a>>,
pub post_transform: Option<&'a PostfixTransform>,
pub allow_unknown_fields: bool,
}
impl<'a> TraitImpl<'a> {
/// Get all declared type parameters.
pub fn declared_type_params(&self) -> IdentSet {
self.generics
.type_params()
.map(|tp| tp.ident.clone())
.collect()
}
/// Get the type parameters which are used by non-skipped, non-magic fields.
/// These type parameters will have a `FromMeta` bound applied to them in emitted
/// code.
pub fn used_type_params(&self) -> IdentSet {
self.type_params_matching(|f| !f.skip, |v| !v.skip)
}
fn type_params_matching<F, V>(&self, field_filter: F, variant_filter: V) -> IdentSet
where
F: Fn(&&Field<'_>) -> bool,
V: Fn(&&Variant<'_>) -> bool,
{
let declared = self.declared_type_params();
match self.data {
Data::Struct(ref v) => self.type_params_in_fields(v, &field_filter, &declared),
Data::Enum(ref v) => {
v.iter()
.filter(variant_filter)
.fold(Default::default(), |mut state, variant| {
state.extend(self.type_params_in_fields(
&variant.data,
&field_filter,
&declared,
));
state
})
}
}
}
/// Get the type parameters of all fields in a set matching some filter
fn type_params_in_fields<'b, F>(
&'b self,
fields: &'b Fields<Field<'a>>,
field_filter: F,
declared: &IdentSet,
) -> IdentSet
where
F: Fn(&&'b Field<'_>) -> bool,
{
fields
.iter()
.filter(field_filter)
.collect_type_params_cloned(&Purpose::BoundImpl.into(), declared)
}
}
impl<'a> TraitImpl<'a> {
/// Gets the `let` declaration for errors accumulated during parsing.
pub fn declare_errors(&self) -> ErrorDeclaration {
ErrorDeclaration::default()
}
/// Gets the check which performs an early return if errors occurred during parsing.
pub fn check_errors(&self) -> ErrorCheck<'_> {
ErrorCheck::default()
}
/// Generate local variable declarations for all fields.
pub(in crate::codegen) fn local_declarations(&self) -> TokenStream {
if let Data::Struct(ref vd) = self.data {
let vdr = vd.as_ref().map(Field::as_declaration);
let decls = vdr.fields.as_slice();
quote!(#(#decls)*)
} else {
quote!()
}
}
pub(in crate::codegen) fn post_transform_call(&self) -> Option<TokenStream> {
self.post_transform.map(|pt| quote!(#pt))
}
/// Generate local variable declaration and initialization for instance from which missing fields will be taken.
pub(in crate::codegen) fn fallback_decl(&self) -> TokenStream {
let default = self.default.as_ref().map(DefaultExpression::as_declaration);
quote!(#default)
}
pub fn require_fields(&self) -> TokenStream {
if let Data::Struct(ref vd) = self.data {
let check_nones = vd.as_ref().map(Field::as_presence_check);
let checks = check_nones.fields.as_slice();
// If a field was marked `flatten`, now is the time to process any unclaimed meta items
// and mark the field as having been seen.
let flatten_field_init = vd.fields.iter().find(|f| f.flatten).map(|v| {
v.as_flatten_initializer(vd.fields.iter().filter_map(Field::as_name).collect())
});
quote! {
#flatten_field_init
#(#checks)*
}
} else {
quote!()
}
}
pub(in crate::codegen) fn initializers(&self) -> TokenStream {
self.make_field_ctx().initializers()
}
/// Generate the loop which walks meta items looking for property matches.
pub(in crate::codegen) fn core_loop(&self) -> TokenStream {
self.make_field_ctx().core_loop()
}
fn make_field_ctx(&'a self) -> FieldsGen<'a> {
match self.data {
Data::Enum(_) => panic!("Core loop on enums isn't supported"),
Data::Struct(ref data) => FieldsGen::new(data, self.allow_unknown_fields),
}
}
}

View File

@@ -0,0 +1,193 @@
use std::borrow::Cow;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
use syn::Ident;
use crate::ast::Fields;
use crate::codegen::error::{ErrorCheck, ErrorDeclaration};
use crate::codegen::{Field, FieldsGen};
use crate::usage::{self, IdentRefSet, IdentSet, UsesTypeParams};
/// A variant of the enum which is deriving `FromMeta`.
#[derive(Debug, Clone)]
pub struct Variant<'a> {
/// The name which will appear in code passed to the `FromMeta` input.
pub name_in_attr: Cow<'a, String>,
/// The name of the variant which will be returned for a given `name_in_attr`.
pub variant_ident: &'a Ident,
/// The name of the parent enum type.
pub ty_ident: &'a Ident,
pub data: Fields<Field<'a>>,
/// Whether or not the variant should be skipped in the generated code.
pub skip: bool,
pub allow_unknown_fields: bool,
}
impl<'a> Variant<'a> {
pub fn as_name(&'a self) -> &'a str {
&self.name_in_attr
}
pub fn as_unit_match_arm(&'a self) -> UnitMatchArm<'a> {
UnitMatchArm(self)
}
pub fn as_data_match_arm(&'a self) -> DataMatchArm<'a> {
DataMatchArm(self)
}
}
impl UsesTypeParams for Variant<'_> {
fn uses_type_params<'b>(
&self,
options: &usage::Options,
type_set: &'b IdentSet,
) -> IdentRefSet<'b> {
self.data.uses_type_params(options, type_set)
}
}
/// Code generator for an enum variant in a unit match position.
/// This is placed in generated `from_string` calls for the parent enum.
/// Value-carrying variants wrapped in this type will emit code to produce an "unsupported format" error.
pub struct UnitMatchArm<'a>(&'a Variant<'a>);
impl ToTokens for UnitMatchArm<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let val: &Variant<'_> = self.0;
if val.skip {
return;
}
let name_in_attr = &val.name_in_attr;
let unsupported_format_error = || {
quote!(::darling::export::Err(
::darling::Error::unsupported_format("literal")
))
};
if val.data.is_unit() {
let variant_ident = val.variant_ident;
let ty_ident = val.ty_ident;
tokens.append_all(quote!(
#name_in_attr => ::darling::export::Ok(#ty_ident::#variant_ident),
));
} else if val.data.is_newtype() {
let field = val
.data
.fields
.first()
.expect("Newtype should have exactly one field");
let field_ty = field.ty;
let ty_ident = val.ty_ident;
let variant_ident = val.variant_ident;
let unsupported_format = unsupported_format_error();
tokens.append_all(quote!{
#name_in_attr => {
match <#field_ty as ::darling::FromMeta>::from_none() {
::darling::export::Some(__value) => ::darling::export::Ok(#ty_ident::#variant_ident(__value)),
::darling::export::None => #unsupported_format,
}
}
})
} else {
let unsupported_format = unsupported_format_error();
tokens.append_all(quote!(
#name_in_attr => #unsupported_format,
));
}
}
}
/// Code generator for an enum variant in a data-carrying match position.
/// This is placed in generated `from_list` calls for the parent enum.
/// Unit variants wrapped in this type will emit code to produce an "unsupported format" error.
pub struct DataMatchArm<'a>(&'a Variant<'a>);
impl ToTokens for DataMatchArm<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let val: &Variant<'_> = self.0;
if val.skip {
return;
}
let name_in_attr = &val.name_in_attr;
let variant_ident = val.variant_ident;
let ty_ident = val.ty_ident;
if val.data.is_unit() {
// Allow unit variants to match a list item if it's just a path with no associated
// value, e.g. `volume(shout)` is allowed.
tokens.append_all(quote!(
#name_in_attr => {
if let ::darling::export::syn::Meta::Path(_) = *__nested {
::darling::export::Ok(#ty_ident::#variant_ident)
} else {
::darling::export::Err(::darling::Error::unsupported_format("non-path"))
}
},
));
return;
}
let vdg = FieldsGen::new(&val.data, val.allow_unknown_fields);
if val.data.is_struct() {
let declare_errors = ErrorDeclaration::default();
let check_errors = ErrorCheck::with_location(name_in_attr);
let require_fields = vdg.require_fields();
let decls = vdg.declarations();
let core_loop = vdg.core_loop();
let inits = vdg.initializers();
tokens.append_all(quote!(
#name_in_attr => {
if let ::darling::export::syn::Meta::List(ref __data) = *__nested {
let __items = ::darling::export::NestedMeta::parse_meta_list(__data.tokens.clone())?;
let __items = &__items;
#declare_errors
#decls
#core_loop
#require_fields
#check_errors
::darling::export::Ok(#ty_ident::#variant_ident {
#inits
})
} else {
::darling::export::Err(::darling::Error::unsupported_format("non-list"))
}
}
));
} else if val.data.is_newtype() {
tokens.append_all(quote!(
#name_in_attr => {
::darling::export::Ok(
#ty_ident::#variant_ident(
::darling::FromMeta::from_meta(__nested)
.map_err(|e| e.at(#name_in_attr))?)
)
}
));
} else {
panic!("Match arms aren't supported for tuple variants yet");
}
}
}

View File

@@ -0,0 +1,105 @@
use proc_macro2::TokenStream;
use quote::quote;
use crate::ast::{Fields, Style};
use crate::codegen::Field;
pub struct FieldsGen<'a> {
fields: &'a Fields<Field<'a>>,
allow_unknown_fields: bool,
}
impl<'a> FieldsGen<'a> {
pub fn new(fields: &'a Fields<Field<'a>>, allow_unknown_fields: bool) -> Self {
Self {
fields,
allow_unknown_fields,
}
}
/// Create declarations for all the fields in the struct.
pub(in crate::codegen) fn declarations(&self) -> TokenStream {
match *self.fields {
Fields {
style: Style::Struct,
ref fields,
..
} => {
let vdr = fields.iter().map(Field::as_declaration);
quote!(#(#vdr)*)
}
_ => panic!("FieldsGen doesn't support tuples yet"),
}
}
/// Generate the loop which walks meta items looking for property matches.
pub(in crate::codegen) fn core_loop(&self) -> TokenStream {
let arms = self.fields.as_ref().map(Field::as_match);
// If there is a flatten field, buffer the unknown field so it can be passed
// to the flatten function with all other unknown fields.
let handle_unknown = if self.fields.iter().any(|f| f.flatten) {
quote! {
__flatten.push(::darling::ast::NestedMeta::Meta(__inner.clone()));
}
}
// If we're allowing unknown fields, then handling one is a no-op.
else if self.allow_unknown_fields {
quote!()
}
// Otherwise, we're going to push a new spanned error pointing at the field.
else {
let mut names = self.fields.iter().filter_map(Field::as_name).peekable();
// We can't call `unknown_field_with_alts` with an empty slice, or else it fails to
// infer the type of the slice item.
let err_fn = if names.peek().is_none() {
quote!(unknown_field(__other))
} else {
quote!(unknown_field_with_alts(__other, &[#(#names),*]))
};
quote! {
__errors.push(::darling::Error::#err_fn.with_span(__inner));
}
};
let arms = arms.iter();
quote!(
for __item in __items {
match *__item {
::darling::export::NestedMeta::Meta(ref __inner) => {
let __name = ::darling::util::path_to_string(__inner.path());
match __name.as_str() {
#(#arms)*
__other => { #handle_unknown }
}
}
::darling::export::NestedMeta::Lit(ref __inner) => {
__errors.push(::darling::Error::unsupported_format("literal")
.with_span(__inner));
}
}
}
)
}
pub fn require_fields(&self) -> TokenStream {
match *self.fields {
Fields {
style: Style::Struct,
ref fields,
..
} => {
let checks = fields.iter().map(Field::as_presence_check);
quote!(#(#checks)*)
}
_ => panic!("FieldsGen doesn't support tuples for requirement checks"),
}
}
pub(in crate::codegen) fn initializers(&self) -> TokenStream {
let inits = self.fields.as_ref().map(Field::as_initializer);
let inits = inits.iter();
quote!(#(#inits),*)
}
}

61
vendor/darling_core/src/derive.rs vendored Normal file
View File

@@ -0,0 +1,61 @@
//! Functions to derive `darling`'s traits from well-formed input, without directly depending
//! on `proc_macro`.
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::DeriveInput;
use crate::options;
/// Run an expression which returns a `darling::Result`, then either return the tokenized
/// representation of the `Ok` value, or the tokens of the compiler errors in the `Err` case.
macro_rules! emit_impl_or_error {
($e:expr) => {
match $e {
Ok(val) => val.into_token_stream(),
Err(err) => err.write_errors(),
}
};
}
/// Create tokens for a `darling::FromMeta` impl from a `DeriveInput`. If
/// the input cannot produce a valid impl, the returned tokens will contain
/// compile errors instead.
pub fn from_meta(input: &DeriveInput) -> TokenStream {
emit_impl_or_error!(options::FromMetaOptions::new(input))
}
/// Create tokens for a `darling::FromAttributes` impl from a `DeriveInput`. If
/// the input cannot produce a valid impl, the returned tokens will contain
/// compile errors instead.
pub fn from_attributes(input: &DeriveInput) -> TokenStream {
emit_impl_or_error!(options::FromAttributesOptions::new(input))
}
/// Create tokens for a `darling::FromDeriveInput` impl from a `DeriveInput`. If
/// the input cannot produce a valid impl, the returned tokens will contain
/// compile errors instead.
pub fn from_derive_input(input: &DeriveInput) -> TokenStream {
emit_impl_or_error!(options::FdiOptions::new(input))
}
/// Create tokens for a `darling::FromField` impl from a `DeriveInput`. If
/// the input cannot produce a valid impl, the returned tokens will contain
/// compile errors instead.
pub fn from_field(input: &DeriveInput) -> TokenStream {
emit_impl_or_error!(options::FromFieldOptions::new(input))
}
/// Create tokens for a `darling::FromTypeParam` impl from a `DeriveInput`. If
/// the input cannot produce a valid impl, the returned tokens will contain
/// compile errors instead.
pub fn from_type_param(input: &DeriveInput) -> TokenStream {
emit_impl_or_error!(options::FromTypeParamOptions::new(input))
}
/// Create tokens for a `darling::FromVariant` impl from a `DeriveInput`. If
/// the input cannot produce a valid impl, the returned tokens will contain
/// compile errors instead.
pub fn from_variant(input: &DeriveInput) -> TokenStream {
emit_impl_or_error!(options::FromVariantOptions::new(input))
}

82
vendor/darling_core/src/error/child.rs vendored Normal file
View File

@@ -0,0 +1,82 @@
use proc_macro2::Span;
/// Exhaustive mirror of [`proc_macro::Level`].
#[derive(Debug, Clone)]
pub(in crate::error) enum Level {
Error,
Warning,
Note,
Help,
}
/// Supplemental message for an [`Error`](super::Error) when it's emitted as a `Diagnostic`.
///
/// # Example Output
/// The `note` and `help` lines below come from child diagnostics.
///
/// ```text
/// error: My custom error
/// --> my_project/my_file.rs:3:5
/// |
/// 13 | FooBar { value: String },
/// | ^^^^^^
/// |
/// = note: My note on the macro usage
/// = help: Try doing this instead
/// ```
#[derive(Debug, Clone)]
pub(in crate::error) struct ChildDiagnostic {
level: Level,
span: Option<Span>,
message: String,
}
impl ChildDiagnostic {
pub(in crate::error) fn new(level: Level, span: Option<Span>, message: String) -> Self {
Self {
level,
span,
message,
}
}
}
impl ChildDiagnostic {
/// Append this child diagnostic to a `Diagnostic`.
///
/// # Panics
/// This method panics if `self` has a span and is being invoked outside of
/// a proc-macro due to the behavior of [`Span::unwrap()`](Span).
pub fn append_to(self, diagnostic: proc_macro::Diagnostic) -> proc_macro::Diagnostic {
match self.level {
Level::Error => {
if let Some(span) = self.span {
diagnostic.span_error(span.unwrap(), self.message)
} else {
diagnostic.error(self.message)
}
}
Level::Warning => {
if let Some(span) = self.span {
diagnostic.span_warning(span.unwrap(), self.message)
} else {
diagnostic.warning(self.message)
}
}
Level::Note => {
if let Some(span) = self.span {
diagnostic.span_note(span.unwrap(), self.message)
} else {
diagnostic.note(self.message)
}
}
Level::Help => {
if let Some(span) = self.span {
diagnostic.span_help(span.unwrap(), self.message)
} else {
diagnostic.help(self.message)
}
}
}
}
}

229
vendor/darling_core/src/error/kind.rs vendored Normal file
View File

@@ -0,0 +1,229 @@
use std::fmt;
use crate::error::Error;
type DeriveInputShape = String;
type FieldName = String;
type MetaFormat = String;
#[derive(Debug, Clone)]
// Don't want to publicly commit to ErrorKind supporting equality yet, but
// not having it makes testing very difficult.
#[cfg_attr(test, derive(PartialEq))]
pub(in crate::error) enum ErrorKind {
/// An arbitrary error message.
Custom(String),
DuplicateField(FieldName),
MissingField(FieldName),
UnsupportedShape {
observed: DeriveInputShape,
expected: Option<String>,
},
UnknownField(ErrorUnknownField),
UnexpectedFormat(MetaFormat),
UnexpectedType(String),
UnknownValue(String),
TooFewItems(usize),
TooManyItems(usize),
/// A set of errors.
Multiple(Vec<Error>),
// TODO make this variant take `!` so it can't exist
#[doc(hidden)]
__NonExhaustive,
}
impl ErrorKind {
pub fn description(&self) -> &str {
use self::ErrorKind::*;
match *self {
Custom(ref s) => s,
DuplicateField(_) => "Duplicate field",
MissingField(_) => "Missing field",
UnknownField(_) => "Unexpected field",
UnsupportedShape { .. } => "Unsupported shape",
UnexpectedFormat(_) => "Unexpected meta-item format",
UnexpectedType(_) => "Unexpected type",
UnknownValue(_) => "Unknown literal value",
TooFewItems(_) => "Too few items",
TooManyItems(_) => "Too many items",
Multiple(_) => "Multiple errors",
__NonExhaustive => unreachable!(),
}
}
/// Deeply counts the number of errors this item represents.
pub fn len(&self) -> usize {
if let ErrorKind::Multiple(ref items) = *self {
items.iter().map(Error::len).sum()
} else {
1
}
}
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::ErrorKind::*;
match *self {
Custom(ref s) => s.fmt(f),
DuplicateField(ref field) => write!(f, "Duplicate field `{}`", field),
MissingField(ref field) => write!(f, "Missing field `{}`", field),
UnknownField(ref field) => field.fmt(f),
UnsupportedShape {
ref observed,
ref expected,
} => {
write!(f, "Unsupported shape `{}`", observed)?;
if let Some(expected) = &expected {
write!(f, ". Expected {}.", expected)?;
}
Ok(())
}
UnexpectedFormat(ref format) => write!(f, "Unexpected meta-item format `{}`", format),
UnexpectedType(ref ty) => write!(f, "Unexpected type `{}`", ty),
UnknownValue(ref val) => write!(f, "Unknown literal value `{}`", val),
TooFewItems(ref min) => write!(f, "Too few items: Expected at least {}", min),
TooManyItems(ref max) => write!(f, "Too many items: Expected no more than {}", max),
Multiple(ref items) if items.len() == 1 => items[0].fmt(f),
Multiple(ref items) => {
write!(f, "Multiple errors: (")?;
let mut first = true;
for item in items {
if !first {
write!(f, ", ")?;
} else {
first = false;
}
item.fmt(f)?;
}
write!(f, ")")
}
__NonExhaustive => unreachable!(),
}
}
}
impl From<ErrorUnknownField> for ErrorKind {
fn from(err: ErrorUnknownField) -> Self {
ErrorKind::UnknownField(err)
}
}
/// An error for an unknown field, with a possible "did-you-mean" suggestion to get
/// the user back on the right track.
#[derive(Clone, Debug)]
// Don't want to publicly commit to ErrorKind supporting equality yet, but
// not having it makes testing very difficult.
#[cfg_attr(test, derive(PartialEq))]
pub(in crate::error) struct ErrorUnknownField {
name: String,
did_you_mean: Option<(f64, String)>,
}
impl ErrorUnknownField {
pub fn new<I: Into<String>>(name: I, did_you_mean: Option<(f64, String)>) -> Self {
ErrorUnknownField {
name: name.into(),
did_you_mean,
}
}
pub fn with_alts<'a, T, I>(field: &str, alternates: I) -> Self
where
T: AsRef<str> + 'a,
I: IntoIterator<Item = &'a T>,
{
ErrorUnknownField::new(field, did_you_mean(field, alternates))
}
/// Add more alternate field names to the error, updating the `did_you_mean` suggestion
/// if a closer match to the unknown field's name is found.
pub fn add_alts<'a, T, I>(&mut self, alternates: I)
where
T: AsRef<str> + 'a,
I: IntoIterator<Item = &'a T>,
{
if let Some(bna) = did_you_mean(&self.name, alternates) {
if let Some(current) = &self.did_you_mean {
if bna.0 > current.0 {
self.did_you_mean = Some(bna);
}
} else {
self.did_you_mean = Some(bna);
}
}
}
#[cfg(feature = "diagnostics")]
pub fn into_diagnostic(self, span: Option<::proc_macro2::Span>) -> ::proc_macro::Diagnostic {
let base = span
.unwrap_or_else(::proc_macro2::Span::call_site)
.unwrap()
.error(self.top_line());
match self.did_you_mean {
Some((_, alt_name)) => base.help(format!("did you mean `{}`?", alt_name)),
None => base,
}
}
#[cfg(feature = "diagnostics")]
fn top_line(&self) -> String {
format!("Unknown field: `{}`", self.name)
}
}
impl From<String> for ErrorUnknownField {
fn from(name: String) -> Self {
ErrorUnknownField::new(name, None)
}
}
impl<'a> From<&'a str> for ErrorUnknownField {
fn from(name: &'a str) -> Self {
ErrorUnknownField::new(name, None)
}
}
impl fmt::Display for ErrorUnknownField {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Unknown field: `{}`", self.name)?;
if let Some((_, ref did_you_mean)) = self.did_you_mean {
write!(f, ". Did you mean `{}`?", did_you_mean)?;
}
Ok(())
}
}
#[cfg(feature = "suggestions")]
fn did_you_mean<'a, T, I>(field: &str, alternates: I) -> Option<(f64, String)>
where
T: AsRef<str> + 'a,
I: IntoIterator<Item = &'a T>,
{
let mut candidate: Option<(f64, &str)> = None;
for pv in alternates {
let confidence = ::strsim::jaro_winkler(field, pv.as_ref());
if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence))
{
candidate = Some((confidence, pv.as_ref()));
}
}
candidate.map(|(score, candidate)| (score, candidate.into()))
}
#[cfg(not(feature = "suggestions"))]
fn did_you_mean<'a, T, I>(_field: &str, _alternates: I) -> Option<(f64, String)>
where
T: AsRef<str> + 'a,
I: IntoIterator<Item = &'a T>,
{
None
}

1035
vendor/darling_core/src/error/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
use syn::Attribute;
use crate::Result;
/// Create an instance by parsing a list of attributes.
///
/// This trait is useful when dealing with items such as traits on traits and impl blocks,
/// for which `darling` does not provide dedicated traits.
pub trait FromAttributes: Sized {
/// Create an instance by parsing a list of attributes.
///
/// By convention, `FromAttributes` implementations should merge item
/// declarations across attributes, so that the following forms are
/// equivalent:
///
/// ```rust,ignore
/// #[derive(Serialize)]
/// #[serde(rename_all = "camel_case")]
/// #[serde(borrow)]
/// pub struct SplitExample {}
///
/// #[derive(Serialize)]
/// #[serde(borrow, rename_all = "camel_case")]
/// pub struct JoinedExample {}
/// ```
fn from_attributes(attrs: &[Attribute]) -> Result<Self>;
}

View File

@@ -0,0 +1,26 @@
use syn::DeriveInput;
use crate::Result;
/// Creates an instance by parsing an entire proc-macro `derive` input,
/// including the, identity, generics, and visibility of the type.
///
/// This trait should either be derived or manually implemented by a type
/// in the proc macro crate which is directly using `darling`. It is unlikely
/// that these implementations will be reusable across crates.
pub trait FromDeriveInput: Sized {
/// Create an instance from `syn::DeriveInput`, or return an error.
fn from_derive_input(input: &DeriveInput) -> Result<Self>;
}
impl FromDeriveInput for () {
fn from_derive_input(_: &DeriveInput) -> Result<Self> {
Ok(())
}
}
impl FromDeriveInput for DeriveInput {
fn from_derive_input(input: &DeriveInput) -> Result<Self> {
Ok(input.clone())
}
}

38
vendor/darling_core/src/from_field.rs vendored Normal file
View File

@@ -0,0 +1,38 @@
use syn::Field;
use crate::Result;
/// Creates an instance by parsing an individual field and its attributes.
pub trait FromField: Sized {
fn from_field(field: &Field) -> Result<Self>;
}
impl FromField for () {
fn from_field(_: &Field) -> Result<Self> {
Ok(())
}
}
impl FromField for Field {
fn from_field(field: &Field) -> Result<Self> {
Ok(field.clone())
}
}
impl FromField for syn::Type {
fn from_field(field: &Field) -> Result<Self> {
Ok(field.ty.clone())
}
}
impl FromField for syn::Visibility {
fn from_field(field: &Field) -> Result<Self> {
Ok(field.vis.clone())
}
}
impl FromField for Vec<syn::Attribute> {
fn from_field(field: &Field) -> Result<Self> {
Ok(field.attrs.clone())
}
}

View File

@@ -0,0 +1,19 @@
use crate::Result;
/// Creates an instance by parsing a specific `syn::GenericParam`.
/// This can be a type param, a lifetime, or a const param.
pub trait FromGenericParam: Sized {
fn from_generic_param(param: &syn::GenericParam) -> Result<Self>;
}
impl FromGenericParam for () {
fn from_generic_param(_param: &syn::GenericParam) -> Result<Self> {
Ok(())
}
}
impl FromGenericParam for syn::GenericParam {
fn from_generic_param(param: &syn::GenericParam) -> Result<Self> {
Ok(param.clone())
}
}

View File

@@ -0,0 +1,27 @@
use syn::Generics;
use crate::Result;
/// Creates an instance by parsing an entire generics declaration, including the
/// `where` clause.
pub trait FromGenerics: Sized {
fn from_generics(generics: &Generics) -> Result<Self>;
}
impl FromGenerics for () {
fn from_generics(_generics: &Generics) -> Result<Self> {
Ok(())
}
}
impl FromGenerics for Generics {
fn from_generics(generics: &Generics) -> Result<Self> {
Ok(generics.clone())
}
}
impl<T: FromGenerics> FromGenerics for Result<T> {
fn from_generics(generics: &Generics) -> Result<Self> {
Ok(FromGenerics::from_generics(generics))
}
}

1236
vendor/darling_core/src/from_meta.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
use syn::TypeParam;
use crate::Result;
/// Creates an instance by parsing an individual type_param and its attributes.
pub trait FromTypeParam: Sized {
fn from_type_param(type_param: &TypeParam) -> Result<Self>;
}
impl FromTypeParam for () {
fn from_type_param(_: &TypeParam) -> Result<Self> {
Ok(())
}
}
impl FromTypeParam for TypeParam {
fn from_type_param(type_param: &TypeParam) -> Result<Self> {
Ok(type_param.clone())
}
}
impl FromTypeParam for Vec<syn::Attribute> {
fn from_type_param(type_param: &TypeParam) -> Result<Self> {
Ok(type_param.attrs.clone())
}
}
impl FromTypeParam for syn::Ident {
fn from_type_param(type_param: &TypeParam) -> Result<Self> {
Ok(type_param.ident.clone())
}
}

33
vendor/darling_core/src/from_variant.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
use syn::Variant;
use crate::Result;
/// Creates an instance from a specified `syn::Variant`.
pub trait FromVariant: Sized {
/// Create an instance from `syn::Variant`, or return an error.
fn from_variant(variant: &Variant) -> Result<Self>;
}
impl FromVariant for () {
fn from_variant(_: &Variant) -> Result<Self> {
Ok(())
}
}
impl FromVariant for Variant {
fn from_variant(variant: &Variant) -> Result<Self> {
Ok(variant.clone())
}
}
impl FromVariant for syn::Ident {
fn from_variant(variant: &Variant) -> Result<Self> {
Ok(variant.ident.clone())
}
}
impl FromVariant for Vec<syn::Attribute> {
fn from_variant(variant: &Variant) -> Result<Self> {
Ok(variant.attrs.clone())
}
}

43
vendor/darling_core/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,43 @@
#![recursion_limit = "256"]
#![cfg_attr(feature = "diagnostics", feature(proc_macro_diagnostic))]
#![warn(rust_2018_idioms)]
#[cfg(feature = "diagnostics")]
extern crate proc_macro;
#[macro_use]
mod macros_private;
#[macro_use]
mod macros_public;
pub mod ast;
pub(crate) mod codegen;
pub mod derive;
pub mod error;
mod from_attributes;
mod from_derive_input;
mod from_field;
mod from_generic_param;
mod from_generics;
mod from_meta;
mod from_type_param;
mod from_variant;
pub(crate) mod options;
pub mod usage;
pub mod util;
pub use self::error::{Error, Result};
pub use self::from_attributes::FromAttributes;
pub use self::from_derive_input::FromDeriveInput;
pub use self::from_field::FromField;
pub use self::from_generic_param::FromGenericParam;
pub use self::from_generics::FromGenerics;
pub use self::from_meta::FromMeta;
pub use self::from_type_param::FromTypeParam;
pub use self::from_variant::FromVariant;
// Re-exports
#[doc(hidden)]
pub use quote::ToTokens;
#[doc(hidden)]
pub use syn;

View File

@@ -0,0 +1,6 @@
macro_rules! path {
($($path:tt)+) => {
::syn::parse_quote!($($path)+)
//stringify!($($path)+).parse().unwrap()
};
}

View File

@@ -0,0 +1,96 @@
//! Macros that should be exported from both `darling_core` and `darling`.
//! Note that these are **sym-linked** into the main code, and so cannot declare on items that are exported differently
//! in `darling_core` vs. `darling`.
/// Generator for `UsesTypeParam` impls that unions the used type parameters of the selected fields.
///
/// # Usage
/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of
/// fields for the rest of its arguments.
///
/// The type of each passed-in field must implement `UsesTypeParams`, or the resulting code won't compile.
///
/// ```rust
/// # extern crate syn;
/// # use darling_core::uses_type_params;
/// #
/// struct MyField {
/// ty: syn::Type,
/// }
///
/// uses_type_params!(MyField, ty);
///
/// fn main() {
/// // no test run
/// }
/// ```
///
/// `darling` cannot derive this trait automatically, as it doesn't know which information extracted from
/// proc-macro input is meant to constitute "using" the type parameter, but crate consumers should
/// implement it by hand or using the macro.
#[macro_export]
macro_rules! uses_type_params {
($impl_type:ty, $accessor:ident) => {
impl $crate::usage::UsesTypeParams for $impl_type {
fn uses_type_params<'gen>(
&self,
options: &$crate::usage::Options,
type_set: &'gen $crate::usage::IdentSet
) -> $crate::usage::IdentRefSet<'gen> {
self.$accessor.uses_type_params(options, type_set)
}
}
};
($impl_type:ty, $first:ident, $($field:ident),+) => {
impl $crate::usage::UsesTypeParams for $impl_type {
fn uses_type_params<'gen>(
&self,
options: &$crate::usage::Options,
type_set: &'gen $crate::usage::IdentSet
) -> $crate::usage::IdentRefSet<'gen> {
let mut hits = self.$first.uses_type_params(options, type_set);
$(
hits.extend(self.$field.uses_type_params(options, type_set));
)*
hits
}
}
};
}
/// Generator for `UsesLifetimes` impls that unions the used lifetimes of the selected fields.
///
/// # Usage
/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of
/// fields for the rest of its arguments.
///
/// The type of each passed-in field must implement `UsesLifetimes`, or the resulting code won't compile.
#[macro_export]
macro_rules! uses_lifetimes {
($impl_type:ty, $accessor:ident) => {
impl $crate::usage::UsesLifetimes for $impl_type {
fn uses_lifetimes<'gen>(
&self,
options: &$crate::usage::Options,
type_set: &'gen $crate::usage::LifetimeSet
) -> $crate::usage::LifetimeRefSet<'gen> {
self.$accessor.uses_lifetimes(options, type_set)
}
}
};
($impl_type:ty, $first:ident, $($field:ident),+) => {
impl $crate::usage::UsesLifetimes for $impl_type {
fn uses_lifetimes<'gen>(
&self,
options: &$crate::usage::Options,
type_set: &'gen $crate::usage::LifetimeSet
) -> $crate::usage::LifetimeRefSet<'gen> {
let mut hits = self.$first.uses_lifetimes(options, type_set);
$(
hits.extend(self.$field.uses_lifetimes(options, type_set));
)*
hits
}
}
};
}

197
vendor/darling_core/src/options/core.rs vendored Normal file
View File

@@ -0,0 +1,197 @@
use ident_case::RenameRule;
use crate::ast::{Data, Fields, Style};
use crate::codegen;
use crate::codegen::PostfixTransform;
use crate::error::Accumulator;
use crate::options::{DefaultExpression, InputField, InputVariant, ParseAttribute, ParseData};
use crate::{Error, FromMeta, Result};
/// A struct or enum which should have `FromMeta` or `FromDeriveInput` implementations
/// generated.
#[derive(Debug, Clone)]
pub struct Core {
/// The type identifier.
pub ident: syn::Ident,
/// The type's generics. If the type does not use any generics, this will
/// be an empty instance.
pub generics: syn::Generics,
/// Controls whether missing properties should cause errors or should be filled by
/// the result of a function call. This can be overridden at the field level.
pub default: Option<DefaultExpression>,
/// The rule that should be used to rename all fields/variants in the container.
pub rename_rule: RenameRule,
/// A transform which will be called on `darling::Result<Self>`. It must either be
/// an `FnOnce(T) -> T` when `map` is used, or `FnOnce(T) -> darling::Result<T>` when
/// `and_then` is used.
///
/// `map` and `and_then` are mutually-exclusive to avoid confusion about the order in
/// which the two are applied.
pub post_transform: Option<codegen::PostfixTransform>,
/// The body of the _deriving_ type.
pub data: Data<InputVariant, InputField>,
/// The custom bound to apply to the generated impl
pub bound: Option<Vec<syn::WherePredicate>>,
/// Whether or not unknown fields should produce an error at compilation time.
pub allow_unknown_fields: Option<bool>,
}
impl Core {
/// Partially initializes `Core` by reading the identity, generics, and body shape.
pub fn start(di: &syn::DeriveInput) -> Result<Self> {
Ok(Core {
ident: di.ident.clone(),
generics: di.generics.clone(),
data: Data::try_empty_from(&di.data)?,
default: Default::default(),
// See https://github.com/TedDriggs/darling/issues/10: We default to snake_case
// for enums to help authors produce more idiomatic APIs.
rename_rule: if let syn::Data::Enum(_) = di.data {
RenameRule::SnakeCase
} else {
Default::default()
},
post_transform: Default::default(),
bound: Default::default(),
allow_unknown_fields: Default::default(),
})
}
fn as_codegen_default(&self) -> Option<codegen::DefaultExpression<'_>> {
self.default.as_ref().map(|expr| match *expr {
DefaultExpression::Explicit(ref path) => codegen::DefaultExpression::Explicit(path),
DefaultExpression::Inherit => {
// It should be impossible for any input to get here,
// so panic rather than returning an error or pretending
// everything is fine.
panic!("DefaultExpression::Inherit is not valid at container level")
}
DefaultExpression::Trait { span } => codegen::DefaultExpression::Trait { span },
})
}
}
impl ParseAttribute for Core {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
let path = mi.path();
if path.is_ident("default") {
if self.default.is_some() {
return Err(Error::duplicate_field("default").with_span(mi));
}
self.default = FromMeta::from_meta(mi)?;
} else if path.is_ident("rename_all") {
// WARNING: This may have been set based on body shape previously,
// so an overwrite may be permissible.
self.rename_rule = FromMeta::from_meta(mi)?;
} else if path.is_ident("map") || path.is_ident("and_then") {
// This unwrap is safe because we just called is_ident above
let transformer = path.get_ident().unwrap().clone();
if let Some(post_transform) = &self.post_transform {
if transformer == post_transform.transformer {
return Err(Error::duplicate_field(&transformer.to_string()).with_span(mi));
} else {
return Err(Error::custom(format!(
"Options `{}` and `{}` are mutually exclusive",
transformer, post_transform.transformer
))
.with_span(mi));
}
}
self.post_transform =
Some(PostfixTransform::new(transformer, FromMeta::from_meta(mi)?));
} else if path.is_ident("bound") {
self.bound = FromMeta::from_meta(mi)?;
} else if path.is_ident("allow_unknown_fields") {
if self.allow_unknown_fields.is_some() {
return Err(Error::duplicate_field("allow_unknown_fields").with_span(mi));
}
self.allow_unknown_fields = FromMeta::from_meta(mi)?;
} else {
return Err(Error::unknown_field_path(path).with_span(mi));
}
Ok(())
}
}
impl ParseData for Core {
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
let v = InputVariant::from_variant(variant, Some(self))?;
match self.data {
Data::Enum(ref mut variants) => {
variants.push(v);
Ok(())
}
Data::Struct(_) => panic!("Core::parse_variant should never be called for a struct"),
}
}
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
let f = InputField::from_field(field, Some(self))?;
match self.data {
Data::Struct(Fields {
style: Style::Unit, ..
}) => panic!("Core::parse_field should not be called on unit"),
Data::Struct(Fields { ref mut fields, .. }) => {
fields.push(f);
Ok(())
}
Data::Enum(_) => panic!("Core::parse_field should never be called for an enum"),
}
}
fn validate_body(&self, errors: &mut Accumulator) {
if let Data::Struct(fields) = &self.data {
let flatten_targets: Vec<_> = fields
.iter()
.filter_map(|field| {
if field.flatten.is_present() {
Some(field.flatten)
} else {
None
}
})
.collect();
if flatten_targets.len() > 1 {
for flatten in flatten_targets {
errors.push(
Error::custom("`#[darling(flatten)]` can only be applied to one field")
.with_span(&flatten.span()),
);
}
}
}
}
}
impl<'a> From<&'a Core> for codegen::TraitImpl<'a> {
fn from(v: &'a Core) -> Self {
codegen::TraitImpl {
ident: &v.ident,
generics: &v.generics,
data: v
.data
.as_ref()
.map_struct_fields(InputField::as_codegen_field)
.map_enum_variants(|variant| variant.as_codegen_variant(&v.ident)),
default: v.as_codegen_default(),
post_transform: v.post_transform.as_ref(),
allow_unknown_fields: v.allow_unknown_fields.unwrap_or_default(),
}
}
}

View File

@@ -0,0 +1,30 @@
use crate::ast::NestedMeta;
use crate::util::PathList;
use crate::{FromMeta, Result};
/// A rule about which attributes to forward to the generated struct.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ForwardAttrsFilter {
All,
Only(PathList),
}
impl ForwardAttrsFilter {
/// Returns `true` if this will not forward any attributes.
pub fn is_empty(&self) -> bool {
match *self {
ForwardAttrsFilter::All => false,
ForwardAttrsFilter::Only(ref list) => list.is_empty(),
}
}
}
impl FromMeta for ForwardAttrsFilter {
fn from_word() -> Result<Self> {
Ok(ForwardAttrsFilter::All)
}
fn from_list(nested: &[NestedMeta]) -> Result<Self> {
Ok(ForwardAttrsFilter::Only(PathList::from_list(nested)?))
}
}

View File

@@ -0,0 +1,43 @@
use syn::{Ident, Path};
use crate::{Error, FromField, FromMeta};
use super::ParseAttribute;
/// A forwarded field and attributes that influence its behavior.
#[derive(Debug, Clone)]
pub struct ForwardedField {
/// The ident of the field that will receive the forwarded value.
pub ident: Ident,
/// Path of the function that will be called to convert the forwarded value
/// into the type expected by the field in `ident`.
pub with: Option<Path>,
}
impl FromField for ForwardedField {
fn from_field(field: &syn::Field) -> crate::Result<Self> {
let result = Self {
ident: field.ident.clone().ok_or_else(|| {
Error::custom("forwarded field must be named field").with_span(field)
})?,
with: None,
};
result.parse_attributes(&field.attrs)
}
}
impl ParseAttribute for ForwardedField {
fn parse_nested(&mut self, mi: &syn::Meta) -> crate::Result<()> {
if mi.path().is_ident("with") {
if self.with.is_some() {
return Err(Error::duplicate_field_path(mi.path()).with_span(mi));
}
self.with = FromMeta::from_meta(mi)?;
Ok(())
} else {
Err(Error::unknown_field_path_with_alts(mi.path(), &["with"]).with_span(mi))
}
}
}

View File

@@ -0,0 +1,74 @@
use quote::ToTokens;
use crate::{ast::Data, codegen::FromAttributesImpl, Error, Result};
use super::{OuterFrom, ParseAttribute, ParseData};
/// Receiver for derived `FromAttributes` impls.
pub struct FromAttributesOptions {
// Note: FromAttributes has no behaviors beyond those common
// to all the `OuterFrom` traits.
pub base: OuterFrom,
}
impl FromAttributesOptions {
pub fn new(di: &syn::DeriveInput) -> Result<Self> {
let opts = (Self {
base: OuterFrom::start(di)?,
})
.parse_attributes(&di.attrs)?
.parse_body(&di.data)?;
if !opts.is_newtype() && opts.base.attr_names.is_empty() {
Err(Error::custom(
"FromAttributes without attributes collects nothing",
))
} else {
Ok(opts)
}
}
fn is_newtype(&self) -> bool {
if let Data::Struct(ref data) = self.base.container.data {
data.is_newtype()
} else {
false
}
}
}
impl ParseAttribute for FromAttributesOptions {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
self.base.parse_nested(mi)
}
}
impl ParseData for FromAttributesOptions {
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
self.base.parse_variant(variant)
}
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
self.base.parse_field(field)
}
fn validate_body(&self, errors: &mut crate::error::Accumulator) {
self.base.validate_body(errors);
}
}
impl<'a> From<&'a FromAttributesOptions> for FromAttributesImpl<'a> {
fn from(v: &'a FromAttributesOptions) -> Self {
FromAttributesImpl {
base: (&v.base.container).into(),
attr_names: &v.base.attr_names,
forward_attrs: v.base.as_forward_attrs(),
}
}
}
impl ToTokens for FromAttributesOptions {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
FromAttributesImpl::from(self).to_tokens(tokens)
}
}

View File

@@ -0,0 +1,100 @@
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::Ident;
use crate::codegen::FromDeriveInputImpl;
use crate::options::{DeriveInputShapeSet, OuterFrom, ParseAttribute, ParseData};
use crate::{FromField, FromMeta, Result};
use super::forwarded_field::ForwardedField;
#[derive(Debug)]
pub struct FdiOptions {
pub base: OuterFrom,
/// The field on the target struct which should receive the type visibility, if any.
pub vis: Option<Ident>,
/// The field on the target struct which should receive the type generics, if any.
pub generics: Option<Ident>,
/// The field on the target struct which should receive the derive input body, if any.
pub data: Option<ForwardedField>,
pub supports: Option<DeriveInputShapeSet>,
}
impl FdiOptions {
pub fn new(di: &syn::DeriveInput) -> Result<Self> {
(FdiOptions {
base: OuterFrom::start(di)?,
vis: Default::default(),
generics: Default::default(),
data: Default::default(),
supports: Default::default(),
})
.parse_attributes(&di.attrs)?
.parse_body(&di.data)
}
}
impl ParseAttribute for FdiOptions {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
if mi.path().is_ident("supports") {
self.supports = FromMeta::from_meta(mi)?;
Ok(())
} else {
self.base.parse_nested(mi)
}
}
}
impl ParseData for FdiOptions {
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
self.base.parse_variant(variant)
}
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
Some("vis") => {
self.vis.clone_from(&field.ident);
Ok(())
}
Some("data") => {
self.data = ForwardedField::from_field(field).map(Some)?;
Ok(())
}
Some("generics") => {
self.generics.clone_from(&field.ident);
Ok(())
}
_ => self.base.parse_field(field),
}
}
fn validate_body(&self, errors: &mut crate::error::Accumulator) {
self.base.validate_body(errors);
}
}
impl<'a> From<&'a FdiOptions> for FromDeriveInputImpl<'a> {
fn from(v: &'a FdiOptions) -> Self {
FromDeriveInputImpl {
base: (&v.base.container).into(),
attr_names: &v.base.attr_names,
from_ident: v.base.from_ident,
ident: v.base.ident.as_ref(),
vis: v.vis.as_ref(),
data: v.data.as_ref(),
generics: v.generics.as_ref(),
forward_attrs: v.base.as_forward_attrs(),
supports: v.supports.as_ref(),
}
}
}
impl ToTokens for FdiOptions {
fn to_tokens(&self, tokens: &mut TokenStream) {
FromDeriveInputImpl::from(self).to_tokens(tokens)
}
}

View File

@@ -0,0 +1,76 @@
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::Ident;
use crate::codegen::FromFieldImpl;
use crate::options::{OuterFrom, ParseAttribute, ParseData};
use crate::Result;
#[derive(Debug)]
pub struct FromFieldOptions {
pub base: OuterFrom,
pub vis: Option<Ident>,
pub ty: Option<Ident>,
}
impl FromFieldOptions {
pub fn new(di: &syn::DeriveInput) -> Result<Self> {
(FromFieldOptions {
base: OuterFrom::start(di)?,
vis: Default::default(),
ty: Default::default(),
})
.parse_attributes(&di.attrs)?
.parse_body(&di.data)
}
}
impl ParseAttribute for FromFieldOptions {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
self.base.parse_nested(mi)
}
}
impl ParseData for FromFieldOptions {
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
self.base.parse_variant(variant)
}
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
Some("vis") => {
self.vis.clone_from(&field.ident);
Ok(())
}
Some("ty") => {
self.ty.clone_from(&field.ident);
Ok(())
}
_ => self.base.parse_field(field),
}
}
fn validate_body(&self, errors: &mut crate::error::Accumulator) {
self.base.validate_body(errors);
}
}
impl<'a> From<&'a FromFieldOptions> for FromFieldImpl<'a> {
fn from(v: &'a FromFieldOptions) -> Self {
FromFieldImpl {
ident: v.base.ident.as_ref(),
vis: v.vis.as_ref(),
ty: v.ty.as_ref(),
base: (&v.base.container).into(),
attr_names: &v.base.attr_names,
forward_attrs: v.base.as_forward_attrs(),
from_ident: v.base.from_ident,
}
}
}
impl ToTokens for FromFieldOptions {
fn to_tokens(&self, tokens: &mut TokenStream) {
FromFieldImpl::from(self).to_tokens(tokens)
}
}

View File

@@ -0,0 +1,153 @@
use std::borrow::Cow;
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::parse_quote;
use crate::ast::Data;
use crate::codegen::FromMetaImpl;
use crate::error::Accumulator;
use crate::options::{Core, ParseAttribute, ParseData};
use crate::util::Callable;
use crate::{Error, FromMeta, Result};
pub struct FromMetaOptions {
base: Core,
/// Override for the default [`FromMeta::from_word`] method.
from_word: Option<Callable>,
/// Override for the default [`FromMeta::from_none`] method.
from_none: Option<Callable>,
}
impl FromMetaOptions {
pub fn new(di: &syn::DeriveInput) -> Result<Self> {
(FromMetaOptions {
base: Core::start(di)?,
from_word: None,
from_none: None,
})
.parse_attributes(&di.attrs)?
.parse_body(&di.data)
}
/// Get the `from_word` method body, if one exists. This can come from direct use of
/// `#[darling(from_word = ...)]` on the container or from use of `#[darling(word)]` on
/// a unit variant.
#[allow(
clippy::wrong_self_convention,
// The reason is commented out due to MSRV issues.
// reason = "This matches the name of the input option and output method"
)]
fn from_word(&self) -> Option<Cow<'_, Callable>> {
self.from_word.as_ref().map(Cow::Borrowed).or_else(|| {
if let Data::Enum(ref variants) = self.base.data {
// The first variant which has `word` set to `true`.
// This assumes that validation has prevented multiple variants
// from claiming `word`.
let variant = variants
.iter()
.find(|v| v.word.map(|x| *x).unwrap_or_default())?;
let variant_ident = &variant.ident;
let closure: syn::ExprClosure = parse_quote! {
|| ::darling::export::Ok(Self::#variant_ident)
};
Some(Cow::Owned(Callable::from(closure)))
} else {
None
}
})
}
}
impl ParseAttribute for FromMetaOptions {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
let path = mi.path();
if path.is_ident("from_word") {
if self.from_word.is_some() {
return Err(Error::duplicate_field_path(path).with_span(path));
}
self.from_word = FromMeta::from_meta(mi).map(Some)?;
} else if path.is_ident("from_none") {
if self.from_none.is_some() {
return Err(Error::duplicate_field_path(path).with_span(path));
}
self.from_none = FromMeta::from_meta(mi).map(Some)?;
} else {
self.base.parse_nested(mi)?;
}
Ok(())
}
}
impl ParseData for FromMetaOptions {
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
self.base.parse_variant(variant)
}
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
self.base.parse_field(field)
}
fn validate_body(&self, errors: &mut Accumulator) {
self.base.validate_body(errors);
match self.base.data {
Data::Struct(ref data) => {
if let Some(from_word) = &self.from_word {
if data.is_unit() {
errors.push(Error::custom("`from_word` cannot be used on unit structs because it conflicts with the generated impl").with_span(from_word));
} else if data.is_newtype() {
errors.push(Error::custom("`from_word` cannot be used on newtype structs because the implementation is entirely delegated to the inner type").with_span(from_word));
}
}
}
Data::Enum(ref data) => {
let word_variants: Vec<_> = data
.iter()
.filter_map(|variant| variant.word.as_ref())
.collect();
if !word_variants.is_empty() {
if let Some(from_word) = &self.from_word {
errors.push(
Error::custom(
"`from_word` cannot be used with an enum that also uses `word`",
)
.with_span(from_word),
)
}
}
// Adds errors for duplicate `#[darling(word)]` annotations across all variants.
if word_variants.len() > 1 {
for word in word_variants {
errors.push(
Error::custom("`#[darling(word)]` can only be applied to one variant")
.with_span(&word.span()),
);
}
}
}
}
}
}
impl<'a> From<&'a FromMetaOptions> for FromMetaImpl<'a> {
fn from(v: &'a FromMetaOptions) -> Self {
FromMetaImpl {
base: (&v.base).into(),
from_word: v.from_word(),
from_none: v.from_none.as_ref(),
}
}
}
impl ToTokens for FromMetaOptions {
fn to_tokens(&self, tokens: &mut TokenStream) {
FromMetaImpl::from(self).to_tokens(tokens)
}
}

View File

@@ -0,0 +1,76 @@
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::Ident;
use crate::codegen::FromTypeParamImpl;
use crate::options::{OuterFrom, ParseAttribute, ParseData};
use crate::Result;
#[derive(Debug)]
pub struct FromTypeParamOptions {
pub base: OuterFrom,
pub bounds: Option<Ident>,
pub default: Option<Ident>,
}
impl FromTypeParamOptions {
pub fn new(di: &syn::DeriveInput) -> Result<Self> {
(FromTypeParamOptions {
base: OuterFrom::start(di)?,
bounds: None,
default: None,
})
.parse_attributes(&di.attrs)?
.parse_body(&di.data)
}
}
impl ParseAttribute for FromTypeParamOptions {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
self.base.parse_nested(mi)
}
}
impl ParseData for FromTypeParamOptions {
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
self.base.parse_variant(variant)
}
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
Some("bounds") => {
self.bounds.clone_from(&field.ident);
Ok(())
}
Some("default") => {
self.default.clone_from(&field.ident);
Ok(())
}
_ => self.base.parse_field(field),
}
}
fn validate_body(&self, errors: &mut crate::error::Accumulator) {
self.base.validate_body(errors);
}
}
impl<'a> From<&'a FromTypeParamOptions> for FromTypeParamImpl<'a> {
fn from(v: &'a FromTypeParamOptions) -> Self {
FromTypeParamImpl {
base: (&v.base.container).into(),
ident: v.base.ident.as_ref(),
bounds: v.bounds.as_ref(),
default: v.default.as_ref(),
attr_names: &v.base.attr_names,
forward_attrs: v.base.as_forward_attrs(),
from_ident: v.base.from_ident,
}
}
}
impl ToTokens for FromTypeParamOptions {
fn to_tokens(&self, tokens: &mut TokenStream) {
FromTypeParamImpl::from(self).to_tokens(tokens)
}
}

View File

@@ -0,0 +1,82 @@
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{DeriveInput, Field, Ident, Meta};
use crate::codegen::FromVariantImpl;
use crate::options::{DataShape, OuterFrom, ParseAttribute, ParseData};
use crate::{FromMeta, Result};
#[derive(Debug, Clone)]
pub struct FromVariantOptions {
pub base: OuterFrom,
/// The field on the deriving struct into which the discriminant expression
/// should be placed by the derived `FromVariant` impl.
pub discriminant: Option<Ident>,
pub fields: Option<Ident>,
pub supports: Option<DataShape>,
}
impl FromVariantOptions {
pub fn new(di: &DeriveInput) -> Result<Self> {
(FromVariantOptions {
base: OuterFrom::start(di)?,
discriminant: Default::default(),
fields: Default::default(),
supports: Default::default(),
})
.parse_attributes(&di.attrs)?
.parse_body(&di.data)
}
}
impl<'a> From<&'a FromVariantOptions> for FromVariantImpl<'a> {
fn from(v: &'a FromVariantOptions) -> Self {
FromVariantImpl {
base: (&v.base.container).into(),
ident: v.base.ident.as_ref(),
discriminant: v.discriminant.as_ref(),
fields: v.fields.as_ref(),
attr_names: &v.base.attr_names,
forward_attrs: v.base.as_forward_attrs(),
from_ident: v.base.from_ident,
supports: v.supports.as_ref(),
}
}
}
impl ParseAttribute for FromVariantOptions {
fn parse_nested(&mut self, mi: &Meta) -> Result<()> {
if mi.path().is_ident("supports") {
self.supports = FromMeta::from_meta(mi)?;
Ok(())
} else {
self.base.parse_nested(mi)
}
}
}
impl ParseData for FromVariantOptions {
fn parse_field(&mut self, field: &Field) -> Result<()> {
match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
Some("discriminant") => {
self.discriminant.clone_from(&field.ident);
Ok(())
}
Some("fields") => {
self.fields.clone_from(&field.ident);
Ok(())
}
_ => self.base.parse_field(field),
}
}
fn validate_body(&self, errors: &mut crate::error::Accumulator) {
self.base.validate_body(errors);
}
}
impl ToTokens for FromVariantOptions {
fn to_tokens(&self, tokens: &mut TokenStream) {
FromVariantImpl::from(self).to_tokens(tokens)
}
}

View File

@@ -0,0 +1,241 @@
use std::borrow::Cow;
use syn::{parse_quote_spanned, spanned::Spanned};
use crate::codegen;
use crate::options::{Core, DefaultExpression, ParseAttribute};
use crate::util::{Callable, Flag, SpannedValue};
use crate::{Error, FromMeta, Result};
#[derive(Debug, Clone)]
pub struct InputField {
pub ident: syn::Ident,
pub attr_name: Option<String>,
pub ty: syn::Type,
pub default: Option<DefaultExpression>,
pub with: Option<Callable>,
/// If `true`, generated code will not look for this field in the input meta item,
/// instead always falling back to either `InputField::default` or `Default::default`.
pub skip: Option<SpannedValue<bool>>,
pub post_transform: Option<codegen::PostfixTransform>,
pub multiple: Option<bool>,
pub flatten: Flag,
}
impl InputField {
/// Generate a view into this field that can be used for code generation.
pub fn as_codegen_field(&self) -> codegen::Field<'_> {
codegen::Field {
ident: &self.ident,
name_in_attr: self
.attr_name
.as_ref()
.map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed),
ty: &self.ty,
default_expression: self.as_codegen_default(),
with_callable: self.with.as_ref().map(|w| w.as_ref()).map_or_else(
|| {
Cow::Owned(
parse_quote_spanned!(self.ty.span()=> ::darling::FromMeta::from_meta),
)
},
Cow::Borrowed,
),
skip: *self.skip.unwrap_or_default(),
post_transform: self.post_transform.as_ref(),
multiple: self.multiple.unwrap_or_default(),
flatten: self.flatten.is_present(),
}
}
/// Generate a codegen::DefaultExpression for this field. This requires the field name
/// in the `Inherit` case.
fn as_codegen_default(&self) -> Option<codegen::DefaultExpression<'_>> {
self.default.as_ref().map(|expr| match *expr {
DefaultExpression::Explicit(ref path) => codegen::DefaultExpression::Explicit(path),
DefaultExpression::Inherit => codegen::DefaultExpression::Inherit(&self.ident),
DefaultExpression::Trait { span } => codegen::DefaultExpression::Trait { span },
})
}
fn new(ident: syn::Ident, ty: syn::Type) -> Self {
InputField {
ident,
ty,
attr_name: None,
default: None,
with: None,
skip: None,
post_transform: Default::default(),
multiple: None,
flatten: Default::default(),
}
}
pub fn from_field(f: &syn::Field, parent: Option<&Core>) -> Result<Self> {
let ident = f
.ident
.clone()
.unwrap_or_else(|| syn::Ident::new("__unnamed", ::proc_macro2::Span::call_site()));
let ty = f.ty.clone();
let base = Self::new(ident, ty).parse_attributes(&f.attrs)?;
Ok(if let Some(container) = parent {
base.with_inherited(container)
} else {
base
})
}
/// Apply inherited settings from the container. This is done _after_ parsing
/// to ensure deference to explicit field-level settings.
fn with_inherited(mut self, parent: &Core) -> Self {
// explicit renamings take precedence over rename rules on the container,
// but in the absence of an explicit name we apply the rule.
if self.attr_name.is_none() {
self.attr_name = Some(parent.rename_rule.apply_to_field(self.ident.to_string()));
}
// Determine the default expression for this field, based on three pieces of information:
// 1. Will we look for this field in the attribute?
// 1. Is there a locally-defined default?
// 1. Did the parent define a default?
self.default = match (&self.skip, self.default.is_some(), parent.default.is_some()) {
// If we have a default, use it.
(_, true, _) => self.default,
// If there isn't an explicit default but the struct sets a default, we'll
// inherit from that.
(_, false, true) => Some(DefaultExpression::Inherit),
// If we're skipping the field and no defaults have been expressed then we should
// use the ::darling::export::Default trait, and set the span to the skip keyword
// so that an error caused by the skipped field's type not implementing `Default`
// will correctly identify why darling is trying to use `Default`.
(Some(v), false, false) if **v => Some(DefaultExpression::Trait { span: v.span() }),
// If we don't have or need a default, then leave it blank.
(_, false, false) => None,
};
self
}
}
impl ParseAttribute for InputField {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
let path = mi.path();
if path.is_ident("rename") {
if self.attr_name.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.attr_name = FromMeta::from_meta(mi)?;
if self.flatten.is_present() {
return Err(
Error::custom("`flatten` and `rename` cannot be used together").with_span(mi),
);
}
} else if path.is_ident("default") {
if self.default.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.default = FromMeta::from_meta(mi)?;
} else if path.is_ident("with") {
if self.with.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.with = Some(FromMeta::from_meta(mi)?);
if self.flatten.is_present() {
return Err(
Error::custom("`flatten` and `with` cannot be used together").with_span(mi),
);
}
} else if path.is_ident("skip") {
if self.skip.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.skip = FromMeta::from_meta(mi)?;
if self.skip.map(|v| *v).unwrap_or_default() && self.flatten.is_present() {
return Err(
Error::custom("`flatten` and `skip` cannot be used together").with_span(mi),
);
}
} else if path.is_ident("map") || path.is_ident("and_then") {
let transformer = path.get_ident().unwrap().clone();
if let Some(post_transform) = &self.post_transform {
if transformer == post_transform.transformer {
return Err(Error::duplicate_field_path(path).with_span(mi));
} else {
return Err(Error::custom(format!(
"Options `{}` and `{}` are mutually exclusive",
transformer, post_transform.transformer
))
.with_span(mi));
}
}
self.post_transform = Some(codegen::PostfixTransform::new(
transformer,
FromMeta::from_meta(mi)?,
));
} else if path.is_ident("multiple") {
if self.multiple.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.multiple = FromMeta::from_meta(mi)?;
if self.multiple == Some(true) && self.flatten.is_present() {
return Err(
Error::custom("`flatten` and `multiple` cannot be used together").with_span(mi),
);
}
} else if path.is_ident("flatten") {
if self.flatten.is_present() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.flatten = FromMeta::from_meta(mi)?;
let mut conflicts = Error::accumulator();
if self.multiple == Some(true) {
conflicts.push(
Error::custom("`flatten` and `multiple` cannot be used together").with_span(mi),
);
}
if self.attr_name.is_some() {
conflicts.push(
Error::custom("`flatten` and `rename` cannot be used together").with_span(mi),
);
}
if self.with.is_some() {
conflicts.push(
Error::custom("`flatten` and `with` cannot be used together").with_span(mi),
);
}
if self.skip.map(|v| *v).unwrap_or_default() {
conflicts.push(
Error::custom("`flatten` and `skip` cannot be used together").with_span(mi),
);
}
conflicts.finish()?;
} else {
return Err(Error::unknown_field_path(path).with_span(mi));
}
Ok(())
}
}

View File

@@ -0,0 +1,125 @@
use std::borrow::Cow;
use crate::ast::Fields;
use crate::codegen;
use crate::options::{Core, InputField, ParseAttribute};
use crate::util::SpannedValue;
use crate::{Error, FromMeta, Result};
#[derive(Debug, Clone)]
pub struct InputVariant {
pub ident: syn::Ident,
attr_name: Option<String>,
data: Fields<InputField>,
skip: Option<bool>,
/// Whether or not the variant should be used to create an instance for
/// `FromMeta::from_word`.
pub word: Option<SpannedValue<bool>>,
/// Whether or not unknown fields are acceptable in this
allow_unknown_fields: Option<bool>,
}
impl InputVariant {
pub fn as_codegen_variant<'a>(&'a self, ty_ident: &'a syn::Ident) -> codegen::Variant<'a> {
codegen::Variant {
ty_ident,
variant_ident: &self.ident,
name_in_attr: self
.attr_name
.as_ref()
.map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed),
data: self.data.as_ref().map(InputField::as_codegen_field),
skip: self.skip.unwrap_or_default(),
allow_unknown_fields: self.allow_unknown_fields.unwrap_or_default(),
}
}
pub fn from_variant(v: &syn::Variant, parent: Option<&Core>) -> Result<Self> {
let mut starter = (InputVariant {
ident: v.ident.clone(),
attr_name: Default::default(),
data: Fields::empty_from(&v.fields),
skip: Default::default(),
word: Default::default(),
allow_unknown_fields: None,
})
.parse_attributes(&v.attrs)?;
starter.data.fields = match v.fields {
syn::Fields::Unit => vec![],
syn::Fields::Unnamed(ref fields) => {
let mut items = Vec::with_capacity(fields.unnamed.len());
for item in &fields.unnamed {
items.push(InputField::from_field(item, parent)?);
}
items
}
syn::Fields::Named(ref fields) => {
let mut items = Vec::with_capacity(fields.named.len());
for item in &fields.named {
items.push(InputField::from_field(item, parent)?);
}
items
}
};
Ok(if let Some(p) = parent {
starter.with_inherited(p)
} else {
starter
})
}
fn with_inherited(mut self, parent: &Core) -> Self {
if self.attr_name.is_none() {
self.attr_name = Some(parent.rename_rule.apply_to_variant(self.ident.to_string()));
}
if self.allow_unknown_fields.is_none() {
self.allow_unknown_fields = Some(parent.allow_unknown_fields.unwrap_or_default());
}
self
}
}
impl ParseAttribute for InputVariant {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
let path = mi.path();
if path.is_ident("rename") {
if self.attr_name.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.attr_name = FromMeta::from_meta(mi)?;
} else if path.is_ident("skip") {
if self.skip.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.skip = FromMeta::from_meta(mi)?;
} else if path.is_ident("word") {
if self.word.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
if !self.data.is_unit() {
let note = "`#[darling(word)]` can only be applied to a unit variant";
#[cfg(feature = "diagnostics")]
let error = Error::unknown_field_path(path).note(note);
#[cfg(not(feature = "diagnostics"))]
let error = Error::custom(format!("Unexpected field: `word`. {}", note));
return Err(error.with_span(mi));
}
self.word = FromMeta::from_meta(mi)?;
} else {
return Err(Error::unknown_field_path(path).with_span(mi));
}
Ok(())
}
}

160
vendor/darling_core/src/options/mod.rs vendored Normal file
View File

@@ -0,0 +1,160 @@
use proc_macro2::Span;
use syn::{parse_quote, spanned::Spanned};
use crate::ast::NestedMeta;
use crate::error::Accumulator;
use crate::{Error, FromMeta, Result};
mod core;
mod forward_attrs;
mod forwarded_field;
mod from_attributes;
mod from_derive;
mod from_field;
mod from_meta;
mod from_type_param;
mod from_variant;
mod input_field;
mod input_variant;
mod outer_from;
mod shape;
pub use self::core::Core;
pub use self::forward_attrs::ForwardAttrsFilter;
pub use self::forwarded_field::ForwardedField;
pub use self::from_attributes::FromAttributesOptions;
pub use self::from_derive::FdiOptions;
pub use self::from_field::FromFieldOptions;
pub use self::from_meta::FromMetaOptions;
pub use self::from_type_param::FromTypeParamOptions;
pub use self::from_variant::FromVariantOptions;
pub use self::input_field::InputField;
pub use self::input_variant::InputVariant;
pub use self::outer_from::OuterFrom;
pub use self::shape::{DataShape, DeriveInputShapeSet};
/// A default/fallback expression encountered in attributes during parsing.
#[derive(Debug, Clone)]
pub enum DefaultExpression {
/// The value should be taken from the `default` instance of the containing struct.
/// This is not valid in container options.
Inherit,
Explicit(syn::Path),
Trait {
/// The input span that is responsible for the use of `Default::default`.
span: Span,
},
}
#[doc(hidden)]
impl FromMeta for DefaultExpression {
// Note: This cannot use `from_word` as it needs to capture the span
// in the `Meta::Path` case.
fn from_meta(item: &syn::Meta) -> Result<Self> {
match item {
syn::Meta::Path(_) => Ok(DefaultExpression::Trait { span: item.span() }),
syn::Meta::List(nm) => Err(Error::unsupported_format("list").with_span(nm)),
syn::Meta::NameValue(nv) => Self::from_expr(&nv.value),
}
}
fn from_expr(expr: &syn::Expr) -> Result<Self> {
syn::Path::from_expr(expr).map(DefaultExpression::Explicit)
}
fn from_value(value: &syn::Lit) -> Result<Self> {
syn::Path::from_value(value).map(DefaultExpression::Explicit)
}
}
/// Middleware for extracting attribute values. Implementers are expected to override
/// `parse_nested` so they can apply individual items to themselves, while `parse_attributes`
/// is responsible for looping through distinct outer attributes and collecting errors.
pub trait ParseAttribute: Sized {
fn parse_attributes(mut self, attrs: &[syn::Attribute]) -> Result<Self> {
let mut errors = Error::accumulator();
for attr in attrs {
if attr.meta.path() == &parse_quote!(darling) {
errors.handle(parse_attr(attr, &mut self));
}
}
errors.finish_with(self)
}
/// Read a meta-item, and apply its values to the current instance.
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()>;
}
fn parse_attr<T: ParseAttribute>(attr: &syn::Attribute, target: &mut T) -> Result<()> {
let mut errors = Error::accumulator();
match &attr.meta {
syn::Meta::List(data) => {
for item in NestedMeta::parse_meta_list(data.tokens.clone())? {
if let NestedMeta::Meta(ref mi) = item {
errors.handle(target.parse_nested(mi));
} else {
panic!("Wasn't able to parse: `{:?}`", item);
}
}
errors.finish()
}
item => panic!("Wasn't able to parse: `{:?}`", item),
}
}
/// Middleware for extracting values from the body of the derive input. Implementers are
/// expected to override `parse_field` or `parse_variant` as appropriate for their use-case,
/// while `parse_body` dispatches to the appropriate methods and handles error collection.
pub trait ParseData: Sized {
fn parse_body(mut self, body: &syn::Data) -> Result<Self> {
use syn::{Data, Fields};
let mut errors = Error::accumulator();
match *body {
Data::Struct(ref data) => match data.fields {
Fields::Unit => {}
Fields::Named(ref fields) => {
for field in &fields.named {
errors.handle(self.parse_field(field));
}
}
Fields::Unnamed(ref fields) => {
for field in &fields.unnamed {
errors.handle(self.parse_field(field));
}
}
},
Data::Enum(ref data) => {
for variant in &data.variants {
errors.handle(self.parse_variant(variant));
}
}
Data::Union(_) => unreachable!(),
};
self.validate_body(&mut errors);
errors.finish_with(self)
}
/// Apply the next found variant to the object, returning an error
/// if parsing goes wrong.
fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
Err(Error::unsupported_format("enum variant").with_span(variant))
}
/// Apply the next found struct field to the object, returning an error
/// if parsing goes wrong.
fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
Err(Error::unsupported_format("struct field").with_span(field))
}
/// Perform validation checks that require data from more than one field or variant.
/// The default implementation does no validations.
/// Implementors can override this method as appropriate for their use-case.
#[allow(unused_variables)]
fn validate_body(&self, errors: &mut Accumulator) {}
}

View File

@@ -0,0 +1,111 @@
use syn::spanned::Spanned;
use syn::{Field, Ident, Meta};
use crate::ast::Data;
use crate::codegen::ForwardAttrs;
use crate::options::{
Core, DefaultExpression, ForwardAttrsFilter, ForwardedField, ParseAttribute, ParseData,
};
use crate::util::PathList;
use crate::{Error, FromField, FromMeta, Result};
/// Reusable base for `FromDeriveInput`, `FromVariant`, `FromField`, and other top-level
/// `From*` traits.
#[derive(Debug, Clone)]
pub struct OuterFrom {
/// The field on the target struct which should receive the type identifier, if any.
pub ident: Option<Ident>,
/// The field on the target struct which should receive the type attributes, if any.
pub attrs: Option<ForwardedField>,
pub container: Core,
/// The attribute names that should be searched.
pub attr_names: PathList,
/// The attribute names that should be forwarded. The presence of the word with no additional
/// filtering will cause _all_ attributes to be cloned and exposed to the struct after parsing.
pub forward_attrs: Option<ForwardAttrsFilter>,
/// Whether or not the container can be made through conversion from the type `Ident`.
pub from_ident: bool,
}
impl OuterFrom {
pub fn start(di: &syn::DeriveInput) -> Result<Self> {
Ok(OuterFrom {
container: Core::start(di)?,
attrs: Default::default(),
ident: Default::default(),
attr_names: Default::default(),
forward_attrs: Default::default(),
from_ident: Default::default(),
})
}
pub fn as_forward_attrs(&self) -> ForwardAttrs<'_> {
ForwardAttrs {
field: self.attrs.as_ref(),
filter: self.forward_attrs.as_ref(),
}
}
}
impl ParseAttribute for OuterFrom {
fn parse_nested(&mut self, mi: &Meta) -> Result<()> {
let path = mi.path();
if path.is_ident("attributes") {
self.attr_names = FromMeta::from_meta(mi)?;
} else if path.is_ident("forward_attrs") {
self.forward_attrs = FromMeta::from_meta(mi)?;
} else if path.is_ident("from_ident") {
// HACK: Declaring that a default is present will cause fields to
// generate correct code, but control flow isn't that obvious.
self.container.default = Some(DefaultExpression::Trait {
// Use the span of the `from_ident` keyword so that errors in generated code
// caused by this will point back to the correct location.
span: path.span(),
});
self.from_ident = true;
} else {
return self.container.parse_nested(mi);
}
Ok(())
}
}
impl ParseData for OuterFrom {
fn parse_field(&mut self, field: &Field) -> Result<()> {
match field.ident.as_ref().map(|v| v.to_string()).as_deref() {
Some("ident") => {
self.ident.clone_from(&field.ident);
Ok(())
}
Some("attrs") => {
self.attrs = ForwardedField::from_field(field).map(Some)?;
Ok(())
}
_ => self.container.parse_field(field),
}
}
fn validate_body(&self, errors: &mut crate::error::Accumulator) {
self.container.validate_body(errors);
if let Some(attrs) = &self.attrs {
if self.forward_attrs.is_none() {
let container_name = match &self.container.data {
Data::Enum(_) => "enum",
Data::Struct(_) => "struct",
};
errors.push(
Error::custom(format!(
"field will not be populated because `forward_attrs` is not set on the {}",
container_name
))
.with_span(&attrs.ident),
);
}
}
}
}

259
vendor/darling_core/src/options/shape.rs vendored Normal file
View File

@@ -0,0 +1,259 @@
//! Types for "shape" validation. This allows types deriving `FromDeriveInput` etc. to declare
//! that they only work on - for example - structs with named fields, or newtype enum variants.
use proc_macro2::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{parse_quote, Meta};
use crate::ast::NestedMeta;
use crate::{Error, FromMeta, Result};
/// Receiver struct for shape validation. Shape validation allows a deriving type
/// to declare that it only accepts - for example - named structs, or newtype enum
/// variants.
///
/// ```rust,ignore
/// #[ignore(any, struct_named, enum_newtype)]
/// ```
#[derive(Debug, Clone)]
pub struct DeriveInputShapeSet {
enum_values: DataShape,
struct_values: DataShape,
any: bool,
}
impl Default for DeriveInputShapeSet {
fn default() -> Self {
DeriveInputShapeSet {
enum_values: DataShape::new("enum_"),
struct_values: DataShape::new("struct_"),
any: Default::default(),
}
}
}
impl FromMeta for DeriveInputShapeSet {
fn from_list(items: &[NestedMeta]) -> Result<Self> {
let mut new = DeriveInputShapeSet::default();
for item in items {
if let NestedMeta::Meta(Meta::Path(ref path)) = *item {
let ident = &path.segments.first().unwrap().ident;
let word = ident.to_string();
if word == "any" {
new.any = true;
} else if word.starts_with("enum_") {
new.enum_values
.set_word(&word)
.map_err(|e| e.with_span(&ident))?;
} else if word.starts_with("struct_") {
new.struct_values
.set_word(&word)
.map_err(|e| e.with_span(&ident))?;
} else {
return Err(Error::unknown_value(&word).with_span(&ident));
}
} else {
return Err(Error::unsupported_format("non-word").with_span(item));
}
}
Ok(new)
}
}
impl ToTokens for DeriveInputShapeSet {
fn to_tokens(&self, tokens: &mut TokenStream) {
let fn_body = if self.any {
quote!(::darling::export::Ok(()))
} else {
let en = &self.enum_values;
let st = &self.struct_values;
quote! {
{
let struct_check = #st;
let enum_check = #en;
match *__body {
::darling::export::syn::Data::Enum(ref data) => {
if enum_check.is_empty() {
return ::darling::export::Err(
::darling::Error::unsupported_shape_with_expected("enum", &format!("struct with {}", struct_check))
);
}
let mut variant_errors = ::darling::Error::accumulator();
for variant in &data.variants {
variant_errors.handle(enum_check.check(variant));
}
variant_errors.finish()
}
::darling::export::syn::Data::Struct(ref struct_data) => {
if struct_check.is_empty() {
return ::darling::export::Err(
::darling::Error::unsupported_shape_with_expected("struct", &format!("enum with {}", enum_check))
);
}
struct_check.check(struct_data)
}
::darling::export::syn::Data::Union(_) => unreachable!(),
}
}
}
};
tokens.append_all(quote! {
#[allow(unused_variables)]
fn __validate_body(__body: &::darling::export::syn::Data) -> ::darling::Result<()> {
#fn_body
}
});
}
}
/// Receiver for shape information within a struct or enum context. See `Shape` for more information
/// on valid uses of shape validation.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct DataShape {
/// The kind of shape being described. This can be `struct_` or `enum_`.
prefix: &'static str,
newtype: bool,
named: bool,
tuple: bool,
unit: bool,
any: bool,
}
impl DataShape {
fn new(prefix: &'static str) -> Self {
DataShape {
prefix,
..Default::default()
}
}
fn set_word(&mut self, word: &str) -> Result<()> {
match word.trim_start_matches(self.prefix) {
"newtype" => {
self.newtype = true;
Ok(())
}
"named" => {
self.named = true;
Ok(())
}
"tuple" => {
self.tuple = true;
Ok(())
}
"unit" => {
self.unit = true;
Ok(())
}
"any" => {
self.any = true;
Ok(())
}
_ => Err(Error::unknown_value(word)),
}
}
}
impl FromMeta for DataShape {
fn from_list(items: &[NestedMeta]) -> Result<Self> {
let mut errors = Error::accumulator();
let mut new = DataShape::default();
for item in items {
if let NestedMeta::Meta(Meta::Path(ref path)) = *item {
errors.handle(new.set_word(&path.segments.first().unwrap().ident.to_string()));
} else {
errors.push(Error::unsupported_format("non-word").with_span(item));
}
}
errors.finish_with(new)
}
}
impl ToTokens for DataShape {
fn to_tokens(&self, tokens: &mut TokenStream) {
let Self {
any,
named,
tuple,
unit,
newtype,
..
} = *self;
let shape_path: syn::Path = parse_quote!(::darling::util::Shape);
let mut shapes = vec![];
if any || named {
shapes.push(quote!(#shape_path::Named));
}
if any || tuple {
shapes.push(quote!(#shape_path::Tuple));
}
if any || newtype {
shapes.push(quote!(#shape_path::Newtype));
}
if any || unit {
shapes.push(quote!(#shape_path::Unit));
}
tokens.append_all(quote! {
::darling::util::ShapeSet::new(vec![#(#shapes),*])
});
}
}
#[cfg(test)]
mod tests {
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse_quote;
use super::DeriveInputShapeSet;
use crate::FromMeta;
/// parse a string as a syn::Meta instance.
fn pm(tokens: TokenStream) -> ::std::result::Result<syn::Meta, String> {
let attribute: syn::Attribute = parse_quote!(#[#tokens]);
Ok(attribute.meta)
}
fn fm<T: FromMeta>(tokens: TokenStream) -> T {
FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input"))
.expect("Tests should pass valid input")
}
#[test]
fn supports_any() {
let decl = fm::<DeriveInputShapeSet>(quote!(ignore(any)));
assert!(decl.any);
}
#[test]
fn supports_struct() {
let decl = fm::<DeriveInputShapeSet>(quote!(ignore(struct_any, struct_newtype)));
assert!(decl.struct_values.any);
assert!(decl.struct_values.newtype);
}
#[test]
fn supports_mixed() {
let decl =
fm::<DeriveInputShapeSet>(quote!(ignore(struct_newtype, enum_newtype, enum_tuple)));
assert!(decl.struct_values.newtype);
assert!(decl.enum_values.newtype);
assert!(decl.enum_values.tuple);
assert!(!decl.struct_values.any);
}
}

View File

@@ -0,0 +1,24 @@
use syn::Generics;
use crate::usage::{IdentSet, LifetimeSet};
/// Extension trait for pulling specific generics data from a generics AST representation.
pub trait GenericsExt {
/// Get the set of all lifetimes declared by the syntax element.
/// This does not look for usage of the lifetime; see `UsesLifetimes` for that.
fn declared_lifetimes(&self) -> LifetimeSet;
/// Get the set of all type parameters declared by the syntax element.
/// This does not look for usage of the type parameter; see `UsesTypeParams` for that.
fn declared_type_params(&self) -> IdentSet;
}
impl GenericsExt for Generics {
fn declared_lifetimes(&self) -> LifetimeSet {
self.lifetimes().map(|lt| lt.lifetime.clone()).collect()
}
fn declared_type_params(&self) -> IdentSet {
self.type_params().map(|tp| tp.ident.clone()).collect()
}
}

View File

@@ -0,0 +1,8 @@
use fnv::FnvHashSet;
use syn::Ident;
/// A set of idents.
pub type IdentSet = FnvHashSet<Ident>;
/// A set of references to idents.
pub type IdentRefSet<'a> = FnvHashSet<&'a Ident>;

View File

@@ -0,0 +1,351 @@
use fnv::FnvHashSet;
use syn::punctuated::Punctuated;
use syn::{Lifetime, Type};
use crate::usage::Options;
/// A set of lifetimes.
pub type LifetimeSet = FnvHashSet<Lifetime>;
/// A set of references to lifetimes.
pub type LifetimeRefSet<'a> = FnvHashSet<&'a Lifetime>;
/// Searcher for finding lifetimes in a syntax tree.
/// This can be used to determine which lifetimes must be emitted in generated code.
pub trait UsesLifetimes {
/// Returns the subset of the queried lifetimes that are used by the implementing syntax element.
///
/// This method only accounts for direct usage by the element; indirect usage via bounds or `where`
/// predicates are not detected.
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a>;
/// Find all used lifetimes, then clone them and return that set.
fn uses_lifetimes_cloned(&self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet {
self.uses_lifetimes(options, lifetimes)
.into_iter()
.cloned()
.collect()
}
}
/// Searcher for finding lifetimes in an iterator.
///
/// This trait extends iterators, providing a way to turn a filtered list of fields or variants into a set
/// of lifetimes.
pub trait CollectLifetimes {
/// Consume an iterator, accumulating all lifetimes in the elements which occur in `lifetimes`.
fn collect_lifetimes<'a>(
self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a>;
/// Consume an iterator using `collect_lifetimes`, then clone all found lifetimes and return that set.
fn collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet;
}
impl<'i, I, T> CollectLifetimes for T
where
T: IntoIterator<Item = &'i I>,
I: 'i + UsesLifetimes,
{
fn collect_lifetimes<'a>(
self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
self.into_iter()
.fold(Default::default(), |mut state, value| {
state.extend(value.uses_lifetimes(options, lifetimes));
state
})
}
fn collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet {
self.collect_lifetimes(options, lifetimes)
.into_iter()
.cloned()
.collect()
}
}
impl<T: UsesLifetimes> UsesLifetimes for Vec<T> {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
self.collect_lifetimes(options, lifetimes)
}
}
impl<T: UsesLifetimes, U> UsesLifetimes for Punctuated<T, U> {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
self.collect_lifetimes(options, lifetimes)
}
}
impl<T: UsesLifetimes> UsesLifetimes for Option<T> {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
self.as_ref()
.map(|v| v.uses_lifetimes(options, lifetimes))
.unwrap_or_default()
}
}
impl UsesLifetimes for Lifetime {
fn uses_lifetimes<'a>(&self, _: &Options, lifetimes: &'a LifetimeSet) -> LifetimeRefSet<'a> {
lifetimes.iter().filter(|lt| *lt == self).collect()
}
}
uses_lifetimes!(syn::AngleBracketedGenericArguments, args);
uses_lifetimes!(syn::AssocType, ty);
uses_lifetimes!(syn::BareFnArg, ty);
uses_lifetimes!(syn::BoundLifetimes, lifetimes);
uses_lifetimes!(syn::ConstParam, ty);
uses_lifetimes!(syn::Constraint, bounds);
uses_lifetimes!(syn::DataEnum, variants);
uses_lifetimes!(syn::DataStruct, fields);
uses_lifetimes!(syn::DataUnion, fields);
uses_lifetimes!(syn::Field, ty);
uses_lifetimes!(syn::FieldsNamed, named);
uses_lifetimes!(syn::LifetimeParam, lifetime, bounds);
uses_lifetimes!(syn::ParenthesizedGenericArguments, inputs, output);
uses_lifetimes!(syn::Path, segments);
uses_lifetimes!(syn::PathSegment, arguments);
uses_lifetimes!(syn::PredicateLifetime, lifetime, bounds);
uses_lifetimes!(syn::PredicateType, lifetimes, bounded_ty, bounds);
uses_lifetimes!(syn::QSelf, ty);
uses_lifetimes!(syn::TraitBound, path, lifetimes);
uses_lifetimes!(syn::TypeArray, elem);
uses_lifetimes!(syn::TypeBareFn, inputs, output);
uses_lifetimes!(syn::TypeGroup, elem);
uses_lifetimes!(syn::TypeImplTrait, bounds);
uses_lifetimes!(syn::TypeParam, bounds);
uses_lifetimes!(syn::TypeParen, elem);
uses_lifetimes!(syn::TypePtr, elem);
uses_lifetimes!(syn::TypeReference, lifetime, elem);
uses_lifetimes!(syn::TypeSlice, elem);
uses_lifetimes!(syn::TypeTuple, elems);
uses_lifetimes!(syn::TypeTraitObject, bounds);
uses_lifetimes!(syn::Variant, fields);
impl UsesLifetimes for syn::Data {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
match *self {
syn::Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes),
syn::Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes),
syn::Data::Union(ref v) => v.uses_lifetimes(options, lifetimes),
}
}
}
impl UsesLifetimes for Type {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
match *self {
Type::Slice(ref v) => v.uses_lifetimes(options, lifetimes),
Type::Array(ref v) => v.uses_lifetimes(options, lifetimes),
Type::Ptr(ref v) => v.uses_lifetimes(options, lifetimes),
Type::Reference(ref v) => v.uses_lifetimes(options, lifetimes),
Type::BareFn(ref v) => v.uses_lifetimes(options, lifetimes),
Type::Tuple(ref v) => v.uses_lifetimes(options, lifetimes),
Type::Path(ref v) => v.uses_lifetimes(options, lifetimes),
Type::Paren(ref v) => v.uses_lifetimes(options, lifetimes),
Type::Group(ref v) => v.uses_lifetimes(options, lifetimes),
Type::TraitObject(ref v) => v.uses_lifetimes(options, lifetimes),
Type::ImplTrait(ref v) => v.uses_lifetimes(options, lifetimes),
Type::Macro(_) | Type::Verbatim(_) | Type::Infer(_) | Type::Never(_) => {
Default::default()
}
_ => panic!("Unknown syn::Type: {:?}", self),
}
}
}
impl UsesLifetimes for syn::Fields {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
self.collect_lifetimes(options, lifetimes)
}
}
impl UsesLifetimes for syn::TypePath {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
let mut hits = self.path.uses_lifetimes(options, lifetimes);
if options.include_type_path_qself() {
hits.extend(self.qself.uses_lifetimes(options, lifetimes));
}
hits
}
}
impl UsesLifetimes for syn::ReturnType {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
if let syn::ReturnType::Type(_, ref ty) = *self {
ty.uses_lifetimes(options, lifetimes)
} else {
Default::default()
}
}
}
impl UsesLifetimes for syn::PathArguments {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
match *self {
syn::PathArguments::None => Default::default(),
syn::PathArguments::AngleBracketed(ref v) => v.uses_lifetimes(options, lifetimes),
syn::PathArguments::Parenthesized(ref v) => v.uses_lifetimes(options, lifetimes),
}
}
}
impl UsesLifetimes for syn::WherePredicate {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
match *self {
syn::WherePredicate::Type(ref v) => v.uses_lifetimes(options, lifetimes),
syn::WherePredicate::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes),
// non-exhaustive enum
// TODO: replace panic with failible function
_ => panic!("Unknown syn::WherePredicate: {:?}", self),
}
}
}
impl UsesLifetimes for syn::GenericArgument {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
match *self {
syn::GenericArgument::Type(ref v) => v.uses_lifetimes(options, lifetimes),
syn::GenericArgument::AssocType(ref v) => v.uses_lifetimes(options, lifetimes),
syn::GenericArgument::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes),
syn::GenericArgument::Constraint(ref v) => v.uses_lifetimes(options, lifetimes),
syn::GenericArgument::AssocConst(_) | syn::GenericArgument::Const(_) => {
Default::default()
}
// non-exhaustive enum
// TODO: replace panic with failible function
_ => panic!("Unknown syn::GenericArgument: {:?}", self),
}
}
}
impl UsesLifetimes for syn::GenericParam {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
match *self {
syn::GenericParam::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes),
syn::GenericParam::Type(ref v) => v.uses_lifetimes(options, lifetimes),
syn::GenericParam::Const(ref v) => v.uses_lifetimes(options, lifetimes),
}
}
}
impl UsesLifetimes for syn::TypeParamBound {
fn uses_lifetimes<'a>(
&self,
options: &Options,
lifetimes: &'a LifetimeSet,
) -> LifetimeRefSet<'a> {
match *self {
syn::TypeParamBound::Trait(ref v) => v.uses_lifetimes(options, lifetimes),
syn::TypeParamBound::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes),
// non-exhaustive enum
// TODO: replace panic with failible function
_ => panic!("Unknown syn::TypeParamBound: {:?}", self),
}
}
}
#[cfg(test)]
mod tests {
use proc_macro2::Span;
use syn::{parse_quote, DeriveInput};
use super::UsesLifetimes;
use crate::usage::GenericsExt;
use crate::usage::Purpose::*;
#[test]
fn struct_named() {
let input: DeriveInput = parse_quote! {
struct Foo<'a, 'b: 'a> {
parent: &'b Bar,
child: &'a Baz,
}
};
let omitted = syn::Lifetime::new("'c", Span::call_site());
let lifetimes = {
let mut lt = input.generics.declared_lifetimes();
lt.insert(omitted);
lt
};
let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes);
assert_eq!(matches.len(), 2);
}
#[test]
fn qself() {
let input: DeriveInput = parse_quote! {
struct Foo<'a, 'b: 'a> {
parent: &'b Bar,
child: <Bar<'a> as MyIterator>::Item,
}
};
let lifetimes = input.generics.declared_lifetimes();
let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes);
assert_eq!(matches.len(), 1);
let decl_matches = input.data.uses_lifetimes(&Declare.into(), &lifetimes);
assert_eq!(decl_matches.len(), 2);
}
}

111
vendor/darling_core/src/usage/mod.rs vendored Normal file
View File

@@ -0,0 +1,111 @@
//! Traits and types used for tracking the usage of generic parameters through a proc-macro input.
//!
//! When generating trait impls, libraries often want to automatically figure out which type parameters
//! are used in which fields, and then emit bounds that will produce the most permissive compilable
//! code.
//!
//! # Usage
//!
//! ## Example 1: Filtering
//! This example accepts a proc-macro input, then finds all lifetimes and type parameters used
//! by private fields.
//!
//! ```rust
//! # extern crate darling_core;
//! # extern crate syn;
//! #
//! # // in real-world usage, import from `darling`
//! # use darling_core::usage::{self, CollectLifetimes, CollectTypeParams, GenericsExt, Purpose};
//! # use syn::{Data, DeriveInput, GenericParam, Generics, Visibility};
//! #
//! # #[allow(dead_code)]
//! fn process(input: &DeriveInput) -> Generics {
//! let type_params = input.generics.declared_type_params();
//! let lifetimes = input.generics.declared_lifetimes();
//!
//! let mut ret_generics = input.generics.clone();
//!
//! if let Data::Struct(ref body) = input.data {
//! let internal_fields = body
//! .fields
//! .iter()
//! .filter(|field| field.vis == Visibility::Inherited)
//! .collect::<Vec<_>>();
//!
//! let int_type_params = internal_fields
//! .collect_type_params(&Purpose::BoundImpl.into(), &type_params);
//!
//! // We could reuse the vec from above, but here we'll instead
//! // directly consume the chained iterator.
//! let int_lifetimes = body
//! .fields
//! .iter()
//! .filter(|field| field.vis == Visibility::Inherited)
//! .collect_lifetimes(&Purpose::BoundImpl.into(), &lifetimes);
//!
//!
//! ret_generics.params = ret_generics
//! .params
//! .into_iter()
//! .filter(|gp| {
//! match *gp {
//! GenericParam::Type(ref ty) => int_type_params.contains(&ty.ident),
//! GenericParam::Lifetime(ref lt) => int_lifetimes.contains(&lt.lifetime),
//! _ => true,
//! }
//! })
//! .collect();
//! }
//!
//! ret_generics
//! }
//!
//! # fn main() {}
//! ```
//!
//! ## Example 2: Integrating with `FromDeriveInput`
//! It is possible to use `darling`'s magic fields feature in tandem with the `usage` feature set.
//! While there is no custom derive for `UsesTypeParams` or `UsesLifetimes`, there are macros to
//! generate impls.
//!
//! ```rust,ignore
//! #![allow(dead_code)]
//!
//! #[derive(FromField)]
//! #[darling(attributes(speak))]
//! struct SpeakerField {
//! ident: Option<syn::Ident>,
//! ty: syn::Type,
//! #[darling(default)]
//! volume: Option<u32>,
//! }
//!
//! uses_type_params!(SpeakerField, ty);
//! uses_lifetimes!(SpeakerField, ty);
//!
//! #[derive(FromDeriveInput)]
//! struct SpeakerOptions {
//! generics: syn::Generics,
//! data: darling::ast::Data<darling::util::Ignored, SpeakerField>,
//! }
//! ```
//!
//! At this point, you are able to call `uses_type_params` on `SpeakerOptions.data`, or any filtered
//! view of it. `darling` internally uses this in conjunction with the `skip` meta-item to determine
//! which type parameters don't require the `FromMeta` bound in generated impls.
//!
//! **Note:** If you are performing operations referencing generic params in meta-items parsed by `darling`,
//! you should determine if those impact the emitted code and wire up `UsesTypeParams` accordingly for
//! your field/variant.
mod generics_ext;
mod ident_set;
mod lifetimes;
mod options;
mod type_params;
pub use self::generics_ext::GenericsExt;
pub use self::ident_set::{IdentRefSet, IdentSet};
pub use self::lifetimes::{CollectLifetimes, LifetimeRefSet, LifetimeSet, UsesLifetimes};
pub use self::options::{Options, Purpose};
pub use self::type_params::{CollectTypeParams, UsesTypeParams};

View File

@@ -0,0 +1,58 @@
/// The goal of tracing generic parameter usage.
///
/// Not all uses of type parameters imply a need to add bounds to a generated trait impl.
/// For example, a field of type `<Vec<T> as a::b::Trait>::Associated` does not need a
/// `where T: Serialize` bound in `serde`.
/// However, a proc macro that is attempting to generate a helper struct _would_ need to
/// know about this usage, or else the generated code would reference an unknown type `T`
/// and fail to compile.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Purpose {
/// The tracing is being used to generate an `impl` block.
///
/// Uses such as `syn::TypePath.qself` will _not_ be returned.
BoundImpl,
/// The tracing is being used to generate a new struct or enum.
///
/// All uses will be returned.
Declare,
}
/// Control struct for searching type parameters.
///
/// This acts as the search context, preserving information that might have been
/// kept on a visitor in a different implementation.
/// Trait implementers are required to pass this through on any invocations they make.
///
/// # Usage
/// For extensibility, `Options` hides all of its fields from consumers.
/// To create an instance, use the `From<Purpose>` trait implementation:
///
/// ```rust
/// # use darling_core::usage::{Options, Purpose};
/// let opts: Options = Purpose::BoundImpl.into();
/// assert!(!opts.include_type_path_qself());
/// ```
#[derive(Debug, Clone)]
pub struct Options {
purpose: Purpose,
#[doc(hidden)]
__nonexhaustive: (),
}
impl From<Purpose> for Options {
fn from(purpose: Purpose) -> Self {
Self {
purpose,
__nonexhaustive: (),
}
}
}
impl Options {
/// Returns `true` if the implementer of `UseTypeParams` should search
/// `<___ as ...>::...` when looking for type parameter uses.
pub fn include_type_path_qself(&self) -> bool {
self.purpose == Purpose::Declare
}
}

View File

@@ -0,0 +1,364 @@
use syn::punctuated::Punctuated;
use syn::{Ident, Type};
use crate::usage::{IdentRefSet, IdentSet, Options};
/// Searcher for finding type params in a syntax tree.
/// This can be used to determine if a given type parameter needs to be bounded in a generated impl.
pub trait UsesTypeParams {
/// Returns the subset of the queried type parameters that are used by the implementing syntax element.
///
/// This method only accounts for direct usage by the element; indirect usage via bounds or `where`
/// predicates are not detected.
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a>;
/// Find all type params using `uses_type_params`, then clone the found values and return the set.
fn uses_type_params_cloned(&self, options: &Options, type_set: &IdentSet) -> IdentSet {
self.uses_type_params(options, type_set)
.into_iter()
.cloned()
.collect()
}
}
/// Searcher for finding type params in an iterator.
///
/// This trait extends iterators, providing a way to turn a filtered list of fields or variants into a set
/// of type parameter idents.
pub trait CollectTypeParams {
/// Consume an iterator, accumulating all type parameters in the elements which occur in `type_set`.
fn collect_type_params<'a>(self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a>;
/// Consume an iterator using `collect_type_params`, then clone all found type params and return that set.
fn collect_type_params_cloned(self, options: &Options, type_set: &IdentSet) -> IdentSet;
}
impl<'i, T, I> CollectTypeParams for T
where
T: IntoIterator<Item = &'i I>,
I: 'i + UsesTypeParams,
{
fn collect_type_params<'a>(self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
self.into_iter().fold(
IdentRefSet::with_capacity_and_hasher(type_set.len(), Default::default()),
|state, value| union_in_place(state, value.uses_type_params(options, type_set)),
)
}
fn collect_type_params_cloned(self, options: &Options, type_set: &IdentSet) -> IdentSet {
self.collect_type_params(options, type_set)
.into_iter()
.cloned()
.collect()
}
}
/// Insert the contents of `right` into `left`.
fn union_in_place<'a>(mut left: IdentRefSet<'a>, right: IdentRefSet<'a>) -> IdentRefSet<'a> {
left.extend(right);
left
}
impl UsesTypeParams for () {
fn uses_type_params<'a>(&self, _options: &Options, _type_set: &'a IdentSet) -> IdentRefSet<'a> {
Default::default()
}
}
impl<T: UsesTypeParams> UsesTypeParams for Option<T> {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
self.as_ref()
.map(|v| v.uses_type_params(options, type_set))
.unwrap_or_default()
}
}
impl<T: UsesTypeParams> UsesTypeParams for Vec<T> {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
self.collect_type_params(options, type_set)
}
}
impl<T: UsesTypeParams, U> UsesTypeParams for Punctuated<T, U> {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
self.collect_type_params(options, type_set)
}
}
uses_type_params!(syn::AngleBracketedGenericArguments, args);
uses_type_params!(syn::AssocType, ty);
uses_type_params!(syn::BareFnArg, ty);
uses_type_params!(syn::Constraint, bounds);
uses_type_params!(syn::DataEnum, variants);
uses_type_params!(syn::DataStruct, fields);
uses_type_params!(syn::DataUnion, fields);
uses_type_params!(syn::Field, ty);
uses_type_params!(syn::FieldsNamed, named);
uses_type_params!(syn::ParenthesizedGenericArguments, inputs, output);
uses_type_params!(syn::PredicateType, bounded_ty, bounds);
uses_type_params!(syn::QSelf, ty);
uses_type_params!(syn::TraitBound, path);
uses_type_params!(syn::TypeArray, elem);
uses_type_params!(syn::TypeBareFn, inputs, output);
uses_type_params!(syn::TypeGroup, elem);
uses_type_params!(syn::TypeImplTrait, bounds);
uses_type_params!(syn::TypeParen, elem);
uses_type_params!(syn::TypePtr, elem);
uses_type_params!(syn::TypeReference, elem);
uses_type_params!(syn::TypeSlice, elem);
uses_type_params!(syn::TypeTuple, elems);
uses_type_params!(syn::TypeTraitObject, bounds);
uses_type_params!(syn::Variant, fields);
impl UsesTypeParams for syn::Data {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
match *self {
syn::Data::Struct(ref v) => v.uses_type_params(options, type_set),
syn::Data::Enum(ref v) => v.uses_type_params(options, type_set),
syn::Data::Union(ref v) => v.uses_type_params(options, type_set),
}
}
}
impl UsesTypeParams for syn::Fields {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
self.collect_type_params(options, type_set)
}
}
/// Check if an Ident exactly matches one of the sought-after type parameters.
impl UsesTypeParams for Ident {
fn uses_type_params<'a>(&self, _options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
type_set.iter().filter(|v| *v == self).collect()
}
}
impl UsesTypeParams for syn::ReturnType {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
if let syn::ReturnType::Type(_, ref ty) = *self {
ty.uses_type_params(options, type_set)
} else {
Default::default()
}
}
}
impl UsesTypeParams for Type {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
match *self {
Type::Slice(ref v) => v.uses_type_params(options, type_set),
Type::Array(ref v) => v.uses_type_params(options, type_set),
Type::Ptr(ref v) => v.uses_type_params(options, type_set),
Type::Reference(ref v) => v.uses_type_params(options, type_set),
Type::BareFn(ref v) => v.uses_type_params(options, type_set),
Type::Tuple(ref v) => v.uses_type_params(options, type_set),
Type::Path(ref v) => v.uses_type_params(options, type_set),
Type::Paren(ref v) => v.uses_type_params(options, type_set),
Type::Group(ref v) => v.uses_type_params(options, type_set),
Type::TraitObject(ref v) => v.uses_type_params(options, type_set),
Type::ImplTrait(ref v) => v.uses_type_params(options, type_set),
Type::Macro(_) | Type::Verbatim(_) | Type::Infer(_) | Type::Never(_) => {
Default::default()
}
_ => panic!("Unknown syn::Type: {:?}", self),
}
}
}
impl UsesTypeParams for syn::TypePath {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
let hits = self.path.uses_type_params(options, type_set);
if options.include_type_path_qself() {
union_in_place(hits, self.qself.uses_type_params(options, type_set))
} else {
hits
}
}
}
impl UsesTypeParams for syn::Path {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
// Not sure if this is even possible, but a path with no segments definitely
// can't use type parameters.
if self.segments.is_empty() {
return Default::default();
}
// A path segment ident can only match if it is not global and it is the first segment
// in the path.
let ident_hits = if self.leading_colon.is_none() {
self.segments[0].ident.uses_type_params(options, type_set)
} else {
Default::default()
};
// Merge ident hit, if any, with all hits from path arguments
self.segments.iter().fold(ident_hits, |state, segment| {
union_in_place(state, segment.arguments.uses_type_params(options, type_set))
})
}
}
impl UsesTypeParams for syn::PathArguments {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
match *self {
syn::PathArguments::None => Default::default(),
syn::PathArguments::AngleBracketed(ref v) => v.uses_type_params(options, type_set),
syn::PathArguments::Parenthesized(ref v) => v.uses_type_params(options, type_set),
}
}
}
impl UsesTypeParams for syn::WherePredicate {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
match *self {
syn::WherePredicate::Lifetime(_) => Default::default(),
syn::WherePredicate::Type(ref v) => v.uses_type_params(options, type_set),
// non-exhaustive enum
// TODO: replace panic with failible function
_ => panic!("Unknown syn::WherePredicate: {:?}", self),
}
}
}
impl UsesTypeParams for syn::GenericArgument {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
match *self {
syn::GenericArgument::Type(ref v) => v.uses_type_params(options, type_set),
syn::GenericArgument::AssocType(ref v) => v.uses_type_params(options, type_set),
syn::GenericArgument::Constraint(ref v) => v.uses_type_params(options, type_set),
syn::GenericArgument::AssocConst(_)
| syn::GenericArgument::Const(_)
| syn::GenericArgument::Lifetime(_) => Default::default(),
// non-exhaustive enum
// TODO: replace panic with failible function
_ => panic!("Unknown syn::GenericArgument: {:?}", self),
}
}
}
impl UsesTypeParams for syn::TypeParamBound {
fn uses_type_params<'a>(&self, options: &Options, type_set: &'a IdentSet) -> IdentRefSet<'a> {
match *self {
syn::TypeParamBound::Trait(ref v) => v.uses_type_params(options, type_set),
syn::TypeParamBound::Lifetime(_) => Default::default(),
// non-exhaustive enum
// TODO: replace panic with failible function
_ => panic!("Unknown syn::TypeParamBound: {:?}", self),
}
}
}
#[cfg(test)]
mod tests {
use proc_macro2::Span;
use syn::{parse_quote, DeriveInput, Ident};
use super::UsesTypeParams;
use crate::usage::IdentSet;
use crate::usage::Purpose::*;
fn ident_set(idents: Vec<&str>) -> IdentSet {
idents
.into_iter()
.map(|s| Ident::new(s, Span::call_site()))
.collect()
}
#[test]
fn finds_simple() {
let input: DeriveInput = parse_quote! { struct Foo<T, U>(T, i32, A, U); };
let generics = ident_set(vec!["T", "U", "X"]);
let matches = input.data.uses_type_params(&BoundImpl.into(), &generics);
assert_eq!(matches.len(), 2);
assert!(matches.contains::<Ident>(&parse_quote!(T)));
assert!(matches.contains::<Ident>(&parse_quote!(U)));
assert!(!matches.contains::<Ident>(&parse_quote!(X)));
assert!(!matches.contains::<Ident>(&parse_quote!(A)));
}
#[test]
fn finds_named() {
let input: DeriveInput = parse_quote! {
struct Foo<T, U = usize> {
bar: T,
world: U,
}
};
let generics = ident_set(vec!["T", "U", "X"]);
let matches = input.data.uses_type_params(&BoundImpl.into(), &generics);
assert_eq!(matches.len(), 2);
assert!(matches.contains::<Ident>(&parse_quote!(T)));
assert!(matches.contains::<Ident>(&parse_quote!(U)));
assert!(!matches.contains::<Ident>(&parse_quote!(X)));
assert!(!matches.contains::<Ident>(&parse_quote!(A)));
}
#[test]
fn finds_as_type_arg() {
let input: DeriveInput = parse_quote! {
struct Foo<T, U> {
bar: T,
world: Vec<U>,
}
};
let generics = ident_set(vec!["T", "U", "X"]);
let matches = input.data.uses_type_params(&BoundImpl.into(), &generics);
assert_eq!(matches.len(), 2);
assert!(matches.contains::<Ident>(&parse_quote!(T)));
assert!(matches.contains::<Ident>(&parse_quote!(U)));
assert!(!matches.contains::<Ident>(&parse_quote!(X)));
assert!(!matches.contains::<Ident>(&parse_quote!(A)));
}
#[test]
fn associated_type() {
let input: DeriveInput =
parse_quote! { struct Foo<'a, T> where T: Iterator { peek: T::Item } };
let generics = ident_set(vec!["T", "INTO"]);
let matches = input.data.uses_type_params(&BoundImpl.into(), &generics);
assert_eq!(matches.len(), 1);
}
#[test]
fn box_fn_output() {
let input: DeriveInput = parse_quote! { struct Foo<T>(Box<dyn Fn() -> T>); };
let generics = ident_set(vec!["T"]);
let matches = input.data.uses_type_params(&BoundImpl.into(), &generics);
assert_eq!(matches.len(), 1);
assert!(matches.contains::<Ident>(&parse_quote!(T)));
}
#[test]
fn box_fn_input() {
let input: DeriveInput = parse_quote! { struct Foo<T>(Box<dyn Fn(&T) -> ()>); };
let generics = ident_set(vec!["T"]);
let matches = input.data.uses_type_params(&BoundImpl.into(), &generics);
assert_eq!(matches.len(), 1);
assert!(matches.contains::<Ident>(&parse_quote!(T)));
}
/// Test that `syn::TypePath` is correctly honoring the different modes a
/// search can execute in.
#[test]
fn qself_vec() {
let input: DeriveInput =
parse_quote! { struct Foo<T>(<Vec<T> as a::b::Trait>::AssociatedItem); };
let generics = ident_set(vec!["T", "U"]);
let bound_matches = input.data.uses_type_params(&BoundImpl.into(), &generics);
assert_eq!(bound_matches.len(), 0);
let declare_matches = input.data.uses_type_params(&Declare.into(), &generics);
assert_eq!(declare_matches.len(), 1);
assert!(declare_matches.contains::<Ident>(&parse_quote!(T)));
}
}

View File

@@ -0,0 +1,62 @@
use quote::ToTokens;
use crate::{Error, FromMeta, Result};
/// Either a path or a closure.
///
/// This type is useful for options that historically took a path,
/// e.g. `#[darling(with = ...)]` or `#[serde(skip_serializing_if = ...)]`
/// and now want to also allow using a closure to avoid needing a separate
/// function declaration.
///
/// In `darling`, this value is wrapped in [`core::convert::identity`] before usage;
/// this allows treatment of the closure and path cases as equivalent, and prevents
/// a closure from accessing locals in the generated code.
#[derive(Debug, Clone)]
pub struct Callable {
/// The callable
call: syn::Expr,
}
impl AsRef<syn::Expr> for Callable {
fn as_ref(&self) -> &syn::Expr {
&self.call
}
}
impl From<syn::ExprPath> for Callable {
fn from(value: syn::ExprPath) -> Self {
Self {
call: syn::Expr::Path(value),
}
}
}
impl From<syn::ExprClosure> for Callable {
fn from(value: syn::ExprClosure) -> Self {
Self {
call: syn::Expr::Closure(value),
}
}
}
impl From<Callable> for syn::Expr {
fn from(value: Callable) -> Self {
value.call
}
}
impl FromMeta for Callable {
fn from_expr(expr: &syn::Expr) -> Result<Self> {
match expr {
syn::Expr::Path(_) | syn::Expr::Closure(_) => Ok(Self { call: expr.clone() }),
_ => Err(Error::unexpected_expr_type(expr)),
}
}
}
impl ToTokens for Callable {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
self.call.to_tokens(tokens);
}
}

99
vendor/darling_core/src/util/flag.rs vendored Normal file
View File

@@ -0,0 +1,99 @@
use proc_macro2::Span;
use syn::{spanned::Spanned, Meta};
use crate::{FromMeta, Result};
/// A meta-item that can be present as a word - with no value - or absent.
///
/// # Defaulting
/// Like `Option`, `Flag` does not require `#[darling(default)]` to be optional.
/// If the caller does not include the property, then an absent `Flag` will be included
/// in the receiver struct.
///
/// # Spans
/// `Flag` keeps the span where its word was seen.
/// This enables attaching custom error messages to the word, such as in the case of two
/// conflicting flags being present.
///
/// # Example
/// ```ignore
/// #[derive(FromMeta)]
/// #[darling(and_then = Self::not_both)]
/// struct Demo {
/// flag_a: Flag,
/// flag_b: Flag,
/// }
///
/// impl Demo {
/// fn not_both(self) -> Result<Self> {
/// if self.flag_a.is_present() && self.flag_b.is_present() {
/// Err(Error::custom("Cannot set flag_a and flag_b").with_span(&self.flag_b.span()))
/// } else {
/// Ok(self)
/// }
/// }
/// }
/// ```
///
/// The above struct would then produce the following error.
///
/// ```ignore
/// #[example(flag_a, flag_b)]
/// // ^^^^^^ Cannot set flag_a and flag_b
/// ```
#[derive(Debug, Clone, Copy, Default)]
pub struct Flag(Option<Span>);
impl Flag {
/// Creates a new `Flag` which corresponds to the presence of a value.
pub fn present() -> Self {
Flag(Some(Span::call_site()))
}
/// Check if the flag is present.
pub fn is_present(&self) -> bool {
self.0.is_some()
}
#[deprecated(since = "0.14.0", note = "Use Flag::is_present")]
pub fn is_some(&self) -> bool {
self.is_present()
}
/// Get the span of the flag, or [`Span::call_site`] if the flag was not present.
pub fn span(&self) -> Span {
self.0.unwrap_or_else(Span::call_site)
}
}
impl FromMeta for Flag {
fn from_none() -> Option<Self> {
Some(Flag(None))
}
fn from_meta(mi: &syn::Meta) -> Result<Self> {
if let Meta::Path(p) = mi {
Ok(Flag(Some(p.span())))
} else {
// The implementation for () will produce an error for all non-path meta items;
// call it to make sure the span behaviors and error messages are the same.
Err(<()>::from_meta(mi).unwrap_err())
}
}
}
impl From<Flag> for bool {
fn from(flag: Flag) -> Self {
flag.is_present()
}
}
impl From<bool> for Flag {
fn from(v: bool) -> Self {
if v {
Flag::present()
} else {
Flag(None)
}
}
}

View File

@@ -0,0 +1,157 @@
use std::fmt;
use std::hash::{Hash, Hasher};
use proc_macro2::{Span, TokenStream};
use quote::ToTokens;
use syn::{Ident, Meta};
use crate::{FromMeta, Result};
/// A wrapper for an `Ident` which also keeps the value as a string.
///
/// This struct can be used to perform string comparisons and operations.
#[derive(Clone, PartialOrd, Ord)]
pub struct IdentString {
ident: Ident,
string: String,
}
impl IdentString {
/// Create a new `IdentString`.
pub fn new(ident: Ident) -> Self {
IdentString {
string: ident.to_string(),
ident,
}
}
/// Get the ident as a `proc_macro2::Ident`.
pub fn as_ident(&self) -> &Ident {
&self.ident
}
/// Get the ident as a string.
pub fn as_str(&self) -> &str {
&self.string
}
/// Get the location of this `Ident` in source.
pub fn span(&self) -> Span {
self.ident.span()
}
/// Apply some transform to the ident's string representation.
///
/// # Panics
/// This will panic if the transform produces an invalid ident.
pub fn map<F, S>(self, map_fn: F) -> Self
where
F: FnOnce(String) -> S,
S: AsRef<str>,
{
let span = self.span();
let string = map_fn(self.string);
Ident::new(string.as_ref(), span).into()
}
}
impl AsRef<Ident> for IdentString {
fn as_ref(&self) -> &Ident {
self.as_ident()
}
}
impl AsRef<str> for IdentString {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl From<Ident> for IdentString {
fn from(ident: Ident) -> Self {
IdentString::new(ident)
}
}
impl From<IdentString> for Ident {
fn from(v: IdentString) -> Ident {
v.ident
}
}
impl From<IdentString> for String {
fn from(v: IdentString) -> String {
v.string
}
}
impl Eq for IdentString {}
impl PartialEq for IdentString {
fn eq(&self, rhs: &Self) -> bool {
self.ident == rhs.ident
}
}
impl PartialEq<String> for IdentString {
fn eq(&self, rhs: &String) -> bool {
self.as_str() == rhs
}
}
impl PartialEq<&str> for IdentString {
fn eq(&self, rhs: &&str) -> bool {
self.as_str() == *rhs
}
}
impl Hash for IdentString {
fn hash<H: Hasher>(&self, state: &mut H) {
self.ident.hash(state);
}
}
impl ToTokens for IdentString {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.ident.to_tokens(tokens);
}
}
impl fmt::Debug for IdentString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.ident)
}
}
impl fmt::Display for IdentString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.ident)
}
}
impl FromMeta for IdentString {
fn from_meta(item: &Meta) -> Result<Self> {
Ident::from_meta(item).map(IdentString::from)
}
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::IdentString;
#[test]
fn convert() {
let i_str = IdentString::new(parse_quote!(t));
assert_eq!(i_str.as_str(), "t");
}
#[test]
fn map_transform() {
let i = IdentString::new(parse_quote!(my));
let after = i.map(|v| format!("var_{}", v));
assert_eq!(after, "var_my");
assert_eq!(after, String::from("var_my"));
}
}

50
vendor/darling_core/src/util/ignored.rs vendored Normal file
View File

@@ -0,0 +1,50 @@
use crate::{
usage::{self, UsesLifetimes, UsesTypeParams},
FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam,
FromVariant, Result,
};
/// An efficient way of discarding data from a syntax element.
///
/// All syntax elements will be successfully read into
/// the `Ignored` struct, with all properties discarded.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Ignored;
macro_rules! ignored {
($trayt:ident, $method:ident, $syn:path) => {
impl $trayt for Ignored {
fn $method(_: &$syn) -> Result<Self> {
Ok(Ignored)
}
}
};
}
ignored!(FromGenericParam, from_generic_param, syn::GenericParam);
ignored!(FromGenerics, from_generics, syn::Generics);
ignored!(FromTypeParam, from_type_param, syn::TypeParam);
ignored!(FromMeta, from_meta, syn::Meta);
ignored!(FromDeriveInput, from_derive_input, syn::DeriveInput);
ignored!(FromField, from_field, syn::Field);
ignored!(FromVariant, from_variant, syn::Variant);
impl UsesTypeParams for Ignored {
fn uses_type_params<'a>(
&self,
_opts: &usage::Options,
_: &'a usage::IdentSet,
) -> usage::IdentRefSet<'a> {
Default::default()
}
}
impl UsesLifetimes for Ignored {
fn uses_lifetimes<'a>(
&self,
_opts: &usage::Options,
_: &'a usage::LifetimeSet,
) -> usage::LifetimeRefSet<'a> {
Default::default()
}
}

26
vendor/darling_core/src/util/mod.rs vendored Normal file
View File

@@ -0,0 +1,26 @@
//! Utility types for attribute parsing.
mod callable;
mod flag;
mod ident_string;
mod ignored;
mod over_ride;
mod parse_attribute;
pub mod parse_expr;
mod path_list;
mod path_to_string;
mod shape;
mod spanned_value;
mod with_original;
pub use self::callable::Callable;
pub use self::flag::Flag;
pub use self::ident_string::IdentString;
pub use self::ignored::Ignored;
pub use self::over_ride::Override;
pub use self::parse_attribute::parse_attribute_to_meta_list;
pub use self::path_list::PathList;
pub use self::path_to_string::path_to_string;
pub use self::shape::{AsShape, Shape, ShapeSet};
pub use self::spanned_value::SpannedValue;
pub use self::with_original::WithOriginal;

View File

@@ -0,0 +1,163 @@
use std::fmt;
use syn::Lit;
use crate::ast::NestedMeta;
use crate::{FromMeta, Result};
use self::Override::*;
/// A value which can inherit a default value or have an explicit value specified.
///
/// # Usage
/// This type is meant for attributes like `default` in `darling`, which can take the following forms:
///
/// * `#[darling(default)]`
/// * `#[darling(default="path::to::fn")]`
///
/// In a struct collecting input for this attribute, that would be written as:
///
/// ```rust,ignore
/// use darling::{util::Override, FromField};
/// #[derive(FromField)]
/// #[darling(attributes(darling))]
/// pub struct Options {
/// default: Option<Override<syn::Path>>,
/// }
///
/// impl Options {
/// fn hydrate(self) -> Option<syn::Path> {
/// self.default.map(|ov| ov.unwrap_or(syn::parse_path("::Default::default").unwrap()))
/// }
/// }
/// ```
///
/// The `word` format (with no associated value), would produce `Override::Inherit`, while a list
/// or value format would produce `Override::Explicit`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Override<T> {
/// Inherit the eventual value from an external source.
Inherit,
/// Explicitly set the value.
Explicit(T),
}
impl<T> Override<T> {
/// Converts from `Override<T>` to `Override<&T>`.
///
/// Produces a new `Override`, containing a reference into the original, leaving the original in place.
pub fn as_ref(&self) -> Override<&T> {
match *self {
Inherit => Inherit,
Explicit(ref val) => Explicit(val),
}
}
/// Converts from `Override<T>` to `Override<&mut T>`.
///
/// Produces a new `Override`, containing a mutable reference into the original.
pub fn as_mut(&mut self) -> Override<&mut T> {
match *self {
Inherit => Inherit,
Explicit(ref mut val) => Explicit(val),
}
}
/// Returns `true` if the override is an `Explicit` value.
pub fn is_explicit(&self) -> bool {
match *self {
Inherit => false,
Explicit(_) => true,
}
}
/// Converts from `Override<T>` to `Option<T>`.
pub fn explicit(self) -> Option<T> {
match self {
Inherit => None,
Explicit(val) => Some(val),
}
}
/// Unwraps an override, yielding the content of an `Explicit`. Otherwise, it returns `optb`.
pub fn unwrap_or(self, optb: T) -> T {
match self {
Inherit => optb,
Explicit(val) => val,
}
}
/// Unwraps an override, yielding the content of an `Explicit`. Otherwise, it calls `op`.
pub fn unwrap_or_else<F>(self, op: F) -> T
where
F: FnOnce() -> T,
{
match self {
Inherit => op(),
Explicit(val) => val,
}
}
}
impl<T: Default> Override<T> {
/// Returns the contained value or the default value of `T`.
pub fn unwrap_or_default(self) -> T {
match self {
Inherit => Default::default(),
Explicit(val) => val,
}
}
}
impl<T> Default for Override<T> {
fn default() -> Self {
Inherit
}
}
impl<T> From<Option<T>> for Override<T> {
fn from(v: Option<T>) -> Self {
match v {
None => Inherit,
Some(val) => Explicit(val),
}
}
}
impl<T: fmt::Display> fmt::Display for Override<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Inherit => write!(f, "Inherit"),
Explicit(ref val) => write!(f, "Explicit `{}`", val),
}
}
}
/// Parses a `Meta`. A bare word will produce `Override::Inherit`, while
/// any value will be forwarded to `T::from_meta`.
impl<T: FromMeta> FromMeta for Override<T> {
fn from_word() -> Result<Self> {
Ok(Inherit)
}
fn from_list(items: &[NestedMeta]) -> Result<Self> {
Ok(Explicit(FromMeta::from_list(items)?))
}
fn from_value(lit: &Lit) -> Result<Self> {
Ok(Explicit(FromMeta::from_value(lit)?))
}
fn from_char(value: char) -> Result<Self> {
Ok(Explicit(FromMeta::from_char(value)?))
}
fn from_string(value: &str) -> Result<Self> {
Ok(Explicit(FromMeta::from_string(value)?))
}
fn from_bool(value: bool) -> Result<Self> {
Ok(Explicit(FromMeta::from_bool(value)?))
}
}

View File

@@ -0,0 +1,86 @@
use crate::{Error, Result};
use std::fmt;
use syn::punctuated::Pair;
use syn::spanned::Spanned;
use syn::{token, Attribute, Meta, MetaList, Path};
/// Try to parse an attribute into a meta list. Path-type meta values are accepted and returned
/// as empty lists with their passed-in path. Name-value meta values and non-meta attributes
/// will cause errors to be returned.
pub fn parse_attribute_to_meta_list(attr: &Attribute) -> Result<MetaList> {
match &attr.meta {
Meta::List(list) => Ok(list.clone()),
Meta::NameValue(nv) => Err(Error::custom(format!(
"Name-value arguments are not supported. Use #[{}(...)]",
DisplayPath(&nv.path)
))
.with_span(&nv)),
Meta::Path(path) => Ok(MetaList {
path: path.clone(),
delimiter: syn::MacroDelimiter::Paren(token::Paren {
span: {
let mut group = proc_macro2::Group::new(
proc_macro2::Delimiter::None,
proc_macro2::TokenStream::new(),
);
group.set_span(attr.span());
group.delim_span()
},
}),
tokens: Default::default(),
}),
}
}
struct DisplayPath<'a>(&'a Path);
impl fmt::Display for DisplayPath<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let path = self.0;
if path.leading_colon.is_some() {
write!(f, "::")?;
}
for segment in path.segments.pairs() {
match segment {
Pair::Punctuated(segment, _) => write!(f, "{}::", segment.ident)?,
Pair::End(segment) => segment.ident.fmt(f)?,
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::parse_attribute_to_meta_list;
use crate::ast::NestedMeta;
use syn::spanned::Spanned;
use syn::{parse_quote, Ident};
#[test]
fn parse_list() {
let meta = parse_attribute_to_meta_list(&parse_quote!(#[bar(baz = 4)])).unwrap();
let nested_meta = NestedMeta::parse_meta_list(meta.tokens).unwrap();
assert_eq!(nested_meta.len(), 1);
}
#[test]
fn parse_path_returns_empty_list() {
let meta = parse_attribute_to_meta_list(&parse_quote!(#[bar])).unwrap();
let nested_meta = NestedMeta::parse_meta_list(meta.tokens).unwrap();
assert!(meta.path.is_ident(&Ident::new("bar", meta.path.span())));
assert!(nested_meta.is_empty());
}
#[test]
fn parse_name_value_returns_error() {
parse_attribute_to_meta_list(&parse_quote!(#[bar = 4])).unwrap_err();
}
#[test]
fn parse_name_value_error_includes_example() {
let err = parse_attribute_to_meta_list(&parse_quote!(#[bar = 4])).unwrap_err();
assert!(err.to_string().contains("#[bar(...)]"));
}
}

View File

@@ -0,0 +1,86 @@
//! Functions to use with `#[darling(with = "...")]` that control how quoted values
//! in [`Meta`] instances are parsed into [`Expr`] fields.
//!
//! Version 1 of syn did not permit expressions on the right-hand side of the `=` in a
//! [`MetaNameValue`](syn::MetaNameValue), so darling accepted string literals and then
//! parsed their contents as expressions.
//! Passing a string literal in this version would have required the use of a raw string
//! to add quotation marks inside the literal.
//!
//! Version 2 of syn removes the requirement that the right-hand side be a literal.
//! For most types, such as [`Path`](syn::Path), the [`FromMeta`] impl can accept the
//! version without quotation marks without causing ambiguity; a path cannot start and
//! end with quotation marks, so removal is automatic.
//!
//! [`Expr`] is the one type where this ambiguity is new and unavoidable. To address this,
//! this module provides different functions for different expected behaviors.
use syn::{Expr, Meta};
use crate::{Error, FromMeta};
/// Parse a [`Meta`] to an [`Expr`]; if the value is a string literal, the emitted
/// expression will be a string literal.
pub fn preserve_str_literal(meta: &Meta) -> crate::Result<Expr> {
match meta {
Meta::Path(_) => Err(Error::unsupported_format("path").with_span(meta)),
Meta::List(_) => Err(Error::unsupported_format("list").with_span(meta)),
Meta::NameValue(nv) => Ok(nv.value.clone()),
}
}
/// Parse a [`Meta`] to an [`Expr`]; if the value is a string literal, the string's
/// contents will be parsed as an expression and emitted.
pub fn parse_str_literal(meta: &Meta) -> crate::Result<Expr> {
match meta {
Meta::Path(_) => Err(Error::unsupported_format("path").with_span(meta)),
Meta::List(_) => Err(Error::unsupported_format("list").with_span(meta)),
Meta::NameValue(nv) => {
if let Expr::Lit(expr_lit) = &nv.value {
Expr::from_value(&expr_lit.lit)
} else {
Ok(nv.value.clone())
}
}
}
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::*;
macro_rules! meta {
($body:expr) => {
{
let attr: ::syn::Attribute = ::syn::parse_quote!(#[ignore = $body]);
attr.meta
}
};
}
#[test]
fn preserve_str() {
assert_eq!(
preserve_str_literal(&meta!("World")).unwrap(),
parse_quote!("World")
);
}
#[test]
fn preserve_binary_exp() {
assert_eq!(
preserve_str_literal(&meta!("World" + 5)).unwrap(),
parse_quote!("World" + 5)
)
}
#[test]
fn parse_ident() {
assert_eq!(
parse_str_literal(&meta!("world")).unwrap(),
parse_quote!(world)
)
}
}

View File

@@ -0,0 +1,105 @@
use std::ops::Deref;
use syn::{Meta, Path};
use crate::ast::NestedMeta;
use crate::{Error, FromMeta, Result};
use super::path_to_string;
/// A list of `syn::Path` instances. This type is used to extract a list of paths from an
/// attribute.
///
/// # Usage
/// An `PathList` field on a struct implementing `FromMeta` will turn `#[builder(derive(serde::Debug, Clone))]` into:
///
/// ```rust,ignore
/// StructOptions {
/// derive: PathList(vec![syn::Path::new("serde::Debug"), syn::Path::new("Clone")])
/// }
/// ```
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct PathList(Vec<Path>);
impl PathList {
/// Create a new list.
pub fn new<T: Into<Path>>(vals: Vec<T>) -> Self {
PathList(vals.into_iter().map(T::into).collect())
}
/// Create a new `Vec` containing the string representation of each path.
pub fn to_strings(&self) -> Vec<String> {
self.0.iter().map(path_to_string).collect()
}
}
impl Deref for PathList {
type Target = Vec<Path>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<Vec<Path>> for PathList {
fn from(v: Vec<Path>) -> Self {
PathList(v)
}
}
impl FromMeta for PathList {
fn from_list(v: &[NestedMeta]) -> Result<Self> {
let mut paths = Vec::with_capacity(v.len());
for nmi in v {
if let NestedMeta::Meta(Meta::Path(ref path)) = *nmi {
paths.push(path.clone());
} else {
return Err(Error::unexpected_type("non-word").with_span(nmi));
}
}
Ok(PathList(paths))
}
}
#[cfg(test)]
mod tests {
use super::PathList;
use crate::FromMeta;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{parse_quote, Attribute, Meta};
/// parse a string as a syn::Meta instance.
fn pm(tokens: TokenStream) -> ::std::result::Result<Meta, String> {
let attribute: Attribute = parse_quote!(#[#tokens]);
Ok(attribute.meta)
}
fn fm<T: FromMeta>(tokens: TokenStream) -> T {
FromMeta::from_meta(&pm(tokens).expect("Tests should pass well-formed input"))
.expect("Tests should pass valid input")
}
#[test]
fn succeeds() {
let paths = fm::<PathList>(quote!(ignore(Debug, Clone, Eq)));
assert_eq!(
paths.to_strings(),
vec![
String::from("Debug"),
String::from("Clone"),
String::from("Eq")
]
);
}
/// Check that the parser rejects non-word members of the list, and that the error
/// has an associated span.
#[test]
fn fails_non_word() {
let input = PathList::from_meta(&pm(quote!(ignore(Debug, Clone = false))).unwrap());
let err = input.unwrap_err();
assert!(err.has_span());
}
}

View File

@@ -0,0 +1,36 @@
/// Transform Rust paths to a readable and comparable string.
///
/// # Limitations
/// * Leading colons are ignored.
/// * Angle brackets and `as` elements are ignored.
///
/// # Example
/// ```rust
/// # use darling_core::util::path_to_string;
/// # use syn::parse_quote;
/// assert_eq!(path_to_string(&parse_quote!(a::b)), "a::b");
/// ```
pub fn path_to_string(path: &syn::Path) -> String {
path.segments
.iter()
.map(|s| s.ident.to_string())
.collect::<Vec<String>>()
.join("::")
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::path_to_string;
#[test]
fn simple_ident() {
assert_eq!(path_to_string(&parse_quote!(a)), "a");
}
#[test]
fn simple_path() {
assert_eq!(path_to_string(&parse_quote!(a::b)), "a::b");
}
}

285
vendor/darling_core/src/util/shape.rs vendored Normal file
View File

@@ -0,0 +1,285 @@
use std::{fmt, iter::FromIterator};
use crate::ast;
/// Get the "shape" of a fields container, such as a struct or variant.
pub trait AsShape {
/// Get the "shape" of a fields container.
fn as_shape(&self) -> Shape;
}
impl<T> AsShape for ast::Fields<T> {
fn as_shape(&self) -> Shape {
match self.style {
ast::Style::Tuple if self.fields.len() == 1 => Shape::Newtype,
ast::Style::Tuple => Shape::Tuple,
ast::Style::Struct => Shape::Named,
ast::Style::Unit => Shape::Unit,
}
}
}
impl AsShape for syn::Fields {
fn as_shape(&self) -> Shape {
match self {
syn::Fields::Named(fields) => fields.as_shape(),
syn::Fields::Unnamed(fields) => fields.as_shape(),
syn::Fields::Unit => Shape::Unit,
}
}
}
impl AsShape for syn::FieldsNamed {
fn as_shape(&self) -> Shape {
Shape::Named
}
}
impl AsShape for syn::FieldsUnnamed {
fn as_shape(&self) -> Shape {
if self.unnamed.len() == 1 {
Shape::Newtype
} else {
Shape::Tuple
}
}
}
impl AsShape for syn::DataStruct {
fn as_shape(&self) -> Shape {
self.fields.as_shape()
}
}
impl AsShape for syn::Variant {
fn as_shape(&self) -> Shape {
self.fields.as_shape()
}
}
/// Description of how fields in a struct or variant are syntactically laid out.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Shape {
/// A set of named fields, e.g. `{ field: String }`.
Named,
/// A list of unnamed fields, e.g. `(String, u64)`.
Tuple,
/// No fields, e.g. `struct Example;`
Unit,
/// A special case of [`Tuple`](Shape#variant.Tuple) with exactly one field, e.g. `(String)`.
Newtype,
}
impl Shape {
pub fn description(&self) -> &'static str {
match self {
Shape::Named => "named fields",
Shape::Tuple => "unnamed fields",
Shape::Unit => "no fields",
Shape::Newtype => "one unnamed field",
}
}
}
impl fmt::Display for Shape {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.description())
}
}
impl AsShape for Shape {
fn as_shape(&self) -> Shape {
*self
}
}
/// A set of [`Shape`] values, which correctly handles the relationship between
/// [newtype](Shape#variant.Newtype) and [tuple](Shape#variant.Tuple) shapes.
///
/// # Example
/// ```rust
/// # use darling_core::util::{Shape, ShapeSet};
/// let shape_set = ShapeSet::new(vec![Shape::Tuple]);
///
/// // This is correct, because all newtypes are single-field tuples.
/// assert!(shape_set.contains(&Shape::Newtype));
/// ```
#[derive(Debug, Clone, Default)]
pub struct ShapeSet {
newtype: bool,
named: bool,
tuple: bool,
unit: bool,
}
impl ShapeSet {
/// Create a new `ShapeSet` which includes the specified items.
///
/// # Exampe
/// ```rust
/// # use darling_core::util::{Shape, ShapeSet};
/// let shape_set = ShapeSet::new(vec![Shape::Named, Shape::Newtype]);
/// assert!(shape_set.contains(&Shape::Newtype));
/// ```
pub fn new(items: impl IntoIterator<Item = Shape>) -> Self {
items.into_iter().collect()
}
/// Insert all possible shapes into the set.
///
/// This is equivalent to calling [`insert`](ShapeSet#method.insert) with every value of [`Shape`].
///
/// # Example
/// ```rust
/// # use darling_core::util::{Shape, ShapeSet};
/// let mut shape_set = ShapeSet::default();
/// shape_set.insert_all();
/// assert!(shape_set.contains(&Shape::Named));
/// ```
pub fn insert_all(&mut self) {
self.insert(Shape::Named);
self.insert(Shape::Newtype);
self.insert(Shape::Tuple);
self.insert(Shape::Unit);
}
/// Insert a shape into the set, so that the set will match that shape
pub fn insert(&mut self, shape: Shape) {
match shape {
Shape::Named => self.named = true,
Shape::Tuple => self.tuple = true,
Shape::Unit => self.unit = true,
Shape::Newtype => self.newtype = true,
}
}
/// Whether this set is empty.
pub fn is_empty(&self) -> bool {
!self.named && !self.newtype && !self.tuple && !self.unit
}
fn contains_shape(&self, shape: Shape) -> bool {
match shape {
Shape::Named => self.named,
Shape::Tuple => self.tuple,
Shape::Unit => self.unit,
Shape::Newtype => self.newtype || self.tuple,
}
}
/// Check if a fields container's shape is in this set.
pub fn contains(&self, fields: &impl AsShape) -> bool {
self.contains_shape(fields.as_shape())
}
/// Check if a field container's shape is in this set of shapes, and produce
/// an [`Error`](crate::Error) if it does not.
pub fn check(&self, fields: &impl AsShape) -> crate::Result<()> {
let shape = fields.as_shape();
if self.contains_shape(shape) {
Ok(())
} else {
Err(crate::Error::unsupported_shape_with_expected(
shape.description(),
self,
))
}
}
fn to_vec(&self) -> Vec<Shape> {
let mut shapes = Vec::with_capacity(3);
if self.named {
shapes.push(Shape::Named);
}
if self.tuple || self.newtype {
shapes.push(if self.tuple {
Shape::Tuple
} else {
Shape::Newtype
});
}
if self.unit {
shapes.push(Shape::Unit)
}
shapes
}
}
impl fmt::Display for ShapeSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let shapes = self.to_vec();
match shapes.len() {
0 => write!(f, "nothing"),
1 => write!(f, "{}", shapes[0]),
2 => write!(f, "{} or {}", shapes[0], shapes[1]),
3 => write!(f, "{}, {}, or {}", shapes[0], shapes[1], shapes[2]),
_ => unreachable!(),
}
}
}
impl FromIterator<Shape> for ShapeSet {
fn from_iter<T: IntoIterator<Item = Shape>>(iter: T) -> Self {
let mut output = ShapeSet::default();
for shape in iter.into_iter() {
output.insert(shape);
}
output
}
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::*;
#[test]
fn any_accepts_anything() {
let mut filter = ShapeSet::default();
filter.insert_all();
let unit_struct: syn::DeriveInput = syn::parse_quote! {
struct Example;
};
if let syn::Data::Struct(data) = unit_struct.data {
assert!(filter.contains(&data));
} else {
panic!("Struct not parsed as struct");
};
}
#[test]
fn tuple_accepts_newtype() {
let filter = ShapeSet::new(vec![Shape::Tuple]);
let newtype_struct: syn::DeriveInput = parse_quote! {
struct Example(String);
};
if let syn::Data::Struct(data) = newtype_struct.data {
assert!(filter.contains(&data));
} else {
panic!("Struct not parsed as struct");
};
}
#[test]
fn newtype_rejects_tuple() {
let filter = ShapeSet::new(vec![Shape::Newtype]);
let tuple_struct: syn::DeriveInput = parse_quote! {
struct Example(String, u64);
};
if let syn::Data::Struct(data) = tuple_struct.data {
assert!(!filter.contains(&data));
} else {
panic!("Struct not parsed as struct");
};
}
}

View File

@@ -0,0 +1,145 @@
use proc_macro2::Span;
use std::ops::{Deref, DerefMut};
use syn::spanned::Spanned;
use crate::{
FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam,
FromVariant, Result,
};
/// A value and an associated position in source code. The main use case for this is
/// to preserve position information to emit warnings from proc macros. You can use
/// a `SpannedValue<T>` as a field in any struct that implements or derives any of
/// `darling`'s core traits.
///
/// To access the underlying value, use the struct's `Deref` implementation.
///
/// # Defaulting
/// This type is meant to be used in conjunction with attribute-extracted options,
/// but the user may not always explicitly set those options in their source code.
/// In this case, using `Default::default()` will create an instance which points
/// to `Span::call_site()`.
#[derive(Debug, Clone, Copy)]
pub struct SpannedValue<T> {
value: T,
span: Span,
}
impl<T> SpannedValue<T> {
pub fn new(value: T, span: Span) -> Self {
SpannedValue { value, span }
}
/// Get the source code location referenced by this struct.
pub fn span(&self) -> Span {
self.span
}
/// Apply a mapping function to a reference to the spanned value.
pub fn map_ref<U>(&self, map_fn: impl FnOnce(&T) -> U) -> SpannedValue<U> {
SpannedValue::new(map_fn(&self.value), self.span)
}
}
impl<T: Default> Default for SpannedValue<T> {
fn default() -> Self {
SpannedValue::new(Default::default(), Span::call_site())
}
}
impl<T> Deref for SpannedValue<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
impl<T> DerefMut for SpannedValue<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.value
}
}
impl<T> AsRef<T> for SpannedValue<T> {
fn as_ref(&self) -> &T {
&self.value
}
}
macro_rules! spanned {
($trayt:ident, $method:ident, $syn:path) => {
impl<T: $trayt> $trayt for SpannedValue<T> {
fn $method(value: &$syn) -> Result<Self> {
Ok(SpannedValue::new(
$trayt::$method(value).map_err(|e| e.with_span(value))?,
value.span(),
))
}
}
};
}
impl<T: FromMeta> FromMeta for SpannedValue<T> {
fn from_meta(item: &syn::Meta) -> Result<Self> {
let value = T::from_meta(item).map_err(|e| e.with_span(item))?;
let span = match item {
// Example: `#[darling(skip)]` as SpannedValue<bool>
// should have the span pointing to the word `skip`.
syn::Meta::Path(path) => path.span(),
// Example: `#[darling(attributes(Value))]` as a SpannedValue<Vec<String>>
// should have the span pointing to the list contents.
syn::Meta::List(list) => list.tokens.span(),
// Example: `#[darling(skip = true)]` as SpannedValue<bool>
// should have the span pointing to the word `true`.
syn::Meta::NameValue(nv) => nv.value.span(),
};
Ok(Self::new(value, span))
}
fn from_nested_meta(item: &crate::ast::NestedMeta) -> Result<Self> {
T::from_nested_meta(item)
.map(|value| Self::new(value, item.span()))
.map_err(|e| e.with_span(item))
}
fn from_value(literal: &syn::Lit) -> Result<Self> {
T::from_value(literal)
.map(|value| Self::new(value, literal.span()))
.map_err(|e| e.with_span(literal))
}
fn from_expr(expr: &syn::Expr) -> Result<Self> {
T::from_expr(expr)
.map(|value| Self::new(value, expr.span()))
.map_err(|e| e.with_span(expr))
}
}
spanned!(FromGenericParam, from_generic_param, syn::GenericParam);
spanned!(FromGenerics, from_generics, syn::Generics);
spanned!(FromTypeParam, from_type_param, syn::TypeParam);
spanned!(FromDeriveInput, from_derive_input, syn::DeriveInput);
spanned!(FromField, from_field, syn::Field);
spanned!(FromVariant, from_variant, syn::Variant);
impl<T: Spanned> From<T> for SpannedValue<T> {
fn from(value: T) -> Self {
let span = value.span();
SpannedValue::new(value, span)
}
}
#[cfg(test)]
mod tests {
use super::*;
use proc_macro2::Span;
/// Make sure that `SpannedValue` can be seamlessly used as its underlying type.
#[test]
fn deref() {
let test = SpannedValue::new("hello", Span::call_site());
assert_eq!("hello", test.trim());
}
}

View File

@@ -0,0 +1,35 @@
use crate::{
FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, FromTypeParam,
FromVariant, Result,
};
/// A container to parse some syntax and retain access to the original.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WithOriginal<T, O> {
pub parsed: T,
pub original: O,
}
impl<T, O> WithOriginal<T, O> {
pub fn new(parsed: T, original: O) -> Self {
WithOriginal { parsed, original }
}
}
macro_rules! with_original {
($trayt:ident, $func:ident, $syn:path) => {
impl<T: $trayt> $trayt for WithOriginal<T, $syn> {
fn $func(value: &$syn) -> Result<Self> {
Ok(WithOriginal::new($trayt::$func(value)?, value.clone()))
}
}
};
}
with_original!(FromDeriveInput, from_derive_input, syn::DeriveInput);
with_original!(FromField, from_field, syn::Field);
with_original!(FromGenerics, from_generics, syn::Generics);
with_original!(FromGenericParam, from_generic_param, syn::GenericParam);
with_original!(FromMeta, from_meta, syn::Meta);
with_original!(FromTypeParam, from_type_param, syn::TypeParam);
with_original!(FromVariant, from_variant, syn::Variant);