use core::{marker::PhantomData, ops::ControlFlow}; use crate::{ any::static_wrapper::{BorrowedStatic, BorrowedStaticValue, OwnedStatic, TempBorrowedStatic}, any_trait, effect::{Effect, Future}, protocol::visitor::{ tagged::{Tagged, TaggedScope}, value::Value, }, }; impl<'ctx, T> crate::Build<'ctx> for Option where T: crate::Build<'ctx>, >::Seed: Default, { type Builder> = Builder<'ctx, T::Builder, E>; } impl<'ctx, T> crate::BuilderTypes<'ctx> for Option where T: crate::Build<'ctx>, >::Seed: Default, { type Error = Error<'ctx, T::Error>; type Value = Option; type Seed = IgnoreMissing; } pub struct Builder<'ctx, B: crate::Builder<'ctx>, E> { value: Option, Error<'ctx, B::Error>>>, ignore_missing: bool, _marker: PhantomData E>, } #[derive(Default)] pub enum IgnoreMissing { #[default] Yes, No, } #[derive(Debug)] pub enum Error<'ctx, T> { Missing, VariantNone, VariantSome(T), UnknownVariantName(Option>), UnknownVariantNum(Option), NoVariantGiven, } impl<'ctx, B, E: Effect<'ctx>> crate::BuilderTypes<'ctx> for Builder<'ctx, B, E> where B: crate::Builder<'ctx, Effect = E>, >::Seed: Default, { type Error = Error<'ctx, B::Error>; type Value = Option; type Seed = IgnoreMissing; } impl<'ctx, B, E: Effect<'ctx>> crate::Builder<'ctx> for Builder<'ctx, B, E> where B: crate::Builder<'ctx, Effect = E>, >::Seed: Default, { type Effect = E; #[inline] fn build<'a>(self) -> Future<'a, 'ctx, Result, E> where Self: 'a, { E::wrap(core::future::ready(match self.value { Some(value) => value, None if self.ignore_missing => Ok(None), None => Err(Error::Missing), })) } fn from_seed<'a>(seed: Self::Seed) -> Future<'a, 'ctx, Self, E> { E::wrap(core::future::ready(Self { value: None, ignore_missing: match seed { IgnoreMissing::Yes => true, IgnoreMissing::No => false, }, _marker: PhantomData, })) } fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx> { self } } any_trait! { impl['a, 'ctx, B, E] Builder<'ctx, B, E> = [ dyn Tagged<'ctx, E> + 'a, ] where B: crate::Builder<'ctx, Effect = E>, E: Effect<'ctx>, >::Seed: Default, } pub mod symbol { use crate::symbol::Symbol; pub const KEY: Symbol = Symbol::new("Key"); pub const TYPE: Symbol = Symbol::new("Type"); pub const VARIANT: Symbol = Symbol::new("Variant"); } impl<'ctx, B, E: Effect<'ctx>> Tagged<'ctx, E> for Builder<'ctx, B, E> where B: crate::Builder<'ctx, Effect = E>, >::Seed: Default, { fn visit<'a>( &'a mut self, scope: &'a mut (dyn TaggedScope<'ctx, E> + Send), ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { E::wrap(async { match scope.kind().await { symbol::KEY | symbol::VARIANT => { // This tag is the variant name/number. let mut variant = VariantVisitor::<'ctx, B::Error, E> { value: None, _marker: PhantomData, }; scope.tag(&mut variant).await?; let variant = match variant.value { Some(Ok(value)) => value, Some(Err(error)) => { self.value = Some(Err(error)); return ControlFlow::Break(()); } None => { self.value = Some(Err(Error::NoVariantGiven)); return ControlFlow::Break(()); } }; match variant { Variant::None => { // Nothing more needs to be done. self.value = Some(Ok(None)); ControlFlow::Continue(()) } Variant::Some => { // Now build a T. let mut builder = B::from_seed(Default::default()).await; scope.value(builder.as_visitor()).await?; match builder.build().await { Ok(value) => { self.value = Some(Ok(Some(value))); ControlFlow::Continue(()) } Err(error) => { self.value = Some(Err(Error::VariantSome(error))); ControlFlow::Break(()) } } } } } _ => { // Ignore any other tags and just use the value. scope.value(self).await } } }) } } enum Variant { None, Some, } pub struct VariantVisitor<'ctx, T, E> { value: Option>>, _marker: PhantomData E>, } any_trait! { impl['a, 'ctx, T, E] VariantVisitor<'ctx, T, E> = [ dyn Value<'a, 'ctx, TempBorrowedStatic<'a, str>, E> + 'a, dyn Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> + 'a, dyn Value<'a, 'ctx, OwnedStatic<&'static str>, E> + 'a, dyn Value<'a, 'ctx, OwnedStatic, E> + 'a, dyn Value<'a, 'ctx, OwnedStatic, E> + 'a, ] where E: Effect<'ctx> } impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, TempBorrowedStatic<'a, str>, E> for VariantVisitor<'ctx, T, E> { fn visit( &'a mut self, TempBorrowedStatic(value): TempBorrowedStatic<'a, str>, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { E::wrap(core::future::ready(match value { "None" => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) } "Some" => { self.value = Some(Ok(Variant::Some)); ControlFlow::Continue(()) } _ => { self.value = Some(Err(Error::UnknownVariantName(None))); ControlFlow::Break(()) } })) } } impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> for VariantVisitor<'ctx, T, E> { fn visit( &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, str>, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { E::wrap(core::future::ready(match value { "None" => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) } "Some" => { self.value = Some(Ok(Variant::Some)); ControlFlow::Continue(()) } value => { self.value = Some(Err(Error::UnknownVariantName(Some( BorrowedStaticValue::Ctx(value), )))); ControlFlow::Break(()) } })) } } impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str>, E> for VariantVisitor<'ctx, T, E> { fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<&'static str>, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { E::wrap(core::future::ready(match value { "None" => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) } "Some" => { self.value = Some(Ok(Variant::Some)); ControlFlow::Continue(()) } value => { self.value = Some(Err(Error::UnknownVariantName(Some( BorrowedStaticValue::Static(value), )))); ControlFlow::Break(()) } })) } } impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic, E> for VariantVisitor<'ctx, T, E> { fn visit( &'a mut self, OwnedStatic(value): OwnedStatic, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { E::wrap(core::future::ready(match value { 0 => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) } 1 => { self.value = Some(Ok(Variant::Some)); ControlFlow::Continue(()) } value => { self.value = Some(Err(Error::UnknownVariantNum(Some(value)))); ControlFlow::Break(()) } })) } } impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic, E> for VariantVisitor<'ctx, T, E> { fn visit( &'a mut self, OwnedStatic(value): OwnedStatic, ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { E::wrap(core::future::ready(match value { 0 => { self.value = Some(Ok(Variant::None)); ControlFlow::Continue(()) } 1 => { self.value = Some(Ok(Variant::Some)); ControlFlow::Continue(()) } value => { self.value = Some(Err(Error::UnknownVariantNum(value.try_into().ok()))); ControlFlow::Break(()) } })) } }