1#![warn(missing_docs)]
2use std::{collections::HashMap, fmt::Display};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum BarcodeType {
15 CodeA,
17 CodeB,
19 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 BarcodeType::CodeC => None,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum BarcodeValue {
38 RegularCharacter(char),
40 Digit(u8),
42 FNC1,
44 FNC2,
46 FNC3,
48 FNC4,
50 StartA,
52 StartB,
54 StartC,
56 Stop,
58 ShiftA,
60 ShiftB,
62 CodeA,
64 CodeB,
66 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#[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 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 pub fn value(&self) -> u8 {
132 self.value
133 }
134
135 pub fn latin(&self) -> char {
137 self.latin
138 }
139
140 pub fn barcode_bits(&self) -> u32 {
142 BARCODE_BITS[self.value() as usize].0
143 }
144
145 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#[derive(Debug, Clone)]
267pub struct Table {
268 entries: [TableEntry; 107],
269}
270
271impl Table {
272 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 pub const fn new_from(entries: [TableEntry; 107]) -> Self {
458 Table { entries }
459 }
460
461 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 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#[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
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_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 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 if let Some(fc) = self.key.remaining.chars().next() {
655 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 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 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#[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 pub fn new(text: &'s str, set: BarcodeType) -> Self {
781 Self {
782 remaining: text,
783 set,
784 fnc4: false,
785 }
786 }
787
788 pub fn with_fnc(mut self, fnc4: bool) -> Self {
790 self.fnc4 = fnc4;
791 self
792 }
793
794 pub fn is_empty(&self) -> bool {
796 self.remaining.is_empty()
797 }
798}