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(())
}
}
}
}