use core::marker::PhantomData;
use crate::nexus::effect::{Reader, State};
use crate::nexus::effects::writer::WriterEffect;
use crate::nexus::row::{ERROR_BIT, IO_BIT, READER_BIT, WRITER_BIT};
use crate::nexus::row::{EffectRow, Pure, Row};
pub struct Satisfied;
pub struct NotSatisfied;
pub trait IsPure {
const IS_PURE: bool;
}
impl IsPure for Pure {
const IS_PURE: bool = true;
}
impl<const BITS: u128> IsPure for Row<BITS> {
const IS_PURE: bool = BITS == 0;
}
pub trait IsIdempotent {
const IS_IDEMPOTENT: bool;
}
impl IsIdempotent for Pure {
const IS_IDEMPOTENT: bool = true;
}
impl<E> IsIdempotent for Reader<E> {
const IS_IDEMPOTENT: bool = true;
}
impl<const BITS: u128> IsIdempotent for Row<BITS> {
const IS_IDEMPOTENT: bool = BITS == 0 || BITS == READER_BIT;
}
pub trait IsTotal {
const IS_TOTAL: bool;
}
impl IsTotal for Pure {
const IS_TOTAL: bool = true;
}
impl<E> IsTotal for Reader<E> {
const IS_TOTAL: bool = true;
}
impl<S> IsTotal for State<S> {
const IS_TOTAL: bool = true;
}
impl<W> IsTotal for WriterEffect<W> {
const IS_TOTAL: bool = true;
}
impl<const BITS: u128> IsTotal for Row<BITS> {
const IS_TOTAL: bool = (BITS & ERROR_BIT) == 0 && (BITS & IO_BIT) == 0;
}
pub struct EffectProperties<R: EffectRow> {
_marker: PhantomData<R>,
}
impl<R: EffectRow> EffectProperties<R> {
pub const IS_PURE: bool = R::IS_PURE;
pub const IS_IDEMPOTENT: bool = R::BITS == 0 || R::BITS == READER_BIT;
pub const IS_TOTAL: bool = (R::BITS & ERROR_BIT) == 0 && (R::BITS & IO_BIT) == 0;
pub const IS_MONOTONIC: bool = R::BITS == 0 || R::BITS == WRITER_BIT;
pub const CAN_PARALLELIZE: bool = Self::IS_PURE;
pub const CAN_MEMOIZE: bool = Self::IS_IDEMPOTENT;
pub const CAN_SPECULATE: bool = Self::IS_TOTAL;
}
pub struct AssertPure<R: EffectRow>(PhantomData<R>);
impl<R: EffectRow> AssertPure<R> {
pub const fn new() -> Self
where
R: IsPure,
{
AssertPure(PhantomData)
}
}
impl<R: EffectRow + IsPure> Default for AssertPure<R> {
#[inline]
fn default() -> Self {
Self::new()
}
}
pub struct AssertIdempotent<R: EffectRow>(PhantomData<R>);
impl<R: EffectRow> AssertIdempotent<R> {
pub const fn new() -> Self
where
R: IsIdempotent,
{
AssertIdempotent(PhantomData)
}
}
impl<R: EffectRow + IsIdempotent> Default for AssertIdempotent<R> {
#[inline]
fn default() -> Self {
Self::new()
}
}
pub struct AssertTotal<R: EffectRow>(PhantomData<R>);
impl<R: EffectRow> AssertTotal<R> {
pub const fn new() -> Self
where
R: IsTotal,
{
AssertTotal(PhantomData)
}
}
impl<R: EffectRow + IsTotal> Default for AssertTotal<R> {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OptimizationHint {
None,
Parallelize,
Memoize,
Speculate,
Fuse,
}
pub const fn optimization_hint<R: EffectRow>() -> OptimizationHint {
if R::IS_PURE {
OptimizationHint::Parallelize
} else if R::BITS == READER_BIT {
OptimizationHint::Memoize
} else if (R::BITS & ERROR_BIT) == 0 && (R::BITS & IO_BIT) == 0 {
OptimizationHint::Speculate
} else {
OptimizationHint::None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nexus::row::STATE_BIT;
#[test]
fn test_pure_is_pure() {
assert!(<Pure as IsPure>::IS_PURE);
assert!(<Row<0> as IsPure>::IS_PURE);
}
#[test]
fn test_state_is_not_pure() {
assert!(!<Row<STATE_BIT> as IsPure>::IS_PURE);
}
#[test]
fn test_reader_is_idempotent() {
assert!(<Row<READER_BIT> as IsIdempotent>::IS_IDEMPOTENT);
}
#[test]
fn test_writer_is_not_idempotent() {
assert!(!<Row<WRITER_BIT> as IsIdempotent>::IS_IDEMPOTENT);
}
#[test]
fn test_error_is_not_total() {
assert!(!<Row<ERROR_BIT> as IsTotal>::IS_TOTAL);
}
#[test]
fn test_state_is_total() {
assert!(<Row<STATE_BIT> as IsTotal>::IS_TOTAL);
}
#[test]
fn test_effect_properties_pure() {
assert!(EffectProperties::<Pure>::IS_PURE);
assert!(EffectProperties::<Pure>::IS_IDEMPOTENT);
assert!(EffectProperties::<Pure>::IS_TOTAL);
assert!(EffectProperties::<Pure>::CAN_PARALLELIZE);
assert!(EffectProperties::<Pure>::CAN_MEMOIZE);
assert!(EffectProperties::<Pure>::CAN_SPECULATE);
}
#[test]
fn test_effect_properties_reader() {
assert!(!EffectProperties::<Row<READER_BIT>>::IS_PURE);
assert!(EffectProperties::<Row<READER_BIT>>::IS_IDEMPOTENT);
assert!(EffectProperties::<Row<READER_BIT>>::IS_TOTAL);
assert!(!EffectProperties::<Row<READER_BIT>>::CAN_PARALLELIZE);
assert!(EffectProperties::<Row<READER_BIT>>::CAN_MEMOIZE);
assert!(EffectProperties::<Row<READER_BIT>>::CAN_SPECULATE);
}
#[test]
fn test_optimization_hint() {
assert_eq!(optimization_hint::<Pure>(), OptimizationHint::Parallelize);
assert_eq!(
optimization_hint::<Row<READER_BIT>>(),
OptimizationHint::Memoize
);
assert_eq!(
optimization_hint::<Row<STATE_BIT>>(),
OptimizationHint::Speculate
);
assert_eq!(optimization_hint::<Row<IO_BIT>>(), OptimizationHint::None);
}
}