multiconst_proc_macros 0.2.0

implementation detail of multiconst
Documentation
//! Syntax-related types and functions, no extension traits.

use used_proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};

use crate::{
    parsing::ParseStream,
    utils::{IsIdent, TokenStreamExt, TokenTreeExt, WithSpan},
    Error,
};

///////////////////////////////////////////////////////////////////////////////

pub(crate) fn tokenize_comma(span: Span, ts: &mut TokenStream) {
    ts.append_one(Punct::new(',', Spacing::Alone).with_span(span));
}

pub(crate) fn tokenize_iter_delim<I, F>(
    delimiter: Delimiter,
    delim_span: Span,
    iter: I,
    ts: &mut TokenStream,
    mut closure: F,
) where
    I: IntoIterator,
    F: FnMut(&mut TokenStream, I::Item),
{
    let mut inner_ts = TokenStream::new();
    for x in iter {
        closure(&mut inner_ts, x);
    }
    let mut group = Group::new(delimiter, inner_ts);
    group.set_span(delim_span);
    ts.append_one(group)
}

pub(crate) fn tokenize_delim<F>(
    delimiter: Delimiter,
    delim_span: Span,
    ts: &mut TokenStream,
    closure: F,
) where
    F: FnOnce(&mut TokenStream),
{
    let mut inner_ts = TokenStream::new();
    closure(&mut inner_ts);
    let mut group = Group::new(delimiter, inner_ts);
    group.set_span(delim_span);
    ts.append_one(group)
}

///////////////////////////////////////////////////////////////////////////////

#[derive(Debug, Copy, Clone)]
pub(crate) struct Spans {
    pub(crate) start: Span,
    pub(crate) end: Span,
}

impl Spans {
    pub(crate) fn from_one(span: Span) -> Self {
        Self {
            start: span,
            end: span,
        }
    }
}

///////////////////////////////////////////////////////////////////////////////

pub(crate) fn tokenize_seq_length_assoc_const(
    crate_kw: &Crate,
    spans: Spans,
    type_: TokenStream,
) -> TokenStream {
    let mut ts = TokenStream::new();

    ts.append_one(Punct::new('<', Spacing::Joint).with_span(spans.start));
    ts.append_one(Group::new(Delimiter::Parenthesis, type_).with_span(spans.start));
    ts.append_one(Ident::new("as", spans.start));
    crate_kw.item_to_ts("SeqLength", spans, &mut ts);
    ts.append_one(Punct::new('>', Spacing::Alone).with_span(spans.end));
    ts.append_one(Punct::new(':', Spacing::Joint).with_span(spans.end));
    ts.append_one(Punct::new(':', Spacing::Alone).with_span(spans.end));
    ts.append_one(Ident::new("LENGTH", spans.end));

    ts
}

///////////////////////////////////////////////////////////////////////////////

pub(crate) struct Crate {
    pub(crate) ident: Ident,
}

impl Crate {
    /// outputs the path to the item at `multiconst::__::{item}`
    pub(crate) fn item_to_ts(&self, item: &str, spans: Spans, ts: &mut TokenStream) {
        ts.append_array([
            TokenTree::Ident(self.ident.clone().with_span(spans.start)),
            Punct::new(':', Spacing::Joint)
                .with_span(spans.start)
                .into(),
            Punct::new(':', Spacing::Alone)
                .with_span(spans.start)
                .into(),
            Ident::new("__", spans.start).into(),
            Punct::new(':', Spacing::Joint)
                .with_span(spans.start)
                .into(),
            Punct::new(':', Spacing::Alone)
                .with_span(spans.start)
                .into(),
            Ident::new(item, spans.end).into(),
        ]);
    }

    pub(crate) fn parse(input: ParseStream<'_>) -> Result<Self, Error> {
        match input.parse_ident() {
            Ok(ident) if ident.which_ident_in(&["$crate", "crate"]).is_some() => {
                Ok(Crate { ident })
            }
            Ok(x) => Err(Error::new(
                Spans::from_one(x.span()),
                "Expected `$crate` or `crate`",
            )),
            Err(e) => Err(e),
        }
    }
}

///////////////////////////////////////////////////////////////////////////////

#[cfg_attr(feature = "__dbg", derive(Debug))]
#[derive(Clone)]
pub(crate) struct OpaqueType {
    pub(crate) spans: Spans,
    pub(crate) ty: TokenStream,
}

///////////////////////////////////////////////////////////////////////////////

/// Loosely parsed `#[...]`-style attributes
#[cfg_attr(feature = "__dbg", derive(Debug))]
#[derive(Clone)]
pub(crate) struct Attributes {
    pub(crate) attrs: TokenStream,
    pub(crate) spans: Spans,
}

impl Attributes {
    pub(crate) fn new() -> Self {
        Self {
            attrs: TokenStream::new(),
            spans: Spans::from_one(Span::call_site()),
        }
    }

    pub(crate) fn take(&mut self) -> Self {
        let attrs = core::mem::replace(&mut self.attrs, TokenStream::new());
        Self {
            attrs,
            spans: self.spans,
        }
    }

    pub(crate) fn ensure_used(&self) -> Result<(), Error> {
        if self.attrs.is_empty() {
            Ok(())
        } else {
            Err(Error::new(self.spans, "these attributes are unused"))
        }
    }

    /// Appens an attribute that comes after `self` into `self`.
    pub(crate) fn append(&mut self, other: Attributes) {
        if self.attrs.is_empty() {
            *self = other;
        } else {
            self.attrs.extend(other.attrs);
            self.spans.end = other.spans.end;
        }
    }

    pub(crate) fn parse(input: ParseStream<'_>) -> Self {
        let mut ts = TokenStream::new();

        let start = input.span();

        while matches!(
            input.peekn(2),
            [tt0, tt1]
            if tt0.is_punct('#') && tt1.is_group(Delimiter::Bracket)
        ) {
            ts.extend(input.next());
            ts.extend(input.next());
        }

        let end = input.last_span();

        Self {
            attrs: ts,
            spans: Spans { start, end },
        }
    }
}