use effectful::effective::Effective;
use effectful::environment::{DynBind, Environment, NativeForm};
use effectful::higher_ranked::Mut;
use effectful::bound::Dynamic;
use effectful::SendSync;
use crate::{
any::OwnedStatic,
any_trait,
hkt::Marker,
never::Never,
protocol::{
visitor::{
request_hint, visit_value, EffectiveVisitExt as _, ValueKnown, ValueProto, VisitResult,
},
walker::hint::{DynVisitorWith, Hint, HintProto, MetaHint, MetaKnown},
DynVisitor, DynWalker,
},
Flow, Walker,
};
#[derive(SendSync)]
pub struct IntegerWalker<T, E> {
value: Dynamic<T>,
_marker: Marker<E>,
}
pub trait Integer:
'static
+ Copy
+ core::fmt::Debug
+ core::fmt::Display
+ TryInto<u8>
+ TryInto<u16>
+ TryInto<u32>
+ TryInto<u64>
+ TryInto<u128>
+ TryInto<usize>
+ TryInto<i8>
+ TryInto<i16>
+ TryInto<i32>
+ TryInto<i64>
+ TryInto<i128>
+ TryInto<isize>
{
}
fn try_into<T: TryInto<U>, U>(value: T) -> Option<U> {
value.try_into().ok()
}
impl<T, E> IntegerWalker<T, E> {
pub fn new(value: T) -> Self {
Self {
value: Dynamic(value),
_marker: Default::default(),
}
}
}
#[derive(SendSync)]
pub struct IntegerWalkerError<T> {
value: Dynamic<T>,
}
impl<T: Integer> ::core::fmt::Debug for IntegerWalkerError<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("IntegerWalkerError")
.field("value", &self.value)
.finish()
}
}
impl<T: Integer> ::core::fmt::Display for IntegerWalkerError<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("IntegerWalkerError")
.field("value", &self.value)
.finish()
}
}
impl<'ctx, T: Integer, E: Environment> Walker<'ctx, E> for IntegerWalker<T, E>
where
Dynamic<T>: DynBind<E>,
Dynamic<OwnedStatic<i8>>: DynBind<E>,
Dynamic<OwnedStatic<i16>>: DynBind<E>,
Dynamic<OwnedStatic<i32>>: DynBind<E>,
Dynamic<OwnedStatic<i64>>: DynBind<E>,
Dynamic<OwnedStatic<i128>>: DynBind<E>,
Dynamic<OwnedStatic<isize>>: DynBind<E>,
Dynamic<OwnedStatic<u8>>: DynBind<E>,
Dynamic<OwnedStatic<u16>>: DynBind<E>,
Dynamic<OwnedStatic<u32>>: DynBind<E>,
Dynamic<OwnedStatic<u64>>: DynBind<E>,
Dynamic<OwnedStatic<u128>>: DynBind<E>,
Dynamic<OwnedStatic<usize>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i8>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i16>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i32>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i64>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i128>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<isize>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u8>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u16>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u32>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u64>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u128>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<usize>>: DynBind<E>,
{
type Error = IntegerWalkerError<T>;
type Output = Dynamic<T>;
fn walk<'visitor: 'effect, 'effect>(
self,
visitor: DynVisitor<'visitor, 'ctx, E>,
) -> NativeForm<'effect, Result<Self::Output, Self::Error>, E>
where
Self: 'effect,
{
let value = self.value;
E::value((self, visitor))
.update((), |_, (this, visitor)| {
request_hint::<E>(visitor.cast(), DynWalker(this))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
})
.map((), |_, ((_, visitor), result)| (visitor, result))
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, i8>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, u8>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, i16>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, u16>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, i32>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, u32>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, i64>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, u64>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, i128>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, u128>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, isize>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.cast::<()>()
.if_skipped(value, |value, visitor| {
if let Some(value) = try_into::<_, usize>(value.0) {
visit_value::<_, E>(visitor.cast(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
})
.map(value, |value, (_, result)| match result {
VisitResult::Skipped(()) => Err(IntegerWalkerError { value }),
VisitResult::Control(_) => Ok(value),
})
.cast()
}
}
impl<T> Integer for T where
T: 'static
+ Copy
+ core::fmt::Debug
+ core::fmt::Display
+ TryInto<u8>
+ TryInto<u16>
+ TryInto<u32>
+ TryInto<u64>
+ TryInto<u128>
+ TryInto<usize>
+ TryInto<i8>
+ TryInto<i16>
+ TryInto<i32>
+ TryInto<i64>
+ TryInto<i128>
+ TryInto<isize>
{
}
any_trait! {
impl['ctx, T][E] IntegerWalker<T, E> = [
HintProto<ValueProto<OwnedStatic<i8>, E>>,
HintProto<ValueProto<OwnedStatic<i16>, E>>,
HintProto<ValueProto<OwnedStatic<i32>, E>>,
HintProto<ValueProto<OwnedStatic<i64>, E>>,
HintProto<ValueProto<OwnedStatic<i128>, E>>,
HintProto<ValueProto<OwnedStatic<u8>, E>>,
HintProto<ValueProto<OwnedStatic<u16>, E>>,
HintProto<ValueProto<OwnedStatic<u32>, E>>,
HintProto<ValueProto<OwnedStatic<u64>, E>>,
HintProto<ValueProto<OwnedStatic<u128>, E>>,
] where
T: Integer,
E: Environment,
Dynamic<T>: DynBind<E>,
Dynamic<OwnedStatic<i8>>: DynBind<E>,
Dynamic<OwnedStatic<i16>>: DynBind<E>,
Dynamic<OwnedStatic<i32>>: DynBind<E>,
Dynamic<OwnedStatic<i64>>: DynBind<E>,
Dynamic<OwnedStatic<i128>>: DynBind<E>,
Dynamic<OwnedStatic<isize>>: DynBind<E>,
Dynamic<OwnedStatic<u8>>: DynBind<E>,
Dynamic<OwnedStatic<u16>>: DynBind<E>,
Dynamic<OwnedStatic<u32>>: DynBind<E>,
Dynamic<OwnedStatic<u64>>: DynBind<E>,
Dynamic<OwnedStatic<u128>>: DynBind<E>,
Dynamic<OwnedStatic<usize>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i8>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i16>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i32>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i64>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<i128>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<isize>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u8>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u16>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u32>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u64>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<u128>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<usize>>: DynBind<E>,
}
macro_rules! impl_hints {
($($type:ty),* $(,)?) => {
$(impl<'ctx, T: Integer, E: Environment> Hint<'ctx, ValueProto<OwnedStatic<$type>, E>>
for IntegerWalker<T, E>
where
Dynamic<T>: DynBind<E>,
Dynamic<OwnedStatic<$type>>: DynBind<E>,
for<'a> Dynamic<&'a OwnedStatic<$type>>: DynBind<E>
{
fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
&'this mut self,
visitor: DynVisitorWith<'visitor, 'ctx, ValueProto<OwnedStatic<$type>, E>>,
_hint: MetaHint<'hint, 'ctx, ValueProto<OwnedStatic<$type>, E>>,
) -> NativeForm<'e, crate::protocol::visitor::VisitResult, E>
where
'ctx: 'this + 'visitor + 'hint + 'e,
{
if let Some(value) = try_into::<_, $type>(self.value.0) {
visit_value::<_, E>(visitor.into_inner(), OwnedStatic(value))
.map((), |_, x| VisitResult::unit_skipped(x))
.cast()
} else {
E::value(VisitResult::Skipped(())).cast()
}
}
fn known<'a>(
&'a mut self,
_hint: &'a MetaHint<'a, 'ctx, ValueProto<OwnedStatic<$type>, E>>,
) -> NativeForm<'a, Result<MetaKnown<'a, 'ctx, ValueProto<OwnedStatic<$type>, E>>, ()>, E>
{
E::value(Ok(ValueKnown { preview: None })).cast()
}
})*
};
}
impl_hints![u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize];