1use alloc::vec::Vec;
10use core::mem::MaybeUninit;
11
12pub trait Buffer {
14 unsafe fn unwritten(&mut self) -> &mut [MaybeUninit<u8>];
39
40 unsafe fn extend_written(&mut self, len: usize);
45}
46
47impl Buffer for Vec<u8> {
48 unsafe fn unwritten(&mut self) -> &mut [MaybeUninit<u8>] {
49 self.spare_capacity_mut()
50 }
51
52 unsafe fn extend_written(&mut self, len: usize) {
53 unsafe {
55 self.set_len(self.len() + len);
56 }
57 }
58}
59
60impl Buffer for Buf<'_> {
61 unsafe fn unwritten(&mut self) -> &mut [MaybeUninit<u8>] {
62 &mut self.buf[*self.filled..]
63 }
64
65 unsafe fn extend_written(&mut self, len: usize) {
66 *self.filled += len;
67 }
68}
69
70#[cfg(feature = "std")]
71impl Buffer for std::io::Cursor<&mut [u8]> {
72 unsafe fn unwritten(&mut self) -> &mut [MaybeUninit<u8>] {
73 let pos = core::cmp::min(self.position(), self.get_ref().len() as u64) as usize;
74 let slice = self.get_mut();
75 let slice = &mut slice[pos..];
76 unsafe { core::slice::from_raw_parts_mut(slice.as_mut_ptr().cast(), slice.len()) }
78 }
79
80 unsafe fn extend_written(&mut self, len: usize) {
81 self.set_position(self.position() + len as u64);
82 }
83}
84
85pub struct Buf<'a> {
87 buf: &'a mut [MaybeUninit<u8>],
88 filled: &'a mut usize,
89}
90
91impl Buf<'_> {
92 #[inline(always)]
94 pub fn remaining(&self) -> usize {
95 self.buf.len() - *self.filled
96 }
97
98 #[inline(always)]
100 pub fn len(&self) -> usize {
101 *self.filled
102 }
103
104 #[inline(always)]
107 pub fn push(&mut self, b: u8) {
108 self.buf[*self.filled] = MaybeUninit::new(b);
109 *self.filled += 1;
110 }
111
112 #[inline(always)]
115 pub fn append(&mut self, buf: &[u8]) {
116 assert!(buf.len() <= self.remaining());
117 unsafe {
119 self.buf
120 .as_mut_ptr()
121 .add(*self.filled)
122 .cast::<u8>()
123 .copy_from_nonoverlapping(buf.as_ptr(), buf.len());
124 }
125 *self.filled += buf.len();
126 }
127
128 #[inline(always)]
131 pub fn fill(&mut self, val: u8, len: usize) {
132 self.buf[*self.filled..][..len].fill(MaybeUninit::new(val));
133 *self.filled += len;
134 }
135
136 #[track_caller]
143 pub fn write_split<R>(&mut self, split_at: usize, f: impl FnOnce(Buf<'_>, Buf<'_>) -> R) -> R {
144 let (left, right) = self.buf[*self.filled..].split_at_mut(split_at);
145 let mut left_filled = 0;
146 let mut right_filled = 0;
147 let r = f(
148 Buf {
149 buf: left,
150 filled: &mut left_filled,
151 },
152 Buf {
153 buf: right,
154 filled: &mut right_filled,
155 },
156 );
157 assert!(left_filled <= left.len());
158 assert!(right_filled <= right.len());
159 *self.filled += left_filled;
160 if right_filled > 0 {
161 let to_zero = left.len() - left_filled;
162 self.fill(0, to_zero);
163 *self.filled += right_filled;
164 }
165 r
166 }
167}
168
169pub fn write_with<T, F, R>(buffer: &mut T, f: F) -> R
172where
173 T: Buffer + ?Sized,
174 F: FnOnce(Buf<'_>) -> R,
175{
176 let mut filled = 0;
177 let buf = unsafe { buffer.unwritten() };
179
180 let r = f(Buf {
181 buf,
182 filled: &mut filled,
183 });
184 unsafe {
186 buffer.extend_written(filled);
187 }
188 r
189}
190
191#[cfg(test)]
192mod tests {
193 use super::write_with;
194 use alloc::vec;
195
196 #[test]
197 #[should_panic]
198 fn test_append_vec_panic() {
199 let mut v = vec![1, 2, 3];
200 write_with(&mut v, |mut buf| {
201 buf.append(&vec![0; buf.remaining() + 1]);
202 });
203 }
204
205 #[test]
206 fn test_append_vec() {
207 let mut v = vec![1, 2, 3, 4];
208 v.reserve(3);
209
210 write_with(&mut v, |mut buf| {
211 buf.append(&[5, 6]);
212 buf.push(7);
213 });
214 assert_eq!(&v, &[1, 2, 3, 4, 5, 6, 7]);
215 }
216
217 #[test]
218 #[cfg(feature = "std")]
219 fn test_cursor_multiple_writes() {
220 let mut backing = [0u8; 8];
221 let mut cursor = std::io::Cursor::new(&mut backing[..]);
222
223 write_with(&mut cursor, |mut buf| {
225 buf.append(&[1, 2, 3]);
226 });
227
228 write_with(&mut cursor, |mut buf| {
230 buf.append(&[4, 5]);
231 });
232
233 assert_eq!(cursor.position(), 5);
234 assert_eq!(&backing[..5], &[1, 2, 3, 4, 5]);
235 }
236
237 #[test]
238 #[cfg(feature = "std")]
239 fn test_cursor_position_beyond_slice() {
240 let mut backing = [0u8; 4];
241 let mut cursor = std::io::Cursor::new(&mut backing[..]);
242 cursor.set_position(100); write_with(&mut cursor, |buf| {
246 assert_eq!(buf.remaining(), 0);
247 });
248 }
249}