use super::row_v2::{EffectId, EffectRow, EffectSet};
use core::marker::PhantomData;
pub trait InferEffectus<R: EffectRow> {}
pub struct EffectusWitness<E: EffectId, R: EffectRow> {
_effect: PhantomData<E>,
_row: PhantomData<R>,
}
impl<E: EffectId, R: EffectRow> EffectusWitness<E, R> {
#[inline]
pub const fn new() -> Self {
const {
assert!(
(R::MASK >> E::ID) & 1 == 1,
"effect row is missing the witnessed effect"
);
}
EffectusWitness {
_effect: PhantomData,
_row: PhantomData,
}
}
}
impl<E: EffectId, R: EffectRow> Default for EffectusWitness<E, R> {
fn default() -> Self {
Self::new()
}
}
impl<E: EffectId, R: EffectRow> Clone for EffectusWitness<E, R> {
fn clone(&self) -> Self {
*self
}
}
impl<E: EffectId, R: EffectRow> Copy for EffectusWitness<E, R> {}
pub struct EffectusBuilder<R: EffectRow> {
_row: PhantomData<R>,
}
impl Default for EffectusBuilder<EffectSet<0>> {
fn default() -> Self {
Self::new()
}
}
impl EffectusBuilder<EffectSet<0>> {
#[inline]
pub const fn new() -> Self {
EffectusBuilder { _row: PhantomData }
}
}
impl<const MASK: u128> EffectusBuilder<EffectSet<MASK>> {
#[inline]
pub fn add<E: EffectId, const NEXT: u128>(self) -> EffectusBuilder<EffectSet<NEXT>> {
EffectusBuilder { _row: PhantomData }
}
#[inline]
pub fn build(self) -> PhantomData<EffectSet<MASK>> {
PhantomData
}
}
pub type BuilderRow<B> = <B as HasRow>::Row;
pub trait HasRow {
type Row: EffectRow;
}
impl<R: EffectRow> HasRow for EffectusBuilder<R> {
type Row = R;
}
pub trait EffectTuple {
const MASK: u128;
}
impl EffectTuple for () {
const MASK: u128 = 0;
}
impl<E1: EffectId> EffectTuple for (E1,) {
const MASK: u128 = 1 << E1::ID;
}
impl<E1: EffectId, E2: EffectId> EffectTuple for (E1, E2) {
const MASK: u128 = (1 << E1::ID) | (1 << E2::ID);
}
impl<E1: EffectId, E2: EffectId, E3: EffectId> EffectTuple for (E1, E2, E3) {
const MASK: u128 = (1 << E1::ID) | (1 << E2::ID) | (1 << E3::ID);
}
impl<E1: EffectId, E2: EffectId, E3: EffectId, E4: EffectId> EffectTuple for (E1, E2, E3, E4) {
const MASK: u128 = (1 << E1::ID) | (1 << E2::ID) | (1 << E3::ID) | (1 << E4::ID);
}
impl<E1: EffectId, E2: EffectId, E3: EffectId, E4: EffectId, E5: EffectId> EffectTuple
for (E1, E2, E3, E4, E5)
{
const MASK: u128 =
(1 << E1::ID) | (1 << E2::ID) | (1 << E3::ID) | (1 << E4::ID) | (1 << E5::ID);
}
#[inline(always)]
pub fn assert_requires_effects<R: EffectRow, Effects: EffectTuple>() {
const {
assert!(
(R::MASK & Effects::MASK) == Effects::MASK,
"effect row is missing required effects"
);
}
}
pub trait RowEquivalent<Other: EffectRow>: EffectRow {}
impl RowEquivalent<EffectSet<0>> for EffectSet<0> {}
pub type Merged<const MASK: u128> = EffectSet<MASK>;
pub trait IsPure: EffectRow {
const IS_PURE: bool;
}
impl IsPure for EffectSet<0> {
const IS_PURE: bool = true;
}
pub struct EffectVar<const N: usize>;
impl<const N: usize> EffectId for EffectVar<N> {
const ID: u64 = N as u64;
const NAME: &'static str = "EffectVar";
}
pub type AnyEffects = EffectVar<0>;
#[cfg(test)]
mod tests {
use super::*;
use crate::effects::row_v2::{IoRow, builtin_ids};
use crate::effects::{ErrorEffectus, IoEffectus};
#[test]
fn test_effectus_witness() {
let _witness: EffectusWitness<IoEffectus, IoRow> = EffectusWitness::new();
}
#[test]
fn test_effectus_builder() {
let _builder = EffectusBuilder::<EffectSet<0>>::new()
.add::<IoEffectus, { 1 << builtin_ids::IO }>()
.add::<ErrorEffectus<&str>, { (1 << builtin_ids::IO) | (1 << builtin_ids::ERROR) }>();
}
fn requires_single<R: EffectRow>() {
assert_requires_effects::<R, (IoEffectus,)>();
}
#[test]
fn test_require_effects() {
requires_single::<IoRow>();
}
#[test]
fn test_is_pure() {
assert!(<EffectSet<0> as IsPure>::IS_PURE);
assert!(!IoRow::is_empty());
}
#[test]
fn test_effect_var() {
fn accepts_effect_id<E: EffectId>() {}
accepts_effect_id::<EffectVar<0>>();
accepts_effect_id::<AnyEffects>();
}
#[test]
fn test_merged_rows() {
type Combined = Merged<{ (1 << builtin_ids::IO) | (1 << builtin_ids::ERROR) }>;
fn requires_row<R: EffectRow>() {}
requires_row::<Combined>();
}
fn with_proof<R: EffectRow>(_witness: EffectusWitness<IoEffectus, R>) {}
#[test]
fn test_witness_as_proof() {
let witness = EffectusWitness::<IoEffectus, IoRow>::new();
with_proof(witness);
}
}