extern crate alloc;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::any::TypeId;
use core::marker::PhantomData;
use super::algebraic::EffectusAlgebraicus;
#[derive(Debug)]
pub struct SignumEffectus<E: EffectusAlgebraicus> {
nomen: &'static str,
type_id: TypeId,
_phantom: PhantomData<E>,
}
impl<E: EffectusAlgebraicus + 'static> SignumEffectus<E> {
#[inline]
pub const fn new(nomen: &'static str) -> Self {
SignumEffectus {
nomen,
type_id: TypeId::of::<E>(),
_phantom: PhantomData,
}
}
#[inline]
pub fn nomen(&self) -> &'static str {
self.nomen
}
#[inline]
pub fn type_id(&self) -> TypeId {
self.type_id
}
#[inline]
pub fn matches<F: EffectusAlgebraicus + 'static>(&self) -> bool {
self.type_id == TypeId::of::<F>()
}
}
impl<E: EffectusAlgebraicus + 'static> Clone for SignumEffectus<E> {
fn clone(&self) -> Self {
*self
}
}
impl<E: EffectusAlgebraicus + 'static> Copy for SignumEffectus<E> {}
pub struct Testimonium<E: EffectusAlgebraicus, H> {
signum: SignumEffectus<E>,
tractator: H,
depth: usize,
}
impl<E: EffectusAlgebraicus + 'static, H> Testimonium<E, H> {
#[inline]
pub fn new(signum: SignumEffectus<E>, tractator: H) -> Self {
Testimonium {
signum,
tractator,
depth: 0,
}
}
#[inline]
pub fn with_depth(signum: SignumEffectus<E>, tractator: H, depth: usize) -> Self {
Testimonium {
signum,
tractator,
depth,
}
}
#[inline]
pub fn signum(&self) -> &SignumEffectus<E> {
&self.signum
}
#[inline]
pub fn tractator(&self) -> &H {
&self.tractator
}
#[inline]
pub fn tractator_mut(&mut self) -> &mut H {
&mut self.tractator
}
#[inline]
pub fn depth(&self) -> usize {
self.depth
}
#[inline]
pub fn into_tractator(self) -> H {
self.tractator
}
}
pub struct VectorTestimonium {
entries: Vec<TestimoniumEntry>,
}
struct TestimoniumEntry {
type_id: TypeId,
_evidence: Box<dyn core::any::Any + Send + Sync>,
}
impl VectorTestimonium {
#[inline]
pub fn new() -> Self {
VectorTestimonium {
entries: Vec::new(),
}
}
#[inline]
pub fn with_capacity(cap: usize) -> Self {
VectorTestimonium {
entries: Vec::with_capacity(cap),
}
}
#[inline]
pub fn push<E, H>(&mut self, evidence: Testimonium<E, H>)
where
E: EffectusAlgebraicus + 'static,
H: Send + Sync + 'static,
{
self.entries.push(TestimoniumEntry {
type_id: TypeId::of::<E>(),
_evidence: Box::new(evidence),
});
}
#[inline]
pub fn lookup<E: EffectusAlgebraicus + 'static>(&self) -> Option<usize> {
let target = TypeId::of::<E>();
self.entries.iter().position(|e| e.type_id == target)
}
#[inline]
pub fn has<E: EffectusAlgebraicus + 'static>(&self) -> bool {
self.lookup::<E>().is_some()
}
#[inline]
pub fn len(&self) -> usize {
self.entries.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
#[inline]
pub fn clear(&mut self) {
self.entries.clear();
}
#[inline]
pub fn pop(&mut self) {
self.entries.pop();
}
}
impl Default for VectorTestimonium {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClausulaGenus {
Fun,
Ctl,
Final,
}
pub enum Clausula<A, B, E: EffectusAlgebraicus, R> {
Fun(Box<dyn Fn(A) -> B + Send + Sync>),
Ctl(Box<dyn Fn(A, Resumptio<B, R>) -> R + Send + Sync>),
Final(Box<dyn Fn(A) -> R + Send + Sync>),
#[doc(hidden)]
_Phantom(PhantomData<E>, core::convert::Infallible),
}
impl<A, B, E: EffectusAlgebraicus, R> Clausula<A, B, E, R> {
#[inline]
pub fn fun<F>(f: F) -> Self
where
F: Fn(A) -> B + Send + Sync + 'static,
{
Clausula::Fun(Box::new(f))
}
#[inline]
pub fn ctl<F>(f: F) -> Self
where
F: Fn(A, Resumptio<B, R>) -> R + Send + Sync + 'static,
{
Clausula::Ctl(Box::new(f))
}
#[inline]
pub fn final_<F>(f: F) -> Self
where
F: Fn(A) -> R + Send + Sync + 'static,
{
Clausula::Final(Box::new(f))
}
#[inline]
pub fn genus(&self) -> ClausulaGenus {
match self {
Clausula::Fun(_) => ClausulaGenus::Fun,
Clausula::Ctl(_) => ClausulaGenus::Ctl,
Clausula::Final(_) => ClausulaGenus::Final,
Clausula::_Phantom(_, never) => match *never {},
}
}
}
pub struct Resumptio<A, R> {
continuation: Box<dyn FnOnce(A) -> R + Send>,
}
impl<A: 'static, R: 'static> Resumptio<A, R> {
#[inline]
pub fn new<F>(f: F) -> Self
where
F: FnOnce(A) -> R + Send + 'static,
{
Resumptio {
continuation: Box::new(f),
}
}
#[inline]
pub fn resume(self, value: A) -> R {
(self.continuation)(value)
}
#[inline]
pub fn map<S: 'static, F>(self, f: F) -> Resumptio<A, S>
where
F: FnOnce(R) -> S + Send + 'static,
{
Resumptio::new(move |a| f(self.resume(a)))
}
#[inline]
pub fn contramap<B: 'static, F>(self, f: F) -> Resumptio<B, R>
where
F: FnOnce(B) -> A + Send + 'static,
{
Resumptio::new(move |b| self.resume(f(b)))
}
}
pub trait TractatorEvidentia<E: EffectusAlgebraicus>: Sized {
type Output;
fn signum(&self) -> SignumEffectus<E>;
fn handle_return(&self, value: Self::Output) -> Self::Output;
fn handle_operation(
&mut self,
evv: &VectorTestimonium,
op: E,
k: Resumptio<E::Result, Self::Output>,
) -> Self::Output;
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn run_with_evidence<E, H, A, F>(handler: H, evv: &mut VectorTestimonium, computation: F) -> A
where
E: EffectusAlgebraicus + 'static,
H: TractatorEvidentia<E, Output = A> + Send + Sync + 'static,
F: FnOnce(&VectorTestimonium) -> A,
A: 'static,
{
let signum = handler.signum();
evv.push(Testimonium::new(signum, ()));
let result = computation(evv);
let result = handler.handle_return(result);
evv.pop();
result
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone)]
struct TestEffect;
impl EffectusAlgebraicus for TestEffect {
type Result = i32;
}
#[test]
fn test_signum_effectus() {
let tag: SignumEffectus<TestEffect> = SignumEffectus::new("TestEffect");
assert_eq!(tag.nomen(), "TestEffect");
assert!(tag.matches::<TestEffect>());
}
#[test]
fn test_testimonium() {
let tag = SignumEffectus::<TestEffect>::new("TestEffect");
let evidence = Testimonium::new(tag, 42i32);
assert_eq!(evidence.depth(), 0);
assert_eq!(*evidence.tractator(), 42);
}
#[test]
fn test_vector_testimonium() {
let mut evv = VectorTestimonium::new();
assert!(evv.is_empty());
let tag = SignumEffectus::<TestEffect>::new("TestEffect");
let evidence = Testimonium::new(tag, ());
evv.push(evidence);
assert_eq!(evv.len(), 1);
assert!(evv.has::<TestEffect>());
}
#[test]
fn test_clausula_genus() {
let fun_clause: Clausula<i32, i32, TestEffect, i32> = Clausula::fun(|x| x * 2);
assert_eq!(fun_clause.genus(), ClausulaGenus::Fun);
let final_clause: Clausula<i32, i32, TestEffect, i32> = Clausula::final_(|x| x);
assert_eq!(final_clause.genus(), ClausulaGenus::Final);
}
#[test]
fn test_resumptio() {
let k = Resumptio::new(|x: i32| x * 2);
let result = k.resume(21);
assert_eq!(result, 42);
}
#[test]
fn test_resumptio_map() {
let k = Resumptio::new(|x: i32| x * 2);
let mapped = k.map(|r| r + 1);
assert_eq!(mapped.resume(20), 41);
}
#[test]
fn test_resumptio_contramap() {
let k = Resumptio::new(|x: i32| x * 2);
let contramapped = k.contramap(|s: &str| s.len() as i32);
assert_eq!(contramapped.resume("hello"), 10);
}
#[test]
fn test_resumptio_one_shot() {
let k = Resumptio::new(|x: i32| x);
let result = k.resume(42);
assert_eq!(result, 42);
}
}