use core::marker::PhantomData;
use ::alloc::string::String;
use crate::{error::{BasicError, UniError}, WalkerHints, protocol::{ProtocolId, AnyHint, Hint, lookup_visit, lookup_hint, AnyVisit, Protocol}, protocols::{str::Str, self}, HintGiven, walk::{WalkOnce, WalkMut, Walk}, build::{Builder, Build}};
macro_rules! impl_walker {
($walker:ident) => {
impl<'value, 'ctx: 'value, VisitorErr: 'ctx> crate::Walker<'value, 'ctx, VisitorErr>
for $walker<'value, 'ctx>
{
type Error = BasicError;
fn hints(&mut self) -> &mut dyn WalkerHints<'value, 'ctx, VisitorErr, Error = Self::Error> {
self
}
}
}
}
macro_rules! impl_hints {
($walker:ident, [$($protocol:ty),* $(,)?]) => {
impl<'value, 'ctx: 'value, VisitorErr: 'ctx> WalkerHints<'value, 'ctx, VisitorErr>
for $walker<'value, 'ctx>
{
type Error = BasicError;
fn protocol(
&mut self,
id: ProtocolId,
) -> Option<AnyHint<'_, 'value, 'ctx, Self::Error, VisitorErr>> {
match id {
$(id if id == ProtocolId::of::<$protocol>() => Some(AnyHint::new(self)),)?
_ => None,
}
}
}
}
}
pub struct WalkerOnce<'value, 'ctx: 'value>(String, PhantomData<&'value ()>);
impl_walker!(WalkerOnce);
impl<'value, 'ctx: 'value, VisitorErr: 'ctx> WalkerHints<'value, 'ctx, VisitorErr>
for WalkerOnce<'value, 'ctx>
{
type Error = BasicError;
fn protocol(
&mut self,
id: ProtocolId,
) -> Option<AnyHint<'_, 'value, 'ctx, Self::Error, VisitorErr>> {
match id {
id if id == ProtocolId::of::<Str>() => Some(AnyHint::new(self)),
_ => None,
}
}
}
impl<'value, 'ctx: 'value, VisitorErr: 'ctx> Hint<'value, 'ctx, Str, VisitorErr>
for Walker<'value, 'ctx>
{
type Error = BasicError;
fn hint(
&mut self,
visitor: &mut dyn crate::Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
_hint: <Str as crate::protocol::Protocol<'value, 'ctx>>::Hint,
) -> Result<HintGiven, UniError<Self::Error, VisitorErr>> {
lookup_visit::<Str, _, _>(visitor)
.map_err(UniError::Walker)?
.ok_or_else(|| UniError::Walker(BasicError("visitor is missing the str protocol")))?
.visit(protocols::str::Data::Value(self.0))?;
Ok(HintGiven)
}
fn known(
&mut self,
_hint: &<Str as crate::protocol::Protocol<'value, 'ctx>>::Hint,
) -> Result<<Str as crate::protocol::Protocol<'value, 'ctx>>::Known, BasicError> {
Ok(protocols::str::Known {
len: Some(self.0.len()),
kind: Some(protocols::str::Kind::Value),
})
}
}
pub struct WalkerMut<'value, 'ctx: 'value>(&'value mut String, PhantomData<&'ctx ()>);
pub struct WalkerRef<'value, 'ctx: 'value>(&'value String, PhantomData<&'ctx ()>);
impl<'value, 'ctx: 'value, VisitorErr: 'ctx> WalkOnce<'value, 'ctx, VisitorErr> for &'ctx str {
type Error = BasicError;
type Walker = Walker<'value, 'ctx>;
fn into_walker(self) -> Self::Walker {
Walker(self, PhantomData)
}
}
impl<'value, 'ctx: 'value, VisitorErr: 'ctx> WalkMut<'value, 'ctx, VisitorErr> for &'ctx str {
type ErrorMut = BasicError;
type WalkerMut = Walker<'value, 'ctx>;
fn walker_mut(&'value mut self) -> Self::Walker {
Walker(self, PhantomData)
}
}
impl<'value, 'ctx: 'value, VisitorErr: 'ctx> Walk<'value, 'ctx, VisitorErr> for &'ctx str {
type ErrorRef = BasicError;
type WalkerRef = Walker<'value, 'ctx>;
fn walker_ref(&'value self) -> Self::Walker {
Walker(self, PhantomData)
}
}
pub struct Visitor<'value>(Option<&'value str>);
impl<'value, 'ctx: 'value, WalkerErr: 'value> crate::Visitor<'value, 'ctx, WalkerErr>
for Visitor<'value>
{
type Error = BasicError;
fn request_hint(
&mut self,
hints: &mut dyn WalkerHints<'value, 'ctx, BasicError, Error = WalkerErr>,
) -> Result<Option<HintGiven>, UniError<WalkerErr, BasicError>> {
if let Some(hint) = lookup_hint::<Str, _, _>(hints).map_err(UniError::Visitor)? {
Ok(Some(hint.hint(
self,
protocols::str::Hint {
kind: Some(protocols::str::Kind::Value),
min_len: None,
max_len: None,
},
)?))
} else {
Ok(None)
}
}
fn protocol(
&mut self,
id: ProtocolId,
) -> Option<AnyVisit<'_, 'value, 'ctx, WalkerErr, BasicError>> {
match id {
id if id == ProtocolId::of::<Str>() => Some(AnyVisit::new(self)),
_ => None,
}
}
}
impl<'value, 'ctx: 'value, WalkerErr: 'value> crate::Visit<'value, 'ctx, Str, WalkerErr>
for Visitor<'value>
{
type Error = BasicError;
fn visit<'walking>(
&'walking mut self,
accessor: <Str as Protocol<'value, 'ctx>>::Accessor<'walking, WalkerErr, BasicError>,
) -> Result<(), UniError<WalkerErr, BasicError>> {
match accessor {
protocols::str::Data::Value(str)
| protocols::str::Data::Context(str)
| protocols::str::Data::Static(str) => self.0 = Some(str),
protocols::str::Data::Walking(_) => {
return Err(UniError::Visitor(BasicError(
"str doesn't live long enough",
)))
}
}
Ok(())
}
}
impl<'value, 'ctx: 'value, WalkerErr: 'value> Builder<'value, 'ctx, WalkerErr> for Visitor<'value> {
type Error = BasicError;
type Value = &'value str;
fn init() -> Self
where
Self: Sized,
{
Visitor(None)
}
fn as_visitor(
&mut self,
) -> &mut dyn crate::Visitor<'value, 'ctx, WalkerErr, Error = Self::Error> {
self
}
fn finish(self) -> Result<Self::Value, UniError<WalkerErr, Self::Error>>
where
Self: Sized,
{
if let Some(str) = self.0 {
Ok(str)
} else {
Err(UniError::Visitor(BasicError("missing str")))
}
}
}
impl<'value, 'ctx: 'value, WalkerErr: 'value> Build<'value, 'ctx, WalkerErr> for &'value str {
type Error = BasicError;
type Builder = Visitor<'value>;
}