use core::cmp::Ordering;
use super::Version;
use crate::cast::As;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Mode {
Numeric,
Alphanumeric,
Byte,
Kanji,
}
impl Mode {
#[must_use]
pub fn length_bits_count(self, version: Version) -> usize {
match version {
Version::Micro(a) => {
let a = a.as_usize();
match self {
Self::Numeric => 2 + a,
Self::Alphanumeric | Self::Byte => 1 + a,
Self::Kanji => a,
}
}
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,
},
Version::RectMicro(..) => {
let index = version.rect_micro_index().unwrap_or(31);
match self {
Self::Numeric => RMQR_LENGTH_BITS_COUNT[index][0],
Self::Alphanumeric => RMQR_LENGTH_BITS_COUNT[index][1],
Self::Byte => RMQR_LENGTH_BITS_COUNT[index][2],
Self::Kanji => RMQR_LENGTH_BITS_COUNT[index][3],
}
}
}
}
#[must_use]
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,
}
}
}
static RMQR_LENGTH_BITS_COUNT: [[usize; 4]; 32] = [
[4, 3, 3, 2],
[5, 5, 4, 3],
[6, 5, 5, 4],
[7, 6, 5, 5],
[7, 6, 6, 5],
[5, 5, 4, 3],
[6, 5, 5, 4],
[7, 6, 5, 5],
[7, 6, 6, 5],
[8, 7, 6, 6],
[4, 4, 3, 2],
[6, 5, 5, 4],
[7, 6, 5, 5],
[7, 6, 6, 5],
[8, 7, 6, 6],
[8, 7, 7, 6],
[5, 5, 4, 3],
[6, 6, 5, 5],
[7, 6, 6, 5],
[7, 7, 6, 6],
[8, 7, 7, 6],
[8, 8, 7, 7],
[7, 6, 6, 5],
[7, 7, 6, 5],
[8, 7, 7, 6],
[8, 7, 7, 6],
[9, 8, 7, 7],
[7, 6, 6, 5],
[8, 7, 6, 6],
[8, 7, 7, 6],
[8, 8, 7, 6],
[9, 8, 8, 7],
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mode_order() {
assert!(Mode::Numeric < Mode::Alphanumeric);
assert!(Mode::Byte > Mode::Kanji);
assert!(!(Mode::Numeric < Mode::Kanji));
assert!(!(Mode::Numeric >= Mode::Kanji));
}
#[test]
fn test_max() {
assert_eq!(Mode::Byte.max(Mode::Kanji), Mode::Byte);
assert_eq!(Mode::Numeric.max(Mode::Alphanumeric), Mode::Alphanumeric);
assert_eq!(
Mode::Alphanumeric.max(Mode::Alphanumeric),
Mode::Alphanumeric
);
assert_eq!(Mode::Numeric.max(Mode::Kanji), Mode::Byte);
assert_eq!(Mode::Kanji.max(Mode::Numeric), Mode::Byte);
assert_eq!(Mode::Alphanumeric.max(Mode::Numeric), Mode::Alphanumeric);
assert_eq!(Mode::Kanji.max(Mode::Kanji), Mode::Kanji);
}
}