as_derive_utils/
utils.rs
1use std::{
2 fmt::Display,
3 mem::{self, ManuallyDrop},
4 ops::{Deref, DerefMut},
5 ptr,
6};
7
8use proc_macro2::{Span, TokenStream as TokenStream2};
9use quote::ToTokens;
10use syn::spanned::Spanned;
11
12pub trait SynErrorExt: Sized {
15 fn into_syn_err(self) -> syn::Error;
16
17 fn prepend_msg<M>(self, msg: M) -> syn::Error
18 where
19 M: AsRef<str>,
20 {
21 let e = self.into_syn_err();
22 syn::Error::new(e.span(), format!("{}{}", msg.as_ref(), e))
23 }
24}
25
26impl SynErrorExt for syn::Error {
27 #[inline(always)]
28 fn into_syn_err(self) -> syn::Error {
29 self
30 }
31}
32
33#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
36pub struct NoTokens;
37
38impl ToTokens for NoTokens {
39 fn to_tokens(&self, _: &mut TokenStream2) {}
40}
41
42pub trait SynResultExt {
45 fn push_err(&mut self, err: syn::Error);
46 fn combine_err<T>(&mut self, res: Result<T, syn::Error>);
47 fn combine_into_err<T>(self, into: &mut Result<T, syn::Error>);
48}
49
50impl<T> SynResultExt for Result<T, syn::Error> {
51 fn push_err(&mut self, err: syn::Error) {
52 match self {
53 this @ Ok(_) => *this = Err(err),
54 Err(e) => e.combine(err),
55 }
56 }
57
58 fn combine_err<T2>(&mut self, res: Result<T2, syn::Error>) {
59 if let Err(err) = res {
60 self.push_err(err);
61 }
62 }
63
64 fn combine_into_err<T2>(self, into: &mut Result<T2, syn::Error>) {
65 into.combine_err(self);
66 }
67}
68
69#[derive(Debug, Clone)]
74pub struct LinearResult<T> {
75 errors: ManuallyDrop<Result<T, syn::Error>>,
76}
77
78impl<T> Drop for LinearResult<T> {
79 fn drop(&mut self) {
80 let res = unsafe { take_manuallydrop(&mut self.errors) };
81 res.expect("Expected LinearResult to be handled");
82 }
83}
84
85impl<T> LinearResult<T> {
86 #[inline]
87 pub fn new(res: Result<T, syn::Error>) -> Self {
88 Self {
89 errors: ManuallyDrop::new(res),
90 }
91 }
92
93 #[inline]
94 pub fn ok(value: T) -> Self {
95 Self::new(Ok(value))
96 }
97}
98
99impl<T> Default for LinearResult<T>
100where
101 T: Default,
102{
103 fn default() -> Self {
104 Self::new(Ok(T::default()))
105 }
106}
107
108impl<T> From<Result<T, syn::Error>> for LinearResult<T> {
109 #[inline]
110 fn from(res: Result<T, syn::Error>) -> Self {
111 Self::new(res)
112 }
113}
114
115impl<T> Deref for LinearResult<T> {
116 type Target = Result<T, syn::Error>;
117
118 fn deref(&self) -> &Result<T, syn::Error> {
119 &self.errors
120 }
121}
122
123impl<T> DerefMut for LinearResult<T> {
124 fn deref_mut(&mut self) -> &mut Result<T, syn::Error> {
125 &mut self.errors
126 }
127}
128
129impl<T> From<LinearResult<T>> for Result<T, syn::Error> {
130 #[inline]
131 fn from(this: LinearResult<T>) -> Result<T, syn::Error> {
132 this.into_result()
133 }
134}
135
136#[allow(dead_code)]
137impl<T> LinearResult<T> {
138 #[inline]
139 pub fn into_result(self) -> Result<T, syn::Error> {
140 let mut this = ManuallyDrop::new(self);
141 unsafe { take_manuallydrop(&mut this.errors) }
142 }
143
144 #[inline]
145 pub fn take(&mut self) -> Result<T, syn::Error>
146 where
147 T: Default,
148 {
149 self.replace(Ok(Default::default()))
150 }
151
152 #[inline]
153 pub fn replace(&mut self, other: Result<T, syn::Error>) -> Result<T, syn::Error> {
154 mem::replace(&mut *self.errors, other)
155 }
156}
157
158impl<T> SynResultExt for LinearResult<T> {
159 #[inline]
160 fn push_err(&mut self, err: syn::Error) {
161 self.errors.push_err(err);
162 }
163
164 #[inline]
165 fn combine_err<T2>(&mut self, res: Result<T2, syn::Error>) {
166 self.errors.combine_err(res);
167 }
168
169 #[inline]
170 fn combine_into_err<T2>(self, into: &mut Result<T2, syn::Error>) {
171 self.into_result().combine_into_err(into);
172 }
173}
174
175pub unsafe fn take_manuallydrop<T>(slot: &mut ManuallyDrop<T>) -> T {
184 ManuallyDrop::into_inner(ptr::read(slot))
185}
186
187pub fn spanned_err(tokens: &dyn ToTokens, display: &dyn Display) -> syn::Error {
190 syn::Error::new_spanned(tokens, display)
191}
192
193#[allow(dead_code)]
194pub fn syn_err(span: Span, display: &dyn Display) -> syn::Error {
195 syn::Error::new(span, display)
196}
197
198pub fn join_spans<I, T>(iter: I) -> Span
201where
202 I: IntoIterator<Item = T>,
203 T: Spanned,
204{
205 let call_site = Span::call_site();
206 let mut iter = iter.into_iter();
207 let first: Span = match iter.next() {
208 Some(x) => x.span(),
209 None => return call_site,
210 };
211
212 iter.fold(first, |l, r| l.join(r.span()).unwrap_or(call_site))
213}
214
215#[inline(never)]
218pub fn dummy_ident() -> syn::Ident {
219 syn::Ident::new("DUMMY_IDENT", Span::call_site())
220}
221
222pub fn type_from_ident(ident: syn::Ident) -> syn::Type {
225 let path: syn::Path = ident.into();
226 let path = syn::TypePath { qself: None, path };
227 path.into()
228}
229
230pub fn expr_from_ident(ident: syn::Ident) -> syn::Expr {
231 let x = syn::Path::from(ident);
232 let x = syn::ExprPath {
233 attrs: Vec::new(),
234 qself: None,
235 path: x,
236 };
237 syn::Expr::Path(x)
238}
239
240pub fn expr_from_int(int: u64) -> syn::Expr {
242 let x = proc_macro2::Literal::u64_unsuffixed(int);
243 let x = syn::LitInt::from(x);
244 let x = syn::Lit::Int(x);
245 let x = syn::ExprLit {
246 attrs: Vec::new(),
247 lit: x,
248 };
249 syn::Expr::Lit(x)
250}
251
252pub fn uint_lit(int: u64) -> syn::LitInt {
255 let x = proc_macro2::Literal::u64_unsuffixed(int);
256 syn::LitInt::from(x)
257}