James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame^] | 1 | use std::ops::{Deref, Range}; |
| 2 | |
| 3 | /// The underlying buffer that is used by a flexbuffer Reader. |
| 4 | /// |
| 5 | /// This allows for custom buffer implementations as long as they can be viewed as a &[u8]. |
| 6 | pub trait Buffer: Deref<Target = [u8]> + Sized { |
| 7 | // The `BufferString` allows for a buffer to return a custom string which will have the |
| 8 | // lifetime of the underlying buffer. A simple `std::str::from_utf8` wouldn't work since that |
| 9 | // returns a &str, which is then owned by the callee (cannot be returned from a function). |
| 10 | // |
| 11 | // Example: During deserialization a `BufferString` is returned, allowing the deserializer |
| 12 | // to "borrow" the given str - b/c there is a "lifetime" guarantee, so to speak, from the |
| 13 | // underlying buffer. |
| 14 | /// A BufferString which will live at least as long as the Buffer itself. |
| 15 | /// |
| 16 | /// Deref's to UTF-8 `str`, and only generated from the `buffer_str` function Result. |
| 17 | type BufferString: Deref<Target = str> + Sized + serde::ser::Serialize; |
| 18 | |
| 19 | /// This method returns an instance of type Self. This allows for lifetimes to be tracked |
| 20 | /// in cases of deserialization. |
| 21 | /// |
| 22 | /// It also lets custom buffers manage reference counts. |
| 23 | /// |
| 24 | /// Returns None if: |
| 25 | /// - range start is greater than end |
| 26 | /// - range end is out of bounds |
| 27 | /// |
| 28 | /// This operation should be fast -> O(1), ideally with no heap allocations. |
| 29 | fn slice(&self, range: Range<usize>) -> Option<Self>; |
| 30 | |
| 31 | /// Creates a shallow copy of the given buffer, similar to `slice`. |
| 32 | /// |
| 33 | /// This operation should be fast -> O(1), ideally with no heap allocations. |
| 34 | #[inline] |
| 35 | fn shallow_copy(&self) -> Self { |
| 36 | self.slice(0..self.len()).unwrap() |
| 37 | } |
| 38 | |
| 39 | /// Creates an empty instance of a `Buffer`. This is different than `Default` b/c it |
| 40 | /// guarantees that the buffer instance will have length zero. |
| 41 | /// |
| 42 | /// Most impls shold be able to implement this via `Default`. |
| 43 | fn empty() -> Self; |
| 44 | |
| 45 | /// Based off of the `empty` function, allows override for optimization purposes. |
| 46 | #[inline] |
| 47 | fn empty_str() -> Self::BufferString { |
| 48 | Self::empty().buffer_str().unwrap() |
| 49 | } |
| 50 | |
| 51 | /// Attempts to convert the given buffer to a custom string type. |
| 52 | /// |
| 53 | /// This should fail if the type does not have valid UTF-8 bytes, and must be zero copy. |
| 54 | fn buffer_str(&self) -> Result<Self::BufferString, std::str::Utf8Error>; |
| 55 | } |
| 56 | |
| 57 | impl<'de> Buffer for &'de [u8] { |
| 58 | type BufferString = &'de str; |
| 59 | |
| 60 | #[inline] |
| 61 | fn slice(&self, range: Range<usize>) -> Option<Self> { |
| 62 | self.get(range) |
| 63 | } |
| 64 | |
| 65 | #[inline] |
| 66 | fn empty() -> Self { |
| 67 | &[] |
| 68 | } |
| 69 | |
| 70 | /// Based off of the `empty` function, allows override for optimization purposes. |
| 71 | #[inline] |
| 72 | fn empty_str() -> Self::BufferString { |
| 73 | &"" |
| 74 | } |
| 75 | |
| 76 | #[inline] |
| 77 | fn buffer_str(&self) -> Result<Self::BufferString, std::str::Utf8Error> { |
| 78 | std::str::from_utf8(self) |
| 79 | } |
| 80 | } |