Diffstat (limited to 'src/walk/walkers/core/int.rs')
-rw-r--r--src/walk/walkers/core/int.rs281
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];