1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
use syn::parse::{Parse, ParseBuffer, ParseStream};
use syn::{parenthesized, Token};
/// Syntax used for providing a value
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum ValueSyntax {
/// `= contents`
Eq,
/// `(contents)`
Paren,
}
impl ValueSyntax {
/// Returns `true` if the syntax is [`Eq`](ValueSyntax::Eq).
#[inline]
#[must_use]
pub const fn is_eq(self) -> bool {
matches!(self, Self::Eq)
}
/// Returns `true` if the syntax is [`Paren`](ValueSyntax::Paren).
#[inline]
#[must_use]
pub const fn is_paren(self) -> bool {
matches!(self, Self::Paren)
}
/// Peek the stream without moving the cursor and attempt to construct self based on the next
/// token
pub fn from_stream(parse: ParseStream) -> Option<Self> {
if parse.peek(Token![=]) {
Some(Self::Eq)
} else if parse.peek(syn::token::Paren) {
Some(Self::Paren)
} else {
None
}
}
/// Parse whatever tokens need to be parsed based on the resolved syntax.
/// Returns a `ParseBuffer` you should continue parsing if the syntax is
/// [`Paren`](ValueSyntax::Paren).
pub fn parse_token(self, input: ParseStream) -> syn::Result<Option<ParseBuffer>> {
match self {
Self::Eq => {
input.parse::<Token![=]>()?;
Ok(None)
}
Self::Paren => {
let content;
parenthesized!(content in input);
Ok(Some(content))
}
}
}
/// Parse whatever tokens need to be parsed based on the resolved syntax and
/// then parse the referenced value as `P`.
pub fn parse<P: Parse>(self, input: ParseStream) -> syn::Result<P> {
if let Some(inner) = self.parse_token(input)? {
inner.parse()
} else {
input.parse()
}
}
}