Diffstat (limited to 'src/impls/alloc/string.rs')
| -rw-r--r-- | src/impls/alloc/string.rs | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/impls/alloc/string.rs b/src/impls/alloc/string.rs new file mode 100644 index 0000000..118eec0 --- /dev/null +++ b/src/impls/alloc/string.rs @@ -0,0 +1,213 @@ +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>; +} |