barcode_gen/
lib.rs

1use std::{collections::VecDeque, fmt::Display, sync::atomic::AtomicUsize};
2
3/// The different barcode types, used to keep track of the type used in the encoder.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum BarcodeType {
6    CodeA,
7    CodeB,
8    CodeC,
9}
10
11/// A value in a barcode, consists of regular characters,
12/// digits for Code C, and control codes.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum BarcodeValue {
15    RegularCharacter(char),
16    Digit(u8),
17    FNC1,
18    FNC2,
19    FNC3,
20    FNC4,
21    StartA,
22    StartB,
23    StartC,
24    Stop,
25    ShiftA,
26    ShiftB,
27    CodeA,
28    CodeB,
29    CodeC,
30}
31
32impl From<char> for BarcodeValue {
33    fn from(value: char) -> Self {
34        BarcodeValue::RegularCharacter(value)
35    }
36}
37
38impl From<u8> for BarcodeValue {
39    fn from(value: u8) -> Self {
40        BarcodeValue::Digit(value)
41    }
42}
43
44/// An entry in the encoding table.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub struct TableEntry {
47    value: u8,
48    a: BarcodeValue,
49    b: BarcodeValue,
50    c: BarcodeValue,
51    latin: char,
52}
53
54impl TableEntry {
55    /// create a new table entry
56    pub fn new(
57        value: u8,
58        a: impl Into<BarcodeValue>,
59        b: impl Into<BarcodeValue>,
60        c: impl Into<BarcodeValue>,
61        latin: char,
62    ) -> Self {
63        Self::new_barcode_value(value, a.into(), b.into(), c.into(), latin)
64    }
65
66    const fn new_barcode_value(
67        value: u8,
68        a: BarcodeValue,
69        b: BarcodeValue,
70        c: BarcodeValue,
71        latin: char,
72    ) -> Self {
73        TableEntry {
74            value,
75            a,
76            b,
77            c,
78            latin,
79        }
80    }
81
82    const fn new_barcode_chars(value: u8, a: char, b: char, c: u8, latin: char) -> Self {
83        Self::new_barcode_value(
84            value,
85            BarcodeValue::RegularCharacter(a),
86            BarcodeValue::RegularCharacter(b),
87            BarcodeValue::Digit(c),
88            latin,
89        )
90    }
91
92    /// the value of the entry, used for calculating the check digit
93    pub fn value(&self) -> u8 {
94        self.value
95    }
96
97    /// the most common character used to represent this value
98    pub fn latin(&self) -> char {
99        self.latin
100    }
101
102    /// the bits used to encode the value on a normal barcode
103    pub fn barcode_bits(&self) -> u32 {
104        BARCODE_BITS[self.value() as usize].0
105    }
106
107    /// the runs for the code
108    ///
109    /// A run of 1231 would mean 1001110 in binary
110    pub fn barcode_runs(&self) -> &'static str {
111        BARCODE_BITS[self.value() as usize].1
112    }
113}
114
115const BARCODE_BITS: [(u32, &str); 109] = [
116    (0b11011001100, "212222"),
117    (0b11001101100, "222122"),
118    (0b11001100110, "222221"),
119    (0b10010011000, "121223"),
120    (0b10010001100, "121322"),
121    (0b10001001100, "131222"),
122    (0b10011001000, "122213"),
123    (0b10011000100, "122312"),
124    (0b10001100100, "132212"),
125    (0b11001001000, "221213"),
126    (0b11001000100, "221312"),
127    (0b11000100100, "231212"),
128    (0b10110011100, "112232"),
129    (0b10011011100, "122132"),
130    (0b10011001110, "122231"),
131    (0b10111001100, "113222"),
132    (0b10011101100, "123122"),
133    (0b10011100110, "123221"),
134    (0b11001110010, "223211"),
135    (0b11001011100, "221132"),
136    (0b11001001110, "221231"),
137    (0b11011100100, "213212"),
138    (0b11001110100, "223112"),
139    (0b11101101110, "312131"),
140    (0b11101001100, "311222"),
141    (0b11100101100, "321122"),
142    (0b11100100110, "321221"),
143    (0b11101100100, "312212"),
144    (0b11100110100, "322112"),
145    (0b11100110010, "322211"),
146    (0b11011011000, "212123"),
147    (0b11011000110, "212321"),
148    (0b11000110110, "232121"),
149    (0b10100011000, "111323"),
150    (0b10001011000, "131123"),
151    (0b10001000110, "131321"),
152    (0b10110001000, "112313"),
153    (0b10001101000, "132113"),
154    (0b10001100010, "132311"),
155    (0b11010001000, "211313"),
156    (0b11000101000, "231113"),
157    (0b11000100010, "231311"),
158    (0b10110111000, "112133"),
159    (0b10110001110, "112331"),
160    (0b10001101110, "132131"),
161    (0b10111011000, "113123"),
162    (0b10111000110, "113321"),
163    (0b10001110110, "133121"),
164    (0b11101110110, "313121"),
165    (0b11010001110, "211331"),
166    (0b11000101110, "231131"),
167    (0b11011101000, "213113"),
168    (0b11011100010, "213311"),
169    (0b11011101110, "213131"),
170    (0b11101011000, "311123"),
171    (0b11101000110, "311321"),
172    (0b11100010110, "331121"),
173    (0b11101101000, "312113"),
174    (0b11101100010, "312311"),
175    (0b11100011010, "332111"),
176    (0b11101111010, "314111"),
177    (0b11001000010, "221411"),
178    (0b11110001010, "431111"),
179    (0b10100110000, "111224"),
180    (0b10100001100, "111422"),
181    (0b10010110000, "121124"),
182    (0b10010000110, "121421"),
183    (0b10000101100, "141122"),
184    (0b10000100110, "141221"),
185    (0b10110010000, "112214"),
186    (0b10110000100, "112412"),
187    (0b10011010000, "122114"),
188    (0b10011000010, "122411"),
189    (0b10000110100, "142112"),
190    (0b10000110010, "142211"),
191    (0b11000010010, "241211"),
192    (0b11001010000, "221114"),
193    (0b11110111010, "413111"),
194    (0b11000010100, "241112"),
195    (0b10001111010, "134111"),
196    (0b10100111100, "111242"),
197    (0b10010111100, "121142"),
198    (0b10010011110, "121241"),
199    (0b10111100100, "114212"),
200    (0b10011110100, "124112"),
201    (0b10011110010, "124211"),
202    (0b11110100100, "411212"),
203    (0b11110010100, "421112"),
204    (0b11110010010, "421211"),
205    (0b11011011110, "212141"),
206    (0b11011110110, "214121"),
207    (0b11110110110, "412121"),
208    (0b10101111000, "111143"),
209    (0b10100011110, "111341"),
210    (0b10001011110, "131141"),
211    (0b10111101000, "114113"),
212    (0b10111100010, "114311"),
213    (0b11110101000, "411113"),
214    (0b11110100010, "411311"),
215    (0b10111011110, "113141"),
216    (0b10111101110, "114131"),
217    (0b11101011110, "311141"),
218    (0b11110101110, "411131"),
219    (0b11010000100, "211412"),
220    (0b11010010000, "211214"),
221    (0b11010011100, "211232"),
222    (0b11000111010, "233111"),
223    (0b11010111000, "211133"),
224    (0b1100011101011, "2331112"),
225];
226
227/// an encoding table, used to encode barcodes.
228#[derive(Debug, Clone)]
229pub struct Table {
230    entries: [TableEntry; 107],
231}
232
233impl Table {
234    /// create a new table
235    pub const fn new() -> Self {
236        Table {
237            entries: [
238                TableEntry::new_barcode_chars(0, ' ', ' ', 0, ' '),
239                TableEntry::new_barcode_chars(1, '!', '!', 1, '!'),
240                TableEntry::new_barcode_chars(2, '"', '"', 2, '"'),
241                TableEntry::new_barcode_chars(3, '#', '#', 3, '#'),
242                TableEntry::new_barcode_chars(4, '$', '$', 4, '$'),
243                TableEntry::new_barcode_chars(5, '%', '%', 5, '%'),
244                TableEntry::new_barcode_chars(6, '&', '&', 6, '&'),
245                TableEntry::new_barcode_chars(7, '\'', '\'', 7, '\''),
246                TableEntry::new_barcode_chars(8, '(', '(', 8, '('),
247                TableEntry::new_barcode_chars(9, ')', ')', 9, ')'),
248                TableEntry::new_barcode_chars(10, '*', '*', 10, '*'),
249                TableEntry::new_barcode_chars(11, '+', '+', 11, '+'),
250                TableEntry::new_barcode_chars(12, ',', ',', 12, ','),
251                TableEntry::new_barcode_chars(13, '-', '-', 13, '-'),
252                TableEntry::new_barcode_chars(14, '.', '.', 14, '.'),
253                TableEntry::new_barcode_chars(15, '/', '/', 15, '/'),
254                TableEntry::new_barcode_chars(16, '0', '0', 16, '0'),
255                TableEntry::new_barcode_chars(17, '1', '1', 17, '1'),
256                TableEntry::new_barcode_chars(18, '2', '2', 18, '2'),
257                TableEntry::new_barcode_chars(19, '3', '3', 19, '3'),
258                TableEntry::new_barcode_chars(20, '4', '4', 20, '4'),
259                TableEntry::new_barcode_chars(21, '5', '5', 21, '5'),
260                TableEntry::new_barcode_chars(22, '6', '6', 22, '6'),
261                TableEntry::new_barcode_chars(23, '7', '7', 23, '7'),
262                TableEntry::new_barcode_chars(24, '8', '8', 24, '8'),
263                TableEntry::new_barcode_chars(25, '9', '9', 25, '9'),
264                TableEntry::new_barcode_chars(26, ':', ':', 26, ':'),
265                TableEntry::new_barcode_chars(27, ';', ';', 27, ';'),
266                TableEntry::new_barcode_chars(28, '<', '<', 28, '<'),
267                TableEntry::new_barcode_chars(29, '=', '=', 29, '='),
268                TableEntry::new_barcode_chars(30, '>', '>', 30, '>'),
269                TableEntry::new_barcode_chars(31, '?', '?', 31, '?'),
270                TableEntry::new_barcode_chars(32, '@', '@', 32, '@'),
271                TableEntry::new_barcode_chars(33, 'A', 'A', 33, 'A'),
272                TableEntry::new_barcode_chars(34, 'B', 'B', 34, 'B'),
273                TableEntry::new_barcode_chars(35, 'C', 'C', 35, 'C'),
274                TableEntry::new_barcode_chars(36, 'D', 'D', 36, 'D'),
275                TableEntry::new_barcode_chars(37, 'E', 'E', 37, 'E'),
276                TableEntry::new_barcode_chars(38, 'F', 'F', 38, 'F'),
277                TableEntry::new_barcode_chars(39, 'G', 'G', 39, 'G'),
278                TableEntry::new_barcode_chars(40, 'H', 'H', 40, 'H'),
279                TableEntry::new_barcode_chars(41, 'I', 'I', 41, 'I'),
280                TableEntry::new_barcode_chars(42, 'J', 'J', 42, 'J'),
281                TableEntry::new_barcode_chars(43, 'K', 'K', 43, 'K'),
282                TableEntry::new_barcode_chars(44, 'L', 'L', 44, 'L'),
283                TableEntry::new_barcode_chars(45, 'M', 'M', 45, 'M'),
284                TableEntry::new_barcode_chars(46, 'N', 'N', 46, 'N'),
285                TableEntry::new_barcode_chars(47, 'O', 'O', 47, 'O'),
286                TableEntry::new_barcode_chars(48, 'P', 'P', 48, 'P'),
287                TableEntry::new_barcode_chars(49, 'Q', 'Q', 49, 'Q'),
288                TableEntry::new_barcode_chars(50, 'R', 'R', 50, 'R'),
289                TableEntry::new_barcode_chars(51, 'S', 'S', 51, 'S'),
290                TableEntry::new_barcode_chars(52, 'T', 'T', 52, 'T'),
291                TableEntry::new_barcode_chars(53, 'U', 'U', 53, 'U'),
292                TableEntry::new_barcode_chars(54, 'V', 'V', 54, 'V'),
293                TableEntry::new_barcode_chars(55, 'W', 'W', 55, 'W'),
294                TableEntry::new_barcode_chars(56, 'X', 'X', 56, 'X'),
295                TableEntry::new_barcode_chars(57, 'Y', 'Y', 57, 'Y'),
296                TableEntry::new_barcode_chars(58, 'Z', 'Z', 58, 'Z'),
297                TableEntry::new_barcode_chars(59, '[', '[', 59, '['),
298                TableEntry::new_barcode_chars(60, '\\', '\\', 60, '\\'),
299                TableEntry::new_barcode_chars(61, ']', ']', 61, ']'),
300                TableEntry::new_barcode_chars(62, '^', '^', 62, '^'),
301                TableEntry::new_barcode_chars(63, '_', '_', 63, '_'),
302                TableEntry::new_barcode_chars(64, '\x00', '`', 64, '`'),
303                TableEntry::new_barcode_chars(65, '\x01', 'a', 65, 'a'),
304                TableEntry::new_barcode_chars(66, '\x02', 'b', 66, 'b'),
305                TableEntry::new_barcode_chars(67, '\x03', 'c', 67, 'c'),
306                TableEntry::new_barcode_chars(68, '\x04', 'd', 68, 'd'),
307                TableEntry::new_barcode_chars(69, '\x05', 'e', 69, 'e'),
308                TableEntry::new_barcode_chars(70, '\x06', 'f', 70, 'f'),
309                TableEntry::new_barcode_chars(71, '\x07', 'g', 71, 'g'),
310                TableEntry::new_barcode_chars(72, '\x08', 'h', 72, 'h'),
311                TableEntry::new_barcode_chars(73, '\x09', 'i', 73, 'i'),
312                TableEntry::new_barcode_chars(74, '\x0A', 'j', 74, 'j'),
313                TableEntry::new_barcode_chars(75, '\x0B', 'k', 75, 'k'),
314                TableEntry::new_barcode_chars(76, '\x0C', 'l', 76, 'l'),
315                TableEntry::new_barcode_chars(77, '\x0D', 'm', 77, 'm'),
316                TableEntry::new_barcode_chars(78, '\x0E', 'n', 78, 'n'),
317                TableEntry::new_barcode_chars(79, '\x0F', 'o', 79, 'o'),
318                TableEntry::new_barcode_chars(80, '\x10', 'p', 80, 'p'),
319                TableEntry::new_barcode_chars(81, '\x11', 'q', 81, 'q'),
320                TableEntry::new_barcode_chars(82, '\x12', 'r', 82, 'r'),
321                TableEntry::new_barcode_chars(83, '\x13', 's', 83, 's'),
322                TableEntry::new_barcode_chars(84, '\x14', 't', 84, 't'),
323                TableEntry::new_barcode_chars(85, '\x15', 'u', 85, 'u'),
324                TableEntry::new_barcode_chars(86, '\x16', 'v', 86, 'v'),
325                TableEntry::new_barcode_chars(87, '\x17', 'w', 87, 'w'),
326                TableEntry::new_barcode_chars(88, '\x18', 'x', 88, 'x'),
327                TableEntry::new_barcode_chars(89, '\x19', 'y', 89, 'y'),
328                TableEntry::new_barcode_chars(90, '\x1A', 'z', 90, 'z'),
329                TableEntry::new_barcode_chars(91, '\x1B', '{', 91, '{'),
330                TableEntry::new_barcode_chars(92, '\x1C', '|', 92, '|'),
331                TableEntry::new_barcode_chars(93, '\x1D', '}', 93, '}'),
332                TableEntry::new_barcode_chars(94, '\x1E', '~', 94, '~'),
333                TableEntry::new_barcode_chars(95, '\x1F', '\x7F', 95, 'Ã'),
334                TableEntry::new_barcode_value(
335                    96,
336                    BarcodeValue::FNC3,
337                    BarcodeValue::FNC3,
338                    BarcodeValue::Digit(96),
339                    'Ä',
340                ),
341                TableEntry::new_barcode_value(
342                    97,
343                    BarcodeValue::FNC2,
344                    BarcodeValue::FNC2,
345                    BarcodeValue::Digit(97),
346                    'Å',
347                ),
348                TableEntry::new_barcode_value(
349                    98,
350                    BarcodeValue::ShiftB,
351                    BarcodeValue::ShiftA,
352                    BarcodeValue::Digit(98),
353                    'Æ',
354                ),
355                TableEntry::new_barcode_value(
356                    99,
357                    BarcodeValue::CodeC,
358                    BarcodeValue::CodeC,
359                    BarcodeValue::Digit(99),
360                    'Ç',
361                ),
362                TableEntry::new_barcode_value(
363                    100,
364                    BarcodeValue::CodeB,
365                    BarcodeValue::FNC4,
366                    BarcodeValue::CodeB,
367                    'È',
368                ),
369                TableEntry::new_barcode_value(
370                    101,
371                    BarcodeValue::FNC4,
372                    BarcodeValue::CodeA,
373                    BarcodeValue::CodeA,
374                    'É',
375                ),
376                TableEntry::new_barcode_value(
377                    102,
378                    BarcodeValue::FNC1,
379                    BarcodeValue::FNC1,
380                    BarcodeValue::FNC1,
381                    'Ê',
382                ),
383                TableEntry::new_barcode_value(
384                    103,
385                    BarcodeValue::StartA,
386                    BarcodeValue::StartA,
387                    BarcodeValue::StartA,
388                    'Ë',
389                ),
390                TableEntry::new_barcode_value(
391                    104,
392                    BarcodeValue::StartB,
393                    BarcodeValue::StartB,
394                    BarcodeValue::StartB,
395                    'Ì',
396                ),
397                TableEntry::new_barcode_value(
398                    105,
399                    BarcodeValue::StartC,
400                    BarcodeValue::StartC,
401                    BarcodeValue::StartC,
402                    'Í',
403                ),
404                TableEntry::new_barcode_value(
405                    108,
406                    BarcodeValue::Stop,
407                    BarcodeValue::Stop,
408                    BarcodeValue::Stop,
409                    'Î',
410                ),
411            ],
412        }
413    }
414
415    /// in case you want to make your own (probably incompatible) table
416    ///
417    /// Use the [`Self::modify`] function to change values in the current table,
418    /// like changing what latin character matches a value
419    pub const fn new_from(entries: [TableEntry; 107]) -> Self {
420        Table { entries }
421    }
422
423    /// Modify a table, allowing you to set custom values for all fields of a table entry. 
424    /// 
425    /// (tip: just make a new table entry and assign it to the parameter)
426    pub fn modify(&self, mut f: impl FnMut(&mut TableEntry)) -> Self {
427        let mut new_entries = self.entries;
428        for entry in &mut new_entries {
429            f(entry);
430        }
431        Table::new_from(new_entries)
432    }
433
434    /// given a requested value and a specific code set, find the value in the table.
435    ///
436    /// It'll return None if the value does not exist in the table, for example when you
437    /// want to use a lower case character but are in Code A.
438    pub fn entry_in_set(
439        &self,
440        value: impl Into<BarcodeValue>,
441        set: BarcodeType,
442    ) -> Option<&TableEntry> {
443        let value = value.into();
444        self.entries.iter().find(|entry| match set {
445            BarcodeType::CodeA => entry.a == value,
446            BarcodeType::CodeB => entry.b == value,
447            BarcodeType::CodeC => entry.c == value,
448        })
449    }
450}
451
452/// A completed barcode.
453#[derive(Debug, PartialEq, Eq)]
454pub struct Barcode<'table> {
455    code: Vec<&'table TableEntry>,
456}
457
458impl PartialOrd for Barcode<'_> {
459    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
460        Some(self.cmp(other))
461    }
462}
463
464impl Ord for Barcode<'_> {
465    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
466        self.code.len().cmp(&other.code.len())
467    }
468}
469
470impl Display for Barcode<'_> {
471    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
472        let mut output = String::new();
473        for entry in &self.code {
474            output.push(entry.latin());
475        }
476        write!(f, "{output}")
477    }
478}
479
480impl<'table> IntoIterator for Barcode<'table> {
481    type Item = &'table TableEntry;
482
483    type IntoIter = std::vec::IntoIter<Self::Item>;
484
485    fn into_iter(self) -> Self::IntoIter {
486        self.code.into_iter()
487    }
488}
489
490/// const value of the most common table. 
491pub const TABLE: Table = Table::new();
492
493/// Make a barcode with the fastest available method.
494pub fn make_barcode(text: &str) -> Option<Barcode<'_>> {
495    #[cfg(feature = "parallel")]
496    let res = make_barcode_custom_table_par(&TABLE, text);
497    #[cfg(not(feature = "parallel"))]
498    let res = make_barcode_custom_table(&TABLE, text);
499    res
500}
501
502/// Make a barcode using a custom table, you can provide [`TABLE`] to
503/// use the normal table. 
504pub fn make_barcode_custom_table<'table>(
505    table: &'table Table,
506    text: &str,
507) -> Option<Barcode<'table>> {
508    let mut stack = VecDeque::new();
509    stack.push_back(BarcodeBuilder::new(table, text));
510    let mut done = vec![];
511
512    let shortest = AtomicUsize::new(usize::MAX);
513
514    while let Some(partial_code) = stack.pop_front() {
515        let options = partial_code.create_child_options();
516
517        for option in options {
518            if option.remaining.is_empty() {
519                let code = option.build();
520                shortest.fetch_min(code.code.len(), std::sync::atomic::Ordering::SeqCst);
521                done.push(code);
522            } else {
523                if option.code.len() <= shortest.load(std::sync::atomic::Ordering::SeqCst) {
524                    stack.push_back(option);
525                }
526            }
527        }
528    }
529
530    done.sort_unstable_by_key(|k| k.code.len());
531
532    done.into_iter().next()
533}
534
535/// like [`make_barcode_custom_table`], but uses [`rayon`] to be up to 10 times faster. 
536#[cfg(feature = "parallel")]
537pub fn make_barcode_custom_table_par<'table>(
538    table: &'table Table,
539    text: &str,
540) -> Option<Barcode<'table>> {
541    use rayon::iter::ParallelIterator;
542    let walker = rayon::iter::walk_tree(BarcodeBuilder::new(table, text), |t| {
543        t.create_child_options()
544    });
545    let res = walker.min_by_key(|v| {
546        if v.remaining.is_empty() {
547            v.code.len()
548        } else {
549            usize::MAX
550        }
551    });
552    res.map(|r| r.build())
553}
554
555#[derive(Debug, Clone)]
556struct BarcodeBuilder<'table, 's> {
557    table: &'table Table,
558    code: Vec<&'table TableEntry>,
559    remaining: &'s str,
560    set: BarcodeType,
561}
562
563impl<'table, 's> BarcodeBuilder<'table, 's> {
564    fn new(table: &'table Table, code: &'s str) -> Self {
565        Self {
566            table,
567            code: Vec::new(),
568            remaining: code,
569            set: BarcodeType::CodeA,
570        }
571    }
572
573    fn create_child_options(&self) -> Vec<Self> {
574        if self.code.is_empty() {
575            return vec![
576                Self {
577                    code: vec![
578                        self.table
579                            .entry_in_set(BarcodeValue::StartA, BarcodeType::CodeA)
580                            .unwrap(),
581                    ],
582                    ..self.clone()
583                },
584                Self {
585                    code: vec![
586                        self.table
587                            .entry_in_set(BarcodeValue::StartB, BarcodeType::CodeB)
588                            .unwrap(),
589                    ],
590                    set: BarcodeType::CodeB,
591                    ..self.clone()
592                },
593                Self {
594                    code: vec![
595                        self.table
596                            .entry_in_set(BarcodeValue::StartC, BarcodeType::CodeC)
597                            .unwrap(),
598                    ],
599                    set: BarcodeType::CodeC,
600                    ..self.clone()
601                },
602            ];
603        }
604        let mut options = Vec::new();
605        let old_set = self.set;
606
607        // try to see if set C works, always two numbers
608
609        if self.remaining.len() >= 2 {
610            let first_two_characters = &self.remaining[..2];
611            if first_two_characters.chars().all(|c| c.is_ascii_digit()) {
612                if let Ok(v) = first_two_characters.parse::<u8>() {
613                    if let Some(s) = self.try_push(|mut s| {
614                        if !matches!(old_set, BarcodeType::CodeC) {
615                            s.code.push(s.in_set(BarcodeValue::CodeC)?);
616                            s.set = BarcodeType::CodeC;
617                        }
618                        s.code.push(s.in_set(v)?);
619                        s.remaining = &s.remaining[2..];
620                        Some(s)
621                    }) {
622                        options.push(s)
623                    };
624                }
625            }
626        }
627
628        // single character, so set A or B
629        if let Some(fc) = self.remaining.chars().next() {
630            // does it exist in the current set?
631            if let Some(s) = self.try_push(|mut s| {
632                s.code.push(s.in_set(fc)?);
633                s.remaining = &s.remaining[fc.len_utf8()..];
634                Some(s)
635            }) {
636                options.push(s);
637            }
638            // shift A or B?
639            for new_set in [BarcodeType::CodeA, BarcodeType::CodeB] {
640                let shift_to = match new_set {
641                    BarcodeType::CodeA => BarcodeValue::ShiftA,
642                    BarcodeType::CodeB => BarcodeValue::ShiftB,
643                    BarcodeType::CodeC => unreachable!(),
644                };
645                if let Some(s) = self.try_push(|mut s| {
646                    s.code.push(s.in_set(shift_to)?);
647                    s.set = new_set;
648                    s.code.push(s.in_set(fc)?);
649                    s.set = old_set;
650                    s.remaining = &s.remaining[fc.len_utf8()..];
651                    Some(s)
652                }) {
653                    options.push(s);
654                }
655
656                let force_to = match new_set {
657                    BarcodeType::CodeA => BarcodeValue::CodeA,
658                    BarcodeType::CodeB => BarcodeValue::CodeB,
659                    BarcodeType::CodeC => unreachable!(),
660                };
661
662                if let Some(s) = self.try_push(|mut s| {
663                    s.code.push(s.in_set(force_to)?);
664                    s.set = new_set;
665                    s.code.push(s.in_set(fc)?);
666                    s.remaining = &s.remaining[fc.len_utf8()..];
667                    Some(s)
668                }) {
669                    options.push(s);
670                }
671            }
672        }
673
674        options
675    }
676
677    fn try_push(&self, to_try: impl FnOnce(Self) -> Option<Self>) -> Option<Self> {
678        to_try(self.clone())
679    }
680
681    fn in_set(&self, v: impl Into<BarcodeValue>) -> Option<&'table TableEntry> {
682        self.table.entry_in_set(v, self.set)
683    }
684
685    fn build(mut self) -> Barcode<'table> {
686        let mut total = 0;
687        for (mut idx, character) in self.code.iter().enumerate() {
688            if idx == 0 {
689                idx = 1;
690            }
691            total += character.value() as usize * idx
692        }
693        total %= 103;
694        self.code.push(
695            self.table
696                .entries
697                .iter()
698                .find(|v| v.value() as usize == total)
699                .unwrap(),
700        );
701        self.code.push(
702            self.table
703                .entry_in_set(BarcodeValue::Stop, self.set)
704                .unwrap(),
705        );
706        Barcode { code: self.code }
707    }
708}