turbo_persistence/
arc_bytes.rs1use std::{
2 borrow::Borrow,
3 fmt::{self, Debug, Formatter},
4 hash::{Hash, Hasher},
5 ops::{Deref, Range},
6 sync::Arc,
7};
8
9#[cfg(feature = "mmap")]
10use memmap2::Mmap;
11
12use crate::{
13 Compression,
14 compression::decompress_into_arc,
15 shared_bytes::{INLINE_CAPACITY, SharedBytes, is_subslice_of},
16};
17#[derive(Clone)]
23enum Repr {
24 Arc {
25 data: *const [u8],
26 _backing: Arc<[u8]>,
27 },
28 #[cfg(feature = "mmap")]
29 Mmap {
30 data: *const [u8],
31 _backing: Arc<Mmap>,
32 },
33 Inline { buf: [u8; INLINE_CAPACITY], len: u8 },
35}
36
37#[derive(Clone)]
40pub struct ArcBytes {
41 repr: Repr,
42}
43
44impl ArcBytes {
45 #[inline]
47 fn backing_bytes(&self) -> Option<&[u8]> {
48 match &self.repr {
49 Repr::Arc { _backing, .. } => Some(_backing),
50 #[cfg(feature = "mmap")]
51 Repr::Mmap { _backing, .. } => Some(_backing),
52 Repr::Inline { .. } => None,
53 }
54 }
55}
56
57unsafe impl Send for ArcBytes {}
58unsafe impl Sync for ArcBytes {}
59
60impl From<Arc<[u8]>> for ArcBytes {
61 fn from(arc: Arc<[u8]>) -> Self {
62 Self {
63 repr: Repr::Arc {
64 data: &*arc as *const [u8],
65 _backing: arc,
66 },
67 }
68 }
69}
70
71impl From<Box<[u8]>> for ArcBytes {
72 fn from(b: Box<[u8]>) -> Self {
73 Self::from(Arc::from(b))
74 }
75}
76
77impl Deref for ArcBytes {
78 type Target = [u8];
79
80 fn deref(&self) -> &Self::Target {
81 match &self.repr {
82 Repr::Arc { data, .. } => unsafe { &**data },
85 #[cfg(feature = "mmap")]
86 Repr::Mmap { data, .. } => unsafe { &**data },
87 Repr::Inline { buf, len } => &buf[..*len as usize],
89 }
90 }
91}
92
93impl Borrow<[u8]> for ArcBytes {
94 fn borrow(&self) -> &[u8] {
95 self
96 }
97}
98
99impl Hash for ArcBytes {
100 fn hash<H: Hasher>(&self, state: &mut H) {
101 self.deref().hash(state)
102 }
103}
104
105impl PartialEq for ArcBytes {
106 fn eq(&self, other: &Self) -> bool {
107 self.deref().eq(other.deref())
108 }
109}
110
111impl Debug for ArcBytes {
112 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
113 Debug::fmt(&**self, f)
114 }
115}
116
117impl Eq for ArcBytes {}
118
119impl ArcBytes {
120 pub fn is_mmap_backed(&self) -> bool {
122 #[cfg(feature = "mmap")]
123 return matches!(self.repr, Repr::Mmap { .. });
124
125 #[cfg(not(feature = "mmap"))]
126 false
127 }
128
129 pub fn is_shared_arc(&self) -> bool {
134 match &self.repr {
135 Repr::Arc { _backing, .. } => Arc::strong_count(_backing) > 1,
136 #[cfg(feature = "mmap")]
137 Repr::Mmap { .. } => false,
138 Repr::Inline { .. } => false,
139 }
140 }
141}
142
143impl SharedBytes for ArcBytes {
144 #[cfg(feature = "mmap")]
145 type MmapHandle = Arc<Mmap>;
146
147 fn slice(self, range: Range<usize>) -> Self {
148 let sliced = &self[range];
149 if let Repr::Inline { .. } = self.repr {
151 return Self::from_inline(sliced);
152 }
153 let data = sliced as *const [u8];
154 Self {
155 repr: match self.repr {
156 Repr::Arc { _backing, .. } => Repr::Arc { data, _backing },
157 #[cfg(feature = "mmap")]
158 Repr::Mmap { _backing, .. } => Repr::Mmap { data, _backing },
159 Repr::Inline { .. } => unreachable!("handled above"),
160 },
161 }
162 }
163
164 unsafe fn slice_from_subslice(&self, subslice: &[u8]) -> Self {
165 if subslice.len() <= INLINE_CAPACITY {
170 return Self::from_inline(subslice);
171 }
172 debug_assert!(
173 self.backing_bytes()
174 .is_some_and(|backing| is_subslice_of(subslice, backing)),
175 "slice_from_subslice: subslice is not within the backing storage"
176 );
177 let data = subslice as *const [u8];
178 Self {
179 repr: match &self.repr {
180 Repr::Arc { _backing, .. } => Repr::Arc {
181 data,
182 _backing: _backing.clone(),
183 },
184 #[cfg(feature = "mmap")]
185 Repr::Mmap { _backing, .. } => Repr::Mmap {
186 data,
187 _backing: _backing.clone(),
188 },
189 Repr::Inline { .. } => return Self::from_inline(subslice),
192 },
193 }
194 }
195
196 #[cfg(feature = "mmap")]
197 unsafe fn from_mmap(mmap: &Arc<Mmap>, subslice: &[u8]) -> Self {
198 debug_assert!(
199 is_subslice_of(subslice, mmap),
200 "from_mmap: subslice is not within the mmap"
201 );
202 ArcBytes {
203 repr: Repr::Mmap {
204 data: subslice as *const [u8],
205 _backing: mmap.clone(),
206 },
207 }
208 }
209
210 fn from_decompressed(
211 compression: Compression,
212 uncompressed_length: u32,
213 block: &[u8],
214 ) -> anyhow::Result<Self> {
215 Ok(ArcBytes::from(decompress_into_arc(
216 compression,
217 uncompressed_length,
218 block,
219 )?))
220 }
221
222 #[inline]
223 fn from_inline(bytes: &[u8]) -> Self {
224 assert!(
225 bytes.len() <= INLINE_CAPACITY,
226 "{} bytes exceeds the {INLINE_CAPACITY} byte inline capacity",
227 bytes.len()
228 );
229 let mut buf = [0u8; INLINE_CAPACITY];
230 buf[..bytes.len()].copy_from_slice(bytes);
231 ArcBytes {
232 repr: Repr::Inline {
233 buf,
234 len: bytes.len() as u8,
235 },
236 }
237 }
238}