evitable_derive_core/
lib.rs

1#![recursion_limit = "4096"]
2
3extern crate proc_macro2;
4extern crate syn;
5#[macro_use]
6extern crate quote;
7extern crate evitable_syn_meta_ext;
8
9use attrs::Attrs;
10use description::{Description, ResolvedDescription};
11use display::DisplayImpl;
12use evitable_syn_meta_ext::{
13  error::Error, error::Result, AttrExt, Fields, FromDeriveInput, FromField, FromMeta, FromVariant,
14  MapFields, Meta, NestedMeta, PathExt,
15};
16use from::FromImpl;
17use ident_case::RenameRule;
18use proc_macro2::{Span, TokenStream};
19use quote::ToTokens;
20use std::borrow::Cow;
21pub use syn::parse_macro_input;
22use syn::{
23  parse::Parser, parse_str, spanned::Spanned, Attribute, DataEnum, DataStruct, DeriveInput, Field,
24  Generics, Ident, Path, Type, Variant, Visibility,
25};
26use trait_assert::assert_trait_impl;
27
28mod attrs;
29mod description;
30mod display;
31mod from;
32mod from_context;
33mod impl_display;
34mod kinds;
35mod trait_assert;
36mod visibility;
37
38trait IntoIdent<'a> {
39  fn into_ident(self) -> Cow<'a, Ident>;
40}
41
42impl<'a> IntoIdent<'a> for Ident {
43  #[inline]
44  fn into_ident(self) -> Cow<'a, Ident> {
45    Cow::Owned(self)
46  }
47}
48
49impl<'a> IntoIdent<'a> for &'a Ident {
50  #[inline]
51  fn into_ident(self) -> Cow<'a, Ident> {
52    Cow::Borrowed(self)
53  }
54}
55
56impl<'a> IntoIdent<'a> for String {
57  #[inline]
58  fn into_ident(self) -> Cow<'a, Ident> {
59    Cow::Owned(Ident::new(&self, Span::call_site()))
60  }
61}
62
63impl<'a> IntoIdent<'a> for &'a str {
64  #[inline]
65  fn into_ident(self) -> Cow<'a, Ident> {
66    Cow::Owned(Ident::new(self, Span::call_site()))
67  }
68}
69
70impl<'a> IntoIdent<'a> for usize {
71  #[inline]
72  fn into_ident(self) -> Cow<'a, Ident> {
73    format!("_{}", self).into_ident()
74  }
75}
76
77impl<'a> IntoIdent<'a> for &'a usize {
78  #[inline]
79  fn into_ident(self) -> Cow<'a, Ident> {
80    (*self).into_ident()
81  }
82}
83
84#[derive(Clone, Copy, PartialEq, Eq)]
85enum CopyMethod {
86  Copy,
87  Clone,
88}
89
90impl Default for CopyMethod {
91  fn default() -> Self {
92    CopyMethod::Copy
93  }
94}
95
96impl CopyMethod {
97  pub fn trait_path(&self) -> Path {
98    match self {
99      CopyMethod::Copy => parse_str("::std::marker::Copy").unwrap(),
100      CopyMethod::Clone => parse_str("::std::clone::Clone").unwrap(),
101    }
102  }
103
104  pub fn copy<T: ToTokens>(&self, from_expr: &T) -> TokenStream {
105    let mut tokens = TokenStream::new();
106    match self {
107      CopyMethod::Copy => tokens.extend(quote! { *#from_expr }),
108      CopyMethod::Clone => tokens.extend(quote! { ::std::clone::Clone::clone(#from_expr) }),
109    }
110
111    tokens
112  }
113
114  #[inline]
115  pub fn is_copy(&self) -> bool {
116    match self {
117      CopyMethod::Copy => true,
118      _ => false,
119    }
120  }
121}
122
123impl FromMeta for CopyMethod {
124  fn from_string<S: Spanned>(value: &str, span: &S) -> Result<Self> {
125    match value {
126      "copy" => Ok(CopyMethod::Copy),
127      "clone" => Ok(CopyMethod::Clone),
128      v => Err(Error::unknown_value(&v).with_span(span)),
129    }
130  }
131
132  fn from_ident(value: &Ident) -> Result<Self> {
133    let s = value.to_string();
134    Self::from_string(&s, value)
135  }
136}
137
138struct ErrorField {
139  ty: Type,
140  include_in_kind: bool,
141  method: CopyMethod,
142}
143
144impl ErrorField {
145  #[inline]
146  pub fn is_copy(&self) -> bool {
147    self.method.is_copy()
148  }
149}
150
151struct ErrorVariant {
152  ident: Ident,
153  description: ResolvedDescription,
154  from_impls: Vec<FromImpl>,
155  fields: Fields<ErrorField>,
156}
157
158impl ErrorVariant {
159  pub(crate) fn destruct(&self) -> TokenStream {
160    match &self.fields {
161      Fields::Unit => TokenStream::new(),
162      Fields::Named(f) => {
163        let idents = f.iter().map(|(i, _)| i);
164        quote! { { #(#idents,)* } }
165      }
166      Fields::Unnamed(f) => {
167        let idents = f.iter().map(|(i, _)| i.into_ident());
168        quote! { ( #(#idents,)* ) }
169      }
170    }
171  }
172}
173
174struct ErrorStruct {
175  description: ResolvedDescription,
176  from_impls: Vec<FromImpl>,
177  fields: Fields<ErrorField>,
178}
179
180enum ErrorData {
181  Struct(ErrorStruct),
182  Enum(Vec<ErrorVariant>),
183}
184
185enum TypeAliasName {
186  Default,
187  Override(Ident),
188  Disabled,
189  Enabled,
190}
191
192impl TypeAliasName {
193  fn ident(&self, default: &str) -> Option<Ident> {
194    match self {
195      TypeAliasName::Disabled => None,
196      TypeAliasName::Override(i) => Some(i.clone()),
197      TypeAliasName::Default | TypeAliasName::Enabled => {
198        Some(Ident::new(default, Span::call_site()))
199      }
200    }
201  }
202}
203
204impl Default for TypeAliasName {
205  fn default() -> Self {
206    TypeAliasName::Default
207  }
208}
209
210impl FromMeta for TypeAliasName {
211  fn from_bool<S: Spanned>(value: bool, _span: &S) -> Result<Self> {
212    if value {
213      Ok(TypeAliasName::Enabled)
214    } else {
215      Ok(TypeAliasName::Disabled)
216    }
217  }
218
219  fn from_string<S: Spanned>(value: &str, span: &S) -> Result<Self> {
220    let ident = Ident::new(value, span.span());
221    Ok(TypeAliasName::Override(ident))
222  }
223
224  fn from_ident(value: &Ident) -> Result<Self> {
225    Ok(TypeAliasName::Override(value.clone()))
226  }
227
228  fn from_empty() -> Result<Self> {
229    Ok(TypeAliasName::Enabled)
230  }
231}
232
233struct ErrorType {
234  ident: Ident,
235  prefix: Option<String>,
236  vis: Visibility,
237  generics: Generics,
238  data: ErrorData,
239  attrs: ErrorTypeAttrs,
240  mod_name: Ident,
241  mod_vis: Visibility,
242  impls_from: Vec<from::FromImplFor>,
243}
244
245struct ErrorTypeAttrs {
246  error_type_name: TypeAliasName,
247  result_type_name: TypeAliasName,
248  kind_type_name: TypeAliasName,
249}
250
251impl ErrorTypeAttrs {
252  fn from_attrs(attrs: &mut Attrs) -> Result<Self> {
253    let error_type_name = attrs.get_optional("error_type")?.unwrap_or_default();
254    let result_type_name = attrs.get_optional("result_type")?.unwrap_or_default();
255    let kind_type_name = attrs.get_optional("kind_type")?.unwrap_or_default();
256
257    Ok(Self {
258      error_type_name,
259      result_type_name,
260      kind_type_name,
261    })
262  }
263}
264
265impl FromVariant for ErrorVariant {
266  fn from_variant(variant: &Variant) -> Result<Self> {
267    let mut attrs = Attrs::from_attributes(&variant.attrs)?;
268    let fields = variant
269      .fields
270      .clone()
271      .try_map_fields(|field| ErrorField::from_field(&field))?;
272
273    let description: Description = attrs.get_required("description", &variant.ident)?;
274    let description = description.resolve_from_variant(&fields)?;
275    let from_impls = attrs.get_list("from")?;
276    attrs.ensure_used()?;
277
278    Ok(ErrorVariant {
279      ident: variant.ident.clone(),
280      description,
281      from_impls,
282      fields,
283    })
284  }
285}
286
287impl FromField for ErrorField {
288  fn from_field(field: &Field) -> Result<Self> {
289    let mut attrs = Attrs::from_attributes(&field.attrs)?;
290    let include_in_kind = attrs.get_optional("include_in_kind")?.unwrap_or(false);
291    let method = if include_in_kind {
292      match attrs.get_optional("method")? {
293        Some(m) => m,
294        None => match attrs.get_optional("clone")? {
295          None => Default::default(),
296          Some(true) => CopyMethod::Clone,
297          Some(false) => CopyMethod::Copy,
298        },
299      }
300    } else {
301      Default::default()
302    };
303
304    attrs.ensure_used()?;
305    Ok(ErrorField {
306      ty: field.ty.clone(),
307      include_in_kind,
308      method,
309    })
310  }
311}
312
313impl ErrorType {
314  fn impl_froms<'a>(
315    data: &ErrorData,
316    ident: &Ident,
317    mod_name: &Ident,
318  ) -> Result<Vec<from::FromImplFor>> {
319    match data {
320      ErrorData::Struct(s) => s
321        .from_impls
322        .iter()
323        .map(|f| f.for_struct(s, mod_name, ident))
324        .collect(),
325      ErrorData::Enum(variants) => variants
326        .iter()
327        .flat_map(|variant| {
328          variant
329            .from_impls
330            .iter()
331            .map(move |f| f.for_variant(&variant, mod_name, ident))
332        })
333        .collect(),
334    }
335  }
336
337  fn new(
338    ident: Ident,
339    vis: Visibility,
340    generics: Generics,
341    data: ErrorData,
342    attrs: ErrorTypeAttrs,
343  ) -> Result<Self> {
344    let ident_str = ident.to_string();
345    let (mod_name, prefix) = if ident_str.ends_with("Context") && ident_str.len() > "Context".len()
346    {
347      let prefix = ident_str[0..ident_str.len() - "Context".len()].to_string();
348      let mod_name = RenameRule::SnakeCase.apply_to_variant(&prefix);
349      (mod_name, Some(prefix))
350    } else {
351      let mod_name = "evitable_".to_owned() + &RenameRule::SnakeCase.apply_to_variant(ident_str);
352      (mod_name, None)
353    };
354
355    let mod_name = Ident::new(&mod_name, ident.span());
356    let mod_vis = visibility::inherited(&vis, 1);
357    let impls_from = Self::impl_froms(&data, &ident, &mod_name)?;
358
359    Ok(Self {
360      ident,
361      prefix,
362      vis,
363      generics,
364      data,
365      attrs,
366      mod_name,
367      mod_vis,
368      impls_from,
369    })
370  }
371}
372
373impl FromDeriveInput for ErrorType {
374  fn from_enum(
375    attrs: &Vec<Attribute>,
376    vis: &Visibility,
377    ident: &Ident,
378    generics: &Generics,
379    input: &DataEnum,
380  ) -> Result<Self> {
381    let variants: Result<Vec<ErrorVariant>> = input
382      .variants
383      .iter()
384      .map(ErrorVariant::from_variant)
385      .collect();
386
387    let mut evitable_attrs = Attrs::from_attributes(attrs)?;
388    let attrs = ErrorTypeAttrs::from_attrs(&mut evitable_attrs)?;
389    evitable_attrs.ensure_used()?;
390    let data = ErrorData::Enum(variants?);
391
392    ErrorType::new(ident.clone(), vis.clone(), generics.clone(), data, attrs)
393  }
394
395  fn from_struct(
396    attrs: &Vec<Attribute>,
397    vis: &Visibility,
398    ident: &Ident,
399    generics: &Generics,
400    input: &DataStruct,
401  ) -> Result<Self> {
402    let fields = (&input.fields).try_map_fields(ErrorField::from_field)?;
403    let mut evitable_attrs = Attrs::from_attributes(attrs)?;
404    let attrs = ErrorTypeAttrs::from_attrs(&mut evitable_attrs)?;
405    let description: Description = evitable_attrs.get_required("description", ident)?;
406    let description = description.resolve_from_inst(&fields, "self")?;
407    let from_impls = evitable_attrs.get_list("from")?;
408    evitable_attrs.ensure_used()?;
409    let data = ErrorData::Struct(ErrorStruct {
410      description,
411      fields,
412      from_impls,
413    });
414
415    ErrorType::new(ident.clone(), vis.clone(), generics.clone(), data, attrs)
416  }
417}
418
419impl ToTokens for ErrorType {
420  fn to_tokens(&self, tokens: &mut TokenStream) {
421    let ty = &self.ident; // TOOD: Generics
422    let vis = &self.vis;
423    let mod_name = &self.mod_name;
424    let mod_item_vis = &self.mod_vis;
425
426    let kinds = kinds::for_type(self);
427    let from_context = from_context::for_type(&kinds, ty);
428    let impl_display = DisplayImpl::for_type(self);
429    let impls_from = &self.impls_from;
430
431    tokens.extend(quote! {
432      #vis mod #mod_name {
433        use super::*;
434
435        #kinds
436        #from_context
437
438        #mod_item_vis struct Error {
439          context: super::#ty,
440          backtrace: ::evitable::Backtrace,
441          source: Option<Box<dyn ::std::error::Error + ::std::marker::Send + ::std::marker::Sync + 'static>>,
442        }
443
444        impl Error {
445          #[inline]
446          fn context(&self) -> &super::#ty {
447            &self.context
448          }
449
450          #[inline]
451          fn backtrace(&self) -> &::evitable::Backtrace {
452            &self.backtrace
453          }
454
455          #[inline]
456          fn kind(&self) -> ErrorKind {
457            ::evitable::ErrorContext::kind(&self.context)
458          }
459        }
460
461        #[automatically_derived]
462        #[allow(unused_qualifications)]
463        impl ::std::convert::From<super::#ty> for Error {
464          #[inline]
465          fn from(context: super::#ty) -> Self {
466            <Error as ::evitable::EvitableError>::new(context, None)
467          }
468        }
469
470        #[automatically_derived]
471        #[allow(unused_qualifications)]
472        impl ::std::fmt::Display for Error {
473          fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
474            ::std::fmt::Display::fmt(&self.context, f)?;
475            if let Some(source) = &self.source {
476              f.write_str("\n---- source ----\n")?;
477              ::std::fmt::Display::fmt(source, f)?;
478            }
479
480            Ok(())
481          }
482        }
483
484        #[automatically_derived]
485        #[allow(unused_qualifications)]
486        impl ::std::fmt::Debug for Error {
487          fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
488            // TODO: Include backtrace
489            ::std::fmt::Debug::fmt(&self.context, f)?;
490            if let Some(source) = &self.source {
491              f.write_str("\n---- source ----\n")?;
492              ::std::fmt::Debug::fmt(source, f)?;
493            }
494
495            Ok(())
496          }
497        }
498
499        #[automatically_derived]
500        #[allow(unused_qualifications)]
501        impl ::std::error::Error for Error {
502          fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
503            match &self.source {
504              None => None,
505              Some(b) => Some(b.as_ref()),
506            }
507          }
508        }
509
510
511        #[automatically_derived]
512        #[allow(unused_qualifications)]
513        impl ::evitable::EvitableError for Error {
514          type Kind = ErrorKind;
515          type Context = super::#ty;
516
517          #[inline]
518          fn context(&self) -> &Self::Context {
519            Error::context(self)
520          }
521
522          #[inline]
523          fn kind(&self) -> Self::Kind {
524            Error::kind(self)
525          }
526
527          #[inline]
528          fn backtrace(&self) -> &::evitable::Backtrace {
529            Error::backtrace(self)
530          }
531
532          #[inline]
533          fn new(context: Self::Context, source: Option<Box<dyn ::std::error::Error + ::std::marker::Send + ::std::marker::Sync + 'static>>) -> Self {
534            let backtrace = ::evitable::Backtrace::new();
535
536            Self {
537              context,
538              source,
539              backtrace,
540            }
541          }
542        }
543
544        #(#impls_from)*
545
546        #mod_item_vis type Result<T> = ::std::result::Result<T, Error>;
547      }
548
549      #impl_display
550
551      #[automatically_derived]
552      #[allow(unused_qualifications)]
553      impl ::evitable::ErrorContext for #ty {
554        type Kind = #mod_name::ErrorKind;
555        type Error = #mod_name::Error;
556
557        fn kind(&self) -> Self::Kind {
558          #mod_name::ErrorKind::from_context(self)
559        }
560      }
561    });
562
563    let prefixed = |s: &'static str| match &self.prefix {
564      None => Cow::Borrowed(s),
565      Some(p) => {
566        let mut full = String::with_capacity(s.len() + p.len());
567        full.push_str(p);
568        full.push_str(s);
569        Cow::Owned(full)
570      }
571    };
572
573    if let Some(ident) = self.attrs.error_type_name.ident(&prefixed("Error")) {
574      tokens.extend(quote! {
575        #vis type #ident = #mod_name::Error;
576      });
577    }
578
579    if let Some(ident) = self.attrs.result_type_name.ident(&prefixed("Result")) {
580      tokens.extend(quote! {
581        #vis type #ident<T> = #mod_name::Result<T>;
582      });
583    }
584
585    if let Some(ident) = self.attrs.kind_type_name.ident(&prefixed("ErrorKind")) {
586      tokens.extend(quote! {
587        #vis type #ident = #mod_name::ErrorKind;
588      });
589    }
590  }
591}
592
593fn add_attribute(input: &mut DeriveInput, attr: Attribute) {
594  input.attrs.push(attr);
595}
596
597trait AttributeTree {
598  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ());
599}
600
601impl AttributeTree for syn::Field {
602  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
603    f(&mut self.attrs);
604  }
605}
606
607impl AttributeTree for syn::FieldsNamed {
608  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
609    for field in self.named.iter_mut() {
610      field.visit(f);
611    }
612  }
613}
614
615impl AttributeTree for syn::FieldsUnnamed {
616  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
617    for field in self.unnamed.iter_mut() {
618      field.visit(f);
619    }
620  }
621}
622
623impl AttributeTree for syn::Fields {
624  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
625    match self {
626      syn::Fields::Named(n) => n.visit(f),
627      syn::Fields::Unnamed(u) => u.visit(f),
628      syn::Fields::Unit => (),
629    }
630  }
631}
632
633impl AttributeTree for syn::DataStruct {
634  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
635    self.fields.visit(f);
636  }
637}
638
639impl AttributeTree for syn::Variant {
640  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
641    f(&mut self.attrs);
642    self.fields.visit(f);
643  }
644}
645
646impl AttributeTree for syn::DataEnum {
647  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
648    for variant in self.variants.iter_mut() {
649      variant.visit(f);
650    }
651  }
652}
653
654impl AttributeTree for syn::Data {
655  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
656    match self {
657      syn::Data::Struct(s) => s.visit(f),
658      syn::Data::Enum(e) => e.visit(f),
659      syn::Data::Union(_) => (),
660    }
661  }
662}
663
664impl AttributeTree for syn::DeriveInput {
665  fn visit(&mut self, f: &impl Fn(&mut Vec<Attribute>) -> ()) {
666    f(&mut self.attrs);
667    self.data.visit(f);
668  }
669}
670
671fn remove_evitable_attrs(input: &mut DeriveInput) {
672  input.visit(&|attrs| {
673    let a = std::mem::replace(attrs, Vec::new());
674    let a = a
675      .into_iter()
676      .filter(|attr| attr.meta().map(|m| !m.is("evitable")).unwrap_or(true))
677      .collect();
678    std::mem::replace(attrs, a);
679  });
680}
681
682pub fn derive_evitable(meta: &TokenStream, input: &mut DeriveInput) -> TokenStream {
683  let mut cloned = input.clone();
684  remove_evitable_attrs(input);
685
686  if !meta.is_empty() {
687    let meta_attr_quote = quote! {#[evitable(#meta)]};
688    let parser = Attribute::parse_outer;
689    let attr = match parser.parse2(meta_attr_quote) {
690      Ok(val) => val[0].clone(),
691      Err(err) => return err.to_compile_error(),
692    };
693
694    add_attribute(&mut cloned, attr);
695  }
696
697  let error_type = ErrorType::from_derive_input(&cloned);
698  match error_type {
699    Ok(val) => quote! { #input #val },
700    Err(err) => err.write_errors(),
701  }
702}