//! 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, _>`][visitor::Value] | //! | `i8`, `i16`, `i32`, `i64`, `i128`, `isize` | [`dyn Value<'_, OwnedStatic, _>`][visitor::Value] | //! | `u8`, `u16`, `u32`, `u64`, `u128`, `usize` | [`dyn Value<'_, OwnedStatic, _>`][visitor::Value] | //! | `f32`, `f64` | [`dyn Value<'_, OwnedStatic, _>`][visitor::Value] | //! | `char` | [`dyn Value<'_, OwnedStatic, _>`][visitor::Value] | //! | `String` | [`dyn Value<'_, OwnedStatic, _>`][visitor::Value] | //! | `Vec` | [`dyn Value<'_, OwnedStatic, _>`][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 { 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, { 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() } }