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