hipstr/bytes/raw/
allocated.rs

1//! Allocated representation.
2
3use alloc::vec::Vec;
4use core::marker::PhantomData;
5use core::mem::{forget, ManuallyDrop, MaybeUninit};
6use core::ops::{Deref, DerefMut, Range};
7use core::panic::{RefUnwindSafe, UnwindSafe};
8use core::ptr::NonNull;
9
10use crate::backend::Backend;
11use crate::smart::{Inner, Smart, UpdateResult};
12
13const MASK: usize = super::MASK as usize;
14const TAG: usize = super::TAG_ALLOCATED as usize;
15
16/// Tagged smart pointer (with forced exposed provenance).
17///
18/// The exposed provenance is required to cast [`Allocated`] from and to the
19/// [`Pivot`](super::Pivot) representation.
20struct TaggedSmart<B: Backend>(usize, PhantomData<Smart<Vec<u8>, B>>);
21
22// Manual implementation of Clone and Copy traits to avoid requiring additional
23// trait bounds on the generic parameter B
24
25impl<B: Backend> Clone for TaggedSmart<B> {
26    #[cfg_attr(coverage_nightly, coverage(off))]
27    fn clone(&self) -> Self {
28        *self
29    }
30}
31
32impl<B: Backend> Copy for TaggedSmart<B> {}
33
34impl<B: Backend> TaggedSmart<B> {
35    /// Constructed a tagged smart pointer from a [`Smart`].
36    #[inline]
37    fn from(raw: Smart<Vec<u8>, B>) -> Self {
38        let ptr = raw.into_raw().as_ptr();
39        debug_assert!(ptr.is_aligned());
40        debug_assert!((ptr as usize) & MASK == 0);
41
42        // SAFETY: add a 2-bit tag to a non-null pointer with the same alignment
43        // requirement as usize (typically 4 bytes on 32-bit architectures, and
44        // more on 64-bit architectures)
45        let addr = ptr.map_addr(|addr| addr | TAG).expose_provenance();
46
47        Self(addr, PhantomData)
48    }
49
50    /// Converts back into the [`Smart`].
51    #[inline]
52    fn into(self) -> Smart<Vec<u8>, B> {
53        let this: Smart<Vec<u8>, B>;
54
55        debug_assert!(self.0 & MASK == TAG);
56
57        // SAFETY: remove a 2-bit tag to a non-null pointer with the same
58        // alignment as usize (typically 4 on 32-bit architectures, and
59        // more on 64-bit architectures)
60        unsafe {
61            let new_ptr = core::ptr::with_exposed_provenance_mut::<Inner<Vec<u8>, B>>(self.0 ^ TAG);
62
63            debug_assert!(!new_ptr.is_null());
64
65            #[cfg(miri)]
66            let _ = &*new_ptr; // check provenance early
67
68            this = Smart::from_raw(NonNull::new_unchecked(new_ptr));
69        }
70
71        this
72    }
73
74    /// Checks if the tag is valid.
75    #[inline]
76    const fn check_tag(self) -> bool {
77        self.0 & MASK == TAG
78    }
79
80    /// Explicitly clones this tagged smart pointer.
81    fn explicit_clone(self) -> Self {
82        let r = ManuallyDrop::new(self.into());
83        Self::from((*r).clone())
84    }
85}
86
87/// Allocated representation.
88///
89/// # Warning!
90///
91/// For big-endian platform, the owner pointer is **after** the slice.
92/// For little-endian platform, the owner pointer is **before** the slice.
93#[repr(C)]
94pub struct Allocated<B: Backend> {
95    #[cfg(target_endian = "little")]
96    /// Tagged smart pointer of the owning vector
97    owner: TaggedSmart<B>,
98
99    /// Pointer to the slice's start
100    ptr: *const u8,
101
102    /// Length of the slice
103    len: usize,
104
105    #[cfg(target_endian = "big")]
106    /// Tagged smart pointer of the owning vector
107    owner: TaggedSmart<B>,
108}
109
110impl<B: Backend> Copy for Allocated<B> {}
111
112impl<B: Backend> Clone for Allocated<B> {
113    #[cfg_attr(coverage_nightly, coverage(off))]
114    fn clone(&self) -> Self {
115        *self
116    }
117}
118
119unsafe impl<B: Backend + Sync> Sync for Allocated<B> {}
120
121unsafe impl<B: Backend + Send> Send for Allocated<B> {}
122
123impl<B: Backend + Unpin> Unpin for Allocated<B> {}
124
125impl<B: Backend + UnwindSafe> UnwindSafe for Allocated<B> {}
126
127impl<B: Backend + RefUnwindSafe> RefUnwindSafe for Allocated<B> {}
128
129impl<B: Backend> Allocated<B> {
130    /// Converts the allocated representation into its owner.
131    fn into_owner(self) -> Smart<Vec<u8>, B> {
132        self.owner.into()
133    }
134
135    /// Returns a reference to the owner.
136    ///
137    /// This function abuses the [`Copy`]-ness of [`Allocated`] to get a copy
138    /// (and not a clone) of the [`Smart`] reference wrapped in [`ManuallyDrop`]
139    /// to ensure it's not dropped.
140    fn owner(&self) -> impl Deref<Target = Smart<Vec<u8>, B>> {
141        ManuallyDrop::new(self.into_owner())
142    }
143
144    /// Returns a mutable reference to the owner.
145    ///
146    /// This function abuses the [`Copy`]-ness of [`Allocated`] to get a copy
147    /// (and not a clone) of the [`Smart`] reference wrapped in [`ManuallyDrop`]
148    /// to ensure it's not dropped.
149    ///
150    /// # Safety
151    ///
152    /// The owner must not be shared, cf. [`Self::is_unique`].
153    unsafe fn owner_mut(&mut self) -> impl DerefMut<Target = Smart<Vec<u8>, B>> {
154        debug_assert!(self.is_unique());
155        ManuallyDrop::new(self.into_owner())
156    }
157
158    /// Creates an allocated from a vector.
159    ///
160    /// Takes ownership of the vector without copying the data.
161    #[inline]
162    pub fn new(v: Vec<u8>) -> Self {
163        let ptr = v.as_ptr();
164        let len = v.len();
165        let owner = Smart::new(v);
166
167        let this = Self {
168            ptr,
169            len,
170            owner: TaggedSmart::from(owner),
171        };
172
173        debug_assert!(this.is_unique());
174
175        this
176    }
177
178    /// Creates an allocated vector from a slice.
179    pub fn from_slice(slice: &[u8]) -> Self {
180        Self::new(slice.to_vec())
181    }
182
183    /// Returns the length of this allocated string.
184    #[inline]
185    pub const fn len(&self) -> usize {
186        // NOTE: must be const to be used in `HipByt::len` even if there is no
187        // way the allocated representation will be used in the const case
188
189        // debug_assert!(self.is_valid()); // not const
190
191        self.len
192    }
193
194    /// Returns as a byte slice.
195    #[inline]
196    pub const fn as_slice(&self) -> &[u8] {
197        // NOTE: must be const to be used in `HipByt::as_slice` even if there is no
198        // way the allocated representation will be used in the const case
199
200        // debug_assert!(self.is_valid()); // not const
201
202        // SAFETY: Type invariant
203        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
204    }
205
206    /// Returns a raw pointer to the first element.
207    #[inline]
208    pub const fn as_ptr(&self) -> *const u8 {
209        // NOTE: must be const to be used in `HipByt::as_ptr` even if there is no way
210        // the allocated representation will be used in the const case
211
212        // debug_assert!(self.is_valid()); // is_valid is not const!
213        self.ptr
214    }
215
216    /// Returns a mutable raw pointer to the first element if this sequence is
217    /// not shared, `None` otherwise.
218    #[inline]
219    #[allow(clippy::needless_pass_by_ref_mut)]
220    pub fn as_mut_ptr(&mut self) -> Option<*mut u8> {
221        if self.is_unique() {
222            Some(self.ptr.cast_mut())
223        } else {
224            None
225        }
226    }
227
228    /// Returns a mutable raw pointer to the first element.
229    ///
230    /// # Safety
231    ///
232    /// The caller must ensure that the `Allocated` is actually uniquely shared.
233    #[inline]
234    #[allow(clippy::needless_pass_by_ref_mut)]
235    pub unsafe fn as_mut_ptr_unchecked(&mut self) -> *mut u8 {
236        debug_assert!(self.is_unique());
237        self.ptr.cast_mut()
238    }
239
240    /// Returns a mutable slice if possible (unique owned reference).
241    #[inline]
242    pub fn as_mut_slice(&mut self) -> Option<&mut [u8]> {
243        if self.is_unique() {
244            // SAFETY:
245            // * unique -> no one else can "see" the string
246            // * type invariant -> valid slice
247            Some(unsafe { self.as_mut_slice_unchecked() })
248        } else {
249            None
250        }
251    }
252
253    /// Returns a mutable slice.
254    ///
255    /// # Safety
256    ///
257    /// The caller must ensure that the `Allocated` is actually uniquely shared.
258    #[inline]
259    pub unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [u8] {
260        debug_assert!(self.is_valid());
261        debug_assert!(self.is_unique());
262
263        unsafe { core::slice::from_raw_parts_mut(self.ptr.cast_mut(), self.len) }
264    }
265
266    /// Creates a new `Allocated` for some range with the same owner.
267    ///
268    /// # Safety
269    ///
270    /// Range must be a range `a..b` such that `a <= b <= len`.
271    #[inline]
272    pub unsafe fn slice_unchecked(&self, range: Range<usize>) -> Self {
273        debug_assert!(self.is_valid());
274        debug_assert!(range.start <= range.end);
275        debug_assert!(range.start <= self.len);
276        debug_assert!(range.end <= self.len);
277
278        let owner = self.owner.explicit_clone();
279
280        // SAFETY: type invariant -> self.ptr..self.ptr+self.len is valid
281        // also Rust like C specify you can move to the last + 1
282        let ptr = unsafe { self.ptr.add(range.start) };
283
284        Self {
285            ptr,
286            len: range.len(),
287            owner,
288        }
289    }
290
291    /// Clones this vector.
292    #[inline]
293    pub fn explicit_clone(&self) -> Self {
294        debug_assert!(self.is_valid());
295
296        let owner = self.owner();
297        if owner.incr() == UpdateResult::Overflow {
298            Self::from_slice(self.as_slice())
299        } else {
300            *self
301        }
302    }
303
304    /// Drops this vector explicitly.
305    #[inline]
306    pub fn explicit_drop(self) {
307        debug_assert!(self.is_valid());
308        let _ = self.into_owner();
309    }
310
311    /// Return `true` iff this representation is valid.
312    #[inline]
313    #[cfg_attr(coverage_nightly, coverage(off))]
314    pub fn is_valid(&self) -> bool {
315        if !self.owner.check_tag() {
316            return false;
317        }
318
319        let owner = self.owner();
320        let owner_ptr = owner.as_ptr();
321        let shift = unsafe { self.ptr.offset_from(owner_ptr) };
322        shift >= 0 && {
323            #[allow(clippy::cast_sign_loss)]
324            let shift = shift as usize;
325            shift <= owner.len() && shift + self.len <= owner.len()
326        }
327    }
328
329    /// Returns the backend capacity.
330    #[inline]
331    pub fn capacity(&self) -> usize {
332        debug_assert!(self.is_valid());
333
334        self.owner().capacity()
335    }
336
337    /// Unwraps the inner vector if it makes any sense.
338    #[inline]
339    pub fn try_into_vec(self) -> Result<Vec<u8>, Self> {
340        debug_assert!(self.is_valid());
341
342        let owner = self.owner();
343        if self.ptr != owner.as_ptr() {
344            // the starts differ, cannot truncate
345            return Err(self);
346        }
347
348        let len = self.len();
349
350        self.into_owner().try_unwrap().map_or_else(
351            |owner| {
352                forget(owner); // do not drop
353                Err(self)
354            },
355            |mut owner| {
356                owner.truncate(len);
357                Ok(owner)
358            },
359        )
360    }
361
362    /// Returns `true` if there is only one reference to the underlying vector.
363    pub fn is_unique(&self) -> bool {
364        debug_assert!(self.is_valid());
365
366        self.owner().is_unique()
367    }
368
369    /// Pushes a slice at the end of the underlying vector.
370    ///
371    /// # Safety
372    ///
373    /// The reference must be unique, cf. [`Self::is_unique`].
374    pub unsafe fn push_slice_unchecked(&mut self, addition: &[u8]) {
375        debug_assert!(self.is_valid());
376
377        // SAFETY: unique by precondition
378        let mut owner = unsafe { self.owner_mut() };
379
380        // SAFETY: unique by precondition
381        let v = unsafe { owner.as_mut_unchecked() };
382
383        // SAFETY: compute the shift from within the vector range (type invariant)
384        #[allow(clippy::cast_sign_loss)]
385        let shift = unsafe { self.ptr.offset_from(v.as_ptr()) as usize };
386        v.truncate(shift + self.len);
387        v.extend_from_slice(addition);
388        self.len += addition.len();
389
390        // SAFETY: shift to within the vector range (the shift was already
391        // in the old range).
392        self.ptr = unsafe { v.as_ptr().add(shift) };
393    }
394
395    /// Returns the remaining spare capacity of the unique vector as a slice of
396    /// `MaybeUnit<u8>`. If the vector is actually shared, returns an empty
397    /// slice.
398    ///
399    /// The returned slice can be used to fill the vector with data (e.g. by
400    /// reading from a file) before marking the data as initialized using the
401    /// `set_len` method.
402    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
403        debug_assert!(self.is_valid());
404
405        if !self.is_unique() {
406            return &mut [];
407        }
408
409        // SAFETY: unique checked above
410        let mut owner = unsafe { self.owner_mut() };
411
412        // SAFETY: lifetime is extended to `'_` only
413        let v = unsafe { owner.as_mut_unchecked_extended() };
414
415        // SAFETY: computes the shift from within the vector range (type
416        // invariant)
417        #[allow(clippy::cast_sign_loss)]
418        let start = unsafe { self.ptr.offset_from(v.as_ptr()) as usize };
419
420        // truncates to the actual used length without shrinking
421        v.truncate(start + self.len);
422
423        v.spare_capacity_mut()
424    }
425
426    /// Forces the length of the vector to `new_len`.
427    ///
428    /// # Safety
429    ///
430    /// Either:
431    /// 1. `new_len` is less than or equal to the current length, in which case
432    ///    this truncates the vector, or
433    /// 2. All of these conditions must be met:
434    ///    - `new_len` is greater than `capacity()`
435    ///    - The elements at `old_len..new_len` must be properly initialized
436    ///    - The vector must be uniquely owned (not shared)
437    ///
438    /// Failing to meet these safety requirements can lead to undefined
439    /// behavior.
440    pub unsafe fn set_len(&mut self, new_len: usize) {
441        if new_len <= self.len {
442            self.len = new_len;
443            return;
444        }
445
446        debug_assert!(self.is_unique());
447        debug_assert!(new_len <= self.capacity());
448
449        // SAFETY: uniqueness is a precondition
450        let mut owner = unsafe { self.owner_mut() };
451
452        // SAFETY: uniqueness is a precondition
453        let v = unsafe { owner.as_mut_unchecked() };
454
455        // SAFETY: compute the shift from within the vector range (type invariant)
456        #[allow(clippy::cast_sign_loss)]
457        let start = unsafe { self.ptr.offset_from(v.as_ptr()).abs_diff(0) };
458        unsafe { v.set_len(start + new_len) };
459        self.len = new_len;
460    }
461
462    /// Shrinks the capacity of the underlying vector as close as possible to
463    /// `min_capacity`.
464    ///
465    /// The capacity will not shrink below the length of the vector or the
466    /// supplied minimum capacity. That is, if the current capacity is less than
467    /// or equal to the minimum capacity, no shrinking is done.
468    pub fn shrink_to(&mut self, min_capacity: usize) {
469        let min_capacity = min_capacity.max(self.len);
470
471        if self.capacity() <= min_capacity {
472            return;
473        }
474
475        let mut new_vec = Vec::with_capacity(min_capacity);
476        new_vec.extend_from_slice(self.as_slice());
477        let old = core::mem::replace(self, Self::new(new_vec));
478        old.explicit_drop();
479    }
480}
481
482#[cfg(test)]
483mod tests {
484    use alloc::vec;
485
486    use super::Allocated;
487    use crate::Rc;
488
489    #[test]
490    fn test_alloc() {
491        let allocated = Allocated::<Rc>::new(vec![]);
492        let _ = allocated.explicit_drop();
493    }
494
495    #[test]
496    #[cfg_attr(coverage_nightly, coverage(off))]
497    fn test_try_into_vec() {
498        let allocated = Allocated::<Rc>::new(vec![0, 1, 2]);
499        assert_eq!(allocated.owner().ref_count(), 1);
500
501        {
502            let slice = unsafe { allocated.slice_unchecked(1..2) };
503
504            assert_eq!(allocated.owner().ref_count(), 2);
505            let Err(allocated) = slice.try_into_vec() else {
506                panic!("shared reference cannot be converted to vec")
507            };
508            allocated.explicit_drop();
509        }
510
511        assert_eq!(allocated.owner().ref_count(), 1);
512
513        assert!(allocated.try_into_vec().is_ok());
514    }
515}