byte_slab/
slab_slice_arc.rs

1//! A reference counted, partial view of an allocation
2//!
3//! A `SlabSliceArc` is used to provide a view onto a portion of a `SlabArc`,
4//! without sharing the entire allocation. It shares the same reference count
5//! as the underlying `SlabArc`, meaning the underlying `SlabArc` will not be
6//! freed if there are only `SlabSliceArc`s remaining. The underlying memory
7//! is freed for reuse automatically when the reference count reaches zero.
8
9use core::ops::Deref;
10
11use crate::slab_arc::SlabArc;
12use core::str::{from_utf8_unchecked, from_utf8, Utf8Error};
13
14// TODO: This doesn't HAVE to be 'static, but it makes my life easier
15// if you want not-that, I guess open an issue and let me know?
16/// A partial view, reference counted, BSlab allocated chunk of bytes.
17///
18/// `SlabSliceArc`s implement the `Deref` trait for access to the
19/// underlying allocation
20///
21/// ## Example
22///
23/// ```rust
24/// use byte_slab::BSlab;
25/// use std::thread::spawn;
26///
27/// static SLAB: BSlab<4, 128> = BSlab::new();
28///
29/// fn main() {
30///     // Initialize the byte slab
31///     SLAB.init().unwrap();
32///
33///     let mut box_1 = SLAB.alloc_box().unwrap();
34///
35///     // Fill
36///     assert_eq!(box_1.len(), 128);
37///     box_1.iter_mut().enumerate().for_each(|(i, x)| *x = i as u8);
38///
39///     // Convert the Box into an Arc for sharing
40///     let arc_1 = box_1.into_arc();
41///
42///     // And we can cheaply take a subslice of the parent
43///     let sub_arc_1 = arc_1.sub_slice_arc(64, 64).unwrap();
44///
45///     // We can now send the sub-slice arc to another thread
46///     let hdl = spawn(move || {
47///         assert_eq!(sub_arc_1.len(), 64);
48///         sub_arc_1.iter().enumerate().for_each(|(i, x)| assert_eq!(i as u8 + 64, *x));
49///     });
50///
51///     // ... while still retaining a local handle to the same data
52///     arc_1.iter().enumerate().for_each(|(i, x)| assert_eq!(i as u8, *x));
53///
54///     hdl.join();
55/// }
56/// ```
57#[derive(Clone)]
58pub struct SlabSliceArc<const N: usize, const SZ: usize> {
59    pub(crate) arc: SlabArc<N, SZ>,
60    pub(crate) start: usize,
61    pub(crate) len: usize,
62}
63
64impl<const N: usize, const SZ: usize> Deref for SlabSliceArc<N, SZ> {
65    type Target = [u8];
66
67    fn deref(&self) -> &Self::Target {
68        // thanks mara for the cleaner slice syntax!
69        &self.arc.deref()[self.start..][..self.len]
70    }
71}
72
73impl<const N: usize, const SZ: usize> SlabSliceArc<N, SZ> {
74    /// Create a (smaller) `SlabSliceArc` from this `SlabSliceArc`, with a partial view
75    /// of the underlying data.
76    ///
77    /// This function will fail if `start` and `len` do not describe a valid
78    /// region of the `SlabSliceArc`.
79    pub fn sub_slice_arc(&self, start: usize, len: usize) -> Result<SlabSliceArc<N, SZ>, ()> {
80        let new_arc = self.arc.clone();
81
82        // Offset inside of our own slice
83        let start = self.start + start;
84
85        let new_end = self.start + self.len;
86        let good_start = start < new_end;
87        let good_len = (start + len) <= new_end;
88
89        if good_start && good_len {
90            let new_slice_arc = SlabSliceArc {
91                arc: new_arc,
92                start,
93                len,
94            };
95
96            Ok(new_slice_arc)
97        } else {
98            Err(())
99        }
100    }
101
102    /// Convert the current `SlabSliceArc` into a `SlabStrArc`.
103    ///
104    /// If the contained bytes do not constitute a valid UTF-8 string, an
105    /// error will be returned.
106    ///
107    /// Note, regardless of success, this function will consume the Slab Arc.
108    /// If this is not desired, consider using [SlabStrArc::from_slab_slice()](SlabStrArc::from_slab_slice())
109    /// instead.
110    pub fn into_str_arc(self) -> Result<SlabStrArc<N, SZ>, Utf8Error> {
111        let _str = from_utf8(&self)?;
112        Ok(SlabStrArc { inner: self })
113    }
114}
115
116/// A partial view, reference counted, BSlab allocated string slice
117///
118/// `SlabStrArc`s implement the `Deref` trait for access to the
119/// underlying allocation as a &str.
120///
121/// ## Example
122///
123/// ```rust
124/// use byte_slab::BSlab;
125/// use std::thread::spawn;
126/// use core::ops::Deref;
127///
128/// static SLAB: BSlab<4, 128> = BSlab::new();
129///
130/// fn main() {
131///     // Initialize the byte slab
132///     SLAB.init().unwrap();
133///
134///     let mut box_1 = SLAB.alloc_box().unwrap();
135///
136///     // Fill
137///     assert_eq!(box_1.len(), 128);
138///     let msg = "Hello, 🌍!";
139///     let msg_len = msg.as_bytes().len();
140///     box_1[..msg_len].copy_from_slice(msg.as_bytes());
141///
142///     // Convert the Box into an Arc for sharing
143///     let arc_1 = box_1.into_arc();
144///
145///     // And we can turn this into an ArcStr
146///     let sub_arc_1 = arc_1
147///         .sub_slice_arc(0, msg_len)
148///         .unwrap()
149///         .into_str_arc()
150///         .unwrap();
151///
152///     // We can now send the sub-slice arc to another thread
153///     let hdl = spawn(move || {
154///         assert_eq!(sub_arc_1.len(), msg_len);
155///         assert_eq!(sub_arc_1.deref(), msg);
156///     });
157///
158///     // ... while still retaining a local handle to the same data
159///     assert_eq!(&arc_1[..msg_len], msg.as_bytes());
160///
161///     hdl.join();
162/// }
163/// ```
164#[derive(Clone)]
165pub struct SlabStrArc<const N: usize, const SZ: usize> {
166    pub(crate) inner: SlabSliceArc<N, SZ>,
167}
168
169impl<const N: usize, const SZ: usize> PartialEq<str> for SlabStrArc<N, SZ> {
170    fn eq(&self, other: &str) -> bool {
171        let stir: &str = self.deref();
172        stir.eq(other)
173    }
174}
175
176impl<const N: usize, const SZ: usize> PartialEq for SlabStrArc<N, SZ> {
177    fn eq(&self, other: &Self) -> bool {
178        let stir_me: &str = self.deref();
179        let stir_ot: &str = other.deref();
180        stir_me.eq(stir_ot)
181    }
182}
183
184impl<const N: usize, const SZ: usize> Eq for SlabStrArc<N, SZ> { }
185
186impl<const N: usize, const SZ: usize> Deref for SlabStrArc<N, SZ> {
187    type Target = str;
188
189    fn deref(&self) -> &Self::Target {
190        let slice: &[u8] = &self.inner;
191
192        // SAFETY: `SlabStrArc`s are checked on creation
193        unsafe {
194            from_utf8_unchecked(slice)
195        }
196    }
197}
198
199impl<const N: usize, const SZ: usize> SlabStrArc<N, SZ> {
200    /// Convert the given `SlabSliceArc` into a `SlabStrArc`.
201    ///
202    /// If the contained bytes do not constitute a valid UTF-8 string, an
203    /// error will be returned. Unlike [SlabSliceArc::into_str_arc()](SlabSliceArc::into_str_arc()),
204    /// this function does not consume the slice, instead cloning the underlying Arc.
205    pub fn from_slab_slice(other: &SlabSliceArc<N, SZ>) -> Result<Self, Utf8Error> {
206        let clone = other.clone();
207        clone.into_str_arc()
208    }
209}