Diffstat (limited to 'src/walk/walkers/core/int.rs')
| -rw-r--r-- | src/walk/walkers/core/int.rs | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/walk/walkers/core/int.rs b/src/walk/walkers/core/int.rs new file mode 100644 index 0000000..97dc54d --- /dev/null +++ b/src/walk/walkers/core/int.rs @@ -0,0 +1,281 @@ +use crate::{ + any::OwnedStatic, + any_trait, + effect::{Effect, EffectExt as _, Effective as _, EffectiveExt as _, ErasedEffective, Ss}, + 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, +}; + +pub struct IntegerWalker<T, E> { + value: T, + _marker: Marker<E>, +} + +pub trait Integer: + 'static + + Copy + + core::fmt::Debug + + core::fmt::Display + + Ss + + 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<'ctx, T, E> IntegerWalker<T, E> { + pub fn new(value: T) -> Self { + Self { + value, + _marker: Default::default(), + } + } +} + +pub struct IntegerWalkerError<T> { + value: 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: Effect> Walker<'ctx, E> for IntegerWalker<T, E> { + type Error = IntegerWalkerError<T>; + + type Output = T; + + fn walk<'visitor: 'effect, 'effect>( + self, + visitor: DynVisitor<'visitor, 'ctx>, + ) -> ErasedEffective<'effect, Result<Self::Output, Self::Error>, E> + where + Self: 'effect, + { + let value = self.value; + + E::as_ctx((self, visitor), move |(this, visitor)| { + request_hint::<E>(visitor.cast(), DynWalker(this)) + .map(VisitResult::unit_skipped) + .cast() + }) + .map(|((_, visitor), result)| (visitor, result)) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, i8>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, u8>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, i16>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, u16>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, i32>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, u32>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, i64>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, u64>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, i128>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, u128>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, isize>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .if_skipped(move |visitor| { + if let Some(value) = try_into::<_, usize>(value) { + visit_value::<_, E>(visitor.cast(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + .cast() + } else { + E::ready(VisitResult::Skipped(())).cast() + } + }) + .map(move |(_, result)| match result { + VisitResult::Skipped(()) => Err(IntegerWalkerError { value }), + VisitResult::Control(_) => Ok(value), + }) + } +} + +impl<T> Integer for T where + T: 'static + + Copy + + core::fmt::Debug + + core::fmt::Display + + Ss + + 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: Effect +} + +macro_rules! impl_hints { + ($($type:ty),* $(,)?) => { + $(impl<'ctx, T: Integer, E: Effect> Hint<'ctx, ValueProto<OwnedStatic<$type>, E>> + for IntegerWalker<T, 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>>, + ) -> ErasedEffective<'e, crate::protocol::visitor::VisitResult, E> + where + 'ctx: 'this + 'visitor + 'hint + 'e, + { + if let Some(value) = try_into::<_, $type>(self.value) { + visit_value::<_, E>(visitor.into_inner(), OwnedStatic(value)) + .map(VisitResult::unit_skipped) + } else { + E::ready(VisitResult::Skipped(())) + } + } + + fn known<'a>( + &'a mut self, + _hint: &'a MetaHint<'a, 'ctx, ValueProto<OwnedStatic<$type>, E>>, + ) -> ErasedEffective<'a, Result<MetaKnown<'a, 'ctx, ValueProto<OwnedStatic<$type>, E>>, ()>, E> + { + E::ready(Ok(ValueKnown { preview: None })) + } + })* + }; +} + +impl_hints![u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]; |