Diffstat (limited to 'src/impls/core/reference.rs')
| -rw-r--r-- | src/impls/core/reference.rs | 199 |
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) + } +} |