Diffstat (limited to 'src/walk/walkers/owned_clone.rs')
-rw-r--r--src/walk/walkers/owned_clone.rs217
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(())
+ }
+ }
+ }
+}