use crate::cast::As;
use core::cmp::{Ordering, PartialOrd};
use core::default::Default;
use core::fmt::{Display, Error, Formatter};
use core::ops::Not;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum QrError {
DataTooLong,
InvalidVersion,
UnsupportedCharacterSet,
InvalidEciDesignator,
InvalidCharacter,
}
impl Display for QrError {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
let msg = match *self {
Self::DataTooLong => "data too long",
Self::InvalidVersion => "invalid version",
Self::UnsupportedCharacterSet => "unsupported character set",
Self::InvalidEciDesignator => "invalid ECI designator",
Self::InvalidCharacter => "invalid character",
};
fmt.write_str(msg)
}
}
pub type QrResult<T> = Result<T, QrError>;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Color {
Light,
Dark,
}
impl Color {
pub fn select<T>(self, dark: T, light: T) -> T {
match self {
Self::Light => light,
Self::Dark => dark,
}
}
}
impl Not for Color {
type Output = Self;
fn not(self) -> Self {
match self {
Self::Light => Self::Dark,
Self::Dark => Self::Light,
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
pub enum EcLevel {
L = 0,
M = 1,
Q = 2,
H = 3,
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Version {
Normal(i16),
}
impl Version {
pub const fn width(self) -> i16 {
match self {
Self::Normal(v) => v * 4 + 17,
}
}
pub fn fetch<T>(self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult<T>
where
T: PartialEq + Default + Copy,
{
if let Self::Normal(v @ 1..=40) = self {
return Ok(table[(v - 1).as_usize()][ec_level as usize]);
}
Err(QrError::InvalidVersion)
}
pub fn mode_bits_count(self) -> usize {
4
}
pub const fn is_micro(self) -> bool {
false
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Mode {
Numeric,
Alphanumeric,
Byte,
Kanji,
}
impl Mode {
pub fn length_bits_count(self, version: Version) -> usize {
match version {
Version::Normal(1..=9) => match self {
Self::Numeric => 10,
Self::Alphanumeric => 9,
Self::Byte | Self::Kanji => 8,
},
Version::Normal(10..=26) => match self {
Self::Numeric => 12,
Self::Alphanumeric => 11,
Self::Byte => 16,
Self::Kanji => 10,
},
Version::Normal(_) => match self {
Self::Numeric => 14,
Self::Alphanumeric => 13,
Self::Byte => 16,
Self::Kanji => 12,
},
}
}
pub const fn data_bits_count(self, raw_data_len: usize) -> usize {
match self {
Self::Numeric => (raw_data_len * 10).div_ceil(3),
Self::Alphanumeric => (raw_data_len * 11).div_ceil(2),
Self::Byte => raw_data_len * 8,
Self::Kanji => raw_data_len * 13,
}
}
#[must_use]
pub fn max(self, other: Self) -> Self {
match self.partial_cmp(&other) {
Some(Ordering::Greater) => self,
Some(_) => other,
None => Self::Byte,
}
}
}
impl PartialOrd for Mode {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (*self, *other) {
(a, b) if a == b => Some(Ordering::Equal),
(Self::Numeric, Self::Alphanumeric) | (_, Self::Byte) => Some(Ordering::Less),
(Self::Alphanumeric, Self::Numeric) | (Self::Byte, _) => Some(Ordering::Greater),
_ => None,
}
}
}
#[cfg(test)]
mod mode_tests {
use crate::types::Mode::{Alphanumeric, Byte, Kanji, Numeric};
#[test]
fn test_mode_order() {
assert!(Numeric < Alphanumeric);
assert!(Byte > Kanji);
}
#[test]
fn test_max() {
assert_eq!(Byte.max(Kanji), Byte);
assert_eq!(Numeric.max(Alphanumeric), Alphanumeric);
assert_eq!(Alphanumeric.max(Alphanumeric), Alphanumeric);
assert_eq!(Numeric.max(Kanji), Byte);
assert_eq!(Kanji.max(Numeric), Byte);
assert_eq!(Alphanumeric.max(Numeric), Alphanumeric);
assert_eq!(Kanji.max(Kanji), Kanji);
}
}