Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs143
1 files changed, 64 insertions, 79 deletions
diff --git a/src/lib.rs b/src/lib.rs
index cba864c..493b0ba 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,116 +3,101 @@
#[cfg(feature = "alloc")]
extern crate alloc;
-// pub mod build;
-pub mod error;
-// pub mod impls;
+pub mod build;
+pub mod impls;
pub mod protocol;
-// pub mod protocols;
-// pub mod transform;
-// pub mod walk;
+pub mod protocols;
+pub mod transform;
+pub mod walk;
-// use buildable::Buildable;
-use protocol::{AnyHint, Hint, ProtocolId, Visit, AnyVisit};
+use protocol::{AnyHint, AnyVisit, Hint, ProtocolId, Visit};
-// pub use buildable::Buildable;
-// pub use walkable::{Walkable, WalkableMut, WalkableRef};
-
-/// Status of a walker after walking using a visitor.
+/// Signal to a walker or visitor that it should exit early or continue.
///
-/// Some walkers can be walked multiple times to extract multiple
-/// values.
-pub enum WalkStatus {
- /// The walker is done.
- ///
- /// Attemping to call `walk` is likely to result in an error.
- Done,
+/// [`Walker`] and [`Visitor`] can't signal an error condition with a
+/// [`Result`] so instead they can use this.
+#[must_use]
+#[derive(Copy, Clone, Debug)]
+pub enum ControlFlow {
+ /// Continue the walk as normal.
+ Continue,
- /// The walker has more values to walk.
- More,
-
- /// The walker will repeat values.
- Repeat,
+ Done,
Error,
}
-/// Walker over a value with lifetime `'value`.
-pub trait Walker<'ctx> {
- /// Walk the walker over the value.
- ///
- /// This is the main entrypoint for walking a value.
- /// The walker should call [`Visit::visit`] on the provided visitor as it walks.
- ///
- /// The default impl calls [`Visitor::request_hint`] then returns an error if no hint
- /// was given. Self describing formats can replace the default impl to fall back to
- /// their own logic if no hint is given. It is recommended to keep the call to
- /// [`Visitor::request_hint`] before using walker specific logic to pick a protocol.
- fn walk(
- &mut self,
- visitor: &mut dyn Visitor<'ctx>,
- ) -> WalkStatus;
-}
+impl ControlFlow {
+ pub fn to_done(self) -> Self {
+ match self {
+ ControlFlow::Continue => ControlFlow::Done,
+ ControlFlow::Done => ControlFlow::Done,
+ ControlFlow::Error => ControlFlow::Error,
+ }
+ }
-pub trait ErrorNeedsHint {
- fn error_needs_hint(&mut self);
+ pub fn to_continue(self) -> Self {
+ match self {
+ ControlFlow::Continue => ControlFlow::Continue,
+ ControlFlow::Done => ControlFlow::Continue,
+ ControlFlow::Error => ControlFlow::Error,
+ }
+ }
}
-pub fn walk_with_hints<'ctx, H: WalkerHints<'ctx>>(
- hints: &mut H,
- visitor: &mut dyn Visitor<'ctx>,
-) -> WalkStatus
-where
- H: ErrorNeedsHint,
-{
- // Request that the visitor give us a hint of what protocol to use.
- match visitor.request_hint(hints, true) {
- Some(status) => status,
- None => {
- hints.error_needs_hint();
- WalkStatus::Error
- },
- }
+/// Walker over a value.
+///
+/// The walker can give out borrows with a lifetime of `'ctx` to the visitor.
+pub trait Walker<'ctx> {
+ /// Walk the value.
+ ///
+ /// The walker will call [`Visit::visit`] methods for one or more
+ /// [`Protocol`][protocol::Protocol] on the given `visitor`.
+ fn walk(&mut self, visitor: &mut dyn Visitor<'ctx>) -> ControlFlow;
}
/// Hint lookup for a walker.
+///
+/// Some walkers may need a hint for what the value it's walking actually is.
+/// To support this, a [`Walker`] will call the visitor's [`Visitor::request_hint`]
+/// method and the visitor can call a [`Hint::hint`] method for a
+/// [`Protocol`][protocol::Protocol] that the walker supports.
pub trait WalkerHints<'ctx> {
/// Query the walker for a given protocol.
///
/// If the walker doesn't support the protocol then a `None` is returned.
- /// Note, a walker can return `None` if it can't handle a hint of the protocol for the given
- /// value.
- fn protocol(
- &mut self,
- id: ProtocolId,
- ) -> Option<AnyHint<'_, 'ctx>>;
+ /// Note, a walker may return a `None` for a particular value but support
+ /// the protocol for other values.
+ ///
+ /// Use [`lookup_hint`][protocol::lookup_hint], or manually call
+ /// [`AnyHint::downcast`] on the returned value to access the [`Hint`].
+ fn protocol(&mut self, id: ProtocolId) -> Option<AnyHint<'_, 'ctx>>;
}
/// Visitor over a value to be built.
pub trait Visitor<'ctx> {
- /// Request the visitor hint what protocol to use.
- ///
- /// It is not recommended to call this while in a protocol hint as a walker.
- /// Calling this method when already processing a hint can cause a infinite loop.
+ /// Request the visitor provide a hint for what protocol to use.
///
- /// The visitor will hint the protocol by calling the [`Hint::hint`] method on the
- /// the walker's returned hint instance for the protocol.
+ /// Some walkers may need a hint for what the value it's walking actually is.
+ /// To support this, a [`Walker`] will call this method
+ /// and the visitor can call a [`Hint::hint`] method for a
+ /// [`Protocol`][protocol::Protocol] that the walker supports.
///
- /// A return value of `Ok(None)` means no hint was given to the walker.
+ /// Returning a `None` means the visitor gave no hint. The `need_hint` will
+ /// be `true` if the walker needs a hint to not encounter an error.
fn request_hint(
&mut self,
hints: &mut dyn WalkerHints<'ctx>,
need_hint: bool,
- ) -> Option<WalkStatus> {
- let _ = hints;
- let _ = need_hint;
- None
- }
+ ) -> ControlFlow;
/// Query the visitor for a given protocol.
///
/// If the visitor doesn't support the protocol then a `None` is returned.
- fn protocol(
- &mut self,
- id: ProtocolId,
- ) -> Option<AnyVisit<'_, 'ctx>>;
+ /// Note, a visitor may return a `None` if it doesn't support the protocol
+ /// for it's current internal state but could otherwise.
+ ///
+ /// Use [`lookup_visit`][protocol::lookup_visit], or manually call
+ /// [`AnyVisit::downcast`] on the returned value to access the [`Visit`].
+ fn protocol(&mut self, id: ProtocolId) -> Option<AnyVisit<'_, 'ctx>>;
}