use super::handler_apply::EffectRow;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EffectTypeError {
pub unpermitted: EffectRow,
}
pub const fn check_effect_row(
signature: EffectRow,
observed: EffectRow,
) -> Result<(), EffectTypeError> {
let unpermitted = observed.bits() & !signature.bits();
if unpermitted == 0 {
Ok(())
} else {
Err(EffectTypeError {
unpermitted: EffectRow::from_bits(unpermitted),
})
}
}
#[must_use]
pub const fn fits_signature(signature: EffectRow, observed: EffectRow) -> bool {
(observed.bits() & !signature.bits()) == 0
}
#[cfg(test)]
mod tests {
use super::super::handler_apply::EffectKind;
use super::*;
#[test]
fn empty_observed_always_fits() {
let sig = EffectRow::empty();
let observed = EffectRow::empty();
assert!(check_effect_row(sig, observed).is_ok());
assert!(fits_signature(sig, observed));
}
fn row_of(kinds: &[EffectKind]) -> EffectRow {
let mut r = EffectRow::empty();
for &k in kinds {
r = r.union(EffectRow::single(k));
}
r
}
#[test]
fn subset_fits() {
let sig = row_of(&[EffectKind::BufferWrite, EffectKind::Atomic]);
let observed = EffectRow::single(EffectKind::BufferWrite);
assert!(check_effect_row(sig, observed).is_ok());
}
#[test]
fn equal_rows_fit() {
let row = row_of(&[EffectKind::HostIo, EffectKind::GpuDispatch]);
assert!(fits_signature(row, row));
}
#[test]
fn excess_effect_pinpointed_in_unpermitted() {
let sig = EffectRow::single(EffectKind::BufferWrite);
let observed = row_of(&[EffectKind::BufferWrite, EffectKind::Atomic]);
let err = check_effect_row(sig, observed).unwrap_err();
assert_eq!(err.unpermitted, EffectRow::single(EffectKind::Atomic));
}
#[test]
fn empty_signature_rejects_everything() {
let sig = EffectRow::empty();
let observed = row_of(&[
EffectKind::BufferWrite,
EffectKind::Atomic,
EffectKind::HostIo,
EffectKind::GpuDispatch,
EffectKind::Barrier,
EffectKind::AsyncLoad,
EffectKind::Trap,
]);
let err = check_effect_row(sig, observed).unwrap_err();
assert_eq!(err.unpermitted, observed);
}
#[test]
fn wider_signature_accepts_narrow_observed() {
let sig = row_of(&[
EffectKind::BufferWrite,
EffectKind::Atomic,
EffectKind::HostIo,
]);
let observed = EffectRow::empty();
assert!(fits_signature(sig, observed));
}
#[test]
fn self_signature_is_identity() {
for kind in [
EffectKind::BufferWrite,
EffectKind::Atomic,
EffectKind::HostIo,
EffectKind::GpuDispatch,
EffectKind::Barrier,
EffectKind::AsyncLoad,
EffectKind::Trap,
] {
let row = EffectRow::single(kind);
assert!(fits_signature(row, row));
}
}
}