barcode_gen/
lib.rs

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