1 #![unstable(feature = "read_buf", issue = "78485")] 2 3 #[cfg(test)] 4 mod tests; 5 6 use crate::fmt::{self, Debug, Formatter}; 7 use crate::io::{Result, Write}; 8 use crate::mem::{self, MaybeUninit}; 9 use crate::{cmp, ptr}; 10 11 /// A borrowed byte buffer which is incrementally filled and initialized. 12 /// 13 /// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the 14 /// buffer that has been logically filled with data, a region that has been initialized at some point but not yet 15 /// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a 16 /// subset of the initialized region. 17 /// 18 /// In summary, the contents of the buffer can be visualized as: 19 /// ```not_rust 20 /// [ capacity ] 21 /// [ filled | unfilled ] 22 /// [ initialized | uninitialized ] 23 /// ``` 24 /// 25 /// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference 26 /// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be 27 /// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor 28 /// has write-only access to the unfilled portion of the buffer (you can think of it as a 29 /// write-only iterator). 30 /// 31 /// The lifetime `'data` is a bound on the lifetime of the underlying data. 32 pub struct BorrowedBuf<'data> { 33 /// The buffer's underlying data. 34 buf: &'data mut [MaybeUninit<u8>], 35 /// The length of `self.buf` which is known to be filled. 36 filled: usize, 37 /// The length of `self.buf` which is known to be initialized. 38 init: usize, 39 } 40 41 impl Debug for BorrowedBuf<'_> { fmt(&self, f: &mut Formatter<'_>) -> fmt::Result42 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 43 f.debug_struct("BorrowedBuf") 44 .field("init", &self.init) 45 .field("filled", &self.filled) 46 .field("capacity", &self.capacity()) 47 .finish() 48 } 49 } 50 51 /// Create a new `BorrowedBuf` from a fully initialized slice. 52 impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> { 53 #[inline] from(slice: &'data mut [u8]) -> BorrowedBuf<'data>54 fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> { 55 let len = slice.len(); 56 57 BorrowedBuf { 58 // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf 59 buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() }, 60 filled: 0, 61 init: len, 62 } 63 } 64 } 65 66 /// Create a new `BorrowedBuf` from an uninitialized buffer. 67 /// 68 /// Use `set_init` if part of the buffer is known to be already initialized. 69 impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuf<'data> { 70 #[inline] from(buf: &'data mut [MaybeUninit<u8>]) -> BorrowedBuf<'data>71 fn from(buf: &'data mut [MaybeUninit<u8>]) -> BorrowedBuf<'data> { 72 BorrowedBuf { buf, filled: 0, init: 0 } 73 } 74 } 75 76 impl<'data> BorrowedBuf<'data> { 77 /// Returns the total capacity of the buffer. 78 #[inline] capacity(&self) -> usize79 pub fn capacity(&self) -> usize { 80 self.buf.len() 81 } 82 83 /// Returns the length of the filled part of the buffer. 84 #[inline] len(&self) -> usize85 pub fn len(&self) -> usize { 86 self.filled 87 } 88 89 /// Returns the length of the initialized part of the buffer. 90 #[inline] init_len(&self) -> usize91 pub fn init_len(&self) -> usize { 92 self.init 93 } 94 95 /// Returns a shared reference to the filled portion of the buffer. 96 #[inline] filled(&self) -> &[u8]97 pub fn filled(&self) -> &[u8] { 98 // SAFETY: We only slice the filled part of the buffer, which is always valid 99 unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) } 100 } 101 102 /// Returns a cursor over the unfilled part of the buffer. 103 #[inline] unfilled<'this>(&'this mut self) -> BorrowedCursor<'this>104 pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> { 105 BorrowedCursor { 106 start: self.filled, 107 // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its 108 // lifetime covariantly is safe. 109 buf: unsafe { 110 mem::transmute::<&'this mut BorrowedBuf<'data>, &'this mut BorrowedBuf<'this>>(self) 111 }, 112 } 113 } 114 115 /// Clears the buffer, resetting the filled region to empty. 116 /// 117 /// The number of initialized bytes is not changed, and the contents of the buffer are not modified. 118 #[inline] clear(&mut self) -> &mut Self119 pub fn clear(&mut self) -> &mut Self { 120 self.filled = 0; 121 self 122 } 123 124 /// Asserts that the first `n` bytes of the buffer are initialized. 125 /// 126 /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer 127 /// bytes than are already known to be initialized. 128 /// 129 /// # Safety 130 /// 131 /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized. 132 #[inline] set_init(&mut self, n: usize) -> &mut Self133 pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { 134 self.init = cmp::max(self.init, n); 135 self 136 } 137 } 138 139 /// A writeable view of the unfilled portion of a [`BorrowedBuf`](BorrowedBuf). 140 /// 141 /// Provides access to the initialized and uninitialized parts of the underlying `BorrowedBuf`. 142 /// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or 143 /// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the 144 /// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform 145 /// the cursor how many bytes have been written. 146 /// 147 /// Once data is written to the cursor, it becomes part of the filled portion of the underlying 148 /// `BorrowedBuf` and can no longer be accessed or re-written by the cursor. I.e., the cursor tracks 149 /// the unfilled part of the underlying `BorrowedBuf`. 150 /// 151 /// The lifetime `'a` is a bound on the lifetime of the underlying buffer (which means it is a bound 152 /// on the data in that buffer by transitivity). 153 #[derive(Debug)] 154 pub struct BorrowedCursor<'a> { 155 /// The underlying buffer. 156 // Safety invariant: we treat the type of buf as covariant in the lifetime of `BorrowedBuf` when 157 // we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into 158 // it, so don't do that! 159 buf: &'a mut BorrowedBuf<'a>, 160 /// The length of the filled portion of the underlying buffer at the time of the cursor's 161 /// creation. 162 start: usize, 163 } 164 165 impl<'a> BorrowedCursor<'a> { 166 /// Reborrow this cursor by cloning it with a smaller lifetime. 167 /// 168 /// Since a cursor maintains unique access to its underlying buffer, the borrowed cursor is 169 /// not accessible while the new cursor exists. 170 #[inline] reborrow<'this>(&'this mut self) -> BorrowedCursor<'this>171 pub fn reborrow<'this>(&'this mut self) -> BorrowedCursor<'this> { 172 BorrowedCursor { 173 // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its 174 // lifetime covariantly is safe. 175 buf: unsafe { 176 mem::transmute::<&'this mut BorrowedBuf<'a>, &'this mut BorrowedBuf<'this>>( 177 self.buf, 178 ) 179 }, 180 start: self.start, 181 } 182 } 183 184 /// Returns the available space in the cursor. 185 #[inline] capacity(&self) -> usize186 pub fn capacity(&self) -> usize { 187 self.buf.capacity() - self.buf.filled 188 } 189 190 /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`. 191 /// 192 /// Note that if this cursor is a reborrowed clone of another, then the count returned is the 193 /// count written via either cursor, not the count since the cursor was reborrowed. 194 #[inline] written(&self) -> usize195 pub fn written(&self) -> usize { 196 self.buf.filled - self.start 197 } 198 199 /// Returns a shared reference to the initialized portion of the cursor. 200 #[inline] init_ref(&self) -> &[u8]201 pub fn init_ref(&self) -> &[u8] { 202 // SAFETY: We only slice the initialized part of the buffer, which is always valid 203 unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.buf[self.buf.filled..self.buf.init]) } 204 } 205 206 /// Returns a mutable reference to the initialized portion of the cursor. 207 #[inline] init_mut(&mut self) -> &mut [u8]208 pub fn init_mut(&mut self) -> &mut [u8] { 209 // SAFETY: We only slice the initialized part of the buffer, which is always valid 210 unsafe { 211 MaybeUninit::slice_assume_init_mut(&mut self.buf.buf[self.buf.filled..self.buf.init]) 212 } 213 } 214 215 /// Returns a mutable reference to the uninitialized part of the cursor. 216 /// 217 /// It is safe to uninitialize any of these bytes. 218 #[inline] uninit_mut(&mut self) -> &mut [MaybeUninit<u8>]219 pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] { 220 &mut self.buf.buf[self.buf.init..] 221 } 222 223 /// Returns a mutable reference to the whole cursor. 224 /// 225 /// # Safety 226 /// 227 /// The caller must not uninitialize any bytes in the initialized portion of the cursor. 228 #[inline] as_mut(&mut self) -> &mut [MaybeUninit<u8>]229 pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] { 230 &mut self.buf.buf[self.buf.filled..] 231 } 232 233 /// Advance the cursor by asserting that `n` bytes have been filled. 234 /// 235 /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be 236 /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements 237 /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements. 238 /// 239 /// # Safety 240 /// 241 /// The caller must ensure that the first `n` bytes of the cursor have been properly 242 /// initialised. 243 #[inline] advance(&mut self, n: usize) -> &mut Self244 pub unsafe fn advance(&mut self, n: usize) -> &mut Self { 245 self.buf.filled += n; 246 self.buf.init = cmp::max(self.buf.init, self.buf.filled); 247 self 248 } 249 250 /// Initializes all bytes in the cursor. 251 #[inline] ensure_init(&mut self) -> &mut Self252 pub fn ensure_init(&mut self) -> &mut Self { 253 let uninit = self.uninit_mut(); 254 // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation 255 // since it is comes from a slice reference. 256 unsafe { 257 ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len()); 258 } 259 self.buf.init = self.buf.capacity(); 260 261 self 262 } 263 264 /// Asserts that the first `n` unfilled bytes of the cursor are initialized. 265 /// 266 /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when 267 /// called with fewer bytes than are already known to be initialized. 268 /// 269 /// # Safety 270 /// 271 /// The caller must ensure that the first `n` bytes of the buffer have already been initialized. 272 #[inline] set_init(&mut self, n: usize) -> &mut Self273 pub unsafe fn set_init(&mut self, n: usize) -> &mut Self { 274 self.buf.init = cmp::max(self.buf.init, self.buf.filled + n); 275 self 276 } 277 278 /// Appends data to the cursor, advancing position within its buffer. 279 /// 280 /// # Panics 281 /// 282 /// Panics if `self.capacity()` is less than `buf.len()`. 283 #[inline] append(&mut self, buf: &[u8])284 pub fn append(&mut self, buf: &[u8]) { 285 assert!(self.capacity() >= buf.len()); 286 287 // SAFETY: we do not de-initialize any of the elements of the slice 288 unsafe { 289 MaybeUninit::write_slice(&mut self.as_mut()[..buf.len()], buf); 290 } 291 292 // SAFETY: We just added the entire contents of buf to the filled section. 293 unsafe { 294 self.set_init(buf.len()); 295 } 296 self.buf.filled += buf.len(); 297 } 298 } 299 300 impl<'a> Write for BorrowedCursor<'a> { write(&mut self, buf: &[u8]) -> Result<usize>301 fn write(&mut self, buf: &[u8]) -> Result<usize> { 302 self.append(buf); 303 Ok(buf.len()) 304 } 305 flush(&mut self) -> Result<()>306 fn flush(&mut self) -> Result<()> { 307 Ok(()) 308 } 309 } 310