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