//! Protocol for giving a visitor a borrowed value.
use core::marker::PhantomData;
use crate::{builtins::walker::hint::Meta, protocol::Protocol};
pub struct Value<T: ?Sized>(PhantomData<fn() -> *const T>);
pub enum Kind<'a, 'ctx: 'a, T: ?Sized> {
Temp(&'a T),
Context(&'ctx T),
TempMut(&'a mut T),
ContextMut(&'ctx mut T),
}
impl<'a, 'ctx, T: ?Sized> Kind<'a, 'ctx, T> {
pub fn into_temp(self) -> &'a T {
use Kind as K;
match self {
K::Temp(v) | K::Context(v) => v,
K::TempMut(v) | K::ContextMut(v) => v,
}
}
pub fn into_context(self) -> Result<&'ctx T, Self> {
use Kind as K;
match self {
K::Context(v) => Ok(v),
K::ContextMut(v) => Ok(v),
this @ (K::Temp(_) | K::TempMut(_)) => Err(this),
}
}
pub fn into_temp_mut(self) -> Result<&'a mut T, Self> {
use Kind as K;
match self {
K::TempMut(v) | K::ContextMut(v) => Ok(v),
this @ (K::Temp(_) | K::Context(_)) => Err(this),
}
}
pub fn into_context_mut(self) -> Result<&'ctx mut T, Self> {
use Kind as K;
match self {
K::ContextMut(v) => Ok(v),
this @ (K::Temp(_) | K::Context(_) | K::TempMut(_)) => {
Err(this)
}
}
}
pub fn variant(&self) -> KindVariants {
use Kind as K;
use KindVariants as V;
match self {
K::Temp(_) => V::Temp,
K::Context(_) => V::Context,
K::TempMut(_) => V::TempMut,
K::ContextMut(_) => V::ContextMut,
}
}
}
pub trait Object<'ctx, T: 'static> {
fn visit(&mut self, value: Kind<'_, 'ctx, T>) -> Result<(), ()>;
}
impl<T: 'static> Protocol for Value<T> {
type Object<'a, 'ctx: 'a> = &'a mut dyn Object<'ctx, T>;
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum KindVariants {
Temp,
Context,
TempMut,
ContextMut,
}
impl KindVariants {
pub fn can_become(&self, wanted: Self) -> bool {
use KindVariants as V;
match (self, wanted) {
(V::Temp, V::Temp) => true,
(V::Temp, V::Context) => false,
(V::Temp, V::TempMut) => false,
(V::Temp, V::ContextMut) => false,
(V::Context, V::Temp) => true,
(V::Context, V::Context) => true,
(V::Context, V::TempMut) => false,
(V::Context, V::ContextMut) => false,
(V::TempMut, V::Temp) => true,
(V::TempMut, V::Context) => false,
(V::TempMut, V::TempMut) => true,
(V::TempMut, V::ContextMut) => false,
(V::ContextMut, V::Temp) => true,
(V::ContextMut, V::Context) => true,
(V::ContextMut, V::TempMut) => true,
(V::ContextMut, V::ContextMut) => true,
}
}
}
pub struct Known {
pub kind: Option<KindVariants>,
}
pub struct Hint {
pub kind: Option<KindVariants>,
}
impl<T: 'static> Meta for Value<T> {
type Known<'a, 'ctx: 'a> = Known;
type Hint<'a, 'ctx: 'a> = Hint;
}