/home/runner/work/bare_err_tree/bare_err_tree/bare_err_tree_proc/src/boiler.rs
Line | Count | Source |
1 | | /* |
2 | | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at https://mozilla.org/MPL/2.0/. |
5 | | */ |
6 | | |
7 | | use std::iter; |
8 | | |
9 | | use proc_macro::TokenStream; |
10 | | use quote::quote; |
11 | | use syn::{Attribute, Generics, Ident, Meta}; |
12 | | |
13 | | /// Derives intended to minimize friction introduced by the wrapper. |
14 | | /// |
15 | | /// Derives transparent Error, Debug, From (both ways), and Deref(Mut). |
16 | | /// If known derivable traits are in scope, re-derives those as well. |
17 | 1 | pub fn wrapper_boilerplate( |
18 | 1 | ident: &Ident, |
19 | 1 | generics: &Generics, |
20 | 1 | attrs: &[Attribute], |
21 | 1 | name_attribute: &Ident, |
22 | 1 | ) -> TokenStream { |
23 | 1 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); |
24 | 1 | |
25 | 1 | // Core set |
26 | 1 | let universal: TokenStream = quote! { |
27 | 1 | #[automatically_derived] |
28 | 1 | impl #impl_generics ::core::error::Error for #name_attribute #ty_generics #where_clause { |
29 | 1 | fn source(&self) -> Option<&(dyn ::core::error::Error + 'static)> { |
30 | 1 | ::core::error::Error::source(&self.inner) |
31 | 1 | } |
32 | 1 | } |
33 | 1 | |
34 | 1 | #[automatically_derived] |
35 | 1 | impl #impl_generics ::core::fmt::Debug for #name_attribute #ty_generics #where_clause { |
36 | 1 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), ::core::fmt::Error> { |
37 | 1 | ::core::fmt::Debug::fmt(&self.inner, f) |
38 | 1 | } |
39 | 1 | } |
40 | 1 | |
41 | 1 | #[automatically_derived] |
42 | 1 | impl #impl_generics ::core::fmt::Display for #name_attribute #ty_generics #where_clause { |
43 | 1 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> Result<(), ::core::fmt::Error> { |
44 | 1 | ::core::fmt::Display::fmt(&self.inner, f) |
45 | 1 | } |
46 | 1 | } |
47 | 1 | |
48 | 1 | #[automatically_derived] |
49 | 1 | impl #impl_generics ::core::convert::From<#ident #ty_generics> for #name_attribute #ty_generics #where_clause { |
50 | 1 | #[track_caller] |
51 | 1 | fn from(inner: #ident #ty_generics) -> Self { |
52 | 1 | Self::_tree(inner) |
53 | 1 | } |
54 | 1 | } |
55 | 1 | |
56 | 1 | #[automatically_derived] |
57 | 1 | impl #impl_generics ::core::convert::From<#name_attribute #ty_generics> for #ident #ty_generics #where_clause { |
58 | 1 | fn from(value: #name_attribute #ty_generics) -> Self { |
59 | 1 | value.inner |
60 | 1 | } |
61 | 1 | } |
62 | 1 | |
63 | 1 | #[automatically_derived] |
64 | 1 | impl #impl_generics ::core::ops::Deref for #name_attribute #ty_generics #where_clause { |
65 | 1 | type Target = #ident #ty_generics; |
66 | 1 | fn deref(&self) -> &Self::Target { |
67 | 1 | &self.inner |
68 | 1 | } |
69 | 1 | } |
70 | 1 | |
71 | 1 | #[automatically_derived] |
72 | 1 | impl #impl_generics ::core::ops::DerefMut for #name_attribute #ty_generics #where_clause { |
73 | 1 | fn deref_mut(&mut self) -> &mut Self::Target { |
74 | 1 | &mut self.inner |
75 | 1 | } |
76 | 1 | } |
77 | 1 | } |
78 | 1 | .into(); |
79 | 1 | |
80 | 1 | // Look for viable extra derives |
81 | 1 | let mut extra_derive = Vec::new(); |
82 | 1 | attrs.iter().for_each(|x| { |
83 | 1 | if let Meta::List(list) = &x.meta { |
84 | 1 | if list.path.get_ident().map(|x| x.to_string()) == Some("derive".to_string()) { |
85 | 1 | let _ = list.parse_nested_meta(|meta| { |
86 | 1 | if let Some(ident) = meta.path.get_ident() { |
87 | 1 | extra_derive.push(ident.clone()); |
88 | 1 | }0 |
89 | 1 | Ok(()) |
90 | 1 | }); |
91 | 1 | }0 |
92 | 0 | } |
93 | 1 | }); |
94 | 1 | |
95 | 1 | // Optimistically added extra derives |
96 | 1 | let extra_derive_tokens = |
97 | 1 | extra_derive |
98 | 1 | .into_iter() |
99 | 1 | .map(|extra| match extra.to_string().to_lowercase().as_str() { |
100 | 1 | "eq" => quote! { |
101 | 0 | #[automatically_derived] |
102 | 0 | impl #impl_generics ::core::cmp::Eq for #name_attribute #ty_generics #where_clause {} |
103 | 0 | } |
104 | 0 | .into(), |
105 | 1 | "partialeq" => quote! { |
106 | 0 | #[automatically_derived] |
107 | 0 | impl #impl_generics ::core::cmp::PartialEq<#name_attribute #ty_generics> for #name_attribute #ty_generics #where_clause { |
108 | 0 | fn eq(&self, other: &#name_attribute #ty_generics) -> bool { |
109 | 0 | self.inner == other.inner |
110 | 0 | } |
111 | 0 | } |
112 | 0 | } |
113 | 0 | .into(), |
114 | 1 | "ord" => quote! { |
115 | 0 | #[automatically_derived] |
116 | 0 | impl #impl_generics ::core::cmp::Ord for #name_attribute #ty_generics #where_clause { |
117 | 0 | fn ord(&self, other: &Self) -> bool { |
118 | 0 | <#ident #ty_generics #where_clause as ::core::cmp::Ord>::ord(self.inner, other.inner) |
119 | 0 | } |
120 | 0 | } |
121 | 0 | } |
122 | 0 | .into(), |
123 | 1 | "partialord" => quote! { |
124 | 0 | #[automatically_derived] |
125 | 0 | impl #impl_generics ::core::cmp::PartialOrd for #name_attribute #ty_generics #where_clause { |
126 | 0 | fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> { |
127 | 0 | <#ident #ty_generics #where_clause as ::core::cmp::ParitalOrd>::partial_cmp(self.inner, other.inner) |
128 | 0 | } |
129 | 0 | } |
130 | 0 | } |
131 | 0 | .into(), |
132 | 1 | "clone" => quote! { |
133 | 0 | #[automatically_derived] |
134 | 0 | impl #impl_generics ::core::clone::Clone for #name_attribute #ty_generics #where_clause { |
135 | 0 | fn clone(&self) -> Self { |
136 | 0 | Self { |
137 | 0 | inner: self.inner.clone(), |
138 | 0 | _err_tree_pkg: self._err_tree_pkg.clone() |
139 | 0 | } |
140 | 0 | } |
141 | 0 | } |
142 | 0 | } |
143 | 0 | .into(), |
144 | 1 | "hash" => quote! { |
145 | 0 | #[automatically_derived] |
146 | 0 | impl #impl_generics ::core::hash::Hash for #name_attribute #ty_generics #where_clause { |
147 | 0 | fn hash<H>(&self, state: &mut H) |
148 | 0 | where H: ::core::hash::Hasher |
149 | 0 | { |
150 | 0 | self.inner.hash(state) |
151 | 0 | } |
152 | 0 | } |
153 | 0 | } |
154 | 0 | .into(), |
155 | 1 | "default" => quote! { |
156 | 0 | #[automatically_derived] |
157 | 0 | impl #impl_generics ::core::default::Default for #name_attribute #ty_generics #where_clause { |
158 | 0 | #[track_caller] |
159 | 0 | fn default() -> Self { |
160 | 0 | Self { |
161 | 0 | inner: #ident ::default(), |
162 | 0 | _err_tree_pkg: ::bare_err_tree::ErrTreePkg::default(), |
163 | 0 | } |
164 | 0 | } |
165 | 0 | } |
166 | 0 | } |
167 | 0 | .into(), |
168 | 1 | _ => quote! {}.into(), |
169 | 1 | }); |
170 | 1 | |
171 | 1 | TokenStream::from_iter(iter::once(universal).chain(extra_derive_tokens)) |
172 | 1 | } |