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