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}