1use std::{
2 collections::{HashMap, VecDeque},
3 fmt::Display,
4 sync::atomic::AtomicUsize,
5};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum BarcodeType {
10 CodeA,
11 CodeB,
12 CodeC,
13}
14
15#[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#[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 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 pub fn value(&self) -> u8 {
98 self.value
99 }
100
101 pub fn latin(&self) -> char {
103 self.latin
104 }
105
106 pub fn barcode_bits(&self) -> u32 {
108 BARCODE_BITS[self.value() as usize].0
109 }
110
111 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#[derive(Debug, Clone)]
233pub struct Table {
234 entries: [TableEntry; 107],
235}
236
237impl Table {
238 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 pub const fn new_from(entries: [TableEntry; 107]) -> Self {
424 Table { entries }
425 }
426
427 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 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#[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
494pub const TABLE: Table = Table::new();
496
497pub fn make_barcode(text: &str) -> Option<Barcode<'_>> {
499 make_barcode_custom_table_dp(&TABLE, text)
500}
501
502pub 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#[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
555pub 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 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 if let Some(fc) = self.remaining.chars().next() {
667 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 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}