Skip to content

Commit 6e08471

Browse files
committed
Amend 0809 to reduce the number of traits.
Use the following trait structure: unsafe trait Placer<Data: ?Sized> { type Place: Place<Data>; fn make_place(&mut self) -> Self::Place; } unsafe trait Boxer<Data: ?Sized>: Sized { type Place: Place<Data, Owner=Self>; fn make_place() -> Self::Place; } trait Place<Data: ?Sized> { type Owner; fn pointer(&mut self) -> *mut Data; unsafe fn finalize(self) -> Self::Owner; } The key differences are: 1. The `Placer` and `Boxer` traits must be unsafe because the compiler will blindly write to the pointers returned by `Placer::make_place(self).pointer()` and `Boxer::make_place().pointer()`. Note: we could have made `Place` itself unsafe but, if we ever decide to eventually support DST placement new, the `DstBoxer` and `DstPlacer` traits would need to be unsafe so there's no point in making Place unsafe. 2. Merge `InPlace` into `Place`. 3. Make the boxing side of the hierarchy mirror the "in (PLACE)" side of hierarchy.
1 parent 55d1032 commit 6e08471

File tree

1 file changed

+83
-109
lines changed

1 file changed

+83
-109
lines changed

text/0809-box-and-in-for-stdlib.md

Lines changed: 83 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ tandem with types provided by the stdlib, such as `Box<T>`.
160160
foo(box some_expr());
161161
```
162162
the type inference system attempts to unify the type `Box<SomeTrait>`
163-
with the return-type of `::protocol::Boxed::finalize(place)`.
163+
with the return-type of `::protocol::Place::finalize(place)`.
164164
This may also be due to weakness in the compiler, but that is not
165165
immediately obvious.
166166

@@ -295,26 +295,26 @@ macro_rules! in_ {
295295
let value = $value;
296296
unsafe {
297297
::std::ptr::write(raw_place, value);
298-
::protocol::InPlace::finalize(place)
298+
::protocol::Place::finalize(place)
299299
}
300300
} }
301301
}
302302

303303
macro_rules! box_ {
304304
($value:expr) => { {
305-
let mut place = ::protocol::BoxPlace::make_place();
305+
let mut place = ::protocol::Boxer::make_place();
306306
let raw_place = ::protocol::Place::pointer(&mut place);
307307
let value = $value;
308308
unsafe {
309309
::std::ptr::write(raw_place, value);
310-
::protocol::Boxed::finalize(place)
310+
::protocol::Place::finalize(place)
311311
}
312312
} }
313313
}
314314

315315
// Note that while both desugarings are very similar, there are some
316316
// slight differences. In particular, the placement-`in` desugaring
317-
// uses `InPlace::finalize(place)`, which is a `finalize` method that
317+
// uses `Place::finalize(place)`, which is a `finalize` method that
318318
// is overloaded based on the `place` argument (the type of which is
319319
// derived from the `<place-expr>` input); on the other hand, the
320320
// overloaded-`box` desugaring uses `Boxed::finalize(place)`, which is
@@ -341,16 +341,30 @@ mod protocol {
341341
/// The client is responsible for two steps: First, initializing the
342342
/// payload (it can access its address via `pointer`). Second,
343343
/// converting the agent to an instance of the owning pointer, via the
344-
/// appropriate `finalize` method (see the `InPlace`.
344+
/// `finalize` method.
345345
///
346346
/// If evaluating EXPR fails, then the destructor for the
347347
/// implementation of Place to clean up any intermediate state
348348
/// (e.g. deallocate box storage, pop a stack, etc).
349-
pub trait Place<Data: ?Sized> {
349+
pub unsafe trait Place<Data: ?Sized> {
350+
/// `Owner` is the type of the end value of `in PLACE { BLOCK }`
351+
///
352+
/// Note that when `in PLACE { BLOCK }` is solely used for
353+
/// side-effecting an existing data-structure,
354+
/// e.g. `Vec::emplace_back`, then `Owner` need not carry any
355+
/// information at all (e.g. it can be the unit type `()` in that
356+
/// case).
357+
type Owner;
358+
350359
/// Returns the address where the input value will be written.
351360
/// Note that the data at this address is generally uninitialized,
352361
/// and thus one should use `ptr::write` for initializing it.
353362
fn pointer(&mut self) -> *mut Data;
363+
364+
/// Converts self into the final value, shifting deallocation/cleanup
365+
/// responsibilities (if any remain), over to the returned instance of
366+
/// `Owner` and forgetting self.
367+
unsafe fn finalize(self) -> Self::Owner;
354368
}
355369

356370
/// Interface to implementations of `in PLACE { BLOCK }`.
@@ -364,77 +378,49 @@ pub trait Place<Data: ?Sized> {
364378
/// let value = { BLOCK };
365379
/// unsafe {
366380
/// std::ptr::write(raw_place, value);
367-
/// InPlace::finalize(place)
381+
/// Place::finalize(place)
368382
/// }
369383
/// ```
370384
///
371385
/// The type of `in PLACE { BLOCK }` is derived from the type of `PLACE`;
372386
/// if the type of `PLACE` is `P`, then the final type of the whole
373-
/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed`
374-
/// traits).
387+
/// expression is `P::Place::Owner` (see the `Place` trait).
375388
///
376389
/// Values for types implementing this trait usually are transient
377390
/// intermediate values (e.g. the return value of `Vec::emplace_back`)
378391
/// or `Copy`, since the `make_place` method takes `self` by value.
379-
pub trait Placer<Data: ?Sized> {
392+
pub unsafe trait Placer<Data: ?Sized> {
380393
/// `Place` is the intermedate agent guarding the
381394
/// uninitialized state for `Data`.
382-
type Place: InPlace<Data>;
395+
type Place: Place<Data>;
383396

384397
/// Creates a fresh place from `self`.
385398
fn make_place(self) -> Self::Place;
386399
}
387400

388-
/// Specialization of `Place` trait supporting `in PLACE { BLOCK }`.
389-
pub trait InPlace<Data: ?Sized>: Place<Data> {
390-
/// `Owner` is the type of the end value of `in PLACE { BLOCK }`
391-
///
392-
/// Note that when `in PLACE { BLOCK }` is solely used for
393-
/// side-effecting an existing data-structure,
394-
/// e.g. `Vec::emplace_back`, then `Owner` need not carry any
395-
/// information at all (e.g. it can be the unit type `()` in that
396-
/// case).
397-
type Owner;
398-
399-
/// Converts self into the final value, shifting
400-
/// deallocation/cleanup responsibilities (if any remain), over to
401-
/// the returned instance of `Owner` and forgetting self.
402-
unsafe fn finalize(self) -> Self::Owner;
403-
}
404-
405401
/// Core trait for the `box EXPR` form.
406402
///
407403
/// `box EXPR` effectively desugars into:
408404
///
409405
/// ```
410-
/// let mut place = BoxPlace::make_place();
406+
/// let mut place = Boxer::make_place();
411407
/// let raw_place = Place::pointer(&mut place);
412408
/// let value = $value;
413409
/// unsafe {
414410
/// ::std::ptr::write(raw_place, value);
415-
/// Boxed::finalize(place)
411+
/// Place::finalize(place)
416412
/// }
417413
/// ```
418414
///
419415
/// The type of `box EXPR` is supplied from its surrounding
420416
/// context; in the above expansion, the result type `T` is used
421417
/// to determine which implementation of `Boxed` to use, and that
422-
/// `<T as Boxed>` in turn dictates determines which
423-
/// implementation of `BoxPlace` to use, namely:
424-
/// `<<T as Boxed>::Place as BoxPlace>`.
425-
pub trait Boxed {
426-
/// The kind of data that is stored in this kind of box.
427-
type Data; /* (`Data` unused b/c cannot yet express below bound.) */
428-
type Place; /* should be bounded by BoxPlace<Self::Data> */
429-
430-
/// Converts filled place into final owning value, shifting
431-
/// deallocation/cleanup responsibilities (if any remain), over to
432-
/// returned instance of `Self` and forgetting `filled`.
433-
unsafe fn finalize(filled: Self::Place) -> Self;
434-
}
418+
/// `<T as Boxer>` in turn dictates determines which
419+
/// implementation of `Place` to use, namely:
420+
/// `<<T as Boxer>::Place as Place>`.
421+
pub unsafe trait Boxer<Data: ?Sized>: Sized {
422+
type Place: Place<Data, Owner=Self>;
435423

436-
/// Specialization of `Place` trait supporting `box EXPR`.
437-
pub trait BoxPlace<Data: ?Sized> : Place<Data> {
438424
/// Creates a globally fresh place.
439425
fn make_place() -> Self;
440426
}
@@ -465,39 +451,31 @@ mod impl_box_for_box {
465451
BoxPlace { fake_box: Some(Box::new(t)) }
466452
}
467453

468-
unsafe fn finalize<T>(mut filled: BoxPlace<T>) -> Box<T> {
469-
let mut ret = None;
470-
mem::swap(&mut filled.fake_box, &mut ret);
471-
ret.unwrap()
454+
unsafe impl<'a, T> proto::Placer<T> for HEAP {
455+
type Place = BoxPlace<T>;
456+
fn make_place(self) -> BoxPlace<T> { make_place() }
472457
}
473458

474-
impl<'a, T> proto::Placer<T> for HEAP {
459+
unsafe impl<T> proto::Boxer<T> for Box<T> {
475460
type Place = BoxPlace<T>;
476-
fn make_place(self) -> BoxPlace<T> { make_place() }
461+
fn make_place() -> BoxPlace<T> { make_place() }
477462
}
478463

479464
impl<T> proto::Place<T> for BoxPlace<T> {
465+
type Owner = Box<T>;
466+
480467
fn pointer(&mut self) -> *mut T {
481468
match self.fake_box {
482469
Some(ref mut b) => &mut **b as *mut T,
483470
None => panic!("impossible"),
484471
}
485472
}
486-
}
487-
488-
impl<T> proto::BoxPlace<T> for BoxPlace<T> {
489-
fn make_place() -> BoxPlace<T> { make_place() }
490-
}
491473

492-
impl<T> proto::InPlace<T> for BoxPlace<T> {
493-
type Owner = Box<T>;
494-
unsafe fn finalize(self) -> Box<T> { finalize(self) }
495-
}
496-
497-
impl<T> proto::Boxed for Box<T> {
498-
type Data = T;
499-
type Place = BoxPlace<T>;
500-
unsafe fn finalize(filled: BoxPlace<T>) -> Self { finalize(filled) }
474+
unsafe fn finalize<T>(mut self) -> Box<T> {
475+
let mut ret = None;
476+
mem::swap(&mut filled.fake_box, &mut ret);
477+
ret.unwrap()
478+
}
501479
}
502480
}
503481

@@ -515,6 +493,8 @@ mod impl_box_for_rc {
515493
struct RcPlace<T> { fake_box: Option<Rc<T>> }
516494

517495
impl<T> proto::Place<T> for RcPlace<T> {
496+
type Owner = Rc<T>;
497+
518498
fn pointer(&mut self) -> *mut T {
519499
if let Some(ref mut b) = self.fake_box {
520500
if let Some(r) = rc::get_mut(b) {
@@ -523,26 +503,24 @@ mod impl_box_for_rc {
523503
}
524504
panic!("impossible");
525505
}
506+
507+
unsafe fn finalize(mut self) -> Rc<T> {
508+
let mut ret = None;
509+
mem::swap(&mut filled.fake_box, &mut ret);
510+
ret.unwrap()
511+
}
526512
}
527513

528-
impl<T> proto::BoxPlace<T> for RcPlace<T> {
514+
unsafe impl<T> proto::Boxer<T> for RcPlace<T> {
515+
type Place = RcPlace<T>;
516+
529517
fn make_place() -> RcPlace<T> {
530518
unsafe {
531519
let t: T = mem::zeroed();
532520
RcPlace { fake_box: Some(Rc::new(t)) }
533521
}
534522
}
535523
}
536-
537-
impl<T> proto::Boxed for Rc<T> {
538-
type Data = T;
539-
type Place = RcPlace<T>;
540-
unsafe fn finalize(mut filled: RcPlace<T>) -> Self {
541-
let mut ret = None;
542-
mem::swap(&mut filled.fake_box, &mut ret);
543-
ret.unwrap()
544-
}
545-
}
546524
}
547525

548526
// Third, we want something to demonstrate placement-`in`. Let us use
@@ -562,33 +540,24 @@ mod impl_in_for_vec_emplace_back {
562540
fn emplace_back(&mut self) -> VecPlacer<T> { VecPlacer { v: self } }
563541
}
564542

565-
impl<'a, T> proto::Placer<T> for VecPlacer<'a, T> {
543+
unsafe impl<'a, T> proto::Placer<T> for VecPlacer<'a, T> {
566544
type Place = VecPlace<'a, T>;
567-
fn make_place(self) -> VecPlace<'a, T> { VecPlace { v: self.v } }
545+
fn make_place(self) -> VecPlace<'a, T> {
546+
selv.v.reserve(1);
547+
VecPlace { v: self.v }
548+
}
568549
}
569550

570551
impl<'a, T> proto::Place<T> for VecPlace<'a, T> {
552+
type Owner = ();
571553
fn pointer(&mut self) -> *mut T {
572554
unsafe {
573-
let idx = self.v.len();
574-
self.v.push(mem::zeroed());
575-
&mut self.v[idx]
555+
self.v.as_mut_ptr().offset(self.v.len())
576556
}
577557
}
578-
}
579-
impl<'a, T> proto::InPlace<T> for VecPlace<'a, T> {
580-
type Owner = ();
581558
unsafe fn finalize(self) -> () {
582-
mem::forget(self);
583-
}
584-
}
585-
586-
#[unsafe_destructor]
587-
impl<'a, T> Drop for VecPlace<'a, T> {
588-
fn drop(&mut self) {
589-
unsafe {
590-
mem::forget(self.v.pop())
591-
}
559+
// checked by reserve.
560+
self.v.set_len(self.v.len() + 1)
592561
}
593562
}
594563
}
@@ -634,28 +603,33 @@ fn main() { }
634603

635604
macro_rules! box_ {
636605
($value:expr) => { {
637-
let mut place = ::BoxPlace::make();
606+
let mut place = ::Boxer::make_place();
638607
let raw_place = ::Place::pointer(&mut place);
639608
let value = $value;
640609
unsafe { ::std::ptr::write(raw_place, value); ::Boxed::fin(place) }
641610
} }
642611
}
643612

613+
644614
// (Support traits and impls for examples below.)
645615

646-
pub trait BoxPlace<Data: ?Sized> : Place<Data> { fn make() -> Self; }
647-
pub trait Place<Data: ?Sized> { fn pointer(&mut self) -> *mut Data; }
648-
pub trait Boxed { type Place; fn fin(filled: Self::Place) -> Self; }
616+
trait Place<Data: ?Sized> {
617+
type Owner;
618+
fn pointer(&mut self) -> *mut Data;
619+
unsafe fn finalize(self) -> Self::Owner;
620+
}
621+
unsafe trait Boxer<Data: ?Sized>: Sized {
622+
type Place: Place<Data, Owner=Self>;
623+
fn make_place() -> Self;
624+
}
649625

650626
struct BP<T: ?Sized> { _fake_box: Option<Box<T>> }
651-
652-
impl<T> BoxPlace<T> for BP<T> { fn make() -> BP<T> { make_pl() } }
653-
impl<T: ?Sized> Place<T> for BP<T> { fn pointer(&mut self) -> *mut T { pointer(self) } }
654-
impl<T: ?Sized> Boxed for Box<T> { type Place = BP<T>; fn fin(x: BP<T>) -> Self { finaliz(x) } }
655-
656-
fn make_pl<T>() -> BP<T> { loop { } }
657-
fn finaliz<T: ?Sized>(mut _filled: BP<T>) -> Box<T> { loop { } }
658-
fn pointer<T: ?Sized>(_p: &mut BP<T>) -> *mut T { loop { } }
627+
unsafe impl<T> Boxer<T> for BP<T> { fn make_place() -> BP<T> { loop { } } }
628+
impl<T: ?Sized> Place<T> for BP<T> {
629+
type Owner = Box<T>;
630+
fn pointer(&mut self) -> *mut T { loop { } }
631+
fn finalize(x: BP<T>) -> Self { loop { } }
632+
}
659633

660634
// START HERE
661635

@@ -701,7 +675,7 @@ including the cases where type-inference fails in the desugaring.
701675
/tmp/foo6.rs:7:1: 14:2 note: in expansion of box_!
702676
/tmp/foo6.rs:37:64: 37:76 note: expansion site
703677
/tmp/foo6.rs:9:25: 9:41 error: the trait `core::marker::Sized` is not implemented for the type `core::ops::Fn()` [E0277]
704-
/tmp/foo6.rs:9 let mut place = ::BoxPlace::make();
678+
/tmp/foo6.rs:9 let mut place = ::Boxer::make_place();
705679
^~~~~~~~~~~~~~~~
706680
/tmp/foo6.rs:7:1: 14:2 note: in expansion of box_!
707681
/tmp/foo6.rs:37:64: 37:76 note: expansion site
@@ -713,7 +687,7 @@ error: aborting due to 2 previous errors
713687
/tmp/foo6.rs:7:1: 14:2 note: in expansion of box_!
714688
/tmp/foo6.rs:52:51: 52:64 note: expansion site
715689
/tmp/foo6.rs:9:25: 9:41 error: the trait `core::marker::Sized` is not implemented for the type `[T]` [E0277]
716-
/tmp/foo6.rs:9 let mut place = ::BoxPlace::make();
690+
/tmp/foo6.rs:9 let mut place = ::Boxer::make_place();
717691
^~~~~~~~~~~~~~~~
718692
/tmp/foo6.rs:7:1: 14:2 note: in expansion of box_!
719693
/tmp/foo6.rs:52:51: 52:64 note: expansion site

0 commit comments

Comments
 (0)