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; 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 ::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}