use core::any::Any;
use crate::{
build::{Build, Builder},
protocol::{
lookup_hint, lookup_visit, AnyVisit, ProtocolId, Visit, VisitorMissingProtocol,
WalkerMissingProtocol,
},
protocols::reference,
walk::{Walk, WalkMut, WalkOnce},
ControlFlow, Visitor, Walker,
};
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>,
}
impl<'ctx, T: ?Sized> MutWalker<'ctx, T> {
pub fn new(value: &'ctx mut T) -> Self {
Self {
value: Some(value),
}
}
}
impl<'ctx, T: ?Sized + Any> WalkOnce<'ctx> for MutWalker<'ctx, T> {
type Error = VisitorMissingProtocol;
type Value = ();
fn walk_once(mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
if let Some(value) = self.value.take() {
let visit = lookup_visit::<reference::ReferenceMut<T>, _>(visitor)?;
visit.visit(reference::Mut::Context(value));
}
Ok(())
}
}
#[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::Walker<'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
}
}
}
}