1use serde::{Deserialize, Serialize};
42use std::fmt;
43use std::time::{Duration, Instant};
44
45pub const DEFAULT_MAX_BUFFER: usize = 65_536;
47
48pub const REGEX_LOOKBACK: usize = 32;
51
52pub trait Framer: Send {
54 fn push(&mut self, data: &[u8], now: Instant, out: &mut Vec<Vec<u8>>);
56 fn poll(&mut self, _now: Instant, _out: &mut Vec<Vec<u8>>) {}
58 fn deadline(&self) -> Option<Instant> {
60 None
61 }
62 fn flush(&mut self) -> Option<Vec<u8>>;
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct ConfigError(pub String);
69
70impl fmt::Display for ConfigError {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 write!(f, "invalid parser options: {}", self.0)
73 }
74}
75
76impl std::error::Error for ConfigError {}
77
78fn bad<T>(msg: &str) -> Result<T, ConfigError> {
79 Err(ConfigError(msg.into()))
80}
81
82#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
84#[serde(untagged)]
85pub enum ByteSeq {
86 Text(String),
87 Bytes(Vec<u8>),
88}
89
90impl ByteSeq {
91 pub fn to_vec(&self) -> Vec<u8> {
92 match self {
93 ByteSeq::Text(s) => s.as_bytes().to_vec(),
94 ByteSeq::Bytes(b) => b.clone(),
95 }
96 }
97}
98
99impl From<&str> for ByteSeq {
100 fn from(s: &str) -> Self {
101 ByteSeq::Text(s.into())
102 }
103}
104
105impl From<&[u8]> for ByteSeq {
106 fn from(b: &[u8]) -> Self {
107 ByteSeq::Bytes(b.to_vec())
108 }
109}
110
111fn non_empty(seq: &ByteSeq, name: &str) -> Result<Vec<u8>, ConfigError> {
112 let v = seq.to_vec();
113 if v.is_empty() {
114 return bad(&format!("\"{name}\" has a 0 length"));
115 }
116 Ok(v)
117}
118
119fn max_buf(v: Option<usize>) -> Result<usize, ConfigError> {
120 match v {
121 Some(0) => bad("\"maxBufferSize\" must be greater than 0"),
122 Some(n) => Ok(n),
123 None => Ok(DEFAULT_MAX_BUFFER),
124 }
125}
126
127fn find(hay: &[u8], needle: &[u8], from: usize) -> Option<usize> {
128 if from > hay.len() || needle.len() > hay.len() - from {
129 return None;
130 }
131 hay[from..]
132 .windows(needle.len())
133 .position(|w| w == needle)
134 .map(|p| p + from)
135}
136
137fn emit(out: &mut Vec<Vec<u8>>, frame: &[u8]) {
138 if !frame.is_empty() {
139 out.push(frame.to_vec());
140 }
141}
142
143fn take_flush(buf: &mut Vec<u8>) -> Option<Vec<u8>> {
144 let rest = std::mem::take(buf);
145 (!rest.is_empty()).then_some(rest)
146}
147
148#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
150#[serde(
151 tag = "type",
152 rename_all = "camelCase",
153 rename_all_fields = "camelCase",
154 deny_unknown_fields
155)]
156pub enum FramerConfig {
157 Delimiter {
159 delimiter: ByteSeq,
160 #[serde(default)]
161 include_delimiter: bool,
162 #[serde(default)]
163 max_buffer_size: Option<usize>,
164 },
165 Readline {
167 #[serde(default)]
168 delimiter: Option<ByteSeq>,
169 #[serde(default)]
170 include_delimiter: bool,
171 #[serde(default)]
172 max_buffer_size: Option<usize>,
173 #[serde(default)]
175 encoding: Option<String>,
176 },
177 ByteLength { length: usize },
179 InterByteTimeout {
181 #[serde(alias = "interval")]
182 interval_ms: u64,
183 #[serde(default)]
184 max_buffer_size: Option<usize>,
185 },
186 PacketLength {
188 #[serde(default)]
190 delimiter: Option<OneOrMany>,
191 #[serde(default)]
192 delimiter_bytes: Option<usize>,
193 #[serde(default)]
194 packet_overhead: Option<usize>,
195 #[serde(default)]
196 length_bytes: Option<usize>,
197 #[serde(default)]
198 length_offset: Option<usize>,
199 #[serde(default)]
200 max_len: Option<usize>,
201 #[serde(default)]
202 max_buffer_size: Option<usize>,
203 },
204 Ready { delimiter: ByteSeq },
206 Regex {
208 regex: String,
209 #[serde(default)]
210 max_buffer_size: Option<usize>,
211 #[serde(default)]
213 encoding: Option<String>,
214 },
215 StartEnd {
217 start_delimiter: ByteSeq,
218 end_delimiter: ByteSeq,
219 #[serde(default)]
220 include_start_delimiter: bool,
221 #[serde(default)]
222 include_end_delimiter: bool,
223 #[serde(default)]
224 max_buffer_size: Option<usize>,
225 },
226 Slip(SlipOptions),
228 CcTalk {
230 #[serde(default, alias = "maxDelayBetweenBytesMs")]
232 max_delay_ms: Option<u64>,
233 },
234}
235
236#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
238#[serde(untagged)]
239pub enum OneOrMany {
240 One(u32),
241 Many(Vec<u32>),
242}
243
244impl FramerConfig {
245 pub fn build(&self) -> Result<Box<dyn Framer>, ConfigError> {
247 Ok(match self {
248 FramerConfig::Delimiter {
249 delimiter,
250 include_delimiter,
251 max_buffer_size,
252 } => Box::new(DelimiterFramer::new(
253 non_empty(delimiter, "delimiter")?,
254 *include_delimiter,
255 max_buf(*max_buffer_size)?,
256 )),
257 FramerConfig::Readline {
258 delimiter,
259 include_delimiter,
260 max_buffer_size,
261 encoding: _,
262 } => {
263 let delimiter = match delimiter {
264 Some(d) => non_empty(d, "delimiter")?,
265 None => b"\n".to_vec(),
266 };
267 Box::new(DelimiterFramer::new(
268 delimiter,
269 *include_delimiter,
270 max_buf(*max_buffer_size)?,
271 ))
272 }
273 FramerConfig::ByteLength { length } => {
274 if *length == 0 {
275 return bad("\"length\" must be greater than 0");
276 }
277 Box::new(ByteLengthFramer {
278 length: *length,
279 buf: Vec::new(),
280 })
281 }
282 FramerConfig::InterByteTimeout {
283 interval_ms,
284 max_buffer_size,
285 } => {
286 if *interval_ms == 0 {
287 return bad("\"intervalMs\" must be greater than 0");
288 }
289 Box::new(InterByteTimeoutFramer {
290 interval: Duration::from_millis(*interval_ms),
291 max: max_buf(*max_buffer_size)?,
292 buf: Vec::new(),
293 deadline: None,
294 })
295 }
296 FramerConfig::PacketLength {
297 delimiter,
298 delimiter_bytes,
299 packet_overhead,
300 length_bytes,
301 length_offset,
302 max_len,
303 max_buffer_size,
304 } => {
305 let p = PacketLengthFramer {
306 delimiters: match delimiter {
307 None => vec![0xaa],
308 Some(OneOrMany::One(d)) => vec![*d],
309 Some(OneOrMany::Many(d)) => d.clone(),
310 },
311 delimiter_bytes: delimiter_bytes.unwrap_or(1),
312 packet_overhead: packet_overhead.unwrap_or(2),
313 length_bytes: length_bytes.unwrap_or(1),
314 length_offset: length_offset.unwrap_or(1),
315 max_len: max_len.unwrap_or(0xff),
316 max: max_buf(*max_buffer_size)?,
317 buf: Vec::new(),
318 started: false,
319 };
320 if p.delimiters.is_empty() || !(1..=4).contains(&p.delimiter_bytes) {
321 return bad("\"delimiter\" needs 1..=4 \"delimiterBytes\"");
322 }
323 if !(1..=8).contains(&p.length_bytes) {
324 return bad("\"lengthBytes\" must be 1..=8");
325 }
326 if p.length_offset < p.delimiter_bytes {
327 return bad("\"lengthOffset\" overlaps the delimiter");
328 }
329 if p.length_offset
331 .checked_add(p.length_bytes)
332 .is_none_or(|end| end > p.max)
333 {
334 return bad("\"lengthOffset\" + \"lengthBytes\" exceeds \"maxBufferSize\"");
335 }
336 Box::new(p)
337 }
338 FramerConfig::Ready { delimiter } => Box::new(ReadyFramer {
339 delimiter: non_empty(delimiter, "delimiter")?,
340 tail: Vec::new(),
341 ready: false,
342 }),
343 FramerConfig::Regex {
344 regex,
345 max_buffer_size,
346 encoding: _,
347 } => Box::new(RegexFramer {
348 regex: regex_lite::Regex::new(regex)
349 .map_err(|e| ConfigError(format!("\"regex\": {e}")))?,
350 max: max_buf(*max_buffer_size)?,
351 text: String::new(),
352 pending: Vec::new(),
353 scanned: 0,
354 full_scan: 0,
355 }),
356 FramerConfig::StartEnd {
357 start_delimiter,
358 end_delimiter,
359 include_start_delimiter,
360 include_end_delimiter,
361 max_buffer_size,
362 } => Box::new(StartEndFramer {
363 start: non_empty(start_delimiter, "startDelimiter")?,
364 end: non_empty(end_delimiter, "endDelimiter")?,
365 include_start: *include_start_delimiter,
366 include_end: *include_end_delimiter,
367 max: max_buf(*max_buffer_size)?,
368 buf: Vec::new(),
369 open: None,
370 scan_from: 0,
371 }),
372 FramerConfig::Slip(o) => Box::new(SlipDecoder::new(o.clone())),
373 FramerConfig::CcTalk { max_delay_ms } => Box::new(CcTalkFramer {
374 max_delay: Duration::from_millis(max_delay_ms.unwrap_or(50)),
375 buf: Vec::new(),
376 last: None,
377 }),
378 })
379 }
380}
381
382struct DelimiterFramer {
384 delimiter: Vec<u8>,
385 include: bool,
386 max: usize,
387 buf: Vec<u8>,
388}
389
390impl DelimiterFramer {
391 fn new(delimiter: Vec<u8>, include: bool, max: usize) -> Self {
392 Self {
393 delimiter,
394 include,
395 max,
396 buf: Vec::new(),
397 }
398 }
399}
400
401impl Framer for DelimiterFramer {
402 fn push(&mut self, data: &[u8], _now: Instant, out: &mut Vec<Vec<u8>>) {
403 let mut from = self.buf.len().saturating_sub(self.delimiter.len() - 1);
405 self.buf.extend_from_slice(data);
406 let mut start = 0;
407 while let Some(pos) = find(&self.buf, &self.delimiter, from.max(start)) {
408 let end = pos
409 + if self.include {
410 self.delimiter.len()
411 } else {
412 0
413 };
414 emit(out, &self.buf[start..end]);
415 start = pos + self.delimiter.len();
416 from = start;
417 }
418 self.buf.drain(..start);
419 while self.buf.len() >= self.max {
421 let rest = self.buf.split_off(self.max);
422 out.push(std::mem::replace(&mut self.buf, rest));
423 }
424 }
425
426 fn flush(&mut self) -> Option<Vec<u8>> {
427 take_flush(&mut self.buf)
428 }
429}
430
431struct ByteLengthFramer {
432 length: usize,
433 buf: Vec<u8>,
434}
435
436impl Framer for ByteLengthFramer {
437 fn push(&mut self, data: &[u8], _now: Instant, out: &mut Vec<Vec<u8>>) {
438 self.buf.extend_from_slice(data);
439 let full = self.buf.len() / self.length * self.length;
440 for frame in self.buf[..full].chunks(self.length) {
441 out.push(frame.to_vec());
442 }
443 self.buf.drain(..full);
444 }
445
446 fn flush(&mut self) -> Option<Vec<u8>> {
447 take_flush(&mut self.buf)
448 }
449}
450
451struct InterByteTimeoutFramer {
452 interval: Duration,
453 max: usize,
454 buf: Vec<u8>,
455 deadline: Option<Instant>,
456}
457
458impl Framer for InterByteTimeoutFramer {
459 fn push(&mut self, data: &[u8], now: Instant, out: &mut Vec<Vec<u8>>) {
460 self.poll(now, out);
462 for &b in data {
463 self.buf.push(b);
464 if self.buf.len() >= self.max {
465 out.push(std::mem::take(&mut self.buf));
466 }
467 }
468 if !data.is_empty() {
469 self.deadline = Some(now + self.interval);
470 }
471 }
472
473 fn poll(&mut self, now: Instant, out: &mut Vec<Vec<u8>>) {
474 if self.deadline.is_some_and(|d| now >= d) {
475 self.deadline = None;
476 emit(out, &std::mem::take(&mut self.buf));
477 }
478 }
479
480 fn deadline(&self) -> Option<Instant> {
481 self.deadline.filter(|_| !self.buf.is_empty())
482 }
483
484 fn flush(&mut self) -> Option<Vec<u8>> {
485 self.deadline = None;
486 take_flush(&mut self.buf)
487 }
488}
489
490struct PacketLengthFramer {
491 delimiters: Vec<u32>,
492 delimiter_bytes: usize,
493 packet_overhead: usize,
494 length_bytes: usize,
495 length_offset: usize,
496 max_len: usize,
497 max: usize,
498 buf: Vec<u8>,
499 started: bool,
500}
501
502impl Framer for PacketLengthFramer {
503 fn push(&mut self, data: &[u8], _now: Instant, out: &mut Vec<Vec<u8>>) {
504 for &b in data {
505 self.buf.push(b);
506 if !self.started {
507 if self.buf.len() > self.delimiter_bytes {
510 self.buf.remove(0);
511 }
512 if self.buf.len() == self.delimiter_bytes {
513 let v = self.buf.iter().fold(0u32, |a, &x| (a << 8) | x as u32);
514 self.started = self.delimiters.contains(&v);
515 }
516 continue;
517 }
518 let end = self.length_offset + self.length_bytes;
519 if self.buf.len() >= end {
520 let len = self.buf[self.length_offset..end]
521 .iter()
522 .rev()
523 .fold(0u64, |a, &x| (a << 8) | x as u64);
524 let total = len.saturating_add(self.packet_overhead as u64);
525 if self.buf.len() as u64 >= total || len > self.max_len as u64 {
526 out.push(std::mem::take(&mut self.buf));
527 self.started = false;
528 continue;
529 }
530 }
531 if self.buf.len() >= self.max {
532 out.push(std::mem::take(&mut self.buf));
534 self.started = false;
535 }
536 }
537 }
538
539 fn flush(&mut self) -> Option<Vec<u8>> {
540 let started = std::mem::take(&mut self.started);
541 let rest = std::mem::take(&mut self.buf);
542 (started && !rest.is_empty()).then_some(rest)
543 }
544}
545
546struct ReadyFramer {
547 delimiter: Vec<u8>,
548 tail: Vec<u8>,
549 ready: bool,
550}
551
552impl Framer for ReadyFramer {
553 fn push(&mut self, data: &[u8], _now: Instant, out: &mut Vec<Vec<u8>>) {
554 if self.ready {
555 emit(out, data);
556 return;
557 }
558 let keep = self.tail.len();
559 self.tail.extend_from_slice(data);
560 if let Some(pos) = find(&self.tail, &self.delimiter, 0) {
561 self.ready = true;
562 let rest = pos + self.delimiter.len();
563 emit(out, &self.tail[rest.max(keep)..]);
564 self.tail = Vec::new();
565 } else {
566 let cut = self.tail.len().saturating_sub(self.delimiter.len() - 1);
567 self.tail.drain(..cut);
568 }
569 }
570
571 fn flush(&mut self) -> Option<Vec<u8>> {
572 None
573 }
574}
575
576struct RegexFramer {
577 regex: regex_lite::Regex,
578 max: usize,
579 text: String,
580 pending: Vec<u8>,
582 scanned: usize,
584 full_scan: usize,
586}
587
588impl RegexFramer {
589 fn decode(&mut self, data: &[u8]) {
590 let mut bytes = std::mem::take(&mut self.pending);
591 bytes.extend_from_slice(data);
592 let mut rest: &[u8] = &bytes;
593 loop {
594 match std::str::from_utf8(rest) {
595 Ok(s) => {
596 self.text.push_str(s);
597 return;
598 }
599 Err(e) => {
600 let (ok, tail) = rest.split_at(e.valid_up_to());
601 self.text
602 .push_str(std::str::from_utf8(ok).unwrap_or_default());
603 match e.error_len() {
604 Some(n) => {
605 self.text.push('\u{FFFD}');
606 rest = &tail[n..];
607 }
608 None => {
609 self.pending = tail.to_vec();
610 return;
611 }
612 }
613 }
614 }
615 }
616 }
617}
618
619impl Framer for RegexFramer {
620 fn push(&mut self, data: &[u8], _now: Instant, out: &mut Vec<Vec<u8>>) {
621 self.decode(data);
622 let mut from = self.scanned.saturating_sub(REGEX_LOOKBACK);
628 if self.text.len() >= 2 * self.full_scan {
629 from = 0;
630 self.full_scan = self.text.len();
631 }
632 while !self.text.is_char_boundary(from) {
633 from -= 1;
634 }
635 if self.regex.find_at(&self.text, from).is_some() {
636 let mut parts: Vec<&str> = self.regex.split(&self.text).collect();
637 let last = parts.pop().unwrap_or_default().to_string();
638 for p in parts {
639 emit(out, p.as_bytes());
640 }
641 self.text = last;
642 self.full_scan = self.text.len();
643 }
644 self.scanned = self.text.len();
645 if self.text.len() >= self.max {
646 out.push(std::mem::take(&mut self.text).into_bytes());
647 self.scanned = 0;
648 self.full_scan = 0;
649 }
650 }
651
652 fn flush(&mut self) -> Option<Vec<u8>> {
653 self.scanned = 0;
654 self.full_scan = 0;
655 let mut rest = std::mem::take(&mut self.text).into_bytes();
656 rest.append(&mut self.pending);
657 (!rest.is_empty()).then_some(rest)
658 }
659}
660
661struct StartEndFramer {
662 start: Vec<u8>,
663 end: Vec<u8>,
664 include_start: bool,
665 include_end: bool,
666 max: usize,
667 buf: Vec<u8>,
668 open: Option<usize>,
670 scan_from: usize,
673}
674
675impl Framer for StartEndFramer {
676 fn push(&mut self, data: &[u8], _now: Instant, out: &mut Vec<Vec<u8>>) {
677 self.buf.extend_from_slice(data);
678 let mut consumed = 0;
679 loop {
680 let s = match self.open {
681 Some(s) => s,
682 None => {
683 let Some(s) = find(&self.buf, &self.start, self.scan_from) else {
684 let tail = self.buf.len().saturating_sub(self.start.len() - 1);
685 self.scan_from = tail.max(consumed);
686 break;
687 };
688 self.open = Some(s);
689 self.scan_from = s + self.start.len();
690 s
691 }
692 };
693 let Some(e) = find(&self.buf, &self.end, self.scan_from) else {
694 let tail = self.buf.len().saturating_sub(self.end.len() - 1);
695 self.scan_from = tail.max(s + self.start.len());
696 break;
697 };
698 let from = if self.include_start {
699 s
700 } else {
701 s + self.start.len()
702 };
703 let to = if self.include_end {
704 e + self.end.len()
705 } else {
706 e
707 };
708 emit(out, &self.buf[from..to]);
709 consumed = e + self.end.len();
710 self.open = None;
711 self.scan_from = consumed;
712 }
713 self.buf.drain(..consumed);
714 self.open = self.open.map(|s| s - consumed);
715 self.scan_from -= consumed;
716 if self.buf.len() >= self.max {
717 self.open = None;
719 self.scan_from = 0;
720 match self
722 .buf
723 .windows(self.start.len())
724 .rposition(|w| w == self.start)
725 {
726 Some(p) if p > 0 => {
727 self.buf.drain(..p);
728 }
729 _ => self.buf.clear(),
730 }
731 }
732 }
733
734 fn flush(&mut self) -> Option<Vec<u8>> {
735 self.open = None;
736 self.scan_from = 0;
737 take_flush(&mut self.buf)
738 }
739}
740
741#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
743#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
744pub struct SlipOptions {
745 #[serde(alias = "START")]
746 pub start: Option<u8>,
747 #[serde(alias = "ESC")]
748 pub esc: u8,
749 #[serde(alias = "END")]
750 pub end: u8,
751 #[serde(alias = "ESC_START")]
752 pub esc_start: Option<u8>,
753 #[serde(alias = "ESC_END")]
754 pub esc_end: u8,
755 #[serde(alias = "ESC_ESC")]
756 pub esc_esc: u8,
757}
758
759impl Default for SlipOptions {
760 fn default() -> Self {
761 Self {
762 start: None,
763 esc: 0xdb,
764 end: 0xc0,
765 esc_start: None,
766 esc_end: 0xdc,
767 esc_esc: 0xdd,
768 }
769 }
770}
771
772pub fn slip_encode(data: &[u8], o: &SlipOptions, bluetooth_quirk: bool) -> Vec<u8> {
774 if bluetooth_quirk && data.is_empty() {
775 return Vec::new();
776 }
777 let mut v = Vec::with_capacity(data.len() * 2 + 3);
778 if bluetooth_quirk {
779 v.push(o.end);
780 }
781 if let Some(s) = o.start {
782 v.push(s);
783 }
784 for &b in data {
785 match b {
786 b if Some(b) == o.start && o.esc_start.is_some() => {
787 v.extend([o.esc, o.esc_start.unwrap_or_default()])
788 }
789 b if b == o.end => v.extend([o.esc, o.esc_end]),
790 b if b == o.esc => v.extend([o.esc, o.esc_esc]),
791 b => v.push(b),
792 }
793 }
794 v.push(o.end);
795 v
796}
797
798pub struct SlipDecoder {
800 o: SlipOptions,
801 buf: Vec<u8>,
802 escape: bool,
803 started: bool,
804}
805
806impl SlipDecoder {
807 pub fn new(o: SlipOptions) -> Self {
808 Self {
809 o,
810 buf: Vec::new(),
811 escape: false,
812 started: false,
813 }
814 }
815}
816
817impl Framer for SlipDecoder {
818 fn push(&mut self, data: &[u8], _now: Instant, out: &mut Vec<Vec<u8>>) {
819 let o = &self.o;
820 for &raw in data {
821 let mut byte = raw;
822 if Some(byte) == o.start {
823 self.started = true;
824 continue;
825 }
826 if o.start.is_none() {
827 self.started = true;
828 }
829 if self.escape {
830 if o.start.is_some() && Some(byte) == o.esc_start {
831 byte = o.start.unwrap_or_default();
832 } else if byte == o.esc_esc {
833 byte = o.esc;
834 } else if byte == o.esc_end {
835 byte = o.end;
836 } else {
837 emit(out, &std::mem::take(&mut self.buf));
839 }
840 } else if byte == o.esc {
841 self.escape = true;
842 continue;
843 } else if byte == o.end {
844 emit(out, &std::mem::take(&mut self.buf));
845 self.escape = false;
846 self.started = false;
847 continue;
848 }
849 self.escape = false;
850 if self.started {
851 self.buf.push(byte);
852 if self.buf.len() >= DEFAULT_MAX_BUFFER {
853 out.push(std::mem::take(&mut self.buf));
854 }
855 }
856 }
857 }
858
859 fn flush(&mut self) -> Option<Vec<u8>> {
860 self.escape = false;
861 self.started = false;
862 take_flush(&mut self.buf)
863 }
864}
865
866struct CcTalkFramer {
867 max_delay: Duration,
868 buf: Vec<u8>,
869 last: Option<Instant>,
870}
871
872impl Framer for CcTalkFramer {
873 fn push(&mut self, data: &[u8], now: Instant, out: &mut Vec<Vec<u8>>) {
874 if !self.max_delay.is_zero() {
875 if self
876 .last
877 .is_some_and(|t| now.duration_since(t) > self.max_delay)
878 {
879 self.buf.clear();
880 }
881 self.last = Some(now);
882 }
883 self.buf.extend_from_slice(data);
884 while self.buf.len() > 1 && self.buf.len() >= self.buf[1] as usize + 5 {
885 let n = self.buf[1] as usize + 5;
886 out.push(self.buf.drain(..n).collect());
887 }
888 }
889
890 fn flush(&mut self) -> Option<Vec<u8>> {
891 self.buf.clear();
893 None
894 }
895}
896
897#[cfg(test)]
898mod tests;