//! A collection of built in protocols between walkers and visitors.
//!
//! Treaty has not set data model. Instead, this module contains a set of basic protocols
//! walkers and visitors can use to exchange information.
//!
//! | Rust Type (`T`) | Protocol |
//! |-----------|----------|
//! | `bool` | [`dyn Value<'_, OwnedStatic<T>, _>`][visitor::Value] |
//! | `i8`, `i16`, `i32`, `i64`, `i128`, `isize` | [`dyn Value<'_, OwnedStatic<T>, _>`][visitor::Value] |
//! | `u8`, `u16`, `u32`, `u64`, `u128`, `usize` | [`dyn Value<'_, OwnedStatic<T>, _>`][visitor::Value] |
//! | `f32`, `f64` | [`dyn Value<'_, OwnedStatic<T>, _>`][visitor::Value] |
//! | `char` | [`dyn Value<'_, OwnedStatic<T>, _>`][visitor::Value] |
//! | `String` | [`dyn Value<'_, OwnedStatic<T>, _>`][visitor::Value] |
//! | `Vec<u8>` | [`dyn Value<'_, OwnedStatic<T>, _>`][visitor::Value] |
//! | `&'src str` | [`dyn Value<'ctx, BorrowedStatic<'ctx, T>, _>`][visitor::Value] |
//! | `&'ctx [u8]` | [`dyn Value<'ctx, BorrowedStatic<'ctx, T>, _>`][visitor::Value] |
//!
//!
//!
//! Interface for interfaces.
//!
//! ## Design
//! The design of protocols is based on an idea found in the
//! [`gdbstub`](https://docs.rs/gdbstub/latest/gdbstub/target/ext/index.html) crate.
//! This idea is of so called inlinable dyn extension traits.
//! However, in the form given in `gdbstub` they can't be used for arbitrary interfaces.
//! The main trait still needs to know about all the possible protocols.
//! That is where this module comes in.
//!
//! This module implements a technique we name dynamic inlinable dyn extension traits (DIDETs).
//! DIDETs adds one more layer to IDETs. Instead of a trait that knows all the possible protocols,
//! we have a single trait [`Implementer`] that allows looking up an extension trait
//! using a type ID. This may seem like it defeats the purpose of IDETs, that being to
//! make them inlinable. However, it turns out LLVM (the optimizer) is able to see
//! through this style of runtime reflection. As such, we still gain the benefits of
//! IDETs but with more flexability.
//! Protocols can now be defined in *any* crate and used between arbitrary crates.
//!
//! A protocol is a special trait that can participate as a DIDET. The only thing needed
//! for a protocol is an associated trait object. Because we need to use the
//! [`TypeId`][core::any::TypeId] of a protocol to perform reflection, we can't just use
//! the trait object itself as the protocol type. Instead an uninhabited type is used
//! as a marker for the trait.
//!
//! We then "implement" a protocol for a type by using [`Implementation`]. This provides
//! a mapping from `T` to the protocol's trait object.
//! By itself, [`Implementation`] is not enough for DIDET. A type also needs to implement
//! [`Implementer`] which allows looking up a particular [`Implementation`] trait object
//! from a [`ProtocolId`].
//!
//! The implementation of DIDETs defined by this module allows [`Implementer`] to be object safe.
//! This is done via the help of the [`AnyImpl`] type. This is not required for the core
//! idea of DIDETs.
pub mod visitor;
pub mod walker;
use core::ops::{Deref, DerefMut};
use effectful::{bound::SsBound, DynBind, SendSync};
use crate::{any::AnyTrait, hkt::ImpliedBound};
pub trait AnyTraitDynBind<'lt, E: SsBound>: AnyTrait<'lt> + DynBind<E> {
fn as_any_trait<'u>(&self) -> &(dyn AnyTrait<'lt> + 'u) where Self: 'u;
fn as_any_trait_mut<'u>(&mut self) -> &mut (dyn AnyTrait<'lt> + 'u) where Self: 'u;
}
impl<'lt, E, T> AnyTraitDynBind<'lt, E> for T
where
E: SsBound,
T: AnyTrait<'lt> + DynBind<E>,
{
fn as_any_trait<'u>(&self) -> &(dyn AnyTrait<'lt> + 'u) where Self: 'u {
self
}
fn as_any_trait_mut<'u>(&mut self) -> &mut (dyn AnyTrait<'lt> + 'u) where Self: 'u {
self
}
}
#[derive(SendSync)]
pub struct DynVisitor<'r, 'src, E: SsBound> {
_b: ImpliedBound<'r, 'src>,
any: &'r mut dyn AnyTraitDynBind<'src, E>,
}
impl<'r, 'src, E: SsBound> DynVisitor<'r, 'src, E> {
pub fn new(any: &'r mut dyn AnyTraitDynBind<'src, E>) -> Self {
DynVisitor {
any,
_b: ImpliedBound::NEW,
}
}
pub fn cast(&mut self) -> DynVisitor<'_, 'src, E> {
DynVisitor::new(self.any)
}
pub fn into_inner(self) -> &'r mut dyn AnyTraitDynBind<'src, E> {
self.any
}
}
impl<'r, 'src, E: SsBound> Deref for DynVisitor<'r, 'src, E> {
type Target = dyn AnyTrait<'src> + 'r;
fn deref(&self) -> &Self::Target {
self.any.as_any_trait()
}
}
impl<'r, 'src, E: SsBound> DerefMut for DynVisitor<'r, 'src, E> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.any.as_any_trait_mut()
}
}
pub trait AsVisitor<'src, E: SsBound> {
fn as_visitor(&mut self) -> DynVisitor<'_, 'src, E>;
}
impl<'r, 'src, E: SsBound> AsVisitor<'src, E> for DynVisitor<'r, 'src, E> {
fn as_visitor(&mut self) -> DynVisitor<'_, 'src, E> {
DynVisitor::new(self.any)
}
}
#[derive(SendSync)]
pub struct DynWalker<'r, 'src, E: SsBound> {
_b: ImpliedBound<'r, 'src>,
any: &'r mut dyn AnyTraitDynBind<'src, E>
}
impl<'r, 'src, E: SsBound> DynWalker<'r, 'src, E> {
pub fn new(any: &'r mut dyn AnyTraitDynBind<'src, E>) -> Self {
DynWalker {
any,
_b: ImpliedBound::NEW,
}
}
pub fn cast(&mut self) -> DynWalker<'_, 'src, E> {
DynWalker::new(self.any)
}
pub fn into_inner(self) -> &'r mut dyn AnyTraitDynBind<'src, E> {
self.any
}
}
impl<'r, 'src, E: SsBound> Deref for DynWalker<'r, 'src, E> {
type Target = dyn AnyTrait<'src> + 'r;
fn deref(&self) -> &Self::Target {
self.any.as_any_trait()
}
}
impl<'r, 'src, E: SsBound> DerefMut for DynWalker<'r, 'src, E> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.any.as_any_trait_mut()
}
}