rustfmt.
This commit is contained in:
parent
01f209d0a5
commit
51dd9c4fa1
|
@ -1,8 +1,8 @@
|
||||||
extern crate image;
|
extern crate image;
|
||||||
extern crate qrcode;
|
extern crate qrcode;
|
||||||
|
|
||||||
use qrcode::QrCode;
|
|
||||||
use image::Luma;
|
use image::Luma;
|
||||||
|
use qrcode::QrCode;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Encode some data into bits.
|
// Encode some data into bits.
|
||||||
|
|
|
@ -3,9 +3,6 @@ use qrcode::QrCode;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let code = QrCode::new(b"Hello").unwrap();
|
let code = QrCode::new(b"Hello").unwrap();
|
||||||
let string = code.render::<char>()
|
let string = code.render::<char>().quiet_zone(false).module_dimensions(2, 1).build();
|
||||||
.quiet_zone(false)
|
|
||||||
.module_dimensions(2, 1)
|
|
||||||
.build();
|
|
||||||
println!("{}", string);
|
println!("{}", string);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
extern crate qrcode;
|
extern crate qrcode;
|
||||||
|
|
||||||
use qrcode::{EcLevel, QrCode, Version};
|
|
||||||
use qrcode::render::svg;
|
use qrcode::render::svg;
|
||||||
|
use qrcode::{EcLevel, QrCode, Version};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
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();
|
||||||
let image = code.render()
|
let image = code
|
||||||
|
.render()
|
||||||
.min_dimensions(200, 200)
|
.min_dimensions(200, 200)
|
||||||
.dark_color(svg::Color("#800000"))
|
.dark_color(svg::Color("#800000"))
|
||||||
.light_color(svg::Color("#ffff80"))
|
.light_color(svg::Color("#ffff80"))
|
||||||
|
|
10
rustfmt.toml
10
rustfmt.toml
|
@ -1,8 +1,2 @@
|
||||||
array_width = 100
|
max_width = 120
|
||||||
chain_width = 100
|
use_small_heuristics = "Max"
|
||||||
fn_call_width = 100
|
|
||||||
# single_line_if_else_max_width = 100
|
|
||||||
struct_lit_width = 100
|
|
||||||
struct_variant_width = 100
|
|
||||||
error_on_line_overflow = false
|
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,5 @@ 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!(
|
print!("{}", code.render().dark_color("\x1b[7m \x1b[0m").light_color("\x1b[49m \x1b[0m").build());
|
||||||
"{}",
|
|
||||||
code.render()
|
|
||||||
.dark_color("\x1b[7m \x1b[0m")
|
|
||||||
.light_color("\x1b[49m \x1b[0m")
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
86
src/bits.rs
86
src/bits.rs
|
@ -5,9 +5,9 @@ use std::cmp::min;
|
||||||
#[cfg(feature = "bench")]
|
#[cfg(feature = "bench")]
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use types::{EcLevel, Mode, QrError, QrResult, Version};
|
|
||||||
use optimize::{total_encoded_len, Optimizer, Parser, Segment};
|
|
||||||
use cast::{As, Truncate};
|
use cast::{As, Truncate};
|
||||||
|
use optimize::{total_encoded_len, Optimizer, Parser, Segment};
|
||||||
|
use types::{EcLevel, Mode, QrError, QrResult, Version};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//{{{ Bits
|
//{{{ Bits
|
||||||
|
@ -31,12 +31,7 @@ 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!(
|
debug_assert!(n == 16 || n < 16 && number < (1 << n), "{} 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);
|
let last_index = self.data.len().wrapping_sub(1);
|
||||||
|
@ -205,8 +200,7 @@ 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)
|
self.push_number_checked(bits, number).or(Err(QrError::UnsupportedCharacterSet))
|
||||||
.or(Err(QrError::UnsupportedCharacterSet))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,10 +324,7 @@ impl Bits {
|
||||||
pub fn push_numeric_data(&mut self, data: &[u8]) -> QrResult<()> {
|
pub fn push_numeric_data(&mut self, data: &[u8]) -> QrResult<()> {
|
||||||
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
|
let number = chunk.iter().map(|b| u16::from(*b - b'0')).fold(0, |a, b| a * 10 + b);
|
||||||
.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);
|
||||||
}
|
}
|
||||||
|
@ -437,10 +428,7 @@ impl Bits {
|
||||||
pub fn push_alphanumeric_data(&mut self, data: &[u8]) -> QrResult<()> {
|
pub fn push_alphanumeric_data(&mut self, data: &[u8]) -> QrResult<()> {
|
||||||
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
|
let number = chunk.iter().map(|b| alphanumeric_digit(*b)).fold(0, |a, b| a * 45 + b);
|
||||||
.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);
|
||||||
}
|
}
|
||||||
|
@ -543,11 +531,7 @@ impl Bits {
|
||||||
return Err(QrError::InvalidCharacter);
|
return Err(QrError::InvalidCharacter);
|
||||||
}
|
}
|
||||||
let cp = u16::from(kanji[0]) * 256 + u16::from(kanji[1]);
|
let cp = u16::from(kanji[0]) * 256 + u16::from(kanji[1]);
|
||||||
let bytes = if cp < 0xe040 {
|
let bytes = if cp < 0xe040 { cp - 0x8140 } else { cp - 0xc140 };
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -564,10 +548,7 @@ mod kanji_tests {
|
||||||
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!(
|
assert_eq!(bits.into_bytes(), vec![0b1000_0000, 0b0010_0110, 0b11001111, 0b1_1101010, 0b101010__00]);
|
||||||
bits.into_bytes(),
|
|
||||||
vec![0b1000_0000, 0b0010_0110, 0b11001111, 0b1_1101010, 0b101010__00]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -579,10 +560,7 @@ 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!(
|
assert_eq!(bits.push_kanji_data(b"\x93_\x93_\x93_\x93_\x93_\x93_\x93_\x93_"), Err(QrError::DataTooLong));
|
||||||
bits.push_kanji_data(b"\x93_\x93_\x93_\x93_\x93_\x93_\x93_\x93_"),
|
|
||||||
Err(QrError::DataTooLong)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,11 +693,7 @@ 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
|
let padding = PADDING_BYTES.iter().cloned().cycle().take(padding_bytes_count);
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.cycle()
|
|
||||||
.take(padding_bytes_count);
|
|
||||||
self.data.extend(padding);
|
self.data.extend(padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,19 +718,8 @@ mod finish_tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bits.into_bytes(),
|
bits.into_bytes(),
|
||||||
vec![
|
vec![
|
||||||
0b00100000,
|
0b00100000, 0b01011011, 0b00001011, 0b01111000, 0b11010001, 0b01110010, 0b11011100, 0b01001101,
|
||||||
0b01011011,
|
0b01000011, 0b01000000, 0b11101100, 0b00010001, 0b11101100,
|
||||||
0b00001011,
|
|
||||||
0b01111000,
|
|
||||||
0b11010001,
|
|
||||||
0b01110010,
|
|
||||||
0b11011100,
|
|
||||||
0b01001101,
|
|
||||||
0b01000011,
|
|
||||||
0b01000000,
|
|
||||||
0b11101100,
|
|
||||||
0b00010001,
|
|
||||||
0b11101100,
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -848,19 +811,8 @@ mod encode_tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
res,
|
res,
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
0b00100000,
|
0b00100000, 0b01011011, 0b00001011, 0b01111000, 0b11010001, 0b01110010, 0b11011100, 0b01001101,
|
||||||
0b01011011,
|
0b01000011, 0b01000000, 0b11101100, 0b00010001, 0b11101100,
|
||||||
0b00001011,
|
|
||||||
0b01111000,
|
|
||||||
0b11010001,
|
|
||||||
0b01110010,
|
|
||||||
0b11011100,
|
|
||||||
0b01001101,
|
|
||||||
0b01000011,
|
|
||||||
0b01000000,
|
|
||||||
0b11101100,
|
|
||||||
0b00010001,
|
|
||||||
0b11101100,
|
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -868,10 +820,7 @@ mod encode_tests {
|
||||||
#[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!(
|
assert_eq!(res, Ok(vec![0b0_0011_000, 0b1111011_1, 0b001_00101, 0b0_00000__00, 0b11101100]));
|
||||||
res,
|
|
||||||
Ok(vec![0b0_0011_000, 0b1111011_1, 0b001_00101, 0b0_00000__00, 0b11101100])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -894,9 +843,7 @@ pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult<Bits> {
|
||||||
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().cloned(), *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
|
let data_capacity = version.fetch(ec_level, &DATA_LENGTHS).expect("invalid DATA_LENGTHS");
|
||||||
.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);
|
||||||
|
@ -941,7 +888,6 @@ mod encode_auto_tests {
|
||||||
assert_eq!(find_min_version(999999, EcLevel::H), Version::Normal(40));
|
assert_eq!(find_min_version(999999, EcLevel::H), Version::Normal(40));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_alpha_q() {
|
fn test_alpha_q() {
|
||||||
let bits = encode_auto(b"HELLO WORLD", EcLevel::Q).unwrap();
|
let bits = encode_auto(b"HELLO WORLD", EcLevel::Q).unwrap();
|
||||||
|
|
258
src/canvas.rs
258
src/canvas.rs
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
|
||||||
use types::{Color, EcLevel, Version};
|
|
||||||
use cast::As;
|
use cast::As;
|
||||||
|
use types::{Color, EcLevel, Version};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//{{{ Modules
|
//{{{ Modules
|
||||||
|
@ -492,7 +492,6 @@ mod alignment_pattern_tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// `ALIGNMENT_PATTERN_POSITIONS` describes the x- and y-coordinates of the
|
/// `ALIGNMENT_PATTERN_POSITIONS` describes the x- and y-coordinates of the
|
||||||
/// center of the alignment patterns. Since the QR code is symmetric, only one
|
/// center of the alignment patterns. Since the QR code is symmetric, only one
|
||||||
/// coordinate is needed.
|
/// coordinate is needed.
|
||||||
|
@ -548,15 +547,7 @@ impl Canvas {
|
||||||
/// `color_odd` will be plotted instead. Thus the timing pattern can be
|
/// `color_odd` will be plotted instead. Thus the timing pattern can be
|
||||||
/// drawn using this method.
|
/// drawn using this method.
|
||||||
///
|
///
|
||||||
fn draw_line(
|
fn draw_line(&mut self, x1: i16, y1: i16, x2: i16, y2: i16, color_even: Color, color_odd: Color) {
|
||||||
&mut self,
|
|
||||||
x1: i16,
|
|
||||||
y1: i16,
|
|
||||||
x2: i16,
|
|
||||||
y2: i16,
|
|
||||||
color_even: Color,
|
|
||||||
color_odd: Color,
|
|
||||||
) {
|
|
||||||
debug_assert!(x1 == x2 || y1 == y2);
|
debug_assert!(x1 == x2 || y1 == y2);
|
||||||
|
|
||||||
if y1 == y2 {
|
if y1 == y2 {
|
||||||
|
@ -657,21 +648,10 @@ impl Canvas {
|
||||||
/// `off_color`. The coordinates will be extracted from the `coords`
|
/// `off_color`. The coordinates will be extracted from the `coords`
|
||||||
/// iterator. It will start from the most significant bits first, so
|
/// iterator. It will start from the most significant bits first, so
|
||||||
/// *trailing* zeros will be ignored.
|
/// *trailing* zeros will be ignored.
|
||||||
fn draw_number(
|
fn draw_number(&mut self, number: u32, bits: u32, on_color: Color, off_color: Color, coords: &[(i16, i16)]) {
|
||||||
&mut self,
|
|
||||||
number: u32,
|
|
||||||
bits: u32,
|
|
||||||
on_color: Color,
|
|
||||||
off_color: Color,
|
|
||||||
coords: &[(i16, i16)],
|
|
||||||
) {
|
|
||||||
let mut mask = 1 << (bits - 1);
|
let mut mask = 1 << (bits - 1);
|
||||||
for &(x, y) in coords {
|
for &(x, y) in coords {
|
||||||
let color = if (mask & number) == 0 {
|
let color = if (mask & number) == 0 { off_color } else { on_color };
|
||||||
off_color
|
|
||||||
} else {
|
|
||||||
on_color
|
|
||||||
};
|
|
||||||
self.put(x, y, color);
|
self.put(x, y, color);
|
||||||
mask >>= 1;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
|
@ -682,29 +662,11 @@ impl Canvas {
|
||||||
let format_info = u32::from(format_info);
|
let format_info = u32::from(format_info);
|
||||||
match self.version {
|
match self.version {
|
||||||
Version::Micro(_) => {
|
Version::Micro(_) => {
|
||||||
self.draw_number(
|
self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_MICRO_QR);
|
||||||
format_info,
|
|
||||||
15,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Light,
|
|
||||||
&FORMAT_INFO_COORDS_MICRO_QR,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Version::Normal(_) => {
|
Version::Normal(_) => {
|
||||||
self.draw_number(
|
self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_MAIN);
|
||||||
format_info,
|
self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_SIDE);
|
||||||
15,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Light,
|
|
||||||
&FORMAT_INFO_COORDS_QR_MAIN,
|
|
||||||
);
|
|
||||||
self.draw_number(
|
|
||||||
format_info,
|
|
||||||
15,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Light,
|
|
||||||
&FORMAT_INFO_COORDS_QR_SIDE,
|
|
||||||
);
|
|
||||||
self.put(8, -8, Color::Dark); // Dark module.
|
self.put(8, -8, Color::Dark); // Dark module.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -723,20 +685,8 @@ impl Canvas {
|
||||||
}
|
}
|
||||||
Version::Normal(a) => {
|
Version::Normal(a) => {
|
||||||
let version_info = VERSION_INFOS[(a - 7).as_usize()];
|
let version_info = VERSION_INFOS[(a - 7).as_usize()];
|
||||||
self.draw_number(
|
self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_BL);
|
||||||
version_info,
|
self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_TR);
|
||||||
18,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Light,
|
|
||||||
&VERSION_INFO_COORDS_BL,
|
|
||||||
);
|
|
||||||
self.draw_number(
|
|
||||||
version_info,
|
|
||||||
18,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Light,
|
|
||||||
&VERSION_INFO_COORDS_TR,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -750,13 +700,7 @@ mod draw_version_info_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_draw_number() {
|
fn test_draw_number() {
|
||||||
let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
|
let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
|
||||||
c.draw_number(
|
c.draw_number(0b10101101, 8, Color::Dark, Color::Light, &[(0, 0), (0, -1), (-2, -2), (-2, 0)]);
|
||||||
0b10101101,
|
|
||||||
8,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Light,
|
|
||||||
&[(0, 0), (0, -1), (-2, -2), (-2, 0)],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&*c.to_debug_str(),
|
&*c.to_debug_str(),
|
||||||
"\n\
|
"\n\
|
||||||
|
@ -1011,40 +955,9 @@ static FORMAT_INFO_COORDS_MICRO_QR: [(i16, i16); 15] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
static VERSION_INFOS: [u32; 34] = [
|
static VERSION_INFOS: [u32; 34] = [
|
||||||
0x07c94,
|
0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78, 0x1145d, 0x12a17,
|
||||||
0x085bc,
|
0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
|
||||||
0x09a99,
|
0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 0x27541, 0x28c69,
|
||||||
0x0a4d3,
|
|
||||||
0x0bbf6,
|
|
||||||
0x0c762,
|
|
||||||
0x0d847,
|
|
||||||
0x0e60d,
|
|
||||||
0x0f928,
|
|
||||||
0x10b78,
|
|
||||||
0x1145d,
|
|
||||||
0x12a17,
|
|
||||||
0x13532,
|
|
||||||
0x149a6,
|
|
||||||
0x15683,
|
|
||||||
0x168c9,
|
|
||||||
0x177ec,
|
|
||||||
0x18ec4,
|
|
||||||
0x191e1,
|
|
||||||
0x1afab,
|
|
||||||
0x1b08e,
|
|
||||||
0x1cc1a,
|
|
||||||
0x1d33f,
|
|
||||||
0x1ed75,
|
|
||||||
0x1f250,
|
|
||||||
0x209d5,
|
|
||||||
0x216f0,
|
|
||||||
0x228ba,
|
|
||||||
0x2379f,
|
|
||||||
0x24b0b,
|
|
||||||
0x2542e,
|
|
||||||
0x26a64,
|
|
||||||
0x27541,
|
|
||||||
0x28c69,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
|
@ -1217,7 +1130,6 @@ mod all_functional_patterns_tests {
|
||||||
assert!(!is_functional(version, version.width(), 1, 9));
|
assert!(!is_functional(version, version.width(), 1, 9));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
|
@ -1250,11 +1162,7 @@ impl Iterator for DataModuleIter {
|
||||||
type Item = (i16, i16);
|
type Item = (i16, i16);
|
||||||
|
|
||||||
fn next(&mut self) -> Option<(i16, i16)> {
|
fn next(&mut self) -> Option<(i16, i16)> {
|
||||||
let adjusted_ref_col = if self.x <= self.timing_pattern_column {
|
let adjusted_ref_col = if self.x <= self.timing_pattern_column { self.x + 1 } else { self.x };
|
||||||
self.x + 1
|
|
||||||
} else {
|
|
||||||
self.x
|
|
||||||
};
|
|
||||||
if adjusted_ref_col <= 0 {
|
if adjusted_ref_col <= 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -1459,19 +1367,11 @@ impl Canvas {
|
||||||
I: Iterator<Item = (i16, i16)>,
|
I: Iterator<Item = (i16, i16)>,
|
||||||
{
|
{
|
||||||
let length = codewords.len();
|
let length = codewords.len();
|
||||||
let last_word = if is_half_codeword_at_end {
|
let last_word = if is_half_codeword_at_end { length - 1 } else { length };
|
||||||
length - 1
|
|
||||||
} else {
|
|
||||||
length
|
|
||||||
};
|
|
||||||
for (i, b) in codewords.iter().enumerate() {
|
for (i, b) in codewords.iter().enumerate() {
|
||||||
let bits_end = if i == last_word { 4 } else { 0 };
|
let bits_end = if i == last_word { 4 } else { 0 };
|
||||||
'outside: for j in (bits_end..=7).rev() {
|
'outside: for j in (bits_end..=7).rev() {
|
||||||
let color = if (*b & (1 << j)) == 0 {
|
let color = if (*b & (1 << j)) == 0 { Color::Light } else { Color::Dark };
|
||||||
Color::Light
|
|
||||||
} else {
|
|
||||||
Color::Dark
|
|
||||||
};
|
|
||||||
while let Some((x, y)) = coords.next() {
|
while let Some((x, y)) = coords.next() {
|
||||||
let r = self.get_mut(x, y);
|
let r = self.get_mut(x, y);
|
||||||
if *r == Module::Empty {
|
if *r == Module::Empty {
|
||||||
|
@ -1784,73 +1684,15 @@ mod mask_tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
static FORMAT_INFOS_QR: [u16; 32] = [
|
static FORMAT_INFOS_QR: [u16; 32] = [
|
||||||
0x5412,
|
0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318,
|
||||||
0x5125,
|
0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b, 0x355f, 0x3068, 0x3f31, 0x3a06,
|
||||||
0x5e7c,
|
0x24b4, 0x2183, 0x2eda, 0x2bed,
|
||||||
0x5b4b,
|
|
||||||
0x45f9,
|
|
||||||
0x40ce,
|
|
||||||
0x4f97,
|
|
||||||
0x4aa0,
|
|
||||||
0x77c4,
|
|
||||||
0x72f3,
|
|
||||||
0x7daa,
|
|
||||||
0x789d,
|
|
||||||
0x662f,
|
|
||||||
0x6318,
|
|
||||||
0x6c41,
|
|
||||||
0x6976,
|
|
||||||
0x1689,
|
|
||||||
0x13be,
|
|
||||||
0x1ce7,
|
|
||||||
0x19d0,
|
|
||||||
0x0762,
|
|
||||||
0x0255,
|
|
||||||
0x0d0c,
|
|
||||||
0x083b,
|
|
||||||
0x355f,
|
|
||||||
0x3068,
|
|
||||||
0x3f31,
|
|
||||||
0x3a06,
|
|
||||||
0x24b4,
|
|
||||||
0x2183,
|
|
||||||
0x2eda,
|
|
||||||
0x2bed,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
static FORMAT_INFOS_MICRO_QR: [u16; 32] = [
|
static FORMAT_INFOS_MICRO_QR: [u16; 32] = [
|
||||||
0x4445,
|
0x4445, 0x4172, 0x4e2b, 0x4b1c, 0x55ae, 0x5099, 0x5fc0, 0x5af7, 0x6793, 0x62a4, 0x6dfd, 0x68ca, 0x7678, 0x734f,
|
||||||
0x4172,
|
0x7c16, 0x7921, 0x06de, 0x03e9, 0x0cb0, 0x0987, 0x1735, 0x1202, 0x1d5b, 0x186c, 0x2508, 0x203f, 0x2f66, 0x2a51,
|
||||||
0x4e2b,
|
0x34e3, 0x31d4, 0x3e8d, 0x3bba,
|
||||||
0x4b1c,
|
|
||||||
0x55ae,
|
|
||||||
0x5099,
|
|
||||||
0x5fc0,
|
|
||||||
0x5af7,
|
|
||||||
0x6793,
|
|
||||||
0x62a4,
|
|
||||||
0x6dfd,
|
|
||||||
0x68ca,
|
|
||||||
0x7678,
|
|
||||||
0x734f,
|
|
||||||
0x7c16,
|
|
||||||
0x7921,
|
|
||||||
0x06de,
|
|
||||||
0x03e9,
|
|
||||||
0x0cb0,
|
|
||||||
0x0987,
|
|
||||||
0x1735,
|
|
||||||
0x1202,
|
|
||||||
0x1d5b,
|
|
||||||
0x186c,
|
|
||||||
0x2508,
|
|
||||||
0x203f,
|
|
||||||
0x2f66,
|
|
||||||
0x2a51,
|
|
||||||
0x34e3,
|
|
||||||
0x31d4,
|
|
||||||
0x3e8d,
|
|
||||||
0x3bba,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
|
@ -1867,15 +1709,9 @@ impl Canvas {
|
||||||
let mut total_score = 0;
|
let mut total_score = 0;
|
||||||
|
|
||||||
for i in 0..self.width {
|
for i in 0..self.width {
|
||||||
let map_fn = |j| if is_horizontal {
|
let map_fn = |j| if is_horizontal { self.get(j, i) } else { self.get(i, j) };
|
||||||
self.get(j, i)
|
|
||||||
} else {
|
|
||||||
self.get(i, j)
|
|
||||||
};
|
|
||||||
|
|
||||||
let colors = (0..self.width)
|
let colors = (0..self.width).map(map_fn).chain(Some(Module::Empty).into_iter());
|
||||||
.map(map_fn)
|
|
||||||
.chain(Some(Module::Empty).into_iter());
|
|
||||||
let mut last_color = Module::Empty;
|
let mut last_color = Module::Empty;
|
||||||
let mut consecutive_len = 1_u16;
|
let mut consecutive_len = 1_u16;
|
||||||
|
|
||||||
|
@ -1924,15 +1760,8 @@ impl Canvas {
|
||||||
/// Every pattern that looks like `#.###.#....` in any orientation will add
|
/// Every pattern that looks like `#.###.#....` in any orientation will add
|
||||||
/// 40 points.
|
/// 40 points.
|
||||||
fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 {
|
fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 {
|
||||||
static PATTERN: [Color; 7] = [
|
static PATTERN: [Color; 7] =
|
||||||
Color::Dark,
|
[Color::Dark, Color::Light, Color::Dark, Color::Dark, Color::Dark, Color::Light, Color::Dark];
|
||||||
Color::Light,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Dark,
|
|
||||||
Color::Light,
|
|
||||||
Color::Dark,
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut total_score = 0;
|
let mut total_score = 0;
|
||||||
|
|
||||||
|
@ -1971,11 +1800,7 @@ impl Canvas {
|
||||||
let dark_modules = self.modules.iter().filter(|m| m.is_dark()).count();
|
let dark_modules = self.modules.iter().filter(|m| m.is_dark()).count();
|
||||||
let total_modules = self.modules.len();
|
let total_modules = self.modules.len();
|
||||||
let ratio = dark_modules * 200 / total_modules;
|
let ratio = dark_modules * 200 / total_modules;
|
||||||
if ratio >= 100 {
|
if ratio >= 100 { ratio - 100 } else { 100 - ratio }.as_u16()
|
||||||
ratio - 100
|
|
||||||
} else {
|
|
||||||
100 - ratio
|
|
||||||
}.as_u16()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the penalty score for having too many light modules on the sides.
|
/// Compute the penalty score for having too many light modules on the sides.
|
||||||
|
@ -1986,12 +1811,8 @@ impl Canvas {
|
||||||
/// has the inverse meaning of this method, but it is very easy to convert
|
/// has the inverse meaning of this method, but it is very easy to convert
|
||||||
/// between the two (this score is (16×width − standard-score)).
|
/// between the two (this score is (16×width − standard-score)).
|
||||||
fn compute_light_side_penalty_score(&self) -> u16 {
|
fn compute_light_side_penalty_score(&self) -> u16 {
|
||||||
let h = (1..self.width)
|
let h = (1..self.width).filter(|j| !self.get(*j, -1).is_dark()).count();
|
||||||
.filter(|j| !self.get(*j, -1).is_dark())
|
let v = (1..self.width).filter(|j| !self.get(-1, *j).is_dark()).count();
|
||||||
.count();
|
|
||||||
let v = (1..self.width)
|
|
||||||
.filter(|j| !self.get(-1, *j).is_dark())
|
|
||||||
.count();
|
|
||||||
|
|
||||||
(h + v + 15 * max(h, v)).as_u16()
|
(h + v + 15 * max(h, v)).as_u16()
|
||||||
}
|
}
|
||||||
|
@ -2001,13 +1822,13 @@ impl Canvas {
|
||||||
fn compute_total_penalty_scores(&self) -> u16 {
|
fn compute_total_penalty_scores(&self) -> u16 {
|
||||||
match self.version {
|
match self.version {
|
||||||
Version::Normal(_) => {
|
Version::Normal(_) => {
|
||||||
let s1a = self.compute_adjacent_penalty_score(true);
|
let s1_a = self.compute_adjacent_penalty_score(true);
|
||||||
let s1b = self.compute_adjacent_penalty_score(false);
|
let s1_b = self.compute_adjacent_penalty_score(false);
|
||||||
let s2 = self.compute_block_penalty_score();
|
let s2 = self.compute_block_penalty_score();
|
||||||
let s3a = self.compute_finder_penalty_score(true);
|
let s3_a = self.compute_finder_penalty_score(true);
|
||||||
let s3b = self.compute_finder_penalty_score(false);
|
let s3_b = self.compute_finder_penalty_score(false);
|
||||||
let s4 = self.compute_balance_penalty_score();
|
let s4 = self.compute_balance_penalty_score();
|
||||||
s1a + s1b + s2 + s3a + s3b + s4
|
s1_a + s1_b + s2 + s3_a + s3_b + s4
|
||||||
}
|
}
|
||||||
Version::Micro(_) => self.compute_light_side_penalty_score(),
|
Version::Micro(_) => self.compute_light_side_penalty_score(),
|
||||||
}
|
}
|
||||||
|
@ -2152,12 +1973,8 @@ static ALL_PATTERNS_QR: [MaskPattern; 8] = [
|
||||||
MaskPattern::Meadow,
|
MaskPattern::Meadow,
|
||||||
];
|
];
|
||||||
|
|
||||||
static ALL_PATTERNS_MICRO_QR: [MaskPattern; 4] = [
|
static ALL_PATTERNS_MICRO_QR: [MaskPattern; 4] =
|
||||||
MaskPattern::HorizontalLines,
|
[MaskPattern::HorizontalLines, MaskPattern::LargeCheckerboard, MaskPattern::Diamonds, MaskPattern::Meadow];
|
||||||
MaskPattern::LargeCheckerboard,
|
|
||||||
MaskPattern::Diamonds,
|
|
||||||
MaskPattern::Meadow,
|
|
||||||
];
|
|
||||||
|
|
||||||
impl Canvas {
|
impl Canvas {
|
||||||
/// Construct a new canvas and apply the best masking that gives the lowest
|
/// Construct a new canvas and apply the best masking that gives the lowest
|
||||||
|
@ -2170,8 +1987,7 @@ impl Canvas {
|
||||||
let mut c = self.clone();
|
let mut c = self.clone();
|
||||||
c.apply_mask(*ptn);
|
c.apply_mask(*ptn);
|
||||||
c
|
c
|
||||||
})
|
}).min_by_key(Self::compute_total_penalty_scores)
|
||||||
.min_by_key(Self::compute_total_penalty_scores)
|
|
||||||
.expect("at least one pattern")
|
.expect("at least one pattern")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ macro_rules! impl_as {
|
||||||
self as isize
|
self as isize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_as!(i16);
|
impl_as!(i16);
|
||||||
|
|
22
src/ec.rs
22
src/ec.rs
|
@ -99,13 +99,8 @@ 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(
|
pub fn construct_codewords(rawbits: &[u8], version: Version, ec_level: EcLevel) -> QrResult<(Vec<u8>, Vec<u8>)> {
|
||||||
rawbits: &[u8],
|
let (block_1_size, block_1_count, block_2_size, block_2_count) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?;
|
||||||
version: Version,
|
|
||||||
ec_level: EcLevel,
|
|
||||||
) -> QrResult<(Vec<u8>, Vec<u8>)> {
|
|
||||||
let (block_1_size, block_1_count, block_2_size, block_2_count) =
|
|
||||||
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;
|
||||||
|
@ -122,10 +117,7 @@ pub fn construct_codewords(
|
||||||
|
|
||||||
// Generate EC codes.
|
// Generate EC codes.
|
||||||
let ec_bytes = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?;
|
let ec_bytes = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?;
|
||||||
let ec_codes = blocks
|
let ec_codes = blocks.iter().map(|block| create_error_correction_code(*block, ec_bytes)).collect::<Vec<Vec<u8>>>();
|
||||||
.iter()
|
|
||||||
.map(|block| create_error_correction_code(*block, ec_bytes))
|
|
||||||
.collect::<Vec<Vec<u8>>>();
|
|
||||||
|
|
||||||
let blocks_vec = interleave(&blocks);
|
let blocks_vec = interleave(&blocks);
|
||||||
let ec_vec = interleave(&ec_codes);
|
let ec_vec = interleave(&ec_codes);
|
||||||
|
@ -141,8 +133,7 @@ mod construct_codewords_test {
|
||||||
#[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) =
|
let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(1), EcLevel::M).unwrap();
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
@ -160,8 +151,7 @@ mod construct_codewords_test {
|
||||||
\xe6\xac\x9a\xd1\xbdRo\x11\n\x02V\xa3l\x83\xa1\xa3\xf0 ox\xc0\xb2'\x85\
|
\xe6\xac\x9a\xd1\xbdRo\x11\n\x02V\xa3l\x83\xa1\xa3\xf0 ox\xc0\xb2'\x85\
|
||||||
\x8d\xec";
|
\x8d\xec";
|
||||||
|
|
||||||
let (blocks_vec, ec_vec) =
|
let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(5), EcLevel::Q).unwrap();
|
||||||
construct_codewords(msg, Version::Normal(5), EcLevel::Q).unwrap();
|
|
||||||
assert_eq!(&*blocks_vec, &expected_blocks[..]);
|
assert_eq!(&*blocks_vec, &expected_blocks[..]);
|
||||||
assert_eq!(&*ec_vec, &expected_ec[..]);
|
assert_eq!(&*ec_vec, &expected_ec[..]);
|
||||||
}
|
}
|
||||||
|
@ -174,8 +164,8 @@ mod construct_codewords_test {
|
||||||
/// Computes the maximum allowed number of erratic modules can be introduced to
|
/// Computes the maximum allowed number of erratic modules can be introduced to
|
||||||
/// the QR code, before the data becomes truly corrupted.
|
/// the QR code, before the data becomes truly corrupted.
|
||||||
pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResult<usize> {
|
pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResult<usize> {
|
||||||
use Version::{Micro, Normal};
|
|
||||||
use EcLevel::{L, M};
|
use EcLevel::{L, M};
|
||||||
|
use Version::{Micro, Normal};
|
||||||
|
|
||||||
let p = match (version, ec_level) {
|
let p = match (version, ec_level) {
|
||||||
(Micro(2), L) | (Normal(1), L) => 3,
|
(Micro(2), L) | (Normal(1), L) => 3,
|
||||||
|
|
54
src/lib.rs
54
src/lib.rs
|
@ -46,19 +46,19 @@ extern crate test;
|
||||||
|
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
|
||||||
pub mod types;
|
|
||||||
pub mod bits;
|
pub mod bits;
|
||||||
pub mod optimize;
|
|
||||||
pub mod ec;
|
|
||||||
pub mod canvas;
|
pub mod canvas;
|
||||||
pub mod render;
|
|
||||||
mod cast;
|
mod cast;
|
||||||
|
pub mod ec;
|
||||||
|
pub mod optimize;
|
||||||
|
pub mod render;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
pub use types::{Color, EcLevel, QrResult, Version};
|
pub use types::{Color, EcLevel, QrResult, Version};
|
||||||
|
|
||||||
use render::{Pixel, Renderer};
|
|
||||||
use checked_int_cast::CheckedIntCast;
|
|
||||||
use cast::As;
|
use cast::As;
|
||||||
|
use checked_int_cast::CheckedIntCast;
|
||||||
|
use render::{Pixel, Renderer};
|
||||||
|
|
||||||
/// The encoded QR code symbol.
|
/// The encoded QR code symbol.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -92,10 +92,7 @@ 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]>>(
|
pub fn with_error_correction_level<D: AsRef<[u8]>>(data: D, ec_level: EcLevel) -> QrResult<Self> {
|
||||||
data: D,
|
|
||||||
ec_level: EcLevel,
|
|
||||||
) -> QrResult<Self> {
|
|
||||||
let bits = bits::encode_auto(data.as_ref(), ec_level)?;
|
let bits = bits::encode_auto(data.as_ref(), ec_level)?;
|
||||||
Self::with_bits(bits, ec_level)
|
Self::with_bits(bits, ec_level)
|
||||||
}
|
}
|
||||||
|
@ -113,11 +110,7 @@ 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]>>(
|
pub fn with_version<D: AsRef<[u8]>>(data: D, version: Version, ec_level: EcLevel) -> QrResult<Self> {
|
||||||
data: D,
|
|
||||||
version: Version,
|
|
||||||
ec_level: EcLevel,
|
|
||||||
) -> QrResult<Self> {
|
|
||||||
let mut bits = bits::Bits::new(version);
|
let mut bits = bits::Bits::new(version);
|
||||||
bits.push_optimal_data(data.as_ref())?;
|
bits.push_optimal_data(data.as_ref())?;
|
||||||
bits.push_terminator(ec_level)?;
|
bits.push_terminator(ec_level)?;
|
||||||
|
@ -189,21 +182,15 @@ impl QrCode {
|
||||||
/// 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 {
|
||||||
let x = x.as_i16_checked()
|
let x = x.as_i16_checked().expect("coordinate is too large for QR code");
|
||||||
.expect("coordinate is too large for QR code");
|
let y = y.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)
|
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
|
||||||
/// debugging only.
|
/// debugging only.
|
||||||
pub fn to_debug_str(&self, on_char: char, off_char: char) -> String {
|
pub fn to_debug_str(&self, on_char: char, off_char: char) -> String {
|
||||||
self.render()
|
self.render().quiet_zone(false).dark_color(on_char).light_color(off_char).build()
|
||||||
.quiet_zone(false)
|
|
||||||
.dark_color(on_char)
|
|
||||||
.light_color(off_char)
|
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the QR code to a vector of booleans. Each entry represents the
|
/// Converts the QR code to a vector of booleans. Each entry represents the
|
||||||
|
@ -217,10 +204,7 @@ 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
|
self.content.into_iter().map(|c| c != Color::Light).collect()
|
||||||
.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.
|
||||||
|
@ -342,9 +326,7 @@ mod image_tests {
|
||||||
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"))
|
let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png")).unwrap().to_luma();
|
||||||
.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());
|
||||||
}
|
}
|
||||||
|
@ -352,14 +334,13 @@ mod image_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_annex_i_micro_qr_as_image() {
|
fn test_annex_i_micro_qr_as_image() {
|
||||||
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();
|
||||||
let image = code.render()
|
let image = code
|
||||||
|
.render()
|
||||||
.min_dimensions(200, 200)
|
.min_dimensions(200, 200)
|
||||||
.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"))
|
let expected = load_from_memory(include_bytes!("test_annex_i_micro_qr_as_image.png")).unwrap().to_rgb();
|
||||||
.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());
|
||||||
}
|
}
|
||||||
|
@ -381,7 +362,8 @@ mod svg_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_annex_i_micro_qr_as_svg() {
|
fn test_annex_i_micro_qr_as_svg() {
|
||||||
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();
|
||||||
let image = code.render()
|
let image = code
|
||||||
|
.render()
|
||||||
.min_dimensions(200, 200)
|
.min_dimensions(200, 200)
|
||||||
.dark_color(SvgColor("#800000"))
|
.dark_color(SvgColor("#800000"))
|
||||||
.light_color(SvgColor("#ffff80"))
|
.light_color(SvgColor("#ffff80"))
|
||||||
|
|
|
@ -26,11 +26,7 @@ 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 {
|
let chars_count = if self.mode == Mode::Kanji { byte_size / 2 } else { byte_size };
|
||||||
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);
|
||||||
|
@ -144,9 +140,7 @@ 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(
|
return Some(Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin });
|
||||||
Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -217,10 +211,7 @@ mod parse_tests {
|
||||||
let segs = parse(b"\x81\x30");
|
let segs = parse(b"\x81\x30");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
segs,
|
segs,
|
||||||
vec![
|
vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Numeric, begin: 1, end: 2 },]
|
||||||
Segment { mode: Mode::Byte, begin: 0, end: 1 },
|
|
||||||
Segment { mode: Mode::Numeric, begin: 1, end: 2 },
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,10 +222,7 @@ mod parse_tests {
|
||||||
let segs = parse(b"\xeb\xc0");
|
let segs = parse(b"\xeb\xc0");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
segs,
|
segs,
|
||||||
vec![
|
vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 },]
|
||||||
Segment { mode: Mode::Byte, begin: 0, end: 1 },
|
|
||||||
Segment { mode: Mode::Byte, begin: 1, end: 2 },
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,10 +231,7 @@ mod parse_tests {
|
||||||
let segs = parse(b"\x81\x7f");
|
let segs = parse(b"\x81\x7f");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
segs,
|
segs,
|
||||||
vec![
|
vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 },]
|
||||||
Segment { mode: Mode::Byte, begin: 0, end: 1 },
|
|
||||||
Segment { mode: Mode::Byte, begin: 1, end: 2 },
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,10 +240,7 @@ mod parse_tests {
|
||||||
let segs = parse(b"\x81\x40\x81");
|
let segs = parse(b"\x81\x40\x81");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
segs,
|
segs,
|
||||||
vec![
|
vec![Segment { mode: Mode::Kanji, begin: 0, end: 2 }, Segment { mode: Mode::Byte, begin: 2, end: 3 },]
|
||||||
Segment { mode: Mode::Kanji, begin: 0, end: 2 },
|
|
||||||
Segment { mode: Mode::Byte, begin: 2, end: 3 },
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,9 +333,7 @@ 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
|
segments.iter().fold(0, |acc, seg| acc + seg.encoded_len(version))
|
||||||
.iter()
|
|
||||||
.fold(0, |acc, seg| acc + seg.encoded_len(version))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -428,14 +408,8 @@ mod optimize_tests {
|
||||||
#[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::Byte, begin: 10, end: 11 }],
|
||||||
Segment { mode: Mode::Kanji, begin: 0, end: 10 },
|
vec![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 },
|
|
||||||
Segment { mode: Mode::Byte, begin: 10, end: 11 },
|
|
||||||
],
|
|
||||||
Version::Normal(1),
|
Version::Normal(1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -507,7 +481,6 @@ fn bench_optimize(bencher: &mut Bencher) {
|
||||||
bencher.iter(|| Parser::new(data).optimize(Version::Normal(15)));
|
bencher.iter(|| Parser::new(data).optimize(Version::Normal(15)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//{{{ Internal types and data for parsing
|
//{{{ Internal types and data for parsing
|
||||||
|
|
|
@ -13,11 +13,11 @@ macro_rules! impl_pixel_for_image_pixel {
|
||||||
|
|
||||||
fn default_color(color: Color) -> Self {
|
fn default_color(color: Color) -> Self {
|
||||||
match color.select($s::zero(), $s::max_value()) {
|
match color.select($s::zero(), $s::max_value()) {
|
||||||
$c => $p { data: $d }
|
$c => $p { data: $d },
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_pixel_for_image_pixel!{ Luma<S>: p => [p] }
|
impl_pixel_for_image_pixel!{ Luma<S>: p => [p] }
|
||||||
|
@ -44,8 +44,8 @@ impl<P: ImagePixel + 'static> Canvas for (P, ImageBuffer<P, Vec<P::Subpixel>>) {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod render_tests {
|
mod render_tests {
|
||||||
use render::Renderer;
|
|
||||||
use image::{Luma, Rgba};
|
use image::{Luma, Rgba};
|
||||||
|
use render::Renderer;
|
||||||
use types::Color;
|
use types::Color;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -82,8 +82,7 @@ mod render_tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_render_rgba_unsized() {
|
fn test_render_rgba_unsized() {
|
||||||
let image =
|
let image = Renderer::<Rgba<u8>>::new(&[Color::Light, Color::Dark, Color::Dark, Color::Dark], 2, 1)
|
||||||
Renderer::<Rgba<u8>>::new(&[Color::Light, Color::Dark, Color::Dark, Color::Dark], 2, 1)
|
|
||||||
.module_dimensions(1, 1)
|
.module_dimensions(1, 1)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -100,11 +99,8 @@ 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::Light, Color::Dark], 2, 1)
|
||||||
&[Color::Dark, Color::Light, Color::Light, Color::Dark],
|
.min_dimensions(10, 10)
|
||||||
2,
|
|
||||||
1,
|
|
||||||
).min_dimensions(10, 10)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
@ -132,11 +128,8 @@ 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::Light, Color::Dark], 2, 1)
|
||||||
&[Color::Dark, Color::Light, Color::Light, Color::Dark],
|
.max_dimensions(10, 5)
|
||||||
2,
|
|
||||||
1,
|
|
||||||
).max_dimensions(10, 5)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Render a QR code into image.
|
//! Render a QR code into image.
|
||||||
|
|
||||||
|
use cast::As;
|
||||||
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;
|
||||||
|
@ -156,8 +156,7 @@ 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",
|
#[deprecated(since = "0.4.0", note = "renamed to `.build()` to de-emphasize the image connection")]
|
||||||
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()
|
||||||
}
|
}
|
||||||
|
@ -165,11 +164,7 @@ 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 {
|
let qz = if self.has_quiet_zone { self.quiet_zone } else { 0 };
|
||||||
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;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! String rendering support.
|
//! String rendering support.
|
||||||
|
|
||||||
|
use cast::As;
|
||||||
use render::{Canvas as RenderCanvas, Pixel};
|
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;
|
||||||
|
@ -85,7 +85,6 @@ impl<P: Element> RenderCanvas for Canvas<P> {
|
||||||
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() {
|
||||||
|
@ -106,11 +105,7 @@ fn test_render_to_string() {
|
||||||
let image: String = Renderer::<char>::new(colors, 2, 1).build();
|
let image: String = Renderer::<char>::new(colors, 2, 1).build();
|
||||||
assert_eq!(&image, " \n \u{2588} \n \u{2588} \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").dark_color("!B!").module_dimensions(2, 2).build();
|
||||||
.light_color("A")
|
|
||||||
.dark_color("!B!")
|
|
||||||
.module_dimensions(2, 2)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&image2,
|
&image2,
|
||||||
|
|
|
@ -69,8 +69,7 @@ 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)
|
write!(self.svg, "M{l} {t}h{w}v{h}H{l}V{t}", l = left, t = top, w = width, h = height).unwrap();
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_image(mut self) -> String {
|
fn into_image(mut self) -> String {
|
||||||
|
|
21
src/types.rs
21
src/types.rs
|
@ -1,8 +1,8 @@
|
||||||
use std::default::Default;
|
use cast::As;
|
||||||
use std::cmp::{Ordering, PartialOrd};
|
use std::cmp::{Ordering, PartialOrd};
|
||||||
|
use std::default::Default;
|
||||||
use std::fmt::{Display, Error, Formatter};
|
use std::fmt::{Display, Error, Formatter};
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
use cast::As;
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//{{{ QrResult
|
//{{{ QrResult
|
||||||
|
@ -182,7 +182,6 @@ impl Version {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//}}}
|
//}}}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//{{{ Mode indicator
|
//{{{ Mode indicator
|
||||||
|
@ -284,14 +283,14 @@ impl PartialOrd for Mode {
|
||||||
/// a superset of all characters supported by `a`.
|
/// a superset of all characters supported by `a`.
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
match (*self, *other) {
|
match (*self, *other) {
|
||||||
(Mode::Numeric, Mode::Alphanumeric) |
|
(Mode::Numeric, Mode::Alphanumeric)
|
||||||
(Mode::Numeric, Mode::Byte) |
|
| (Mode::Numeric, Mode::Byte)
|
||||||
(Mode::Alphanumeric, Mode::Byte) |
|
| (Mode::Alphanumeric, Mode::Byte)
|
||||||
(Mode::Kanji, Mode::Byte) => Some(Ordering::Less),
|
| (Mode::Kanji, Mode::Byte) => Some(Ordering::Less),
|
||||||
(Mode::Alphanumeric, Mode::Numeric) |
|
(Mode::Alphanumeric, Mode::Numeric)
|
||||||
(Mode::Byte, Mode::Numeric) |
|
| (Mode::Byte, Mode::Numeric)
|
||||||
(Mode::Byte, Mode::Alphanumeric) |
|
| (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,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue