xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/qr_code-2.0.0/src/types.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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