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

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);