//! `plexus-vectors` — conformance fixtures and the harness that consumes them.
//!
//! Used as a `[dev-dependencies]` by the other crates (`ARCHITECTURE.md` §7).
//! The harness operates on in-memory byte slices so it stays `no_std`; the
//! consuming test supplies the expected bytes (e.g. via `include_bytes!`) and
//! the produced bytes from the encoder under test.
//!
//! Fixtures themselves live under `fixtures/` and are byte-exact captures from a
//! running reference. Capturing them requires a Python `RNS` reference and lands
//! in Phase 1 (§11.1); see `fixtures/README.md`.
#![no_std]
#![forbid(unsafe_code)]

/// The outcome of comparing produced bytes against an expected fixture.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VectorOutcome {
    /// Byte-for-byte identical.
    Match,
    /// Same length, but a byte differed.
    Mismatch {
        /// Index of the first differing byte.
        at: usize,
        /// Expected byte at `at`.
        expected: u8,
        /// Actual byte at `at`.
        actual: u8,
    },
    /// Lengths differed.
    LengthMismatch {
        /// Expected length.
        expected: usize,
        /// Actual length.
        actual: usize,
    },
}

/// Compare `produced` against `expected`, reporting the first divergence.
///
/// This is the core conformance assertion: encoders must reproduce captured
/// reference bytes exactly.
#[must_use]
pub fn compare(produced: &[u8], expected: &[u8]) -> VectorOutcome {
    if produced.len() != expected.len() {
        return VectorOutcome::LengthMismatch {
            expected: expected.len(),
            actual: produced.len(),
        };
    }
    for (at, (a, e)) in produced.iter().zip(expected.iter()).enumerate() {
        if a != e {
            return VectorOutcome::Mismatch {
                at,
                expected: *e,
                actual: *a,
            };
        }
    }
    VectorOutcome::Match
}

#[cfg(test)]
mod tests {
    use super::{compare, VectorOutcome};

    #[test]
    fn identical_slices_match() {
        assert_eq!(compare(&[1, 2, 3], &[1, 2, 3]), VectorOutcome::Match);
    }

    #[test]
    fn reports_first_mismatch() {
        assert_eq!(
            compare(&[1, 2, 9], &[1, 2, 3]),
            VectorOutcome::Mismatch {
                at: 2,
                expected: 3,
                actual: 9
            }
        );
    }

    #[test]
    fn reports_length_mismatch() {
        assert_eq!(
            compare(&[1, 2], &[1, 2, 3]),
            VectorOutcome::LengthMismatch {
                expected: 3,
                actual: 2
            }
        );
    }
}
