Skip to main content

android_usb_serial/
xonxoff.rs

1//! Software XON/XOFF filter for RX paths.
2
3use crate::config::{CHAR_XOFF, CHAR_XON};
4
5#[derive(Debug, Clone, Default)]
6pub struct XonXoffFilter {
7    pub enabled: bool,
8    pub paused: bool,
9}
10
11impl XonXoffFilter {
12    pub fn new(enabled: bool) -> Self {
13        Self {
14            enabled,
15            paused: false,
16        }
17    }
18
19    /// Strip inline XON/XOFF control bytes (matches Java `XonXoffFilter`).
20    pub fn filter(&mut self, input: &[u8]) -> Vec<u8> {
21        if !self.enabled {
22            return input.to_vec();
23        }
24        let ctrl_count = input
25            .iter()
26            .filter(|&&b| b == CHAR_XON || b == CHAR_XOFF)
27            .count();
28        if ctrl_count == 0 {
29            return input.to_vec();
30        }
31        let mut out = Vec::with_capacity(input.len().saturating_sub(ctrl_count));
32        for &b in input {
33            match b {
34                CHAR_XON => self.paused = false,
35                CHAR_XOFF => self.paused = true,
36                _ => out.push(b),
37            }
38        }
39        out
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn filters_between_xoff_and_xon() {
49        let mut f = XonXoffFilter::new(true);
50        let out = f.filter(&[b'a', CHAR_XOFF, b'b', CHAR_XON, b'c']);
51        assert_eq!(out, vec![b'a', b'b', b'c']);
52    }
53}