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