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(())
}
}
}
}