educe/common/
where_predicates_bool.rs1use quote::{quote, ToTokens};
2use syn::{
3 parse::{Parse, ParseStream},
4 punctuated::Punctuated,
5 spanned::Spanned,
6 token::Comma,
7 Expr, GenericParam, Lit, Meta, MetaNameValue, Path, Token, Type, WherePredicate,
8};
9
10use super::path::path_to_string;
11
12pub(crate) type WherePredicates = Punctuated<WherePredicate, Token![,]>;
13
14pub(crate) enum WherePredicatesOrBool {
15 WherePredicates(WherePredicates),
16 Bool(bool),
17 All,
18}
19
20impl WherePredicatesOrBool {
21 fn from_lit(lit: &Lit) -> syn::Result<Self> {
22 Ok(match lit {
23 Lit::Bool(lit) => Self::Bool(lit.value),
24 Lit::Str(lit) => match lit.parse_with(WherePredicates::parse_terminated) {
25 Ok(where_predicates) => Self::WherePredicates(where_predicates),
26 Err(_) if lit.value().is_empty() => Self::Bool(false),
27 Err(error) => return Err(error),
28 },
29 other => {
30 return Err(syn::Error::new(
31 other.span(),
32 "unexpected kind of literal (only boolean or string allowed)",
33 ))
34 },
35 })
36 }
37}
38
39impl Parse for WherePredicatesOrBool {
40 #[inline]
41 fn parse(input: ParseStream) -> syn::Result<Self> {
42 if let Ok(lit) = input.parse::<Lit>() {
43 return Self::from_lit(&lit);
44 }
45
46 if let Ok(_star) = input.parse::<Token![*]>() {
47 return Ok(Self::All);
48 }
49
50 Ok(Self::WherePredicates(input.parse_terminated(WherePredicate::parse, Token![,])?))
51 }
52}
53
54#[inline]
55pub(crate) fn meta_name_value_2_where_predicates_bool(
56 name_value: &MetaNameValue,
57) -> syn::Result<WherePredicatesOrBool> {
58 if let Expr::Lit(lit) = &name_value.value {
59 return WherePredicatesOrBool::from_lit(&lit.lit);
60 }
61
62 Err(syn::Error::new(
63 name_value.value.span(),
64 format!(
65 "expected `{path} = \"where_predicates\"` or `{path} = false`",
66 path = path_to_string(&name_value.path)
67 ),
68 ))
69}
70
71#[inline]
72pub(crate) fn meta_2_where_predicates(meta: &Meta) -> syn::Result<WherePredicatesOrBool> {
73 match &meta {
74 Meta::NameValue(name_value) => meta_name_value_2_where_predicates_bool(name_value),
75 Meta::List(list) => list.parse_args::<WherePredicatesOrBool>(),
76 Meta::Path(path) => Err(syn::Error::new(
77 path.span(),
78 format!(
79 "expected `{path} = \"where_predicates\"`, `{path}(where_predicates)`, `{path} = \
80 false`, or `{path}(false)`",
81 path = path.clone().into_token_stream()
82 ),
83 )),
84 }
85}
86
87#[inline]
88pub(crate) fn create_where_predicates_from_all_generic_parameters(
89 params: &Punctuated<GenericParam, Comma>,
90 bound_trait: &Path,
91) -> WherePredicates {
92 let mut where_predicates = Punctuated::new();
93
94 for param in params {
95 if let GenericParam::Type(ty) = param {
96 let ident = &ty.ident;
97
98 where_predicates.push(syn::parse2(quote! { #ident: #bound_trait }).unwrap());
99 }
100 }
101
102 where_predicates
103}
104
105#[inline]
106pub(crate) fn create_where_predicates_from_generic_parameters_check_types(
107 bound_trait: &Path,
108 types: &[&Type],
109 supertraits: &[proc_macro2::TokenStream],
110) -> WherePredicates {
111 let mut where_predicates = Punctuated::new();
112
113 for t in types {
114 where_predicates.push(syn::parse2(quote! { #t: #bound_trait }).unwrap());
115 }
116
117 for supertrait in supertraits {
118 where_predicates.push(syn::parse2(quote! { Self: #supertrait }).unwrap());
119 }
120
121 where_predicates
122}