vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Reporter notification dispatch.
//!
//! Thin wrappers that fan out conformance events (start, pass, fail, done)
//! to all registered reporters. Each notification removes the reporter from
//! its slot, releases the lock, invokes user code, and then stores it back.

use crate::pipeline::reporter::Reporter;
use crate::spec::types::ParityFailure;
#[cfg(loom)]
use loom::sync::Mutex;
#[cfg(not(loom))]
use std::sync::Mutex;

/// Notify all reporters that an op has started testing.
#[inline]
pub(crate) fn start(reporters: &[Mutex<Option<Box<dyn Reporter>>>], op_id: &str, count: usize) {
    for reporter in reporters {
        with_reporter(reporter, |reporter| reporter.on_op_start(op_id, count));
    }
}

/// Notify all reporters that a single input passed.
#[inline]
pub(crate) fn pass(reporters: &[Mutex<Option<Box<dyn Reporter>>>], op_id: &str, label: &str) {
    for reporter in reporters {
        with_reporter(reporter, |reporter| reporter.on_pass(op_id, label));
    }
}

/// Notify all reporters that a single input failed.
#[inline]
pub(crate) fn fail(reporters: &[Mutex<Option<Box<dyn Reporter>>>], failure: &ParityFailure) {
    for reporter in reporters {
        with_reporter(reporter, |reporter| reporter.on_fail(failure));
    }
}

/// Notify all reporters that an op has finished all inputs.
#[inline]
pub(crate) fn done(
    reporters: &[Mutex<Option<Box<dyn Reporter>>>],
    op_id: &str,
    pass_count: usize,
    fail_count: usize,
) {
    for reporter in reporters {
        with_reporter(reporter, |reporter| {
            reporter.on_op_done(op_id, pass_count, fail_count);
        });
    }
}

fn with_reporter(slot: &Mutex<Option<Box<dyn Reporter>>>, call: impl FnOnce(&mut dyn Reporter)) {
    let Some(mut reporter) = take_reporter(slot) else {
        return;
    };
    call(reporter.as_mut());
    if let Ok(mut guard) = slot.lock() {
        if guard.is_none() {
            *guard = Some(reporter);
        }
    }
}

fn take_reporter(slot: &Mutex<Option<Box<dyn Reporter>>>) -> Option<Box<dyn Reporter>> {
    let Ok(mut guard) = slot.lock() else {
        return None;
    };
    guard.take()
}