use core::any::Any;
use crate::{
build::{Build, Builder},
protocol::{
lookup_hint, lookup_visit, AnyHint, AnyVisit, Hint, ProtocolId, Visit,
VisitorMissingProtocol, WalkerMissingProtocol,
},
protocols::{recoverable, reference},
walk::{Walk, WalkMut, WalkOnce},
ControlFlow, Visitor, Walker,
};
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 }
}
}
impl<'ctx, T: ?Sized + Any> WalkOnce<'ctx> for RefWalker<'ctx, T> {
type Error = VisitorMissingProtocol;
type Value = ();
fn walk_once(mut self, visitor: &mut dyn Visitor<'ctx>) -> Result<Self::Value, Self::Error> {
match visitor.request_hint(&mut self, false) {
ControlFlow::Continue => {
Hint::<reference::Reference<T>>::hint(
&mut self,
visitor,
reference::Hint {
kind: None,
min_len: None,
max_len: None,
},
);
}
_ => {}
}
if let Some(err) = self.error {
Err(err)
} else {
Ok(())
}
}
}
impl<'ctx, T: ?Sized + Any> Walker<'ctx> for RefWalker<'ctx, T> {
fn protocol(&mut self, id: ProtocolId) -> Option<crate::protocol::AnyHint<'_, 'ctx>> {
if id == ProtocolId::of::<reference::Reference<T>>() {
Some(AnyHint::new::<reference::Reference<T>>(self))
} else if id == ProtocolId::of::<reference::Reference<T>>() {
Some(AnyHint::new::<recoverable::Recoverable>(self))
} else {
None
}
}
}
impl<'ctx, T: ?Sized + Any> Hint<'ctx, reference::Reference<T>> for RefWalker<'ctx, T> {
fn hint(&mut self, visitor: &mut dyn Visitor<'ctx>, _hint: reference::Hint) -> 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
}
}
}
fn known(&mut self, _hint: &reference::Hint) -> reference::Known {
reference::Known {
kind: Some(reference::Kind::Context),
len: None,
}
}
}
impl<'ctx, T: ?Sized + Any> Hint<'ctx, recoverable::Recoverable> for RefWalker<'ctx, T> {
fn hint(&mut self, visitor: &mut dyn Visitor<'ctx>, _hint: ()) -> ControlFlow {
match lookup_visit::<recoverable::Recoverable, _>(visitor) {
Ok(visit) => visit.visit(self).to_done(),
Err(err) => {
self.error = Some(err);
ControlFlow::Error
}
}
}
fn known(&mut self, _hint: &()) {}
}
impl<'ctx, T: ?Sized + Any> recoverable::Accessor<'ctx> for RefWalker<'ctx, T> {
fn new_walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow {
todo!()
}
}
#[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::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::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
}
}
}
}