qrism 0.1.0

A Rust library for generating and reading QR codes with Reed-Solomon error correction. Supports traditional monochromatic QR codes with additional experimental multicolor QR support for enhanced storage capacity.
Documentation
use std::{
    fmt,
    ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
};

use crate::utils::{QRError, QRResult};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct G(pub u8);

impl From<u8> for G {
    fn from(value: u8) -> Self {
        G(value)
    }
}

impl From<G> for u8 {
    fn from(g: G) -> Self {
        g.0
    }
}

impl fmt::Display for G {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Add for G {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        Self(self.0 ^ other.0)
    }
}

impl AddAssign for G {
    fn add_assign(&mut self, other: Self) {
        self.0 ^= other.0;
    }
}

impl Sub for G {
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        Self(self.0 ^ other.0)
    }
}

impl SubAssign for G {
    fn sub_assign(&mut self, other: Self) {
        self.0 ^= other.0;
    }
}

impl Mul<Self> for G {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
        if self.0 == 0 || rhs.0 == 0 {
            return Self(0);
        }

        let log_l = LOG_TABLE[self.0 as usize] as usize;
        let log_r = LOG_TABLE[rhs.0 as usize] as usize;

        let mut log_sum = log_l + log_r;
        if log_sum >= 255 {
            log_sum -= 255;
        }

        Self(EXP_TABLE[log_sum])
    }
}

impl MulAssign for G {
    fn mul_assign(&mut self, rhs: Self) {
        if self.0 == 0 || rhs.0 == 0 {
            self.0 = 0;
            return;
        }

        let log_l = LOG_TABLE[self.0 as usize] as usize;
        let log_r = LOG_TABLE[rhs.0 as usize] as usize;

        let mut log_sum = log_l + log_r;
        if log_sum >= 255 {
            log_sum -= 255;
        }

        self.0 = EXP_TABLE[log_sum];
    }
}

impl G {
    pub fn gen_pow(p: usize) -> G {
        debug_assert!(p < 256, "Generator power must be less than 256: Power {p}");
        Self(EXP_TABLE[p])
    }

    pub fn div(self, rhs: Self) -> QRResult<Self> {
        if rhs.0 == 0 {
            return Err(QRError::DivisionByZero);
        }
        if self.0 == 0 {
            return Ok(Self(0));
        }
        let log_l = LOG_TABLE[self.0 as usize] as usize;
        let log_r = LOG_TABLE[rhs.0 as usize] as usize;
        let log_sum = if log_l < log_r { 255 + log_l - log_r } else { log_l - log_r };
        Ok(Self(EXP_TABLE[log_sum]))
    }
}

// Global constants
//------------------------------------------------------------------------------

static LOG_TABLE: &[u8] = b"\
\xff\x00\x01\x19\x02\x32\x1a\xc6\x03\xdf\x33\xee\x1b\x68\xc7\x4b\
\x04\x64\xe0\x0e\x34\x8d\xef\x81\x1c\xc1\x69\xf8\xc8\x08\x4c\x71\
\x05\x8a\x65\x2f\xe1\x24\x0f\x21\x35\x93\x8e\xda\xf0\x12\x82\x45\
\x1d\xb5\xc2\x7d\x6a\x27\xf9\xb9\xc9\x9a\x09\x78\x4d\xe4\x72\xa6\
\x06\xbf\x8b\x62\x66\xdd\x30\xfd\xe2\x98\x25\xb3\x10\x91\x22\x88\
\x36\xd0\x94\xce\x8f\x96\xdb\xbd\xf1\xd2\x13\x5c\x83\x38\x46\x40\
\x1e\x42\xb6\xa3\xc3\x48\x7e\x6e\x6b\x3a\x28\x54\xfa\x85\xba\x3d\
\xca\x5e\x9b\x9f\x0a\x15\x79\x2b\x4e\xd4\xe5\xac\x73\xf3\xa7\x57\
\x07\x70\xc0\xf7\x8c\x80\x63\x0d\x67\x4a\xde\xed\x31\xc5\xfe\x18\
\xe3\xa5\x99\x77\x26\xb8\xb4\x7c\x11\x44\x92\xd9\x23\x20\x89\x2e\
\x37\x3f\xd1\x5b\x95\xbc\xcf\xcd\x90\x87\x97\xb2\xdc\xfc\xbe\x61\
\xf2\x56\xd3\xab\x14\x2a\x5d\x9e\x84\x3c\x39\x53\x47\x6d\x41\xa2\
\x1f\x2d\x43\xd8\xb7\x7b\xa4\x76\xc4\x17\x49\xec\x7f\x0c\x6f\xf6\
\x6c\xa1\x3b\x52\x29\x9d\x55\xaa\xfb\x60\x86\xb1\xbb\xcc\x3e\x5a\
\xcb\x59\x5f\xb0\x9c\xa9\xa0\x51\x0b\xf5\x16\xeb\x7a\x75\x2c\xd7\
\x4f\xae\xd5\xe9\xe6\xe7\xad\xe8\x74\xd6\xf4\xea\xa8\x50\x58\xaf";

static EXP_TABLE: &[u8] = b"\
\x01\x02\x04\x08\x10\x20\x40\x80\x1d\x3a\x74\xe8\xcd\x87\x13\x26\
\x4c\x98\x2d\x5a\xb4\x75\xea\xc9\x8f\x03\x06\x0c\x18\x30\x60\xc0\
\x9d\x27\x4e\x9c\x25\x4a\x94\x35\x6a\xd4\xb5\x77\xee\xc1\x9f\x23\
\x46\x8c\x05\x0a\x14\x28\x50\xa0\x5d\xba\x69\xd2\xb9\x6f\xde\xa1\
\x5f\xbe\x61\xc2\x99\x2f\x5e\xbc\x65\xca\x89\x0f\x1e\x3c\x78\xf0\
\xfd\xe7\xd3\xbb\x6b\xd6\xb1\x7f\xfe\xe1\xdf\xa3\x5b\xb6\x71\xe2\
\xd9\xaf\x43\x86\x11\x22\x44\x88\x0d\x1a\x34\x68\xd0\xbd\x67\xce\
\x81\x1f\x3e\x7c\xf8\xed\xc7\x93\x3b\x76\xec\xc5\x97\x33\x66\xcc\
\x85\x17\x2e\x5c\xb8\x6d\xda\xa9\x4f\x9e\x21\x42\x84\x15\x2a\x54\
\xa8\x4d\x9a\x29\x52\xa4\x55\xaa\x49\x92\x39\x72\xe4\xd5\xb7\x73\
\xe6\xd1\xbf\x63\xc6\x91\x3f\x7e\xfc\xe5\xd7\xb3\x7b\xf6\xf1\xff\
\xe3\xdb\xab\x4b\x96\x31\x62\xc4\x95\x37\x6e\xdc\xa5\x57\xae\x41\
\x82\x19\x32\x64\xc8\x8d\x07\x0e\x1c\x38\x70\xe0\xdd\xa7\x53\xa6\
\x51\xa2\x59\xb2\x79\xf2\xf9\xef\xc3\x9b\x2b\x56\xac\x45\x8a\x09\
\x12\x24\x48\x90\x3d\x7a\xf4\xf5\xf7\xf3\xfb\xeb\xcb\x8b\x0b\x16\
\x2c\x58\xb0\x7d\xfa\xe9\xcf\x83\x1b\x36\x6c\xd8\xad\x47\x8e\x01";