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