use core::fmt::{Debug, Display}; use crate::hkt::{Marker, CovariantLt, BorrowsCtx}; use effectful::bound::Dynamic; use effectful::effective::{Effective, Canonical}; use effectful::environment::{Environment}; use effectful::SendSync; use effectful::DynBind; use crate::any::{type_name, OwnedStatic, TempBorrowedStatic}; use crate::protocol::visitor::{DynRecoverableScope, Recoverable}; use crate::protocol::AsVisitor; use crate::{ any::AnyTrait, build::BuilderTypes, protocol::{ visitor::{tags, Tag, Value, VisitResult}, DynVisitor, }, walk::DynWalkerObjSafe, Builder, Flow, }; #[derive(SendSync)] pub struct EnumBuilder<'lt, 'ctx, Info, Mode, E: Environment> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, { inner: Inner<'lt, 'ctx, Info, Mode, E>, } #[derive(SendSync)] enum Inner<'lt, 'ctx, Info, Mode, E: Environment> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, { Temp, Seed(Info::Seed), Builder { builder: Info::Builders }, Value(Result, Info::Error>), } pub trait EnumBuildInfo<'lt, 'ctx, Mode, E: Environment>: 'lt { type Builders: DynBind; type Seed: DynBind; type Error: DynBind + Debug + Display; type ValueT: type_name::Static; type T; type VariantMarker: DynBind + Copy + Display; fn new_builder<'a>( seed: Self::Seed, variant: Self::VariantMarker, ) -> Canonical<'a, Self::Builders, E>; fn finish_builder<'a>( builder: Self::Builders, ) -> Canonical<'a, Result, Self::Error>, E> where Dynamic: DynBind; fn from_value<'a>(value: type_name::Lowered<'a, 'ctx, Self::ValueT>) -> Self::T; fn as_visitor<'a>(builder: &'a mut Self::Builders) -> DynVisitor<'a, 'lt, 'ctx, E>; fn marker_from_name(name: &str) -> Option; fn marker_from_discriminant(discriminant: u32) -> Option; fn guess_variant<'a>( seed: Self::Seed, scope: DynRecoverableScope<'a, 'ctx, E>, ) -> Canonical<'a, Result, Self::Error>, E> where Dynamic: DynBind; } impl<'lt, 'ctx, Info, Mode, E: Environment> BuilderTypes for EnumBuilder<'lt, 'ctx, Info, Mode, E> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, Dynamic: DynBind, { type Seed = Info::Seed; type Error = Info::Error; type Value = Info::T; type Output = Dynamic; fn unwrap_output(output: Self::Output) -> Self::Value { output.0 } } impl<'lt, 'ctx, Info, Mode: 'lt, E: Environment> Builder<'lt, 'ctx, E> for EnumBuilder<'lt, 'ctx, Info, Mode, E> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, Dynamic: DynBind, for<'a> Dynamic>: DynBind, for<'a> Dynamic>: DynBind, Dynamic>: DynBind, { fn from_seed<'a>(seed: Self::Seed) -> Canonical<'a, Self, E> where Self: 'a, { E::value(Self { inner: Inner::Seed(seed), }) .cast() } fn build<'a>(self) -> Canonical<'a, Result, E> where Self: 'a, { match self.inner { Inner::Temp => unreachable!(), Inner::Seed(_seed) => { // what to do... todo!() } Inner::Builder { builder } => Info::finish_builder(builder), Inner::Value(value) => E::value(value).cast(), } } } impl<'lt, 'ctx, Info, Mode: 'lt, E: Environment> AsVisitor<'lt, 'ctx, E> for EnumBuilder<'lt, 'ctx, Info, Mode, E> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, Dynamic: DynBind, for<'a> Dynamic>: DynBind, for<'a> Dynamic>: DynBind, Dynamic>: DynBind, { fn as_visitor<'a>(&'a mut self) -> DynVisitor<'a, 'lt, 'ctx, E> { DynVisitor(self) } } impl<'lt, 'ctx: 'lt, Info, Mode: 'lt, E: Environment> AnyTrait<'lt, 'ctx> for EnumBuilder<'lt, 'ctx, Info, Mode, E> where E: Environment, Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, Dynamic: DynBind, for<'a> Dynamic>: DynBind, for<'a> Dynamic>: DynBind, Dynamic>: DynBind, { } // any_trait! { // impl['ctx, Info, Mode][E] EnumBuilder<'ctx, Info, Mode, E> = [ // ValueProto, // TagProto, // RecoverableProto // ] ref { // let (_this, _id); // } else ref { // None // } mut { // let (this, id); // // // If a variant has been chosen, then forward everything to it's builder. // if matches!(this.inner, Inner::Builder { .. }) { // match &mut this.inner { // Inner::Builder { builder } => { // return Info::as_visitor(builder).0.upcast_to_id_mut(id) // } // _ => unreachable!(), // } // } // } else mut { // None // } where // E: Environment, // Info: EnumBuildInfo<'ctx, Mode, E>, // Dynamic: DynBind, // for<'a> Dynamic>: DynBind, // for<'a> Dynamic>: DynBind, // Dynamic>: DynBind, // } impl<'lt, 'ctx, Info, Mode, E: Environment> Recoverable<'ctx, E> for EnumBuilder<'lt, 'ctx, Info, Mode, E> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, Dynamic: DynBind, { fn visit<'a>( &'a mut self, scope: DynRecoverableScope<'a, 'ctx, E>, ) -> Canonical<'a, VisitResult, E> { match core::mem::replace(&mut self.inner, Inner::Temp) { Inner::Seed(seed) => Info::guess_variant(seed, scope) .map(self, |this, result| { this.inner = Inner::Value(result); Flow::Done.into() }) .cast(), inner => { self.inner = inner; E::value(Flow::Continue.into()).cast() } } } } impl<'lt, 'ctx, Info, Mode, E: Environment> Value<'ctx, Info::ValueT, E> for EnumBuilder<'lt, 'ctx, Info, Mode, E> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, Dynamic: DynBind, { fn visit<'this: 'value, 'value: 'e, 'e>( &'this mut self, value: type_name::Lowered<'value, 'ctx, Info::ValueT>, ) -> Canonical<'e, VisitResult>>, E> where type_name::Lowered<'value, 'ctx, Info::ValueT>: Sized, Dynamic>: DynBind, 'ctx: 'this + 'value, { self.inner = Inner::Value(Ok(Dynamic(Info::from_value(value)))); E::value(Flow::Done.into()).cast() } } impl<'lt, 'ctx: 'lt, Info, Mode: 'lt, E: Environment> Tag<'ctx, tags::Variant, E> for EnumBuilder<'lt, 'ctx, Info, Mode, E> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, Dynamic: DynBind, for<'a> Dynamic>: DynBind, Dynamic>: DynBind, { fn visit<'a: 'c, 'b: 'c, 'd: 'b, 'c>( &'a mut self, _kind: tags::Variant, walker: DynWalkerObjSafe<'b, 'd, 'ctx, E>, ) -> Canonical<'c, VisitResult, E> where 'ctx: 'd + 'b + 'c, 'lt: 'a + 'c, { let visitor = VariantVisitor:: { marker: None, _m: BorrowsCtx::NEW }; E::value((visitor, walker)) .update_map((), |_, (visitor, walker)| { walker.walk(DynVisitor(visitor)).cast() }) .then(self, |this, ((visitor, _), result)| { if let Some(variant) = visitor.marker { match core::mem::replace(&mut this.inner, Inner::Temp) { // A variant was given so we need to make the builder for // it. Inner::Seed(seed) => Info::new_builder(seed, variant) .map((this, result), |(this, result), builder| { this.inner = Inner::Builder { builder }; result.to_done().into() }) .cast::<()>(), inner => { this.inner = inner; E::value(result.to_done().into()).cast() } } } else { E::value(result.to_done().into()).cast() } }) .cast() } } #[derive(SendSync)] struct VariantVisitor<'lt, 'ctx, Info, Mode, E: Environment> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, { marker: Option, _m: BorrowsCtx<'lt, 'ctx>, } impl<'lt, 'ctx: 'lt, Info, Mode: 'lt, E: Environment> AnyTrait<'lt, 'ctx> for VariantVisitor<'lt, 'ctx, Info, Mode, E> where E: Environment, Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, Dynamic>: DynBind, for<'a> Dynamic>: DynBind, { } // any_trait! { // impl['ctx, Info, Mode][E] VariantVisitor<'ctx, Info, Mode, E> = [ // ValueProto, E>, // ValueProto, E>, // ] // where // E: Environment, // Info: EnumBuildInfo<'ctx, Mode, E>, // Dynamic>: DynBind, // for<'a> Dynamic>: DynBind, // } // impl<'ctx, Info, Mode, E: Environment> Value<'ctx, TempBorrowedStaticHrt, E> // for VariantVisitor<'ctx, Info, Mode, E> // where // Info: EnumBuildInfo<'ctx, Mode, E>, // for<'a> Dynamic, E>>: DynBind, // { // fn visit<'a>( // &'a mut self, // TempBorrowedStatic(value): TypeName::T<'a, 'ctx, TempBorrowedStaticHrt, E>, // ) -> Canonical<'a, VisitResult, E>>>, E> // where // TypeName::T<'a, 'ctx, TempBorrowedStaticHrt, E>: Sized, // 'ctx: 'a, // { // if let Some(variant) = Info::marker_from_name(value) { // self.marker = Some(variant); // // E::value(Flow::Done.into()).cast() // } else { // E::value(Flow::Continue.into()).cast() // } // } // } impl<'lt, 'ctx, Info, Mode, E: Environment> Value<'ctx, OwnedStatic, E> for VariantVisitor<'lt, 'ctx, Info, Mode, E> where Info: EnumBuildInfo<'lt, 'ctx, Mode, E>, for<'a> Dynamic>>: DynBind, Dynamic>: DynBind, { fn visit<'this: 'value, 'value: 'e, 'e>( &'this mut self, value: type_name::Lowered<'value, 'ctx, OwnedStatic>, ) -> Canonical<'e, VisitResult>>>, E> where type_name::Lowered<'value, 'ctx, OwnedStatic>: Sized, Dynamic>>: DynBind, 'ctx: 'this + 'value, { if let Some(variant) = Info::marker_from_discriminant(value.0) { self.marker = Some(variant); E::value(Flow::Done.into()).cast() } else { E::value(Flow::Continue.into()).cast() } } }