Diffstat (limited to 'src/impls/core/reference.rs')
-rw-r--r--src/impls/core/reference.rs199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/impls/core/reference.rs b/src/impls/core/reference.rs
new file mode 100644
index 0000000..457af7a
--- /dev/null
+++ b/src/impls/core/reference.rs
@@ -0,0 +1,199 @@
+//! Impls for references `&T` and `&mut T`.
+//!
+//! ## Walk
+//!
+//! `&T` implements [`WalkOnce`], [`WalkMut`], and [`Walk`] if `T` implements [`Walk`].
+//!
+//! `&mut T` implements [`WalkOnce`], and [`WalkMut`] if `T` implements [`WalkMut`].
+//!
+//! ## Build
+
+// === &T ===
+
+use core::{any::Any, marker::PhantomData};
+
+use crate::{
+ build::{Build, Builder},
+ error::{Missing, UniError, WalkerError, WrongProtocol},
+ protocol::{AnyVisit, ProtocolId, Visit},
+ protocol_list,
+ protocols::reference::{self, Reference},
+ walk::{Walk, WalkMut, WalkOnce},
+};
+
+impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T: ?Sized> WalkOnce<'value, 'ctx, VisitorErr>
+ for &'ctx T
+where
+ T: Walk<'value, 'ctx, VisitorErr>,
+{
+ type ErrorOnce = T::Error;
+ type WalkerOnce = T::Walker;
+
+ fn into_walker(self) -> T::Walker {
+ T::walker(self)
+ }
+}
+
+impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T: ?Sized> WalkMut<'value, 'ctx, VisitorErr>
+ for &'ctx T
+where
+ T: Walk<'value, 'ctx, VisitorErr>,
+{
+ type ErrorMut = T::Error;
+ type WalkerMut = T::Walker;
+
+ fn walker_mut(&'value mut self) -> T::Walker {
+ T::walker(*self)
+ }
+}
+
+impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T: ?Sized> Walk<'value, 'ctx, VisitorErr> for &'ctx T
+where
+ T: Walk<'value, 'ctx, VisitorErr>,
+{
+ type Error = T::Error;
+ type Walker = T::Walker;
+
+ fn walker(&'value self) -> Self::Walker {
+ T::walker(self)
+ }
+}
+
+/// Error when building a reference.
+///
+/// References can only be built if the walker gives a
+/// long enough lifetime reference. See the [`Reference`]
+/// protocol.
+#[derive(thiserror::Error, Debug)]
+pub enum ShortLifetime {
+ /// The walker gave a `'walking` lifetime reference
+ /// but a longer lifetime was needed.
+ #[error("got `'walking` lifetime")]
+ Walking,
+
+ /// The walker gave a `'value` lifetime reference
+ /// but a longer lifetime was needed.
+ #[error("got `'value` lifetime")]
+ Value,
+
+ /// The walker gave a `'context` lifetime reference
+ /// but a longer lifetime was needed.
+ #[error("got `'ctx` lifetime")]
+ Context,
+}
+
+#[derive(Debug)]
+pub struct BuilderRefValue<'value, T: ?Sized>(Option<&'value T>);
+
+impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any> Build<'value, 'ctx, WalkerErr>
+ for &'value T
+{
+ type Error = Missing<WrongProtocol<ShortLifetime>>;
+
+ type Builder = BuilderRefValue<'value, T>;
+}
+
+impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any> Builder<'value, 'ctx, WalkerErr>
+ for BuilderRefValue<'value, T>
+{
+ type Error = Missing<WrongProtocol<ShortLifetime>>;
+
+ type Value = &'value T;
+
+ fn init() -> Self
+ where
+ Self: Sized,
+ {
+ Self(None)
+ }
+
+ fn as_visitor(
+ &mut self,
+ ) -> &mut dyn crate::Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> {
+ self
+ }
+
+ fn finish(self) -> Result<Self::Value, crate::error::UniError<WalkerErr, Self::Error>>
+ where
+ Self: Sized,
+ {
+ self.0.ok_or(UniError::Visitor(Missing::Missing))
+ }
+}
+
+impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any>
+ crate::Visitor<'value, 'ctx, WalkerErr> for BuilderRefValue<'value, T>
+{
+ type Error = Missing<WrongProtocol<ShortLifetime>>;
+
+ fn protocol(
+ &mut self,
+ id: crate::protocol::ProtocolId,
+ ) -> Option<crate::protocol::AnyVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>> {
+ match id {
+ id if id == ProtocolId::of::<Reference<T>>() => Some(AnyVisit::new(self)),
+ _ => None,
+ }
+ }
+
+ fn all_protocols() -> impl Iterator<Item = crate::protocol::ProtocolDescription>
+ where
+ Self: Sized,
+ {
+ protocol_list![Reference<T>]
+ }
+}
+
+impl<'value, 'ctx: 'value, WalkerErr: 'value, T: ?Sized + Any>
+ Visit<'value, 'ctx, Reference<T>, WalkerErr> for BuilderRefValue<'value, T>
+{
+ type Error = Missing<WrongProtocol<ShortLifetime>>;
+
+ fn visit<'walking>(
+ &'walking mut self,
+ accessor: <Reference<T> as crate::protocol::Protocol<'value, 'ctx>>::Accessor<
+ 'walking,
+ WalkerErr,
+ Self::Error,
+ >,
+ ) -> Result<(), UniError<WalkerErr, Self::Error>> {
+ use reference::Ref::*;
+
+ match accessor {
+ Walking(_) => Err(UniError::Visitor(Missing::Error(WrongProtocol::Error(
+ ShortLifetime::Walking,
+ )))),
+ Value(value) | Context(value) | Static(value) => {
+ self.0 = Some(value);
+
+ Ok(())
+ }
+ }
+ }
+}
+
+// === &mut T ===
+
+impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T> WalkOnce<'value, 'ctx, VisitorErr> for &'ctx mut T
+where
+ T: WalkMut<'value, 'ctx, VisitorErr>,
+{
+ type ErrorOnce = T::ErrorMut;
+ type WalkerOnce = T::WalkerMut;
+
+ fn into_walker(self) -> T::WalkerMut {
+ T::walker_mut(self)
+ }
+}
+
+impl<'value, 'ctx: 'value, VisitorErr: 'ctx, T> WalkMut<'value, 'ctx, VisitorErr> for &'ctx mut T
+where
+ T: WalkMut<'value, 'ctx, VisitorErr>,
+{
+ type ErrorMut = T::ErrorMut;
+ type WalkerMut = T::WalkerMut;
+
+ fn walker_mut(&'value mut self) -> T::WalkerMut {
+ T::walker_mut(self)
+ }
+}