Rustfmt and clippy.

This commit is contained in:
kennytm 2017-11-07 16:23:50 +08:00
parent 8be25fa56a
commit 21efb6205e
18 changed files with 1948 additions and 1324 deletions

View file

@ -15,20 +15,16 @@ addons:
matrix: matrix:
include: include:
- os: linux - os: linux
rust: 1.17.0 rust: 1.20.0
- os: linux - os: linux
rust: 1.21.0 rust: stable
- os: osx - os: osx
rust: 1.21.0 rust: stable
- os: linux - os: linux
rust: beta rust: beta
- os: linux - os: linux
rust: nightly rust: nightly
matrix:
allow_failures:
- rust: beta
install: install:
- if [ "$TRAVIS_OS_NAME" = 'linux' ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi - if [ "$TRAVIS_OS_NAME" = 'linux' ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi
- rustup target add i686-$OS - rustup target add i686-$OS

View file

@ -21,6 +21,7 @@ maintenance = { status = "passively-maintained" }
[dependencies] [dependencies]
image = { version = "0.17", optional = true } image = { version = "0.17", optional = true }
checked_int_cast = "1"
[features] [features]
default = ["image", "svg"] default = ["image", "svg"]

View file

@ -13,14 +13,14 @@ Cargo.toml
```toml ```toml
[dependencies] [dependencies]
qrcode = "0.4" qrcode = "0.5"
``` ```
The default settings will depend on the `image` crate. If you don't need image generation capability, disable the `default-features`: The default settings will depend on the `image` crate. If you don't need image generation capability, disable the `default-features`:
```toml ```toml
[dependencies] [dependencies]
qrcode = { version = "0.4", default-features = false } qrcode = { version = "0.5", default-features = false }
``` ```
Example Example

View file

@ -1,5 +1,5 @@
extern crate qrcode;
extern crate image; extern crate image;
extern crate qrcode;
use qrcode::QrCode; use qrcode::QrCode;
use image::Luma; use image::Luma;

View file

@ -1,6 +1,6 @@
extern crate qrcode; extern crate qrcode;
use qrcode::{QrCode, Version, EcLevel}; use qrcode::{EcLevel, QrCode, Version};
use qrcode::render::svg; use qrcode::render::svg;
fn main() { fn main() {

8
rustfmt.toml Normal file
View file

@ -0,0 +1,8 @@
array_width = 100
chain_width = 100
fn_call_width = 100
# single_line_if_else_max_width = 100
struct_lit_width = 100
struct_variant_width = 100
error_on_line_overflow = false

View file

@ -6,9 +6,11 @@ pub fn main() {
let arg = env::args().nth(1).unwrap(); let arg = env::args().nth(1).unwrap();
let code = qrcode::QrCode::new(arg.as_bytes()).unwrap(); let code = qrcode::QrCode::new(arg.as_bytes()).unwrap();
print!("{}", code.render() print!(
"{}",
code.render()
.dark_color("\x1b[7m \x1b[0m") .dark_color("\x1b[7m \x1b[0m")
.light_color("\x1b[49m \x1b[0m") .light_color("\x1b[49m \x1b[0m")
.build()); .build()
);
} }

View file

@ -5,8 +5,9 @@ use std::cmp::min;
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
use test::Bencher; use test::Bencher;
use types::{QrResult, QrError, Mode, EcLevel, Version}; use types::{EcLevel, Mode, QrError, QrResult, Version};
use optimize::{Parser, Optimizer, total_encoded_len, Segment}; use optimize::{total_encoded_len, Optimizer, Parser, Segment};
use cast::{As, Truncate};
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
//{{{ Bits //{{{ Bits
@ -20,8 +21,8 @@ pub struct Bits {
impl Bits { impl Bits {
/// Constructs a new, empty bits structure. /// Constructs a new, empty bits structure.
pub fn new(version: Version) -> Bits { pub fn new(version: Version) -> Self {
Bits { data: Vec::new(), bit_offset: 0, version: version } Self { data: Vec::new(), bit_offset: 0, version: version }
} }
/// Pushes an N-bit big-endian integer to the end of the bits. /// Pushes an N-bit big-endian integer to the end of the bits.
@ -30,29 +31,34 @@ impl Bits {
/// `n` bit in size. Otherwise the excess bits may stomp on the existing /// `n` bit in size. Otherwise the excess bits may stomp on the existing
/// ones. /// ones.
fn push_number(&mut self, n: usize, number: u16) { fn push_number(&mut self, n: usize, number: u16) {
debug_assert!(n == 16 || n < 16 && number < (1 << n), debug_assert!(
"{} is too big as a {}-bit number", number, n); n == 16 || n < 16 && number < (1 << n),
"{} is too big as a {}-bit number",
number,
n
);
let b = self.bit_offset + n; let b = self.bit_offset + n;
let last_index = self.data.len().wrapping_sub(1);
match (self.bit_offset, b) { match (self.bit_offset, b) {
(0, 0...8) => { (0, 0...8) => {
self.data.push((number << (8-b)) as u8); self.data.push((number << (8 - b)).truncate_as_u8());
} }
(0, _) => { (0, _) => {
self.data.push((number >> (b-8)) as u8); self.data.push((number >> (b - 8)).truncate_as_u8());
self.data.push((number << (16-b)) as u8); self.data.push((number << (16 - b)).truncate_as_u8());
} }
(_, 0...8) => { (_, 0...8) => {
*self.data.last_mut().unwrap() |= (number << (8-b)) as u8; self.data[last_index] |= (number << (8 - b)).truncate_as_u8();
} }
(_, 9...16) => { (_, 9...16) => {
*self.data.last_mut().unwrap() |= (number >> (b-8)) as u8; self.data[last_index] |= (number >> (b - 8)).truncate_as_u8();
self.data.push((number << (16-b)) as u8); self.data.push((number << (16 - b)).truncate_as_u8());
} }
_ => { _ => {
*self.data.last_mut().unwrap() |= (number >> (b-8)) as u8; self.data[last_index] |= (number >> (b - 8)).truncate_as_u8();
self.data.push((number >> (b-16)) as u8); self.data.push((number >> (b - 16)).truncate_as_u8());
self.data.push((number << (24-b)) as u8); self.data.push((number << (24 - b)).truncate_as_u8());
} }
} }
self.bit_offset = b & 7; self.bit_offset = b & 7;
@ -66,7 +72,7 @@ impl Bits {
if n > 16 || number >= (1 << n) { if n > 16 || number >= (1 << n) {
Err(QrError::DataTooLong) Err(QrError::DataTooLong)
} else { } else {
self.push_number(n, number as u16); self.push_number(n, number.as_u16());
Ok(()) Ok(())
} }
} }
@ -91,6 +97,11 @@ impl Bits {
} }
} }
/// Whether there are any bits pushed.
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
/// The maximum number of bits allowed by the provided QR code version and /// The maximum number of bits allowed by the provided QR code version and
/// error correction level. /// error correction level.
pub fn max_len(&self, ec_level: EcLevel) -> QrResult<usize> { pub fn max_len(&self, ec_level: EcLevel) -> QrResult<usize> {
@ -118,14 +129,19 @@ fn test_push_number() {
let bytes = bits.into_bytes(); let bytes = bits.into_bytes();
assert_eq!(bytes, vec![0b010__110__10, // 90 assert_eq!(
bytes,
vec![
0b010__110__10, // 90
0b1__001_1010, // 154 0b1__001_1010, // 154
0b1100__1011, // 203 0b1100__1011, // 203
0b0110_1101, // 109 0b0110_1101, // 109
0b01_1001_00, // 100 0b01_1001_00, // 100
0b01__111_001, // 121 0b01__111_001, // 121
0b0_1110_001, // 113 0b0_1110_001, // 113
0b1__0000000]); // 128 0b1__0000000, // 128
]
);
} }
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
@ -171,6 +187,7 @@ impl Bits {
/// If the mode is not supported in the provided version, this method /// If the mode is not supported in the provided version, this method
/// returns `Err(QrError::UnsupportedCharacterSet)`. /// returns `Err(QrError::UnsupportedCharacterSet)`.
pub fn push_mode_indicator(&mut self, mode: ExtendedMode) -> QrResult<()> { pub fn push_mode_indicator(&mut self, mode: ExtendedMode) -> QrResult<()> {
#[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
let number = match (self.version, mode) { let number = match (self.version, mode) {
(Version::Micro(1), ExtendedMode::Data(Mode::Numeric)) => return Ok(()), (Version::Micro(1), ExtendedMode::Data(Mode::Numeric)) => return Ok(()),
(Version::Micro(_), ExtendedMode::Data(Mode::Numeric)) => 0, (Version::Micro(_), ExtendedMode::Data(Mode::Numeric)) => 0,
@ -188,7 +205,8 @@ impl Bits {
(_, ExtendedMode::StructuredAppend) => 0b0011, (_, ExtendedMode::StructuredAppend) => 0b0011,
}; };
let bits = self.version.mode_bits_count(); let bits = self.version.mode_bits_count();
self.push_number_checked(bits, number).or(Err(QrError::UnsupportedCharacterSet)) self.push_number_checked(bits, number)
.or(Err(QrError::UnsupportedCharacterSet))
} }
} }
@ -234,19 +252,19 @@ impl Bits {
/// return `Err(QrError::InvalidECIDesignator)`. /// return `Err(QrError::InvalidECIDesignator)`.
pub fn push_eci_designator(&mut self, eci_designator: u32) -> QrResult<()> { pub fn push_eci_designator(&mut self, eci_designator: u32) -> QrResult<()> {
self.reserve(12); // assume the common case that eci_designator <= 127. self.reserve(12); // assume the common case that eci_designator <= 127.
try!(self.push_mode_indicator(ExtendedMode::Eci)); self.push_mode_indicator(ExtendedMode::Eci)?;
match eci_designator { match eci_designator {
0...127 => { 0...127 => {
self.push_number(8, eci_designator as u16); self.push_number(8, eci_designator.as_u16());
} }
128...16383 => { 128...16383 => {
self.push_number(2, 0b10); self.push_number(2, 0b10);
self.push_number(14, eci_designator as u16); self.push_number(14, eci_designator.as_u16());
} }
16384...999999 => { 16384...999999 => {
self.push_number(3, 0b110); self.push_number(3, 0b110);
self.push_number(5, (eci_designator >> 16) as u16); self.push_number(5, (eci_designator >> 16).as_u16());
self.push_number(16, (eci_designator & 0xffff) as u16); self.push_number(16, (eci_designator & 0xffff).as_u16());
} }
_ => return Err(QrError::InvalidEciDesignator), _ => return Err(QrError::InvalidEciDesignator),
} }
@ -257,7 +275,7 @@ impl Bits {
#[cfg(test)] #[cfg(test)]
mod eci_tests { mod eci_tests {
use bits::Bits; use bits::Bits;
use types::{Version, QrError}; use types::{QrError, Version};
#[test] #[test]
fn test_9() { fn test_9() {
@ -277,10 +295,7 @@ mod eci_tests {
fn test_999999() { fn test_999999() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_eci_designator(999999), Ok(())); assert_eq!(bits.push_eci_designator(999999), Ok(()));
assert_eq!(bits.into_bytes(), vec![0b0111__110_0, assert_eq!(bits.into_bytes(), vec![0b0111__110_0, 0b11110100, 0b00100011, 0b1111__0000]);
0b11110100,
0b00100011,
0b1111__0000]);
} }
#[test] #[test]
@ -304,8 +319,8 @@ impl Bits {
fn push_header(&mut self, mode: Mode, raw_data_len: usize) -> QrResult<()> { fn push_header(&mut self, mode: Mode, raw_data_len: usize) -> QrResult<()> {
let length_bits = mode.length_bits_count(self.version); let length_bits = mode.length_bits_count(self.version);
self.reserve(length_bits + 4 + mode.data_bits_count(raw_data_len)); self.reserve(length_bits + 4 + mode.data_bits_count(raw_data_len));
try!(self.push_mode_indicator(ExtendedMode::Data(mode))); self.push_mode_indicator(ExtendedMode::Data(mode))?;
try!(self.push_number_checked(length_bits, raw_data_len)); self.push_number_checked(length_bits, raw_data_len)?;
Ok(()) Ok(())
} }
@ -313,9 +328,12 @@ impl Bits {
/// ///
/// The data should only contain the characters 0 to 9. /// The data should only contain the characters 0 to 9.
pub fn push_numeric_data(&mut self, data: &[u8]) -> QrResult<()> { pub fn push_numeric_data(&mut self, data: &[u8]) -> QrResult<()> {
try!(self.push_header(Mode::Numeric, data.len())); self.push_header(Mode::Numeric, data.len())?;
for chunk in data.chunks(3) { for chunk in data.chunks(3) {
let number = chunk.iter().map(|b| (*b - b'0') as u16).fold(0, |a, b| a*10 + b); let number = chunk
.iter()
.map(|b| u16::from(*b - b'0'))
.fold(0, |a, b| a * 10 + b);
let length = chunk.len() * 3 + 1; let length = chunk.len() * 3 + 1;
self.push_number(length, number); self.push_number(length, number);
} }
@ -326,25 +344,26 @@ impl Bits {
#[cfg(test)] #[cfg(test)]
mod numeric_tests { mod numeric_tests {
use bits::Bits; use bits::Bits;
use types::{Version, QrError}; use types::{QrError, Version};
#[test] #[test]
fn test_iso_18004_2006_example_1() { fn test_iso_18004_2006_example_1() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_numeric_data(b"01234567"), Ok(())); assert_eq!(bits.push_numeric_data(b"01234567"), Ok(()));
assert_eq!(bits.into_bytes(), vec![0b0001_0000, assert_eq!(
0b001000_00, bits.into_bytes(),
0b00001100, vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b01_100001, 0b1__0000000]
0b01010110, );
0b01_100001,
0b1__0000000]);
} }
#[test] #[test]
fn test_iso_18004_2000_example_2() { fn test_iso_18004_2000_example_2() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(())); assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(()));
assert_eq!(bits.into_bytes(), vec![0b0001_0000, assert_eq!(
bits.into_bytes(),
vec![
0b0001_0000,
0b010000_00, 0b010000_00,
0b00001100, 0b00001100,
0b01010110, 0b01010110,
@ -352,21 +371,28 @@ mod numeric_tests {
0b0110_1110, 0b0110_1110,
0b000101_00, 0b000101_00,
0b11101010, 0b11101010,
0b0101__0000]); 0b0101__0000,
]
);
} }
#[test] #[test]
fn test_iso_18004_2006_example_2() { fn test_iso_18004_2006_example_2() {
let mut bits = Bits::new(Version::Micro(3)); let mut bits = Bits::new(Version::Micro(3));
assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(())); assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(()));
assert_eq!(bits.into_bytes(), vec![0b00_10000_0, assert_eq!(
bits.into_bytes(),
vec![
0b00_10000_0,
0b00000110, 0b00000110,
0b0_0101011, 0b0_0101011,
0b001_10101, 0b001_10101,
0b00110_111, 0b00110_111,
0b0000101_0, 0b0000101_0,
0b01110101, 0b01110101,
0b00101__000]); 0b00101__000,
]
);
} }
#[test] #[test]
@ -380,16 +406,16 @@ mod numeric_tests {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
//{{{ Mode::Alphanumeric mode //{{{ Mode::Alphanumeric mode
/// In QR code "Mode::Alphanumeric" mode, a pair of alphanumeric characters will be /// In QR code `Mode::Alphanumeric` mode, a pair of alphanumeric characters will
/// encoded as a base-45 integer. `alphanumeric_digit` converts each character /// be encoded as a base-45 integer. `alphanumeric_digit` converts each
/// into its corresponding base-45 digit. /// character into its corresponding base-45 digit.
/// ///
/// The conversion is specified in ISO/IEC 18004:2006, §8.4.3, Table 5. /// The conversion is specified in ISO/IEC 18004:2006, §8.4.3, Table 5.
#[inline] #[inline]
fn alphanumeric_digit(character: u8) -> u16 { fn alphanumeric_digit(character: u8) -> u16 {
match character { match character {
b'0' ... b'9' => (character - b'0') as u16, b'0'...b'9' => u16::from(character - b'0'),
b'A' ... b'Z' => (character - b'A') as u16 + 10, b'A'...b'Z' => u16::from(character - b'A') + 10,
b' ' => 36, b' ' => 36,
b'$' => 37, b'$' => 37,
b'%' => 38, b'%' => 38,
@ -409,9 +435,12 @@ impl Bits {
/// The data should only contain the charaters A to Z (excluding lowercase), /// The data should only contain the charaters A to Z (excluding lowercase),
/// 0 to 9, space, `$`, `%`, `*`, `+`, `-`, `.`, `/` or `:`. /// 0 to 9, space, `$`, `%`, `*`, `+`, `-`, `.`, `/` or `:`.
pub fn push_alphanumeric_data(&mut self, data: &[u8]) -> QrResult<()> { pub fn push_alphanumeric_data(&mut self, data: &[u8]) -> QrResult<()> {
try!(self.push_header(Mode::Alphanumeric, data.len())); self.push_header(Mode::Alphanumeric, data.len())?;
for chunk in data.chunks(2) { for chunk in data.chunks(2) {
let number = chunk.iter().map(|b| alphanumeric_digit(*b)).fold(0, |a, b| a*45 + b); let number = chunk
.iter()
.map(|b| alphanumeric_digit(*b))
.fold(0, |a, b| a * 45 + b);
let length = chunk.len() * 5 + 1; let length = chunk.len() * 5 + 1;
self.push_number(length, number); self.push_number(length, number);
} }
@ -422,18 +451,16 @@ impl Bits {
#[cfg(test)] #[cfg(test)]
mod alphanumeric_tests { mod alphanumeric_tests {
use bits::Bits; use bits::Bits;
use types::{Version, QrError}; use types::{QrError, Version};
#[test] #[test]
fn test_iso_18004_2006_example() { fn test_iso_18004_2006_example() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(())); assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(()));
assert_eq!(bits.into_bytes(), vec![0b0010_0000, assert_eq!(
0b00101_001, bits.into_bytes(),
0b11001110, vec![0b0010_0000, 0b00101_001, 0b11001110, 0b11100111, 0b001_00001, 0b0__0000000]
0b11100111, );
0b001_00001,
0b0__0000000]);
} }
#[test] #[test]
@ -456,9 +483,9 @@ mod alphanumeric_tests {
impl Bits { impl Bits {
/// Encodes 8-bit byte data to the bits. /// Encodes 8-bit byte data to the bits.
pub fn push_byte_data(&mut self, data: &[u8]) -> QrResult<()> { pub fn push_byte_data(&mut self, data: &[u8]) -> QrResult<()> {
try!(self.push_header(Mode::Byte, data.len())); self.push_header(Mode::Byte, data.len())?;
for b in data { for b in data {
self.push_number(8, *b as u16); self.push_number(8, u16::from(*b));
} }
Ok(()) Ok(())
} }
@ -467,13 +494,16 @@ impl Bits {
#[cfg(test)] #[cfg(test)]
mod byte_tests { mod byte_tests {
use bits::Bits; use bits::Bits;
use types::{Version, QrError}; use types::{QrError, Version};
#[test] #[test]
fn test() { fn test() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_byte_data(b"\x12\x34\x56\x78\x9a\xbc\xde\xf0"), Ok(())); assert_eq!(bits.push_byte_data(b"\x12\x34\x56\x78\x9a\xbc\xde\xf0"), Ok(()));
assert_eq!(bits.into_bytes(), vec![0b0100_0000, assert_eq!(
bits.into_bytes(),
vec![
0b0100_0000,
0b1000_0001, 0b1000_0001,
0b0010_0011, 0b0010_0011,
0b0100_0101, 0b0100_0101,
@ -482,7 +512,9 @@ mod byte_tests {
0b1010_1011, 0b1010_1011,
0b1100_1101, 0b1100_1101,
0b1110_1111, 0b1110_1111,
0b0000__0000]); 0b0000__0000,
]
);
} }
#[test] #[test]
@ -505,13 +537,17 @@ mod byte_tests {
impl Bits { impl Bits {
/// Encodes Shift JIS double-byte data to the bits. /// Encodes Shift JIS double-byte data to the bits.
pub fn push_kanji_data(&mut self, data: &[u8]) -> QrResult<()> { pub fn push_kanji_data(&mut self, data: &[u8]) -> QrResult<()> {
try!(self.push_header(Mode::Kanji, data.len()/2)); self.push_header(Mode::Kanji, data.len() / 2)?;
for kanji in data.chunks(2) { for kanji in data.chunks(2) {
if kanji.len() != 2 { if kanji.len() != 2 {
return Err(QrError::InvalidCharacter); return Err(QrError::InvalidCharacter);
} }
let cp = (kanji[0] as u16) * 256 + (kanji[1] as u16); let cp = u16::from(kanji[0]) * 256 + u16::from(kanji[1]);
let bytes = if cp < 0xe040 { cp - 0x8140 } else { cp - 0xc140 }; let bytes = if cp < 0xe040 {
cp - 0x8140
} else {
cp - 0xc140
};
let number = (bytes >> 8) * 0xc0 + (bytes & 0xff); let number = (bytes >> 8) * 0xc0 + (bytes & 0xff);
self.push_number(13, number); self.push_number(13, number);
} }
@ -522,17 +558,16 @@ impl Bits {
#[cfg(test)] #[cfg(test)]
mod kanji_tests { mod kanji_tests {
use bits::Bits; use bits::Bits;
use types::{Version, QrError}; use types::{QrError, Version};
#[test] #[test]
fn test_iso_18004_example() { fn test_iso_18004_example() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_kanji_data(b"\x93\x5f\xe4\xaa"), Ok(())); assert_eq!(bits.push_kanji_data(b"\x93\x5f\xe4\xaa"), Ok(()));
assert_eq!(bits.into_bytes(), vec![0b1000_0000, assert_eq!(
0b0010_0110, bits.into_bytes(),
0b11001111, vec![0b1000_0000, 0b0010_0110, 0b11001111, 0b1_1101010, 0b101010__00]
0b1_1101010, );
0b101010__00]);
} }
#[test] #[test]
@ -544,8 +579,10 @@ mod kanji_tests {
#[test] #[test]
fn test_data_too_long() { fn test_data_too_long() {
let mut bits = Bits::new(Version::Micro(3)); let mut bits = Bits::new(Version::Micro(3));
assert_eq!(bits.push_kanji_data(b"\x93_\x93_\x93_\x93_\x93_\x93_\x93_\x93_"), assert_eq!(
Err(QrError::DataTooLong)); bits.push_kanji_data(b"\x93_\x93_\x93_\x93_\x93_\x93_\x93_\x93_"),
Err(QrError::DataTooLong)
);
} }
} }
@ -593,8 +630,8 @@ impl Bits {
/// bits.push_fnc1_second_position(b'A' + 100); /// bits.push_fnc1_second_position(b'A' + 100);
/// ``` /// ```
pub fn push_fnc1_second_position(&mut self, application_indicator: u8) -> QrResult<()> { pub fn push_fnc1_second_position(&mut self, application_indicator: u8) -> QrResult<()> {
try!(self.push_mode_indicator(ExtendedMode::Fnc1Second)); self.push_mode_indicator(ExtendedMode::Fnc1Second)?;
self.push_number(8, application_indicator as u16); self.push_number(8, u16::from(application_indicator));
Ok(()) Ok(())
} }
} }
@ -646,7 +683,6 @@ static DATA_LENGTHS: [[usize; 4]; 44] = [
[21616, 16816, 12016, 9136], [21616, 16816, 12016, 9136],
[22496, 17728, 12656, 9776], [22496, 17728, 12656, 9776],
[23648, 18672, 13328, 10208], [23648, 18672, 13328, 10208],
// Micro versions // Micro versions
[20, 0, 0, 0], [20, 0, 0, 0],
[40, 32, 0, 0], [40, 32, 0, 0],
@ -658,12 +694,12 @@ impl Bits {
/// Pushes the ending bits to indicate no more data. /// Pushes the ending bits to indicate no more data.
pub fn push_terminator(&mut self, ec_level: EcLevel) -> QrResult<()> { pub fn push_terminator(&mut self, ec_level: EcLevel) -> QrResult<()> {
let terminator_size = match self.version { let terminator_size = match self.version {
Version::Micro(a) => (a as usize) * 2 + 1, Version::Micro(a) => a.as_usize() * 2 + 1,
_ => 4, _ => 4,
}; };
let cur_length = self.len(); let cur_length = self.len();
let data_length = try!(self.max_len(ec_level)); let data_length = self.max_len(ec_level)?;
if cur_length > data_length { if cur_length > data_length {
return Err(QrError::DataTooLong); return Err(QrError::DataTooLong);
} }
@ -679,7 +715,11 @@ impl Bits {
self.bit_offset = 0; self.bit_offset = 0;
let data_bytes_length = data_length / 8; let data_bytes_length = data_length / 8;
let padding_bytes_count = data_bytes_length - self.data.len(); let padding_bytes_count = data_bytes_length - self.data.len();
let padding = PADDING_BYTES.iter().cloned().cycle().take(padding_bytes_count); let padding = PADDING_BYTES
.iter()
.cloned()
.cycle()
.take(padding_bytes_count);
self.data.extend(padding); self.data.extend(padding);
} }
@ -694,18 +734,31 @@ impl Bits {
#[cfg(test)] #[cfg(test)]
mod finish_tests { mod finish_tests {
use bits::Bits; use bits::Bits;
use types::{Version, EcLevel, QrError}; use types::{EcLevel, QrError, Version};
#[test] #[test]
fn test_hello_world() { fn test_hello_world() {
let mut bits = Bits::new(Version::Normal(1)); let mut bits = Bits::new(Version::Normal(1));
assert_eq!(bits.push_alphanumeric_data(b"HELLO WORLD"), Ok(())); assert_eq!(bits.push_alphanumeric_data(b"HELLO WORLD"), Ok(()));
assert_eq!(bits.push_terminator(EcLevel::Q), Ok(())); assert_eq!(bits.push_terminator(EcLevel::Q), Ok(()));
assert_eq!(bits.into_bytes(), vec![0b00100000, 0b01011011, 0b00001011, assert_eq!(
0b01111000, 0b11010001, 0b01110010, bits.into_bytes(),
0b11011100, 0b01001101, 0b01000011, vec![
0b01000000, 0b11101100, 0b00010001, 0b00100000,
0b11101100]); 0b01011011,
0b00001011,
0b01111000,
0b11010001,
0b01110010,
0b11011100,
0b01001101,
0b01000011,
0b01000000,
0b11101100,
0b00010001,
0b11101100,
]
);
} }
#[test] #[test]
@ -755,16 +808,17 @@ mod finish_tests {
impl Bits { impl Bits {
/// Push a segmented data to the bits, and then terminate it. /// Push a segmented data to the bits, and then terminate it.
pub fn push_segments<I>(&mut self, data: &[u8], segments_iter: I) -> QrResult<()> pub fn push_segments<I>(&mut self, data: &[u8], segments_iter: I) -> QrResult<()>
where I: Iterator<Item=Segment> where
I: Iterator<Item = Segment>,
{ {
for segment in segments_iter { for segment in segments_iter {
let slice = &data[segment.begin..segment.end]; let slice = &data[segment.begin..segment.end];
try!(match segment.mode { match segment.mode {
Mode::Numeric => self.push_numeric_data(slice), Mode::Numeric => self.push_numeric_data(slice),
Mode::Alphanumeric => self.push_alphanumeric_data(slice), Mode::Alphanumeric => self.push_alphanumeric_data(slice),
Mode::Byte => self.push_byte_data(slice), Mode::Byte => self.push_byte_data(slice),
Mode::Kanji => self.push_kanji_data(slice), Mode::Kanji => self.push_kanji_data(slice),
}); }?;
} }
Ok(()) Ok(())
} }
@ -774,36 +828,50 @@ impl Bits {
let segments = Parser::new(data).optimize(self.version); let segments = Parser::new(data).optimize(self.version);
self.push_segments(data, segments) self.push_segments(data, segments)
} }
} }
#[cfg(test)] #[cfg(test)]
mod encode_tests { mod encode_tests {
use bits::Bits; use bits::Bits;
use types::{Version, QrError, QrResult, EcLevel}; use types::{EcLevel, QrError, QrResult, Version};
fn encode(data: &[u8], version: Version, ec_level: EcLevel) -> QrResult<Vec<u8>> { fn encode(data: &[u8], version: Version, ec_level: EcLevel) -> QrResult<Vec<u8>> {
let mut bits = Bits::new(version); let mut bits = Bits::new(version);
try!(bits.push_optimal_data(data)); bits.push_optimal_data(data)?;
try!(bits.push_terminator(ec_level)); bits.push_terminator(ec_level)?;
Ok(bits.into_bytes()) Ok(bits.into_bytes())
} }
#[test] #[test]
fn test_alphanumeric() { fn test_alphanumeric() {
let res = encode(b"HELLO WORLD", Version::Normal(1), EcLevel::Q); let res = encode(b"HELLO WORLD", Version::Normal(1), EcLevel::Q);
assert_eq!(res, Ok(vec![0b00100000, 0b01011011, 0b00001011, assert_eq!(
0b01111000, 0b11010001, 0b01110010, res,
0b11011100, 0b01001101, 0b01000011, Ok(vec![
0b01000000, 0b11101100, 0b00010001, 0b00100000,
0b11101100])); 0b01011011,
0b00001011,
0b01111000,
0b11010001,
0b01110010,
0b11011100,
0b01001101,
0b01000011,
0b01000000,
0b11101100,
0b00010001,
0b11101100,
])
);
} }
#[test] #[test]
fn test_auto_mode_switch() { fn test_auto_mode_switch() {
let res = encode(b"123A", Version::Micro(2), EcLevel::L); let res = encode(b"123A", Version::Micro(2), EcLevel::L);
assert_eq!(res, Ok(vec![0b0_0011_000, 0b1111011_1, 0b001_00101, assert_eq!(
0b0_00000__00, 0b11101100])); res,
Ok(vec![0b0_0011_000, 0b1111011_1, 0b001_00101, 0b0_00000__00, 0b11101100])
);
} }
#[test] #[test]
@ -824,15 +892,17 @@ mod encode_tests {
pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult<Bits> { pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult<Bits> {
let segments = Parser::new(data).collect::<Vec<Segment>>(); let segments = Parser::new(data).collect::<Vec<Segment>>();
for version in &[Version::Normal(9), Version::Normal(26), Version::Normal(40)] { for version in &[Version::Normal(9), Version::Normal(26), Version::Normal(40)] {
let opt_segments = Optimizer::new(segments.iter().map(|s| *s), *version).collect::<Vec<_>>(); let opt_segments = Optimizer::new(segments.iter().cloned(), *version).collect::<Vec<_>>();
let total_len = total_encoded_len(&*opt_segments, *version); let total_len = total_encoded_len(&*opt_segments, *version);
let data_capacity = version.fetch(ec_level, &DATA_LENGTHS).unwrap(); let data_capacity = version
.fetch(ec_level, &DATA_LENGTHS)
.expect("invalid DATA_LENGTHS");
if total_len <= data_capacity { if total_len <= data_capacity {
let min_version = find_min_version(total_len, ec_level); let min_version = find_min_version(total_len, ec_level);
let mut bits = Bits::new(min_version); let mut bits = Bits::new(min_version);
bits.reserve(total_len); bits.reserve(total_len);
try!(bits.push_segments(data, opt_segments.into_iter())); bits.push_segments(data, opt_segments.into_iter())?;
try!(bits.push_terminator(ec_level)); bits.push_terminator(ec_level)?;
return Ok(bits); return Ok(bits);
} }
} }
@ -852,13 +922,13 @@ fn find_min_version(length: usize, ec_level: EcLevel) -> Version {
max = half; max = half;
} }
} }
Version::Normal((min + 1) as i16) Version::Normal((min + 1).as_i16())
} }
#[cfg(test)] #[cfg(test)]
mod encode_auto_tests { mod encode_auto_tests {
use bits::{find_min_version, encode_auto}; use bits::{encode_auto, find_min_version};
use types::{Version, EcLevel}; use types::{EcLevel, Version};
#[test] #[test]
fn test_find_min_version() { fn test_find_min_version() {
@ -893,5 +963,3 @@ mod encode_auto_tests {
//}}} //}}}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

File diff suppressed because it is too large Load diff

90
src/cast.rs Normal file
View file

@ -0,0 +1,90 @@
use std::fmt::Display;
#[cfg(debug_assertions)]
use checked_int_cast::CheckedIntCast;
pub trait Truncate {
fn truncate_as_u8(self) -> u8;
}
impl Truncate for u16 {
#[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))]
fn truncate_as_u8(self) -> u8 {
(self & 0xff) as u8
}
}
pub trait As {
fn as_u16(self) -> u16;
fn as_i16(self) -> i16;
fn as_u32(self) -> u32;
fn as_usize(self) -> usize;
fn as_isize(self) -> isize;
}
trait ExpectOrOverflow {
type Output;
fn expect_or_overflow<D: Display>(self, value: D, ty: &str) -> Self::Output;
}
impl<T> ExpectOrOverflow for Option<T> {
type Output = T;
fn expect_or_overflow<D: Display>(self, value: D, ty: &str) -> Self::Output {
match self {
Some(v) => v,
None => panic!("{} overflows {}", value, ty),
}
}
}
macro_rules! impl_as {
($ty:ty) => {
#[cfg(debug_assertions)]
impl As for $ty {
fn as_u16(self) -> u16 {
self.as_u16_checked().expect_or_overflow(self, "u16")
}
fn as_i16(self) -> i16 {
self.as_i16_checked().expect_or_overflow(self, "i16")
}
fn as_u32(self) -> u32 {
self.as_u32_checked().expect_or_overflow(self, "u32")
}
fn as_usize(self) -> usize {
self.as_usize_checked().expect_or_overflow(self, "usize")
}
fn as_isize(self) -> isize {
self.as_isize_checked().expect_or_overflow(self, "usize")
}
}
#[cfg(not(debug_assertions))]
#[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))]
impl As for $ty {
fn as_u16(self) -> u16 {
self as u16
}
fn as_i16(self) -> i16 {
self as i16
}
fn as_u32(self) -> u32 {
self as u32
}
fn as_usize(self) -> usize {
self as usize
}
fn as_isize(self) -> isize {
self as isize
}
}
}
}
impl_as!(i16);
impl_as!(u32);
impl_as!(usize);
impl_as!(isize);

116
src/ec.rs
View file

@ -1,9 +1,8 @@
//! The `ec` module applies the Reed-Solomon error correction codes. //! The `ec` module applies the Reed-Solomon error correction codes.
use std::iter::repeat;
use std::ops::Deref; use std::ops::Deref;
use types::{QrResult, Version, EcLevel}; use types::{EcLevel, QrResult, Version};
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
//{{{ Error correction primitive //{{{ Error correction primitive
@ -18,25 +17,27 @@ use types::{QrResult, Version, EcLevel};
/// GF(256), and then computes the polynomial modulus with a generator /// GF(256), and then computes the polynomial modulus with a generator
/// polynomial of degree N. /// polynomial of degree N.
pub fn create_error_correction_code(data: &[u8], ec_code_size: usize) -> Vec<u8> { pub fn create_error_correction_code(data: &[u8], ec_code_size: usize) -> Vec<u8> {
let mut res = data.to_vec();
res.extend(repeat(0).take(ec_code_size));
let data_len = data.len(); let data_len = data.len();
let log_den = GENERATOR_POLYNOMIALS[ec_code_size]; let log_den = GENERATOR_POLYNOMIALS[ec_code_size];
let mut res = data.to_vec();
res.resize(ec_code_size + data_len, 0);
// rust-lang-nursery/rust-clippy#2213
#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
for i in 0..data_len { for i in 0..data_len {
let lead_coeff = res[i] as usize; let lead_coeff = res[i] as usize;
if lead_coeff == 0 { if lead_coeff == 0 {
continue; continue;
} }
let log_lead_coeff = LOG_TABLE[lead_coeff] as usize; let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]);
for (u, v) in res[i + 1..].iter_mut().zip(log_den.iter()) { for (u, v) in res[i + 1..].iter_mut().zip(log_den.iter()) {
*u ^= EXP_TABLE[((*v as usize + log_lead_coeff) % 255) as usize]; *u ^= EXP_TABLE[(usize::from(*v) + log_lead_coeff) % 255];
} }
} }
res.into_iter().skip(data_len).collect() res.split_off(data_len)
} }
#[cfg(test)] #[cfg(test)]
@ -73,8 +74,8 @@ mod ec_tests {
/// ///
/// The longest slice must be at the last of `blocks`, and `blocks` must not be /// The longest slice must be at the last of `blocks`, and `blocks` must not be
/// empty. /// empty.
fn interleave<T: Copy, V: Deref<Target=[T]>>(blocks: &Vec<V>) -> Vec<T> { fn interleave<T: Copy, V: Deref<Target = [T]>>(blocks: &[V]) -> Vec<T> {
let last_block_len = blocks.last().unwrap().len(); let last_block_len = blocks.last().expect("non-empty blocks").len();
let mut res = Vec::with_capacity(last_block_len * blocks.len()); let mut res = Vec::with_capacity(last_block_len * blocks.len());
for i in 0..last_block_len { for i in 0..last_block_len {
for t in blocks { for t in blocks {
@ -88,7 +89,7 @@ fn interleave<T: Copy, V: Deref<Target=[T]>>(blocks: &Vec<V>) -> Vec<T> {
#[test] #[test]
fn test_interleave() { fn test_interleave() {
let res = interleave(&vec![&b"1234"[..], b"5678", b"abcdef", b"ghijkl"]); let res = interleave(&[&b"1234"[..], b"5678", b"abcdef", b"ghijkl"]);
assert_eq!(&*res, b"15ag26bh37ci48djekfl"); assert_eq!(&*res, b"15ag26bh37ci48djekfl");
} }
@ -98,11 +99,13 @@ fn test_interleave() {
/// Constructs data and error correction codewords ready to be put in the QR /// Constructs data and error correction codewords ready to be put in the QR
/// code matrix. /// code matrix.
pub fn construct_codewords(rawbits: &[u8], pub fn construct_codewords(
rawbits: &[u8],
version: Version, version: Version,
ec_level: EcLevel) -> QrResult<(Vec<u8>, Vec<u8>)> { ec_level: EcLevel,
) -> QrResult<(Vec<u8>, Vec<u8>)> {
let (block_1_size, block_1_count, block_2_size, block_2_count) = let (block_1_size, block_1_count, block_2_size, block_2_count) =
try!(version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)); version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?;
let blocks_count = block_1_count + block_2_count; let blocks_count = block_1_count + block_2_count;
let block_1_end = block_1_size * block_1_count; let block_1_end = block_1_size * block_1_count;
@ -118,8 +121,9 @@ pub fn construct_codewords(rawbits: &[u8],
} }
// Generate EC codes. // Generate EC codes.
let ec_bytes = try!(version.fetch(ec_level, &EC_BYTES_PER_BLOCK)); let ec_bytes = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?;
let ec_codes = blocks.iter() let ec_codes = blocks
.iter()
.map(|block| create_error_correction_code(*block, ec_bytes)) .map(|block| create_error_correction_code(*block, ec_bytes))
.collect::<Vec<Vec<u8>>>(); .collect::<Vec<Vec<u8>>>();
@ -132,24 +136,34 @@ pub fn construct_codewords(rawbits: &[u8],
#[cfg(test)] #[cfg(test)]
mod construct_codewords_test { mod construct_codewords_test {
use ec::construct_codewords; use ec::construct_codewords;
use types::{Version, EcLevel}; use types::{EcLevel, Version};
#[test] #[test]
fn test_add_ec_simple() { fn test_add_ec_simple() {
let msg = b" [\x0bx\xd1r\xdcMC@\xec\x11\xec\x11\xec\x11"; let msg = b" [\x0bx\xd1r\xdcMC@\xec\x11\xec\x11\xec\x11";
let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(1), EcLevel::M).unwrap(); let (blocks_vec, ec_vec) =
construct_codewords(msg, Version::Normal(1), EcLevel::M).unwrap();
assert_eq!(&*blocks_vec, msg); assert_eq!(&*blocks_vec, msg);
assert_eq!(&*ec_vec, b"\xc4#'w\xeb\xd7\xe7\xe2]\x17"); assert_eq!(&*ec_vec, b"\xc4#'w\xeb\xd7\xe7\xe2]\x17");
} }
#[test] #[test]
fn test_add_ec_complex() { fn test_add_ec_complex() {
let msg = b"CUF\x86W&U\xc2w2\x06\x12\x06g&\xf6\xf6B\x07v\x86\xf2\x07&V\x16\xc6\xc7\x92\x06\xb6\xe6\xf7w2\x07v\x86W&R\x06\x86\x972\x07F\xf7vV\xc2\x06\x972\x10\xec\x11\xec\x11\xec\x11\xec"; let msg = b"CUF\x86W&U\xc2w2\x06\x12\x06g&\xf6\xf6B\x07v\x86\xf2\x07&V\x16\xc6\xc7\x92\x06\
let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(5), EcLevel::Q).unwrap(); \xb6\xe6\xf7w2\x07v\x86W&R\x06\x86\x972\x07F\xf7vV\xc2\x06\x972\x10\xec\x11\xec\
assert_eq!(&*blocks_vec, \x11\xec\x11\xec";
&b"C\xf6\xb6FU\xf6\xe6\xf7FB\xf7v\x86\x07wVWv2\xc2&\x86\x07\x06U\xf2v\x97\xc2\x07\x862w&W\x102V&\xec\x06\x16R\x11\x12\xc6\x06\xec\x06\xc7\x86\x11g\x92\x97\xec&\x062\x11\x07\xec"[..]); let expected_blocks = b"C\xf6\xb6FU\xf6\xe6\xf7FB\xf7v\x86\x07wVWv2\xc2&\x86\x07\x06U\xf2v\
assert_eq!(&*ec_vec, \x97\xc2\x07\x862w&W\x102V&\xec\x06\x16R\x11\x12\xc6\x06\xec\x06\
&b"\xd5W\x94\xeb\xc7\xcct\x9f\x0b`\xb1\x05-<\xd4\xads\xcaL\x18\xf7\xb6\x85\x93\xf1|K;\xdf\x9d\xf2!\xe5\xc8\xeej\xf8\x86L(\x9a\x1b\xc3\xffu\x81\xe6\xac\x9a\xd1\xbdRo\x11\n\x02V\xa3l\x83\xa1\xa3\xf0 ox\xc0\xb2'\x85\x8d\xec"[..]); \xc7\x86\x11g\x92\x97\xec&\x062\x11\x07\xec";
let expected_ec = b"\xd5W\x94\xeb\xc7\xcct\x9f\x0b`\xb1\x05-<\xd4\xads\xcaL\x18\xf7\xb6\x85\
\x93\xf1|K;\xdf\x9d\xf2!\xe5\xc8\xeej\xf8\x86L(\x9a\x1b\xc3\xffu\x81\
\xe6\xac\x9a\xd1\xbdRo\x11\n\x02V\xa3l\x83\xa1\xa3\xf0 ox\xc0\xb2'\x85\
\x8d\xec";
let (blocks_vec, ec_vec) =
construct_codewords(msg, Version::Normal(5), EcLevel::Q).unwrap();
assert_eq!(&*blocks_vec, &expected_blocks[..]);
assert_eq!(&*ec_vec, &expected_ec[..]);
} }
} }
@ -170,8 +184,8 @@ pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResult<usize
_ => 0, _ => 0,
}; };
let ec_bytes_per_block = try!(version.fetch(ec_level, &EC_BYTES_PER_BLOCK)); let ec_bytes_per_block = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?;
let (_, count1, _, count2) = try!(version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)); let (_, count1, _, count2) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?;
let ec_bytes = (count1 + count2) * ec_bytes_per_block; let ec_bytes = (count1 + count2) * ec_bytes_per_block;
Ok((ec_bytes - p) / 2) Ok((ec_bytes - p) / 2)
@ -180,7 +194,7 @@ pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResult<usize
#[cfg(test)] #[cfg(test)]
mod max_allowed_errors_test { mod max_allowed_errors_test {
use ec::max_allowed_errors; use ec::max_allowed_errors;
use types::{Version, EcLevel}; use types::{EcLevel, Version};
#[test] #[test]
fn test_low_versions() { fn test_low_versions() {
@ -231,10 +245,42 @@ mod max_allowed_errors_test {
//{{{ Precomputed tables for GF(256). //{{{ Precomputed tables for GF(256).
/// `EXP_TABLE` encodes the value of 2<sup>n</sup> in the Galois Field GF(256). /// `EXP_TABLE` encodes the value of 2<sup>n</sup> in the Galois Field GF(256).
static EXP_TABLE: &'static [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"; static EXP_TABLE: &'static [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";
/// `LOG_TABLE` is the inverse function of `EXP_TABLE`. /// `LOG_TABLE` is the inverse function of `EXP_TABLE`.
static LOG_TABLE: &'static [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 LOG_TABLE: &'static [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";
/// The generator polynomial list. /// The generator polynomial list.
/// ///
@ -245,6 +291,8 @@ static LOG_TABLE: &'static [u8] = b"\xff\x00\x01\x19\x02\x32\x1a\xc6\x03\xdf\x33
/// is the Reed-Solomon error correction code. /// is the Reed-Solomon error correction code.
/// ///
/// A partial list can be found from ISO/IEC 18004:2006 Annex A. /// A partial list can be found from ISO/IEC 18004:2006 Annex A.
#[cfg_attr(rustfmt, rustfmt_skip)]
// ^ this attribute is currently useless, see rust-lang-nursery/rustfmt#1080 and 1298
static GENERATOR_POLYNOMIALS: [&'static [u8]; 70] = [ static GENERATOR_POLYNOMIALS: [&'static [u8]; 70] = [
b"", b"",
b"\x00", b"\x00",
@ -339,7 +387,6 @@ static EC_BYTES_PER_BLOCK: [[usize; 4]; 44] = [
[24, 22, 22, 26], // 8 [24, 22, 22, 26], // 8
[30, 22, 20, 24], // 9 [30, 22, 20, 24], // 9
[18, 26, 24, 28], // 10 [18, 26, 24, 28], // 10
[20, 30, 28, 24], // 11 [20, 30, 28, 24], // 11
[24, 22, 26, 28], // 12 [24, 22, 26, 28], // 12
[26, 22, 24, 22], // 13 [26, 22, 24, 22], // 13
@ -350,7 +397,6 @@ static EC_BYTES_PER_BLOCK: [[usize; 4]; 44] = [
[30, 26, 28, 28], // 18 [30, 26, 28, 28], // 18
[28, 26, 26, 26], // 19 [28, 26, 26, 26], // 19
[28, 26, 30, 28], // 20 [28, 26, 30, 28], // 20
[28, 26, 28, 30], // 21 [28, 26, 28, 30], // 21
[28, 28, 30, 24], // 22 [28, 28, 30, 24], // 22
[30, 28, 30, 30], // 23 [30, 28, 30, 30], // 23
@ -361,7 +407,6 @@ static EC_BYTES_PER_BLOCK: [[usize; 4]; 44] = [
[30, 28, 30, 30], // 28 [30, 28, 30, 30], // 28
[30, 28, 30, 30], // 29 [30, 28, 30, 30], // 29
[30, 28, 30, 30], // 30 [30, 28, 30, 30], // 30
[30, 28, 30, 30], // 31 [30, 28, 30, 30], // 31
[30, 28, 30, 30], // 32 [30, 28, 30, 30], // 32
[30, 28, 30, 30], // 33 [30, 28, 30, 30], // 33
@ -372,7 +417,6 @@ static EC_BYTES_PER_BLOCK: [[usize; 4]; 44] = [
[30, 28, 30, 30], // 38 [30, 28, 30, 30], // 38
[30, 28, 30, 30], // 39 [30, 28, 30, 30], // 39
[30, 28, 30, 30], // 40 [30, 28, 30, 30], // 40
// Micro versions. // Micro versions.
[2, 0, 0, 0], // M1 [2, 0, 0, 0], // M1
[5, 6, 0, 0], // M2 [5, 6, 0, 0], // M2
@ -401,7 +445,6 @@ static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [
[(97, 2, 0, 0), (38, 2, 39, 2), (18, 4, 19, 2), (14, 4, 15, 2)], // 8 [(97, 2, 0, 0), (38, 2, 39, 2), (18, 4, 19, 2), (14, 4, 15, 2)], // 8
[(116, 2, 0, 0), (36, 3, 37, 2), (16, 4, 17, 4), (12, 4, 13, 4)], // 9 [(116, 2, 0, 0), (36, 3, 37, 2), (16, 4, 17, 4), (12, 4, 13, 4)], // 9
[(68, 2, 69, 2), (43, 4, 44, 1), (19, 6, 20, 2), (15, 6, 16, 2)], // 10 [(68, 2, 69, 2), (43, 4, 44, 1), (19, 6, 20, 2), (15, 6, 16, 2)], // 10
[(81, 4, 0, 0), (50, 1, 51, 4), (22, 4, 23, 4), (12, 3, 13, 8)], // 11 [(81, 4, 0, 0), (50, 1, 51, 4), (22, 4, 23, 4), (12, 3, 13, 8)], // 11
[(92, 2, 93, 2), (36, 6, 37, 2), (20, 4, 21, 6), (14, 7, 15, 4)], // 12 [(92, 2, 93, 2), (36, 6, 37, 2), (20, 4, 21, 6), (14, 7, 15, 4)], // 12
[(107, 4, 0, 0), (37, 8, 38, 1), (20, 8, 21, 4), (11, 12, 12, 4)], // 13 [(107, 4, 0, 0), (37, 8, 38, 1), (20, 8, 21, 4), (11, 12, 12, 4)], // 13
@ -412,7 +455,6 @@ static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [
[(120, 5, 121, 1), (43, 9, 44, 4), (22, 17, 23, 1), (14, 2, 15, 19)], // 18 [(120, 5, 121, 1), (43, 9, 44, 4), (22, 17, 23, 1), (14, 2, 15, 19)], // 18
[(113, 3, 114, 4), (44, 3, 45, 11), (21, 17, 22, 4), (13, 9, 14, 16)], // 19 [(113, 3, 114, 4), (44, 3, 45, 11), (21, 17, 22, 4), (13, 9, 14, 16)], // 19
[(107, 3, 108, 5), (41, 3, 42, 13), (24, 15, 25, 5), (15, 15, 16, 10)], // 20 [(107, 3, 108, 5), (41, 3, 42, 13), (24, 15, 25, 5), (15, 15, 16, 10)], // 20
[(116, 4, 117, 4), (42, 17, 0, 0), (22, 17, 23, 6), (16, 19, 17, 6)], // 21 [(116, 4, 117, 4), (42, 17, 0, 0), (22, 17, 23, 6), (16, 19, 17, 6)], // 21
[(111, 2, 112, 7), (46, 17, 0, 0), (24, 7, 25, 16), (13, 34, 0, 0)], // 22 [(111, 2, 112, 7), (46, 17, 0, 0), (24, 7, 25, 16), (13, 34, 0, 0)], // 22
[(121, 4, 122, 5), (47, 4, 48, 14), (24, 11, 25, 14), (15, 16, 16, 14)], // 23 [(121, 4, 122, 5), (47, 4, 48, 14), (24, 11, 25, 14), (15, 16, 16, 14)], // 23
@ -423,7 +465,6 @@ static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [
[(117, 3, 118, 10), (45, 3, 46, 23), (24, 4, 25, 31), (15, 11, 16, 31)], // 28 [(117, 3, 118, 10), (45, 3, 46, 23), (24, 4, 25, 31), (15, 11, 16, 31)], // 28
[(116, 7, 117, 7), (45, 21, 46, 7), (23, 1, 24, 37), (15, 19, 16, 26)], // 29 [(116, 7, 117, 7), (45, 21, 46, 7), (23, 1, 24, 37), (15, 19, 16, 26)], // 29
[(115, 5, 116, 10), (47, 19, 48, 10), (24, 15, 25, 25), (15, 23, 16, 25)], // 30 [(115, 5, 116, 10), (47, 19, 48, 10), (24, 15, 25, 25), (15, 23, 16, 25)], // 30
[(115, 13, 116, 3), (46, 2, 47, 29), (24, 42, 25, 1), (15, 23, 16, 28)], // 31 [(115, 13, 116, 3), (46, 2, 47, 29), (24, 42, 25, 1), (15, 23, 16, 28)], // 31
[(115, 17, 0, 0), (46, 10, 47, 23), (24, 10, 25, 35), (15, 19, 16, 35)], // 32 [(115, 17, 0, 0), (46, 10, 47, 23), (24, 10, 25, 35), (15, 19, 16, 35)], // 32
[(115, 17, 116, 1), (46, 14, 47, 21), (24, 29, 25, 19), (15, 11, 16, 46)], // 33 [(115, 17, 116, 1), (46, 14, 47, 21), (24, 29, 25, 19), (15, 11, 16, 46)], // 33
@ -434,7 +475,6 @@ static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [
[(122, 4, 123, 18), (46, 13, 47, 32), (24, 48, 25, 14), (15, 42, 16, 32)], // 38 [(122, 4, 123, 18), (46, 13, 47, 32), (24, 48, 25, 14), (15, 42, 16, 32)], // 38
[(117, 20, 118, 4), (47, 40, 48, 7), (24, 43, 25, 22), (15, 10, 16, 67)], // 39 [(117, 20, 118, 4), (47, 40, 48, 7), (24, 43, 25, 22), (15, 10, 16, 67)], // 39
[(118, 19, 119, 6), (47, 18, 48, 31), (24, 34, 25, 34), (15, 20, 16, 61)], // 40 [(118, 19, 119, 6), (47, 18, 48, 31), (24, 34, 25, 34), (15, 20, 16, 61)], // 40
// Micro versions. // Micro versions.
[(3, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M1 [(3, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M1
[(5, 1, 0, 0), (4, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M2 [(5, 1, 0, 0), (4, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M2
@ -443,5 +483,3 @@ static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [
]; ];
//}}} //}}}

View file

@ -30,9 +30,16 @@
//! ``` //! ```
#![cfg_attr(feature = "bench", feature(test))] // Unstable libraries #![cfg_attr(feature = "bench", feature(test))] // Unstable libraries
#![cfg_attr(feature = "cargo-clippy", deny(warnings, clippy_pedantic))]
#![cfg_attr(feature = "cargo-clippy",
allow(unreadable_literal, missing_docs_in_private_items, shadow_reuse,
range_plus_one))]
#[cfg(feature="bench")] extern crate test; extern crate checked_int_cast;
#[cfg(feature="image")] extern crate image; #[cfg(feature = "image")]
extern crate image;
#[cfg(feature = "bench")]
extern crate test;
use std::ops::Index; use std::ops::Index;
@ -42,10 +49,13 @@ pub mod optimize;
pub mod ec; pub mod ec;
pub mod canvas; pub mod canvas;
pub mod render; pub mod render;
mod cast;
pub use types::{QrResult, Color, EcLevel, Version}; pub use types::{Color, EcLevel, QrResult, Version};
use render::{Pixel, Renderer}; use render::{Pixel, Renderer};
use checked_int_cast::CheckedIntCast;
use cast::As;
/// The encoded QR code symbol. /// The encoded QR code symbol.
#[derive(Clone)] #[derive(Clone)]
@ -66,8 +76,8 @@ impl QrCode {
/// ///
/// let code = QrCode::new(b"Some data").unwrap(); /// let code = QrCode::new(b"Some data").unwrap();
/// ///
pub fn new<D: AsRef<[u8]>>(data: D) -> QrResult<QrCode> { pub fn new<D: AsRef<[u8]>>(data: D) -> QrResult<Self> {
QrCode::with_error_correction_level(data, EcLevel::M) Self::with_error_correction_level(data, EcLevel::M)
} }
/// Constructs a new QR code which automatically encodes the given data at a /// Constructs a new QR code which automatically encodes the given data at a
@ -79,9 +89,12 @@ impl QrCode {
/// ///
/// let code = QrCode::with_error_correction_level(b"Some data", EcLevel::H).unwrap(); /// let code = QrCode::with_error_correction_level(b"Some data", EcLevel::H).unwrap();
/// ///
pub fn with_error_correction_level<D: AsRef<[u8]>>(data: D, ec_level: EcLevel) -> QrResult<QrCode> { pub fn with_error_correction_level<D: AsRef<[u8]>>(
let bits = try!(bits::encode_auto(data.as_ref(), ec_level)); data: D,
QrCode::with_bits(bits, ec_level) ec_level: EcLevel,
) -> QrResult<Self> {
let bits = bits::encode_auto(data.as_ref(), ec_level)?;
Self::with_bits(bits, ec_level)
} }
/// Constructs a new QR code for the given version and error correction /// Constructs a new QR code for the given version and error correction
@ -97,11 +110,15 @@ impl QrCode {
/// ///
/// let micro_code = QrCode::with_version(b"123", Version::Micro(1), EcLevel::L).unwrap(); /// let micro_code = QrCode::with_version(b"123", Version::Micro(1), EcLevel::L).unwrap();
/// ///
pub fn with_version<D: AsRef<[u8]>>(data: D, version: Version, ec_level: EcLevel) -> QrResult<QrCode> { pub fn with_version<D: AsRef<[u8]>>(
data: D,
version: Version,
ec_level: EcLevel,
) -> QrResult<Self> {
let mut bits = bits::Bits::new(version); let mut bits = bits::Bits::new(version);
try!(bits.push_optimal_data(data.as_ref())); bits.push_optimal_data(data.as_ref())?;
try!(bits.push_terminator(ec_level)); bits.push_terminator(ec_level)?;
QrCode::with_bits(bits, ec_level) Self::with_bits(bits, ec_level)
} }
/// Constructs a new QR code with encoded bits. /// Constructs a new QR code with encoded bits.
@ -126,19 +143,19 @@ impl QrCode {
/// bits.push_terminator(EcLevel::L); /// bits.push_terminator(EcLevel::L);
/// let qrcode = QrCode::with_bits(bits, EcLevel::L); /// let qrcode = QrCode::with_bits(bits, EcLevel::L);
/// ///
pub fn with_bits(bits: bits::Bits, ec_level: EcLevel) -> QrResult<QrCode> { pub fn with_bits(bits: bits::Bits, ec_level: EcLevel) -> QrResult<Self> {
let version = bits.version(); let version = bits.version();
let data = bits.into_bytes(); let data = bits.into_bytes();
let (encoded_data, ec_data) = try!(ec::construct_codewords(&*data, version, ec_level)); let (encoded_data, ec_data) = ec::construct_codewords(&*data, version, ec_level)?;
let mut canvas = canvas::Canvas::new(version, ec_level); let mut canvas = canvas::Canvas::new(version, ec_level);
canvas.draw_all_functional_patterns(); canvas.draw_all_functional_patterns();
canvas.draw_data(&*encoded_data, &*ec_data); canvas.draw_data(&*encoded_data, &*ec_data);
let canvas = canvas.apply_best_mask(); let canvas = canvas.apply_best_mask();
Ok(QrCode { Ok(Self {
content: canvas.into_colors(), content: canvas.into_colors(),
version: version, version: version,
ec_level: ec_level, ec_level: ec_level,
width: version.width() as usize, width: version.width().as_usize(),
}) })
} }
@ -163,13 +180,17 @@ impl QrCode {
/// before the data becomes corrupted. Note that errors should not be /// before the data becomes corrupted. Note that errors should not be
/// introduced to functional modules. /// introduced to functional modules.
pub fn max_allowed_errors(&self) -> usize { pub fn max_allowed_errors(&self) -> usize {
ec::max_allowed_errors(self.version, self.ec_level).unwrap() ec::max_allowed_errors(self.version, self.ec_level).expect("invalid version or ec_level")
} }
/// Checks whether a module at coordinate (x, y) is a functional module or /// Checks whether a module at coordinate (x, y) is a functional module or
/// not. /// not.
pub fn is_functional(&self, x: usize, y: usize) -> bool { pub fn is_functional(&self, x: usize, y: usize) -> bool {
canvas::is_functional(self.version, self.version.width(), x as i16, y as i16) let x = x.as_i16_checked()
.expect("coordinate is too large for QR code");
let y = y.as_i16_checked()
.expect("coordinate is too large for QR code");
canvas::is_functional(self.version, self.version.width(), x, y)
} }
/// Converts the QR code into a human-readable string. This is mainly for /// Converts the QR code into a human-readable string. This is mainly for
@ -193,7 +214,10 @@ impl QrCode {
/// color of the module, with "true" means dark and "false" means light. /// color of the module, with "true" means dark and "false" means light.
#[deprecated(since = "0.4.0", note = "use `into_colors()` instead")] #[deprecated(since = "0.4.0", note = "use `into_colors()` instead")]
pub fn into_vec(self) -> Vec<bool> { pub fn into_vec(self) -> Vec<bool> {
self.content.into_iter().map(|c| c != Color::Light).collect() self.content
.into_iter()
.map(|c| c != Color::Light)
.collect()
} }
/// Converts the QR code to a vector of colors. /// Converts the QR code to a vector of colors.
@ -250,13 +274,15 @@ impl Index<(usize, usize)> for QrCode {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use {QrCode, Version, EcLevel}; use {EcLevel, QrCode, Version};
#[test] #[test]
fn test_annex_i_qr() { fn test_annex_i_qr() {
// This uses the ISO Annex I as test vector. // This uses the ISO Annex I as test vector.
let code = QrCode::with_version(b"01234567", Version::Normal(1), EcLevel::M).unwrap(); let code = QrCode::with_version(b"01234567", Version::Normal(1), EcLevel::M).unwrap();
assert_eq!(&*code.to_debug_str('#', '.'), "\ assert_eq!(
&*code.to_debug_str('#', '.'),
"\
#######..#.##.#######\n\ #######..#.##.#######\n\
#.....#..####.#.....#\n\ #.....#..####.#.....#\n\
#.###.#.#.....#.###.#\n\ #.###.#.#.....#.###.#\n\
@ -277,13 +303,16 @@ mod tests {
#.###.#.##..#..#.....\n\ #.###.#.##..#..#.....\n\
#.###.#.#.##.#..#.#..\n\ #.###.#.#.##.#..#.#..\n\
#.....#........##.##.\n\ #.....#........##.##.\n\
#######.####.#..#.#.."); #######.####.#..#.#.."
);
} }
#[test] #[test]
fn test_annex_i_micro_qr() { fn test_annex_i_micro_qr() {
let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
assert_eq!(&*code.to_debug_str('#', '.'), "\ assert_eq!(
&*code.to_debug_str('#', '.'),
"\
#######.#.#.#\n\ #######.#.#.#\n\
#.....#.###.#\n\ #.....#.###.#\n\
#.###.#..##.#\n\ #.###.#..##.#\n\
@ -296,20 +325,23 @@ mod tests {
.##.#.#.#.#.#\n\ .##.#.#.#.#.#\n\
###..#######.\n\ ###..#######.\n\
...#.#....##.\n\ ...#.#....##.\n\
###.#..##.###"); ###.#..##.###"
);
} }
} }
#[cfg(all(test, feature = "image"))] #[cfg(all(test, feature = "image"))]
mod image_tests { mod image_tests {
use image::{Luma, Rgb, load_from_memory}; use image::{load_from_memory, Luma, Rgb};
use {QrCode, Version, EcLevel}; use {EcLevel, QrCode, Version};
#[test] #[test]
fn test_annex_i_qr_as_image() { fn test_annex_i_qr_as_image() {
let code = QrCode::new(b"01234567").unwrap(); let code = QrCode::new(b"01234567").unwrap();
let image = code.render::<Luma<u8>>().build(); let image = code.render::<Luma<u8>>().build();
let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png")).unwrap().to_luma(); let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png"))
.unwrap()
.to_luma();
assert_eq!(image.dimensions(), expected.dimensions()); assert_eq!(image.dimensions(), expected.dimensions());
assert_eq!(image.into_raw(), expected.into_raw()); assert_eq!(image.into_raw(), expected.into_raw());
} }
@ -322,7 +354,9 @@ mod image_tests {
.dark_color(Rgb { data: [128, 0, 0] }) .dark_color(Rgb { data: [128, 0, 0] })
.light_color(Rgb { data: [255, 255, 128] }) .light_color(Rgb { data: [255, 255, 128] })
.build(); .build();
let expected = load_from_memory(include_bytes!("test_annex_i_micro_qr_as_image.png")).unwrap().to_rgb(); let expected = load_from_memory(include_bytes!("test_annex_i_micro_qr_as_image.png"))
.unwrap()
.to_rgb();
assert_eq!(image.dimensions(), expected.dimensions()); assert_eq!(image.dimensions(), expected.dimensions());
assert_eq!(image.into_raw(), expected.into_raw()); assert_eq!(image.into_raw(), expected.into_raw());
} }
@ -331,7 +365,7 @@ mod image_tests {
#[cfg(all(test, feature = "svg"))] #[cfg(all(test, feature = "svg"))]
mod svg_tests { mod svg_tests {
use render::svg::Color as SvgColor; use render::svg::Color as SvgColor;
use {QrCode, Version, EcLevel}; use {EcLevel, QrCode, Version};
#[test] #[test]
fn test_annex_i_qr_as_svg() { fn test_annex_i_qr_as_svg() {
@ -353,4 +387,3 @@ mod svg_tests {
assert_eq!(&image, expected); assert_eq!(&image, expected);
} }
} }

View file

@ -26,7 +26,11 @@ impl Segment {
/// length bits) when this segment is encoded. /// length bits) when this segment is encoded.
pub fn encoded_len(&self, version: Version) -> usize { pub fn encoded_len(&self, version: Version) -> usize {
let byte_size = self.end - self.begin; let byte_size = self.end - self.begin;
let chars_count = if self.mode == Mode::Kanji { byte_size / 2 } else { byte_size }; let chars_count = if self.mode == Mode::Kanji {
byte_size / 2
} else {
byte_size
};
let mode_bits_count = version.mode_bits_count(); let mode_bits_count = version.mode_bits_count();
let length_bits_count = self.mode.length_bits_count(version); let length_bits_count = self.mode.length_bits_count(version);
@ -115,24 +119,20 @@ impl<'a> Iterator for Parser<'a> {
if self.pending_single_byte { if self.pending_single_byte {
self.pending_single_byte = false; self.pending_single_byte = false;
self.begin += 1; self.begin += 1;
return Some(Segment { return Some(Segment { mode: Mode::Byte, begin: self.begin - 1, end: self.begin });
mode: Mode::Byte,
begin: self.begin-1,
end: self.begin,
});
} }
loop { loop {
let (i, ecs) = match self.ecs_iter.next() { let (i, ecs) = match self.ecs_iter.next() {
None => { return None; }, None => return None,
Some(a) => a Some(a) => a,
}; };
let (next_state, action) = STATE_TRANSITION[self.state as usize + ecs as usize]; let (next_state, action) = STATE_TRANSITION[self.state as usize + ecs as usize];
self.state = next_state; self.state = next_state;
let old_begin = self.begin; let old_begin = self.begin;
let push_mode = match action { let push_mode = match action {
Action::Idle => { continue; } Action::Idle => continue,
Action::Numeric => Mode::Numeric, Action::Numeric => Mode::Numeric,
Action::Alpha => Mode::Alphanumeric, Action::Alpha => Mode::Alphanumeric,
Action::Byte => Mode::Byte, Action::Byte => Mode::Byte,
@ -144,21 +144,15 @@ impl<'a> Iterator for Parser<'a> {
} else { } else {
self.pending_single_byte = true; self.pending_single_byte = true;
self.begin = next_begin; self.begin = next_begin;
return Some(Segment { return Some(
mode: Mode::Kanji, Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin },
begin: old_begin, );
end: next_begin,
});
} }
} }
}; };
self.begin = i; self.begin = i;
return Some(Segment { return Some(Segment { mode: push_mode, begin: old_begin, end: i });
mode: push_mode,
begin: old_begin,
end: i,
});
} }
} }
} }
@ -175,39 +169,59 @@ mod parse_tests {
#[test] #[test]
fn test_parse_1() { fn test_parse_1() {
let segs = parse(b"01049123451234591597033130128%10ABC123"); let segs = parse(b"01049123451234591597033130128%10ABC123");
assert_eq!(segs, vec![Segment { mode: Mode::Numeric, begin: 0, end: 29 }, assert_eq!(
segs,
vec![
Segment { mode: Mode::Numeric, begin: 0, end: 29 },
Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 }, Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 },
Segment { mode: Mode::Numeric, begin: 30, end: 32 }, Segment { mode: Mode::Numeric, begin: 30, end: 32 },
Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 }, Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 },
Segment { mode: Mode::Numeric, begin: 35, end: 38 }]); Segment { mode: Mode::Numeric, begin: 35, end: 38 },
]
);
} }
#[test] #[test]
fn test_parse_shift_jis_example_1() { fn test_parse_shift_jis_example_1() {
let segs = parse(b"\x82\xa0\x81\x41\x41\xb1\x81\xf0"); // "あ、AアÅ" let segs = parse(b"\x82\xa0\x81\x41\x41\xb1\x81\xf0"); // "あ、AアÅ"
assert_eq!(segs, vec![Segment { mode: Mode::Kanji, begin: 0, end: 4 }, assert_eq!(
segs,
vec![
Segment { mode: Mode::Kanji, begin: 0, end: 4 },
Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 }, Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 },
Segment { mode: Mode::Byte, begin: 5, end: 6 }, Segment { mode: Mode::Byte, begin: 5, end: 6 },
Segment { mode: Mode::Kanji, begin: 6, end: 8 }]); Segment { mode: Mode::Kanji, begin: 6, end: 8 },
]
);
} }
#[test] #[test]
fn test_parse_utf_8() { fn test_parse_utf_8() {
// Mojibake? // Mojibake?
let segs = parse(b"\xe3\x81\x82\xe3\x80\x81A\xef\xbd\xb1\xe2\x84\xab"); let segs = parse(b"\xe3\x81\x82\xe3\x80\x81A\xef\xbd\xb1\xe2\x84\xab");
assert_eq!(segs, vec![Segment { mode: Mode::Kanji, begin: 0, end: 4 }, assert_eq!(
segs,
vec![
Segment { mode: Mode::Kanji, begin: 0, end: 4 },
Segment { mode: Mode::Byte, begin: 4, end: 5 }, Segment { mode: Mode::Byte, begin: 4, end: 5 },
Segment { mode: Mode::Kanji, begin: 5, end: 7 }, Segment { mode: Mode::Kanji, begin: 5, end: 7 },
Segment { mode: Mode::Byte, begin: 7, end: 10 }, Segment { mode: Mode::Byte, begin: 7, end: 10 },
Segment { mode: Mode::Kanji, begin: 10, end: 12 }, Segment { mode: Mode::Kanji, begin: 10, end: 12 },
Segment { mode: Mode::Byte, begin: 12, end: 13 }]); Segment { mode: Mode::Byte, begin: 12, end: 13 },
]
);
} }
#[test] #[test]
fn test_not_kanji_1() { fn test_not_kanji_1() {
let segs = parse(b"\x81\x30"); let segs = parse(b"\x81\x30");
assert_eq!(segs, vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, assert_eq!(
Segment { mode: Mode::Numeric, begin: 1, end: 2 }]); segs,
vec![
Segment { mode: Mode::Byte, begin: 0, end: 1 },
Segment { mode: Mode::Numeric, begin: 1, end: 2 },
]
);
} }
#[test] #[test]
@ -215,22 +229,37 @@ mod parse_tests {
// Note that it's implementation detail that the byte seq is split into // Note that it's implementation detail that the byte seq is split into
// two. Perhaps adjust the test to check for this. // two. Perhaps adjust the test to check for this.
let segs = parse(b"\xeb\xc0"); let segs = parse(b"\xeb\xc0");
assert_eq!(segs, vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, assert_eq!(
Segment { mode: Mode::Byte, begin: 1, end: 2 }]); segs,
vec![
Segment { mode: Mode::Byte, begin: 0, end: 1 },
Segment { mode: Mode::Byte, begin: 1, end: 2 },
]
);
} }
#[test] #[test]
fn test_not_kanji_3() { fn test_not_kanji_3() {
let segs = parse(b"\x81\x7f"); let segs = parse(b"\x81\x7f");
assert_eq!(segs, vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, assert_eq!(
Segment { mode: Mode::Byte, begin: 1, end: 2 }]); segs,
vec![
Segment { mode: Mode::Byte, begin: 0, end: 1 },
Segment { mode: Mode::Byte, begin: 1, end: 2 },
]
);
} }
#[test] #[test]
fn test_not_kanji_4() { fn test_not_kanji_4() {
let segs = parse(b"\x81\x40\x81"); let segs = parse(b"\x81\x40\x81");
assert_eq!(segs, vec![Segment { mode: Mode::Kanji, begin: 0, end: 2 }, assert_eq!(
Segment { mode: Mode::Byte, begin: 2, end: 3 }]); segs,
vec![
Segment { mode: Mode::Kanji, begin: 0, end: 2 },
Segment { mode: Mode::Byte, begin: 2, end: 3 },
]
);
} }
} }
@ -238,6 +267,7 @@ mod parse_tests {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
//{{{ Optimizer //{{{ Optimizer
#[cfg_attr(feature = "cargo-clippy", allow(stutter))] // rust-lang-nursery/rust-clippy#2212 ಠ_ಠ
pub struct Optimizer<I> { pub struct Optimizer<I> {
parser: I, parser: I,
last_segment: Segment, last_segment: Segment,
@ -253,16 +283,16 @@ impl<I: Iterator<Item=Segment>> Optimizer<I> {
/// left to right until the new segment is longer than before. This method /// left to right until the new segment is longer than before. This method
/// does *not* use Annex J from the ISO standard. /// does *not* use Annex J from the ISO standard.
/// ///
pub fn new(mut segments: I, version: Version) -> Optimizer<I> { pub fn new(mut segments: I, version: Version) -> Self {
match segments.next() { match segments.next() {
None => Optimizer { None => Self {
parser: segments, parser: segments,
last_segment: Segment { mode: Mode::Numeric, begin: 0, end: 0 }, last_segment: Segment { mode: Mode::Numeric, begin: 0, end: 0 },
last_segment_size: 0, last_segment_size: 0,
version: version, version: version,
ended: true, ended: true,
}, },
Some(segment) => Optimizer { Some(segment) => Self {
parser: segments, parser: segments,
last_segment: segment, last_segment: segment,
last_segment_size: segment.encoded_len(version), last_segment_size: segment.encoded_len(version),
@ -321,12 +351,14 @@ impl<I: Iterator<Item=Segment>> Iterator for Optimizer<I> {
/// Computes the total encoded length of all segments. /// Computes the total encoded length of all segments.
pub fn total_encoded_len(segments: &[Segment], version: Version) -> usize { pub fn total_encoded_len(segments: &[Segment], version: Version) -> usize {
// TODO revert to `.map().sum()` after `sum()` is stable. // TODO revert to `.map().sum()` after `sum()` is stable.
segments.iter().fold(0, |acc, seg| acc + seg.encoded_len(version)) segments
.iter()
.fold(0, |acc, seg| acc + seg.encoded_len(version))
} }
#[cfg(test)] #[cfg(test)]
mod optimize_tests { mod optimize_tests {
use optimize::{Optimizer, total_encoded_len, Segment}; use optimize::{total_encoded_len, Optimizer, Segment};
use types::{Mode, Version}; use types::{Mode, Version};
fn test_optimization_result(given: Vec<Segment>, expected: Vec<Segment>, version: Version) { fn test_optimization_result(given: Vec<Segment>, expected: Vec<Segment>, version: Version) {
@ -336,116 +368,114 @@ mod optimize_tests {
if given != opt_segs { if given != opt_segs {
assert!(prev_len > new_len, "{} > {}", prev_len, new_len); assert!(prev_len > new_len, "{} > {}", prev_len, new_len);
} }
assert!(opt_segs == expected, assert!(
opt_segs == expected,
"Optimization gave something better: {} < {} ({:?})", "Optimization gave something better: {} < {} ({:?})",
new_len, total_encoded_len(&*expected, version), opt_segs); new_len,
total_encoded_len(&*expected, version),
opt_segs
);
} }
#[test] #[test]
fn test_example_1() { fn test_example_1() {
test_optimization_result( test_optimization_result(
vec![
vec![Segment { mode: Mode::Alphanumeric, begin: 0, end: 3 }, Segment { mode: Mode::Alphanumeric, begin: 0, end: 3 },
Segment { mode: Mode::Numeric, begin: 3, end: 6 }, Segment { mode: Mode::Numeric, begin: 3, end: 6 },
Segment { mode: Mode::Byte, begin: 6, end: 10 }], Segment { mode: Mode::Byte, begin: 6, end: 10 },
],
vec![Segment { mode: Mode::Alphanumeric, begin: 0, end: 6 }, vec![
Segment { mode: Mode::Byte, begin: 6, end: 10 }], Segment { mode: Mode::Alphanumeric, begin: 0, end: 6 },
Segment { mode: Mode::Byte, begin: 6, end: 10 },
Version::Normal(1) ],
Version::Normal(1),
); );
} }
#[test] #[test]
fn test_example_2() { fn test_example_2() {
test_optimization_result( test_optimization_result(
vec![
vec![Segment { mode: Mode::Numeric, begin: 0, end: 29 }, Segment { mode: Mode::Numeric, begin: 0, end: 29 },
Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 }, Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 },
Segment { mode: Mode::Numeric, begin: 30, end: 32 }, Segment { mode: Mode::Numeric, begin: 30, end: 32 },
Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 }, Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 },
Segment { mode: Mode::Numeric, begin: 35, end: 38 }], Segment { mode: Mode::Numeric, begin: 35, end: 38 },
],
vec![Segment { mode: Mode::Numeric, begin: 0, end: 29 }, vec![
Segment { mode: Mode::Alphanumeric, begin: 29, end: 38 }], Segment { mode: Mode::Numeric, begin: 0, end: 29 },
Segment { mode: Mode::Alphanumeric, begin: 29, end: 38 },
Version::Normal(9) ],
Version::Normal(9),
); );
} }
#[test] #[test]
fn test_example_3() { fn test_example_3() {
test_optimization_result( test_optimization_result(
vec![
vec![Segment { mode: Mode::Kanji, begin: 0, end: 4 }, Segment { mode: Mode::Kanji, begin: 0, end: 4 },
Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 }, Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 },
Segment { mode: Mode::Byte, begin: 5, end: 6 }, Segment { mode: Mode::Byte, begin: 5, end: 6 },
Segment { mode: Mode::Kanji, begin: 6, end: 8 }], Segment { mode: Mode::Kanji, begin: 6, end: 8 },
],
vec![Segment { mode: Mode::Byte, begin: 0, end: 8 }], vec![Segment { mode: Mode::Byte, begin: 0, end: 8 }],
Version::Normal(1),
Version::Normal(1)
); );
} }
#[test] #[test]
fn test_example_4() { fn test_example_4() {
test_optimization_result( test_optimization_result(
vec![
vec![Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Kanji, begin: 0, end: 10 },
Segment { mode: Mode::Byte, begin: 10, end: 11 }], Segment { mode: Mode::Byte, begin: 10, end: 11 },
],
vec![Segment { mode: Mode::Kanji, begin: 0, end: 10 }, vec![
Segment { mode: Mode::Byte, begin: 10, end: 11 }], Segment { mode: Mode::Kanji, begin: 0, end: 10 },
Segment { mode: Mode::Byte, begin: 10, end: 11 },
Version::Normal(1) ],
Version::Normal(1),
); );
} }
#[test] #[test]
fn test_annex_j_guideline_1a() { fn test_annex_j_guideline_1a() {
test_optimization_result( test_optimization_result(
vec![
vec![Segment { mode: Mode::Numeric, begin: 0, end: 3 }, Segment { mode: Mode::Numeric, begin: 0, end: 3 },
Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }], Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
],
vec![Segment { mode: Mode::Numeric, begin: 0, end: 3 }, vec![
Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }], Segment { mode: Mode::Numeric, begin: 0, end: 3 },
Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
Version::Micro(2) ],
Version::Micro(2),
); );
} }
#[test] #[test]
fn test_annex_j_guideline_1b() { fn test_annex_j_guideline_1b() {
test_optimization_result( test_optimization_result(
vec![
vec![Segment { mode: Mode::Numeric, begin: 0, end: 2 }, Segment { mode: Mode::Numeric, begin: 0, end: 2 },
Segment { mode: Mode::Alphanumeric, begin: 2, end: 4 }], Segment { mode: Mode::Alphanumeric, begin: 2, end: 4 },
],
vec![Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }], vec![Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }],
Version::Micro(2),
Version::Micro(2)
); );
} }
#[test] #[test]
fn test_annex_j_guideline_1c() { fn test_annex_j_guideline_1c() {
test_optimization_result( test_optimization_result(
vec![
vec![Segment { mode: Mode::Numeric, begin: 0, end: 3 }, Segment { mode: Mode::Numeric, begin: 0, end: 3 },
Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }], Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
],
vec![Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }], vec![Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }],
Version::Micro(3),
Version::Micro(3)
); );
} }
@ -456,10 +486,25 @@ mod optimize_tests {
fn bench_optimize(bencher: &mut Bencher) { fn bench_optimize(bencher: &mut Bencher) {
use types::Version; use types::Version;
let data = b"QR\x83R\x81[\x83h\x81i\x83L\x83\x85\x81[\x83A\x81[\x83\x8b\x83R\x81[\x83h\x81j\x82\xc6\x82\xcd\x81A1994\x94N\x82\xc9\x83f\x83\x93\x83\\\x81[\x82\xcc\x8aJ\x94\xad\x95\x94\x96\xe5\x81i\x8c\xbb\x8d\xdd\x82\xcd\x95\xaa\x97\xa3\x82\xb5\x83f\x83\x93\x83\\\x81[\x83E\x83F\x81[\x83u\x81j\x82\xaa\x8aJ\x94\xad\x82\xb5\x82\xbd\x83}\x83g\x83\x8a\x83b\x83N\x83X\x8c^\x93\xf1\x8e\x9f\x8c\xb3\x83R\x81[\x83h\x82\xc5\x82\xa0\x82\xe9\x81B\x82\xc8\x82\xa8\x81AQR\x83R\x81[\x83h\x82\xc6\x82\xa2\x82\xa4\x96\xbc\x8f\xcc\x81i\x82\xa8\x82\xe6\x82\xd1\x92P\x8c\xea\x81j\x82\xcd\x83f\x83\x93\x83\\\x81[\x83E\x83F\x81[\x83u\x82\xcc\x93o\x98^\x8f\xa4\x95W\x81i\x91\xe64075066\x8d\x86\x81j\x82\xc5\x82\xa0\x82\xe9\x81BQR\x82\xcdQuick Response\x82\xc9\x97R\x97\x88\x82\xb5\x81A\x8d\x82\x91\xac\x93\xc7\x82\xdd\x8e\xe6\x82\xe8\x82\xaa\x82\xc5\x82\xab\x82\xe9\x82\xe6\x82\xa4\x82\xc9\x8aJ\x94\xad\x82\xb3\x82\xea\x82\xbd\x81B\x93\x96\x8f\x89\x82\xcd\x8e\xa9\x93\xae\x8e\xd4\x95\x94\x95i\x8dH\x8f\xea\x82\xe2\x94z\x91\x97\x83Z\x83\x93\x83^\x81[\x82\xc8\x82\xc7\x82\xc5\x82\xcc\x8eg\x97p\x82\xf0\x94O\x93\xaa\x82\xc9\x8aJ\x94\xad\x82\xb3\x82\xea\x82\xbd\x82\xaa\x81A\x8c\xbb\x8d\xdd\x82\xc5\x82\xcd\x83X\x83}\x81[\x83g\x83t\x83H\x83\x93\x82\xcc\x95\x81\x8by\x82\xc8\x82\xc7\x82\xc9\x82\xe6\x82\xe8\x93\xfa\x96{\x82\xc9\x8c\xc0\x82\xe7\x82\xb8\x90\xa2\x8aE\x93I\x82\xc9\x95\x81\x8by\x82\xb5\x82\xc4\x82\xa2\x82\xe9\x81B"; let data = b"QR\x83R\x81[\x83h\x81i\x83L\x83\x85\x81[\x83A\x81[\x83\x8b\x83R\x81[\x83h\x81j\
bencher.iter(|| { \x82\xc6\x82\xcd\x81A1994\x94N\x82\xc9\x83f\x83\x93\x83\\\x81[\x82\xcc\x8aJ\
Parser::new(data).optimize(Version::Normal(15)) \x94\xad\x95\x94\x96\xe5\x81i\x8c\xbb\x8d\xdd\x82\xcd\x95\xaa\x97\xa3\x82\xb5\x83f\
}); \x83\x93\x83\\\x81[\x83E\x83F\x81[\x83u\x81j\x82\xaa\x8aJ\x94\xad\x82\xb5\x82\xbd\
\x83}\x83g\x83\x8a\x83b\x83N\x83X\x8c^\x93\xf1\x8e\x9f\x8c\xb3\x83R\x81[\x83h\
\x82\xc5\x82\xa0\x82\xe9\x81B\x82\xc8\x82\xa8\x81AQR\x83R\x81[\x83h\x82\xc6\
\x82\xa2\x82\xa4\x96\xbc\x8f\xcc\x81i\x82\xa8\x82\xe6\x82\xd1\x92P\x8c\xea\x81j\
\x82\xcd\x83f\x83\x93\x83\\\x81[\x83E\x83F\x81[\x83u\x82\xcc\x93o\x98^\x8f\xa4\
\x95W\x81i\x91\xe64075066\x8d\x86\x81j\x82\xc5\x82\xa0\x82\xe9\x81BQR\x82\xcd\
Quick Response\x82\xc9\x97R\x97\x88\x82\xb5\x81A\x8d\x82\x91\xac\x93\xc7\x82\xdd\
\x8e\xe6\x82\xe8\x82\xaa\x82\xc5\x82\xab\x82\xe9\x82\xe6\x82\xa4\x82\xc9\x8aJ\
\x94\xad\x82\xb3\x82\xea\x82\xbd\x81B\x93\x96\x8f\x89\x82\xcd\x8e\xa9\x93\xae\
\x8e\xd4\x95\x94\x95i\x8dH\x8f\xea\x82\xe2\x94z\x91\x97\x83Z\x83\x93\x83^\x81[\
\x82\xc8\x82\xc7\x82\xc5\x82\xcc\x8eg\x97p\x82\xf0\x94O\x93\xaa\x82\xc9\x8aJ\
\x94\xad\x82\xb3\x82\xea\x82\xbd\x82\xaa\x81A\x8c\xbb\x8d\xdd\x82\xc5\x82\xcd\x83X\
\x83}\x81[\x83g\x83t\x83H\x83\x93\x82\xcc\x95\x81\x8by\x82\xc8\x82\xc7\x82\xc9\
\x82\xe6\x82\xe8\x93\xfa\x96{\x82\xc9\x8c\xc0\x82\xe7\x82\xb8\x90\xa2\x8aE\x93I\
\x82\xc9\x95\x81\x8by\x82\xb5\x82\xc4\x82\xa2\x82\xe9\x81B";
bencher.iter(|| Parser::new(data).optimize(Version::Normal(15)));
} }
@ -514,7 +559,7 @@ enum ExclCharSet {
impl ExclCharSet { impl ExclCharSet {
/// Determines which character set a byte is in. /// Determines which character set a byte is in.
fn from_u8(c: u8) -> ExclCharSet { fn from_u8(c: u8) -> Self {
match c { match c {
0x20 | 0x24 | 0x25 | 0x2a | 0x2b | 0x2d...0x2f | 0x3a => ExclCharSet::Symbol, 0x20 | 0x24 | 0x25 | 0x2a | 0x2b | 0x2d...0x2f | 0x3a => ExclCharSet::Symbol,
0x30...0x39 => ExclCharSet::Numeric, 0x30...0x39 => ExclCharSet::Numeric,
@ -524,7 +569,7 @@ impl ExclCharSet {
0xeb => ExclCharSet::KanjiHi3, 0xeb => ExclCharSet::KanjiHi3,
0x40 | 0x5b...0x7e | 0x80 | 0xa0...0xbf => ExclCharSet::KanjiLo1, 0x40 | 0x5b...0x7e | 0x80 | 0xa0...0xbf => ExclCharSet::KanjiLo1,
0xc0...0xdf | 0xec...0xfc => ExclCharSet::KanjiLo2, 0xc0...0xdf | 0xec...0xfc => ExclCharSet::KanjiLo2,
_ => ExclCharSet::Byte _ => ExclCharSet::Byte,
} }
} }
} }
@ -583,7 +628,6 @@ static STATE_TRANSITION: [(State, Action); 70] = [
// STATE_TRANSITION[current_state + next_character] == (next_state, what_to_do) // STATE_TRANSITION[current_state + next_character] == (next_state, what_to_do)
// Init state: // Init state:
(State::Init, Action::Idle), // End (State::Init, Action::Idle), // End
(State::Alpha, Action::Idle), // Symbol (State::Alpha, Action::Idle), // Symbol
(State::Numeric, Action::Idle), // Numeric (State::Numeric, Action::Idle), // Numeric
@ -594,9 +638,7 @@ static STATE_TRANSITION: [(State, Action); 70] = [
(State::Byte, Action::Idle), // KanjiLo1 (State::Byte, Action::Idle), // KanjiLo1
(State::Byte, Action::Idle), // KanjiLo2 (State::Byte, Action::Idle), // KanjiLo2
(State::Byte, Action::Idle), // Byte (State::Byte, Action::Idle), // Byte
// Numeric state: // Numeric state:
(State::Init, Action::Numeric), // End (State::Init, Action::Numeric), // End
(State::Alpha, Action::Numeric), // Symbol (State::Alpha, Action::Numeric), // Symbol
(State::Numeric, Action::Idle), // Numeric (State::Numeric, Action::Idle), // Numeric
@ -607,9 +649,7 @@ static STATE_TRANSITION: [(State, Action); 70] = [
(State::Byte, Action::Numeric), // KanjiLo1 (State::Byte, Action::Numeric), // KanjiLo1
(State::Byte, Action::Numeric), // KanjiLo2 (State::Byte, Action::Numeric), // KanjiLo2
(State::Byte, Action::Numeric), // Byte (State::Byte, Action::Numeric), // Byte
// Alpha state: // Alpha state:
(State::Init, Action::Alpha), // End (State::Init, Action::Alpha), // End
(State::Alpha, Action::Idle), // Symbol (State::Alpha, Action::Idle), // Symbol
(State::Numeric, Action::Alpha), // Numeric (State::Numeric, Action::Alpha), // Numeric
@ -620,9 +660,7 @@ static STATE_TRANSITION: [(State, Action); 70] = [
(State::Byte, Action::Alpha), // KanjiLo1 (State::Byte, Action::Alpha), // KanjiLo1
(State::Byte, Action::Alpha), // KanjiLo2 (State::Byte, Action::Alpha), // KanjiLo2
(State::Byte, Action::Alpha), // Byte (State::Byte, Action::Alpha), // Byte
// Byte state: // Byte state:
(State::Init, Action::Byte), // End (State::Init, Action::Byte), // End
(State::Alpha, Action::Byte), // Symbol (State::Alpha, Action::Byte), // Symbol
(State::Numeric, Action::Byte), // Numeric (State::Numeric, Action::Byte), // Numeric
@ -633,9 +671,7 @@ static STATE_TRANSITION: [(State, Action); 70] = [
(State::Byte, Action::Idle), // KanjiLo1 (State::Byte, Action::Idle), // KanjiLo1
(State::Byte, Action::Idle), // KanjiLo2 (State::Byte, Action::Idle), // KanjiLo2
(State::Byte, Action::Idle), // Byte (State::Byte, Action::Idle), // Byte
// KanjiHi12 state: // KanjiHi12 state:
(State::Init, Action::KanjiAndSingleByte), // End (State::Init, Action::KanjiAndSingleByte), // End
(State::Alpha, Action::KanjiAndSingleByte), // Symbol (State::Alpha, Action::KanjiAndSingleByte), // Symbol
(State::Numeric, Action::KanjiAndSingleByte), // Numeric (State::Numeric, Action::KanjiAndSingleByte), // Numeric
@ -646,9 +682,7 @@ static STATE_TRANSITION: [(State, Action); 70] = [
(State::Kanji, Action::Idle), // KanjiLo1 (State::Kanji, Action::Idle), // KanjiLo1
(State::Kanji, Action::Idle), // KanjiLo2 (State::Kanji, Action::Idle), // KanjiLo2
(State::Byte, Action::KanjiAndSingleByte), // Byte (State::Byte, Action::KanjiAndSingleByte), // Byte
// KanjiHi3 state: // KanjiHi3 state:
(State::Init, Action::KanjiAndSingleByte), // End (State::Init, Action::KanjiAndSingleByte), // End
(State::Alpha, Action::KanjiAndSingleByte), // Symbol (State::Alpha, Action::KanjiAndSingleByte), // Symbol
(State::Numeric, Action::KanjiAndSingleByte), // Numeric (State::Numeric, Action::KanjiAndSingleByte), // Numeric
@ -659,9 +693,7 @@ static STATE_TRANSITION: [(State, Action); 70] = [
(State::Kanji, Action::Idle), // KanjiLo1 (State::Kanji, Action::Idle), // KanjiLo1
(State::Byte, Action::KanjiAndSingleByte), // KanjiLo2 (State::Byte, Action::KanjiAndSingleByte), // KanjiLo2
(State::Byte, Action::KanjiAndSingleByte), // Byte (State::Byte, Action::KanjiAndSingleByte), // Byte
// Kanji state: // Kanji state:
(State::Init, Action::Kanji), // End (State::Init, Action::Kanji), // End
(State::Alpha, Action::Kanji), // Symbol (State::Alpha, Action::Kanji), // Symbol
(State::Numeric, Action::Kanji), // Numeric (State::Numeric, Action::Kanji), // Numeric
@ -675,5 +707,3 @@ static STATE_TRANSITION: [(State, Action); 70] = [
]; ];
//}}} //}}}

View file

@ -1,9 +1,9 @@
#![cfg(feature="image")] #![cfg(feature="image")]
use render::{Pixel, Canvas}; use render::{Canvas, Pixel};
use types::Color; use types::Color;
use image::{Pixel as ImagePixel, Rgb, Rgba, Luma, LumaA, Primitive, ImageBuffer}; use image::{ImageBuffer, Luma, LumaA, Pixel as ImagePixel, Primitive, Rgb, Rgba};
macro_rules! impl_pixel_for_image_pixel { macro_rules! impl_pixel_for_image_pixel {
($p:ident<$s:ident>: $c:pat => $d:expr) => { ($p:ident<$s:ident>: $c:pat => $d:expr) => {
@ -50,12 +50,26 @@ mod render_tests {
#[test] #[test]
fn test_render_luma8_unsized() { fn test_render_luma8_unsized() {
let image = Renderer::<Luma<u8>>::new(&[ let image = Renderer::<Luma<u8>>::new(
Color::Light, Color::Dark, Color::Dark, &[
Color::Dark, Color::Light, Color::Light, Color::Light,
Color::Light, Color::Dark, Color::Light, Color::Dark,
], 3, 1).module_dimensions(1, 1).build(); Color::Dark,
//
Color::Dark,
Color::Light,
Color::Light,
//
Color::Light,
Color::Dark,
Color::Light,
],
3,
1,
).module_dimensions(1, 1)
.build();
#[cfg_attr(rustfmt, rustfmt_skip)]
let expected = [ let expected = [
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 0, 0, 255, 255, 255, 0, 0, 255,
@ -68,11 +82,12 @@ mod render_tests {
#[test] #[test]
fn test_render_rgba_unsized() { fn test_render_rgba_unsized() {
let image = Renderer::<Rgba<u8>>::new(&[ let image =
Color::Light, Color::Dark, Renderer::<Rgba<u8>>::new(&[Color::Light, Color::Dark, Color::Dark, Color::Dark], 2, 1)
Color::Dark, Color::Dark, .module_dimensions(1, 1)
], 2, 1).module_dimensions(1, 1).build(); .build();
#[cfg_attr(rustfmt, rustfmt_skip)]
let expected: &[u8] = &[ let expected: &[u8] = &[
255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255,
255,255,255,255, 255,255,255,255, 0, 0, 0,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, 0, 0, 0,255, 255,255,255,255,
@ -85,11 +100,14 @@ mod render_tests {
#[test] #[test]
fn test_render_resized_min() { fn test_render_resized_min() {
let image = Renderer::<Luma<u8>>::new(&[ let image = Renderer::<Luma<u8>>::new(
Color::Dark, Color::Light, &[Color::Dark, Color::Light, Color::Light, Color::Dark],
Color::Light, Color::Dark, 2,
], 2, 1).min_dimensions(10, 10).build(); 1,
).min_dimensions(10, 10)
.build();
#[cfg_attr(rustfmt, rustfmt_skip)]
let expected: &[u8] = &[ let expected: &[u8] = &[
255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255,
255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255,
@ -114,11 +132,14 @@ mod render_tests {
#[test] #[test]
fn test_render_resized_max() { fn test_render_resized_max() {
let image = Renderer::<Luma<u8>>::new(&[ let image = Renderer::<Luma<u8>>::new(
Color::Dark, Color::Light, &[Color::Dark, Color::Light, Color::Light, Color::Dark],
Color::Light, Color::Dark, 2,
], 2, 1).max_dimensions(10, 5).build(); 1,
).max_dimensions(10, 5)
.build();
#[cfg_attr(rustfmt, rustfmt_skip)]
let expected: &[u8] = &[ let expected: &[u8] = &[
255,255, 255,255, 255,255, 255,255, 255,255, 255,255, 255,255, 255,255,

View file

@ -2,6 +2,7 @@
use std::cmp::max; use std::cmp::max;
use types::Color; use types::Color;
use cast::As;
pub mod image; pub mod image;
pub mod string; pub mod string;
@ -57,6 +58,7 @@ pub trait Canvas: Sized {
/// A QR code renderer. This is a builder type which converts a bool-vector into /// A QR code renderer. This is a builder type which converts a bool-vector into
/// an image. /// an image.
#[cfg_attr(feature = "cargo-clippy", allow(stutter))] // rust-lang-nursery/rust-clippy#2212 ಠ_ಠ
pub struct Renderer<'a, P: Pixel> { pub struct Renderer<'a, P: Pixel> {
content: &'a [Color], content: &'a [Color],
modules_count: u32, // <- we call it `modules_count` here to avoid ambiguity of `width`. modules_count: u32, // <- we call it `modules_count` here to avoid ambiguity of `width`.
@ -74,7 +76,7 @@ impl<'a, P: Pixel> Renderer<'a, P> {
assert!(modules_count * modules_count == content.len()); assert!(modules_count * modules_count == content.len());
Renderer { Renderer {
content, content,
modules_count: modules_count as u32, modules_count: modules_count.as_u32(),
quiet_zone, quiet_zone,
module_size: P::default_unit_size(), module_size: P::default_unit_size(),
dark_color: P::default_color(Color::Dark), dark_color: P::default_color(Color::Dark),
@ -154,7 +156,8 @@ impl<'a, P: Pixel> Renderer<'a, P> {
} }
/// Renders the QR code into an image. /// Renders the QR code into an image.
#[deprecated(since="0.4.0", note="renamed to `.build()` to de-emphasize the image connection")] #[deprecated(since = "0.4.0",
note = "renamed to `.build()` to de-emphasize the image connection")]
pub fn to_image(&self) -> P::Image { pub fn to_image(&self) -> P::Image {
self.build() self.build()
} }
@ -162,7 +165,11 @@ impl<'a, P: Pixel> Renderer<'a, P> {
/// Renders the QR code into an image. /// Renders the QR code into an image.
pub fn build(&self) -> P::Image { pub fn build(&self) -> P::Image {
let w = self.modules_count; let w = self.modules_count;
let qz = if self.has_quiet_zone { self.quiet_zone } else { 0 }; let qz = if self.has_quiet_zone {
self.quiet_zone
} else {
0
};
let width = w + 2 * qz; let width = w + 2 * qz;
let (mw, mh) = self.module_size; let (mw, mh) = self.module_size;

View file

@ -1,7 +1,8 @@
//! String rendering support. //! String rendering support.
use render::{Pixel, Canvas as RenderCanvas}; use render::{Canvas as RenderCanvas, Pixel};
use types::Color; use types::Color;
use cast::As;
pub trait Element: Copy { pub trait Element: Copy {
fn default_color(color: Color) -> Self; fn default_color(color: Color) -> Self;
@ -11,7 +12,7 @@ pub trait Element: Copy {
impl Element for char { impl Element for char {
fn default_color(color: Color) -> Self { fn default_color(color: Color) -> Self {
color.select('', ' ') color.select('\u{2588}', ' ')
} }
fn strlen(self) -> usize { fn strlen(self) -> usize {
@ -25,7 +26,7 @@ impl Element for char {
impl<'a> Element for &'a str { impl<'a> Element for &'a str {
fn default_color(color: Color) -> Self { fn default_color(color: Color) -> Self {
color.select("", " ") color.select("\u{2588}", " ")
} }
fn strlen(self) -> usize { fn strlen(self) -> usize {
@ -47,7 +48,7 @@ pub struct Canvas<P: Element> {
} }
impl<P: Element> Pixel for P { impl<P: Element> Pixel for P {
type Canvas = Canvas<P>; type Canvas = Canvas<Self>;
type Image = String; type Image = String;
fn default_unit_size() -> (u32, u32) { fn default_unit_size() -> (u32, u32) {
@ -64,29 +65,29 @@ impl<P: Element> RenderCanvas for Canvas<P> {
type Image = String; type Image = String;
fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self { fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self {
let width = width as usize; let width = width.as_usize();
let height = height as isize; let height = height.as_isize();
let dark_cap = dark_pixel.strlen() as isize; let dark_cap = dark_pixel.strlen().as_isize();
let light_cap = light_pixel.strlen() as isize; let light_cap = light_pixel.strlen().as_isize();
Canvas { Self {
buffer: vec![light_pixel; width * (height as usize)], buffer: vec![light_pixel; width * height.as_usize()],
width, width,
dark_pixel, dark_pixel,
dark_cap_inc: dark_cap - light_cap, dark_cap_inc: dark_cap - light_cap,
capacity: light_cap * (width as isize) * height + (height - 1), capacity: light_cap * width.as_isize() * height + (height - 1),
} }
} }
fn draw_dark_pixel(&mut self, x: u32, y: u32) { fn draw_dark_pixel(&mut self, x: u32, y: u32) {
let x = x as usize; let x = x.as_usize();
let y = y as usize; let y = y.as_usize();
self.capacity += self.dark_cap_inc; self.capacity += self.dark_cap_inc;
self.buffer[x + y * self.width] = self.dark_pixel; self.buffer[x + y * self.width] = self.dark_pixel;
} }
fn into_image(self) -> String { fn into_image(self) -> String {
let mut result = String::with_capacity(self.capacity as usize); let mut result = String::with_capacity(self.capacity.as_usize());
for (i, pixel) in self.buffer.into_iter().enumerate() { for (i, pixel) in self.buffer.into_iter().enumerate() {
if i != 0 && i % self.width == 0 { if i != 0 && i % self.width == 0 {
result.push('\n'); result.push('\n');
@ -101,12 +102,9 @@ impl<P: Element> RenderCanvas for Canvas<P> {
fn test_render_to_string() { fn test_render_to_string() {
use render::Renderer; use render::Renderer;
let colors = &[ let colors = &[Color::Dark, Color::Light, Color::Light, Color::Dark];
Color::Dark, Color::Light,
Color::Light, Color::Dark,
];
let image: String = Renderer::<char>::new(colors, 2, 1).build(); let image: String = Renderer::<char>::new(colors, 2, 1).build();
assert_eq!(&image, " \n \n \n "); assert_eq!(&image, " \n \u{2588} \n \u{2588} \n ");
let image2 = Renderer::new(colors, 2, 1) let image2 = Renderer::new(colors, 2, 1)
.light_color("A") .light_color("A")
@ -114,13 +112,15 @@ fn test_render_to_string() {
.module_dimensions(2, 2) .module_dimensions(2, 2)
.build(); .build();
assert_eq!(&image2, "\ assert_eq!(
AAAAAAAA\n\ &image2,
"AAAAAAAA\n\
AAAAAAAA\n\ AAAAAAAA\n\
AA!B!!B!AAAA\n\ AA!B!!B!AAAA\n\
AA!B!!B!AAAA\n\ AA!B!!B!AAAA\n\
AAAA!B!!B!AA\n\ AAAA!B!!B!AA\n\
AAAA!B!!B!AA\n\ AAAA!B!!B!AA\n\
AAAAAAAA\n\ AAAAAAAA\n\
AAAAAAAA"); AAAAAAAA"
);
} }

View file

@ -19,7 +19,7 @@
use std::fmt::Write; use std::fmt::Write;
use std::marker::PhantomData; use std::marker::PhantomData;
use render::{Pixel, Canvas as RenderCanvas}; use render::{Canvas as RenderCanvas, Pixel};
use types::Color as ModuleColor; use types::Color as ModuleColor;
/// An SVG color. /// An SVG color.
@ -48,8 +48,17 @@ impl<'a> RenderCanvas for Canvas<'a> {
fn new(width: u32, height: u32, dark_pixel: Color<'a>, light_pixel: Color<'a>) -> Self { fn new(width: u32, height: u32, dark_pixel: Color<'a>, light_pixel: Color<'a>) -> Self {
Canvas { Canvas {
svg: format!( svg: format!(
r#"<?xml version="1.0" standalone="yes"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="{w}" height="{h}" shape-rendering="crispEdges"><rect x="0" y="0" width="{w}" height="{h}" fill="{bg}"/><path fill="{fg}" d=""#, concat!(
w=width, h=height, fg=dark_pixel.0, bg=light_pixel.0 r#"<?xml version="1.0" standalone="yes"?>"#,
r#"<svg xmlns="http://www.w3.org/2000/svg""#,
r#" version="1.1" width="{w}" height="{h}" shape-rendering="crispEdges">"#,
r#"<rect x="0" y="0" width="{w}" height="{h}" fill="{bg}"/>"#,
r#"<path fill="{fg}" d=""#,
),
w = width,
h = height,
fg = dark_pixel.0,
bg = light_pixel.0
), ),
marker: PhantomData, marker: PhantomData,
} }
@ -60,10 +69,12 @@ impl<'a> RenderCanvas for Canvas<'a> {
} }
fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u32) { fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u32) {
write!(self.svg, "M{l} {t}h{w}v{h}H{l}V{t}", l=left, t=top, w=width, h=height).unwrap(); write!(self.svg, "M{l} {t}h{w}v{h}H{l}V{t}", l = left, t = top, w = width, h = height)
.unwrap();
} }
fn into_image(self) -> String { fn into_image(mut self) -> String {
self.svg + r#""/></svg>"# self.svg.push_str(r#""/></svg>"#);
self.svg
} }
} }

View file

@ -1,7 +1,8 @@
use std::default::Default; use std::default::Default;
use std::cmp::{PartialOrd, Ordering}; use std::cmp::{Ordering, PartialOrd};
use std::fmt::{Display, Formatter, Error}; use std::fmt::{Display, Error, Formatter};
use std::ops::Not; use std::ops::Not;
use cast::As;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
//{{{ QrResult //{{{ QrResult
@ -76,8 +77,8 @@ impl Color {
} }
impl Not for Color { impl Not for Color {
type Output = Color; type Output = Self;
fn not(self) -> Color { fn not(self) -> Self {
match self { match self {
Color::Light => Color::Dark, Color::Light => Color::Dark,
Color::Dark => Color::Light, Color::Dark => Color::Light,
@ -146,26 +147,28 @@ impl Version {
/// If the entry compares equal to the default value of T, this method /// If the entry compares equal to the default value of T, this method
/// returns `Err(QrError::InvalidVersion)`. /// returns `Err(QrError::InvalidVersion)`.
pub fn fetch<T>(&self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult<T> pub fn fetch<T>(&self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult<T>
where T: PartialEq + Default + Copy where
T: PartialEq + Default + Copy,
{ {
match *self { match *self {
Version::Normal(v @ 1...40) => Ok(table[v as usize - 1][ec_level as usize]), Version::Normal(v @ 1...40) => {
return Ok(table[(v - 1).as_usize()][ec_level as usize]);
}
Version::Micro(v @ 1...4) => { Version::Micro(v @ 1...4) => {
let obj = table[v as usize + 39][ec_level as usize]; let obj = table[(v + 39).as_usize()][ec_level as usize];
if obj != Default::default() { if obj != T::default() {
Ok(obj) return Ok(obj);
} else { }
}
_ => {}
}
Err(QrError::InvalidVersion) Err(QrError::InvalidVersion)
} }
}
_ => Err(QrError::InvalidVersion)
}
}
/// The number of bits needed to encode the mode indicator. /// The number of bits needed to encode the mode indicator.
pub fn mode_bits_count(&self) -> usize { pub fn mode_bits_count(&self) -> usize {
match *self { match *self {
Version::Micro(a) => (a - 1) as usize, Version::Micro(a) => (a - 1).as_usize(),
_ => 4, _ => 4,
} }
} }
@ -213,7 +216,7 @@ impl Mode {
pub fn length_bits_count(&self, version: Version) -> usize { pub fn length_bits_count(&self, version: Version) -> usize {
match version { match version {
Version::Micro(a) => { Version::Micro(a) => {
let a = a as usize; let a = a.as_usize();
match *self { match *self {
Mode::Numeric => 2 + a, Mode::Numeric => 2 + a,
Mode::Alphanumeric | Mode::Byte => 1 + a, Mode::Alphanumeric | Mode::Byte => 1 + a,
@ -223,8 +226,7 @@ impl Mode {
Version::Normal(1...9) => match *self { Version::Normal(1...9) => match *self {
Mode::Numeric => 10, Mode::Numeric => 10,
Mode::Alphanumeric => 9, Mode::Alphanumeric => 9,
Mode::Byte => 8, Mode::Byte | Mode::Kanji => 8,
Mode::Kanji => 8,
}, },
Version::Normal(10...26) => match *self { Version::Normal(10...26) => match *self {
Mode::Numeric => 12, Mode::Numeric => 12,
@ -268,7 +270,7 @@ impl Mode {
/// assert!(a <= c); /// assert!(a <= c);
/// assert!(b <= c); /// assert!(b <= c);
/// ///
pub fn max(&self, other: Mode) -> Mode { pub fn max(&self, other: Self) -> Self {
match self.partial_cmp(&other) { match self.partial_cmp(&other) {
Some(Ordering::Less) | Some(Ordering::Equal) => other, Some(Ordering::Less) | Some(Ordering::Equal) => other,
Some(Ordering::Greater) => *self, Some(Ordering::Greater) => *self,
@ -280,15 +282,15 @@ impl Mode {
impl PartialOrd for Mode { impl PartialOrd for Mode {
/// Defines a partial ordering between modes. If `a <= b`, then `b` contains /// Defines a partial ordering between modes. If `a <= b`, then `b` contains
/// a superset of all characters supported by `a`. /// a superset of all characters supported by `a`.
fn partial_cmp(&self, other: &Mode) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (*self, *other) { match (*self, *other) {
(Mode::Numeric, Mode::Alphanumeric) => Some(Ordering::Less), (Mode::Numeric, Mode::Alphanumeric) |
(Mode::Alphanumeric, Mode::Numeric) => Some(Ordering::Greater), (Mode::Numeric, Mode::Byte) |
(Mode::Numeric, Mode::Byte) => Some(Ordering::Less), (Mode::Alphanumeric, Mode::Byte) |
(Mode::Byte, Mode::Numeric) => Some(Ordering::Greater),
(Mode::Alphanumeric, Mode::Byte) => Some(Ordering::Less),
(Mode::Byte, Mode::Alphanumeric) => Some(Ordering::Greater),
(Mode::Kanji, Mode::Byte) => Some(Ordering::Less), (Mode::Kanji, Mode::Byte) => Some(Ordering::Less),
(Mode::Alphanumeric, Mode::Numeric) |
(Mode::Byte, Mode::Numeric) |
(Mode::Byte, Mode::Alphanumeric) |
(Mode::Byte, Mode::Kanji) => Some(Ordering::Greater), (Mode::Byte, Mode::Kanji) => Some(Ordering::Greater),
(a, b) if a == b => Some(Ordering::Equal), (a, b) if a == b => Some(Ordering::Equal),
_ => None, _ => None,
@ -298,7 +300,7 @@ impl PartialOrd for Mode {
#[cfg(test)] #[cfg(test)]
mod mode_tests { mod mode_tests {
use types::Mode::{Numeric, Alphanumeric, Byte, Kanji}; use types::Mode::{Alphanumeric, Byte, Kanji, Numeric};
#[test] #[test]
fn test_mode_order() { fn test_mode_order() {
@ -321,5 +323,3 @@ mod mode_tests {
} }
//}}} //}}}