1
- struct AnyStackMeta {
1
+ struct AnyStackMeta < T > {
2
2
offset : usize ,
3
- func : unsafe fn ( value : * mut u8 , user_data : * mut u8 ) ,
3
+ func : unsafe fn ( value : * mut u8 , user_data : & mut T ) ,
4
4
}
5
5
6
- pub struct AnyStack {
6
+ pub struct AnyStack < T > {
7
7
bytes : Vec < u8 > ,
8
- metas : Vec < AnyStackMeta > ,
8
+ metas : Vec < AnyStackMeta < T > > ,
9
9
}
10
10
11
- impl Default for AnyStack {
11
+ impl < T > Default for AnyStack < T > {
12
12
fn default ( ) -> Self {
13
13
Self {
14
14
bytes : vec ! [ ] ,
@@ -17,97 +17,89 @@ impl Default for AnyStack {
17
17
}
18
18
}
19
19
20
- unsafe impl Send for AnyStack { }
21
- unsafe impl Sync for AnyStack { }
20
+ // SAFE: All values pushed onto the stack are required to be [`Send`]
21
+ unsafe impl < T > Send for AnyStack < T > { }
22
22
23
- impl AnyStack {
23
+ // SAFE: All values pushed onto the stack are required to be [`Sync`]
24
+ unsafe impl < T > Sync for AnyStack < T > { }
25
+
26
+ impl < T > AnyStack < T > {
27
+ ////Constructs a new, empty `AnyStack<T>`.
28
+ /// The stack will not allocate until elements are pushed onto it.
24
29
#[ inline]
25
30
pub fn new ( ) -> Self {
26
31
Self :: default ( )
27
32
}
28
33
34
+ /// Returns the number of elements in the [`AnyStack`], also referred to as its ‘length’.
29
35
#[ inline]
30
36
pub fn len ( & self ) -> usize {
31
37
self . metas . len ( )
32
38
}
33
39
40
+ /// Returns true if the [`AnyStack`] contains no elements.
34
41
#[ inline]
35
42
pub fn is_empty ( & self ) -> bool {
36
43
self . len ( ) == 0
37
44
}
38
45
39
- /// Clears in internal bytes and metas storage.
40
- ///
41
- /// # Safety
42
- ///
43
- /// This does not [`drop`] the pushed values.
44
- /// The pushed values must be dropped via [`AnyStack::apply`] and
45
- /// the provided `func` before calling this function.
46
- #[ inline]
47
- pub unsafe fn clear ( & mut self ) {
48
- self . bytes . clear ( ) ;
49
- self . metas . clear ( ) ;
50
- }
51
-
52
46
/// Push a new `value` onto the stack.
53
47
///
54
48
/// # Safety
55
49
///
56
- /// `func` must safely handle the provided `value` bytes and `user_data` bytes.
50
+ /// `func` must safely handle the provided `value` bytes.
51
+ /// _NOTE_: the bytes provided to the given function may **NOT** be aligned. If you wish
52
+ /// to read the value, consider using [`std::ptr::read_unalinged`].
53
+ ///
57
54
/// [`AnyStack`] does not drop the contained member.
58
- /// The user should manually call [`AnyStack::apply`] and in the implementation
59
- /// of the provided `func` function from [`AnyStack::push`], the element should
60
- /// be dropped.
61
- pub unsafe fn push < U > (
62
- & mut self ,
63
- value : U ,
64
- func : unsafe fn ( value : * mut u8 , user_data : * mut u8 ) ,
65
- ) {
66
- let align = std:: mem:: align_of :: < U > ( ) ;
55
+ /// The user should manually call [`AnyStack::consume`] and in the implementation
56
+ /// of the provided `func` the element should be dropped.
57
+ #[ inline]
58
+ pub unsafe fn push < U > ( & mut self , value : U , func : unsafe fn ( value : * mut u8 , user_data : & mut T ) )
59
+ where
60
+ U : Send + Sync ,
61
+ {
67
62
let size = std:: mem:: size_of :: < U > ( ) ;
68
63
69
- if self . is_empty ( ) {
70
- self . bytes . reserve ( size) ;
71
- }
72
-
73
64
let old_len = self . bytes . len ( ) ;
74
65
75
- let aligned_offset = loop {
76
- let aligned_offset = self . bytes . as_ptr ( ) . add ( old_len) . align_offset ( align) ;
77
-
78
- if old_len + aligned_offset + size > self . bytes . capacity ( ) {
79
- self . bytes . reserve ( aligned_offset + size) ;
80
- } else {
81
- break aligned_offset;
82
- }
83
- } ;
84
-
85
- let offset = old_len + aligned_offset;
86
- let total_bytes = size + aligned_offset;
87
- self . bytes . set_len ( old_len + total_bytes) ;
88
-
89
- self . metas . push ( AnyStackMeta { offset, func } ) ;
90
-
66
+ self . bytes . reserve ( size) ;
91
67
std:: ptr:: copy_nonoverlapping (
92
68
& value as * const U as * const u8 ,
93
- self . bytes . as_mut_ptr ( ) . add ( offset ) ,
69
+ self . bytes . as_mut_ptr ( ) . add ( old_len ) ,
94
70
size,
95
71
) ;
72
+ self . bytes . set_len ( old_len + size) ;
73
+
74
+ self . metas . push ( AnyStackMeta {
75
+ offset : old_len,
76
+ func,
77
+ } ) ;
96
78
97
79
std:: mem:: forget ( value) ;
98
80
}
99
81
100
- /// Call each user `func` for each inserted value with `user_data`.
82
+ /// Call each user `func` for each inserted value with `user_data`
83
+ /// and then clears the internal bytes/metas vectors.
101
84
///
102
- /// # Safety
85
+ /// # Warning
103
86
///
104
- /// It is up to the user to safely handle `user_data` in each of the initially
105
- /// provided `func` functions in [`AnyStack::push`].
106
- pub unsafe fn apply ( & mut self , user_data : * mut u8 ) {
87
+ /// This does not [`drop`] the pushed values.
88
+ /// If the value should be dropped, the initially provided `func`
89
+ /// should ensure any necessary cleanup occurs.
90
+ pub fn consume ( & mut self , user_data : & mut T ) {
107
91
let byte_ptr = self . bytes . as_mut_ptr ( ) ;
108
92
for meta in self . metas . iter ( ) {
109
- ( meta. func ) ( byte_ptr. add ( meta. offset ) , user_data) ;
93
+ // SAFE: The safety guarantees are promised to be held by the caller
94
+ // from [`AnyStack::push`].
95
+ // Also each value has it's offset correctly stored in it's assocaited meta.
96
+ unsafe {
97
+ ( meta. func ) ( byte_ptr. add ( meta. offset ) , user_data) ;
98
+ }
110
99
}
100
+
101
+ self . bytes . clear ( ) ;
102
+ self . metas . clear ( ) ;
111
103
}
112
104
}
113
105
@@ -136,18 +128,16 @@ mod test {
136
128
137
129
/// # Safety
138
130
///
139
- /// This function does not touch the `user_data` provided,
140
- /// and this is only used when the value is a `DropCheck`.
141
- /// Lastly, this drops the `DropCheck` value and is only
131
+ /// This function is only used when the value is a `DropCheck`.
132
+ /// This also drops the `DropCheck` value and is only
142
133
/// every call once.
143
- unsafe fn drop_check_func ( bytes : * mut u8 , _: * mut u8 ) {
144
- assert_eq ! ( bytes. align_offset( std:: mem:: align_of:: <DropCheck >( ) ) , 0 ) ;
145
- let _ = bytes. cast :: < DropCheck > ( ) . read ( ) ;
134
+ unsafe fn drop_check_func ( bytes : * mut u8 , _: & mut ( ) ) {
135
+ let _ = bytes. cast :: < DropCheck > ( ) . read_unaligned ( ) ;
146
136
}
147
137
148
138
#[ test]
149
139
fn test_anystack_drop ( ) {
150
- let mut stack = AnyStack :: new ( ) ;
140
+ let mut stack = AnyStack :: < ( ) > :: new ( ) ;
151
141
152
142
let ( dropcheck_a, drops_a) = DropCheck :: new ( ) ;
153
143
let ( dropcheck_b, drops_b) = DropCheck :: new ( ) ;
@@ -161,10 +151,7 @@ mod test {
161
151
assert_eq ! ( drops_a. load( Ordering :: Relaxed ) , 0 ) ;
162
152
assert_eq ! ( drops_b. load( Ordering :: Relaxed ) , 0 ) ;
163
153
164
- // SAFE: The `drop_check_func` does not access the null `user_data`.
165
- unsafe {
166
- stack. apply ( std:: ptr:: null_mut ( ) ) ;
167
- }
154
+ stack. consume ( & mut ( ) ) ;
168
155
169
156
assert_eq ! ( drops_a. load( Ordering :: Relaxed ) , 1 ) ;
170
157
assert_eq ! ( drops_b. load( Ordering :: Relaxed ) , 1 ) ;
@@ -174,11 +161,9 @@ mod test {
174
161
175
162
/// # Safety
176
163
/// `bytes` must point to a valid `u32`
177
- /// `world` must point to a mutable `FakeWorld`.
178
164
/// Since `u32` is a primitive type, it does not require a `drop` call.
179
- unsafe fn increment_fake_world_u32 ( bytes : * mut u8 , world : * mut u8 ) {
180
- let world = & mut * world. cast :: < FakeWorld > ( ) ;
181
- world. 0 += * bytes. cast :: < u32 > ( ) ;
165
+ unsafe fn increment_fake_world_u32 ( bytes : * mut u8 , world : & mut FakeWorld ) {
166
+ world. 0 += bytes. cast :: < u32 > ( ) . read_unaligned ( ) ;
182
167
}
183
168
184
169
#[ test]
@@ -199,19 +184,10 @@ mod test {
199
184
200
185
let mut world = FakeWorld ( 0 ) ;
201
186
202
- // SAFE: the given `user_data` is a `&mut FakeWorld` which is safely
203
- // handled in the invocation of `increment_fake_world_u32`
204
- unsafe {
205
- stack. apply ( & mut world as * mut FakeWorld as * mut u8 ) ;
206
- }
187
+ stack. consume ( & mut world) ;
207
188
208
189
assert_eq ! ( world. 0 , 15 ) ;
209
190
210
- // SAFE: the data is only `u32` so they don't need to be dropped.
211
- unsafe {
212
- stack. clear ( ) ;
213
- }
214
-
215
191
assert ! ( stack. is_empty( ) ) ;
216
192
assert_eq ! ( stack. len( ) , 0 ) ;
217
193
}
0 commit comments