1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use core::ptr;
use crate::allocator::AllocatorProvider;
use crate::dynamic::common::limit::LEN_VALUE_MASK_USIZE;
use crate::dynamic::types::DynamicVec;
impl<'a, const N: usize, A> Clone for DynamicVec<'a, N, A>
where
A: AllocatorProvider + Clone,
{
#[inline]
fn clone(&self) -> Self {
if self.is_referenced() {
// Clone Referenced separately to preserve pointer provenance.
// Copying the raw pointer through the InlineVec byte-array
// view strips Miri provenance, causing UB when dereferenced.
let r = unsafe { &*self.0.referenced };
let len = r.len & LEN_VALUE_MASK_USIZE;
// Safety: r.ptr was created from a &'a [u8] in from_referenced,
// so reconstituting the slice with the original lifetime is sound.
let slice = unsafe { core::slice::from_raw_parts(r.ptr, len) };
Self::from_referenced(slice, r.allocator.clone())
} else if self.is_inline() {
Self::from_inline(unsafe { (*self.0.inline).clone() })
} else {
Self::from_eco(unsafe { (*self.0.spilled).clone() })
}
}
}
impl<const N: usize, A> Drop for DynamicVec<'_, N, A>
where
A: AllocatorProvider,
{
#[inline]
fn drop(&mut self) {
// `is_inline()` returns true for both Inline and Referenced variants
// (both have bit 7 set in tagged_len), so `!is_inline()` identifies
// exactly the Spilled variant. This avoids the full 3-way variant
// dispatch that `variant_mut()` performs (saving one branch).
if !self.is_inline() {
unsafe {
// Safety: We are guaranteed to have a valid `EcoVec`.
ptr::drop_in_place(&mut *self.0.spilled);
}
}
// Inline and Referenced don't own heap memory that needs dropping.
// The allocator field inside ManuallyDrop is not dropped, but
// Global (the typical allocator) is a ZST with no Drop impl.
}
}
impl<const N: usize, A> PartialEq for DynamicVec<'_, N, A>
where
A: AllocatorProvider,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
// is_inline() is true for both Inline and Referenced (bit 7 set).
// !is_inline() identifies exactly the Spilled variant.
let si = self.is_inline();
let oi = other.is_inline();
if !si & !oi {
// Both Spilled: EcoVec::PartialEq has a pointer-identity
// fast-path for clones that share the same backing allocation.
unsafe { *self.0.spilled == *other.0.spilled }
} else {
// At least one operand is Inline or Referenced: compare by
// content. A raw-byte comparison is unsound here because
// (1) inline tail bytes `[len..N)` are not guaranteed zero after
// shrinking ops (`truncate`, `clear`), and
// (2) Inline and Referenced encode the same content with different
// bytes (an inline buffer vs. a pointer + length),
// so equal-content values can have differing raw bytes.
self.as_slice() == other.as_slice()
}
}
}
impl<const N: usize, A> Eq for DynamicVec<'_, N, A> where A: AllocatorProvider {}
impl<const N: usize, A> core::fmt::Debug for DynamicVec<'_, N, A>
where
A: AllocatorProvider,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("DynamicVec")
.field("referenced", &self.is_referenced())
.field("inline", &self.is_inline())
.field("len", &self.len())
.field("data", &self.as_slice())
.finish()
}
}