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