Diffstat (limited to 'src/build/builders/core/option.rs')
| -rw-r--r-- | src/build/builders/core/option.rs | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/src/build/builders/core/option.rs b/src/build/builders/core/option.rs new file mode 100644 index 0000000..00c79c9 --- /dev/null +++ b/src/build/builders/core/option.rs @@ -0,0 +1,327 @@ +use core::{marker::PhantomData, ops::ControlFlow}; + +use crate::{ + any::static_wrapper::{BorrowedStatic, BorrowedStaticValue, OwnedStatic, TempBorrowedStatic}, + any_trait, + effect::{AsyncEffect, AsyncSendEffect, EffectAnyTrait, SyncEffect, Yield}, + protocol::visitor::{Tagged, TaggedScope, Value}, + AsVisitor, +}; + +impl<'ctx, T, E> crate::Build<'ctx, E> for Option<T> +where + E: EffectAnyTrait<'ctx>, + Builder<'ctx, T::Builder, E>: AsVisitor<'ctx, E>, + T: crate::Build<'ctx, E>, +{ + type Builder = Builder<'ctx, T::Builder, E>; +} + +pub struct Builder<'ctx, B: crate::Builder<'ctx, E>, E: EffectAnyTrait<'ctx>> { + value: Option<Result<Option<B::Value>, Error<'ctx, B::Error>>>, + ignore_missing: bool, + _marker: PhantomData<fn() -> (&'ctx (), E)>, +} + +#[derive(Default)] +pub enum IgnoreMissing { + #[default] + Yes, + No, +} + +#[derive(Debug)] +pub enum Error<'ctx, T> { + Missing, + VariantNone, + VariantSome(T), + UnknownVariantName(Option<BorrowedStaticValue<'ctx, str>>), + UnknownVariantNum(Option<u8>), + NoVariantGiven, +} + +impl<'ctx, B, E> crate::Builder<'ctx, E> for Builder<'ctx, B, E> +where + E: EffectAnyTrait<'ctx>, + Self: AsVisitor<'ctx, E>, + B: crate::Builder<'ctx, E>, +{ + type Error = Error<'ctx, B::Error>; + + type Value = Option<B::Value>; + + #[inline] + fn build<'a>(self) -> Result<Self::Value, Self::Error> + where + Self: 'a, + { + match self.value { + Some(value) => value, + None if self.ignore_missing => Ok(None), + None => Err(Error::Missing), + } + } + + type Seed = IgnoreMissing; + + fn from_seed(seed: Self::Seed) -> Self { + Self { + value: None, + ignore_missing: match seed { + IgnoreMissing::Yes => true, + IgnoreMissing::No => false, + }, + _marker: PhantomData, + } + } + + type Effect = SyncEffect; +} + +impl<'ctx, B: crate::Builder<'ctx, SyncEffect>> AsVisitor<'ctx, SyncEffect> + for Builder<'ctx, B, SyncEffect> +{ + fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, SyncEffect> { + self + } +} + +impl<'ctx, B: crate::Builder<'ctx, AsyncEffect>> AsVisitor<'ctx, AsyncEffect> + for Builder<'ctx, B, AsyncEffect> +{ + fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, AsyncEffect> { + self + } +} + +impl<'ctx, B> AsVisitor<'ctx, AsyncSendEffect> for Builder<'ctx, B, AsyncSendEffect> +where + B: crate::Builder<'ctx, AsyncSendEffect>, + <B as crate::Builder<'ctx, AsyncSendEffect>>::Value: Send, + <B as crate::Builder<'ctx, AsyncSendEffect>>::Error: Send, +{ + fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, AsyncSendEffect> { + self + } +} + +any_trait! { + impl['a, 'ctx, B] Builder<'ctx, B, SyncEffect> = [ + ] where B: crate::Builder<'ctx, SyncEffect> +} + +any_trait! { + impl['a, 'ctx, B] Builder<'ctx, B, AsyncEffect> = [ + ] where B: crate::Builder<'ctx, AsyncEffect> +} + +any_trait! { + impl['a, 'ctx, B] Builder<'ctx, B, AsyncSendEffect> = [ + ] where B: crate::Builder<'ctx, AsyncSendEffect> +} + +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> Tagged<'ctx, SyncEffect> for Builder<'ctx, B, SyncEffect> +where + B: crate::DefaultBuilder<'ctx, SyncEffect, Effect = SyncEffect>, +{ + fn visit<'a>( + &'a mut self, + scope: &'a mut dyn TaggedScope<'ctx, SyncEffect>, + ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> + where + 'ctx: 'a, + { + match scope.kind() { + symbol::KEY | symbol::VARIANT => { + // This tag is the variant name/number. + let mut variant = VariantVisitor::<'ctx, B::Error> { value: None }; + scope.tag(&mut variant)?; + 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::default(); + scope.value(builder.as_visitor())?; + match builder.build() { + 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) + } + } + } +} + +enum Variant { + None, + Some, +} + +pub struct VariantVisitor<'ctx, T> { + value: Option<Result<Variant, Error<'ctx, T>>>, +} + +any_trait! { + impl['a, 'ctx, T] VariantVisitor<'ctx, T> = [ + dyn Value<'a, 'ctx, TempBorrowedStatic<'a, str>, SyncEffect> + 'a, + dyn Value<'a, 'ctx, BorrowedStatic<'ctx, str>, SyncEffect> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<&'static str>, SyncEffect> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<u8>, SyncEffect> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<u16>, SyncEffect> + 'a, + ] +} + +impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, TempBorrowedStatic<'a, str>, SyncEffect> + for VariantVisitor<'ctx, T> +{ + fn visit( + &'a mut self, + TempBorrowedStatic(value): TempBorrowedStatic<'a, str>, + ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + 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> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, SyncEffect> + for VariantVisitor<'ctx, T> +{ + fn visit( + &'a mut self, + BorrowedStatic(value): BorrowedStatic<'ctx, str>, + ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + 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> Value<'a, 'ctx, OwnedStatic<&'static str>, SyncEffect> + for VariantVisitor<'ctx, T> +{ + fn visit( + &'a mut self, + OwnedStatic(value): OwnedStatic<&'static str>, + ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + 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> Value<'a, 'ctx, OwnedStatic<u8>, SyncEffect> for VariantVisitor<'ctx, T> { + fn visit( + &'a mut self, + OwnedStatic(value): OwnedStatic<u8>, + ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + 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> Value<'a, 'ctx, OwnedStatic<u16>, SyncEffect> for VariantVisitor<'ctx, T> { + fn visit( + &'a mut self, + OwnedStatic(value): OwnedStatic<u16>, + ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + 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(()) + } + } + } +} |