Diffstat (limited to 'src/impls/core/reference_mut.rs')
| -rw-r--r-- | src/impls/core/reference_mut.rs | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/impls/core/reference_mut.rs b/src/impls/core/reference_mut.rs new file mode 100644 index 0000000..5f0eff7 --- /dev/null +++ b/src/impls/core/reference_mut.rs @@ -0,0 +1,162 @@ +use core::any::Any; + +use crate::{ + protocol::{lookup_visit, VisitorMissingProtocol, WalkerMissingProtocol, lookup_hint, ProtocolId, AnyVisit, Visit}, + protocols::reference, + walk::{WalkMut, WalkOnce, Walk}, + Visitor, Walker, ControlFlow, build::{Builder, Build}, +}; + +impl<'borrow, 'ctx, T> WalkOnce<'ctx> for &'borrow mut T +where + T: WalkMut<'borrow, 'ctx> +{ + type Error = T::Error; + + type Value = T::Value; + + fn walk_once(self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk_mut(self, visitor) + } +} + +impl<'borrow, 'ctx, T> WalkMut<'borrow, 'ctx> for &'borrow mut T +where + T: WalkMut<'borrow, 'ctx> +{ + fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk_mut(self, visitor) + } +} + +impl<'borrow, 'ctx, T> Walk<'borrow, 'ctx> for &'borrow mut T +where + T: Walk<'borrow, 'ctx> +{ + fn walk(&'borrow self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> { + T::walk(self, visitor) + } +} + +impl<'ctx, T: ?Sized + Any> Build<'ctx> for &'ctx mut T { + type Builder = MutBuilder<'ctx, T>; +} + +pub struct MutWalker<'ctx, T: ?Sized> { + value: Option<&'ctx mut T>, + error: Option<VisitorMissingProtocol>, +} + +impl<'ctx, T: ?Sized> MutWalker<'ctx, T> { + pub fn new(value: &'ctx mut T) -> Self { + Self { + value: Some(value), + error: None, + } + } + + pub fn into_error(self) -> Option<VisitorMissingProtocol> { + self.error + } +} + +impl<'ctx:, T: ?Sized + Any> Walker<'ctx> for MutWalker<'ctx, T> { + fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow { + if let Some(value) = self.value.take() { + match lookup_visit::<reference::ReferenceMut<T>, _>(visitor) { + Ok(visit) => visit.visit(reference::Mut::Context(value)).to_done(), + Err(err) => { + self.error = Some(err); + ControlFlow::Continue + }, + } + } else { + ControlFlow::Done + } + } +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Missing value after walk.")] + MissingValue, + + #[error("A value with a lifetime to short was given.")] + ShortLifetime, + + #[error(transparent)] + MissingProtocol(#[from] WalkerMissingProtocol) +} + +pub struct MutBuilder<'ctx, T: ?Sized> { + value: Option<Result<&'ctx mut T, Error>>, +} + +impl<'ctx, T: ?Sized> Default for MutBuilder<'ctx, T> { + fn default() -> Self { + Self { value: None } + } +} + +impl<'ctx, T: ?Sized + Any> Builder<'ctx> for MutBuilder<'ctx, T> { + type Error = Error; + + type Value = &'ctx mut T; + + fn as_visitor(&mut self) -> &mut dyn Visitor<'ctx> { + self + } + + fn build(self) -> Result<Self::Value, Self::Error> { + match self.value { + Some(Ok(value)) => Ok(value), + Some(Err(err)) => Err(err.into()), + None => Err(Error::MissingValue), + } + } +} + +impl<'ctx, T: ?Sized + Any> Visitor<'ctx> for MutBuilder<'ctx, T> { + fn request_hint( + &mut self, + hints: &mut dyn crate::WalkerHints<'ctx>, + _need_hint: bool, + ) -> ControlFlow { + match lookup_hint::<reference::Reference<T>, _>(hints) { + Ok(hint) => hint.hint(self, reference::Hint { + kind: Some(reference::Kind::Context), + min_len: None, + max_len: None, + }), + Err(err) => { + self.value = Some(Err(err.into())); + ControlFlow::Error + }, + } + } + + fn protocol(&mut self, id: crate::protocol::ProtocolId) -> Option<AnyVisit<'_, 'ctx>> { + if id == ProtocolId::of::<reference::ReferenceMut<T>>() { + Some(AnyVisit::new(self)) + } else { + None + } + } +} + +impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::ReferenceMut<T>> for MutBuilder<'ctx, T> { + fn visit(&mut self, accessor: reference::Mut<'_, 'ctx, T>) -> ControlFlow { + match accessor { + reference::Mut::Walking(_) => { + self.value = Some(Err(Error::ShortLifetime)); + ControlFlow::Continue + }, + reference::Mut::Context(value) | + reference::Mut::Static(value) => { + self.value = Some(Ok(value)); + ControlFlow::Done + }, + } + + } +} |