Diffstat (limited to 'src/build/builders/core/value.rs')
-rw-r--r--src/build/builders/core/value.rs231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/build/builders/core/value.rs b/src/build/builders/core/value.rs
new file mode 100644
index 0000000..d82ea1e
--- /dev/null
+++ b/src/build/builders/core/value.rs
@@ -0,0 +1,231 @@
+use core::fmt::Display;
+
+use crate::{
+ any::{
+ AnyTrait, BorrowedMutStatic, BorrowedMutStaticHrt, BorrowedStatic, BorrowedStaticHrt,
+ OwnedStatic, TempBorrowedMutStatic, TempBorrowedMutStaticHrt, TempBorrowedStatic,
+ TempBorrowedStaticHrt,
+ },
+ any_trait,
+ effect::{Effect, EffectExt as _, Effective as _, EffectiveExt as _, ErasedEffective, Ss},
+ hkt::Marker,
+ protocol::{
+ visitor::{
+ EffectiveVisitExt as _, RequestHint, RequestHintProto, Value, ValueProto, VisitResult,
+ },
+ walker::hint::hint_protocol,
+ DynVisitor, DynWalker,
+ },
+ Flow,
+};
+
+#[non_exhaustive]
+pub struct ValueError<T>(Marker<T>);
+
+impl<T> ::core::fmt::Debug for ValueError<T> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "missing value of type `{}`", core::any::type_name::<T>())
+ }
+}
+
+impl<T> Display for ValueError<T> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "missing value of type `{}`", core::any::type_name::<T>())
+ }
+}
+
+pub enum Cloneable {}
+pub enum NotCloneable {}
+
+/// Builder for `'static` values.
+///
+/// This builder only uses the [`Value`] protocol.
+pub struct ValueBuilder<T, Clone, E> {
+ value: Option<T>,
+ _marker: Marker<(E, Clone)>,
+}
+
+impl<T: Ss, Clone, E> crate::BuilderTypes for ValueBuilder<T, Clone, E> {
+ type Error = ValueError<T>;
+
+ type Value = T;
+
+ type Seed = ();
+}
+
+impl<'ctx, T: Ss + 'static, Clone, E: Effect> crate::Builder<'ctx, E> for ValueBuilder<T, Clone, E>
+where
+ Self: AnyTrait<'ctx>,
+{
+ fn build<'a>(self) -> ErasedEffective<'a, Result<Self::Value, Self::Error>, E>
+ where
+ Self: 'a,
+ {
+ E::ready(self.value.ok_or(ValueError(Default::default())))
+ }
+
+ fn from_seed<'a>(_seed: Self::Seed) -> ErasedEffective<'a, Self, E>
+ where
+ Self: 'a,
+ {
+ E::ready(Self {
+ value: None,
+ _marker: Default::default(),
+ })
+ }
+
+ fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> {
+ DynVisitor(self)
+ }
+}
+
+any_trait! {
+ impl['ctx, T, E] ValueBuilder<T, NotCloneable, E> = [
+ RequestHintProto<E>,
+ ValueProto<OwnedStatic<T>, E>,
+ ] where
+ E: Effect,
+ T: Ss + 'static
+}
+
+any_trait! {
+ impl['ctx, T, E] ValueBuilder<T, Cloneable, E> = [
+ RequestHintProto<E>,
+ ValueProto<OwnedStatic<T>, E>,
+ ValueProto<BorrowedStaticHrt<T>, E>,
+ ValueProto<TempBorrowedStaticHrt<T>, E>,
+ ValueProto<BorrowedMutStaticHrt<T>, E>,
+ ValueProto<TempBorrowedMutStaticHrt<T>, E>,
+ ] where
+ E: Effect,
+ T: Ss + 'static + Clone,
+}
+
+impl<'ctx, T: Ss + 'static, E: Effect> RequestHint<'ctx, E> for ValueBuilder<T, NotCloneable, E> {
+ fn request_hint<'a>(
+ &'a mut self,
+ walker: DynWalker<'a, 'ctx>,
+ ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
+ E::as_ctx((self, walker), |(this, walker)| {
+ hint_protocol::<ValueProto<OwnedStatic<T>, E>>(walker.cast(), *this, ()).cast()
+ })
+ .map(|((_, walker), result)| result.map_skipped(|_| walker))
+ }
+}
+
+impl<'ctx, T: Ss + 'static, E: Effect> RequestHint<'ctx, E> for ValueBuilder<T, Cloneable, E>
+where
+ T: Clone,
+{
+ fn request_hint<'a>(
+ &'a mut self,
+ walker: DynWalker<'a, 'ctx>,
+ ) -> ErasedEffective<'a, VisitResult<DynWalker<'a, 'ctx>>, E> {
+ E::as_ctx((self, walker), |(this, walker)| {
+ hint_protocol::<ValueProto<OwnedStatic<T>, E>>(walker.cast(), *this, ()).cast()
+ })
+ .if_not_finished(|(this, walker)| {
+ hint_protocol::<ValueProto<BorrowedStaticHrt<T>, E>>(walker.cast(), *this, ()).cast()
+ })
+ .if_not_finished(|(this, walker)| {
+ hint_protocol::<ValueProto<TempBorrowedStaticHrt<T>, E>>(walker.cast(), *this, ())
+ .cast()
+ })
+ .if_not_finished(|(this, walker)| {
+ hint_protocol::<ValueProto<BorrowedMutStaticHrt<T>, E>>(walker.cast(), *this, ()).cast()
+ })
+ .if_not_finished(|(this, walker)| {
+ hint_protocol::<ValueProto<TempBorrowedMutStaticHrt<T>, E>>(walker.cast(), *this, ())
+ .cast()
+ })
+ .map(|((_, walker), result)| result.map_skipped(|_| walker))
+ }
+}
+
+impl<'ctx, T: Ss + 'static, Clone, E: Effect> Value<'ctx, OwnedStatic<T>, E>
+ for ValueBuilder<T, Clone, E>
+{
+ fn visit<'a>(
+ &'a mut self,
+ OwnedStatic(value): OwnedStatic<T>,
+ ) -> ErasedEffective<'a, VisitResult<OwnedStatic<T>>, E>
+ where
+ 'ctx: 'a,
+ {
+ self.value = Some(value);
+
+ E::ready(Flow::Done.into())
+ }
+}
+
+impl<'ctx, T: Ss + 'static, E: Effect> Value<'ctx, BorrowedStaticHrt<T>, E>
+ for ValueBuilder<T, Cloneable, E>
+where
+ T: Clone,
+{
+ fn visit<'a>(
+ &'a mut self,
+ BorrowedStatic(value): BorrowedStatic<'ctx, T>,
+ ) -> ErasedEffective<'a, VisitResult<BorrowedStatic<'ctx, T>>, E>
+ where
+ 'ctx: 'a,
+ {
+ self.value = Some(value.clone());
+
+ E::ready(Flow::Done.into())
+ }
+}
+
+impl<'ctx, T: Ss + 'static, E: Effect> Value<'ctx, TempBorrowedStaticHrt<T>, E>
+ for ValueBuilder<T, Cloneable, E>
+where
+ T: Clone,
+{
+ fn visit<'a>(
+ &'a mut self,
+ TempBorrowedStatic(value): TempBorrowedStatic<'a, T>,
+ ) -> ErasedEffective<'a, VisitResult<TempBorrowedStatic<'a, T>>, E>
+ where
+ 'ctx: 'a,
+ {
+ self.value = Some(value.clone());
+
+ E::ready(Flow::Done.into())
+ }
+}
+
+impl<'ctx, T: Ss + 'static, E: Effect> Value<'ctx, BorrowedMutStaticHrt<T>, E>
+ for ValueBuilder<T, Cloneable, E>
+where
+ T: Clone,
+{
+ fn visit<'a>(
+ &'a mut self,
+ BorrowedMutStatic(value): BorrowedMutStatic<'ctx, T>,
+ ) -> ErasedEffective<'a, VisitResult<BorrowedMutStatic<'ctx, T>>, E>
+ where
+ 'ctx: 'a,
+ {
+ self.value = Some(value.clone());
+
+ E::ready(Flow::Done.into())
+ }
+}
+
+impl<'ctx, T: Ss + 'static, E: Effect> Value<'ctx, TempBorrowedMutStaticHrt<T>, E>
+ for ValueBuilder<T, Cloneable, E>
+where
+ T: Clone,
+{
+ fn visit<'a>(
+ &'a mut self,
+ TempBorrowedMutStatic(value): TempBorrowedMutStatic<'a, T>,
+ ) -> ErasedEffective<'a, VisitResult<TempBorrowedMutStatic<'a, T>>, E>
+ where
+ 'ctx: 'a,
+ {
+ self.value = Some(value.clone());
+
+ E::ready(Flow::Done.into())
+ }
+}