1 //! Type to support QR code encoding 2 3 use crate::cast::As; 4 use crate::structured::StructuredQrError; 5 use std::cmp::{Ordering, PartialOrd}; 6 use std::default::Default; 7 use std::fmt::{Display, Error, Formatter}; 8 use std::ops::Not; 9 10 /// `QrError` encodes the error encountered when generating a QR code. 11 #[derive(Debug, PartialEq, Eq, Copy, Clone)] 12 pub enum QrError { 13 /// The data is too long to encode into a QR code for the given version. 14 DataTooLong, 15 16 /// The provided version / error correction level combination is invalid. 17 InvalidVersion, 18 19 /// Some characters in the data cannot be supported by the provided QR code 20 /// version. 21 UnsupportedCharacterSet, 22 23 /// The provided ECI designator is invalid. A valid designator should be 24 /// between 0 and 999999. 25 InvalidEciDesignator, 26 27 /// A character not belonging to the character set is found. 28 InvalidCharacter, 29 30 /// 31 Structured(StructuredQrError), 32 } 33 34 impl Display for QrError { fmt(&self, fmt: &mut Formatter) -> Result<(), Error>35 fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { 36 match *self { 37 QrError::DataTooLong => fmt.write_str("data too long"), 38 QrError::InvalidVersion => fmt.write_str("invalid version"), 39 QrError::UnsupportedCharacterSet => fmt.write_str("unsupported character set"), 40 QrError::InvalidEciDesignator => fmt.write_str("invalid ECI designator"), 41 QrError::InvalidCharacter => fmt.write_str("invalid character"), 42 QrError::Structured(e) => write!(fmt, "{}", e), 43 } 44 } 45 } 46 47 impl ::std::error::Error for QrError {} 48 49 /// `QrResult` is a convenient alias for a QR code generation result. 50 pub type QrResult<T> = Result<T, QrError>; 51 52 //}}} 53 //------------------------------------------------------------------------------ 54 //{{{ Color 55 56 /// The color of a module. 57 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] 58 pub enum Color { 59 /// The module is light colored. 60 Light, 61 /// The module is dark colored. 62 Dark, 63 } 64 65 impl Color { 66 /// Selects a value according to color of the module. Equivalent to 67 /// `if self != Color::Light { dark } else { light }`. 68 /// 69 /// # Examples 70 /// 71 /// ```rust 72 /// # use qr_code::types::Color; 73 /// assert_eq!(Color::Light.select(1, 0), 0); 74 /// assert_eq!(Color::Dark.select("black", "white"), "black"); 75 /// ``` select<T>(self, dark: T, light: T) -> T76 pub fn select<T>(self, dark: T, light: T) -> T { 77 match self { 78 Color::Light => light, 79 Color::Dark => dark, 80 } 81 } 82 } 83 84 impl Not for Color { 85 type Output = Self; not(self) -> Self86 fn not(self) -> Self { 87 match self { 88 Color::Light => Color::Dark, 89 Color::Dark => Color::Light, 90 } 91 } 92 } 93 94 //}}} 95 //------------------------------------------------------------------------------ 96 //{{{ Error correction level 97 98 /// The error correction level. It allows the original information be recovered 99 /// even if parts of the code is damaged. 100 #[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)] 101 #[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))] 102 pub enum EcLevel { 103 /// Low error correction. Allows up to 7% of wrong blocks. 104 L = 0, 105 106 /// Medium error correction (default). Allows up to 15% of wrong blocks. 107 M = 1, 108 109 /// "Quartile" error correction. Allows up to 25% of wrong blocks. 110 Q = 2, 111 112 /// High error correction. Allows up to 30% of wrong blocks. 113 H = 3, 114 } 115 116 //}}} 117 //------------------------------------------------------------------------------ 118 //{{{ Version 119 120 /// In QR code terminology, `Version` means the size of the generated image. 121 /// Larger version means the size of code is larger, and therefore can carry 122 /// more information. 123 /// 124 /// The smallest version is `Version::Normal(1)` of size 21×21, and the largest 125 /// is `Version::Normal(40)` of size 177×177. 126 #[derive(Debug, PartialEq, Eq, Copy, Clone)] 127 pub enum Version { 128 /// A normal QR code version. The parameter should be between 1 and 40. 129 Normal(i16), 130 131 /// A Micro QR code version. The parameter should be between 1 and 4. 132 Micro(i16), 133 } 134 135 impl Version { 136 /// Get the number of "modules" on each size of the QR code, i.e. the width 137 /// and height of the code. width(self) -> i16138 pub fn width(self) -> i16 { 139 match self { 140 Version::Normal(v) => v * 4 + 17, 141 Version::Micro(v) => v * 2 + 9, 142 } 143 } 144 145 /// Obtains an object from a hard-coded table. 146 /// 147 /// The table must be a 44×4 array. The outer array represents the content 148 /// for each version. The first 40 entry corresponds to QR code versions 1 149 /// to 40, and the last 4 corresponds to Micro QR code version 1 to 4. The 150 /// inner array represents the content in each error correction level, in 151 /// the order [L, M, Q, H]. 152 /// 153 /// # Errors 154 /// 155 /// If the entry compares equal to the default value of `T`, this method 156 /// returns `Err(QrError::InvalidVersion)`. fetch<T>(self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult<T> where T: PartialEq + Default + Copy,157 pub fn fetch<T>(self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult<T> 158 where 159 T: PartialEq + Default + Copy, 160 { 161 match self { 162 Version::Normal(v @ 1..=40) => { 163 return Ok(table[(v - 1).as_usize()][ec_level as usize]); 164 } 165 Version::Micro(v @ 1..=4) => { 166 let obj = table[(v + 39).as_usize()][ec_level as usize]; 167 if obj != T::default() { 168 return Ok(obj); 169 } 170 } 171 _ => {} 172 } 173 Err(QrError::InvalidVersion) 174 } 175 176 /// The number of bits needed to encode the mode indicator. mode_bits_count(self) -> usize177 pub fn mode_bits_count(self) -> usize { 178 match self { 179 Version::Micro(a) => (a - 1).as_usize(), 180 _ => 4, 181 } 182 } 183 184 /// Checks whether is version refers to a Micro QR code. is_micro(self) -> bool185 pub fn is_micro(self) -> bool { 186 match self { 187 Version::Normal(_) => false, 188 Version::Micro(_) => true, 189 } 190 } 191 } 192 193 //}}} 194 //------------------------------------------------------------------------------ 195 //{{{ Mode indicator 196 197 /// The mode indicator, which specifies the character set of the encoded data. 198 #[derive(Debug, PartialEq, Eq, Copy, Clone)] 199 pub enum Mode { 200 /// The data contains only characters 0 to 9. 201 Numeric, 202 203 /// The data contains only uppercase letters (A–Z), numbers (0–9) and a few 204 /// punctuations marks (space, `$`, `%`, `*`, `+`, `-`, `.`, `/`, `:`). 205 Alphanumeric, 206 207 /// The data contains arbitrary binary data. 208 Byte, 209 210 /// The data contains Shift-JIS-encoded double-byte text. 211 Kanji, 212 } 213 214 impl Mode { 215 /// Computes the number of bits needed to encode the data length. 216 /// 217 /// use qr_code::types::{Version, Mode}; 218 /// 219 /// assert_eq!(Mode::Numeric.length_bits_count(Version::Normal(1)), 10); 220 /// 221 /// This method will return `Err(QrError::UnsupportedCharacterSet)` if the 222 /// mode is not supported in the given version. length_bits_count(self, version: Version) -> usize223 pub fn length_bits_count(self, version: Version) -> usize { 224 match version { 225 Version::Micro(a) => { 226 let a = a.as_usize(); 227 match self { 228 Mode::Numeric => 2 + a, 229 Mode::Alphanumeric | Mode::Byte => 1 + a, 230 Mode::Kanji => a, 231 } 232 } 233 Version::Normal(1..=9) => match self { 234 Mode::Numeric => 10, 235 Mode::Alphanumeric => 9, 236 Mode::Byte | Mode::Kanji => 8, 237 }, 238 Version::Normal(10..=26) => match self { 239 Mode::Numeric => 12, 240 Mode::Alphanumeric => 11, 241 Mode::Byte => 16, 242 Mode::Kanji => 10, 243 }, 244 Version::Normal(_) => match self { 245 Mode::Numeric => 14, 246 Mode::Alphanumeric => 13, 247 Mode::Byte => 16, 248 Mode::Kanji => 12, 249 }, 250 } 251 } 252 253 /// Computes the number of bits needed to some data of a given raw length. 254 /// 255 /// use qr_code::types::Mode; 256 /// 257 /// assert_eq!(Mode::Numeric.data_bits_count(7), 24); 258 /// 259 /// Note that in Kanji mode, the `raw_data_len` is the number of Kanjis, 260 /// i.e. half the total size of bytes. data_bits_count(self, raw_data_len: usize) -> usize261 pub fn data_bits_count(self, raw_data_len: usize) -> usize { 262 match self { 263 Mode::Numeric => (raw_data_len * 10 + 2) / 3, 264 Mode::Alphanumeric => (raw_data_len * 11 + 1) / 2, 265 Mode::Byte => raw_data_len * 8, 266 Mode::Kanji => raw_data_len * 13, 267 } 268 } 269 270 /// Find the lowest common mode which both modes are compatible with. 271 /// 272 /// use qr_code::types::Mode; 273 /// 274 /// let a = Mode::Numeric; 275 /// let b = Mode::Kanji; 276 /// let c = a.max(b); 277 /// assert!(a <= c); 278 /// assert!(b <= c); 279 /// max(self, other: Self) -> Self280 pub fn max(self, other: Self) -> Self { 281 match self.partial_cmp(&other) { 282 Some(Ordering::Less) | Some(Ordering::Equal) => other, 283 Some(Ordering::Greater) => self, 284 None => Mode::Byte, 285 } 286 } 287 288 pub(crate) const ALL_MODES: &'static [Mode] = 289 &[Mode::Numeric, Mode::Alphanumeric, Mode::Byte, Mode::Kanji]; 290 } 291 292 impl PartialOrd for Mode { 293 /// Defines a partial ordering between modes. If `a <= b`, then `b` contains 294 /// a superset of all characters supported by `a`. partial_cmp(&self, other: &Self) -> Option<Ordering>295 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 296 match (*self, *other) { 297 (Mode::Numeric, Mode::Alphanumeric) 298 | (Mode::Numeric, Mode::Byte) 299 | (Mode::Alphanumeric, Mode::Byte) 300 | (Mode::Kanji, Mode::Byte) => Some(Ordering::Less), 301 (Mode::Alphanumeric, Mode::Numeric) 302 | (Mode::Byte, Mode::Numeric) 303 | (Mode::Byte, Mode::Alphanumeric) 304 | (Mode::Byte, Mode::Kanji) => Some(Ordering::Greater), 305 (a, b) if a == b => Some(Ordering::Equal), 306 _ => None, 307 } 308 } 309 } 310 311 #[cfg(test)] 312 mod mode_tests { 313 use crate::types::Mode::{Alphanumeric, Byte, Kanji, Numeric}; 314 315 #[test] test_mode_order()316 fn test_mode_order() { 317 assert!(Numeric < Alphanumeric); 318 assert!(Byte > Kanji); 319 assert!(!(Numeric < Kanji)); 320 assert!(!(Numeric >= Kanji)); 321 } 322 323 #[test] test_max()324 fn test_max() { 325 assert_eq!(Byte.max(Kanji), Byte); 326 assert_eq!(Numeric.max(Alphanumeric), Alphanumeric); 327 assert_eq!(Alphanumeric.max(Alphanumeric), Alphanumeric); 328 assert_eq!(Numeric.max(Kanji), Byte); 329 assert_eq!(Kanji.max(Numeric), Byte); 330 assert_eq!(Alphanumeric.max(Numeric), Alphanumeric); 331 assert_eq!(Kanji.max(Kanji), Kanji); 332 } 333 } 334 335 //}}} 336