use core::fmt::{Debug, Display};
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<Dynamic<Info::T>, Info::Error>),
}
pub trait EnumBuildInfo<'lt, 'ctx, Mode, E: Environment>: 'lt {
type Builders: DynBind<E>;
type Seed: DynBind<E>;
type Error: DynBind<E> + Debug + Display;
type ValueT: type_name::Static;
type T;
type VariantMarker: DynBind<E> + 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<Dynamic<Self::T>, Self::Error>, E>
where
Dynamic<Self::T>: DynBind<E>;
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<Self::VariantMarker>;
fn marker_from_discriminant(discriminant: u32) -> Option<Self::VariantMarker>;
fn guess_variant<'a>(
seed: Self::Seed,
scope: DynRecoverableScope<'a, 'ctx, E>,
) -> Canonical<'a, Result<Dynamic<Self::T>, Self::Error>, E>
where
Dynamic<Self::T>: DynBind<E>;
}
impl<'lt, 'ctx, Info, Mode, E: Environment> BuilderTypes<E> for EnumBuilder<'lt, 'ctx, Info, Mode, E>
where
Info: EnumBuildInfo<'lt, 'ctx, Mode, E>,
Dynamic<Info::T>: DynBind<E>,
{
type Seed = Info::Seed;
type Error = Info::Error;
type Value = Info::T;
type Output = Dynamic<Info::T>;
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<Info::T>: DynBind<E>,
for<'a> Dynamic<type_name::Lowered<'a, 'ctx, Info::ValueT>>: DynBind<E>,
for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
Dynamic<OwnedStatic<u32>>: DynBind<E>,
{
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<Self::Output, Self::Error>, 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<Info::T>: DynBind<E>,
for<'a> Dynamic<type_name::Lowered<'a, 'ctx, Info::ValueT>>: DynBind<E>,
for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
Dynamic<OwnedStatic<u32>>: DynBind<E>,
{
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<Info::T>: DynBind<E>,
for<'a> Dynamic<type_name::Lowered<'a, 'ctx, Info::ValueT>>: DynBind<E>,
for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
Dynamic<OwnedStatic<u32>>: DynBind<E>,
{
}
// any_trait! {
// impl['ctx, Info, Mode][E] EnumBuilder<'ctx, Info, Mode, E> = [
// ValueProto<Info::ValueT, E>,
// TagProto<tags::Variant, E>,
// RecoverableProto<E>
// ] 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<Info::T>: DynBind<E>,
// for<'a> Dynamic<TypeName::T<'a, 'ctx, Info::ValueT, E>>: DynBind<E>,
// for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
// Dynamic<OwnedStatic<u32>>: DynBind<E>,
// }
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<Info::T>: DynBind<E>,
{
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<Info::T>: DynBind<E>,
{
fn visit<'this: 'value, 'value: 'e, 'e>(
&'this mut self,
value: type_name::Lowered<'value, 'ctx, Info::ValueT>,
) -> Canonical<'e, VisitResult<Dynamic<type_name::Lowered<'value, 'ctx, Info::ValueT>>>, E>
where
type_name::Lowered<'value, 'ctx, Info::ValueT>: Sized,
Dynamic<type_name::Lowered<'value, 'ctx, Info::ValueT>>: DynBind<E>,
'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<Info::T>: DynBind<E>,
for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
Dynamic<OwnedStatic<u32>>: DynBind<E>,
{
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::<Info, Mode, E> { marker: None };
E::value(visitor)
.update_map::<'_, '_, _, Flow>(walker, |walker, visitor| {
let y: DynVisitor<'_, 'lt, 'ctx, E> = DynVisitor(visitor);
let walker: DynWalkerObjSafe<'b, 'd, 'ctx, E> = walker;
let x: Canonical<'_, Flow, E> = walker.walk(y);
let y: Canonical<'_, Flow, E, &'_ ()> = x.cast();
y
// E::value(Flow::Done).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::<VisitResult>(result.to_done().into()).cast()
// }
// }
// } else {
// E::value(result.to_done().into()).cast()
// }
// });
// .cast()
todo!();
}
}
#[derive(SendSync)]
struct VariantVisitor<'lt, 'ctx, Info, Mode, E: Environment>
where
Info: EnumBuildInfo<'lt, 'ctx, Mode, E>,
{
marker: Option<Info::VariantMarker>,
}
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<OwnedStatic<u32>>: DynBind<E>,
for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
{
}
// any_trait! {
// impl['ctx, Info, Mode][E] VariantVisitor<'ctx, Info, Mode, E> = [
// ValueProto<TempBorrowedStaticHrt<str>, E>,
// ValueProto<OwnedStatic<u32>, E>,
// ]
// where
// E: Environment,
// Info: EnumBuildInfo<'ctx, Mode, E>,
// Dynamic<OwnedStatic<u32>>: DynBind<E>,
// for<'a> Dynamic<TempBorrowedStatic<'a, str>>: DynBind<E>,
// }
// impl<'ctx, Info, Mode, E: Environment> Value<'ctx, TempBorrowedStaticHrt<str>, E>
// for VariantVisitor<'ctx, Info, Mode, E>
// where
// Info: EnumBuildInfo<'ctx, Mode, E>,
// for<'a> Dynamic<TypeName::T<'a, 'ctx, TempBorrowedStaticHrt<str>, E>>: DynBind<E>,
// {
// fn visit<'a>(
// &'a mut self,
// TempBorrowedStatic(value): TypeName::T<'a, 'ctx, TempBorrowedStaticHrt<str>, E>,
// ) -> Canonical<'a, VisitResult<Dynamic<TypeName::T<'a, 'ctx, TempBorrowedStaticHrt<str>, E>>>, E>
// where
// TypeName::T<'a, 'ctx, TempBorrowedStaticHrt<str>, 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<u32>, E>
for VariantVisitor<'lt, 'ctx, Info, Mode, E>
where
Info: EnumBuildInfo<'lt, 'ctx, Mode, E>,
for<'a> Dynamic<type_name::Lowered<'a, 'ctx, OwnedStatic<u32>>>: DynBind<E>,
Dynamic<OwnedStatic<u32>>: DynBind<E>,
{
fn visit<'this: 'value, 'value: 'e, 'e>(
&'this mut self,
value: type_name::Lowered<'value, 'ctx, OwnedStatic<u32>>,
) -> Canonical<'e, VisitResult<Dynamic<type_name::Lowered<'value, 'ctx, OwnedStatic<u32>>>>, E>
where
type_name::Lowered<'value, 'ctx, OwnedStatic<u32>>: Sized,
Dynamic<type_name::Lowered<'value, 'ctx, OwnedStatic<u32>>>: DynBind<E>,
'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()
}
}
}