1#![allow(clippy::unicode_not_nfc)]
2#[cfg(not(feature = "std"))]
13#[allow(unused_imports)]
14use alloc::{
15 borrow::ToOwned,
16 format,
17 string::{String, ToString},
18 vec,
19 vec::Vec,
20};
21
22use crate::types::{Mode, Version};
23use core::marker::PhantomData;
24use core::slice::Iter;
25
26#[derive(PartialEq, Eq, Debug, Copy, Clone)]
31pub struct Segment {
32 pub mode: Mode,
34
35 pub begin: usize,
37
38 pub end: usize,
40}
41
42impl Segment {
43 pub fn encoded_len(&self, version: Version) -> usize {
46 let byte_size = self.end - self.begin;
47 let chars_count = if self.mode == Mode::Kanji { byte_size / 2 } else { byte_size };
48
49 let mode_bits_count = version.mode_bits_count();
50 let length_bits_count = self.mode.length_bits_count(version);
51 let data_bits_count = self.mode.data_bits_count(chars_count);
52
53 mode_bits_count + length_bits_count + data_bits_count
54 }
55}
56
57struct EcsIter<I> {
72 base: I,
73 index: usize,
74 ended: bool,
75}
76
77impl<'a, I: Iterator<Item = &'a u8>> Iterator for EcsIter<I> {
78 type Item = (usize, ExclCharSet);
79
80 fn next(&mut self) -> Option<(usize, ExclCharSet)> {
81 if self.ended {
82 return None;
83 }
84
85 match self.base.next() {
86 None => {
87 self.ended = true;
88 Some((self.index, ExclCharSet::End))
89 }
90 Some(c) => {
91 let old_index = self.index;
92 self.index += 1;
93 Some((old_index, ExclCharSet::from_u8(*c)))
94 }
95 }
96 }
97}
98
99pub struct Parser<'a> {
101 ecs_iter: EcsIter<Iter<'a, u8>>,
102 state: State,
103 begin: usize,
104 pending_single_byte: bool,
105}
106
107impl<'a> Parser<'a> {
108 pub fn new(data: &[u8]) -> Parser<'_> {
120 Parser {
121 ecs_iter: EcsIter { base: data.iter(), index: 0, ended: false },
122 state: State::Init,
123 begin: 0,
124 pending_single_byte: false,
125 }
126 }
127}
128
129impl<'a> Iterator for Parser<'a> {
130 type Item = Segment;
131
132 fn next(&mut self) -> Option<Segment> {
133 if self.pending_single_byte {
134 self.pending_single_byte = false;
135 self.begin += 1;
136 return Some(Segment { mode: Mode::Byte, begin: self.begin - 1, end: self.begin });
137 }
138
139 loop {
140 let (i, ecs) = self.ecs_iter.next()?;
141 let (next_state, action) = STATE_TRANSITION[self.state as usize + ecs as usize];
142 self.state = next_state;
143
144 let old_begin = self.begin;
145 let push_mode = match action {
146 Action::Idle => continue,
147 Action::Numeric => Mode::Numeric,
148 Action::Alpha => Mode::Alphanumeric,
149 Action::Byte => Mode::Byte,
150 Action::Kanji => Mode::Kanji,
151 Action::KanjiAndSingleByte => {
152 let next_begin = i - 1;
153 if self.begin == next_begin {
154 Mode::Byte
155 } else {
156 self.pending_single_byte = true;
157 self.begin = next_begin;
158 return Some(Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin });
159 }
160 }
161 };
162
163 self.begin = i;
164 return Some(Segment { mode: push_mode, begin: old_begin, end: i });
165 }
166 }
167}
168
169#[cfg(test)]
170mod parse_tests {
171 use crate::optimize::{Parser, Segment};
172 use crate::types::Mode;
173
174 fn parse(data: &[u8]) -> Vec<Segment> {
175 Parser::new(data).collect()
176 }
177
178 #[test]
179 fn test_parse_1() {
180 let segs = parse(b"01049123451234591597033130128%10ABC123");
181 assert_eq!(
182 segs,
183 vec![
184 Segment { mode: Mode::Numeric, begin: 0, end: 29 },
185 Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 },
186 Segment { mode: Mode::Numeric, begin: 30, end: 32 },
187 Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 },
188 Segment { mode: Mode::Numeric, begin: 35, end: 38 },
189 ]
190 );
191 }
192
193 #[test]
194 fn test_parse_shift_jis_example_1() {
195 let segs = parse(b"\x82\xa0\x81\x41\x41\xb1\x81\xf0"); assert_eq!(
197 segs,
198 vec![
199 Segment { mode: Mode::Kanji, begin: 0, end: 4 },
200 Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 },
201 Segment { mode: Mode::Byte, begin: 5, end: 6 },
202 Segment { mode: Mode::Kanji, begin: 6, end: 8 },
203 ]
204 );
205 }
206
207 #[test]
208 fn test_parse_utf_8() {
209 let segs = parse(b"\xe3\x81\x82\xe3\x80\x81A\xef\xbd\xb1\xe2\x84\xab");
211 assert_eq!(
212 segs,
213 vec![
214 Segment { mode: Mode::Kanji, begin: 0, end: 4 },
215 Segment { mode: Mode::Byte, begin: 4, end: 5 },
216 Segment { mode: Mode::Kanji, begin: 5, end: 7 },
217 Segment { mode: Mode::Byte, begin: 7, end: 10 },
218 Segment { mode: Mode::Kanji, begin: 10, end: 12 },
219 Segment { mode: Mode::Byte, begin: 12, end: 13 },
220 ]
221 );
222 }
223
224 #[test]
225 fn test_not_kanji_1() {
226 let segs = parse(b"\x81\x30");
227 assert_eq!(
228 segs,
229 vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Numeric, begin: 1, end: 2 }]
230 );
231 }
232
233 #[test]
234 fn test_not_kanji_2() {
235 let segs = parse(b"\xeb\xc0");
238 assert_eq!(
239 segs,
240 vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 }]
241 );
242 }
243
244 #[test]
245 fn test_not_kanji_3() {
246 let segs = parse(b"\x81\x7f");
247 assert_eq!(
248 segs,
249 vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 }]
250 );
251 }
252
253 #[test]
254 fn test_not_kanji_4() {
255 let segs = parse(b"\x81\x40\x81");
256 assert_eq!(
257 segs,
258 vec![Segment { mode: Mode::Kanji, begin: 0, end: 2 }, Segment { mode: Mode::Byte, begin: 2, end: 3 }]
259 );
260 }
261}
262
263pub struct Optimizer<I> {
270 optimized: Vec<Segment>,
271 index: usize,
272 _source: PhantomData<I>,
273}
274
275impl<I: Iterator<Item = Segment>> Optimizer<I> {
276 pub fn new(segments: I, version: Version) -> Self {
283 let segments = segments.collect::<Vec<_>>();
284 Self { optimized: optimize_segments(&segments, version), index: 0, _source: PhantomData }
285 }
286}
287
288impl<'a> Parser<'a> {
289 pub fn optimize(self, version: Version) -> Optimizer<Parser<'a>> {
292 Optimizer::new(self, version)
293 }
294}
295
296impl<I: Iterator<Item = Segment>> Iterator for Optimizer<I> {
297 type Item = Segment;
298
299 fn next(&mut self) -> Option<Segment> {
300 let segment = self.optimized.get(self.index).copied();
301 if segment.is_some() {
302 self.index += 1;
303 }
304 segment
305 }
306
307 fn size_hint(&self) -> (usize, Option<usize>) {
308 let remaining = self.optimized.len().saturating_sub(self.index);
309 (remaining, Some(remaining))
310 }
311}
312
313impl<I: Iterator<Item = Segment>> ExactSizeIterator for Optimizer<I> {}
314impl<I: Iterator<Item = Segment>> core::iter::FusedIterator for Optimizer<I> {}
315
316pub fn total_encoded_len(segments: &[Segment], version: Version) -> usize {
318 segments.iter().map(|seg| seg.encoded_len(version)).sum()
319}
320
321#[must_use]
326pub fn optimize_segments(segments: &[Segment], version: Version) -> Vec<Segment> {
327 let len = segments.len();
328 if len == 0 {
329 return Vec::new();
330 }
331
332 let mut best_bits = vec![usize::MAX; len + 1];
333 let mut best_count = vec![usize::MAX; len + 1];
334 let mut previous = vec![0_usize; len + 1];
335 let mut previous_mode = vec![Mode::Byte; len + 1];
336 best_bits[0] = 0;
337 best_count[0] = 0;
338
339 for end in 1..=len {
340 let mut mode = segments[end - 1].mode;
341 for start in (0..end).rev() {
342 if start + 1 < end {
343 mode = segments[start].mode.max(mode);
344 }
345 let merged = Segment { mode, begin: segments[start].begin, end: segments[end - 1].end };
346 let Some(candidate_bits) = best_bits[start].checked_add(merged.encoded_len(version)) else {
347 continue;
348 };
349 let candidate_count = best_count[start] + 1;
350 if candidate_bits < best_bits[end] || candidate_bits == best_bits[end] && candidate_count < best_count[end]
351 {
352 best_bits[end] = candidate_bits;
353 best_count[end] = candidate_count;
354 previous[end] = start;
355 previous_mode[end] = mode;
356 }
357 }
358 }
359
360 let mut cursor = len;
361 let mut optimized = Vec::with_capacity(best_count[len]);
362 while cursor > 0 {
363 let start = previous[cursor];
364 optimized.push(Segment {
365 mode: previous_mode[cursor],
366 begin: segments[start].begin,
367 end: segments[cursor - 1].end,
368 });
369 cursor = start;
370 }
371 optimized.reverse();
372 optimized
373}
374
375#[cfg(test)]
376mod optimize_tests {
377 use crate::optimize::{Optimizer, Segment, optimize_segments, total_encoded_len};
378 use crate::types::{Mode, Version};
379
380 fn test_optimization_result(given: &[Segment], expected: &[Segment], version: Version) {
381 let prev_len = total_encoded_len(given, version);
382 let opt_segs = Optimizer::new(given.iter().copied(), version).collect::<Vec<_>>();
383 let new_len = total_encoded_len(&opt_segs, version);
384 if given != opt_segs {
385 assert!(prev_len > new_len, "{prev_len} > {new_len}");
386 }
387 assert_eq!(
388 opt_segs,
389 expected,
390 "Optimization gave something better: {} < {} ({:?})",
391 new_len,
392 total_encoded_len(expected, version),
393 opt_segs
394 );
395 }
396
397 #[test]
398 fn test_example_1() {
399 test_optimization_result(
400 &[
401 Segment { mode: Mode::Alphanumeric, begin: 0, end: 3 },
402 Segment { mode: Mode::Numeric, begin: 3, end: 6 },
403 Segment { mode: Mode::Byte, begin: 6, end: 10 },
404 ],
405 &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 6 }, Segment { mode: Mode::Byte, begin: 6, end: 10 }],
406 Version::Normal(1),
407 );
408 }
409
410 #[test]
411 fn test_example_2() {
412 test_optimization_result(
413 &[
414 Segment { mode: Mode::Numeric, begin: 0, end: 29 },
415 Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 },
416 Segment { mode: Mode::Numeric, begin: 30, end: 32 },
417 Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 },
418 Segment { mode: Mode::Numeric, begin: 35, end: 38 },
419 ],
420 &[
421 Segment { mode: Mode::Numeric, begin: 0, end: 29 },
422 Segment { mode: Mode::Alphanumeric, begin: 29, end: 38 },
423 ],
424 Version::Normal(9),
425 );
426 }
427
428 #[test]
429 fn test_example_3() {
430 test_optimization_result(
431 &[
432 Segment { mode: Mode::Kanji, begin: 0, end: 4 },
433 Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 },
434 Segment { mode: Mode::Byte, begin: 5, end: 6 },
435 Segment { mode: Mode::Kanji, begin: 6, end: 8 },
436 ],
437 &[Segment { mode: Mode::Byte, begin: 0, end: 8 }],
438 Version::Normal(1),
439 );
440 }
441
442 #[test]
443 fn test_example_4() {
444 test_optimization_result(
445 &[Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }],
446 &[Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }],
447 Version::Normal(1),
448 );
449 }
450
451 #[test]
452 fn test_annex_j_guideline_1a() {
453 test_optimization_result(
454 &[
455 Segment { mode: Mode::Numeric, begin: 0, end: 3 },
456 Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
457 ],
458 &[
459 Segment { mode: Mode::Numeric, begin: 0, end: 3 },
460 Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
461 ],
462 Version::Micro(2),
463 );
464 }
465
466 #[test]
467 fn test_annex_j_guideline_1b() {
468 test_optimization_result(
469 &[
470 Segment { mode: Mode::Numeric, begin: 0, end: 2 },
471 Segment { mode: Mode::Alphanumeric, begin: 2, end: 4 },
472 ],
473 &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }],
474 Version::Micro(2),
475 );
476 }
477
478 #[test]
479 fn test_annex_j_guideline_1c() {
480 test_optimization_result(
481 &[
482 Segment { mode: Mode::Numeric, begin: 0, end: 3 },
483 Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
484 ],
485 &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }],
486 Version::Micro(3),
487 );
488 }
489
490 #[test]
491 fn dynamic_programming_can_skip_a_local_merge_for_a_better_total() {
492 let given = [
493 Segment { mode: Mode::Numeric, begin: 0, end: 7 },
494 Segment { mode: Mode::Alphanumeric, begin: 7, end: 8 },
495 Segment { mode: Mode::Numeric, begin: 8, end: 9 },
496 ];
497
498 let optimized = optimize_segments(&given, Version::Normal(1));
499
500 assert_eq!(
501 optimized,
502 vec![
503 Segment { mode: Mode::Numeric, begin: 0, end: 7 },
504 Segment { mode: Mode::Alphanumeric, begin: 7, end: 9 },
505 ]
506 );
507 assert!(
508 total_encoded_len(&optimized, Version::Normal(1))
509 < total_encoded_len(&[Segment { mode: Mode::Alphanumeric, begin: 0, end: 9 }], Version::Normal(1))
510 );
511 }
512}
513
514#[derive(Copy, Clone)]
522enum ExclCharSet {
523 End = 0,
525
526 Symbol = 1,
529
530 Numeric = 2,
532
533 Alpha = 3,
536
537 KanjiHi1 = 4,
539
540 KanjiHi2 = 5,
542
543 KanjiHi3 = 6,
547
548 KanjiLo1 = 7,
552
553 KanjiLo2 = 8,
558
559 Byte = 9,
561}
562
563impl ExclCharSet {
564 fn from_u8(c: u8) -> Self {
566 match c {
567 0x20 | 0x24 | 0x25 | 0x2a | 0x2b | 0x2d..=0x2f | 0x3a => ExclCharSet::Symbol,
568 0x30..=0x39 => ExclCharSet::Numeric,
569 0x41..=0x5a => ExclCharSet::Alpha,
570 0x81..=0x9f => ExclCharSet::KanjiHi1,
571 0xe0..=0xea => ExclCharSet::KanjiHi2,
572 0xeb => ExclCharSet::KanjiHi3,
573 0x40 | 0x5b..=0x7e | 0x80 | 0xa0..=0xbf => ExclCharSet::KanjiLo1,
574 0xc0..=0xdf | 0xec..=0xfc => ExclCharSet::KanjiLo2,
575 _ => ExclCharSet::Byte,
576 }
577 }
578}
579
580#[derive(Copy, Clone)]
582enum State {
583 Init = 0,
585
586 Numeric = 10,
588
589 Alpha = 20,
591
592 Byte = 30,
594
595 KanjiHi12 = 40,
598
599 KanjiHi3 = 50,
602
603 Kanji = 60,
605}
606
607#[derive(Copy, Clone)]
609enum Action {
610 Idle,
612
613 Numeric,
615
616 Alpha,
618
619 Byte,
621
622 Kanji,
624
625 KanjiAndSingleByte,
628}
629
630static STATE_TRANSITION: [(State, Action); 70] = [
631 (State::Init, Action::Idle), (State::Alpha, Action::Idle), (State::Numeric, Action::Idle), (State::Alpha, Action::Idle), (State::KanjiHi12, Action::Idle), (State::KanjiHi12, Action::Idle), (State::KanjiHi3, Action::Idle), (State::Byte, Action::Idle), (State::Byte, Action::Idle), (State::Byte, Action::Idle), (State::Init, Action::Numeric), (State::Alpha, Action::Numeric), (State::Numeric, Action::Idle), (State::Alpha, Action::Numeric), (State::KanjiHi12, Action::Numeric), (State::KanjiHi12, Action::Numeric), (State::KanjiHi3, Action::Numeric), (State::Byte, Action::Numeric), (State::Byte, Action::Numeric), (State::Byte, Action::Numeric), (State::Init, Action::Alpha), (State::Alpha, Action::Idle), (State::Numeric, Action::Alpha), (State::Alpha, Action::Idle), (State::KanjiHi12, Action::Alpha), (State::KanjiHi12, Action::Alpha), (State::KanjiHi3, Action::Alpha), (State::Byte, Action::Alpha), (State::Byte, Action::Alpha), (State::Byte, Action::Alpha), (State::Init, Action::Byte), (State::Alpha, Action::Byte), (State::Numeric, Action::Byte), (State::Alpha, Action::Byte), (State::KanjiHi12, Action::Byte), (State::KanjiHi12, Action::Byte), (State::KanjiHi3, Action::Byte), (State::Byte, Action::Idle), (State::Byte, Action::Idle), (State::Byte, Action::Idle), (State::Init, Action::KanjiAndSingleByte), (State::Alpha, Action::KanjiAndSingleByte), (State::Numeric, Action::KanjiAndSingleByte), (State::Kanji, Action::Idle), (State::Kanji, Action::Idle), (State::Kanji, Action::Idle), (State::Kanji, Action::Idle), (State::Kanji, Action::Idle), (State::Kanji, Action::Idle), (State::Byte, Action::KanjiAndSingleByte), (State::Init, Action::KanjiAndSingleByte), (State::Alpha, Action::KanjiAndSingleByte), (State::Numeric, Action::KanjiAndSingleByte), (State::Kanji, Action::Idle), (State::Kanji, Action::Idle), (State::KanjiHi12, Action::KanjiAndSingleByte), (State::KanjiHi3, Action::KanjiAndSingleByte), (State::Kanji, Action::Idle), (State::Byte, Action::KanjiAndSingleByte), (State::Byte, Action::KanjiAndSingleByte), (State::Init, Action::Kanji), (State::Alpha, Action::Kanji), (State::Numeric, Action::Kanji), (State::Alpha, Action::Kanji), (State::KanjiHi12, Action::Idle), (State::KanjiHi12, Action::Idle), (State::KanjiHi3, Action::Idle), (State::Byte, Action::Kanji), (State::Byte, Action::Kanji), (State::Byte, Action::Kanji), ];
711
712