Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 143 |
1 files changed, 64 insertions, 79 deletions
@@ -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>>; } |