rust_expect/util/
zerocopy.rs1use std::io::{self, IoSlice, Write};
36use std::ops::{Deref, Range, RangeBounds};
37
38use bytes::{Buf, Bytes, BytesMut};
39
40#[derive(Debug, Clone, Default)]
45pub struct BytesBuffer {
46 inner: BytesMut,
47}
48
49impl BytesBuffer {
50 #[must_use]
52 pub fn new() -> Self {
53 Self {
54 inner: BytesMut::new(),
55 }
56 }
57
58 #[must_use]
60 pub fn with_capacity(capacity: usize) -> Self {
61 Self {
62 inner: BytesMut::with_capacity(capacity),
63 }
64 }
65
66 #[must_use]
68 pub fn from_bytes(data: impl Into<Bytes>) -> Self {
69 let bytes: Bytes = data.into();
70 let mut inner = BytesMut::with_capacity(bytes.len());
71 inner.extend_from_slice(&bytes);
72 Self { inner }
73 }
74
75 #[must_use]
77 pub fn len(&self) -> usize {
78 self.inner.len()
79 }
80
81 #[must_use]
83 pub fn is_empty(&self) -> bool {
84 self.inner.is_empty()
85 }
86
87 #[must_use]
89 pub fn capacity(&self) -> usize {
90 self.inner.capacity()
91 }
92
93 pub fn extend(&mut self, data: &[u8]) {
95 self.inner.extend_from_slice(data);
96 }
97
98 pub fn reserve(&mut self, additional: usize) {
100 self.inner.reserve(additional);
101 }
102
103 pub fn clear(&mut self) {
105 self.inner.clear();
106 }
107
108 #[must_use]
112 pub fn slice(&self, range: Range<usize>) -> Bytes {
113 self.inner.clone().freeze().slice(range)
114 }
115
116 #[must_use]
118 pub fn slice_ref<R: RangeBounds<usize>>(&self, range: R) -> Bytes {
119 use std::ops::Bound;
120
121 let start = match range.start_bound() {
122 Bound::Included(&n) => n,
123 Bound::Excluded(&n) => n + 1,
124 Bound::Unbounded => 0,
125 };
126
127 let end = match range.end_bound() {
128 Bound::Included(&n) => n + 1,
129 Bound::Excluded(&n) => n,
130 Bound::Unbounded => self.len(),
131 };
132
133 self.slice(start..end)
134 }
135
136 #[must_use]
140 pub fn freeze(self) -> Bytes {
141 self.inner.freeze()
142 }
143
144 pub fn split_to(&mut self, at: usize) -> BytesMut {
148 self.inner.split_to(at)
149 }
150
151 pub fn split_off(&mut self, at: usize) -> BytesMut {
153 self.inner.split_off(at)
154 }
155
156 pub fn advance(&mut self, n: usize) {
158 self.inner.advance(n);
159 }
160
161 #[must_use]
163 pub fn as_bytes(&self) -> &[u8] {
164 &self.inner
165 }
166
167 #[must_use]
169 pub fn as_str_lossy(&self) -> std::borrow::Cow<'_, str> {
170 String::from_utf8_lossy(&self.inner)
171 }
172
173 #[must_use]
175 pub fn find(&self, needle: &[u8]) -> Option<usize> {
176 self.inner
177 .windows(needle.len())
178 .position(|window| window == needle)
179 }
180
181 #[must_use]
183 pub fn find_str(&self, needle: &str) -> Option<usize> {
184 self.find(needle.as_bytes())
185 }
186
187 #[must_use]
189 pub fn tail(&self, n: usize) -> &[u8] {
190 let start = self.len().saturating_sub(n);
191 &self.inner[start..]
192 }
193
194 #[must_use]
196 pub fn head(&self, n: usize) -> &[u8] {
197 let end = n.min(self.len());
198 &self.inner[..end]
199 }
200}
201
202impl Deref for BytesBuffer {
203 type Target = [u8];
204
205 fn deref(&self) -> &Self::Target {
206 &self.inner
207 }
208}
209
210impl AsRef<[u8]> for BytesBuffer {
211 fn as_ref(&self) -> &[u8] {
212 &self.inner
213 }
214}
215
216impl From<Vec<u8>> for BytesBuffer {
217 fn from(vec: Vec<u8>) -> Self {
218 Self {
219 inner: BytesMut::from(&vec[..]),
220 }
221 }
222}
223
224impl From<&[u8]> for BytesBuffer {
225 fn from(slice: &[u8]) -> Self {
226 Self {
227 inner: BytesMut::from(slice),
228 }
229 }
230}
231
232impl From<&str> for BytesBuffer {
233 fn from(s: &str) -> Self {
234 Self::from(s.as_bytes())
235 }
236}
237
238impl Write for BytesBuffer {
239 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
240 self.extend(buf);
241 Ok(buf.len())
242 }
243
244 fn flush(&mut self) -> io::Result<()> {
245 Ok(())
246 }
247}
248
249#[derive(Debug, Default)]
254pub struct VecWriter {
255 chunks: Vec<Bytes>,
256 total_len: usize,
257}
258
259impl VecWriter {
260 #[must_use]
262 pub const fn new() -> Self {
263 Self {
264 chunks: Vec::new(),
265 total_len: 0,
266 }
267 }
268
269 #[must_use]
271 pub fn with_capacity(capacity: usize) -> Self {
272 Self {
273 chunks: Vec::with_capacity(capacity),
274 total_len: 0,
275 }
276 }
277
278 pub fn push(&mut self, data: impl Into<Bytes>) {
280 let bytes: Bytes = data.into();
281 self.total_len += bytes.len();
282 self.chunks.push(bytes);
283 }
284
285 pub fn push_slice(&mut self, data: &[u8]) {
287 self.push(Bytes::copy_from_slice(data));
288 }
289
290 #[must_use]
292 pub const fn chunk_count(&self) -> usize {
293 self.chunks.len()
294 }
295
296 #[must_use]
298 pub const fn len(&self) -> usize {
299 self.total_len
300 }
301
302 #[must_use]
304 pub const fn is_empty(&self) -> bool {
305 self.total_len == 0
306 }
307
308 pub fn clear(&mut self) {
310 self.chunks.clear();
311 self.total_len = 0;
312 }
313
314 #[must_use]
318 pub fn as_io_slices(&self) -> Vec<IoSlice<'_>> {
319 self.chunks.iter().map(|b| IoSlice::new(b)).collect()
320 }
321
322 #[must_use]
326 pub fn freeze(self) -> Bytes {
327 if self.chunks.len() == 1 {
328 return self
330 .chunks
331 .into_iter()
332 .next()
333 .expect("guarded by chunks.len() == 1 above");
334 }
335
336 let mut buffer = BytesMut::with_capacity(self.total_len);
337 for chunk in self.chunks {
338 buffer.extend_from_slice(&chunk);
339 }
340 buffer.freeze()
341 }
342
343 pub fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
349 let slices = self.as_io_slices();
350 writer.write_vectored(&slices)
351 }
352}
353
354#[derive(Debug)]
359pub enum BorrowedView<'a> {
360 Borrowed(&'a [u8]),
362 Owned(Bytes),
364}
365
366impl<'a> BorrowedView<'a> {
367 #[must_use]
369 pub const fn borrowed(data: &'a [u8]) -> Self {
370 Self::Borrowed(data)
371 }
372
373 #[must_use]
375 pub fn owned(data: impl Into<Bytes>) -> Self {
376 Self::Owned(data.into())
377 }
378
379 #[must_use]
381 pub const fn len(&self) -> usize {
382 match self {
383 Self::Borrowed(b) => b.len(),
384 Self::Owned(b) => b.len(),
385 }
386 }
387
388 #[must_use]
390 pub const fn is_empty(&self) -> bool {
391 self.len() == 0
392 }
393
394 #[must_use]
396 pub fn as_slice(&self) -> &[u8] {
397 match self {
398 Self::Borrowed(b) => b,
399 Self::Owned(b) => b,
400 }
401 }
402
403 #[must_use]
407 pub fn into_owned(self) -> Bytes {
408 match self {
409 Self::Borrowed(b) => Bytes::copy_from_slice(b),
410 Self::Owned(b) => b,
411 }
412 }
413}
414
415impl Deref for BorrowedView<'_> {
416 type Target = [u8];
417
418 fn deref(&self) -> &Self::Target {
419 self.as_slice()
420 }
421}
422
423impl AsRef<[u8]> for BorrowedView<'_> {
424 fn as_ref(&self) -> &[u8] {
425 self.as_slice()
426 }
427}
428
429pub trait ZeroCopySource {
431 fn view(&self) -> BorrowedView<'_>;
433
434 fn len(&self) -> usize {
436 self.view().len()
437 }
438
439 fn is_empty(&self) -> bool {
441 self.len() == 0
442 }
443}
444
445impl ZeroCopySource for [u8] {
446 fn view(&self) -> BorrowedView<'_> {
447 BorrowedView::borrowed(self)
448 }
449}
450
451impl ZeroCopySource for Vec<u8> {
452 fn view(&self) -> BorrowedView<'_> {
453 BorrowedView::borrowed(self)
454 }
455}
456
457impl ZeroCopySource for Bytes {
458 fn view(&self) -> BorrowedView<'_> {
459 BorrowedView::Owned(self.clone())
460 }
461}
462
463impl ZeroCopySource for BytesBuffer {
464 fn view(&self) -> BorrowedView<'_> {
465 BorrowedView::borrowed(&self.inner)
466 }
467}
468
469impl ZeroCopySource for str {
470 fn view(&self) -> BorrowedView<'_> {
471 BorrowedView::borrowed(self.as_bytes())
472 }
473}
474
475impl ZeroCopySource for String {
476 fn view(&self) -> BorrowedView<'_> {
477 BorrowedView::borrowed(self.as_bytes())
478 }
479}
480
481#[derive(Debug)]
486pub struct ReadPool {
487 buffers: Vec<BytesMut>,
488 buffer_size: usize,
489}
490
491impl ReadPool {
492 #[must_use]
494 pub const fn new(buffer_size: usize) -> Self {
495 Self {
496 buffers: Vec::new(),
497 buffer_size,
498 }
499 }
500
501 pub fn acquire(&mut self) -> BytesMut {
503 self.buffers
504 .pop()
505 .unwrap_or_else(|| BytesMut::with_capacity(self.buffer_size))
506 }
507
508 pub fn release(&mut self, mut buffer: BytesMut) {
510 buffer.clear();
511 if buffer.capacity() <= self.buffer_size * 2 {
513 self.buffers.push(buffer);
514 }
515 }
516
517 pub fn clear(&mut self) {
519 self.buffers.clear();
520 }
521
522 #[must_use]
524 pub const fn available(&self) -> usize {
525 self.buffers.len()
526 }
527}
528
529impl Default for ReadPool {
530 fn default() -> Self {
531 Self::new(8192) }
533}
534
535#[cfg(test)]
536mod tests {
537 use super::*;
538
539 #[test]
540 fn bytes_buffer_basic() {
541 let mut buffer = BytesBuffer::new();
542 buffer.extend(b"hello");
543 buffer.extend(b" world");
544
545 assert_eq!(buffer.len(), 11);
546 assert_eq!(buffer.as_bytes(), b"hello world");
547 }
548
549 #[test]
550 fn bytes_buffer_slicing() {
551 let mut buffer = BytesBuffer::with_capacity(20);
552 buffer.extend(b"hello world");
553
554 let slice = buffer.slice(0..5);
555 assert_eq!(&slice[..], b"hello");
556
557 let slice = buffer.slice_ref(6..);
558 assert_eq!(&slice[..], b"world");
559 }
560
561 #[test]
562 fn bytes_buffer_find() {
563 let buffer = BytesBuffer::from("the quick brown fox");
564
565 assert_eq!(buffer.find(b"quick"), Some(4));
566 assert_eq!(buffer.find_str("fox"), Some(16));
567 assert_eq!(buffer.find(b"lazy"), None);
568 }
569
570 #[test]
571 fn bytes_buffer_head_tail() {
572 let buffer = BytesBuffer::from("hello world");
573
574 assert_eq!(buffer.head(5), b"hello");
575 assert_eq!(buffer.tail(5), b"world");
576 assert_eq!(buffer.head(100), b"hello world");
577 assert_eq!(buffer.tail(100), b"hello world");
578 }
579
580 #[test]
581 fn vec_writer_basic() {
582 let mut writer = VecWriter::new();
583 writer.push(b"hello".as_slice());
584 writer.push(b" ".as_slice());
585 writer.push(b"world".as_slice());
586
587 assert_eq!(writer.chunk_count(), 3);
588 assert_eq!(writer.len(), 11);
589
590 let bytes = writer.freeze();
591 assert_eq!(&bytes[..], b"hello world");
592 }
593
594 #[test]
595 fn vec_writer_io_slices() {
596 let mut writer = VecWriter::new();
597 writer.push_slice(b"hello");
598 writer.push_slice(b"world");
599
600 let slices = writer.as_io_slices();
601 assert_eq!(slices.len(), 2);
602 }
603
604 #[test]
605 fn borrowed_view() {
606 let data = b"hello world";
607 let borrowed = BorrowedView::borrowed(data);
608
609 assert_eq!(borrowed.len(), 11);
610 assert_eq!(borrowed.as_slice(), data);
611
612 let owned = borrowed.into_owned();
613 assert_eq!(&owned[..], data);
614 }
615
616 #[test]
617 fn zero_copy_source_trait() {
618 let vec: Vec<u8> = b"hello".to_vec();
619 let view = vec.view();
620 assert_eq!(view.len(), 5);
621
622 let string = "world".to_string();
623 let view = string.view();
624 assert_eq!(view.len(), 5);
625 }
626
627 #[test]
628 fn read_pool() {
629 let mut pool = ReadPool::new(4096);
630
631 assert_eq!(pool.available(), 0);
632
633 let buf1 = pool.acquire();
634 assert!(buf1.capacity() >= 4096);
635
636 let buf2 = pool.acquire();
637 pool.release(buf1);
638 assert_eq!(pool.available(), 1);
639
640 let buf3 = pool.acquire();
641 assert_eq!(pool.available(), 0);
642
643 pool.release(buf2);
644 pool.release(buf3);
645 assert_eq!(pool.available(), 2);
646 }
647
648 #[test]
649 fn write_trait() {
650 use std::io::Write;
651
652 let mut buffer = BytesBuffer::new();
653 write!(buffer, "hello {}", 42).unwrap();
654 assert_eq!(buffer.as_str_lossy(), "hello 42");
655 }
656}