1use crate::lazy_bool::LazyBool;
2use darling::FromDeriveInput;
3use proc_macro::TokenStream;
4use proc_macro2::TokenStream as TokenStream2;
5use quote::ToTokens;
6use std::ops::{BitAnd, BitOr, Not};
7use syn::{
8 parse::{Parse, ParseStream},
9 parse_quote,
10 punctuated::Punctuated,
11 Attribute, DeriveInput, Generics, Meta, Path, PathSegment, Token, TypeGenerics, WhereClause,
12};
13
14pub(crate) trait IteratorExt {
16 fn collect_error(self) -> syn::Result<()>
17 where
18 Self: Iterator<Item = syn::Result<()>> + Sized,
19 {
20 let accu = Ok(());
21 self.fold(accu, |accu, error| match (accu, error) {
22 (Ok(()), error) => error,
23 (accu, Ok(())) => accu,
24 (Err(mut err), Err(error)) => {
25 err.combine(error);
26 Err(err)
27 }
28 })
29 }
30}
31impl<I> IteratorExt for I where I: Iterator<Item = syn::Result<()>> + Sized {}
32
33#[derive(#[automatically_derived]
#[allow(clippy :: manual_unwrap_or_default)]
impl ::darling::FromDeriveInput for DeriveOptions {
fn from_derive_input(__di: &::darling::export::syn::DeriveInput)
-> ::darling::Result<Self> {
let mut __errors = ::darling::Error::accumulator();
let mut alt_crate_path:
(bool, ::darling::export::Option<Option<Path>>) =
(false, None);
use ::darling::ToTokens;
for __attr in &__di.attrs {
match ::darling::export::ToString::to_string(&__attr.path().clone().into_token_stream()).as_str()
{
"serde_with" => {
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; }
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() {
"crate" => {
if !alt_crate_path.0 {
alt_crate_path =
(true,
__errors.handle(::darling::export::identity::<fn(&::darling::export::syn::Meta)
->
::darling::Result<_>>(::darling::FromMeta::from_meta)(__inner).map_err(|e|
e.with_span(&__inner).at("crate"))));
} else {
__errors.push(::darling::Error::duplicate_field("crate").with_span(&__inner));
}
}
__other => {
__errors.push(::darling::Error::unknown_field_with_alts(__other,
&["crate"]).with_span(__inner));
}
}
}
::darling::export::NestedMeta::Lit(ref __inner) => {
__errors.push(::darling::Error::unsupported_format("literal").with_span(__inner));
}
}
}
}
::darling::export::Err(__err) => {
__errors.push(__err.into());
}
}
}
::darling::export::Err(__err) => { __errors.push(__err); }
}
}
_ => continue,
}
}
__errors.handle(::darling::export::Ok(&__di.data).and_then(::darling::export::Ok));
__errors.finish()?;
::darling::export::Ok(DeriveOptions {
alt_crate_path: if let Some(__val) = alt_crate_path.1 {
__val
} else { ::darling::export::Default::default() },
})
}
}FromDeriveInput)]
35#[darling(attributes(serde_with))]
36pub(crate) struct DeriveOptions {
37 #[darling(rename = "crate", default)]
39 pub(crate) alt_crate_path: Option<Path>,
40}
41
42impl DeriveOptions {
43 pub(crate) fn from_derive_input(input: &DeriveInput) -> Result<Self, TokenStream> {
44 match <Self as FromDeriveInput>::from_derive_input(input) {
45 Ok(v) => Ok(v),
46 Err(e) => Err(TokenStream::from(e.write_errors())),
47 }
48 }
49
50 pub(crate) fn get_serde_with_path(&self) -> Path {
51 self.alt_crate_path
52 .clone()
53 .unwrap_or_else(|| syn::parse_str("::serde_with").unwrap())
54 }
55}
56
57pub(crate) fn split_with_de_lifetime(
60 generics: &Generics,
61) -> (DeImplGenerics<'_>, TypeGenerics<'_>, Option<&WhereClause>) {
62 let de_impl_generics = DeImplGenerics(generics);
63 let (_, ty_generics, where_clause) = generics.split_for_impl();
64 (de_impl_generics, ty_generics, where_clause)
65}
66
67pub(crate) struct DeImplGenerics<'a>(&'a Generics);
68
69impl ToTokens for DeImplGenerics<'_> {
70 fn to_tokens(&self, tokens: &mut TokenStream2) {
71 let mut generics = self.0.clone();
72 generics.params = Some(::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lifetime(&mut _s, "\'de");
_s
})parse_quote!('de))
73 .into_iter()
74 .chain(generics.params)
75 .collect();
76 let (impl_generics, _, _) = generics.split_for_impl();
77 impl_generics.to_tokens(tokens);
78 }
79}
80
81struct CfgAttr {
88 condition: Meta,
89 _comma: ::syn::token::CommaToken![,],
90 metas: Punctuated<Meta, ::syn::token::CommaToken![,]>,
91}
92
93impl Parse for CfgAttr {
94 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
95 Ok(Self {
96 condition: input.parse()?,
97 _comma: input.parse()?,
98 metas: Punctuated::parse_terminated(input)?,
99 })
100 }
101}
102
103pub(crate) fn has_derive_jsonschema(input: TokenStream) -> syn::Result<SchemaFieldConfig> {
105 fn parse_derive_args(input: ParseStream<'_>) -> syn::Result<Punctuated<Path, ::syn::token::CommaToken![,]>> {
106 Punctuated::parse_terminated_with(input, Path::parse_mod_style)
107 }
108
109 fn eval_metas<'a>(metas: impl IntoIterator<Item = &'a Meta>) -> syn::Result<SchemaFieldConfig> {
110 metas
111 .into_iter()
112 .map(eval_meta)
113 .try_fold(
114 SchemaFieldConfig::False,
115 |state, result| Ok(state | result?),
116 )
117 }
118
119 fn eval_meta(meta: &Meta) -> syn::Result<SchemaFieldConfig> {
120 match meta.path() {
121 path if path.is_ident("cfg_attr") => {
122 let CfgAttr {
123 condition, metas, ..
124 } = meta.require_list()?.parse_args()?;
125
126 Ok(eval_metas(&metas)? & SchemaFieldConfig::Lazy(condition.into()))
127 }
128 path if path.is_ident("derive") => {
129 let config = if meta
130 .require_list()?
131 .parse_args_with(parse_derive_args)?
132 .into_iter()
133 .any(|Path { segments, .. }| {
134 match segments.last() {
139 Some(PathSegment { ident, .. }) => ident == "JsonSchema",
140 _ => false,
141 }
142 }) {
143 SchemaFieldConfig::True
144 } else {
145 LazyBool::default()
146 };
147 Ok(config)
148 }
149 _ => Ok(SchemaFieldConfig::False),
150 }
151 }
152
153 let DeriveInput { attrs, .. } = syn::parse(input)?;
154 let metas = attrs.iter().map(|Attribute { meta, .. }| meta);
155 eval_metas(metas)
156}
157
158pub(crate) type SchemaFieldConfig = LazyBool<SchemaFieldCondition>;
160
161impl From<Meta> for SchemaFieldConfig {
162 fn from(meta: Meta) -> Self {
163 Self::Lazy(meta.into())
164 }
165}
166
167#[derive(#[automatically_derived]
impl ::core::clone::Clone for SchemaFieldCondition {
#[inline]
fn clone(&self) -> SchemaFieldCondition {
SchemaFieldCondition(::core::clone::Clone::clone(&self.0))
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for SchemaFieldCondition {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"SchemaFieldCondition", &&self.0)
}
}Debug, #[automatically_derived]
impl ::core::cmp::Eq for SchemaFieldCondition {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Meta>;
}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for SchemaFieldCondition {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for SchemaFieldCondition {
#[inline]
fn eq(&self, other: &SchemaFieldCondition) -> bool { self.0 == other.0 }
}PartialEq)]
168pub(crate) struct SchemaFieldCondition(pub(crate) Meta);
169
170impl BitAnd for SchemaFieldCondition {
171 type Output = Self;
172
173 fn bitand(self, Self(rhs): Self) -> Self::Output {
174 let Self(lhs) = self;
175 Self(::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "all");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&lhs, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&rhs, &mut _s);
_s
});
_s
})parse_quote!(all(#lhs, #rhs)))
176 }
177}
178
179impl BitAnd<&SchemaFieldCondition> for SchemaFieldCondition {
180 type Output = Self;
181
182 fn bitand(self, Self(rhs): &Self) -> Self::Output {
183 let Self(lhs) = self;
184 Self(::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "all");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&lhs, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&rhs, &mut _s);
_s
});
_s
})parse_quote!(all(#lhs, #rhs)))
185 }
186}
187
188impl BitOr for SchemaFieldCondition {
189 type Output = Self;
190
191 fn bitor(self, Self(rhs): Self) -> Self::Output {
192 let Self(lhs) = self;
193 Self(::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "any");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&lhs, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&rhs, &mut _s);
_s
});
_s
})parse_quote!(any(#lhs, #rhs)))
194 }
195}
196
197impl Not for SchemaFieldCondition {
198 type Output = Self;
199
200 fn not(self) -> Self::Output {
201 let Self(condition) = self;
202 Self(::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "not");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&condition, &mut _s);
_s
});
_s
})parse_quote!(not(#condition)))
203 }
204}
205
206impl From<Meta> for SchemaFieldCondition {
207 fn from(meta: Meta) -> Self {
208 Self(meta)
209 }
210}
211
212pub(crate) fn schemars_with_attr_if(
215 attrs: &[Attribute],
216 filter: &[&str],
217) -> syn::Result<SchemaFieldConfig> {
218 fn eval_metas<'a>(
219 filter: &[&str],
220 metas: impl IntoIterator<Item = &'a Meta>,
221 ) -> syn::Result<SchemaFieldConfig> {
222 metas
223 .into_iter()
224 .map(|meta| eval_meta(filter, meta))
225 .try_fold(
226 SchemaFieldConfig::False,
227 |state, result| Ok(state | result?),
228 )
229 }
230
231 fn eval_meta(filter: &[&str], meta: &Meta) -> syn::Result<SchemaFieldConfig> {
232 match meta.path() {
233 path if path.is_ident("cfg_attr") => {
234 let CfgAttr {
235 condition, metas, ..
236 } = meta.require_list()?.parse_args()?;
237
238 Ok(eval_metas(filter, &metas)? & SchemaFieldConfig::from(condition))
239 }
240 path if path.is_ident("schemars") => {
241 let config = if meta
242 .require_list()?
243 .parse_args_with(<Punctuated<Meta, ::syn::token::CommaToken![,]>>::parse_terminated)?
244 .into_iter()
245 .any(|meta| match meta.path().get_ident() {
246 Some(ident) => filter.iter().any(|relevant| ident == relevant),
247 _ => false,
248 }) {
249 SchemaFieldConfig::True
250 } else {
251 LazyBool::default()
252 };
253 Ok(config)
254 }
255 _ => Ok(SchemaFieldConfig::False),
256 }
257 }
258
259 let metas = attrs.iter().map(|Attribute { meta, .. }| meta);
260 eval_metas(filter, metas)
261}