1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//! 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.

use core::{
    future::Future,
    pin::{pin, Pin},
    ptr,
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

use crate::any::AnyTrait;

pub mod visitor;
pub mod walker;

#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;

pub type Visitor<'a, 'ctx> = dyn AnyTrait<'ctx> + 'a;
pub type Walker<'a, 'ctx> = dyn AnyTrait<'ctx> + 'a;

pub trait Effect: 'static {
    type ControlFlow<'a, C, B>;
}

pub type ControlFlowFor<'a, E = SyncEffect, C = (), B = ()> = <E as Effect>::ControlFlow<'a, C, B>;

pub enum SyncEffect {}

impl Effect for SyncEffect {
    type ControlFlow<'a, C, B> = core::ops::ControlFlow<B, C>;
}

fn noop() -> Waker {
    const VTABLE: RawWakerVTable = RawWakerVTable::new(|_| RAW, |_| {}, |_| {}, |_| {});
    const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE);

    unsafe { Waker::from_raw(RAW) }
}

#[cfg(feature = "alloc")]
pub enum AsyncEffect {}

#[cfg(feature = "alloc")]
impl Effect for AsyncEffect {
    type ControlFlow<'a, C, B> =
        core::pin::Pin<Box<dyn core::future::Future<Output = core::ops::ControlFlow<B, C>> + 'a>>;
}