Skip to main content

arcbox_virtio_console/
io.rs

1//! Console I/O backends — the in-process trait plus stdio and buffer impls.
2//!
3//! Real terminal (`pty`) and Unix socket (`socket`) backends live in
4//! sibling modules so the device file does not have to know about them.
5
6use std::collections::VecDeque;
7use std::io::{Read, Write};
8
9/// Console I/O handler trait.
10pub trait ConsoleIo: Send + Sync {
11    /// Reads data from the console (host -> guest).
12    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>;
13
14    /// Writes data to the console (guest -> host).
15    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize>;
16
17    /// Flushes pending output.
18    fn flush(&mut self) -> std::io::Result<()>;
19}
20
21/// Standard I/O console handler.
22pub struct StdioConsole;
23
24impl ConsoleIo for StdioConsole {
25    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
26        std::io::stdin().read(buf)
27    }
28
29    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
30        std::io::stdout().write(buf)
31    }
32
33    fn flush(&mut self) -> std::io::Result<()> {
34        std::io::stdout().flush()
35    }
36}
37
38/// Buffer-based console for testing.
39pub struct BufferConsole {
40    /// Input data (to be read by guest).
41    pub input: VecDeque<u8>,
42    /// Output data (written by guest).
43    pub output: Vec<u8>,
44}
45
46impl BufferConsole {
47    /// Creates a new buffer console.
48    #[must_use]
49    pub const fn new() -> Self {
50        Self {
51            input: VecDeque::new(),
52            output: Vec::new(),
53        }
54    }
55
56    /// Pushes data to the input buffer.
57    pub fn push_input(&mut self, data: &[u8]) {
58        self.input.extend(data);
59    }
60
61    /// Takes all output data.
62    pub fn take_output(&mut self) -> Vec<u8> {
63        std::mem::take(&mut self.output)
64    }
65}
66
67impl Default for BufferConsole {
68    fn default() -> Self {
69        Self::new()
70    }
71}
72
73impl ConsoleIo for BufferConsole {
74    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
75        let len = buf.len().min(self.input.len());
76        for (i, byte) in self.input.drain(..len).enumerate() {
77            buf[i] = byte;
78        }
79        Ok(len)
80    }
81
82    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
83        self.output.extend_from_slice(buf);
84        Ok(buf.len())
85    }
86
87    fn flush(&mut self) -> std::io::Result<()> {
88        Ok(())
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn test_buffer_console() {
98        let mut buffer = BufferConsole::new();
99
100        buffer.push_input(b"Hello");
101
102        let mut buf = [0u8; 10];
103        let n = buffer.read(&mut buf).unwrap();
104        assert_eq!(n, 5);
105        assert_eq!(&buf[..n], b"Hello");
106
107        buffer.write(b"World").unwrap();
108        let output = buffer.take_output();
109        assert_eq!(&output, b"World");
110    }
111
112    #[test]
113    fn test_buffer_console_empty_read() {
114        let mut buffer = BufferConsole::new();
115
116        let mut buf = [0u8; 10];
117        let n = buffer.read(&mut buf).unwrap();
118        assert_eq!(n, 0);
119    }
120
121    #[test]
122    fn test_buffer_console_partial_read() {
123        let mut buffer = BufferConsole::new();
124        buffer.push_input(b"Hello, World!");
125
126        let mut buf = [0u8; 5];
127        let n = buffer.read(&mut buf).unwrap();
128        assert_eq!(n, 5);
129        assert_eq!(&buf, b"Hello");
130
131        let mut buf2 = [0u8; 10];
132        let n2 = buffer.read(&mut buf2).unwrap();
133        assert_eq!(n2, 8);
134        assert_eq!(&buf2[..n2], b", World!");
135    }
136
137    #[test]
138    fn test_buffer_console_multiple_writes() {
139        let mut buffer = BufferConsole::new();
140
141        buffer.write(b"Hello").unwrap();
142        buffer.write(b" ").unwrap();
143        buffer.write(b"World").unwrap();
144
145        let output = buffer.take_output();
146        assert_eq!(&output, b"Hello World");
147    }
148
149    #[test]
150    fn test_buffer_console_flush() {
151        let mut buffer = BufferConsole::new();
152        assert!(buffer.flush().is_ok());
153    }
154
155    #[test]
156    fn test_buffer_console_default() {
157        let buffer = BufferConsole::default();
158        assert!(buffer.input.is_empty());
159        assert!(buffer.output.is_empty());
160    }
161}