From 9628e259710c6d24a89b0a1800a1951a0000b969 Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Wed, 15 Nov 2017 17:14:40 +0000 Subject: [PATCH] Updated Rust code to wrap valid mask numbers in a simple struct, removed unnecessary argument assertions. --- rust/examples/qrcodegen-demo.rs | 11 ++++--- rust/examples/qrcodegen-worker.rs | 3 +- rust/src/lib.rs | 55 ++++++++++++++++++------------- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/rust/examples/qrcodegen-demo.rs b/rust/examples/qrcodegen-demo.rs index 7c73b27..1fa2d3f 100644 --- a/rust/examples/qrcodegen-demo.rs +++ b/rust/examples/qrcodegen-demo.rs @@ -25,6 +25,7 @@ */ extern crate qrcodegen; +use qrcodegen::Mask; use qrcodegen::QrCode; use qrcodegen::QrCodeEcc; use qrcodegen::QrSegment; @@ -144,18 +145,18 @@ fn do_mask_demo() { 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 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); // Chinese text as UTF-8 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); - 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); - 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); - 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); } diff --git a/rust/examples/qrcodegen-worker.rs b/rust/examples/qrcodegen-worker.rs index a527f1a..5537f19 100644 --- a/rust/examples/qrcodegen-worker.rs +++ b/rust/examples/qrcodegen-worker.rs @@ -27,6 +27,7 @@ */ extern crate qrcodegen; +use qrcodegen::Mask; use qrcodegen::QrCode; use qrcodegen::QrCodeEcc; use qrcodegen::QrSegment; @@ -74,7 +75,7 @@ fn main() { } // Try to make QR Code symbol - let msk: Option = 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], Version::new(minversion as u8), Version::new(maxversion as u8), msk, boostecl != 0) { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 6255d94..949642f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -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). // 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: u8, + mask: Mask, // The modules of this QR Code symbol (false = white, true = black) modules: Vec, @@ -101,9 +101,8 @@ impl QrCode { // 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. pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc, - minversion: Version, maxversion: Version, mask: Option, boostecl: bool) -> Option { + minversion: Version, maxversion: Version, mask: Option, boostecl: bool) -> Option { assert!(minversion.value() <= maxversion.value(), "Invalid value"); - assert!(mask == None || mask.unwrap() <= 7, "Invalid value"); // Find the minimal version number to use let mut version = minversion; @@ -168,16 +167,13 @@ impl QrCode { // 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 // 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) -> QrCode { - // Check arguments - assert!(mask == None || mask.unwrap() <= 7, "Value out of range"); - + pub fn encode_codewords(ver: Version, ecl: QrCodeEcc, datacodewords: &[u8], mask: Option) -> QrCode { // Initialize fields let size: usize = (ver.value() as usize) * 4 + 17; let mut result = QrCode { version: ver, size: size as i32, - mask: 0, // Dummy value + mask: Mask::new(0), // Dummy value errorcorrectionlevel: ecl, modules: vec![false; size * size], // Entirely white grid isfunction: vec![false; size * size], @@ -211,7 +207,7 @@ impl QrCode { // Returns this QR Code's mask, in the range [0, 7]. - pub fn mask(&self) -> u8 { + pub fn mask(&self) -> Mask { self.mask } @@ -297,18 +293,18 @@ impl QrCode { } // 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(); } // 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. - fn draw_format_bits(&mut self, mask: u8) { + fn draw_format_bits(&mut self, mask: Mask) { // Calculate error correction code and pack bits let size: i32 = self.size; // 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; for _ in 0 .. 10 { 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. // 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.). - fn apply_mask(&mut self, mask: u8) { - assert!(mask <= 7, "Mask value out of range"); + fn apply_mask(&mut self, mask: Mask) { + let mask = mask.value(); for y in 0 .. self.size { for x in 0 .. self.size { 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 // 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. - fn handle_constructor_masking(&mut self, mut mask: Option) { - if mask == None { // Automatically choose best mask + fn handle_constructor_masking(&mut self, mut mask: Option) { + if mask.is_none() { // Automatically choose best mask let mut minpenalty: i32 = std::i32::MAX; for i in 0u8 .. 8 { - self.draw_format_bits(i); - self.apply_mask(i); + let newmask = Mask::new(i); + self.draw_format_bits(newmask); + self.apply_mask(newmask); let penalty: i32 = self.get_penalty_score(); if penalty < minpenalty { - mask = Some(i); + mask = Some(newmask); 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(); - assert!(msk <= 7, "Assertion error"); + let msk: Mask = mask.unwrap(); self.draw_format_bits(msk); // Overwrite old format bits self.apply_mask(msk); // Apply the final choice of mask self.mask = msk; @@ -1104,3 +1100,18 @@ impl Version { 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 + } +}