Skip to content

Commit 32dc01d

Browse files
committed
updated docs
added `save_spare` removed `set_len` updated unsized storages
1 parent 9c9968b commit 32dc01d

File tree

4 files changed

+99
-62
lines changed

4 files changed

+99
-62
lines changed

src/lib.rs

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,15 @@ use core::{
160160
mod extension;
161161
mod impls;
162162
mod slice;
163-
// mod set_len;
164163

165164
pub mod iter;
166165
pub mod raw;
167166

168167
use raw::Storage;
169168

169+
#[doc(hidden)]
170+
pub use core;
171+
170172
/// A heap backed vector with a growable capacity
171173
#[cfg(any(doc, feature = "alloc"))]
172174
#[cfg(feature = "nightly")]
@@ -181,7 +183,7 @@ pub type HeapVec<T> = GenericVec<T, raw::Heap<T>>;
181183
#[cfg(any(doc, feature = "nightly"))]
182184
pub type ArrayVec<T, const N: usize> = TypeVec<T, [T; N]>;
183185
/// An slice backed vector backed by potentially uninitialized memory
184-
pub type SliceVec<'a, T> = GenericVec<T, raw::UninitSlice<'a, T>>;
186+
pub type SliceVec<'a, T> = GenericVec<T, &'a mut raw::UninitSlice<T>>;
185187

186188
/// An array backed vector backed by initialized memory
187189
#[cfg(any(doc, feature = "nightly"))]
@@ -286,6 +288,37 @@ macro_rules! uninit_array {
286288
};
287289
}
288290

291+
/// Save the changes to [`GenericVec::spare_capacity_mut`]
292+
///
293+
/// $orig - a mutable reference to a [`GenericVec`]
294+
/// $spare - the [`SliceVec`] that was obtained from [`$orig.spare_capacity_mut()`]
295+
///
296+
/// # Safety
297+
///
298+
/// `$spare` should be the [`SliceVec`] returned by `$orig.spare_capacity_mut()`
299+
#[macro_export]
300+
macro_rules! save_spare {
301+
($spare:expr, $orig:expr) => {{
302+
let spare: $crate::SliceVec<_> = $spare;
303+
let spare = $crate::core::mem::ManuallyDrop::new(spare);
304+
let len = spare.len();
305+
let ptr = spare.as_ptr();
306+
let orig: &mut $crate::GenericVec<_, _> = $orig;
307+
$crate::validate_spare(ptr, orig);
308+
let len = len + orig.len();
309+
$orig.set_len_unchecked(len);
310+
}};
311+
}
312+
313+
#[doc(hidden)]
314+
pub fn validate_spare<T>(spare_ptr: *const T, orig: &[T]) {
315+
debug_assert!(
316+
unsafe { orig.as_ptr().add(orig.len()) == spare_ptr },
317+
"Tried to use `save_spare!` with a `SliceVec` that was not obtained from `GenricVec::spare_capacity_mut`. \
318+
This is undefined behavior on release mode!"
319+
)
320+
}
321+
289322
/// A vector type that can be backed up by a variety of different backends
290323
/// including slices, arrays, and the heap.
291324
#[repr(C)]
@@ -452,13 +485,13 @@ impl<T, A: std::alloc::AllocRef> HeapVec<T, A> {
452485
#[cfg(not(feature = "nightly"))]
453486
impl<'a, T> SliceVec<'a, T> {
454487
/// Create a new empty `SliceVec`
455-
pub fn new(slice: &'a mut [MaybeUninit<T>]) -> Self { Self::with_storage(raw::UninitSlice::new(slice)) }
488+
pub fn new(slice: &'a mut [MaybeUninit<T>]) -> Self { Self::with_storage(raw::UninitSlice::from_mut(slice)) }
456489
}
457490

458491
#[cfg(feature = "nightly")]
459492
impl<'a, T> SliceVec<'a, T> {
460493
/// Create a new empty `SliceVec`
461-
pub const fn new(slice: &'a mut [MaybeUninit<T>]) -> Self { Self::with_storage(raw::UninitSlice::new(slice)) }
494+
pub const fn new(slice: &'a mut [MaybeUninit<T>]) -> Self { Self::with_storage(raw::UninitSlice::from_mut(slice)) }
462495
}
463496

464497
impl<'a, T: Copy> InitSliceVec<'a, T> {
@@ -587,10 +620,28 @@ impl<T, S: ?Sized + Storage<T>> GenericVec<T, S> {
587620
pub unsafe fn storage_mut(&mut self) -> &mut S { &mut self.storage }
588621

589622
/// Returns the remaining spare capacity of the vector as
590-
/// a `SliceVec<'_, T>`.
623+
/// a [`SliceVec<'_, T>`](SliceVec).
591624
///
592-
/// Keep in mind that the `SliceVec<'_, T>` will drop all elements
593-
/// that you push into it!
625+
/// Keep in mind that the [`SliceVec<'_, T>`](SliceVec) will drop all elements
626+
/// that you push into it when it goes out of scope! If you want
627+
/// these modifications to persist then you should use [`save_spare`]
628+
/// to persist these writes.
629+
///
630+
/// ```
631+
/// let mut vec = generic_vec::TypeVec::<i32, [i32; 16]>::new();
632+
///
633+
/// let mut spare = vec.spare_capacity_mut();
634+
/// spare.push(0);
635+
/// spare.push(2);
636+
/// drop(spare);
637+
/// assert_eq!(vec, []);
638+
///
639+
/// let mut spare = vec.spare_capacity_mut();
640+
/// spare.push(0);
641+
/// spare.push(2);
642+
/// unsafe { generic_vec::save_spare!(spare, &mut vec) }
643+
/// assert_eq!(vec, [0, 2]);
644+
/// ```
594645
pub fn spare_capacity_mut(&mut self) -> SliceVec<'_, T> {
595646
// Safety
596647
//
@@ -725,9 +776,7 @@ impl<T, S: ?Sized + Storage<T>> GenericVec<T, S> {
725776
}
726777

727778
unsafe {
728-
let writer = core::mem::ManuallyDrop::new(writer);
729-
let len = writer.len() + self.len();
730-
self.set_len_unchecked(len);
779+
save_spare!(writer, self);
731780
}
732781
}
733782

@@ -1601,7 +1650,7 @@ impl<T, S: ?Sized + Storage<T>> GenericVec<T, S> {
16011650
///
16021651
/// When the iterator is dropped, all elements in the range are removed from
16031652
/// the vector, even if the iterator was not fully consumed. If the iterator
1604-
/// is not dropped (with mem::forget for example), it is unspecified how many
1653+
/// is not dropped (with `mem::forget` for example), it is unspecified how many
16051654
/// elements are removed.
16061655
///
16071656
/// # Panic

src/raw/slice.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,22 @@ use core::mem::{align_of, size_of, MaybeUninit};
44

55
/// An uninitialized slice storage
66
#[repr(transparent)]
7-
pub struct UninitSlice<'a, T>(&'a mut [MaybeUninit<T>]);
7+
pub struct UninitSlice<T>([MaybeUninit<T>]);
88

9-
unsafe impl<T> Send for UninitSlice<'_, T> {}
10-
unsafe impl<T> Sync for UninitSlice<'_, T> {}
9+
unsafe impl<T> Send for UninitSlice<T> {}
10+
unsafe impl<T> Sync for UninitSlice<T> {}
1111

1212
#[cfg(not(feature = "nightly"))]
13-
impl<'a, T> UninitSlice<'a, T> {
13+
impl<T> UninitSlice<T> {
1414
/// Create a new `UninitSlice` storage
15-
pub fn new(buffer: &'a mut [MaybeUninit<T>]) -> Self { Self(buffer) }
16-
17-
/// Reborrow an `UninitSlice` storage
18-
pub fn as_ref(&mut self) -> UninitSlice<'_, T> { UninitSlice(self.0) }
15+
pub fn from_mut(buffer: &mut [MaybeUninit<T>]) -> &mut Self { unsafe { &mut *(buffer as *mut [_] as *mut Self) } }
1916

2017
/// Get the backing value of the this `Uninit` storage
2118
///
2219
/// # Safety
2320
///
2421
/// You may not write uninitialized memory to this slice
25-
pub unsafe fn into_inner(self) -> &'a mut [MaybeUninit<T>] { self.0 }
22+
pub unsafe fn into_mut(&mut self) -> &mut [MaybeUninit<T>] { unsafe { &mut *(self as *mut Self as *mut [_]) } }
2623
}
2724

2825
#[cfg(feature = "nightly")]
@@ -41,7 +38,7 @@ impl<'a, T> UninitSlice<'a, T> {
4138
pub const unsafe fn into_inner(self) -> &'a mut [MaybeUninit<T>] { self.0 }
4239
}
4340

44-
unsafe impl<T, U> Storage<U> for UninitSlice<'_, T> {
41+
unsafe impl<T, U> Storage<U> for UninitSlice<T> {
4542
const IS_ALIGNED: bool = align_of::<T>() >= align_of::<U>();
4643

4744
fn capacity(&self) -> usize { crate::raw::capacity(self.0.len(), size_of::<T>(), size_of::<U>()) }

src/raw/uninit.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! `UninitBuffer` represents some uninitialized memory
2+
//!
3+
14
use core::mem::{align_of, size_of, MaybeUninit};
25

36
use super::{AllocError, Storage, StorageWithCapacity};
@@ -8,10 +11,29 @@ struct AlignedBuffer<T, A> {
811
value: T,
912
}
1013

11-
/// An uninitialized storage
14+
/// An uninitialized storage. This storage can store values
15+
/// of any type that has an alignment smaller of equal to `T` or `A`.
16+
///
17+
/// `UninitBuffer` has a max capacity of
18+
/// `round_up(size_of::<T>(), align_::<A>()) / size_of::<Element>()`
19+
/// elements.
20+
///
21+
/// i.e. `UninitBuffer<[i32; 12]>` can store 12 `i32`s, but
22+
/// `UninitBuffer<[i32; 1], u64>` can store 2 `i32`s. Because `u64 is
23+
/// aligned to 8 bytes, so `round_up(4 bytes, 8 bytes) / 4 bytes == 2`
1224
///
13-
/// This type is represented as, generally the second type parameter can only
14-
/// be used to align the storage
25+
/// You can query the capacity with [`UninitBuffer::capacity`]
26+
///
27+
/// ```rust
28+
/// # use generic_vec::raw::UninitBuffer;
29+
/// assert_eq!(UninitBuffer::<[i32; 12]>::capacity::<i32>(), 12);
30+
/// assert_eq!(UninitBuffer::<[i32; 1], u64>::capacity::<i32>(), 2);
31+
/// assert_eq!(UninitBuffer::<[i32; 1]>::capacity::<u64>(), 0);
32+
/// ```
33+
///
34+
/// ## In memory representation
35+
///
36+
/// This type is represented in memory as
1537
///
1638
/// ```
1739
/// #[repr(C)]
@@ -21,12 +43,10 @@ struct AlignedBuffer<T, A> {
2143
/// }
2244
/// ```
2345
///
24-
/// By default the alignment type is set to `u8`, so that it doesn't get in the way.
25-
/// But if you need a higher alignment, then you can change the second type.
26-
/// This allows you to do things like `UninitBuffer<[u8; 4], u32>` to get a
27-
/// 4 byte aligned buffer of 4 bytes or `UninitBuffer<[CustomType; 12], usize>` to
28-
/// get an array of `CustomType`, and guarantee it is pointer-aligned.
29-
#[repr(C)]
46+
/// The size of the buffer is determined by type paramter `T`, and
47+
/// the alignment is the maximum alignment of `T` and `A`. This means
48+
/// that `A` should be used to ensure a certain alignment.
49+
#[repr(transparent)]
3050
pub struct UninitBuffer<T, A = u8>(MaybeUninit<AlignedBuffer<T, A>>);
3151

3252
unsafe impl<T, A> Send for UninitBuffer<T, A> {}
@@ -41,6 +61,9 @@ const fn size<U, T, A>() -> usize {
4161
}
4262

4363
impl<T, A> UninitBuffer<T, A> {
64+
/// Get the capacity of this buffer for a given element type
65+
pub const fn capacity<U>() -> usize { size::<U, T, A>() }
66+
4467
/// Create a new uninitialized array storage
4568
pub const fn uninit() -> Self { Self(MaybeUninit::uninit()) }
4669

src/set_len.rs

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)