Updated Rust code to wrap valid mask numbers in a simple struct, removed unnecessary argument assertions.

This commit is contained in:
Project Nayuki 2017-11-15 17:14:40 +00:00
parent a88f0942af
commit 9628e25971
3 changed files with 41 additions and 28 deletions

View File

@ -25,6 +25,7 @@
*/ */
extern crate qrcodegen; extern crate qrcodegen;
use qrcodegen::Mask;
use qrcodegen::QrCode; use qrcodegen::QrCode;
use qrcodegen::QrCodeEcc; use qrcodegen::QrCodeEcc;
use qrcodegen::QrSegment; use qrcodegen::QrSegment;
@ -144,18 +145,18 @@ fn do_mask_demo() {
let segs = QrSegment::make_segments(&to_chars("https://www.nayuki.io/")); let segs = QrSegment::make_segments(&to_chars("https://www.nayuki.io/"));
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true).unwrap(); // Automatic mask let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true).unwrap(); // Automatic mask
print_qr(&qr); print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(3), true).unwrap(); // Force mask 3 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(3)), true).unwrap(); // Force mask 3
print_qr(&qr); print_qr(&qr);
// Chinese text as UTF-8 // Chinese text as UTF-8
let segs = QrSegment::make_segments(&to_chars("維基百科Wikipedia聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫")); let segs = QrSegment::make_segments(&to_chars("維基百科Wikipedia聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫"));
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(0), true).unwrap(); // Force mask 0 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(0)), true).unwrap(); // Force mask 0
print_qr(&qr); print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(1), true).unwrap(); // Force mask 1 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(1)), true).unwrap(); // Force mask 1
print_qr(&qr); print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(5), true).unwrap(); // Force mask 5 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(5)), true).unwrap(); // Force mask 5
print_qr(&qr); print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(7), true).unwrap(); // Force mask 7 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(7)), true).unwrap(); // Force mask 7
print_qr(&qr); print_qr(&qr);
} }

View File

@ -27,6 +27,7 @@
*/ */
extern crate qrcodegen; extern crate qrcodegen;
use qrcodegen::Mask;
use qrcodegen::QrCode; use qrcodegen::QrCode;
use qrcodegen::QrCodeEcc; use qrcodegen::QrCodeEcc;
use qrcodegen::QrSegment; use qrcodegen::QrSegment;
@ -74,7 +75,7 @@ fn main() {
} }
// Try to make QR Code symbol // Try to make QR Code symbol
let msk: Option<u8> = if mask == -1 { None } else { Some(mask as u8) }; let msk = if mask == -1 { None } else { Some(Mask::new(mask as u8)) };
match QrCode::encode_segments_advanced(&segs, ECC_LEVELS[errcorlvl as usize], match QrCode::encode_segments_advanced(&segs, ECC_LEVELS[errcorlvl as usize],
Version::new(minversion as u8), Version::new(maxversion as u8), msk, boostecl != 0) { Version::new(minversion as u8), Version::new(maxversion as u8), msk, boostecl != 0) {

View File

@ -43,7 +43,7 @@ pub struct QrCode {
// The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer). // The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
// Note that even if a constructor was called with automatic masking requested // Note that even if a constructor was called with automatic masking requested
// (mask = -1), the resulting object will still have a mask value between 0 and 7. // (mask = -1), the resulting object will still have a mask value between 0 and 7.
mask: u8, mask: Mask,
// The modules of this QR Code symbol (false = white, true = black) // The modules of this QR Code symbol (false = white, true = black)
modules: Vec<bool>, modules: Vec<bool>,
@ -101,9 +101,8 @@ impl QrCode {
// Returns a wrapped QrCode if successful, or None if the data is too long to fit // Returns a wrapped QrCode if successful, or None if the data is too long to fit
// in any version in the given range at the given ECC level. // in any version in the given range at the given ECC level.
pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc, pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc,
minversion: Version, maxversion: Version, mask: Option<u8>, boostecl: bool) -> Option<QrCode> { minversion: Version, maxversion: Version, mask: Option<Mask>, boostecl: bool) -> Option<QrCode> {
assert!(minversion.value() <= maxversion.value(), "Invalid value"); assert!(minversion.value() <= maxversion.value(), "Invalid value");
assert!(mask == None || mask.unwrap() <= 7, "Invalid value");
// Find the minimal version number to use // Find the minimal version number to use
let mut version = minversion; let mut version = minversion;
@ -168,16 +167,13 @@ impl QrCode {
// Creates a new QR Code symbol with the given version number, error correction level, // Creates a new QR Code symbol with the given version number, error correction level,
// binary data array, and mask number. This is a cumbersome low-level constructor that // binary data array, and mask number. This is a cumbersome low-level constructor that
// should not be invoked directly by the user. To go one level up, see the encode_segments() function. // should not be invoked directly by the user. To go one level up, see the encode_segments() function.
pub fn encode_codewords(ver: Version, ecl: QrCodeEcc, datacodewords: &[u8], mask: Option<u8>) -> QrCode { pub fn encode_codewords(ver: Version, ecl: QrCodeEcc, datacodewords: &[u8], mask: Option<Mask>) -> QrCode {
// Check arguments
assert!(mask == None || mask.unwrap() <= 7, "Value out of range");
// Initialize fields // Initialize fields
let size: usize = (ver.value() as usize) * 4 + 17; let size: usize = (ver.value() as usize) * 4 + 17;
let mut result = QrCode { let mut result = QrCode {
version: ver, version: ver,
size: size as i32, size: size as i32,
mask: 0, // Dummy value mask: Mask::new(0), // Dummy value
errorcorrectionlevel: ecl, errorcorrectionlevel: ecl,
modules: vec![false; size * size], // Entirely white grid modules: vec![false; size * size], // Entirely white grid
isfunction: vec![false; size * size], isfunction: vec![false; size * size],
@ -211,7 +207,7 @@ impl QrCode {
// Returns this QR Code's mask, in the range [0, 7]. // Returns this QR Code's mask, in the range [0, 7].
pub fn mask(&self) -> u8 { pub fn mask(&self) -> Mask {
self.mask self.mask
} }
@ -297,18 +293,18 @@ impl QrCode {
} }
// Draw configuration data // Draw configuration data
self.draw_format_bits(0); // Dummy mask value; overwritten later in the constructor self.draw_format_bits(Mask::new(0)); // Dummy mask value; overwritten later in the constructor
self.draw_version(); self.draw_version();
} }
// Draws two copies of the format bits (with its own error correction code) // Draws two copies of the format bits (with its own error correction code)
// based on the given mask and this object's error correction level field. // based on the given mask and this object's error correction level field.
fn draw_format_bits(&mut self, mask: u8) { fn draw_format_bits(&mut self, mask: Mask) {
// Calculate error correction code and pack bits // Calculate error correction code and pack bits
let size: i32 = self.size; let size: i32 = self.size;
// errcorrlvl is uint2, mask is uint3 // errcorrlvl is uint2, mask is uint3
let mut data: u32 = self.errorcorrectionlevel.format_bits() << 3 | (mask as u32); let mut data: u32 = self.errorcorrectionlevel.format_bits() << 3 | (mask.value() as u32);
let mut rem: u32 = data; let mut rem: u32 = data;
for _ in 0 .. 10 { for _ in 0 .. 10 {
rem = (rem << 1) ^ ((rem >> 9) * 0x537); rem = (rem << 1) ^ ((rem >> 9) * 0x537);
@ -477,8 +473,8 @@ impl QrCode {
// properties, calling applyMask(m) twice with the same value is equivalent to no change at all. // properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
// This means it is possible to apply a mask, undo it, and try another mask. Note that a final // This means it is possible to apply a mask, undo it, and try another mask. Note that a final
// well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.). // well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
fn apply_mask(&mut self, mask: u8) { fn apply_mask(&mut self, mask: Mask) {
assert!(mask <= 7, "Mask value out of range"); let mask = mask.value();
for y in 0 .. self.size { for y in 0 .. self.size {
for x in 0 .. self.size { for x in 0 .. self.size {
let invert: bool = match mask { let invert: bool = match mask {
@ -501,22 +497,22 @@ impl QrCode {
// A messy helper function for the constructors. This QR Code must be in an unmasked state when this // A messy helper function for the constructors. This QR Code must be in an unmasked state when this
// method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed. // method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
// This method applies and returns the actual mask chosen, from 0 to 7. // This method applies and returns the actual mask chosen, from 0 to 7.
fn handle_constructor_masking(&mut self, mut mask: Option<u8>) { fn handle_constructor_masking(&mut self, mut mask: Option<Mask>) {
if mask == None { // Automatically choose best mask if mask.is_none() { // Automatically choose best mask
let mut minpenalty: i32 = std::i32::MAX; let mut minpenalty: i32 = std::i32::MAX;
for i in 0u8 .. 8 { for i in 0u8 .. 8 {
self.draw_format_bits(i); let newmask = Mask::new(i);
self.apply_mask(i); self.draw_format_bits(newmask);
self.apply_mask(newmask);
let penalty: i32 = self.get_penalty_score(); let penalty: i32 = self.get_penalty_score();
if penalty < minpenalty { if penalty < minpenalty {
mask = Some(i); mask = Some(newmask);
minpenalty = penalty; minpenalty = penalty;
} }
self.apply_mask(i); // Undoes the mask due to XOR self.apply_mask(newmask); // Undoes the mask due to XOR
} }
} }
let msk: u8 = mask.unwrap(); let msk: Mask = mask.unwrap();
assert!(msk <= 7, "Assertion error");
self.draw_format_bits(msk); // Overwrite old format bits self.draw_format_bits(msk); // Overwrite old format bits
self.apply_mask(msk); // Apply the final choice of mask self.apply_mask(msk); // Apply the final choice of mask
self.mask = msk; self.mask = msk;
@ -1104,3 +1100,18 @@ impl Version {
self.0 self.0
} }
} }
#[derive(Copy, Clone)]
pub struct Mask(u8);
impl Mask {
pub fn new(mask: u8) -> Self {
assert!(mask <= 7, "Mask value out of range");
Mask(mask)
}
pub fn value(&self) -> u8 {
self.0
}
}