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
12////////////////////////////////////////////////////////////////////////////////
13
14pub 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////////////////////////////////////////////////////////////////////////////////
34
35#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
36pub struct NoTokens;
37
38impl ToTokens for NoTokens {
39    fn to_tokens(&self, _: &mut TokenStream2) {}
40}
41
42////////////////////////////////////////////////////////////////////////////////
43
44pub 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////////////////////////////////////////////////////////////////////////////////
70
71/// A result wrapper which panics if it's the error variant is not handled,
72/// by calling `.into_result()`.
73#[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
175////////////////////////////////////////////////////////////////////////////////
176
177/// Takes the contents out of a `ManuallyDrop<T>`.
178///
179/// # Safety
180///
181/// After this function is called `slot` will become uninitialized and
182/// must not be read again.
183pub unsafe fn take_manuallydrop<T>(slot: &mut ManuallyDrop<T>) -> T {
184    ManuallyDrop::into_inner(ptr::read(slot))
185}
186
187////////////////////////////////////////////////////////////////////////////////
188
189pub 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
198////////////////////////////////////////////////////////////////////////////////
199
200pub 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////////////////////////////////////////////////////////////////////////////////
216
217#[inline(never)]
218pub fn dummy_ident() -> syn::Ident {
219    syn::Ident::new("DUMMY_IDENT", Span::call_site())
220}
221
222////////////////////////////////////////////////////////////////////////////////
223
224pub 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
240/// Used to tokenize an integer without a type suffix.
241pub 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
252/// Used to tokenize an integer without a type suffix.
253/// This one should be cheaper than `expr_from_int`.
254pub fn uint_lit(int: u64) -> syn::LitInt {
255    let x = proc_macro2::Literal::u64_unsuffixed(int);
256    syn::LitInt::from(x)
257}