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 T
where
T: Walk<'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(self, visitor)
}
}
impl<'borrow, 'a, 'ctx, T> WalkMut<'borrow, 'ctx> for &'a T
where
T: Walk<'a, 'ctx>
{
fn walk_mut(&'borrow mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
T::walk(self, visitor)
}
}
impl<'borrow, 'a, 'ctx, T> Walk<'borrow, 'ctx> for &'a T
where
T: Walk<'a, '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 T {
type Builder = RefBuilder<'ctx, T>;
}
pub struct RefWalker<'ctx, T: ?Sized> {
value: &'ctx T,
error: Option<VisitorMissingProtocol>,
}
impl<'ctx, T: ?Sized> RefWalker<'ctx, T> {
pub fn new(value: &'ctx T) -> Self {
Self {
value,
error: None,
}
}
pub fn into_error(self) -> Option<VisitorMissingProtocol> {
self.error
}
}
impl<'ctx:, T: ?Sized + Any> Walker<'ctx> for RefWalker<'ctx, T> {
fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow {
match lookup_visit::<reference::Reference<T>, _>(visitor) {
Ok(visit) => visit.visit(reference::Ref::Context(self.value)).to_done(),
Err(err) => {
self.error = Some(err);
ControlFlow::Error
},
}
}
}
#[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 RefBuilder<'ctx, T: ?Sized> {
value: Option<Result<&'ctx T, Error>>,
}
impl<'ctx, T: ?Sized> Default for RefBuilder<'ctx, T> {
fn default() -> Self {
Self { value: None }
}
}
impl<'ctx, T: ?Sized + Any> Builder<'ctx> for RefBuilder<'ctx, T> {
type Error = Error;
type Value = &'ctx 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 RefBuilder<'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::Reference<T>>() {
Some(AnyVisit::new::<reference::Reference<T>>(self))
} else if id == ProtocolId::of::<reference::ReferenceMut<T>>() {
Some(AnyVisit::new::<reference::ReferenceMut<T>>(self))
} else {
None
}
}
}
impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::Reference<T>> for RefBuilder<'ctx, T> {
fn visit(&mut self, accessor: reference::Ref<'_, 'ctx, T>) -> ControlFlow {
match accessor {
reference::Ref::Walking(_) => {
self.value = Some(Err(Error::ShortLifetime));
ControlFlow::Error
},
reference::Ref::Context(value) |
reference::Ref::Static(value) => {
self.value = Some(Ok(value));
ControlFlow::Done
},
}
}
}
impl<'ctx, T: ?Sized + Any> Visit<'ctx, reference::ReferenceMut<T>> for RefBuilder<'ctx, T> {
fn visit(&mut self, accessor: reference::Mut<'_, 'ctx, T>) -> ControlFlow {
match accessor {
reference::Mut::Walking(_) => {
self.value = Some(Err(Error::ShortLifetime));
ControlFlow::Error
},
reference::Mut::Context(value) |
reference::Mut::Static(value) => {
self.value = Some(Ok(value));
ControlFlow::Done
},
}
}
}