//! Lehmer GCD step type for tracking remainder pairs during modular
//! inversion and extended GCD computations.

mod apply;
mod consts;
mod new;
mod steps_u128;
mod steps_u64;

/// State of a single Lehmer GCD iteration.
///
/// Stores the two 64-bit approximations `(a, b)` where `a >= b` extracted
/// from the top bits of the full-precision remainders, along with the 2×2
/// cofactor matrix accumulated from the mini-Euclidean loop.
///
/// The matrix `[[m00, m01], [m10, m11]]` encodes the combined effect of
/// multiple Euclidean steps. When `even` is true the matrix is applied as:
/// - `a' = m00*a - m01*b`
/// - `b' = m11*b - m10*a`
///
/// When `even` is false the signs are swapped.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LehmerStep {
    /// The larger remainder approximation.
    pub a: u64,
    /// The smaller remainder approximation.
    pub b: u64,
    /// Matrix entry (0,0).
    pub m00: u64,
    /// Matrix entry (0,1).
    pub m01: u64,
    /// Matrix entry (1,0).
    pub m10: u64,
    /// Matrix entry (1,1).
    pub m11: u64,
    /// Parity of the number of swaps performed.
    pub even: bool,
}

#[cfg(test)]
mod ai_tests {
    use super::*;

    /// Construction and field access for all fields.
    #[test]
    fn construct_and_access() {
        let step = LehmerStep {
            a: 10,
            b: 3,
            m00: 1,
            m01: 0,
            m10: 0,
            m11: 1,
            even: true,
        };
        assert_eq!(step.a, 10);
        assert_eq!(step.b, 3);
        assert_eq!(step.m00, 1);
        assert_eq!(step.m01, 0);
        assert_eq!(step.m10, 0);
        assert_eq!(step.m11, 1);
        assert!(step.even);
    }

    /// Copy semantics work correctly.
    #[test]
    fn copy_semantics() {
        let step = LehmerStep {
            a: 1,
            b: 0,
            m00: 5,
            m01: 3,
            m10: 2,
            m11: 7,
            even: false,
        };
        let copy = step;
        assert_eq!(step, copy);
    }

    /// Identity matrix with even parity.
    #[test]
    fn identity_matrix() {
        let step = LehmerStep {
            a: u64::MAX,
            b: 1,
            m00: 1,
            m01: 0,
            m10: 0,
            m11: 1,
            even: true,
        };
        assert_eq!(step.m00, 1);
        assert_eq!(step.m01, 0);
        assert_eq!(step.m10, 0);
        assert_eq!(step.m11, 1);
        assert!(step.even);
    }

    /// Odd parity after an odd number of swaps.
    #[test]
    fn odd_parity() {
        let step = LehmerStep {
            a: 7,
            b: 3,
            m00: 0,
            m01: 1,
            m10: 1,
            m11: 2,
            even: false,
        };
        assert!(!step.even);
        assert_eq!(step.m00, 0);
        assert_eq!(step.m01, 1);
        assert_eq!(step.m10, 1);
        assert_eq!(step.m11, 2);
    }
}
