vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Version + since_version helpers.
//!
//! Aliases for [`crate::spec::version`] so both the singular file
//! (which holds the canonical `Version` struct and
//! `CURRENT_VERSION` constant) and the plural module name used by
//! `PLAN.md` resolve. Code that references `crate::spec::versions`
//! sees the same types as `crate::spec::version`.
//!
//! Additionally, this module exposes `since_version` helpers that
//! enforce I13 (userspace stability) and I15 (certificate stability)
//! by refusing to accept an `OpSpec` whose `since_version` is greater
//! than `CURRENT_VERSION` — a contributor cannot backdate an op onto
//! an older schema version.

pub use crate::spec::version::{Version, CURRENT_VERSION, V1_0};

/// True when `since` is less than or equal to the current schema
/// version.
///
/// New ops must set `since_version: CURRENT_VERSION`; older values are
/// legal only for ops that genuinely shipped in an earlier version.
/// This predicate is the cheap check used by the builder before a spec
/// is admitted to the registry.
#[must_use]
#[inline]
pub fn is_backwards_compatible(since: Version) -> bool {
    since <= CURRENT_VERSION
}

/// Enforce I13: a Program valid under `since` must remain valid under
/// every later version.
///
/// Returns `Err` if the contributor tried to declare a future version
/// that does not exist yet. This prevents contributors from accidentally
/// or maliciously claiming that an op shipped in a schema version that
/// has not been released.
///
/// # Errors
///
/// Returns [`SinceVersionError::FutureVersion`] when `since` is greater
/// than `CURRENT_VERSION`.
#[inline]
pub fn check_since_version(since: Version) -> Result<(), SinceVersionError> {
    if since > CURRENT_VERSION {
        return Err(SinceVersionError::FutureVersion {
            declared: since,
            current: CURRENT_VERSION,
        });
    }
    Ok(())
}

/// Errors returned by [`check_since_version`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SinceVersionError {
    /// The declared `since_version` is ahead of the crate's
    /// `CURRENT_VERSION`. New ops must ship simultaneously with the
    /// version bump that introduces them.
    FutureVersion {
        /// The version the contributor declared.
        declared: Version,
        /// The current crate schema version.
        current: Version,
    },
}

impl core::fmt::Display for SinceVersionError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::FutureVersion { declared, current } => write!(
                f,
                "since_version {declared:?} is ahead of CURRENT_VERSION {current:?}. \
                 Fix: either ship a version bump that makes declared become the current, \
                 or set since_version to CURRENT_VERSION."
            ),
        }
    }
}

impl core::error::Error for SinceVersionError {}