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.chunks.into_iter().next().unwrap();
330 }
331
332 let mut buffer = BytesMut::with_capacity(self.total_len);
333 for chunk in self.chunks {
334 buffer.extend_from_slice(&chunk);
335 }
336 buffer.freeze()
337 }
338
339 pub fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
345 let slices = self.as_io_slices();
346 writer.write_vectored(&slices)
347 }
348}
349
350#[derive(Debug)]
355pub enum BorrowedView<'a> {
356 Borrowed(&'a [u8]),
358 Owned(Bytes),
360}
361
362impl<'a> BorrowedView<'a> {
363 #[must_use]
365 pub const fn borrowed(data: &'a [u8]) -> Self {
366 Self::Borrowed(data)
367 }
368
369 #[must_use]
371 pub fn owned(data: impl Into<Bytes>) -> Self {
372 Self::Owned(data.into())
373 }
374
375 #[must_use]
377 pub const fn len(&self) -> usize {
378 match self {
379 Self::Borrowed(b) => b.len(),
380 Self::Owned(b) => b.len(),
381 }
382 }
383
384 #[must_use]
386 pub const fn is_empty(&self) -> bool {
387 self.len() == 0
388 }
389
390 #[must_use]
392 pub fn as_slice(&self) -> &[u8] {
393 match self {
394 Self::Borrowed(b) => b,
395 Self::Owned(b) => b,
396 }
397 }
398
399 #[must_use]
403 pub fn into_owned(self) -> Bytes {
404 match self {
405 Self::Borrowed(b) => Bytes::copy_from_slice(b),
406 Self::Owned(b) => b,
407 }
408 }
409}
410
411impl Deref for BorrowedView<'_> {
412 type Target = [u8];
413
414 fn deref(&self) -> &Self::Target {
415 self.as_slice()
416 }
417}
418
419impl AsRef<[u8]> for BorrowedView<'_> {
420 fn as_ref(&self) -> &[u8] {
421 self.as_slice()
422 }
423}
424
425pub trait ZeroCopySource {
427 fn view(&self) -> BorrowedView<'_>;
429
430 fn len(&self) -> usize {
432 self.view().len()
433 }
434
435 fn is_empty(&self) -> bool {
437 self.len() == 0
438 }
439}
440
441impl ZeroCopySource for [u8] {
442 fn view(&self) -> BorrowedView<'_> {
443 BorrowedView::borrowed(self)
444 }
445}
446
447impl ZeroCopySource for Vec<u8> {
448 fn view(&self) -> BorrowedView<'_> {
449 BorrowedView::borrowed(self)
450 }
451}
452
453impl ZeroCopySource for Bytes {
454 fn view(&self) -> BorrowedView<'_> {
455 BorrowedView::Owned(self.clone())
456 }
457}
458
459impl ZeroCopySource for BytesBuffer {
460 fn view(&self) -> BorrowedView<'_> {
461 BorrowedView::borrowed(&self.inner)
462 }
463}
464
465impl ZeroCopySource for str {
466 fn view(&self) -> BorrowedView<'_> {
467 BorrowedView::borrowed(self.as_bytes())
468 }
469}
470
471impl ZeroCopySource for String {
472 fn view(&self) -> BorrowedView<'_> {
473 BorrowedView::borrowed(self.as_bytes())
474 }
475}
476
477#[derive(Debug)]
482pub struct ReadPool {
483 buffers: Vec<BytesMut>,
484 buffer_size: usize,
485}
486
487impl ReadPool {
488 #[must_use]
490 pub const fn new(buffer_size: usize) -> Self {
491 Self {
492 buffers: Vec::new(),
493 buffer_size,
494 }
495 }
496
497 pub fn acquire(&mut self) -> BytesMut {
499 self.buffers
500 .pop()
501 .unwrap_or_else(|| BytesMut::with_capacity(self.buffer_size))
502 }
503
504 pub fn release(&mut self, mut buffer: BytesMut) {
506 buffer.clear();
507 if buffer.capacity() <= self.buffer_size * 2 {
509 self.buffers.push(buffer);
510 }
511 }
512
513 pub fn clear(&mut self) {
515 self.buffers.clear();
516 }
517
518 #[must_use]
520 pub const fn available(&self) -> usize {
521 self.buffers.len()
522 }
523}
524
525impl Default for ReadPool {
526 fn default() -> Self {
527 Self::new(8192) }
529}
530
531#[cfg(test)]
532mod tests {
533 use super::*;
534
535 #[test]
536 fn bytes_buffer_basic() {
537 let mut buffer = BytesBuffer::new();
538 buffer.extend(b"hello");
539 buffer.extend(b" world");
540
541 assert_eq!(buffer.len(), 11);
542 assert_eq!(buffer.as_bytes(), b"hello world");
543 }
544
545 #[test]
546 fn bytes_buffer_slicing() {
547 let mut buffer = BytesBuffer::with_capacity(20);
548 buffer.extend(b"hello world");
549
550 let slice = buffer.slice(0..5);
551 assert_eq!(&slice[..], b"hello");
552
553 let slice = buffer.slice_ref(6..);
554 assert_eq!(&slice[..], b"world");
555 }
556
557 #[test]
558 fn bytes_buffer_find() {
559 let buffer = BytesBuffer::from("the quick brown fox");
560
561 assert_eq!(buffer.find(b"quick"), Some(4));
562 assert_eq!(buffer.find_str("fox"), Some(16));
563 assert_eq!(buffer.find(b"lazy"), None);
564 }
565
566 #[test]
567 fn bytes_buffer_head_tail() {
568 let buffer = BytesBuffer::from("hello world");
569
570 assert_eq!(buffer.head(5), b"hello");
571 assert_eq!(buffer.tail(5), b"world");
572 assert_eq!(buffer.head(100), b"hello world");
573 assert_eq!(buffer.tail(100), b"hello world");
574 }
575
576 #[test]
577 fn vec_writer_basic() {
578 let mut writer = VecWriter::new();
579 writer.push(b"hello".as_slice());
580 writer.push(b" ".as_slice());
581 writer.push(b"world".as_slice());
582
583 assert_eq!(writer.chunk_count(), 3);
584 assert_eq!(writer.len(), 11);
585
586 let bytes = writer.freeze();
587 assert_eq!(&bytes[..], b"hello world");
588 }
589
590 #[test]
591 fn vec_writer_io_slices() {
592 let mut writer = VecWriter::new();
593 writer.push_slice(b"hello");
594 writer.push_slice(b"world");
595
596 let slices = writer.as_io_slices();
597 assert_eq!(slices.len(), 2);
598 }
599
600 #[test]
601 fn borrowed_view() {
602 let data = b"hello world";
603 let borrowed = BorrowedView::borrowed(data);
604
605 assert_eq!(borrowed.len(), 11);
606 assert_eq!(borrowed.as_slice(), data);
607
608 let owned = borrowed.into_owned();
609 assert_eq!(&owned[..], data);
610 }
611
612 #[test]
613 fn zero_copy_source_trait() {
614 let vec: Vec<u8> = b"hello".to_vec();
615 let view = vec.view();
616 assert_eq!(view.len(), 5);
617
618 let string = "world".to_string();
619 let view = string.view();
620 assert_eq!(view.len(), 5);
621 }
622
623 #[test]
624 fn read_pool() {
625 let mut pool = ReadPool::new(4096);
626
627 assert_eq!(pool.available(), 0);
628
629 let buf1 = pool.acquire();
630 assert!(buf1.capacity() >= 4096);
631
632 let buf2 = pool.acquire();
633 pool.release(buf1);
634 assert_eq!(pool.available(), 1);
635
636 let buf3 = pool.acquire();
637 assert_eq!(pool.available(), 0);
638
639 pool.release(buf2);
640 pool.release(buf3);
641 assert_eq!(pool.available(), 2);
642 }
643
644 #[test]
645 fn write_trait() {
646 use std::io::Write;
647
648 let mut buffer = BytesBuffer::new();
649 write!(buffer, "hello {}", 42).unwrap();
650 assert_eq!(buffer.as_str_lossy(), "hello 42");
651 }
652}