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::slice::Iter;
24
25#[derive(PartialEq, Eq, Debug, Copy, Clone)]
30pub struct Segment {
31 pub mode: Mode,
33
34 pub begin: usize,
36
37 pub end: usize,
39}
40
41impl Segment {
42 pub fn encoded_len(&self, version: Version) -> usize {
45 let byte_size = self.end - self.begin;
46 let chars_count = if self.mode == Mode::Kanji { byte_size / 2 } else { byte_size };
47
48 let mode_bits_count = version.mode_bits_count();
49 let length_bits_count = self.mode.length_bits_count(version);
50 let data_bits_count = self.mode.data_bits_count(chars_count);
51
52 mode_bits_count + length_bits_count + data_bits_count
53 }
54}
55
56struct EcsIter<I> {
71 base: I,
72 index: usize,
73 ended: bool,
74}
75
76impl<'a, I: Iterator<Item = &'a u8>> Iterator for EcsIter<I> {
77 type Item = (usize, ExclCharSet);
78
79 fn next(&mut self) -> Option<(usize, ExclCharSet)> {
80 if self.ended {
81 return None;
82 }
83
84 match self.base.next() {
85 None => {
86 self.ended = true;
87 Some((self.index, ExclCharSet::End))
88 }
89 Some(c) => {
90 let old_index = self.index;
91 self.index += 1;
92 Some((old_index, ExclCharSet::from_u8(*c)))
93 }
94 }
95 }
96}
97
98pub struct Parser<'a> {
100 ecs_iter: EcsIter<Iter<'a, u8>>,
101 state: State,
102 begin: usize,
103 pending_single_byte: bool,
104}
105
106impl<'a> Parser<'a> {
107 pub fn new(data: &[u8]) -> Parser<'_> {
119 Parser {
120 ecs_iter: EcsIter { base: data.iter(), index: 0, ended: false },
121 state: State::Init,
122 begin: 0,
123 pending_single_byte: false,
124 }
125 }
126}
127
128impl<'a> Iterator for Parser<'a> {
129 type Item = Segment;
130
131 fn next(&mut self) -> Option<Segment> {
132 if self.pending_single_byte {
133 self.pending_single_byte = false;
134 self.begin += 1;
135 return Some(Segment { mode: Mode::Byte, begin: self.begin - 1, end: self.begin });
136 }
137
138 loop {
139 let (i, ecs) = self.ecs_iter.next()?;
140 let (next_state, action) = STATE_TRANSITION[self.state as usize + ecs as usize];
141 self.state = next_state;
142
143 let old_begin = self.begin;
144 let push_mode = match action {
145 Action::Idle => continue,
146 Action::Numeric => Mode::Numeric,
147 Action::Alpha => Mode::Alphanumeric,
148 Action::Byte => Mode::Byte,
149 Action::Kanji => Mode::Kanji,
150 Action::KanjiAndSingleByte => {
151 let next_begin = i - 1;
152 if self.begin == next_begin {
153 Mode::Byte
154 } else {
155 self.pending_single_byte = true;
156 self.begin = next_begin;
157 return Some(Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin });
158 }
159 }
160 };
161
162 self.begin = i;
163 return Some(Segment { mode: push_mode, begin: old_begin, end: i });
164 }
165 }
166}
167
168#[cfg(test)]
169mod parse_tests {
170 use crate::optimize::{Parser, Segment};
171 use crate::types::Mode;
172
173 fn parse(data: &[u8]) -> Vec<Segment> {
174 Parser::new(data).collect()
175 }
176
177 #[test]
178 fn test_parse_1() {
179 let segs = parse(b"01049123451234591597033130128%10ABC123");
180 assert_eq!(
181 segs,
182 vec![
183 Segment { mode: Mode::Numeric, begin: 0, end: 29 },
184 Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 },
185 Segment { mode: Mode::Numeric, begin: 30, end: 32 },
186 Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 },
187 Segment { mode: Mode::Numeric, begin: 35, end: 38 },
188 ]
189 );
190 }
191
192 #[test]
193 fn test_parse_shift_jis_example_1() {
194 let segs = parse(b"\x82\xa0\x81\x41\x41\xb1\x81\xf0"); assert_eq!(
196 segs,
197 vec![
198 Segment { mode: Mode::Kanji, begin: 0, end: 4 },
199 Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 },
200 Segment { mode: Mode::Byte, begin: 5, end: 6 },
201 Segment { mode: Mode::Kanji, begin: 6, end: 8 },
202 ]
203 );
204 }
205
206 #[test]
207 fn test_parse_utf_8() {
208 let segs = parse(b"\xe3\x81\x82\xe3\x80\x81A\xef\xbd\xb1\xe2\x84\xab");
210 assert_eq!(
211 segs,
212 vec![
213 Segment { mode: Mode::Kanji, begin: 0, end: 4 },
214 Segment { mode: Mode::Byte, begin: 4, end: 5 },
215 Segment { mode: Mode::Kanji, begin: 5, end: 7 },
216 Segment { mode: Mode::Byte, begin: 7, end: 10 },
217 Segment { mode: Mode::Kanji, begin: 10, end: 12 },
218 Segment { mode: Mode::Byte, begin: 12, end: 13 },
219 ]
220 );
221 }
222
223 #[test]
224 fn test_not_kanji_1() {
225 let segs = parse(b"\x81\x30");
226 assert_eq!(
227 segs,
228 vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Numeric, begin: 1, end: 2 }]
229 );
230 }
231
232 #[test]
233 fn test_not_kanji_2() {
234 let segs = parse(b"\xeb\xc0");
237 assert_eq!(
238 segs,
239 vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 }]
240 );
241 }
242
243 #[test]
244 fn test_not_kanji_3() {
245 let segs = parse(b"\x81\x7f");
246 assert_eq!(
247 segs,
248 vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 }]
249 );
250 }
251
252 #[test]
253 fn test_not_kanji_4() {
254 let segs = parse(b"\x81\x40\x81");
255 assert_eq!(
256 segs,
257 vec![Segment { mode: Mode::Kanji, begin: 0, end: 2 }, Segment { mode: Mode::Byte, begin: 2, end: 3 }]
258 );
259 }
260}
261
262pub struct Optimizer<I> {
269 parser: I,
270 last_segment: Segment,
271 last_segment_size: usize,
272 version: Version,
273 ended: bool,
274}
275
276impl<I: Iterator<Item = Segment>> Optimizer<I> {
277 pub fn new(mut segments: I, version: Version) -> Self {
284 match segments.next() {
285 None => Self {
286 parser: segments,
287 last_segment: Segment { mode: Mode::Numeric, begin: 0, end: 0 },
288 last_segment_size: 0,
289 version,
290 ended: true,
291 },
292 Some(segment) => Self {
293 parser: segments,
294 last_segment: segment,
295 last_segment_size: segment.encoded_len(version),
296 version,
297 ended: false,
298 },
299 }
300 }
301}
302
303impl<'a> Parser<'a> {
304 pub fn optimize(self, version: Version) -> Optimizer<Parser<'a>> {
307 Optimizer::new(self, version)
308 }
309}
310
311impl<I: Iterator<Item = Segment>> Iterator for Optimizer<I> {
312 type Item = Segment;
313
314 fn next(&mut self) -> Option<Segment> {
315 if self.ended {
316 return None;
317 }
318
319 loop {
320 match self.parser.next() {
321 None => {
322 self.ended = true;
323 return Some(self.last_segment);
324 }
325 Some(segment) => {
326 let seg_size = segment.encoded_len(self.version);
327
328 let new_segment = Segment {
329 mode: self.last_segment.mode.max(segment.mode),
330 begin: self.last_segment.begin,
331 end: segment.end,
332 };
333 let new_size = new_segment.encoded_len(self.version);
334
335 if self.last_segment_size + seg_size >= new_size {
336 self.last_segment = new_segment;
337 self.last_segment_size = new_size;
338 } else {
339 let old_segment = self.last_segment;
340 self.last_segment = segment;
341 self.last_segment_size = seg_size;
342 return Some(old_segment);
343 }
344 }
345 }
346 }
347 }
348}
349
350pub fn total_encoded_len(segments: &[Segment], version: Version) -> usize {
352 segments.iter().map(|seg| seg.encoded_len(version)).sum()
353}
354
355#[cfg(test)]
356mod optimize_tests {
357 use crate::optimize::{Optimizer, Segment, total_encoded_len};
358 use crate::types::{Mode, Version};
359
360 fn test_optimization_result(given: &[Segment], expected: &[Segment], version: Version) {
361 let prev_len = total_encoded_len(given, version);
362 let opt_segs = Optimizer::new(given.iter().copied(), version).collect::<Vec<_>>();
363 let new_len = total_encoded_len(&opt_segs, version);
364 if given != opt_segs {
365 assert!(prev_len > new_len, "{prev_len} > {new_len}");
366 }
367 assert_eq!(
368 opt_segs,
369 expected,
370 "Optimization gave something better: {} < {} ({:?})",
371 new_len,
372 total_encoded_len(expected, version),
373 opt_segs
374 );
375 }
376
377 #[test]
378 fn test_example_1() {
379 test_optimization_result(
380 &[
381 Segment { mode: Mode::Alphanumeric, begin: 0, end: 3 },
382 Segment { mode: Mode::Numeric, begin: 3, end: 6 },
383 Segment { mode: Mode::Byte, begin: 6, end: 10 },
384 ],
385 &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 6 }, Segment { mode: Mode::Byte, begin: 6, end: 10 }],
386 Version::Normal(1),
387 );
388 }
389
390 #[test]
391 fn test_example_2() {
392 test_optimization_result(
393 &[
394 Segment { mode: Mode::Numeric, begin: 0, end: 29 },
395 Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 },
396 Segment { mode: Mode::Numeric, begin: 30, end: 32 },
397 Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 },
398 Segment { mode: Mode::Numeric, begin: 35, end: 38 },
399 ],
400 &[
401 Segment { mode: Mode::Numeric, begin: 0, end: 29 },
402 Segment { mode: Mode::Alphanumeric, begin: 29, end: 38 },
403 ],
404 Version::Normal(9),
405 );
406 }
407
408 #[test]
409 fn test_example_3() {
410 test_optimization_result(
411 &[
412 Segment { mode: Mode::Kanji, begin: 0, end: 4 },
413 Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 },
414 Segment { mode: Mode::Byte, begin: 5, end: 6 },
415 Segment { mode: Mode::Kanji, begin: 6, end: 8 },
416 ],
417 &[Segment { mode: Mode::Byte, begin: 0, end: 8 }],
418 Version::Normal(1),
419 );
420 }
421
422 #[test]
423 fn test_example_4() {
424 test_optimization_result(
425 &[Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }],
426 &[Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }],
427 Version::Normal(1),
428 );
429 }
430
431 #[test]
432 fn test_annex_j_guideline_1a() {
433 test_optimization_result(
434 &[
435 Segment { mode: Mode::Numeric, begin: 0, end: 3 },
436 Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
437 ],
438 &[
439 Segment { mode: Mode::Numeric, begin: 0, end: 3 },
440 Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
441 ],
442 Version::Micro(2),
443 );
444 }
445
446 #[test]
447 fn test_annex_j_guideline_1b() {
448 test_optimization_result(
449 &[
450 Segment { mode: Mode::Numeric, begin: 0, end: 2 },
451 Segment { mode: Mode::Alphanumeric, begin: 2, end: 4 },
452 ],
453 &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }],
454 Version::Micro(2),
455 );
456 }
457
458 #[test]
459 fn test_annex_j_guideline_1c() {
460 test_optimization_result(
461 &[
462 Segment { mode: Mode::Numeric, begin: 0, end: 3 },
463 Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 },
464 ],
465 &[Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }],
466 Version::Micro(3),
467 );
468 }
469}
470
471#[derive(Copy, Clone)]
479enum ExclCharSet {
480 End = 0,
482
483 Symbol = 1,
486
487 Numeric = 2,
489
490 Alpha = 3,
493
494 KanjiHi1 = 4,
496
497 KanjiHi2 = 5,
499
500 KanjiHi3 = 6,
504
505 KanjiLo1 = 7,
509
510 KanjiLo2 = 8,
515
516 Byte = 9,
518}
519
520impl ExclCharSet {
521 fn from_u8(c: u8) -> Self {
523 match c {
524 0x20 | 0x24 | 0x25 | 0x2a | 0x2b | 0x2d..=0x2f | 0x3a => ExclCharSet::Symbol,
525 0x30..=0x39 => ExclCharSet::Numeric,
526 0x41..=0x5a => ExclCharSet::Alpha,
527 0x81..=0x9f => ExclCharSet::KanjiHi1,
528 0xe0..=0xea => ExclCharSet::KanjiHi2,
529 0xeb => ExclCharSet::KanjiHi3,
530 0x40 | 0x5b..=0x7e | 0x80 | 0xa0..=0xbf => ExclCharSet::KanjiLo1,
531 0xc0..=0xdf | 0xec..=0xfc => ExclCharSet::KanjiLo2,
532 _ => ExclCharSet::Byte,
533 }
534 }
535}
536
537#[derive(Copy, Clone)]
539enum State {
540 Init = 0,
542
543 Numeric = 10,
545
546 Alpha = 20,
548
549 Byte = 30,
551
552 KanjiHi12 = 40,
555
556 KanjiHi3 = 50,
559
560 Kanji = 60,
562}
563
564#[derive(Copy, Clone)]
566enum Action {
567 Idle,
569
570 Numeric,
572
573 Alpha,
575
576 Byte,
578
579 Kanji,
581
582 KanjiAndSingleByte,
585}
586
587static STATE_TRANSITION: [(State, Action); 70] = [
588 (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), ];
668
669