use core::hint::black_box;
use super::effect::Eff;
use super::effects::error::ErrorComputation;
use super::effects::reader::ReaderComputation;
use super::effects::state::StatefulComputation;
use super::row::Pure;
#[derive(Clone, Copy, Debug)]
pub struct Measurement {
pub iterations: u64,
pub correct: bool,
}
impl Measurement {
#[inline]
pub fn new(iterations: u64, correct: bool) -> Self {
Measurement {
iterations,
correct,
}
}
}
#[inline(never)]
pub fn measure_baseline<A, F: Fn() -> A>(f: F, iterations: u64) -> Measurement {
for _ in 0..iterations {
black_box(f());
}
Measurement::new(iterations, true)
}
#[inline(never)]
pub fn measure_pure_eff<A, F: Fn() -> Eff<Pure, A>>(f: F, iterations: u64) -> Measurement {
for _ in 0..iterations {
black_box(f().run_pure());
}
Measurement::new(iterations, true)
}
#[inline(never)]
pub fn measure_state<S: Clone + 'static, A: 'static, F: Fn() -> StatefulComputation<S, A>>(
f: F,
initial: S,
iterations: u64,
) -> Measurement {
for _ in 0..iterations {
let comp = f();
black_box(comp.run(initial.clone()));
}
Measurement::new(iterations, true)
}
#[inline(never)]
pub fn measure_reader<E: Clone + 'static, A: 'static, F: Fn() -> ReaderComputation<E, A>>(
f: F,
env: &E,
iterations: u64,
) -> Measurement {
for _ in 0..iterations {
let comp = f();
black_box(comp.run(env));
}
Measurement::new(iterations, true)
}
#[inline(never)]
pub fn measure_error<Err, A, F: Fn() -> ErrorComputation<Err, A>>(
f: F,
iterations: u64,
) -> Measurement {
for _ in 0..iterations {
let comp = f();
let _ = black_box(comp.run());
}
Measurement::new(iterations, true)
}
#[inline(never)]
pub fn measure_handwritten_state<S: Clone, A, F: Fn(S) -> (A, S)>(
f: F,
initial: S,
iterations: u64,
) -> Measurement {
for _ in 0..iterations {
black_box(f(initial.clone()));
}
Measurement::new(iterations, true)
}
#[inline(never)]
pub fn measure_handwritten_reader<E, A, F: Fn(&E) -> A>(
f: F,
env: &E,
iterations: u64,
) -> Measurement {
for _ in 0..iterations {
black_box(f(env));
}
Measurement::new(iterations, true)
}
#[inline(never)]
pub fn measure_handwritten_result<E, A, F: Fn() -> Result<A, E>>(
f: F,
iterations: u64,
) -> Measurement {
for _ in 0..iterations {
let _ = black_box(f());
}
Measurement::new(iterations, true)
}
pub fn verify_pure_semantics<A: PartialEq>(
baseline: impl Fn() -> A,
effectful: impl Fn() -> Eff<Pure, A>,
) -> bool {
baseline() == effectful().run_pure()
}
pub fn verify_state_semantics<S: Clone + PartialEq + 'static, A: PartialEq + 'static>(
handwritten: impl Fn(S) -> (A, S),
effectful: impl Fn() -> StatefulComputation<S, A>,
initial: S,
) -> bool {
let (a1, s1) = handwritten(initial.clone());
let (a2, s2) = effectful().run(initial);
a1 == a2 && s1 == s2
}
pub fn verify_reader_semantics<E: 'static, A: PartialEq + 'static>(
handwritten: impl Fn(&E) -> A,
effectful: impl Fn() -> ReaderComputation<E, A>,
env: &E,
) -> bool {
handwritten(env) == effectful().run(env)
}
pub fn verify_error_semantics<Err: PartialEq, A: PartialEq>(
handwritten: impl Fn() -> Result<A, Err>,
effectful: impl Fn() -> ErrorComputation<Err, A>,
) -> bool {
handwritten() == effectful().run()
}
#[derive(Clone, Copy, Debug)]
pub struct OverheadReport {
pub pattern: &'static str,
pub target: f64,
pub meets_target: bool,
}
impl OverheadReport {
#[inline]
pub fn new(pattern: &'static str, target: f64, actual: f64) -> Self {
OverheadReport {
pattern,
target,
meets_target: actual <= target,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nexus::ops::pure;
#[test]
fn test_verify_pure_semantics() {
assert!(verify_pure_semantics(|| 42, || pure(42),));
}
#[test]
fn test_verify_state_semantics() {
assert!(verify_state_semantics(
|s: i32| (s + 1, s + 10),
|| StatefulComputation::new(|s: i32| (s + 1, s + 10)),
5,
));
}
#[test]
fn test_verify_reader_semantics() {
assert!(verify_reader_semantics(
|e: &i32| e + 1,
|| ReaderComputation::new(|e: &i32| e + 1),
&10,
));
}
#[test]
fn test_verify_error_semantics() {
assert!(verify_error_semantics(
|| Ok::<i32, &str>(42),
|| ErrorComputation::ok(42),
));
}
#[test]
fn test_measure_baseline() {
let m = measure_baseline(|| 42, 100);
assert_eq!(m.iterations, 100);
assert!(m.correct);
}
#[test]
fn test_measure_pure_eff() {
let m = measure_pure_eff(|| pure(42), 100);
assert_eq!(m.iterations, 100);
assert!(m.correct);
}
#[test]
fn test_measure_state() {
let m = measure_state(|| StatefulComputation::new(|s: i32| (s + 1, s)), 0, 100);
assert_eq!(m.iterations, 100);
assert!(m.correct);
}
#[test]
fn test_measure_reader() {
let m = measure_reader(|| ReaderComputation::new(|e: &i32| *e + 1), &10, 100);
assert_eq!(m.iterations, 100);
assert!(m.correct);
}
#[test]
fn test_measure_error() {
let m = measure_error(|| ErrorComputation::<&str, i32>::ok(42), 100);
assert_eq!(m.iterations, 100);
assert!(m.correct);
}
}