@@ -136,10 +136,28 @@ impl ConstAllocator {
136
136
/// core::mem::forget(al.clone());
137
137
/// }
138
138
/// ```
139
+ #[ inline]
139
140
pub const fn with < F , R > ( f : F ) -> R
140
141
where
141
142
F : ~const FnOnce ( & ConstAllocator ) -> R ,
142
143
{
144
+ Self :: with_inner ( f)
145
+ }
146
+
147
+ /// The variant of [`Self::with`] that lets you pass an additional parameter
148
+ /// to the closure.
149
+ ///
150
+ /// This can be used to work around the lack of compiler support for const
151
+ /// closures.
152
+ #[ inline]
153
+ pub const fn with_parametric < P , F , R > ( p : P , f : F ) -> R
154
+ where
155
+ F : ~const FnOnce ( P , & ConstAllocator ) -> R ,
156
+ {
157
+ Self :: with_inner ( ( p, f) )
158
+ }
159
+
160
+ const fn with_inner < F : ~const FnOnceConstAllocator > ( f : F ) -> F :: Output {
143
161
struct RefCountGuard ( usize ) ;
144
162
impl const Drop for RefCountGuard {
145
163
fn drop ( & mut self ) {
@@ -168,7 +186,43 @@ impl ConstAllocator {
168
186
tlsf : tlsf. 0 . as_mut ( ) . unwrap ( ) ,
169
187
} ;
170
188
171
- f ( & this)
189
+ f. call ( & this)
190
+ }
191
+ }
192
+
193
+ /// The trait for types accepted by [`ConstAllocator::with_inner`].
194
+ trait FnOnceConstAllocator {
195
+ type Output ;
196
+ fn call ( self , allocator : & ConstAllocator ) -> Self :: Output ;
197
+ }
198
+
199
+ /// This implementation's `call` method simply calls the `FnOnce` receiver.
200
+ impl < T : ~const FnOnce ( & ConstAllocator ) -> Output , Output > const FnOnceConstAllocator for T {
201
+ type Output = Output ;
202
+ fn call ( self , allocator : & ConstAllocator ) -> Self :: Output {
203
+ self ( allocator)
204
+ }
205
+ }
206
+
207
+ /// This implementation's `call` method calls the `FnOnce` receiver with an
208
+ /// associated parameter value.
209
+ impl < P , T : ~const FnOnce ( P , & ConstAllocator ) -> Output , Output > const FnOnceConstAllocator
210
+ for ( P , T )
211
+ {
212
+ type Output = Output ;
213
+ fn call ( self , allocator : & ConstAllocator ) -> Self :: Output {
214
+ let mut this = core:: mem:: MaybeUninit :: new ( self ) ;
215
+ // Safety: It's initialized
216
+ let this = unsafe { & mut * this. as_mut_ptr ( ) } ;
217
+ // Safety: `md.0` and `md.1` are in `MaybeUninit`, so this will not
218
+ // cause double free
219
+ let param = unsafe { core:: ptr:: read ( & this. 0 ) } ;
220
+ let func = unsafe { core:: ptr:: read ( & this. 1 ) } ;
221
+ func ( param, allocator)
222
+
223
+ // FIXME: The following implementation doesn't work because of
224
+ // <https://github.com/rust-lang/rust/issues/86897>
225
+ // (self.1)(self.0, allocator)
172
226
}
173
227
}
174
228
0 commit comments