Diffstat (limited to 'src/walk/walkers/owned_clone.rs')
| -rw-r--r-- | src/walk/walkers/owned_clone.rs | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/walk/walkers/owned_clone.rs b/src/walk/walkers/owned_clone.rs new file mode 100644 index 0000000..27a323e --- /dev/null +++ b/src/walk/walkers/owned_clone.rs @@ -0,0 +1,217 @@ +use crate::build::protocols; +use crate::protocol::Implementer; +use crate::protocol::{ImplementerExt, ProtocolExt}; +use crate::{implementer, walk, Walker}; + +use super::MissingProtocol; + +pub struct OwnedCloneWalker<T> { + value: Option<T>, + error: Option<MissingProtocol>, + hint_given: bool, +} + +impl<T> OwnedCloneWalker<T> { + pub const fn new(value: T) -> Self { + Self { + value: Some(value), + error: None, + hint_given: false, + } + } +} + +impl<T> From<T> for OwnedCloneWalker<T> { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl<'ctx, T: 'static + Clone> Walker<'ctx> for OwnedCloneWalker<T> { + type Error = MissingProtocol; + + type Value = (); + + fn walk(mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<Self::Value, Self::Error> { + // Request the visitor give a hint. + // This allows the use of the recoverable protocol. + if let Some(interface) = visitor.interface_for::<protocols::hint::RequestHint>() { + match interface.as_object().request_hint(&mut self) { + Ok(()) => {} + Err(()) => { + return match self.error { + Some(err) => Err(err), + None => Ok(()), + }; + } + } + } + + // If no hint was given then just use the owned protocol. + if !self.hint_given { + let _ = walk::protocols::hint::Object::<protocols::owned::Owned<T>>::hint( + &mut self, + visitor, + (), + ); + } + + // Return an error if there was one. + match self.error { + Some(err) => Err(err), + None => Ok(()), + } + } +} + +implementer! { + impl['ctx, T: 'static + Clone] OwnedCloneWalker<T> = [ + walk::protocols::hint::Hint<protocols::owned::Owned<T>>, + walk::protocols::hint::Hint<protocols::recoverable::Recoverable>, + walk::protocols::hint::Hint<protocols::borrowed::Borrowed<T>>, + walk::protocols::hint::Hint<protocols::borrowed_mut::BorrowedMut<T>>, + ]; +} + +impl<'ctx, T: 'static + Clone> walk::protocols::hint::Object<'ctx, protocols::owned::Owned<T>> + for OwnedCloneWalker<T> +{ + fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>, _hint: ()) -> Result<(), ()> { + self.hint_given = true; + + if let Some(interface) = visitor.interface_for::<protocols::owned::Owned<T>>() { + // If this happens it means the value was already visited and consumed. + let Some(value) = self.value.take() else { + return Ok(()); // We return Ok because the walker isn't in an error state. + }; + + // Visit the value. + interface.as_object().visit(value) + } else { + self.error = Some(MissingProtocol(protocols::owned::Owned::<T>::id())); + Err(()) + } + } + + fn known(&mut self, _hint: &()) -> Result<(), ()> { + Ok(()) + } +} + +impl<'ctx, T: 'static + Clone> walk::protocols::hint::Object<'ctx, protocols::borrowed::Borrowed<T>> + for OwnedCloneWalker<T> +{ + fn hint( + &mut self, + visitor: &mut dyn Implementer<'ctx>, + _hint: protocols::borrowed::Hint, + ) -> Result<(), ()> { + self.hint_given = true; + + if let Some(interface) = visitor.interface_for::<protocols::borrowed::Borrowed<T>>() { + // If this happens it means the value was already visited and consumed. + let Some(value) = &self.value else { + return Ok(()); // We return Ok because the walker isn't in an error state. + }; + + // Visit the value. + interface.as_object().visit(protocols::borrowed::Value::Temp(value)) + } else { + self.error = Some(MissingProtocol(protocols::owned::Owned::<T>::id())); + Err(()) + } + } + + fn known( + &mut self, + _hint: &protocols::borrowed::Hint, + ) -> Result<protocols::borrowed::Known, ()> { + Ok(protocols::borrowed::Known { + kind: Some(protocols::borrowed::Kind::Temp), + }) + } +} + +impl<'ctx, T: 'static + Clone> walk::protocols::hint::Object<'ctx, protocols::borrowed_mut::BorrowedMut<T>> + for OwnedCloneWalker<T> +{ + fn hint( + &mut self, + visitor: &mut dyn Implementer<'ctx>, + _hint: protocols::borrowed_mut::Hint, + ) -> Result<(), ()> { + self.hint_given = true; + + if let Some(interface) = visitor.interface_for::<protocols::borrowed_mut::BorrowedMut<T>>() { + // If this happens it means the value was already visited and consumed. + let Some(value) = &mut self.value else { + return Ok(()); // We return Ok because the walker isn't in an error state. + }; + + // Visit the value. + interface.as_object().visit(protocols::borrowed_mut::Value::Temp(value)) + } else { + self.error = Some(MissingProtocol(protocols::owned::Owned::<T>::id())); + Err(()) + } + } + + fn known( + &mut self, + _hint: &protocols::borrowed_mut::Hint, + ) -> Result<protocols::borrowed_mut::Known, ()> { + Ok(protocols::borrowed_mut::Known { + kind: Some(protocols::borrowed_mut::Kind::Temp), + }) + } +} + +impl<'ctx, T: 'static + Clone> + walk::protocols::hint::Object<'ctx, protocols::recoverable::Recoverable> + for OwnedCloneWalker<T> +{ + fn hint(&mut self, visitor: &mut dyn Implementer<'ctx>, _hint: ()) -> Result<(), ()> { + self.hint_given = true; + + if let Some(interface) = visitor.interface_for::<protocols::recoverable::Recoverable>() { + // This walker is already recoverable. + interface.as_object().visit(self) + } else { + self.error = Some(MissingProtocol(protocols::recoverable::Recoverable::id())); + Err(()) + } + } + + fn known(&mut self, _hint: &()) -> Result<(), ()> { + Ok(()) + } +} + +impl<'ctx, T: 'static + Clone> protocols::recoverable::RecoverableWalker<'ctx> + for OwnedCloneWalker<T> +{ + fn new_walk(&mut self, visitor: &mut dyn Implementer<'ctx>) -> Result<(), ()> { + // Short circuit if the walker has an error. + if self.error.is_some() { + return Err(()); + } + + // Short circuit if the walker doesn't have a value. + // If this happens it means the value was already visited and consumed. + let Some(value) = &self.value else { + return Ok(()); // We return Ok because the walker isn't in an error state. + }; + + // Clone the value to put into a new walker instance. + let walker = Self::new(value.clone()); + + // Walk the walker. + match walker.walk(visitor) { + Ok(()) => Ok(()), // We don't know if the visitor had an issue. + Err(err) => { + self.error = Some(err); + Err(()) + } + } + } +} |