sark-gen 0.29.1

Sark proc-macro generators
Documentation
use syn::{ext::IdentExt as _, parse, parse::discouraged::Speculative as _, token::Paren};

pub(crate) fn local(name: &str) -> syn::Ident {
    syn::Ident::new(name, proc_macro2::Span::mixed_site())
}

pub(crate) struct Taken<'a> {
    next: parse::ParseBuffer<'a>,
    span: proc_macro2::Span,
}

pub(crate) enum Word {
    Async,
    Guard,
    Request,
    Scope,
    Stream,
}

impl Word {
    pub(crate) fn try_take<'a>(
        self,
        input: parse::ParseStream<'a>,
    ) -> syn::Result<Option<Taken<'a>>> {
        let expected = self.as_str();
        if !input.peek(syn::Ident::peek_any) {
            return Ok(None);
        }
        let next = input.fork();
        let ident = next.call(syn::Ident::parse_any)?;
        if ident != expected {
            return Ok(None);
        }
        Ok(Some(Taken {
            next,
            span: ident.span(),
        }))
    }

    pub(crate) fn try_call<'a>(
        self,
        input: parse::ParseStream<'a>,
    ) -> syn::Result<Option<Taken<'a>>> {
        Ok(self.try_take(input)?.and_then(Taken::into_call))
    }

    const fn as_str(&self) -> &str {
        match self {
            Self::Async => "async",
            Self::Guard => "guard",
            Self::Request => "request",
            Self::Scope => "scope",
            Self::Stream => "stream",
        }
    }
}

impl<'a> Taken<'a> {
    pub(crate) fn parse_with<T>(
        self,
        input: parse::ParseStream<'a>,
        parser: impl for<'b> FnOnce(parse::ParseStream<'b>) -> syn::Result<T>,
    ) -> syn::Result<T> {
        let value = parser(&self.next)?;
        input.advance_to(&self.next);
        Ok(value)
    }

    pub(crate) fn error(self, message: &str) -> syn::Error {
        syn::Error::new(self.span, message)
    }

    fn into_call(self) -> Option<Self> {
        if self.next.peek(Paren) {
            Some(self)
        } else {
            None
        }
    }
}