1use std::io;
7
8pub const DEFAULT_CAPACITY: usize = 16 * 1024;
10
11#[derive(Debug)]
17pub struct PtyBuffer {
18 data: Box<[u8]>,
20 read_pos: usize,
22 write_pos: usize,
24}
25
26impl PtyBuffer {
27 #[must_use]
29 pub fn new(capacity: usize) -> Self {
30 Self {
31 data: vec![0u8; capacity].into_boxed_slice(),
32 read_pos: 0,
33 write_pos: 0,
34 }
35 }
36
37 #[must_use]
39 pub fn with_default_capacity() -> Self {
40 Self::new(DEFAULT_CAPACITY)
41 }
42
43 #[must_use]
45 pub const fn capacity(&self) -> usize {
46 self.data.len()
47 }
48
49 #[must_use]
51 pub const fn len(&self) -> usize {
52 if self.write_pos >= self.read_pos {
53 self.write_pos - self.read_pos
54 } else {
55 self.capacity() - self.read_pos + self.write_pos
56 }
57 }
58
59 #[must_use]
61 pub const fn is_empty(&self) -> bool {
62 self.read_pos == self.write_pos
63 }
64
65 #[must_use]
67 pub const fn available(&self) -> usize {
68 self.capacity() - self.len() - 1
70 }
71
72 #[must_use]
74 pub const fn is_full(&self) -> bool {
75 self.available() == 0
76 }
77
78 #[must_use]
83 pub fn readable(&self) -> &[u8] {
84 if self.write_pos >= self.read_pos {
85 &self.data[self.read_pos..self.write_pos]
86 } else {
87 &self.data[self.read_pos..]
89 }
90 }
91
92 #[must_use]
97 pub fn writable(&mut self) -> &mut [u8] {
98 let cap = self.capacity();
99 if self.write_pos >= self.read_pos {
100 let end = if self.read_pos == 0 { cap - 1 } else { cap };
102 &mut self.data[self.write_pos..end]
103 } else {
104 &mut self.data[self.write_pos..self.read_pos - 1]
106 }
107 }
108
109 pub fn consume(&mut self, count: usize) {
115 assert!(count <= self.len(), "cannot consume more than available");
116 self.read_pos = (self.read_pos + count) % self.capacity();
117 }
118
119 pub fn produce(&mut self, count: usize) {
125 assert!(
126 count <= self.available(),
127 "cannot produce more than available"
128 );
129 self.write_pos = (self.write_pos + count) % self.capacity();
130 }
131
132 pub const fn clear(&mut self) {
134 self.read_pos = 0;
135 self.write_pos = 0;
136 }
137
138 pub fn read(&mut self, buf: &mut [u8]) -> usize {
142 let mut total = 0;
143
144 while total < buf.len() && !self.is_empty() {
145 let readable = self.readable();
146 let to_copy = readable.len().min(buf.len() - total);
147 buf[total..total + to_copy].copy_from_slice(&readable[..to_copy]);
148 self.consume(to_copy);
149 total += to_copy;
150 }
151
152 total
153 }
154
155 pub fn write(&mut self, data: &[u8]) -> usize {
159 let mut total = 0;
160
161 while total < data.len() && !self.is_full() {
162 let writable = self.writable();
163 let to_copy = writable.len().min(data.len() - total);
164 writable[..to_copy].copy_from_slice(&data[total..total + to_copy]);
165 self.produce(to_copy);
166 total += to_copy;
167 }
168
169 total
170 }
171}
172
173impl Default for PtyBuffer {
174 fn default() -> Self {
175 Self::with_default_capacity()
176 }
177}
178
179impl io::Read for PtyBuffer {
180 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
181 Ok(self.read(buf))
182 }
183}
184
185impl io::Write for PtyBuffer {
186 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
187 Ok(self.write(buf))
188 }
189
190 fn flush(&mut self) -> io::Result<()> {
191 Ok(())
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn new_buffer_is_empty() {
201 let buf = PtyBuffer::new(1024);
202 assert!(buf.is_empty());
203 assert_eq!(buf.len(), 0);
204 assert_eq!(buf.capacity(), 1024);
205 }
206
207 #[test]
208 fn write_and_read() {
209 let mut buf = PtyBuffer::new(1024);
210 let data = b"hello world";
211
212 let written = buf.write(data);
213 assert_eq!(written, data.len());
214 assert_eq!(buf.len(), data.len());
215
216 let mut output = [0u8; 32];
217 let read = buf.read(&mut output);
218 assert_eq!(read, data.len());
219 assert_eq!(&output[..read], data);
220 assert!(buf.is_empty());
221 }
222
223 #[test]
224 fn wrap_around() {
225 let mut buf = PtyBuffer::new(16);
226
227 let data1 = b"12345678901";
229 buf.write(data1);
230
231 let mut tmp = [0u8; 8];
233 buf.read(&mut tmp);
234
235 let data2 = b"abcdefgh";
237 let written = buf.write(data2);
238 assert!(written > 0);
239
240 let mut output = [0u8; 32];
242 let total = buf.read(&mut output);
243 assert!(!output[..total].is_empty());
244 }
245
246 #[test]
247 fn clear_resets_buffer() {
248 let mut buf = PtyBuffer::new(1024);
249 buf.write(b"test data");
250 assert!(!buf.is_empty());
251
252 buf.clear();
253 assert!(buf.is_empty());
254 assert_eq!(buf.len(), 0);
255 }
256}