Diffstat (limited to 'src/build/builders/core/option.rs')
-rw-r--r--src/build/builders/core/option.rs327
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(())
+ }
+ }
+ }
+}