From a88f0942afe7ee188173270ef5304ef9bbbce2dc Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Wed, 15 Nov 2017 17:06:26 +0000 Subject: [PATCH] Updated Rust code to wrap valid version numbers in a simple struct, removed unnecessary argument assertions. --- rust/examples/qrcodegen-worker.rs | 9 ++-- rust/src/lib.rs | 69 +++++++++++++++++++------------ 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/rust/examples/qrcodegen-worker.rs b/rust/examples/qrcodegen-worker.rs index d79948a..a527f1a 100644 --- a/rust/examples/qrcodegen-worker.rs +++ b/rust/examples/qrcodegen-worker.rs @@ -30,6 +30,7 @@ extern crate qrcodegen; use qrcodegen::QrCode; use qrcodegen::QrCodeEcc; use qrcodegen::QrSegment; +use qrcodegen::Version; fn main() { @@ -57,9 +58,9 @@ fn main() { let mask = read_int(); let boostecl = read_int(); assert!(0 <= errcorlvl && errcorlvl <= 3); - assert!((qrcodegen::QrCode_MIN_VERSION as i16) <= minversion + assert!((qrcodegen::QrCode_MIN_VERSION.value() as i16) <= minversion && minversion <= maxversion - && maxversion <= (qrcodegen::QrCode_MAX_VERSION as i16)); + && maxversion <= (qrcodegen::QrCode_MAX_VERSION.value() as i16)); assert!(-1 <= mask && mask <= 7); assert!(boostecl >> 1 == 0); @@ -75,11 +76,11 @@ fn main() { // Try to make QR Code symbol let msk: Option = if mask == -1 { None } else { Some(mask as u8) }; match QrCode::encode_segments_advanced(&segs, ECC_LEVELS[errcorlvl as usize], - minversion as u8, maxversion as u8, msk, boostecl != 0) { + Version::new(minversion as u8), Version::new(maxversion as u8), msk, boostecl != 0) { Some(qr) => { // Print grid of modules - println!("{}", qr.version()); + println!("{}", qr.version().value()); for y in 0 .. qr.size() { for x in 0 .. qr.size() { println!("{}", qr.get_module(x, y) as i8); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 3562af4..6255d94 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -31,7 +31,7 @@ pub struct QrCode { // This QR Code symbol's version number, which is always between 1 and 40 (inclusive). - version: u8, + version: Version, // The width and height of this QR Code symbol, measured in modules. // Always equal to version × 4 + 17, in the range 21 to 177. @@ -101,12 +101,12 @@ 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: u8, maxversion: u8, mask: Option, boostecl: bool) -> Option { - assert!(QrCode_MIN_VERSION <= minversion && minversion <= maxversion && maxversion <= QrCode_MAX_VERSION, "Invalid value"); + 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: u8 = minversion; + let mut version = minversion; let datausedbits: usize; loop { // Number of data bits available @@ -117,10 +117,10 @@ impl QrCode { break; // This version number is found to be suitable } } - if version >= maxversion { // All versions in the range could not fit the given data + if version.value() >= maxversion.value() { // All versions in the range could not fit the given data return None; } - version += 1; + version = Version::new(version.value() + 1); } // Increase the error correction level while the data still fits in the current version number @@ -168,13 +168,12 @@ 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: u8, ecl: QrCodeEcc, datacodewords: &[u8], mask: Option) -> QrCode { + pub fn encode_codewords(ver: Version, ecl: QrCodeEcc, datacodewords: &[u8], mask: Option) -> QrCode { // Check arguments - assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Value out of range"); assert!(mask == None || mask.unwrap() <= 7, "Value out of range"); // Initialize fields - let size: usize = (ver as usize) * 4 + 17; + let size: usize = (ver.value() as usize) * 4 + 17; let mut result = QrCode { version: ver, size: size as i32, @@ -194,7 +193,7 @@ impl QrCode { // Returns this QR Code's version, in the range [1, 40]. - pub fn version(&self) -> u8 { + pub fn version(&self) -> Version { self.version } @@ -343,16 +342,16 @@ impl QrCode { // Draws two copies of the version bits (with its own error correction code), // based on this object's version field (which only has an effect for 7 <= version <= 40). fn draw_version(&mut self) { - if self.version < 7 { + if self.version.value() < 7 { return; } // Calculate error correction code and pack bits - let mut rem: u32 = self.version as u32; // version is uint6, in the range [7, 40] + let mut rem: u32 = self.version.value() as u32; // version is uint6, in the range [7, 40] for _ in 0 .. 12 { rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); } - let data: u32 = (self.version as u32) << 12 | rem; // uint18 + let data: u32 = (self.version.value() as u32) << 12 | rem; // uint18 assert!(data >> 18 == 0, "Assertion error"); // Draw two copies @@ -621,8 +620,8 @@ impl QrCode { // Returns a set of positions of the alignment patterns in ascending order. These positions are // used on both the x and y axes. Each value in the resulting list is in the range [0, 177). // This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes. - fn get_alignment_pattern_positions(ver: u8) -> Vec { - assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Version number out of range"); + fn get_alignment_pattern_positions(ver: Version) -> Vec { + let ver = ver.value(); if ver == 1 { vec![] } else { @@ -647,8 +646,8 @@ impl QrCode { // Returns the number of data bits that can be stored in a QR Code of the given version number, after // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. - fn get_num_raw_data_modules(ver: u8) -> usize { - assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Version number out of range"); + fn get_num_raw_data_modules(ver: Version) -> usize { + let ver = ver.value(); let mut result: usize = (16 * (ver as usize) + 128) * (ver as usize) + 64; if ver >= 2 { let numalign: usize = (ver as usize) / 7 + 2; @@ -664,8 +663,7 @@ impl QrCode { // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any // QR Code of the given version number and error correction level, with remainder bits discarded. // This stateless pure function could be implemented as a (40*4)-cell lookup table. - fn get_num_data_codewords(ver: u8, ecl: QrCodeEcc) -> usize { - assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Version number out of range"); + fn get_num_data_codewords(ver: Version, ecl: QrCodeEcc) -> usize { QrCode::get_num_raw_data_modules(ver) / 8 - QrCode::table_get(&ECC_CODEWORDS_PER_BLOCK, ver, ecl) * QrCode::table_get(&NUM_ERROR_CORRECTION_BLOCKS, ver, ecl) @@ -673,9 +671,8 @@ impl QrCode { // Returns an entry from the given table based on the given values. - fn table_get(table: &'static [[i8; 41]; 4], ver: u8, ecl: QrCodeEcc) -> usize { - assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Version number out of range"); - table[ecl.ordinal()][ver as usize] as usize + fn table_get(table: &'static [[i8; 41]; 4], ver: Version, ecl: QrCodeEcc) -> usize { + table[ecl.ordinal()][ver.value() as usize] as usize } } @@ -683,8 +680,8 @@ impl QrCode { /*---- Public constants ----*/ -pub const QrCode_MIN_VERSION: u8 = 1; -pub const QrCode_MAX_VERSION: u8 = 40; +pub const QrCode_MIN_VERSION: Version = Version( 1); +pub const QrCode_MAX_VERSION: Version = Version(40); /*---- Private tables of constants ----*/ @@ -981,8 +978,7 @@ impl QrSegment { /*---- Other static functions ----*/ // Package-private helper function. - fn get_total_bits(segs: &[QrSegment], version: u8) -> Option { - assert!(QrCode_MIN_VERSION <= version && version <= QrCode_MAX_VERSION, "Version number out of range"); + fn get_total_bits(segs: &[QrSegment], version: Version) -> Option { let mut result: usize = 0; for seg in segs { let ccbits = seg.mode.num_char_count_bits(version); @@ -1050,7 +1046,7 @@ impl QrSegmentMode { // Returns the bit width of the segment character count field // for this mode object at the given version number. - pub fn num_char_count_bits(&self, ver: u8) -> u8 { + pub fn num_char_count_bits(&self, ver: Version) -> u8 { let array: [u8; 3] = match *self { QrSegmentMode::Numeric => [10, 12, 14], QrSegmentMode::Alphanumeric => [ 9, 11, 13], @@ -1059,6 +1055,7 @@ impl QrSegmentMode { QrSegmentMode::Eci => [ 0, 0, 0], }; + let ver = ver.value(); if 1 <= ver && ver <= 9 { array[0] } else if 10 <= ver && ver <= 26 { @@ -1089,3 +1086,21 @@ impl BitBuffer { } } } + + + +/*---- Miscellaneous values ----*/ + +#[derive(Copy, Clone)] +pub struct Version(u8); + +impl Version { + pub fn new(ver: u8) -> Self { + assert!(QrCode_MIN_VERSION.value() <= ver && ver <= QrCode_MAX_VERSION.value(), "Version number out of range"); + Version(ver) + } + + pub fn value(&self) -> u8 { + self.0 + } +}