1pub mod ascii;
42pub mod capture;
43pub mod event;
44pub mod iter;
45pub mod signature;
46
47use smallvec::SmallVec;
48
49use ascii::AsciiControl;
50use event::{CSI, DCS, Esc, EscInvalid, SS2, SS3, VTEvent, VTIntermediate};
51
52const ESC: u8 = AsciiControl::Esc as _;
53const BEL: u8 = AsciiControl::Bel as _;
54const DEL: u8 = AsciiControl::Del as _;
55const CAN: u8 = AsciiControl::Can as _;
56const SUB: u8 = AsciiControl::Sub as _;
57const CSI: u8 = b'[';
58const OSC: u8 = b']';
59const SS2: u8 = b'N';
60const SS3: u8 = b'O';
61const DCS: u8 = b'P';
62const APC: u8 = b'_';
63const PM: u8 = b'^';
64const SOS: u8 = b'X';
65const ST_FINAL: u8 = b'\\';
66
67use crate::event::{Param, ParamBuf, Params};
68
69#[allow(private_bounds)]
71pub trait VTEventCallback: VTEventCallbackMaybeAbortable<()> {
72 fn event(&mut self, event: VTEvent<'_>) -> ();
73}
74
75impl<T: FnMut(VTEvent<'_>)> VTEventCallback for T {
76 #[inline(always)]
77 fn event(&mut self, event: VTEvent<'_>) -> () {
78 self(event)
79 }
80}
81
82impl<T: VTEventCallback> VTEventCallbackMaybeAbortable<()> for T {
83 #[inline(always)]
84 fn event(&mut self, event: VTEvent<'_>) -> () {
85 VTEventCallback::event(self, event)
86 }
87}
88
89#[allow(private_bounds)]
92pub trait VTEventCallbackAbortable: VTEventCallbackMaybeAbortable<bool> {
93 fn event(&mut self, event: VTEvent<'_>) -> bool;
94}
95
96impl<T: VTEventCallbackAbortable> VTEventCallbackMaybeAbortable<bool> for T {
97 #[inline(always)]
98 fn event(&mut self, event: VTEvent<'_>) -> bool {
99 VTEventCallbackAbortable::event(self, event)
100 }
101}
102
103impl<T: FnMut(VTEvent<'_>) -> bool> VTEventCallbackAbortable for T {
104 #[inline(always)]
105 fn event(&mut self, event: VTEvent<'_>) -> bool {
106 self(event)
107 }
108}
109
110trait VTEventCallbackMaybeAbortable<R: MaybeAbortable> {
111 fn event<'e>(&mut self, event: VTEvent<'e>) -> R;
112}
113
114enum VTAction<'a> {
116 None,
119 Event(VTEvent<'a>),
122 End(VTEnd),
124 Buffer(VTEmit),
127 Hold(VTEmit),
130 Cancel(VTEmit),
132}
133
134#[derive(Debug, Copy, Clone, PartialEq, Eq)]
135enum VTEmit {
136 Ground,
138 Dcs,
140 Osc,
142}
143
144#[derive(Debug, Copy, Clone, PartialEq, Eq)]
145enum VTEnd {
146 Dcs,
148 Osc { used_bel: bool },
150}
151
152#[inline]
153const fn is_c0(b: u8) -> bool {
154 b <= 0x1F && b != b'\r' && b != b'\n' && b != b'\t'
156}
157#[inline]
158fn is_printable(b: u8) -> bool {
159 (0x20..=0x7E).contains(&b)
160}
161#[inline]
162fn is_intermediate(b: u8) -> bool {
163 (0x20..=0x2F).contains(&b)
165}
166#[inline]
167const fn is_final(b: u8) -> bool {
168 b >= 0x40 && b <= 0x7E
169}
170#[inline]
171fn is_digit(b: u8) -> bool {
172 b.is_ascii_digit()
173}
174#[inline]
175fn is_priv(b: u8) -> bool {
176 matches!(b, b'<' | b'=' | b'>' | b'?')
177}
178
179macro_rules! byte_predicate {
180 (|$p:ident| $body:block) => {{
181 let mut out: [bool; 256] = [false; 256];
182 let mut i = 0;
183 while i < 256 {
184 let $p: u8 = i as u8;
185 out[i] = $body;
186 i += 1;
187 }
188 out
189 }};
190}
191
192const ENDS_CSI: [bool; 256] =
193 byte_predicate!(|b| { is_final(b) || b == ESC || b == CAN || b == SUB });
194
195const ENDS_GROUND: [bool; 256] = byte_predicate!(|b| { is_c0(b) || b == DEL });
196
197#[derive(Debug, Copy, Clone, PartialEq, Eq)]
198enum State {
199 Ground,
200 Escape,
201 EscInt,
202 EscSs2,
203 EscSs3,
204 CsiEntry,
205 CsiParam,
206 CsiInt,
207 CsiIgnore,
208 DcsEntry,
209 DcsParam,
210 DcsInt,
211 DcsIgnore,
212 DcsIgnoreEsc,
213 DcsPassthrough,
214 DcsEsc,
215 OscString,
216 OscEsc,
217 SosPmApcString,
218 SpaEsc,
219}
220
221pub const VT_PARSER_INTEREST_NONE: u8 = 0;
223pub const VT_PARSER_INTEREST_CSI: u8 = 1 << 0;
225pub const VT_PARSER_INTEREST_DCS: u8 = 1 << 1;
227pub const VT_PARSER_INTEREST_OSC: u8 = 1 << 2;
229pub const VT_PARSER_INTEREST_ESCAPE_RECOVERY: u8 = 1 << 4;
231pub const VT_PARSER_INTEREST_OTHER: u8 = 1 << 5;
233
234pub const VT_PARSER_INTEREST_ALL: u8 = VT_PARSER_INTEREST_CSI
236 | VT_PARSER_INTEREST_DCS
237 | VT_PARSER_INTEREST_OSC
238 | VT_PARSER_INTEREST_ESCAPE_RECOVERY
239 | VT_PARSER_INTEREST_OTHER;
240
241pub const VT_PARSER_INTEREST_DEFAULT: u8 = VT_PARSER_INTEREST_CSI
243 | VT_PARSER_INTEREST_DCS
244 | VT_PARSER_INTEREST_OSC
245 | VT_PARSER_INTEREST_OTHER;
246
247#[must_use]
248trait MaybeAbortable {
249 fn abort(self) -> bool;
250}
251
252impl MaybeAbortable for bool {
253 #[inline(always)]
254 fn abort(self) -> bool {
255 !self
256 }
257}
258
259impl MaybeAbortable for () {
260 #[inline(always)]
261 fn abort(self) -> bool {
262 false
263 }
264}
265
266pub struct VTPushParser<const INTEREST: u8 = VT_PARSER_INTEREST_DEFAULT> {
271 st: State,
272
273 ints: VTIntermediate,
275 params: Params,
276 cur_param: Param,
277 priv_prefix: Option<u8>,
278 held_byte: Option<u8>,
279}
280
281impl Default for VTPushParser {
282 fn default() -> Self {
283 Self::new()
284 }
285}
286
287impl VTPushParser {
288 pub const fn new() -> Self {
289 VTPushParser::new_with()
290 }
291
292 pub fn decode_buffer<'a>(input: &'a [u8], mut cb: impl for<'b> FnMut(VTEvent<'b>)) {
294 let mut parser = VTPushParser::new();
295 parser.feed_with(input, &mut cb);
296 }
297
298 pub const fn new_with_interest<const INTEREST: u8>() -> VTPushParser<INTEREST> {
299 VTPushParser::new_with()
300 }
301}
302
303macro_rules! invalid {
305 ($self:ident .priv_prefix, $self_:ident .ints, $b:expr) => {
306 if let Some(p) = $self.priv_prefix {
307 if $self.ints.len() == 0 {
308 VTEvent::EscInvalid(EscInvalid::Two(p, $b))
309 } else if $self.ints.len() == 1 {
310 VTEvent::EscInvalid(EscInvalid::Three(p, $self.ints.data[0], $b))
311 } else {
312 VTEvent::EscInvalid(EscInvalid::Four(
313 p,
314 $self.ints.data[0],
315 $self.ints.data[1],
316 $b,
317 ))
318 }
319 } else {
320 if $self.ints.len() == 0 {
321 VTEvent::EscInvalid(EscInvalid::One($b))
322 } else if $self.ints.len() == 1 {
323 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $b))
324 } else {
325 VTEvent::EscInvalid(EscInvalid::Three(
326 $self.ints.data[0],
327 $self.ints.data[1],
328 $b,
329 ))
330 }
331 }
332 };
333 ($self:ident .priv_prefix, $self_:ident .ints) => {
334 if let Some(p) = $self.priv_prefix {
335 if $self.ints.len() == 0 {
336 VTEvent::EscInvalid(EscInvalid::One(p))
337 } else if $self.ints.len() == 1 {
338 VTEvent::EscInvalid(EscInvalid::Two(p, $self.ints.data[0]))
339 } else {
340 VTEvent::EscInvalid(EscInvalid::Three(p, $self.ints.data[0], $self.ints.data[1]))
341 }
342 } else {
343 if $self.ints.len() == 0 {
344 VTEvent::C0(0x1b)
346 } else if $self.ints.len() == 1 {
347 VTEvent::EscInvalid(EscInvalid::One($self.ints.data[0]))
348 } else {
349 VTEvent::EscInvalid(EscInvalid::Two($self.ints.data[0], $self.ints.data[1]))
350 }
351 }
352 };
353 ($a:expr) => {
354 VTEvent::EscInvalid(EscInvalid::One($a))
355 };
356 ($a:expr, $b:expr) => {
357 VTEvent::EscInvalid(EscInvalid::Two($a, $b))
358 };
359}
360
361impl<const INTEREST: u8> VTPushParser<INTEREST> {
362 const fn new_with() -> Self {
363 Self {
364 st: State::Ground,
365 ints: VTIntermediate::empty(),
366 params: SmallVec::new_const(),
367 cur_param: SmallVec::new_const(),
368 priv_prefix: None,
369 held_byte: None,
370 }
371 }
372
373 #[inline]
417 pub fn feed_with<'this, 'input, F: VTEventCallback>(
418 &'this mut self,
419 input: &'input [u8],
420 mut cb: F,
421 ) {
422 self.feed_with_internal(input, &mut cb);
423 }
424
425 #[inline]
438 pub fn feed_with_abortable<'this, 'input, F: VTEventCallbackAbortable>(
439 &'this mut self,
440 input: &'input [u8],
441 mut cb: F,
442 ) -> usize {
443 self.feed_with_internal(input, &mut cb)
444 }
445
446 #[inline(always)]
447 fn feed_with_internal<'this, 'input, R: MaybeAbortable, F: VTEventCallbackMaybeAbortable<R>>(
448 &'this mut self,
449 input: &'input [u8],
450 cb: &mut F,
451 ) -> usize {
452 if input.is_empty() {
453 return 0;
454 }
455
456 #[derive(Debug)]
457 struct FeedState {
458 buffer_idx: usize,
459 current_emit: Option<VTEmit>,
460 hold: bool,
461 }
462
463 let mut state = FeedState {
464 buffer_idx: 0,
465 current_emit: None,
466 hold: self.held_byte.is_some(),
467 };
468
469 let mut held_byte = self.held_byte.take();
470 let mut i = 0;
471
472 while i < input.len() {
473 if self.st == State::Ground {
475 let start = i;
476 loop {
477 if i >= input.len() {
478 cb.event(VTEvent::Raw(&input[start..]));
479 return input.len();
480 }
481 if ENDS_GROUND[input[i] as usize] {
482 break;
483 }
484 i += 1;
485 }
486
487 if start != i && cb.event(VTEvent::Raw(&input[start..i])).abort() {
488 return i;
489 }
490
491 if input[i] == ESC {
492 self.clear_hdr_collectors();
493 self.st = State::Escape;
494 i += 1;
495 continue;
496 }
497 }
498
499 if self.st == State::CsiIgnore {
501 loop {
502 if i >= input.len() {
503 return input.len();
504 }
505 if ENDS_CSI[input[i] as usize] {
506 break;
507 }
508 i += 1;
509 }
510
511 if input[i] == ESC {
512 self.st = State::Escape;
513 } else {
514 self.st = State::Ground;
515 }
516 i += 1;
517 continue;
518 }
519
520 let action = self.push_with(input[i]);
521
522 match action {
523 VTAction::None => {
524 if let Some(emit) = state.current_emit {
525 let range = state.buffer_idx..(i - state.hold as usize);
527 if !range.is_empty()
528 && match emit {
529 VTEmit::Ground => cb.event(VTEvent::Raw(&input[range])),
530 VTEmit::Dcs => cb.event(VTEvent::DcsData(&input[range])),
531 VTEmit::Osc => cb.event(VTEvent::OscData(&input[range])),
532 }
533 .abort()
534 {
535 if state.hold {
536 self.held_byte = Some(0x1b);
537 }
538 return i + 1;
539 }
540 if state.hold {
541 held_byte = Some(0x1b);
542 }
543 state.current_emit = None;
544 }
545 }
546 VTAction::Event(e) => {
547 if cb.event(e).abort() {
548 return i + 1;
549 }
550 }
551 VTAction::End(VTEnd::Dcs) => {
552 state.current_emit = None;
553 let hold = std::mem::take(&mut state.hold);
554 let range = state.buffer_idx..(i.saturating_sub(hold as usize));
555 if cb.event(VTEvent::DcsEnd(&input[range])).abort() {
556 return i + 1;
557 }
558 held_byte = None;
559 }
560 VTAction::End(VTEnd::Osc { used_bel }) => {
561 state.current_emit = None;
562 let hold = std::mem::take(&mut state.hold);
563 let range = state.buffer_idx..(i.saturating_sub(hold as usize));
564 if cb
565 .event(VTEvent::OscEnd {
566 data: &input[range],
567 used_bel,
568 })
569 .abort()
570 {
571 return i + 1;
572 }
573 held_byte = None;
574 }
575 VTAction::Buffer(emit) | VTAction::Hold(emit) => {
576 if state.current_emit.is_none()
577 && let Some(h) = held_byte.take()
578 && match emit {
579 VTEmit::Ground => cb.event(VTEvent::Raw(&[h])),
580 VTEmit::Dcs => cb.event(VTEvent::DcsData(&[h])),
581 VTEmit::Osc => cb.event(VTEvent::OscData(&[h])),
582 }
583 .abort()
584 {
585 if matches!(action, VTAction::Hold(_)) {
586 self.held_byte = Some(0x1b);
587 return 1;
588 }
589 return 0;
590 }
591
592 debug_assert!(state.current_emit.is_none() || state.current_emit == Some(emit));
593
594 state.hold = matches!(action, VTAction::Hold(_));
595 if state.current_emit.is_none() {
596 state.buffer_idx = i;
597 state.current_emit = Some(emit);
598 }
599 }
600 VTAction::Cancel(emit) => {
601 state.current_emit = None;
602 state.hold = false;
603 if match emit {
604 VTEmit::Ground => unreachable!(),
605 VTEmit::Dcs => cb.event(VTEvent::DcsCancel),
606 VTEmit::Osc => cb.event(VTEvent::OscCancel),
607 }
608 .abort()
609 {
610 return i + 1;
611 }
612 }
613 };
614 i += 1;
615 }
616
617 if state.hold {
619 self.held_byte = Some(0x1b);
620 }
621
622 if let Some(emit) = state.current_emit.take() {
623 let range = &input[state.buffer_idx..input.len() - state.hold as usize];
624 if !range.is_empty() {
625 match emit {
626 VTEmit::Ground => cb.event(VTEvent::Raw(range)),
627 VTEmit::Dcs => cb.event(VTEvent::DcsData(range)),
628 VTEmit::Osc => cb.event(VTEvent::OscData(range)),
629 };
630 }
631 };
632
633 input.len()
635 }
636
637 pub fn is_ground(&self) -> bool {
639 self.st == State::Ground
640 }
641
642 pub fn idle(&mut self) -> Option<VTEvent<'static>> {
646 match self.st {
647 State::Escape => {
648 self.st = State::Ground;
649 Some(VTEvent::C0(ESC))
650 }
651 State::EscInt => {
652 self.st = State::Ground;
653 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
654 None
655 } else {
656 Some(invalid!(self.priv_prefix, self.ints))
657 }
658 }
659 State::EscSs2 | State::EscSs3 => {
660 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
661 self.st = State::Ground;
662 None
663 } else {
664 let c = match self.st {
665 State::EscSs2 => SS2,
666 State::EscSs3 => SS3,
667 _ => unreachable!(),
668 };
669 self.st = State::Ground;
670 Some(invalid!(c))
671 }
672 }
673 _ => None,
674 }
675 }
676
677 fn push_with(&mut self, b: u8) -> VTAction {
678 use State::*;
679 match self.st {
680 Ground => self.on_ground(b),
681 Escape => self.on_escape(b),
682 EscInt => self.on_esc_int(b),
683 EscSs2 => self.on_esc_ss2(b),
684 EscSs3 => self.on_esc_ss3(b),
685
686 CsiEntry => self.on_csi_entry(b),
687 CsiParam => self.on_csi_param(b),
688 CsiInt => self.on_csi_int(b),
689 CsiIgnore => self.on_csi_ignore(b),
690
691 DcsEntry => self.on_dcs_entry(b),
692 DcsParam => self.on_dcs_param(b),
693 DcsInt => self.on_dcs_int(b),
694 DcsIgnore => self.on_dcs_ignore(b),
695 DcsIgnoreEsc => self.on_dcs_ignore_esc(b),
696 DcsPassthrough => self.on_dcs_pass(b),
697 DcsEsc => self.on_dcs_esc(b),
698
699 OscString => self.on_osc_string(b),
700 OscEsc => self.on_osc_esc(b),
701
702 SosPmApcString => self.on_spa_string(b),
703 SpaEsc => self.on_spa_esc(b),
704 }
705 }
706
707 pub fn finish<F: FnMut(VTEvent)>(&mut self, _cb: &mut F) {
708 self.reset_collectors();
709 self.st = State::Ground;
710
711 }
713
714 fn clear_hdr_collectors(&mut self) {
719 self.ints.clear();
720 self.params.clear();
721 self.cur_param.clear();
722 self.priv_prefix = None;
723 }
724
725 fn reset_collectors(&mut self) {
726 self.clear_hdr_collectors();
727 }
728
729 fn next_param(&mut self) {
730 self.params.push(std::mem::take(&mut self.cur_param));
731 }
732
733 fn finish_params_if_any(&mut self) {
734 if !self.cur_param.is_empty() || !self.params.is_empty() {
735 self.next_param();
736 }
737 }
738
739 fn emit_csi(&mut self, final_byte: u8) -> VTAction {
740 self.finish_params_if_any();
741
742 let mut borrowed: SmallVec<[&[u8]; 4]> = SmallVec::new();
744 borrowed.extend(self.params.iter().map(|v| v.as_slice()));
745
746 let privp = self.priv_prefix.take();
747 VTAction::Event(VTEvent::Csi(CSI {
748 private: privp,
749 params: ParamBuf {
750 params: &self.params,
751 },
752 intermediates: self.ints,
753 final_byte,
754 }))
755 }
756
757 fn dcs_start(&mut self, final_byte: u8) -> VTAction {
758 self.finish_params_if_any();
759
760 let privp = self.priv_prefix.take();
761 VTAction::Event(VTEvent::DcsStart(DCS {
762 private: privp,
763 params: ParamBuf {
764 params: &self.params,
765 },
766 intermediates: self.ints,
767 final_byte,
768 }))
769 }
770
771 fn on_ground(&mut self, b: u8) -> VTAction {
776 match b {
777 ESC => {
778 self.clear_hdr_collectors();
779 self.st = State::Escape;
780 VTAction::None
781 }
782 DEL => VTAction::Event(VTEvent::C0(DEL)),
783 c if is_c0(c) => VTAction::Event(VTEvent::C0(c)),
784 p if is_printable(p) => VTAction::Buffer(VTEmit::Ground),
785 _ => VTAction::Buffer(VTEmit::Ground), }
787 }
788
789 fn on_escape(&mut self, b: u8) -> VTAction {
790 use State::*;
791 match b {
792 CAN | SUB => {
793 self.st = Ground;
794 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
795 VTAction::None
796 } else {
797 VTAction::Event(invalid!(b))
798 }
799 }
800 DEL => {
803 self.st = Ground;
804 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
805 VTAction::None
806 } else {
807 VTAction::Event(invalid!(b))
808 }
809 }
810 c if is_intermediate(c) => {
811 if self.ints.push(c) {
812 self.st = EscInt;
813 } else {
814 self.st = Ground;
815 }
816 VTAction::None
817 }
818 b'?' => {
820 self.priv_prefix = Some(b);
821 self.st = EscInt;
822 VTAction::None
823 }
824 c if is_priv(c) => {
826 self.st = Ground;
827 VTAction::Event(VTEvent::Esc(Esc {
828 intermediates: VTIntermediate::empty(),
829 private: None,
830 final_byte: b,
831 }))
832 }
833 CSI => {
834 if INTEREST & VT_PARSER_INTEREST_CSI == 0 {
835 self.st = CsiIgnore;
836 } else {
837 self.st = CsiEntry;
838 }
839 VTAction::None
840 }
841 DCS => {
842 if INTEREST & VT_PARSER_INTEREST_DCS == 0 {
843 self.st = DcsIgnore;
844 } else {
845 self.st = DcsEntry;
846 }
847 VTAction::None
848 }
849 OSC => {
850 self.st = OscString;
851 VTAction::Event(VTEvent::OscStart)
852 }
853 SS2 => {
854 self.st = EscSs2;
855 VTAction::None
856 }
857 SS3 => {
858 self.st = EscSs3;
859 VTAction::None
860 }
861 SOS | PM | APC => {
862 self.st = State::SosPmApcString;
863 VTAction::None
864 }
865 c if is_final(c) || is_digit(c) => {
866 self.st = Ground;
867 VTAction::Event(VTEvent::Esc(Esc {
868 intermediates: self.ints,
869 private: self.priv_prefix.take(),
870 final_byte: c,
871 }))
872 }
873 ESC => {
874 VTAction::Event(VTEvent::C0(ESC))
876 }
877 _ => {
878 self.st = Ground;
879 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
880 VTAction::None
881 } else {
882 VTAction::Event(invalid!(b))
883 }
884 }
885 }
886 }
887
888 fn on_esc_int(&mut self, b: u8) -> VTAction {
889 use State::*;
890 match b {
891 CAN | SUB => {
892 self.st = Ground;
893 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
894 VTAction::None
895 } else {
896 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
897 }
898 }
899 DEL => {
902 self.st = Ground;
903 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
904 VTAction::None
905 } else {
906 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
907 }
908 }
909 c if is_intermediate(c) => {
910 if !self.ints.push(c) {
911 self.st = Ground;
912 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
913 VTAction::None
914 } else {
915 VTAction::Event(invalid!(self.priv_prefix, self.ints, b))
916 }
917 } else {
918 VTAction::None
919 }
920 }
921 c if is_final(c) || is_digit(c) => {
922 self.st = Ground;
923 VTAction::Event(VTEvent::Esc(Esc {
924 intermediates: self.ints,
925 private: self.priv_prefix.take(),
926 final_byte: c,
927 }))
928 }
929 ESC => {
932 self.st = Escape;
933 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
934 VTAction::None
935 } else {
936 VTAction::Event(invalid!(self.priv_prefix, self.ints))
937 }
938 }
939 c => {
940 self.st = Ground;
941 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
942 VTAction::None
943 } else {
944 VTAction::Event(invalid!(self.priv_prefix, self.ints, c))
945 }
946 }
947 }
948 }
949
950 fn on_esc_ss2(&mut self, b: u8) -> VTAction {
951 use State::*;
952 self.st = Ground;
953 match b {
954 CAN | SUB => {
955 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
956 VTAction::None
957 } else {
958 VTAction::Event(invalid!(SS2, b))
959 }
960 }
961 ESC => {
964 self.st = Escape;
965 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
966 VTAction::None
967 } else {
968 VTAction::Event(invalid!(SS2))
969 }
970 }
971 c => VTAction::Event(VTEvent::Ss2(SS2 { char: c })),
972 }
973 }
974
975 fn on_esc_ss3(&mut self, b: u8) -> VTAction {
976 use State::*;
977 self.st = Ground;
978 match b {
979 CAN | SUB => {
980 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
981 VTAction::None
982 } else {
983 VTAction::Event(invalid!(SS3, b))
984 }
985 }
986 ESC => {
989 self.st = Escape;
990 if INTEREST & VT_PARSER_INTEREST_ESCAPE_RECOVERY == 0 {
991 VTAction::None
992 } else {
993 VTAction::Event(invalid!(SS3))
994 }
995 }
996 c => VTAction::Event(VTEvent::Ss3(SS3 { char: c })),
997 }
998 }
999
1000 fn on_csi_entry(&mut self, b: u8) -> VTAction {
1002 use State::*;
1003 match b {
1004 CAN | SUB => {
1005 self.st = Ground;
1006 VTAction::None
1007 }
1008 DEL => VTAction::None,
1009 ESC => {
1010 self.st = Escape;
1011 VTAction::None
1012 }
1013 c if is_priv(c) => {
1014 self.priv_prefix = Some(c);
1015 self.st = CsiParam;
1016 VTAction::None
1017 }
1018 d if is_digit(d) => {
1019 self.cur_param.push(d);
1020 self.st = CsiParam;
1021 VTAction::None
1022 }
1023 b';' => {
1024 self.next_param();
1025 self.st = CsiParam;
1026 VTAction::None
1027 }
1028 b':' => {
1029 self.cur_param.push(b':');
1030 self.st = CsiParam;
1031 VTAction::None
1032 }
1033 c if is_intermediate(c) => {
1034 if self.ints.push(c) {
1035 self.st = CsiInt;
1036 } else {
1037 self.st = Ground;
1038 }
1039 VTAction::None
1040 }
1041 c if is_final(c) => {
1042 self.st = Ground;
1043 self.emit_csi(c)
1044 }
1045 _ => {
1046 self.st = CsiIgnore;
1047 VTAction::None
1048 }
1049 }
1050 }
1051
1052 fn on_csi_param(&mut self, b: u8) -> VTAction {
1053 use State::*;
1054 match b {
1055 CAN | SUB => {
1056 self.st = Ground;
1057 VTAction::None
1058 }
1059 DEL => VTAction::None,
1060 ESC => {
1061 self.st = Escape;
1062 VTAction::None
1063 }
1064 d if is_digit(d) => {
1065 self.cur_param.push(d);
1066 VTAction::None
1067 }
1068 b';' => {
1069 self.next_param();
1070 VTAction::None
1071 }
1072 b':' => {
1073 self.cur_param.push(b':');
1074 VTAction::None
1075 }
1076 c if is_intermediate(c) => {
1077 if self.ints.push(c) {
1078 self.st = CsiInt;
1079 } else {
1080 self.st = Ground;
1081 }
1082 VTAction::None
1083 }
1084 c if is_final(c) => {
1085 self.st = Ground;
1086 self.emit_csi(c)
1087 }
1088 _ => {
1089 self.st = CsiIgnore;
1090 VTAction::None
1091 }
1092 }
1093 }
1094
1095 fn on_csi_int(&mut self, b: u8) -> VTAction {
1096 use State::*;
1097 match b {
1098 CAN | SUB => {
1099 self.st = Ground;
1100 VTAction::None
1101 }
1102 DEL => VTAction::None,
1103 ESC => {
1104 self.st = Escape;
1105 VTAction::None
1106 }
1107 c if is_intermediate(c) => {
1108 if self.ints.push(c) {
1109 self.st = CsiInt;
1110 } else {
1111 self.st = Ground;
1112 }
1113 VTAction::None
1114 }
1115 c if is_final(c) => {
1116 self.st = Ground;
1117 self.emit_csi(c)
1118 }
1119 _ => {
1120 self.st = CsiIgnore;
1121 VTAction::None
1122 }
1123 }
1124 }
1125
1126 fn on_csi_ignore(&mut self, b: u8) -> VTAction {
1127 use State::*;
1128 match b {
1129 CAN | SUB => {
1130 self.st = Ground;
1131 VTAction::None
1132 }
1133 DEL => VTAction::None,
1134 ESC => {
1135 self.st = Escape;
1136 VTAction::None
1137 }
1138 c if is_final(c) => {
1139 self.st = Ground;
1140 VTAction::None
1141 }
1142 _ => VTAction::None,
1143 }
1144 }
1145
1146 fn on_dcs_entry(&mut self, b: u8) -> VTAction {
1148 use State::*;
1149 match b {
1150 CAN | SUB => {
1151 self.st = Ground;
1152 VTAction::None
1153 }
1154 DEL => VTAction::None,
1155 ESC => {
1156 self.st = Escape;
1157 VTAction::None
1158 }
1159 c if is_priv(c) => {
1160 self.priv_prefix = Some(c);
1161 self.st = DcsParam;
1162 VTAction::None
1163 }
1164 d if is_digit(d) => {
1165 self.cur_param.push(d);
1166 self.st = DcsParam;
1167 VTAction::None
1168 }
1169 b';' => {
1170 self.next_param();
1171 self.st = DcsParam;
1172 VTAction::None
1173 }
1174 b':' => {
1175 self.st = DcsIgnore;
1176 VTAction::None
1177 }
1178 c if is_intermediate(c) => {
1179 if self.ints.push(c) {
1180 self.st = DcsInt;
1181 } else {
1182 self.st = Ground;
1183 }
1184 VTAction::None
1185 }
1186 c if is_final(c) => {
1187 self.st = DcsPassthrough;
1188 self.dcs_start(c)
1189 }
1190 _ => {
1191 self.st = DcsIgnore;
1192 VTAction::None
1193 }
1194 }
1195 }
1196
1197 fn on_dcs_param(&mut self, b: u8) -> VTAction {
1198 use State::*;
1199 match b {
1200 CAN | SUB => {
1201 self.st = Ground;
1202 VTAction::None
1203 }
1204 DEL => VTAction::None,
1205 ESC => {
1206 self.st = Escape;
1207 VTAction::None
1208 }
1209 d if is_digit(d) => {
1210 self.cur_param.push(d);
1211 VTAction::None
1212 }
1213 b';' => {
1214 self.next_param();
1215 VTAction::None
1216 }
1217 b':' => {
1218 self.st = DcsIgnore;
1219 VTAction::None
1220 }
1221 c if is_intermediate(c) => {
1222 if self.ints.push(c) {
1223 self.st = DcsInt;
1224 } else {
1225 self.st = Ground;
1226 }
1227 self.st = DcsInt;
1228 VTAction::None
1229 }
1230 c if is_final(c) => {
1231 self.st = DcsPassthrough;
1232 self.dcs_start(c)
1233 }
1234 _ => {
1235 self.st = DcsIgnore;
1236 VTAction::None
1237 }
1238 }
1239 }
1240
1241 fn on_dcs_int(&mut self, b: u8) -> VTAction {
1242 use State::*;
1243 match b {
1244 CAN | SUB => {
1245 self.st = Ground;
1246 VTAction::None
1247 }
1248 DEL => VTAction::None,
1249 ESC => {
1250 self.st = Escape;
1251 VTAction::None
1252 }
1253 c if is_intermediate(c) => {
1254 if self.ints.push(c) {
1255 self.st = DcsInt;
1256 } else {
1257 self.st = Ground;
1258 }
1259 VTAction::None
1260 }
1261 c if is_final(c) || is_digit(c) || c == b':' || c == b';' => {
1262 self.st = DcsPassthrough;
1263 self.dcs_start(c)
1264 }
1265 _ => {
1266 self.st = DcsIgnore;
1267 VTAction::None
1268 }
1269 }
1270 }
1271
1272 fn on_dcs_ignore(&mut self, b: u8) -> VTAction {
1273 use State::*;
1274 match b {
1275 CAN | SUB => {
1276 self.st = Ground;
1277 VTAction::None
1278 }
1279 DEL => VTAction::None,
1280 ESC => {
1281 self.st = DcsIgnoreEsc;
1282 VTAction::None
1283 }
1284 _ => VTAction::None,
1285 }
1286 }
1287
1288 fn on_dcs_ignore_esc(&mut self, b: u8) -> VTAction {
1289 use State::*;
1290 match b {
1291 CAN | SUB => {
1292 self.st = Ground;
1293 VTAction::None
1294 }
1295 ST_FINAL => {
1296 self.st = Ground;
1297 VTAction::None
1298 }
1299 DEL => VTAction::None,
1300 ESC => VTAction::None,
1301 _ => {
1302 self.st = DcsIgnore;
1303 VTAction::None
1304 }
1305 }
1306 }
1307
1308 fn on_dcs_pass(&mut self, b: u8) -> VTAction {
1309 use State::*;
1310 match b {
1311 CAN | SUB => {
1312 self.st = Ground;
1313 VTAction::Cancel(VTEmit::Dcs)
1314 }
1315 DEL => VTAction::None,
1316 ESC => {
1317 self.st = DcsEsc;
1318 VTAction::Hold(VTEmit::Dcs)
1319 }
1320 _ => VTAction::Buffer(VTEmit::Dcs),
1321 }
1322 }
1323
1324 fn on_dcs_esc(&mut self, b: u8) -> VTAction {
1325 use State::*;
1326 match b {
1327 ST_FINAL => {
1328 self.st = Ground;
1329 VTAction::End(VTEnd::Dcs)
1330 }
1331 DEL => VTAction::None,
1332 ESC => {
1333 VTAction::Hold(VTEmit::Dcs)
1335 }
1336 _ => {
1337 self.st = DcsPassthrough;
1339 VTAction::Buffer(VTEmit::Dcs)
1340 }
1341 }
1342 }
1343
1344 fn on_osc_string(&mut self, b: u8) -> VTAction {
1346 use State::*;
1347 match b {
1348 CAN | SUB => {
1349 self.st = Ground;
1350 VTAction::Cancel(VTEmit::Osc)
1351 }
1352 DEL => VTAction::None,
1353 BEL => {
1354 self.st = Ground;
1355 VTAction::End(VTEnd::Osc { used_bel: true })
1356 }
1357 ESC => {
1358 self.st = OscEsc;
1359 VTAction::Hold(VTEmit::Osc)
1360 }
1361 p if is_printable(p) => VTAction::Buffer(VTEmit::Osc),
1362 _ => VTAction::None, }
1364 }
1365
1366 fn on_osc_esc(&mut self, b: u8) -> VTAction {
1367 use State::*;
1368 match b {
1369 ST_FINAL => {
1370 self.st = Ground;
1371 VTAction::End(VTEnd::Osc { used_bel: false })
1372 } ESC => VTAction::Hold(VTEmit::Osc),
1374 DEL => VTAction::None,
1375 _ => {
1376 self.st = OscString;
1377 VTAction::Buffer(VTEmit::Osc)
1378 }
1379 }
1380 }
1381
1382 fn on_spa_string(&mut self, b: u8) -> VTAction {
1384 use State::*;
1385 match b {
1386 CAN | SUB => {
1387 self.st = Ground;
1388 VTAction::None
1389 }
1390 DEL => VTAction::None,
1391 ESC => {
1392 self.st = SpaEsc;
1393 VTAction::None
1394 }
1395 _ => VTAction::None,
1396 }
1397 }
1398
1399 fn on_spa_esc(&mut self, b: u8) -> VTAction {
1400 use State::*;
1401 match b {
1402 ST_FINAL => {
1403 self.st = Ground;
1404 VTAction::None
1405 }
1406 DEL => VTAction::None,
1407 ESC => {
1408 VTAction::None
1410 }
1411 _ => {
1412 self.st = State::SosPmApcString;
1413 VTAction::None
1414 }
1415 }
1416 }
1417}
1418
1419#[cfg(test)]
1420mod tests {
1421 use crate::event::VTOwnedEvent;
1422
1423 use super::*;
1424 use pretty_assertions::assert_eq;
1425
1426 #[test]
1427 fn test_edge_cases() {
1428 let mut result = String::new();
1430 VTPushParser::decode_buffer(&[], |e| result.push_str(&format!("{e:?}\n")));
1431 assert_eq!(result.trim(), "");
1432
1433 let mut result = String::new();
1435 VTPushParser::decode_buffer(b"\x1b", |e| result.push_str(&format!("{e:?}\n")));
1436 assert_eq!(result.trim(), "");
1437
1438 let mut result = String::new();
1440 VTPushParser::decode_buffer(b"\x1b[", |e| result.push_str(&format!("{e:?}\n")));
1441 assert_eq!(result.trim(), "");
1442
1443 let mut result = String::new();
1445 VTPushParser::decode_buffer(b"\x1bP", |e| result.push_str(&format!("{e:?}\n")));
1446 assert_eq!(result.trim(), "");
1447
1448 let mut result = String::new();
1450 VTPushParser::decode_buffer(b"\x1b]", |e| result.push_str(&format!("{e:?}\n")));
1451 assert_eq!(result.trim(), "OscStart");
1452 }
1453
1454 #[test]
1455 fn test_streaming_behavior() {
1456 let mut parser = VTPushParser::new(); let mut result = String::new();
1459 let mut callback = |vt_input: VTEvent<'_>| {
1460 result.push_str(&format!("{vt_input:?}\n"));
1461 };
1462
1463 parser.feed_with(b"\x1bP1;2;3 |", &mut callback);
1465 parser.feed_with(b"data", &mut callback);
1466 parser.feed_with(b" more", &mut callback);
1467 parser.feed_with(b"\x1b\\", &mut callback);
1468
1469 assert_eq!(
1470 result.trim(),
1471 "DcsStart('1', '2', '3', ' ', |)\nDcsData('data')\nDcsData(' more')\nDcsEnd('')"
1472 );
1473 }
1474
1475 #[test]
1476 fn test_dcs_payload_passthrough() {
1477 let dcs_cases: &[(&[u8], &str)] = &[
1485 (b"\x1bPq\x1b[38:2:12:34:56m\x1b\\", "<ESC>[38:2:12:34:56m"),
1487 (b"\x1bPq\x1b[48:2:0:0:0m;xyz\x1b\\", "<ESC>[48:2:0:0:0m;xyz"),
1489 (
1491 b"\x1bP1$r\x1b[38:2:10:20:30;58:2::200:100:0m\x1b\\",
1492 "<ESC>[38:2:10:20:30;58:2::200:100:0m",
1493 ),
1494 (
1496 b"\x1bPqABC\x1b\x1bDEF\x1bXG\x1b\\",
1497 "ABC<ESC><ESC>DEF<ESC>XG",
1498 ),
1499 (b"\x1bPqDATA\x07MORE\x1b\\", "DATA<BEL>MORE"),
1501 (b"\x1bP!|\x1b[38:5:208m\x1b\\", "<ESC>[38:5:208m"),
1503 (b"\x1bP>|Hello world\x1b\\", "Hello world"),
1505 (
1507 b"\x1bPq\x1b[38:2:1:2:3m\x1b[48:5:17m\x1b\\",
1508 "<ESC>[38:2:1:2:3m<ESC>[48:5:17m",
1509 ),
1510 (
1512 b"\x1bPq\x1b[58:2::000:007:042m\x1b\\",
1513 "<ESC>[58:2::000:007:042m",
1514 ),
1515 ];
1516
1517 for (input, expected_body) in dcs_cases {
1518 let events = collect_owned_events(input);
1519
1520 let mut actual_body = Vec::new();
1522 for event in &events {
1523 match event {
1524 VTOwnedEvent::DcsData(data) | VTOwnedEvent::DcsEnd(data) => {
1525 actual_body.extend(data);
1526 }
1527 _ => {}
1528 }
1529 }
1530
1531 let actual_body = String::from_utf8(actual_body).unwrap();
1532 let actual_body = actual_body
1533 .replace("\x1b", "<ESC>")
1534 .replace("\x07", "<BEL>");
1535
1536 assert_eq!(
1537 actual_body, *expected_body,
1538 "DCS payload mismatch for input {:?}. Full events: {:#?}",
1539 input, events
1540 );
1541 }
1542 }
1543
1544 fn collect_events(input: &[u8]) -> Vec<String> {
1545 let mut out = Vec::new();
1546 let mut p = VTPushParser::new();
1547 p.feed_with(input, |ev: VTEvent| out.push(format!("{ev:?}")));
1548 out
1549 }
1550
1551 fn collect_owned_events(input: &[u8]) -> Vec<VTOwnedEvent> {
1552 let mut out = Vec::new();
1553 let mut p = VTPushParser::new();
1554 p.feed_with(input, &mut |ev: VTEvent| out.push(ev.to_owned()));
1555 out
1556 }
1557
1558 #[test]
1559 fn dcs_esc_esc_del() {
1560 let ev = collect_events(b"\x1bP1;2;3|\x1b\x1b\x7fdata\x1b\\");
1561 eprintln!("{ev:?}");
1562 }
1563
1564 #[test]
1565 fn osc_bel() {
1566 let mut parser = VTPushParser::new();
1567 let mut output = String::new();
1568 for b in b"\x1b]X\x07" {
1569 parser.feed_with(&[*b], &mut |ev: VTEvent| {
1570 output.push_str(&format!("{ev:?}\n"));
1571 });
1572 }
1573 assert_eq!(output.trim(), "OscStart\nOscData('X')\nOscEnd('')");
1574 }
1575
1576 #[test]
1577 fn dcs_header_with_colon_is_ignored_case1() {
1578 let ev = collect_events(b"\x1bP1:2qHELLO\x1b\\");
1580 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1582 }
1583
1584 #[test]
1585 fn dcs_header_with_colon_is_ignored_case2() {
1586 let ev = collect_events(b"\x1bP:1qDATA\x1b\\");
1588 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1589 }
1590
1591 #[test]
1592 fn dcs_header_with_colon_is_ignored_case3() {
1593 let ev = collect_events(b"\x1bP12:34!qPAYLOAD\x1b\\");
1595 assert!(ev.iter().all(|e| !e.starts_with("DcsStart")), "{ev:#?}");
1596 }
1597
1598 #[test]
1599 fn osc_aborted_by_can_mid_body() {
1600 let mut s = Vec::new();
1602 s.extend_from_slice(b"\x1b]0;Title");
1603 s.push(CAN);
1604 s.extend_from_slice(b"more\x07");
1605
1606 let ev = collect_debug(&s);
1607
1608 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1613 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1614 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1615 }
1616
1617 #[test]
1618 fn osc_aborted_by_sub_before_terminator() {
1619 let mut s = Vec::new();
1620 s.extend_from_slice(b"\x1b]52;c;YWJjZA==");
1621 s.push(SUB); s.extend_from_slice(b"\x1b\\"); let ev = collect_debug(&s);
1625 assert!(ev.iter().any(|e| e.starts_with("OscStart")), "{ev:#?}");
1629 assert!(!ev.iter().any(|e| e.starts_with("OscData")), "{ev:#?}");
1630 assert!(!ev.iter().any(|e| e.starts_with("OscEnd")), "{ev:#?}");
1631 }
1632
1633 fn collect_debug(input: &[u8]) -> Vec<String> {
1635 let mut out = Vec::new();
1636 let mut p = VTPushParser::new();
1637 p.feed_with(input, |ev: VTEvent| out.push(format!("{ev:?}")));
1638 out
1639 }
1640
1641 #[test]
1642 fn dcs_aborted_by_can_before_body() {
1643 let mut s = Vec::new();
1645 s.extend_from_slice(b"\x1bPq"); s.push(CAN);
1647 s.extend_from_slice(b"IGNORED\x1b\\"); let ev = collect_debug(&s);
1650
1651 assert_eq!(ev.len(), 4, "{ev:#?}");
1652 assert_eq!(ev[0], "DcsStart('', q)");
1653 assert_eq!(ev[1], "DcsCancel");
1654 assert_eq!(ev[2], "Raw('IGNORED')");
1655 assert_eq!(ev[3], "Esc('', \\)");
1656 }
1657
1658 #[test]
1659 fn dcs_aborted_by_can_mid_body() {
1660 let mut s = Vec::new();
1662 s.extend_from_slice(b"\x1bPqABC");
1663 s.push(CAN);
1664 s.extend_from_slice(b"MORE\x1b\\"); let ev = collect_debug(&s);
1667
1668 assert_eq!(ev.len(), 4, "{ev:#?}");
1669 assert_eq!(ev[0], "DcsStart('', q)");
1670 assert_eq!(ev[1], "DcsCancel");
1671 assert_eq!(ev[2], "Raw('MORE')");
1672 assert_eq!(ev[3], "Esc('', \\)");
1673 }
1674
1675 #[test]
1678 fn spa_aborted_by_can_is_ignored() {
1679 let mut s = Vec::new();
1681 s.extend_from_slice(b"\x1b_hello");
1682 s.push(CAN);
1683 s.extend_from_slice(b"world\x1b\\");
1684
1685 let ev = collect_debug(&s);
1686 assert_eq!(ev.len(), 2, "{ev:#?}");
1687 assert_eq!(ev[0], "Raw('world')");
1688 assert_eq!(ev[1], "Esc('', \\)");
1689 }
1690
1691 #[test]
1692 fn spa_sub_aborts_too() {
1693 let mut s = Vec::new();
1694 s.extend_from_slice(b"\x1bXhello");
1695 s.push(SUB);
1696 s.extend_from_slice(b"world\x1b\\");
1697 let ev = collect_debug(&s);
1698 assert_eq!(ev.len(), 2, "{ev:#?}");
1699 assert_eq!(ev[0], "Raw('world')");
1700 assert_eq!(ev[1], "Esc('', \\)");
1701 }
1702
1703 #[test]
1706 fn can_in_ground_is_c0() {
1707 let mut s = Vec::new();
1708 s.extend_from_slice(b"abc");
1709 s.push(CAN);
1710 s.extend_from_slice(b"def");
1711 let ev = collect_debug(&s);
1712 assert_eq!(ev.len(), 3, "{ev:#?}");
1714 assert_eq!(ev[0], "Raw('abc')");
1715 assert_eq!(ev[1], "C0(18)");
1716 assert_eq!(ev[2], "Raw('def')");
1717 }
1718
1719 #[test]
1722 fn three_byte_sequences_capturable() {
1723 let mut bytes = vec![];
1724 for i in 0..=0xFFFFFF_u32 {
1725 bytes.clear();
1726 let test_bytes = i.to_le_bytes();
1727 let test_bytes = &test_bytes[..3];
1728 if test_bytes.iter().any(|b| b == &0) {
1729 continue;
1730 }
1731 if test_bytes[0] == 0x1b && matches!(test_bytes[1], CSI | DCS | OSC | APC | PM | SOS) {
1732 continue;
1733 }
1734 if test_bytes[1] == 0x1b && matches!(test_bytes[2], CSI | DCS | OSC | APC | PM | SOS) {
1735 continue;
1736 }
1737
1738 let mut parser = VTPushParser::<VT_PARSER_INTEREST_ALL>::new_with();
1739 parser.feed_with(test_bytes, |event: VTEvent| {
1740 let mut chunk = [0_u8; 3];
1741 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1742 panic!("Failed to encode event {test_bytes:X?} -> {event:?}")
1743 });
1744 bytes.extend_from_slice(&chunk[..b]);
1745 });
1746 if let Some(event) = parser.idle() {
1747 let mut chunk = [0_u8; 3];
1748 let b = event.encode(&mut chunk).unwrap_or_else(|_| {
1749 panic!("Failed to encode event {test_bytes:X?} -> {event:?}")
1750 });
1751 bytes.extend_from_slice(&chunk[..b]);
1752 }
1753
1754 if bytes.len() != 3 || bytes != test_bytes {
1755 eprintln!("Failed to parse:");
1756 parser.feed_with(test_bytes, |event: VTEvent| {
1757 eprintln!("{event:?}");
1758 });
1759 if let Some(event) = parser.idle() {
1760 eprintln!("{event:?}");
1761 }
1762 assert_eq!(bytes, test_bytes, "{test_bytes:X?} -> {bytes:X?}");
1763 }
1764 }
1765 }
1766}