@@ -181,24 +181,95 @@ where
181
181
}
182
182
183
183
/// Types that can allocate a custom slice DST within them.
184
+ ///
185
+ /// # Implementation note
186
+ ///
187
+ /// For most types, [`TryAllocSliceDst`] should be the implementation primitive.
188
+ /// This trait can then be implemented in terms of `TryAllocSliceDst`:
189
+ ///
190
+ /// ```rust
191
+ /// # use {slice_dst::*, std::ptr};
192
+ /// # struct Container<T: ?Sized>(Box<T>);
193
+ /// # unsafe impl<S: ?Sized + SliceDst> TryAllocSliceDst<S> for Container<S> {
194
+ /// # unsafe fn try_new_slice_dst<I, E>(len: usize, init: I) -> Result<Self, E>
195
+ /// # where I: FnOnce(ptr::NonNull<S>) -> Result<(), E>
196
+ /// # { unimplemented!() }
197
+ /// # }
198
+ /// unsafe impl<S: ?Sized + SliceDst> AllocSliceDst<S> for Container<S> {
199
+ /// unsafe fn new_slice_dst<I>(len: usize, init: I) -> Self
200
+ /// where
201
+ /// I: FnOnce(ptr::NonNull<S>),
202
+ /// {
203
+ /// enum Void {} // or never (!) once it is stable
204
+ /// #[allow(clippy::unit_arg)]
205
+ /// let init = |ptr| Ok::<(), Void>(init(ptr));
206
+ /// match Self::try_new_slice_dst(len, init) {
207
+ /// Ok(a) => a,
208
+ /// Err(void) => match void {},
209
+ /// }
210
+ /// }
211
+ /// }
212
+ /// ```
213
+ ///
214
+ /// This is not a blanket impl due to coherence rules; if the blanket impl were present,
215
+ /// it would be impossible to implement `AllocSliceDst` instead of `TryAllocSliceDst`.
184
216
pub unsafe trait AllocSliceDst < S : ?Sized + SliceDst > {
185
217
/// Create a new custom slice DST.
186
218
///
187
219
/// # Safety
188
220
///
189
221
/// `init` must properly initialize the object behind the pointer.
190
- /// The stored length of the slice DST must be the same as the length used in this call.
191
222
/// `init` receives a fully uninitialized pointer and must not read anything before writing.
192
223
unsafe fn new_slice_dst < I > ( len : usize , init : I ) -> Self
193
224
where
194
225
I : FnOnce ( ptr:: NonNull < S > ) ;
195
226
}
196
227
228
+ // FUTURE: export? Would need better generic support.
229
+ macro_rules! impl_alloc_by_try_alloc {
230
+ ( $T: ident) => {
231
+ unsafe impl <S : ?Sized + SliceDst > $crate:: AllocSliceDst <S > for $T<S > {
232
+ unsafe fn new_slice_dst<I >( len: usize , init: I ) -> Self
233
+ where
234
+ I : FnOnce ( :: core:: ptr:: NonNull <S >) ,
235
+ {
236
+ enum Void { }
237
+ #[ allow( clippy:: unit_arg) ]
238
+ let init = |ptr| :: core:: result:: Result :: <( ) , Void >:: Ok ( init( ptr) ) ;
239
+ match <Self as $crate:: TryAllocSliceDst <S >>:: try_new_slice_dst( len, init) {
240
+ Ok ( a) => a,
241
+ Err ( void) => match void { } ,
242
+ }
243
+ }
244
+ }
245
+ } ;
246
+ }
247
+
248
+ /// Types that can allocate a custom slice DST within them,
249
+ /// given a fallible initialization function.
250
+ pub unsafe trait TryAllocSliceDst < S : ?Sized + SliceDst > : AllocSliceDst < S > + Sized {
251
+ /// Create a new custom slice DST with a fallible initialization function.
252
+ ///
253
+ /// # Safety
254
+ ///
255
+ /// `init` must properly initialize the object behind the pointer.
256
+ /// `init` receives a fully uninitialized pointer and must not read anything before writing.
257
+ ///
258
+ /// If the initialization closure panics or returns an error,
259
+ /// the allocated place will be deallocated but not dropped.
260
+ /// To clean up the partially initialized type, we suggest
261
+ /// proxying creation through scope guarding types.
262
+ unsafe fn try_new_slice_dst < I , E > ( len : usize , init : I ) -> Result < Self , E >
263
+ where
264
+ I : FnOnce ( ptr:: NonNull < S > ) -> Result < ( ) , E > ;
265
+ }
266
+
197
267
// SAFETY: Box is guaranteed to be allocatable by GlobalAlloc.
198
- unsafe impl < S : ?Sized + SliceDst > AllocSliceDst < S > for Box < S > {
199
- unsafe fn new_slice_dst < I > ( len : usize , init : I ) -> Self
268
+ impl_alloc_by_try_alloc ! ( Box ) ;
269
+ unsafe impl < S : ?Sized + SliceDst > TryAllocSliceDst < S > for Box < S > {
270
+ unsafe fn try_new_slice_dst < I , E > ( len : usize , init : I ) -> Result < Self , E >
200
271
where
201
- I : FnOnce ( ptr:: NonNull < S > ) ,
272
+ I : FnOnce ( ptr:: NonNull < S > ) -> Result < ( ) , E > ,
202
273
{
203
274
struct RawBox < S : ?Sized + SliceDst > ( ptr:: NonNull < S > , Layout ) ;
204
275
@@ -223,26 +294,30 @@ unsafe impl<S: ?Sized + SliceDst> AllocSliceDst<S> for Box<S> {
223
294
}
224
295
225
296
let ptr = RawBox :: new ( len) ;
226
- init ( ptr. 0 ) ;
227
- ptr. finalize ( )
297
+ init ( ptr. 0 ) ? ;
298
+ Ok ( ptr. finalize ( ) )
228
299
}
229
300
}
230
301
231
- unsafe impl < S : ?Sized + SliceDst > AllocSliceDst < S > for Rc < S > {
232
- unsafe fn new_slice_dst < I > ( len : usize , init : I ) -> Self
302
+ // SAFETY: just delegates to `Box`'s implementation (for now?)
303
+ impl_alloc_by_try_alloc ! ( Rc ) ;
304
+ unsafe impl < S : ?Sized + SliceDst > TryAllocSliceDst < S > for Rc < S > {
305
+ unsafe fn try_new_slice_dst < I , E > ( len : usize , init : I ) -> Result < Self , E >
233
306
where
234
- I : FnOnce ( ptr:: NonNull < S > ) ,
307
+ I : FnOnce ( ptr:: NonNull < S > ) -> Result < ( ) , E > ,
235
308
{
236
- Box :: new_slice_dst ( len, init) . into ( )
309
+ Box :: try_new_slice_dst ( len, init) . map ( Into :: into )
237
310
}
238
311
}
239
312
240
- unsafe impl < S : ?Sized + SliceDst > AllocSliceDst < S > for Arc < S > {
241
- unsafe fn new_slice_dst < I > ( len : usize , init : I ) -> Self
313
+ // SAFETY: just delegates to `Box`'s implementation (for now?)
314
+ impl_alloc_by_try_alloc ! ( Arc ) ;
315
+ unsafe impl < S : ?Sized + SliceDst > TryAllocSliceDst < S > for Arc < S > {
316
+ unsafe fn try_new_slice_dst < I , E > ( len : usize , init : I ) -> Result < Self , E >
242
317
where
243
- I : FnOnce ( ptr:: NonNull < S > ) ,
318
+ I : FnOnce ( ptr:: NonNull < S > ) -> Result < ( ) , E > ,
244
319
{
245
- Box :: new_slice_dst ( len, init) . into ( )
320
+ Box :: try_new_slice_dst ( len, init) . map ( Into :: into )
246
321
}
247
322
}
248
323
0 commit comments