barcode_gen/
lib.rs

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