use quote::quote;
use crate::apply_tuple::map_range;
use crate::types::*;
pub(crate) fn err_ty(msg: &str) -> Ty {
TyError(quote! { compile_error!(#msg); }).into()
}
pub(crate) fn check_expand_limit(what: &str, len: usize) -> Option<Ty> {
(len > MAX_EXPAND).then(|| {
err_ty(&format!(
"batch-impl: `{}` 的展开产物数量 {} 超过上限 {},可能是指数/范围/笛卡尔积误写",
what, len, MAX_EXPAND
))
})
}
pub(crate) trait Apply:
Clone + Into<Ty> + Into<Box<Ty>> + Into<Option<Box<Ty>>>
{
fn apply(self, o: Ty) -> Ty {
match o {
Ty::Array(arr) => {
let result: Vec<Ty> =
arr.0.into_iter().map(|e| self.clone().apply(e)).collect();
if let Some(e) = check_expand_limit(
"并列列表链式展开",
result.iter().map(count_leaves).sum(),
) {
return e;
}
TyArray(result).into()
}
Ty::Group(g) => self.apply(*g.0),
Ty::WithCode(wc) => match wc.0 {
Some(inner) => TyWithCode(self.apply(*inner).into(), wc.1).into(),
None => TyWithCode(self.into(), wc.1).into(),
},
Ty::WithWhere(ww) => match ww.0 {
Some(inner) => TyWithWhere(self.apply(*inner).into(), ww.1).into(),
None => TyWithWhere(self.into(), ww.1).into(),
},
Ty::WithType(wt) => TyWithType(wt.0, self.apply(*wt.1).into()).into(),
Ty::Error(e) => e.into(),
Ty::Range(TyRange { start, end, inclusive }) => {
map_range(start, end, inclusive, |n| {
self.clone().apply(TyNum(n).into())
})
}
_ => self.apply_help(o),
}
}
fn apply_help(self, o: Ty) -> Ty;
}
impl Apply for Ty {
fn apply_help(self, o: Ty) -> Ty {
match self {
Ty::WithPrefix(wp) => wp.apply_help(o),
Ty::Primitive(p) => p.apply_help(o),
Ty::Generic(g) => g.apply_help(o),
Ty::Trait(t) => t.apply_help(o),
Ty::Array(a) => a.apply_help(o),
Ty::Tuple(t) => t.apply_help(o),
Ty::Group(g) => g.apply_help(o),
Ty::Fn(f) => f.apply_help(o),
Ty::WithAttr(w) => w.apply_help(o),
Ty::WithTrait(wt) => wt.apply_help(o),
Ty::WithType(wt) => wt.apply_help(o),
Ty::WithCode(wc) => wc.apply_help(o),
Ty::WithWhere(ww) => ww.apply_help(o),
Ty::TypeParam(t) => t.apply_help(o),
Ty::Num(n) => n.apply_help(o),
Ty::Range(r) => r.apply_help(o),
Ty::PrimitiveArray(pa) => pa.apply_help(o),
Ty::Error(e) => e.into(),
}
}
}
impl Apply for TyWithPrefix {
fn apply_help(self, o: Ty) -> Ty {
match self.0 {
TyPrefix::Ref
| TyPrefix::RefMut
| TyPrefix::PtrConst
| TyPrefix::PtrMut
| TyPrefix::Unsafe => {
let inner = match self.1 {
Some(t) => t.apply(o),
None => o,
};
TyWithPrefix(self.0, inner.into()).into()
}
TyPrefix::SelfType => o,
}
}
}
impl Apply for TyPrimitive {
fn apply_help(self, o: Ty) -> Ty {
match o {
Ty::TypeParam(tp) => TyGeneric(self.into(), tp).into(),
_ => TyGeneric(self.into(), TyTypeParam::single(&o)).into(),
}
}
}
impl Apply for TyGeneric {
fn apply_help(self, o: Ty) -> Ty {
let mut tp = self.1;
match o {
Ty::TypeParam(rhs) => tp.extend(rhs),
_ => tp.push_arg(&o),
}
TyGeneric(self.0, tp).into()
}
}
impl Apply for TyTrait {
fn apply_help(self, o: Ty) -> Ty {
match o {
Ty::TypeParam(rhs) => {
let mut tp = self.1;
tp.extend(rhs);
TyTrait(self.0, tp).into()
}
_ => TyWithTrait(self, o.into()).into(),
}
}
}
impl Apply for TyArray {
fn apply_help(self, o: Ty) -> Ty {
let result = self.0.into_iter().map(|e| e.apply(o.clone())).collect();
TyArray(result).into()
}
}