vyre_primitives/effects/
handler_compose.rs1use super::handler_apply::{EffectRow, Handler};
19
20#[must_use]
23#[inline]
24pub const fn handler_compose(a: Handler, b: Handler) -> Handler {
25 Handler::from_row(EffectRow::from_bits(
26 a.handled().bits() | b.handled().bits(),
27 ))
28}
29
30#[cfg(test)]
31mod tests {
32 use super::super::handler_apply::{handler_apply, EffectKind, EffectRow, Handler};
33 use super::handler_compose;
34
35 fn handler_for(kinds: &[EffectKind]) -> Handler {
36 let mut row = EffectRow::empty();
37 for k in kinds {
38 row = row.union(EffectRow::single(*k));
39 }
40 Handler::from_row(row)
41 }
42
43 #[test]
44 fn composed_handler_discharges_union() {
45 let a = Handler::single(EffectKind::BufferWrite);
46 let b = Handler::single(EffectKind::Atomic);
47 let composed = handler_compose(a, b);
48 assert!(composed.handled().contains(EffectKind::BufferWrite));
49 assert!(composed.handled().contains(EffectKind::Atomic));
50 assert!(!composed.handled().contains(EffectKind::HostIo));
51 }
52
53 #[test]
54 fn compose_is_commutative() {
55 let a = Handler::single(EffectKind::BufferWrite);
56 let b = Handler::single(EffectKind::Atomic);
57 assert_eq!(handler_compose(a, b), handler_compose(b, a));
58 }
59
60 #[test]
61 fn compose_is_associative() {
62 let a = Handler::single(EffectKind::BufferWrite);
63 let b = Handler::single(EffectKind::Atomic);
64 let c = Handler::single(EffectKind::HostIo);
65 assert_eq!(
66 handler_compose(a, handler_compose(b, c)),
67 handler_compose(handler_compose(a, b), c)
68 );
69 }
70
71 #[test]
72 fn identity_left_neutral() {
73 let id = Handler::from_row(EffectRow::empty());
74 let h = Handler::single(EffectKind::BufferWrite);
75 assert_eq!(
76 handler_compose(id, h).handled().bits(),
77 EffectKind::BufferWrite.mask()
78 );
79 }
80
81 #[test]
82 fn identity_right_neutral() {
83 let id = Handler::from_row(EffectRow::empty());
84 let h = Handler::single(EffectKind::BufferWrite);
85 assert_eq!(
86 handler_compose(h, id).handled().bits(),
87 EffectKind::BufferWrite.mask()
88 );
89 }
90
91 #[test]
92 fn idempotent_on_equal() {
93 let h = handler_for(&[EffectKind::BufferWrite, EffectKind::Atomic]);
94 let mask = EffectKind::BufferWrite.mask() | EffectKind::Atomic.mask();
95 assert_eq!(handler_compose(h, h).handled().bits(), mask);
96 }
97
98 #[test]
99 fn apply_compose_equals_apply_apply() {
100 let row = handler_for(&[
103 EffectKind::BufferWrite,
104 EffectKind::Atomic,
105 EffectKind::HostIo,
106 ])
107 .handled();
108 let a = Handler::single(EffectKind::BufferWrite);
109 let b = Handler::single(EffectKind::Atomic);
110 let lhs = handler_apply(row, handler_compose(a, b));
111 let rhs = handler_apply(handler_apply(row, a), b);
112 assert_eq!(lhs, rhs);
113 }
114
115 #[test]
116 fn composed_full_handler_discharges_full_row() {
117 let row = handler_for(&[
118 EffectKind::BufferWrite,
119 EffectKind::Atomic,
120 EffectKind::HostIo,
121 EffectKind::GpuDispatch,
122 ])
123 .handled();
124 let composed = handler_compose(
125 handler_for(&[EffectKind::BufferWrite, EffectKind::Atomic]),
126 handler_for(&[EffectKind::HostIo, EffectKind::GpuDispatch]),
127 );
128 assert!(handler_apply(row, composed).is_empty());
129 }
130}