deluxe_core/
util.rs

1use proc_macro2::{Span, TokenStream};
2use quote::TokenStreamExt;
3use std::{
4    borrow::Borrow,
5    cell::RefCell,
6    fmt::Display,
7    hash::Hash,
8    ops::{Deref, DerefMut},
9};
10use syn::parse::{ParseBuffer, ParseStream};
11
12use crate::{parse_helpers::inputs_span, parse_meta::*};
13
14/// The error type for parsers.
15pub type Error = syn::Error;
16/// The result of a parse method.
17pub type Result<T> = syn::Result<T>;
18
19/// A wrapper for a list of errors. Can be empty.
20#[derive(Clone, Debug, Default)]
21#[repr(transparent)]
22pub struct Errors {
23    // RefCell here so this can be re-entrant when used from parser combinators
24    errors: RefCell<Option<Error>>,
25}
26
27impl Errors {
28    #[inline]
29    /// Creates a new empty error list.
30    pub const fn new() -> Self {
31        Self {
32            errors: RefCell::new(None),
33        }
34    }
35    /// Checks if the list contains any errors.
36    #[inline]
37    pub fn is_empty(&self) -> bool {
38        self.errors.borrow().is_none()
39    }
40    /// Reset the list to an empty state.
41    #[inline]
42    pub fn clear(&self) {
43        self.errors.take();
44    }
45    /// Pushes one error onto the list. This function is a wrapper around [`syn::Error::new`].
46    #[inline]
47    pub fn push<T: Display>(&self, span: Span, message: T) {
48        self.push_syn(Error::new(span, message));
49    }
50    /// Pushes one error onto the list, setting the error's span to
51    /// [`Span::call_site()`](proc_macro2::Span::call_site).
52    #[inline]
53    pub fn push_call_site<T: Display>(&self, message: T) {
54        self.push(Span::call_site(), message);
55    }
56    /// Pushes one error onto the list spanning the given syntax tree node. This
57    /// function is a wrapper around [`syn::Error::new_spanned`].
58    #[inline]
59    pub fn push_spanned<T, U>(&self, tokens: T, message: U)
60    where
61        T: quote::ToTokens,
62        U: Display,
63    {
64        self.push_syn(Error::new_spanned(tokens, message));
65    }
66    /// Pushes one previously constructed [`Error`] onto the list.
67    #[inline]
68    pub fn push_syn(&self, error: Error) {
69        let mut storage = self.errors.borrow_mut();
70        if let Some(storage) = storage.as_mut() {
71            storage.combine(error);
72        } else {
73            storage.replace(error);
74        }
75    }
76    /// Pushes an error onto the list from a [`Result`].
77    ///
78    /// If `result` is [`Err`], pushes the error and returns [`None`]. If `result` is [`Ok`],
79    /// returns <code>[Some]\(T)</code>.
80    #[inline]
81    pub fn push_result<T>(&self, result: Result<T>) -> Option<T> {
82        match result {
83            Ok(t) => Some(t),
84            Err(e) => {
85                self.push_syn(e);
86                None
87            }
88        }
89    }
90    /// Appends all errors from `iter` into this list.
91    #[inline]
92    pub fn extend<T: IntoIterator<Item = Error>>(&self, iter: T) {
93        let mut errors = self.errors.borrow_mut();
94        if let Some(errors) = errors.as_mut() {
95            errors.extend(iter);
96        } else {
97            let mut iter = iter.into_iter();
98            if let Some(next) = iter.next() {
99                let errors = errors.insert(next);
100                errors.extend(iter);
101            }
102        }
103    }
104    /// Returns `Err` if the list has errors, or `Ok(value)` if the list is empty.
105    ///
106    /// If the list has any errors, returns [`Err`] containing one [`Error`] with all of the errors
107    /// combined using [`Error::combine`](syn::Error::combine).
108    #[inline]
109    pub fn into_result<T>(self, value: T) -> Result<T> {
110        if let Some(err) = self.errors.take() {
111            Err(err)
112        } else {
113            Ok(value)
114        }
115    }
116    /// Checks if the error list is empty.
117    ///
118    /// If the list has any errors, returns [`Err`] containing one [`Error`] with all of the errors
119    /// combined using [`Error::combine`](syn::Error::combine). Otherwise, returns [`Ok`].
120    #[inline]
121    pub fn check(self) -> Result<()> {
122        self.into_result(())
123    }
124    /// Returns the inner if the error list has errors.
125    ///
126    /// # Panics
127    ///
128    /// Panics if the error list is empty.
129    #[inline]
130    pub fn unwrap_err(self) -> Error {
131        if let Some(err) = self.errors.take() {
132            err
133        } else {
134            panic!("expected Errors to not be empty");
135        }
136    }
137    /// Returns a new `Err` if the error list has errors.
138    ///
139    /// # Panics
140    ///
141    /// Panics if the error list is empty.
142    #[inline]
143    pub fn bail<T>(self) -> Result<T> {
144        Err(self.unwrap_err())
145    }
146    /// Converts the error list into a token stream containing [`std::compile_error`] invocations.
147    ///
148    /// The errors are generated with [`Error::into_compile_error`](syn::Error::into_compile_error).
149    ///
150    /// Returns [`None`] if the list is empty.
151    #[inline]
152    pub fn into_compile_error(self) -> Option<TokenStream> {
153        self.errors.take().map(|e| e.into_compile_error())
154    }
155    /// Returns an iterator of token streams containing [`std::compile_error`] invocations.
156    ///
157    /// Each token stream will contain one invocation. The errors are generated with
158    /// [`Error::into_compile_error`](syn::Error::into_compile_error).
159    #[inline]
160    pub fn into_compile_errors(self) -> impl IntoIterator<Item = TokenStream> {
161        self.errors
162            .take()
163            .into_iter()
164            .map(|e| e.into_compile_error())
165    }
166    /// Creates a token stream containing the current set of errors and `item`.
167    pub fn output_with<Q: quote::ToTokens>(self, item: Q) -> TokenStream {
168        let mut tokens = item.into_token_stream();
169        quote::ToTokens::to_tokens(&self, &mut tokens);
170        tokens
171    }
172}
173
174impl quote::ToTokens for Errors {
175    #[inline]
176    fn to_tokens(&self, tokens: &mut TokenStream) {
177        tokens.extend(self.to_token_stream());
178    }
179    fn to_token_stream(&self) -> TokenStream {
180        self.errors
181            .borrow()
182            .as_ref()
183            .map(|e| e.to_compile_error())
184            .unwrap_or_default()
185    }
186    #[inline]
187    fn into_token_stream(self) -> TokenStream
188    where
189        Self: Sized,
190    {
191        self.into_compile_error().unwrap_or_default()
192    }
193}
194
195impl From<Error> for Errors {
196    #[inline]
197    fn from(err: Error) -> Self {
198        Self {
199            errors: RefCell::new(Some(err)),
200        }
201    }
202}
203
204impl FromIterator<Error> for Errors {
205    #[inline]
206    fn from_iter<T: IntoIterator<Item = Error>>(iter: T) -> Self {
207        let mut iter = iter.into_iter();
208        let errors = iter.next().map(|mut first| {
209            first.extend(iter);
210            first
211        });
212        Self {
213            errors: RefCell::new(errors),
214        }
215    }
216}
217
218impl IntoIterator for Errors {
219    type Item = Error;
220    type IntoIter = ErrorsIntoIter;
221    #[inline]
222    fn into_iter(self) -> Self::IntoIter {
223        ErrorsIntoIter {
224            errors: self.errors.take().map(|e| e.into_iter()),
225        }
226    }
227}
228
229/// An iterator containing all the errors in an [`Errors`].
230pub struct ErrorsIntoIter {
231    errors: Option<<Error as IntoIterator>::IntoIter>,
232}
233
234impl Iterator for ErrorsIntoIter {
235    type Item = Error;
236    fn next(&mut self) -> Option<Self::Item> {
237        self.errors.as_mut().and_then(|e| e.next())
238    }
239}
240
241/// A wrapper for adding a [`Span`](proc_macro2::Span) to an arbitrary value.
242///
243/// Implementations are provided for all the parsing traits that simply delegate to `T`, capturing
244/// the inital [`Span`](proc_macro2::Span) from the [`ParseStream`](syn::parse::ParseStream).
245#[derive(Copy, Clone, Debug)]
246pub struct SpannedValue<T> {
247    value: T,
248    span: Span,
249}
250
251impl<T> SpannedValue<T> {
252    /// Creates a new value wrapping a T, with the span set to
253    /// [`Span::call_site`](proc_macro2::Span::call_site).
254    #[inline]
255    pub fn new(value: T) -> Self {
256        Self::with_span(value, Span::call_site())
257    }
258    /// Creates a new value wrapping a T, with the span set to `span`.
259    #[inline]
260    pub fn with_span(value: T, span: Span) -> Self {
261        Self { value, span }
262    }
263    /// Unwraps a `SpannedValue` into a `T`. Note this is an associated function, not a method.
264    #[inline]
265    pub fn into_inner(value: SpannedValue<T>) -> T {
266        value.value
267    }
268}
269
270impl<T: Default> Default for SpannedValue<T> {
271    #[inline]
272    fn default() -> Self {
273        Self::new(T::default())
274    }
275}
276
277impl<T: Display> Display for SpannedValue<T> {
278    #[inline]
279    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
280        self.value.fmt(f)
281    }
282}
283
284impl<T: PartialEq> PartialEq for SpannedValue<T> {
285    #[inline]
286    fn eq(&self, other: &Self) -> bool {
287        self.value == other.value
288    }
289}
290
291impl<T: Eq> Eq for SpannedValue<T> {}
292
293impl<T: PartialOrd> PartialOrd for SpannedValue<T> {
294    #[inline]
295    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
296        self.value.partial_cmp(&other.value)
297    }
298}
299
300impl<T: Ord> Ord for SpannedValue<T> {
301    #[inline]
302    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
303        self.value.cmp(&other.value)
304    }
305}
306
307impl<T: Hash> Hash for SpannedValue<T> {
308    #[inline]
309    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
310        self.value.hash(state);
311    }
312}
313
314impl<T> quote::ToTokens for SpannedValue<T> {
315    #[inline]
316    fn to_tokens(&self, tokens: &mut TokenStream) {
317        let mut group = proc_macro2::Group::new(proc_macro2::Delimiter::None, Default::default());
318        group.set_span(self.span);
319        tokens.append(group);
320    }
321}
322
323impl<T: ParseMetaItem> ParseMetaItem for SpannedValue<T> {
324    #[inline]
325    fn parse_meta_item(input: ParseStream, mode: crate::ParseMode) -> Result<Self> {
326        let span = input.span();
327        let value = T::parse_meta_item(input, mode)?;
328        let span = input.span().join(span).unwrap_or(span);
329        Ok(Self { value, span })
330    }
331    #[inline]
332    fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
333        inputs: &[S],
334        mode: ParseMode,
335    ) -> Result<Self> {
336        let span = inputs.first().map(|p| p.borrow().span());
337        let value = T::parse_meta_item_inline(inputs, mode)?;
338        let span = span
339            .and_then(|s| inputs.last().and_then(|p| p.borrow().span().join(s)))
340            .unwrap_or_else(Span::call_site);
341        Ok(Self { value, span })
342    }
343    #[inline]
344    fn parse_meta_item_flag(span: Span) -> Result<Self> {
345        Ok(Self {
346            value: T::parse_meta_item_flag(span)?,
347            span,
348        })
349    }
350    #[inline]
351    fn parse_meta_item_named(input: ParseStream, name: &str, span: Span) -> Result<Self> {
352        let value = T::parse_meta_item_named(input, name, span)?;
353        let span = input.span().join(span).unwrap_or(span);
354        Ok(Self { value, span })
355    }
356}
357
358impl<T: ParseMetaFlatUnnamed> ParseMetaFlatUnnamed for SpannedValue<T> {
359    #[inline]
360    fn field_count() -> Option<usize> {
361        T::field_count()
362    }
363    fn parse_meta_flat_unnamed<'s, S: Borrow<ParseBuffer<'s>>>(
364        inputs: &[S],
365        mode: ParseMode,
366        index: usize,
367    ) -> Result<Self> {
368        let mut span = crate::parse_helpers::inputs_span(inputs);
369        let value = T::parse_meta_flat_unnamed(inputs, mode, index)?;
370        if let Some(closed) = span.join(inputs_span(inputs)) {
371            span = closed;
372        }
373        Ok(Self { value, span })
374    }
375}
376
377impl<T: ParseMetaFlatNamed> ParseMetaFlatNamed for SpannedValue<T> {
378    const ACCEPTS_ALL: bool = T::ACCEPTS_ALL;
379    #[inline]
380    fn field_names() -> &'static [&'static str] {
381        T::field_names()
382    }
383    fn parse_meta_flat_named<'s, S: Borrow<ParseBuffer<'s>>>(
384        inputs: &[S],
385        mode: ParseMode,
386        prefix: &str,
387        validate: bool,
388    ) -> Result<Self> {
389        let mut span = crate::parse_helpers::inputs_span(inputs);
390        let value = T::parse_meta_flat_named(inputs, mode, prefix, validate)?;
391        if let Some(closed) = span.join(inputs_span(inputs)) {
392            span = closed;
393        }
394        Ok(Self { value, span })
395    }
396}
397
398impl<T: ParseMetaAppend> ParseMetaAppend for SpannedValue<T> {
399    fn parse_meta_append<'s, S, I, P>(inputs: &[S], paths: I) -> Result<Self>
400    where
401        S: Borrow<ParseBuffer<'s>>,
402        I: IntoIterator<Item = P>,
403        I::IntoIter: Clone,
404        P: AsRef<str>,
405    {
406        let mut span = inputs_span(inputs);
407        let value = T::parse_meta_append(inputs, paths)?;
408        if let Some(closed) = span.join(inputs_span(inputs)) {
409            span = closed;
410        }
411        Ok(Self { value, span })
412    }
413}
414
415impl<T: ParseMetaRest> ParseMetaRest for SpannedValue<T> {
416    fn parse_meta_rest<'s, S: Borrow<ParseBuffer<'s>>>(
417        inputs: &[S],
418        exclude: &[&str],
419    ) -> Result<Self> {
420        let mut span = inputs_span(inputs);
421        let value = T::parse_meta_rest(inputs, exclude)?;
422        if let Some(closed) = span.join(inputs_span(inputs)) {
423            span = closed;
424        }
425        Ok(Self { value, span })
426    }
427}
428
429impl<T> From<T> for SpannedValue<T> {
430    #[inline]
431    fn from(value: T) -> Self {
432        Self {
433            value,
434            span: Span::call_site(),
435        }
436    }
437}
438
439impl<T> Deref for SpannedValue<T> {
440    type Target = T;
441    #[inline]
442    fn deref(&self) -> &Self::Target {
443        &self.value
444    }
445}
446
447impl<T> DerefMut for SpannedValue<T> {
448    #[inline]
449    fn deref_mut(&mut self) -> &mut Self::Target {
450        &mut self.value
451    }
452}
453
454/// A value for a boolean named field that can only be a name (set) or omitted (unset).
455///
456/// Similar to an <code>[Option]&lt;[SpannedValue]&lt;[bool]>></code> but does not allow `=` or
457/// `()` after the field name. Thus, it is only useful with named fields. Parsing this out of a
458/// tuple struct or tuple variant will always result in a parse error.
459///
460/// It is not necessary to use [`#[deluxe(default)]`](ParseMetaItem#deluxedefault-1) on a field
461/// using this type. The field will automatically be created with a `false` value if the name is
462/// omitted.
463#[derive(Copy, Clone, Debug, Default)]
464pub struct Flag(Option<Span>);
465
466impl Flag {
467    /// Creates a new `true` flag value spanned to `span`.
468    #[inline]
469    pub fn set(span: Span) -> Self {
470        Self(Some(span))
471    }
472    /// Creates a new `true` flag value spanned to [`Span::call_site`].
473    #[inline]
474    pub fn set_call_site() -> Self {
475        Self(Some(Span::call_site()))
476    }
477    /// Creates a new `false` flag value.
478    #[inline]
479    pub fn unset() -> Self {
480        Self(None)
481    }
482    /// Returns `true` if the flag was set.
483    #[inline]
484    pub fn is_set(&self) -> bool {
485        self.0.is_some()
486    }
487}
488
489impl From<bool> for Flag {
490    #[inline]
491    fn from(value: bool) -> Self {
492        Self(value.then(Span::call_site))
493    }
494}
495
496impl From<Flag> for bool {
497    #[inline]
498    fn from(value: Flag) -> Self {
499        value.is_set()
500    }
501}
502
503impl Eq for Flag {}
504
505impl PartialEq for Flag {
506    #[inline]
507    fn eq(&self, other: &Self) -> bool {
508        self.is_set() == other.is_set()
509    }
510}
511
512impl PartialEq<bool> for Flag {
513    #[inline]
514    fn eq(&self, other: &bool) -> bool {
515        self.is_set() == *other
516    }
517}
518
519impl PartialEq<Flag> for bool {
520    #[inline]
521    fn eq(&self, other: &Flag) -> bool {
522        *self == other.is_set()
523    }
524}
525
526impl quote::ToTokens for Flag {
527    #[inline]
528    fn to_tokens(&self, tokens: &mut TokenStream) {
529        tokens.append(proc_macro2::Ident::new(
530            self.0.map(|_| "true").unwrap_or("false"),
531            self.0.unwrap_or_else(Span::call_site),
532        ));
533    }
534}
535
536impl ParseMetaItem for Flag {
537    #[inline]
538    fn parse_meta_item(input: ParseStream, mode: ParseMode) -> Result<Self> {
539        Self::parse_meta_item_inline(&[input], mode)
540    }
541    #[inline]
542    fn parse_meta_item_inline<'s, S: Borrow<ParseBuffer<'s>>>(
543        inputs: &[S],
544        _mode: ParseMode,
545    ) -> Result<Self> {
546        Err(Error::new(
547            crate::parse_helpers::inputs_span(inputs),
548            "field with type `Flag` can only be a named field with no value",
549        ))
550    }
551    #[inline]
552    fn parse_meta_item_flag(span: Span) -> Result<Self> {
553        Ok(Self(Some(span)))
554    }
555    #[inline]
556    fn parse_meta_item_named(input: ParseStream, _name: &str, span: Span) -> Result<Self> {
557        if input.is_empty() || input.peek(syn::Token![,]) {
558            Self::parse_meta_item_flag(span)
559        } else {
560            Err(Error::new(input.span(), "unexpected token"))
561        }
562    }
563    #[inline]
564    fn missing_meta_item(_name: &str, _span: Span) -> Result<Self> {
565        Ok(Self::unset())
566    }
567}