Diffstat (limited to 'src/builtins/visitor/borrow.rs')
-rw-r--r--src/builtins/visitor/borrow.rs116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/builtins/visitor/borrow.rs b/src/builtins/visitor/borrow.rs
new file mode 100644
index 0000000..511d429
--- /dev/null
+++ b/src/builtins/visitor/borrow.rs
@@ -0,0 +1,116 @@
+//! 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;
+}