#![allow(clippy::type_complexity)]
use crate::{
BitsOrderFormat, BitsStoreFormat, Field, FieldIter, PathIter, Primitive, ResolvedTypeVisitor,
UnhandledKind, Variant, VariantIter,
};
use smallvec::SmallVec;
pub struct ConcreteFieldIter<'resolver, TypeId> {
fields: SmallVec<[Option<Field<'resolver, TypeId>>; 16]>,
idx: usize,
}
impl<'resolver, TypeId> Iterator for ConcreteFieldIter<'resolver, TypeId> {
type Item = Field<'resolver, TypeId>;
fn next(&mut self) -> Option<Self::Item> {
let field = self
.fields
.get_mut(self.idx)?
.take()
.expect("Expected a field but got None");
self.idx += 1;
Some(field)
}
}
impl<'resolver, TypeId> ExactSizeIterator for ConcreteFieldIter<'resolver, TypeId> {
fn len(&self) -> usize {
self.fields.len()
}
}
pub struct ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
> {
_marker: core::marker::PhantomData<(TypeId, Output, &'resolver ())>,
context: Context,
visit_unhandled: UnhandledFn,
visit_not_found: NotFoundFn,
visit_composite: CompositeFn,
visit_variant: VariantFn,
visit_sequence: SequenceFn,
visit_array: ArrayFn,
visit_tuple: TupleFn,
visit_primitive: PrimitiveFn,
visit_compact: CompactFn,
visit_bit_sequence: BitSequenceFn,
}
pub fn new<'resolver, Context, TypeId, Output, NewUnhandledFn>(
context: Context,
unhandled_fn: NewUnhandledFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
NewUnhandledFn,
impl FnOnce(Context) -> Output,
impl FnOnce(
Context,
&mut dyn PathIter<'resolver>,
&'_ mut dyn FieldIter<'resolver, TypeId>,
) -> Output,
impl FnOnce(
Context,
&mut dyn PathIter<'resolver>,
&'_ mut dyn VariantIter<'resolver, ConcreteFieldIter<'resolver, TypeId>>,
) -> Output,
impl FnOnce(Context, &mut dyn PathIter<'resolver>, TypeId) -> Output,
impl FnOnce(Context, TypeId, usize) -> Output,
impl FnOnce(Context, &'_ mut dyn ExactSizeIterator<Item = TypeId>) -> Output,
impl FnOnce(Context, Primitive) -> Output,
impl FnOnce(Context, TypeId) -> Output,
impl FnOnce(Context, BitsStoreFormat, BitsOrderFormat) -> Output,
>
where
NewUnhandledFn: FnOnce(Context, UnhandledKind) -> Output + Clone,
{
let visit_unhandled = unhandled_fn.clone();
let visit_not_found = {
let u = unhandled_fn.clone();
move |ctx| u(ctx, UnhandledKind::NotFound)
};
let visit_composite = {
let u = unhandled_fn.clone();
move |ctx, _: &mut dyn PathIter<'resolver>, _: &mut dyn FieldIter<'resolver, TypeId>| {
u(ctx, UnhandledKind::Composite)
}
};
let visit_variant = {
let u = unhandled_fn.clone();
move |ctx,
_: &mut dyn PathIter<'resolver>,
_: &mut dyn VariantIter<'resolver, ConcreteFieldIter<'resolver, TypeId>>| {
u(ctx, UnhandledKind::Variant)
}
};
let visit_sequence = {
let u = unhandled_fn.clone();
move |ctx, _: &mut dyn PathIter<'resolver>, _| u(ctx, UnhandledKind::Sequence)
};
let visit_array = {
let u = unhandled_fn.clone();
move |ctx, _, _| u(ctx, UnhandledKind::Array)
};
let visit_tuple = {
let u = unhandled_fn.clone();
move |ctx, _: &mut dyn ExactSizeIterator<Item = TypeId>| u(ctx, UnhandledKind::Tuple)
};
let visit_primitive = {
let u = unhandled_fn.clone();
move |ctx, _| u(ctx, UnhandledKind::Primitive)
};
let visit_compact = {
let u = unhandled_fn.clone();
move |ctx, _| u(ctx, UnhandledKind::Compact)
};
let visit_bit_sequence = {
let u = unhandled_fn.clone();
move |ctx, _, _| u(ctx, UnhandledKind::BitSequence)
};
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context,
visit_unhandled,
visit_not_found,
visit_composite,
visit_variant,
visit_sequence,
visit_array,
visit_tuple,
visit_primitive,
visit_compact,
visit_bit_sequence,
}
}
impl<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
{
pub fn visit_not_found<NewNotFoundFn>(
self,
new_not_found_fn: NewNotFoundFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NewNotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
where
NewNotFoundFn: FnOnce(Context) -> Output,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: new_not_found_fn,
visit_composite: self.visit_composite,
visit_variant: self.visit_variant,
visit_sequence: self.visit_sequence,
visit_array: self.visit_array,
visit_tuple: self.visit_tuple,
visit_primitive: self.visit_primitive,
visit_compact: self.visit_compact,
visit_bit_sequence: self.visit_bit_sequence,
}
}
pub fn visit_composite<NewCompositeFn>(
self,
new_composite_fn: NewCompositeFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
NewCompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
where
NewCompositeFn: FnOnce(
Context,
&mut dyn PathIter<'resolver>,
&mut dyn FieldIter<'resolver, TypeId>,
) -> Output,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: self.visit_not_found,
visit_composite: new_composite_fn,
visit_variant: self.visit_variant,
visit_sequence: self.visit_sequence,
visit_array: self.visit_array,
visit_tuple: self.visit_tuple,
visit_primitive: self.visit_primitive,
visit_compact: self.visit_compact,
visit_bit_sequence: self.visit_bit_sequence,
}
}
pub fn visit_variant<NewVariantFn>(
self,
new_variant_fn: NewVariantFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
NewVariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
where
NewVariantFn: FnOnce(
Context,
&mut dyn PathIter<'resolver>,
&mut dyn VariantIter<'resolver, ConcreteFieldIter<'resolver, TypeId>>,
) -> Output,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: self.visit_not_found,
visit_composite: self.visit_composite,
visit_variant: new_variant_fn,
visit_sequence: self.visit_sequence,
visit_array: self.visit_array,
visit_tuple: self.visit_tuple,
visit_primitive: self.visit_primitive,
visit_compact: self.visit_compact,
visit_bit_sequence: self.visit_bit_sequence,
}
}
pub fn visit_sequence<NewSequenceFn>(
self,
new_sequence_fn: NewSequenceFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
NewSequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
where
NewSequenceFn: FnOnce(Context, &mut dyn PathIter<'resolver>, TypeId) -> Output,
TypeId: 'resolver,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: self.visit_not_found,
visit_composite: self.visit_composite,
visit_variant: self.visit_variant,
visit_sequence: new_sequence_fn,
visit_array: self.visit_array,
visit_tuple: self.visit_tuple,
visit_primitive: self.visit_primitive,
visit_compact: self.visit_compact,
visit_bit_sequence: self.visit_bit_sequence,
}
}
pub fn visit_array<NewArrayFn>(
self,
new_array_fn: NewArrayFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
NewArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
where
NewArrayFn: FnOnce(Context, TypeId, usize) -> Output,
TypeId: 'resolver,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: self.visit_not_found,
visit_composite: self.visit_composite,
visit_variant: self.visit_variant,
visit_sequence: self.visit_sequence,
visit_array: new_array_fn,
visit_tuple: self.visit_tuple,
visit_primitive: self.visit_primitive,
visit_compact: self.visit_compact,
visit_bit_sequence: self.visit_bit_sequence,
}
}
pub fn visit_tuple<NewTupleFn>(
self,
new_tuple_fn: NewTupleFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
NewTupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
where
NewTupleFn: FnOnce(Context, &mut dyn ExactSizeIterator<Item = TypeId>) -> Output,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: self.visit_not_found,
visit_composite: self.visit_composite,
visit_variant: self.visit_variant,
visit_sequence: self.visit_sequence,
visit_array: self.visit_array,
visit_tuple: new_tuple_fn,
visit_primitive: self.visit_primitive,
visit_compact: self.visit_compact,
visit_bit_sequence: self.visit_bit_sequence,
}
}
pub fn visit_primitive<NewPrimitiveFn>(
self,
new_primitive_fn: NewPrimitiveFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
NewPrimitiveFn,
CompactFn,
BitSequenceFn,
>
where
NewPrimitiveFn: FnOnce(Context, Primitive) -> Output,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: self.visit_not_found,
visit_composite: self.visit_composite,
visit_variant: self.visit_variant,
visit_sequence: self.visit_sequence,
visit_array: self.visit_array,
visit_tuple: self.visit_tuple,
visit_primitive: new_primitive_fn,
visit_compact: self.visit_compact,
visit_bit_sequence: self.visit_bit_sequence,
}
}
pub fn visit_compact<NewCompactFn>(
self,
new_compact_fn: NewCompactFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
NewCompactFn,
BitSequenceFn,
>
where
NewCompactFn: FnOnce(Context, TypeId) -> Output,
TypeId: 'resolver,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: self.visit_not_found,
visit_composite: self.visit_composite,
visit_variant: self.visit_variant,
visit_sequence: self.visit_sequence,
visit_array: self.visit_array,
visit_tuple: self.visit_tuple,
visit_primitive: self.visit_primitive,
visit_compact: new_compact_fn,
visit_bit_sequence: self.visit_bit_sequence,
}
}
pub fn visit_bit_sequence<NewBitSequenceFn>(
self,
new_bit_sequence_fn: NewBitSequenceFn,
) -> ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
NewBitSequenceFn,
>
where
NewBitSequenceFn: FnOnce(Context, BitsStoreFormat, BitsOrderFormat) -> Output,
{
ConcreteResolvedTypeVisitor {
_marker: core::marker::PhantomData,
context: self.context,
visit_unhandled: self.visit_unhandled,
visit_not_found: self.visit_not_found,
visit_composite: self.visit_composite,
visit_variant: self.visit_variant,
visit_sequence: self.visit_sequence,
visit_array: self.visit_array,
visit_tuple: self.visit_tuple,
visit_primitive: self.visit_primitive,
visit_compact: self.visit_compact,
visit_bit_sequence: new_bit_sequence_fn,
}
}
}
impl<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
> ResolvedTypeVisitor<'resolver>
for ConcreteResolvedTypeVisitor<
'resolver,
Context,
TypeId,
Output,
UnhandledFn,
NotFoundFn,
CompositeFn,
VariantFn,
SequenceFn,
ArrayFn,
TupleFn,
PrimitiveFn,
CompactFn,
BitSequenceFn,
>
where
TypeId: Clone + Default + core::fmt::Debug + 'static,
UnhandledFn: FnOnce(Context, UnhandledKind) -> Output,
NotFoundFn: FnOnce(Context) -> Output,
CompositeFn: FnOnce(
Context,
&mut dyn PathIter<'resolver>,
&mut dyn FieldIter<'resolver, TypeId>,
) -> Output,
VariantFn: FnOnce(
Context,
&mut dyn PathIter<'resolver>,
&mut dyn VariantIter<'resolver, ConcreteFieldIter<'resolver, TypeId>>,
) -> Output,
SequenceFn: FnOnce(Context, &mut dyn PathIter<'resolver>, TypeId) -> Output,
ArrayFn: FnOnce(Context, TypeId, usize) -> Output,
TupleFn: FnOnce(Context, &mut dyn ExactSizeIterator<Item = TypeId>) -> Output,
PrimitiveFn: FnOnce(Context, Primitive) -> Output,
CompactFn: FnOnce(Context, TypeId) -> Output,
BitSequenceFn: FnOnce(Context, BitsStoreFormat, BitsOrderFormat) -> Output,
{
type TypeId = TypeId;
type Value = Output;
fn visit_unhandled(self, kind: UnhandledKind) -> Self::Value {
(self.visit_unhandled)(self.context, kind)
}
fn visit_not_found(self) -> Self::Value {
(self.visit_not_found)(self.context)
}
fn visit_composite<Path, Fields>(self, mut path: Path, mut fields: Fields) -> Self::Value
where
Path: PathIter<'resolver>,
Fields: FieldIter<'resolver, Self::TypeId>,
{
(self.visit_composite)(
self.context,
&mut path,
&mut fields as &mut dyn FieldIter<'resolver, Self::TypeId>,
)
}
fn visit_variant<Path, Fields, Var>(self, mut path: Path, variants: Var) -> Self::Value
where
Path: PathIter<'resolver>,
Fields: FieldIter<'resolver, Self::TypeId>,
Var: VariantIter<'resolver, Fields>,
{
let mut var_iter = variants.map(|v| Variant {
index: v.index,
name: v.name,
fields: ConcreteFieldIter {
fields: v.fields.map(Some).collect(),
idx: 0,
},
});
(self.visit_variant)(self.context, &mut path, &mut var_iter)
}
fn visit_sequence<Path>(self, mut path: Path, type_id: Self::TypeId) -> Self::Value
where
Path: PathIter<'resolver>,
{
(self.visit_sequence)(self.context, &mut path, type_id)
}
fn visit_array(self, type_id: Self::TypeId, len: usize) -> Self::Value {
(self.visit_array)(self.context, type_id, len)
}
fn visit_tuple<TypeIds>(self, mut type_ids: TypeIds) -> Self::Value
where
TypeIds: ExactSizeIterator<Item = Self::TypeId>,
{
(self.visit_tuple)(
self.context,
&mut type_ids as &mut dyn ExactSizeIterator<Item = Self::TypeId>,
)
}
fn visit_primitive(self, primitive: Primitive) -> Self::Value {
(self.visit_primitive)(self.context, primitive)
}
fn visit_compact(self, type_id: Self::TypeId) -> Self::Value {
(self.visit_compact)(self.context, type_id)
}
fn visit_bit_sequence(
self,
store_format: BitsStoreFormat,
order_format: BitsOrderFormat,
) -> Self::Value {
(self.visit_bit_sequence)(self.context, store_format, order_format)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::TypeResolver;
#[test]
fn check_type_inference() {
let visitor = new((), |_, _| 1u64)
.visit_array(|_, _, _| 2)
.visit_composite(|_, _, _| 3)
.visit_bit_sequence(|_, _, _| 4)
.visit_compact(|_, _| 5)
.visit_not_found(|_| 6)
.visit_tuple(|_, _| 8)
.visit_variant(|_, _, _| 9);
struct Foo;
impl crate::TypeResolver for Foo {
type TypeId = u32;
type Error = u8;
fn resolve_type<'this, V: ResolvedTypeVisitor<'this, TypeId = Self::TypeId>>(
&'this self,
_type_id: Self::TypeId,
visitor: V,
) -> Result<V::Value, Self::Error> {
Ok(visitor.visit_not_found())
}
}
assert_eq!(Foo.resolve_type(123, visitor).unwrap(), 6);
}
}