Diffstat (limited to 'src/impls/alloc/string.rs')
-rw-r--r--src/impls/alloc/string.rs213
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>;
+}