logos_codegen/
util.rs

1use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
2use quote::{quote, ToTokens};
3use syn::Ident;
4
5/// Analog to Option<TokenStream>, except when put into the quote!
6/// macro, `MaybeVoid::Void` will produce `()`
7#[derive(Clone, Default)]
8pub enum MaybeVoid {
9    Some(TokenStream),
10    #[default]
11    Void,
12}
13
14impl MaybeVoid {
15    pub fn replace(&mut self, stream: TokenStream) -> MaybeVoid {
16        std::mem::replace(self, MaybeVoid::Some(stream))
17    }
18
19    pub fn take(&mut self) -> MaybeVoid {
20        std::mem::replace(self, MaybeVoid::Void)
21    }
22}
23
24impl ToTokens for MaybeVoid {
25    fn to_tokens(&self, out: &mut TokenStream) {
26        match self {
27            MaybeVoid::Some(stream) => out.extend(stream.clone()),
28            MaybeVoid::Void => out.extend(quote!(())),
29        }
30    }
31
32    fn to_token_stream(&self) -> TokenStream {
33        match self {
34            MaybeVoid::Some(stream) => stream.clone(),
35            MaybeVoid::Void => quote!(()),
36        }
37    }
38
39    fn into_token_stream(self) -> TokenStream {
40        match self {
41            MaybeVoid::Some(stream) => stream,
42            MaybeVoid::Void => quote!(()),
43        }
44    }
45}
46
47pub fn is_punct(tt: &TokenTree, expect: char) -> bool {
48    matches!(tt, TokenTree::Punct(punct) if punct.as_char() == expect && punct.spacing() == Spacing::Alone)
49}
50
51/// If supplied `tt` is a punct matching a char, returns `None`, else returns `tt`
52pub fn expect_punct(tt: Option<TokenTree>, expect: char) -> Option<TokenTree> {
53    tt.filter(|tt| !is_punct(tt, expect))
54}
55
56pub trait ToIdent {
57    fn to_ident(&self) -> Ident;
58}
59
60impl ToIdent for str {
61    fn to_ident(&self) -> Ident {
62        Ident::new(self, Span::call_site())
63    }
64}