rw_deno_core/io/
buffers.rs

1// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2use bytes::Buf;
3use bytes::BytesMut;
4use serde_v8::JsBuffer;
5use serde_v8::V8Slice;
6use std::ops::Deref;
7use std::ops::DerefMut;
8
9/// BufView is a wrapper around an underlying contiguous chunk of bytes. It can
10/// be created from a [JsBuffer], [bytes::Bytes], or [Vec<u8>] and implements
11/// `Deref<[u8]>` and `AsRef<[u8]>`.
12///
13/// The wrapper has the ability to constrain the exposed view to a sub-region of
14/// the underlying buffer. This is useful for write operations, because they may
15/// have to be called multiple times, with different views onto the buffer to be
16/// able to write it entirely.
17#[derive(Debug)]
18pub struct BufView {
19  inner: BufViewInner,
20  cursor: usize,
21}
22
23#[derive(Debug)]
24enum BufViewInner {
25  Empty,
26  Bytes(bytes::Bytes),
27  JsBuffer(V8Slice<u8>),
28}
29
30impl BufView {
31  const fn from_inner(inner: BufViewInner) -> Self {
32    Self { inner, cursor: 0 }
33  }
34
35  pub const fn empty() -> Self {
36    Self::from_inner(BufViewInner::Empty)
37  }
38
39  /// Get the length of the buffer view. This is the length of the underlying
40  /// buffer minus the cursor position.
41  pub fn len(&self) -> usize {
42    match &self.inner {
43      BufViewInner::Empty => 0,
44      BufViewInner::Bytes(bytes) => bytes.len() - self.cursor,
45      BufViewInner::JsBuffer(js_buf) => js_buf.len() - self.cursor,
46    }
47  }
48
49  /// Is the buffer view empty?
50  pub fn is_empty(&self) -> bool {
51    self.len() == 0
52  }
53
54  /// Advance the internal cursor of the buffer view by `n` bytes.
55  pub fn advance_cursor(&mut self, n: usize) {
56    assert!(self.len() >= n);
57    self.cursor += n;
58  }
59
60  /// Reset the internal cursor of the buffer view to the beginning of the
61  /// buffer. Returns the old cursor position.
62  pub fn reset_cursor(&mut self) -> usize {
63    let old = self.cursor;
64    self.cursor = 0;
65    old
66  }
67
68  /// Adjust the length of the remaining buffer. If the requested size is greater than the current
69  /// length, no changes are made.
70  pub fn truncate(&mut self, size: usize) {
71    match &mut self.inner {
72      BufViewInner::Empty => {}
73      BufViewInner::Bytes(bytes) => bytes.truncate(size + self.cursor),
74      BufViewInner::JsBuffer(buffer) => buffer.truncate(size + self.cursor),
75    }
76  }
77
78  /// Split the underlying buffer. The other piece will maintain the current cursor position while this buffer
79  /// will have a cursor of zero.
80  pub fn split_off(&mut self, at: usize) -> Self {
81    let at = at + self.cursor;
82    assert!(at <= self.len());
83    let other = match &mut self.inner {
84      BufViewInner::Empty => BufViewInner::Empty,
85      BufViewInner::Bytes(bytes) => BufViewInner::Bytes(bytes.split_off(at)),
86      BufViewInner::JsBuffer(buffer) => {
87        BufViewInner::JsBuffer(buffer.split_off(at))
88      }
89    };
90    Self {
91      inner: other,
92      cursor: 0,
93    }
94  }
95
96  /// Split the underlying buffer. The other piece will have a cursor of zero while this buffer
97  /// will maintain the current cursor position.
98  pub fn split_to(&mut self, at: usize) -> Self {
99    assert!(at <= self.len());
100    let at = at + self.cursor;
101    let other = match &mut self.inner {
102      BufViewInner::Empty => BufViewInner::Empty,
103      BufViewInner::Bytes(bytes) => BufViewInner::Bytes(bytes.split_to(at)),
104      BufViewInner::JsBuffer(buffer) => {
105        BufViewInner::JsBuffer(buffer.split_to(at))
106      }
107    };
108    let cursor = std::mem::take(&mut self.cursor);
109    Self {
110      inner: other,
111      cursor,
112    }
113  }
114}
115
116impl Buf for BufView {
117  fn remaining(&self) -> usize {
118    self.len()
119  }
120
121  fn chunk(&self) -> &[u8] {
122    self.deref()
123  }
124
125  fn advance(&mut self, cnt: usize) {
126    self.advance_cursor(cnt)
127  }
128}
129
130impl Deref for BufView {
131  type Target = [u8];
132
133  fn deref(&self) -> &[u8] {
134    let buf = match &self.inner {
135      BufViewInner::Empty => &[],
136      BufViewInner::Bytes(bytes) => bytes.deref(),
137      BufViewInner::JsBuffer(js_buf) => js_buf.deref(),
138    };
139    &buf[self.cursor..]
140  }
141}
142
143impl AsRef<[u8]> for BufView {
144  fn as_ref(&self) -> &[u8] {
145    self.deref()
146  }
147}
148
149impl From<JsBuffer> for BufView {
150  fn from(buf: JsBuffer) -> Self {
151    Self::from_inner(BufViewInner::JsBuffer(buf.into_parts()))
152  }
153}
154
155impl From<Vec<u8>> for BufView {
156  fn from(vec: Vec<u8>) -> Self {
157    Self::from_inner(BufViewInner::Bytes(vec.into()))
158  }
159}
160
161impl From<bytes::Bytes> for BufView {
162  fn from(buf: bytes::Bytes) -> Self {
163    Self::from_inner(BufViewInner::Bytes(buf))
164  }
165}
166
167impl From<BufView> for bytes::Bytes {
168  fn from(buf: BufView) -> Self {
169    match buf.inner {
170      BufViewInner::Empty => bytes::Bytes::new(),
171      BufViewInner::Bytes(bytes) => bytes,
172      BufViewInner::JsBuffer(js_buf) => js_buf.into(),
173    }
174  }
175}
176
177/// BufMutViewWhole is equivalent to `BufMutView`, but cannot be split, preventing
178/// someone from accidentally holding a `BufView` down the road that is being actively
179/// mutated from JavaScript.
180pub struct BufMutViewWhole {
181  inner: BufMutViewInner,
182  cursor: usize,
183}
184
185/// BufMutView is a wrapper around an underlying contiguous chunk of writable
186/// bytes. It can be created from a `JsBuffer` or a `Vec<u8>` and implements
187/// `DerefMut<[u8]>` and `AsMut<[u8]>`.
188///
189/// The wrapper has the ability to constrain the exposed view to a sub-region of
190/// the underlying buffer. This is useful for write operations, because they may
191/// have to be called multiple times, with different views onto the buffer to be
192/// able to write it entirely.
193///
194/// A `BufMutView` can be turned into a `BufView` by calling `BufMutView::into_view`.
195#[derive(Debug)]
196pub struct BufMutView {
197  inner: BufMutViewInner,
198  cursor: usize,
199}
200
201#[derive(Debug)]
202enum BufMutViewInner {
203  JsBuffer(V8Slice<u8>),
204  Bytes(BytesMut),
205}
206
207impl Default for BufMutView {
208  fn default() -> Self {
209    BufMutView {
210      inner: BufMutViewInner::Bytes(BytesMut::default()),
211      cursor: 0,
212    }
213  }
214}
215
216impl BufMutView {
217  fn from_inner(inner: BufMutViewInner) -> Self {
218    Self { inner, cursor: 0 }
219  }
220
221  pub fn new(len: usize) -> Self {
222    let bytes = BytesMut::zeroed(len);
223    Self::from_inner(BufMutViewInner::Bytes(bytes))
224  }
225
226  /// Get the length of the buffer view. This is the length of the underlying
227  /// buffer minus the cursor position.
228  pub fn len(&self) -> usize {
229    match &self.inner {
230      BufMutViewInner::JsBuffer(js_buf) => js_buf.len() - self.cursor,
231      BufMutViewInner::Bytes(bytes) => bytes.len() - self.cursor,
232    }
233  }
234
235  /// Is the buffer view empty?
236  pub fn is_empty(&self) -> bool {
237    self.len() == 0
238  }
239
240  /// Advance the internal cursor of the buffer view by `n` bytes.
241  pub fn advance_cursor(&mut self, n: usize) {
242    assert!(self.len() >= n);
243    self.cursor += n;
244  }
245
246  /// Reset the internal cursor of the buffer view to the beginning of the
247  /// buffer. Returns the old cursor position.
248  pub fn reset_cursor(&mut self) -> usize {
249    let old = self.cursor;
250    self.cursor = 0;
251    old
252  }
253
254  /// Turn this `BufMutView` into a `BufView`.
255  pub fn into_view(self) -> BufView {
256    let inner = match self.inner {
257      BufMutViewInner::JsBuffer(js_buf) => BufViewInner::JsBuffer(js_buf),
258      BufMutViewInner::Bytes(bytes) => BufViewInner::Bytes(bytes.into()),
259    };
260    BufView {
261      inner,
262      cursor: self.cursor,
263    }
264  }
265
266  /// Attempts to unwrap the underlying buffer into a [`BytesMut`], consuming the `BufMutView`. If
267  /// this buffer does not have a [`BytesMut`], returns `Self`.
268  pub fn maybe_unwrap_bytes(self) -> Result<BytesMut, Self> {
269    match self.inner {
270      BufMutViewInner::JsBuffer(_) => Err(self),
271      BufMutViewInner::Bytes(bytes) => Ok(bytes),
272    }
273  }
274
275  /// This attempts to grow the `BufMutView` to a target size, by a maximum increment. This method
276  /// will be replaced by a better API in the future and should not be used at this time.
277  #[must_use = "The result of this method should be tested"]
278  #[deprecated = "API will be replaced in the future"]
279  #[doc(hidden)]
280  pub fn maybe_resize(
281    &mut self,
282    target_size: usize,
283    maximum_increment: usize,
284  ) -> Option<usize> {
285    if let BufMutViewInner::Bytes(bytes) = &mut self.inner {
286      use std::cmp::Ordering::*;
287      let len = bytes.len();
288      let target_size = target_size + self.cursor;
289      match target_size.cmp(&len) {
290        Greater => {
291          bytes.resize(std::cmp::min(target_size, len + maximum_increment), 0);
292        }
293        Less => {
294          bytes.truncate(target_size);
295        }
296        Equal => {}
297      }
298      Some(bytes.len())
299    } else {
300      None
301    }
302  }
303
304  /// This attempts to grow the `BufMutView` to a target size, by a maximum increment. This method
305  /// will be replaced by a better API in the future and should not be used at this time.
306  #[must_use = "The result of this method should be tested"]
307  #[deprecated = "API will be replaced in the future"]
308  #[doc(hidden)]
309  pub fn maybe_grow(&mut self, target_size: usize) -> Option<usize> {
310    if let BufMutViewInner::Bytes(bytes) = &mut self.inner {
311      let len = bytes.len();
312      let target_size = target_size + self.cursor;
313      if target_size > len {
314        bytes.resize(target_size, 0);
315      }
316      Some(bytes.len())
317    } else {
318      None
319    }
320  }
321
322  /// Adjust the length of the remaining buffer and ensure that the cursor continues to
323  /// stay in-bounds.
324  pub fn truncate(&mut self, size: usize) {
325    match &mut self.inner {
326      BufMutViewInner::Bytes(bytes) => bytes.truncate(size + self.cursor),
327      BufMutViewInner::JsBuffer(buffer) => buffer.truncate(size + self.cursor),
328    }
329    self.cursor = std::cmp::min(self.cursor, self.len());
330  }
331
332  /// Split the underlying buffer. The other piece will maintain the current cursor position while this buffer
333  /// will have a cursor of zero.
334  pub fn split_off(&mut self, at: usize) -> Self {
335    let at = at + self.cursor;
336    assert!(at <= self.len());
337    let other = match &mut self.inner {
338      BufMutViewInner::Bytes(bytes) => {
339        BufMutViewInner::Bytes(bytes.split_off(at))
340      }
341      BufMutViewInner::JsBuffer(buffer) => {
342        BufMutViewInner::JsBuffer(buffer.split_off(at))
343      }
344    };
345    Self {
346      inner: other,
347      cursor: 0,
348    }
349  }
350
351  /// Split the underlying buffer. The other piece will have a cursor of zero while this buffer
352  /// will maintain the current cursor position.
353  pub fn split_to(&mut self, at: usize) -> Self {
354    assert!(at <= self.len());
355    let at = at + self.cursor;
356    let other = match &mut self.inner {
357      BufMutViewInner::Bytes(bytes) => {
358        BufMutViewInner::Bytes(bytes.split_to(at))
359      }
360      BufMutViewInner::JsBuffer(buffer) => {
361        BufMutViewInner::JsBuffer(buffer.split_to(at))
362      }
363    };
364    let cursor = std::mem::take(&mut self.cursor);
365    Self {
366      inner: other,
367      cursor,
368    }
369  }
370}
371
372impl Buf for BufMutView {
373  fn remaining(&self) -> usize {
374    self.len()
375  }
376
377  fn chunk(&self) -> &[u8] {
378    self.deref()
379  }
380
381  fn advance(&mut self, cnt: usize) {
382    self.advance_cursor(cnt)
383  }
384}
385
386impl Deref for BufMutView {
387  type Target = [u8];
388
389  fn deref(&self) -> &[u8] {
390    let buf = match &self.inner {
391      BufMutViewInner::JsBuffer(js_buf) => js_buf.deref(),
392      BufMutViewInner::Bytes(vec) => vec.deref(),
393    };
394    &buf[self.cursor..]
395  }
396}
397
398impl DerefMut for BufMutView {
399  fn deref_mut(&mut self) -> &mut [u8] {
400    let buf = match &mut self.inner {
401      BufMutViewInner::JsBuffer(js_buf) => js_buf.deref_mut(),
402      BufMutViewInner::Bytes(vec) => vec.deref_mut(),
403    };
404    &mut buf[self.cursor..]
405  }
406}
407
408impl AsRef<[u8]> for BufMutView {
409  fn as_ref(&self) -> &[u8] {
410    self.deref()
411  }
412}
413
414impl AsMut<[u8]> for BufMutView {
415  fn as_mut(&mut self) -> &mut [u8] {
416    self.deref_mut()
417  }
418}
419
420impl From<JsBuffer> for BufMutView {
421  fn from(buf: JsBuffer) -> Self {
422    Self::from_inner(BufMutViewInner::JsBuffer(buf.into_parts()))
423  }
424}
425
426impl From<BytesMut> for BufMutView {
427  fn from(buf: BytesMut) -> Self {
428    Self::from_inner(BufMutViewInner::Bytes(buf))
429  }
430}
431
432impl BufMutViewWhole {
433  fn from_inner(inner: BufMutViewInner) -> Self {
434    Self { inner, cursor: 0 }
435  }
436
437  pub fn new(len: usize) -> Self {
438    let bytes = BytesMut::zeroed(len);
439    Self::from_inner(BufMutViewInner::Bytes(bytes))
440  }
441
442  /// Get the length of the buffer view. This is the length of the underlying
443  /// buffer minus the cursor position.
444  pub fn len(&self) -> usize {
445    match &self.inner {
446      BufMutViewInner::JsBuffer(js_buf) => js_buf.len() - self.cursor,
447      BufMutViewInner::Bytes(bytes) => bytes.len() - self.cursor,
448    }
449  }
450
451  /// Is the buffer view empty?
452  pub fn is_empty(&self) -> bool {
453    self.len() == 0
454  }
455
456  /// Advance the internal cursor of the buffer view by `n` bytes.
457  pub fn advance_cursor(&mut self, n: usize) {
458    assert!(self.len() >= n);
459    self.cursor += n;
460  }
461
462  /// Reset the internal cursor of the buffer view to the beginning of the
463  /// buffer. Returns the old cursor position.
464  pub fn reset_cursor(&mut self) -> usize {
465    let old = self.cursor;
466    self.cursor = 0;
467    old
468  }
469
470  /// Turn this `BufMutView` into a `BufView`.
471  pub fn into_view(self) -> BufView {
472    let inner = match self.inner {
473      BufMutViewInner::JsBuffer(js_buf) => BufViewInner::JsBuffer(js_buf),
474      BufMutViewInner::Bytes(bytes) => BufViewInner::Bytes(bytes.into()),
475    };
476    BufView {
477      inner,
478      cursor: self.cursor,
479    }
480  }
481
482  /// Attempts to unwrap the underlying buffer into a [`BytesMut`], consuming the `BufMutView`. If
483  /// this buffer does not have a [`BytesMut`], returns `Self`.
484  pub fn maybe_unwrap_bytes(self) -> Result<BytesMut, Self> {
485    match self.inner {
486      BufMutViewInner::JsBuffer(_) => Err(self),
487      BufMutViewInner::Bytes(bytes) => Ok(bytes),
488    }
489  }
490
491  /// Adjust the length of the remaining buffer and ensure that the cursor continues to
492  /// stay in-bounds.
493  pub fn truncate(&mut self, size: usize) {
494    match &mut self.inner {
495      BufMutViewInner::Bytes(bytes) => bytes.truncate(size + self.cursor),
496      BufMutViewInner::JsBuffer(buffer) => buffer.truncate(size + self.cursor),
497    }
498    self.cursor = std::cmp::min(self.cursor, self.len());
499  }
500}
501
502impl Buf for BufMutViewWhole {
503  fn remaining(&self) -> usize {
504    self.len()
505  }
506
507  fn chunk(&self) -> &[u8] {
508    self.deref()
509  }
510
511  fn advance(&mut self, cnt: usize) {
512    self.advance_cursor(cnt)
513  }
514}
515
516impl Deref for BufMutViewWhole {
517  type Target = [u8];
518
519  fn deref(&self) -> &[u8] {
520    let buf = match &self.inner {
521      BufMutViewInner::JsBuffer(js_buf) => js_buf.deref(),
522      BufMutViewInner::Bytes(vec) => vec.deref(),
523    };
524    &buf[self.cursor..]
525  }
526}
527
528impl DerefMut for BufMutViewWhole {
529  fn deref_mut(&mut self) -> &mut [u8] {
530    let buf = match &mut self.inner {
531      BufMutViewInner::JsBuffer(js_buf) => js_buf.deref_mut(),
532      BufMutViewInner::Bytes(vec) => vec.deref_mut(),
533    };
534    &mut buf[self.cursor..]
535  }
536}
537
538impl From<JsBuffer> for BufMutViewWhole {
539  fn from(buf: JsBuffer) -> Self {
540    Self::from_inner(BufMutViewInner::JsBuffer(buf.into_parts()))
541  }
542}
543
544impl From<BytesMut> for BufMutViewWhole {
545  fn from(buf: BytesMut) -> Self {
546    Self::from_inner(BufMutViewInner::Bytes(buf))
547  }
548}
549
550#[cfg(test)]
551mod tests {
552  use super::*;
553
554  #[test]
555  pub fn bufview_read_and_truncate() {
556    let mut buf = BufView::from(vec![1, 2, 3, 4]);
557    assert_eq!(4, buf.len());
558    assert_eq!(0, buf.cursor);
559    assert_eq!(1, buf.get_u8());
560    assert_eq!(3, buf.len());
561    // The cursor is at position 1, so this truncates the underlying buffer to 2+1
562    buf.truncate(2);
563    assert_eq!(2, buf.len());
564    assert_eq!(2, buf.get_u8());
565    assert_eq!(1, buf.len());
566
567    buf.reset_cursor();
568    assert_eq!(3, buf.len());
569  }
570
571  #[test]
572  pub fn bufview_split() {
573    let mut buf = BufView::from(Vec::from_iter(0..100));
574    assert_eq!(100, buf.len());
575    buf.advance_cursor(25);
576    assert_eq!(75, buf.len());
577    let mut other = buf.split_off(10);
578    assert_eq!(25, buf.cursor);
579    assert_eq!(10, buf.len());
580    assert_eq!(65, other.len());
581
582    let other2 = other.split_to(20);
583    assert_eq!(20, other2.len());
584    assert_eq!(45, other.len());
585
586    assert_eq!(100, buf.cursor + buf.len() + other.len() + other2.len());
587    buf.reset_cursor();
588    assert_eq!(100, buf.cursor + buf.len() + other.len() + other2.len());
589  }
590
591  #[test]
592  pub fn bufmutview_read_and_truncate() {
593    let mut buf = BufMutView::from(BytesMut::from([1, 2, 3, 4].as_slice()));
594    assert_eq!(4, buf.len());
595    assert_eq!(0, buf.cursor);
596    assert_eq!(1, buf.get_u8());
597    assert_eq!(3, buf.len());
598    // The cursor is at position 1, so this truncates the underlying buffer to 2+1
599    buf.truncate(2);
600    assert_eq!(2, buf.len());
601    assert_eq!(2, buf.get_u8());
602    assert_eq!(1, buf.len());
603
604    buf.reset_cursor();
605    assert_eq!(3, buf.len());
606  }
607
608  #[test]
609  pub fn bufmutview_split() {
610    let mut buf =
611      BufMutView::from(BytesMut::from(Vec::from_iter(0..100).as_slice()));
612    assert_eq!(100, buf.len());
613    buf.advance_cursor(25);
614    assert_eq!(75, buf.len());
615    let mut other = buf.split_off(10);
616    assert_eq!(25, buf.cursor);
617    assert_eq!(10, buf.len());
618    assert_eq!(65, other.len());
619
620    let other2 = other.split_to(20);
621    assert_eq!(20, other2.len());
622    assert_eq!(45, other.len());
623
624    assert_eq!(100, buf.cursor + buf.len() + other.len() + other2.len());
625    buf.reset_cursor();
626    assert_eq!(100, buf.cursor + buf.len() + other.len() + other2.len());
627  }
628
629  #[test]
630  #[allow(deprecated)]
631  fn bufmutview_resize() {
632    let new =
633      || BufMutView::from(BytesMut::from(Vec::from_iter(0..100).as_slice()));
634    let mut buf = new();
635    assert_eq!(100, buf.len());
636    buf.maybe_resize(200, 10).unwrap();
637    assert_eq!(110, buf.len());
638
639    let mut buf = new();
640    assert_eq!(100, buf.len());
641    buf.maybe_resize(200, 100).unwrap();
642    assert_eq!(200, buf.len());
643
644    let mut buf = new();
645    assert_eq!(100, buf.len());
646    buf.maybe_resize(200, 1000).unwrap();
647    assert_eq!(200, buf.len());
648
649    let mut buf = new();
650    buf.advance_cursor(50);
651    assert_eq!(50, buf.len());
652    buf.maybe_resize(100, 100).unwrap();
653    assert_eq!(100, buf.len());
654    buf.reset_cursor();
655    assert_eq!(150, buf.len());
656  }
657
658  #[test]
659  #[allow(deprecated)]
660  fn bufmutview_grow() {
661    let new =
662      || BufMutView::from(BytesMut::from(Vec::from_iter(0..100).as_slice()));
663    let mut buf = new();
664    assert_eq!(100, buf.len());
665    buf.maybe_grow(200).unwrap();
666    assert_eq!(200, buf.len());
667
668    let mut buf = new();
669    buf.advance_cursor(50);
670    assert_eq!(50, buf.len());
671    buf.maybe_grow(100).unwrap();
672    assert_eq!(100, buf.len());
673    buf.reset_cursor();
674    assert_eq!(150, buf.len());
675  }
676}