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