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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! Single DST stored inline
use core::{marker, mem, ops, ptr};
/// Stack-allocated dynamically sized type
///
/// `T` is the unsized type contained.
/// `D` is the buffer used to hold the unsized type (both data and metadata).
pub struct ValueA<T: ?Sized, D: ::DataBuf> {
_pd: marker::PhantomData<T>,
// Data contains the object data first, then padding, then the pointer information
data: D,
}
impl<T: ?Sized, D: ::DataBuf> ValueA<T, D> {
/// Construct a stack-based DST
///
/// Returns Ok(dst) if the allocation was successful, or Err(val) if it failed
#[cfg(feature = "unsize")]
pub fn new<U: marker::Unsize<T>>(val: U) -> Result<ValueA<T, D>, U>
where
(U, D::Inner): crate::AlignmentValid,
D: Default,
{
Self::new_stable(val, |p| p)
}
/// Construct a stack-based DST using a pre-constructed buffer
///
/// Returns `Ok(dst)` if the allocation was successful, or `Err(val)` if it failed
#[cfg(feature = "unsize")]
pub fn in_buffer<U: marker::Unsize<T>>(buffer: D, val: U) -> Result<ValueA<T, D>, U>
where
(U, D::Inner): crate::AlignmentValid,
{
Self::in_buffer_stable(buffer, val, |p| p)
}
/// Construct a stack-based DST (without needing `Unsize`)
///
/// Returns `Ok(dst)` if the allocation was successful, or `Err(val)` if it failed
pub fn new_stable<U, F: FnOnce(&U) -> &T>(val: U, get_ref: F) -> Result<ValueA<T, D>, U>
where
(U, D::Inner): crate::AlignmentValid,
D: Default,
{
Self::in_buffer_stable(D::default(), val, get_ref)
}
/// Construct a stack-based DST (without needing `Unsize`)
///
/// Returns `Ok(dst)` if the allocation was successful, or `Err(val)` if it failed
pub fn in_buffer_stable<U, F: FnOnce(&U) -> &T>(
buffer: D,
val: U,
get_ref: F,
) -> Result<ValueA<T, D>, U>
where
(U, D::Inner): crate::AlignmentValid,
{
<(U, D::Inner) as crate::AlignmentValid>::check();
let rv = unsafe {
let mut ptr: *const _ = crate::check_fat_pointer(&val, get_ref);
let words = super::ptr_as_slice(&mut ptr);
ValueA::new_raw(
&words[1..],
words[0] as *mut (),
mem::size_of::<U>(),
buffer,
)
};
match rv {
Some(r) => {
// Prevent the destructor from running, now that we've copied it away
mem::forget(val);
Ok(r)
}
None => Err(val),
}
}
#[cfg(all(feature = "alloc", feature = "unsize"))]
/// Construct a stack-based DST, falling back on boxing if the value doesn't fit
///
/// ```
/// # extern crate core;
/// use stack_dst::ValueA;
/// use core::fmt::Debug;
/// let val = [1usize, 2, 3, 4];
/// assert!( ValueA::<dyn Debug, [usize; 2]>::new(val).is_err() );
/// let v = ValueA::<dyn Debug, [usize; 2]>::new_or_boxed(val);
/// println!("v = {:?}", v);
/// ```
pub fn new_or_boxed<U>(val: U) -> ValueA<T, D>
where
U: marker::Unsize<T>,
::alloc::boxed::Box<U>: marker::Unsize<T>,
D: Default,
{
Self::new(val).unwrap_or_else(|val| {
Self::new(Box::new(val))
.ok()
.expect("Insufficient space for Box<T>")
})
}
/// UNSAFE: `data` must point to `size` bytes, which shouldn't be freed if `Some` is returned
pub unsafe fn new_raw(
info: &[usize],
data: *mut (),
size: usize,
buffer: D,
) -> Option<ValueA<T, D>> {
if info.len() * mem::size_of::<usize>() + size > mem::size_of::<D>() {
None
} else {
let mut rv = ValueA {
_pd: marker::PhantomData,
data: buffer,
};
assert!(info.len() + D::round_to_words(size) <= rv.data.as_ref().len());
// Place pointer information at the end of the region
// - Allows the data to be at the start for alignment purposes
{
let info_ofs = rv.data.as_ref().len() - info.len();
let info_dst = &mut rv.data.as_mut()[info_ofs..];
crate::store_metadata(info_dst, info);
}
let src_ptr = data as *const u8;
let dataptr = rv.data.as_mut()[..].as_mut_ptr() as *mut u8;
for i in 0..size {
*dataptr.add(i) = *src_ptr.add(i);
}
Some(rv)
}
}
#[cfg(false_)]
#[cfg(feature = "unsize")]
// TODO: A function to replace the contents (reusing a non-trivial buffer)
pub fn replace<U>(&mut self, val: U) -> Result<(), U> {
// Check size requirements (allow resizing)
// If met, drop the existing item and move in the new item
}
/// Obtain raw pointer to the contained data
unsafe fn as_ptr(&self) -> *mut T {
let data = self.data.as_ref();
let info_size = mem::size_of::<*mut T>() / mem::size_of::<usize>() - 1;
let info_ofs = data.len() - info_size;
super::make_fat_ptr(data[..].as_ptr() as usize, &data[info_ofs..])
}
}
impl<T: ?Sized, D: ::DataBuf> ops::Deref for ValueA<T, D> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.as_ptr() }
}
}
impl<T: ?Sized, D: ::DataBuf> ops::DerefMut for ValueA<T, D> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.as_ptr() }
}
}
impl<T: ?Sized, D: ::DataBuf> ops::Drop for ValueA<T, D> {
fn drop(&mut self) {
unsafe { ptr::drop_in_place(&mut **self) }
}
}
mod trait_impls;