use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote};
use std::cell::Cell;
use syn::Ident;
#[derive(Clone, Debug)]
pub(crate) struct TyArray(pub(crate) Vec<Ty>);
#[derive(Clone, Debug)]
pub(crate) struct TyTuple(pub(crate) Vec<Ty>);
#[derive(Clone, Debug)]
pub(crate) struct TyGroup(pub(crate) Box<Ty>);
#[derive(Clone, Debug)]
pub(crate) struct TyPrimitiveArray(
pub(crate) Option<Box<Ty>>,
pub(crate) Option<TokenStream>,
);
#[derive(Clone, Debug)]
pub(crate) struct TyPrimitive(pub(crate) TokenStream);
#[derive(Clone, Debug)]
pub(crate) struct TyGeneric(pub(crate) Box<Ty>, pub(crate) TyTypeParam);
#[derive(Clone, Debug)]
pub(crate) struct TyTrait(pub(crate) TokenStream, pub(crate) TyTypeParam);
#[derive(Clone, Debug)]
pub(crate) struct TyTypeParam {
pub(crate) params: Vec<(TokenStream, Option<Ty>)>,
pub(crate) bindings: Vec<(TokenStream, TokenStream)>,
}
impl TyTypeParam {
pub(crate) fn single(arg: &Ty) -> Self {
TyTypeParam {
params: vec![(arg.to_token_stream(), None)],
bindings: vec![],
}
}
pub(crate) fn push_arg(&mut self, arg: &Ty) {
self.params.push((arg.to_token_stream(), None));
}
pub(crate) fn extend(&mut self, other: TyTypeParam) {
self.params.extend(other.params);
self.bindings.extend(other.bindings);
}
}
#[derive(Clone, Debug)]
pub(crate) struct TyCodeBlock(pub(crate) TokenStream);
#[derive(Clone, Debug)]
pub(crate) struct TyWithCode(pub(crate) Option<Box<Ty>>, pub(crate) TyCodeBlock);
#[derive(Copy, Clone, Debug)]
pub(crate) enum TyPrefix {
Ref,
RefMut,
PtrConst,
PtrMut,
SelfType,
Unsafe,
}
#[derive(Clone, Debug)]
pub(crate) struct TyWithPrefix(pub(crate) TyPrefix, pub(crate) Option<Box<Ty>>);
#[derive(Clone, Debug)]
pub(crate) struct TyFn(
pub(crate) Option<Vec<Ty>>,
pub(crate) Option<Box<Ty>>,
pub(crate) bool,
);
#[derive(Clone, Debug)]
pub(crate) struct TyAttr(pub(crate) TokenStream);
#[derive(Clone, Debug)]
pub(crate) struct TyWithAttr(pub(crate) TyAttr, pub(crate) Option<Box<Ty>>);
#[derive(Copy, Clone, Debug)]
pub(crate) struct TyNum(pub(crate) usize);
#[derive(Copy, Clone, Debug)]
pub(crate) struct TyRange {
pub(crate) start: usize,
pub(crate) end: usize,
pub(crate) inclusive: bool,
}
#[derive(Clone, Debug)]
pub(crate) struct TyWithTrait(pub(crate) TyTrait, pub(crate) Box<Ty>);
#[derive(Clone, Debug)]
pub(crate) struct TyWithType(pub(crate) TyTypeParam, pub(crate) Box<Ty>);
#[derive(Clone, Debug)]
pub(crate) struct TyError(pub(crate) TokenStream);
#[derive(Clone, Debug)]
pub(crate) struct TyWhere(pub(crate) TokenStream);
#[derive(Clone, Debug)]
pub(crate) struct TyWithWhere(pub(crate) Option<Box<Ty>>, pub(crate) TyWhere);
#[derive(Clone, Debug)]
pub(crate) struct Ty {
pub(crate) span: Span,
pub(crate) kind: TyKind,
}
impl Ty {
pub(crate) fn new(span: Span, kind: TyKind) -> Self {
Ty { span, kind }
}
pub(crate) fn with_span(mut self, span: Span) -> Self {
self.span = span;
self
}
}
#[derive(Clone, Debug)]
pub(crate) enum TyKind {
Array(TyArray),
Tuple(TyTuple),
Group(TyGroup),
PrimitiveArray(TyPrimitiveArray),
Primitive(TyPrimitive),
Generic(TyGeneric),
Trait(TyTrait),
TypeParam(TyTypeParam),
Fn(TyFn),
WithPrefix(TyWithPrefix),
WithAttr(TyWithAttr),
WithTrait(TyWithTrait),
WithType(TyWithType),
WithCode(TyWithCode),
WithWhere(TyWithWhere),
Num(TyNum),
Range(TyRange),
Error(TyError),
}
#[derive(Copy, Clone)]
pub(crate) enum Op {
Semi,
Comma,
Dash,
Caret,
Prim,
}
impl Op {
pub(crate) fn next(self) -> Option<Op> {
match self {
Op::Semi => Some(Op::Comma),
Op::Comma => Some(Op::Dash),
Op::Dash => Some(Op::Caret),
Op::Caret => Some(Op::Prim),
Op::Prim => None,
}
}
pub(crate) fn stop_chars(self) -> &'static [char] {
match self {
Op::Semi => &[',', ';'],
Op::Comma => &[','],
Op::Dash => &['-', ','],
Op::Caret => &['^', '-', ','],
Op::Prim => &[],
}
}
}
pub(crate) const MAX_EXPAND: usize = 1024;
pub(crate) fn count_leaves(ty: &Ty) -> usize {
match &ty.kind {
TyKind::Array(a) => a.0.iter().map(count_leaves).sum(),
_ => 1,
}
}
thread_local! {
static GROUP_COUNTER: Cell<usize> = 0.into();
}
pub(crate) fn reset_fresh_counter() {
GROUP_COUNTER.set(0);
}
pub(crate) fn take_group() -> usize {
GROUP_COUNTER.with(|c| {
let g = c.get();
c.set(g + 1);
g
})
}
pub(crate) fn fresh_param(g: usize, i: usize) -> TokenStream {
let name = format!("_Param_{}_{}_BatchGen_", g, i);
let ident = Ident::new(&name, proc_macro2::Span::call_site());
quote!(#ident)
}