Skip to main content

minibytes/
bytes.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8use std::any::Any;
9use std::ops::Range;
10use std::ops::RangeBounds;
11use std::sync::Arc;
12use std::sync::Weak;
13
14pub type Bytes = AbstractBytes<[u8]>;
15pub trait BytesOwner: AsRef<[u8]> + Send + Sync + 'static {}
16
17pub type WeakBytes = Weak<dyn AbstractOwner<[u8]>>;
18
19/// Immutable bytes with zero-copy slicing and cloning.
20pub struct AbstractBytes<T: ?Sized> {
21    pub(crate) ptr: *const u8,
22    pub(crate) len: usize,
23
24    // Actual owner of the bytes. None for static buffers.
25    pub(crate) owner: Option<Arc<dyn AbstractOwner<T>>>,
26}
27
28/// The actual storage owning the bytes.
29pub trait AbstractOwner<T: ?Sized>: AsRef<T> + Send + Sync + 'static {
30    fn as_any_mut(&mut self) -> &mut dyn Any;
31}
32
33impl<T: BytesOwner> AbstractOwner<[u8]> for T {
34    fn as_any_mut(&mut self) -> &mut dyn Any {
35        self
36    }
37}
38
39// AbstractOwner<T> is Send + Sync and AbstractBytes<T> is immutable.
40unsafe impl<T: ?Sized> Send for AbstractBytes<T> {}
41unsafe impl<T: ?Sized> Sync for AbstractBytes<T> {}
42
43// #[derive(Clone)] does not work well with type parameters.
44// Therefore implement Clone manually.
45impl<T: ?Sized> Clone for AbstractBytes<T> {
46    fn clone(&self) -> Self {
47        Self {
48            ptr: self.ptr,
49            len: self.len,
50            owner: self.owner.clone(),
51        }
52    }
53}
54
55// Core implementation of Bytes.
56impl<T> AbstractBytes<T>
57where
58    T: SliceLike + ?Sized,
59    T::Owned: AbstractOwner<T>,
60{
61    /// Returns a slice of self for the provided range.
62    /// This operation is `O(1)`.
63    pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
64        use std::ops::Bound;
65        let start = match range.start_bound() {
66            Bound::Included(&n) => n,
67            Bound::Excluded(&n) => n + 1,
68            Bound::Unbounded => 0,
69        };
70        let end = match range.end_bound() {
71            Bound::Included(&n) => n + 1,
72            Bound::Excluded(&n) => n,
73            Bound::Unbounded => self.len,
74        };
75        assert!(start <= end, "invalid slice {}..{}", start, end);
76        assert!(end <= self.len, "{} exceeds Bytes length {}", end, self.len);
77        if start == end {
78            Self::new()
79        } else {
80            T::check_slice_bytes(self.as_bytes(), start, end);
81            Self {
82                ptr: unsafe { self.ptr.add(start) },
83                len: end - start,
84                owner: self.owner.clone(),
85            }
86        }
87    }
88
89    /// Attempt to convert `slice` to a zero-copy slice of this `Bytes`.
90    /// Copy the `slice` if zero-copy cannot be done.
91    ///
92    /// This is similar to `bytes::Bytes::slice_ref` from `bytes 0.5.4`,
93    /// but does not panic.
94    pub fn slice_to_bytes(&self, slice: &T) -> Self {
95        match self.range_of_slice(slice) {
96            Some(range) => self.slice(range),
97            None => Self::copy_from_slice(slice),
98        }
99    }
100
101    /// Return a range `x` so that `self[x]` matches `slice` exactly
102    /// (not only content, but also internal pointer addresses).
103    ///
104    /// Returns `None` if `slice` is outside the memory range of this
105    /// `Bytes`.
106    ///
107    /// This operation is `O(1)`.
108    pub fn range_of_slice(&self, slice: &T) -> Option<Range<usize>> {
109        let slice_start = slice.as_ptr() as usize;
110        let slice_end = slice_start + slice.len();
111        let bytes_start = self.ptr as usize;
112        let bytes_end = bytes_start + self.len;
113        if slice_start >= bytes_start && slice_end <= bytes_end {
114            let start = slice_start - bytes_start;
115            Some(start..start + slice.len())
116        } else {
117            None
118        }
119    }
120
121    /// Creates an empty `Bytes`.
122    #[inline]
123    pub fn new() -> Self {
124        let empty = T::EMPTY.as_bytes();
125        Self {
126            ptr: empty.as_ptr(),
127            len: empty.len(),
128            owner: None,
129        }
130    }
131
132    /// Creates `Bytes` from a [`BytesOwner`] (for example, `Vec<u8>`).
133    pub fn from_owner(value: impl AbstractOwner<T>) -> Self {
134        let slice: &T = value.as_ref();
135        let bytes = slice.as_bytes();
136        Self {
137            ptr: bytes.as_ptr(),
138            len: bytes.len(),
139            owner: Some(Arc::new(value)),
140        }
141    }
142
143    /// Creates `Bytes` instance from slice, by copying it.
144    pub fn copy_from_slice(data: &T) -> Self {
145        Self::from_owner(data.to_owned())
146    }
147
148    #[inline]
149    pub(crate) fn as_bytes(&self) -> &[u8] {
150        unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
151    }
152
153    /// Create a weak pointer. Returns `None` if backed by a static buffer.
154    /// Note the weak pointer has the full range of the buffer.
155    pub fn downgrade(&self) -> Option<Weak<dyn AbstractOwner<T>>> {
156        self.owner.as_ref().map(Arc::downgrade)
157    }
158
159    /// The reverse of `downgrade`. Returns `None` if the value was dropped.
160    /// Note the upgraded `Bytes` has the full range of the buffer.
161    pub fn upgrade(weak: &Weak<dyn AbstractOwner<T>>) -> Option<Self> {
162        let arc = weak.upgrade()?;
163        let slice_like: &T = arc.as_ref().as_ref();
164        Some(Self {
165            ptr: slice_like.as_ptr(),
166            len: slice_like.len(),
167            owner: Some(arc),
168        })
169    }
170}
171
172impl Bytes {
173    #[inline]
174    pub(crate) fn as_slice(&self) -> &[u8] {
175        self.as_bytes()
176    }
177
178    /// Creates `Bytes` from a static slice.
179    pub const fn from_static(slice: &'static [u8]) -> Self {
180        Self {
181            ptr: slice.as_ptr(),
182            len: slice.len(),
183            owner: None,
184        }
185    }
186
187    /// Convert to `Vec<u8>`, in a zero-copy way if possible.
188    pub fn into_vec(mut self) -> Vec<u8> {
189        let len = self.len();
190
191        'zero_copy: {
192            let arc_owner = match self.owner.as_mut() {
193                None => break 'zero_copy,
194                Some(owner) => owner,
195            };
196            let owner = match Arc::get_mut(arc_owner) {
197                None => break 'zero_copy,
198                Some(owner) => owner,
199            };
200            let any = owner.as_any_mut();
201            let mut maybe_vec = any.downcast_mut::<Vec<u8>>();
202            match maybe_vec {
203                Some(ref mut owner) if owner.len() == len => {
204                    let mut result: Vec<u8> = Vec::new();
205                    std::mem::swap(&mut result, owner);
206                    return result;
207                }
208                _ => break 'zero_copy,
209            }
210        }
211
212        self.as_slice().to_vec()
213    }
214}
215
216#[cfg(feature = "non-zerocopy-into")]
217impl From<Bytes> for Vec<u8> {
218    fn from(value: Bytes) -> Vec<u8> {
219        value.into_vec()
220    }
221}
222
223pub trait SliceLike: 'static {
224    type Owned;
225    const EMPTY: &'static Self;
226
227    fn as_bytes(&self) -> &[u8];
228    fn to_owned(&self) -> Self::Owned;
229
230    #[inline]
231    fn check_slice_bytes(bytes: &[u8], start: usize, end: usize) {
232        let _ = (bytes, start, end);
233    }
234
235    #[inline]
236    fn len(&self) -> usize {
237        self.as_bytes().len()
238    }
239
240    #[inline]
241    fn as_ptr(&self) -> *const u8 {
242        self.as_bytes().as_ptr()
243    }
244}
245
246impl SliceLike for [u8] {
247    type Owned = Vec<u8>;
248    const EMPTY: &'static Self = b"";
249
250    #[inline]
251    fn as_bytes(&self) -> &[u8] {
252        self
253    }
254    #[inline]
255    fn to_owned(&self) -> Self::Owned {
256        self.to_vec()
257    }
258}