diff --git a/text/0809-box-and-in-for-stdlib.md b/text/0809-box-and-in-for-stdlib.md index 5c379041bc6..dcf1690f66d 100644 --- a/text/0809-box-and-in-for-stdlib.md +++ b/text/0809-box-and-in-for-stdlib.md @@ -160,7 +160,7 @@ tandem with types provided by the stdlib, such as `Box`. foo(box some_expr()); ``` the type inference system attempts to unify the type `Box` - with the return-type of `::protocol::Boxed::finalize(place)`. + with the return-type of `::protocol::Place::finalize(place)`. This may also be due to weakness in the compiler, but that is not immediately obvious. @@ -295,26 +295,26 @@ macro_rules! in_ { let value = $value; unsafe { ::std::ptr::write(raw_place, value); - ::protocol::InPlace::finalize(place) + ::protocol::Place::finalize(place) } } } } macro_rules! box_ { ($value:expr) => { { - let mut place = ::protocol::BoxPlace::make_place(); + let mut place = ::protocol::Boxer::make_place(); let raw_place = ::protocol::Place::pointer(&mut place); let value = $value; unsafe { ::std::ptr::write(raw_place, value); - ::protocol::Boxed::finalize(place) + ::protocol::Place::finalize(place) } } } } // Note that while both desugarings are very similar, there are some // slight differences. In particular, the placement-`in` desugaring -// uses `InPlace::finalize(place)`, which is a `finalize` method that +// uses `Place::finalize(place)`, which is a `finalize` method that // is overloaded based on the `place` argument (the type of which is // derived from the `` input); on the other hand, the // overloaded-`box` desugaring uses `Boxed::finalize(place)`, which is @@ -341,16 +341,30 @@ mod protocol { /// The client is responsible for two steps: First, initializing the /// payload (it can access its address via `pointer`). Second, /// converting the agent to an instance of the owning pointer, via the -/// appropriate `finalize` method (see the `InPlace`. +/// `finalize` method. /// /// If evaluating EXPR fails, then the destructor for the /// implementation of Place to clean up any intermediate state /// (e.g. deallocate box storage, pop a stack, etc). -pub trait Place { +pub unsafe trait Place { + /// `Owner` is the type of the end value of `in PLACE { BLOCK }` + /// + /// Note that when `in PLACE { BLOCK }` is solely used for + /// side-effecting an existing data-structure, + /// e.g. `Vec::emplace_back`, then `Owner` need not carry any + /// information at all (e.g. it can be the unit type `()` in that + /// case). + type Owner; + /// Returns the address where the input value will be written. /// Note that the data at this address is generally uninitialized, /// and thus one should use `ptr::write` for initializing it. fn pointer(&mut self) -> *mut Data; + + /// Converts self into the final value, shifting deallocation/cleanup + /// responsibilities (if any remain), over to the returned instance of + /// `Owner` and forgetting self. + unsafe fn finalize(self) -> Self::Owner; } /// Interface to implementations of `in PLACE { BLOCK }`. @@ -364,77 +378,49 @@ pub trait Place { /// let value = { BLOCK }; /// unsafe { /// std::ptr::write(raw_place, value); -/// InPlace::finalize(place) +/// Place::finalize(place) /// } /// ``` /// /// The type of `in PLACE { BLOCK }` is derived from the type of `PLACE`; /// if the type of `PLACE` is `P`, then the final type of the whole -/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` -/// traits). +/// expression is `P::Place::Owner` (see the `Place` trait). /// /// Values for types implementing this trait usually are transient /// intermediate values (e.g. the return value of `Vec::emplace_back`) /// or `Copy`, since the `make_place` method takes `self` by value. -pub trait Placer { +pub unsafe trait Placer { /// `Place` is the intermedate agent guarding the /// uninitialized state for `Data`. - type Place: InPlace; + type Place: Place; /// Creates a fresh place from `self`. fn make_place(self) -> Self::Place; } -/// Specialization of `Place` trait supporting `in PLACE { BLOCK }`. -pub trait InPlace: Place { - /// `Owner` is the type of the end value of `in PLACE { BLOCK }` - /// - /// Note that when `in PLACE { BLOCK }` is solely used for - /// side-effecting an existing data-structure, - /// e.g. `Vec::emplace_back`, then `Owner` need not carry any - /// information at all (e.g. it can be the unit type `()` in that - /// case). - type Owner; - - /// Converts self into the final value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// the returned instance of `Owner` and forgetting self. - unsafe fn finalize(self) -> Self::Owner; -} - /// Core trait for the `box EXPR` form. /// /// `box EXPR` effectively desugars into: /// /// ``` -/// let mut place = BoxPlace::make_place(); +/// let mut place = Boxer::make_place(); /// let raw_place = Place::pointer(&mut place); /// let value = $value; /// unsafe { /// ::std::ptr::write(raw_place, value); -/// Boxed::finalize(place) +/// Place::finalize(place) /// } /// ``` /// /// The type of `box EXPR` is supplied from its surrounding /// context; in the above expansion, the result type `T` is used /// to determine which implementation of `Boxed` to use, and that -/// `` in turn dictates determines which -/// implementation of `BoxPlace` to use, namely: -/// `<::Place as BoxPlace>`. -pub trait Boxed { - /// The kind of data that is stored in this kind of box. - type Data; /* (`Data` unused b/c cannot yet express below bound.) */ - type Place; /* should be bounded by BoxPlace */ - - /// Converts filled place into final owning value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// returned instance of `Self` and forgetting `filled`. - unsafe fn finalize(filled: Self::Place) -> Self; -} +/// `` in turn dictates determines which +/// implementation of `Place` to use, namely: +/// `<::Place as Place>`. +pub unsafe trait Boxer: Sized { + type Place: Place; -/// Specialization of `Place` trait supporting `box EXPR`. -pub trait BoxPlace : Place { /// Creates a globally fresh place. fn make_place() -> Self; } @@ -465,39 +451,31 @@ mod impl_box_for_box { BoxPlace { fake_box: Some(Box::new(t)) } } - unsafe fn finalize(mut filled: BoxPlace) -> Box { - let mut ret = None; - mem::swap(&mut filled.fake_box, &mut ret); - ret.unwrap() + unsafe impl<'a, T> proto::Placer for HEAP { + type Place = BoxPlace; + fn make_place(self) -> BoxPlace { make_place() } } - impl<'a, T> proto::Placer for HEAP { + unsafe impl proto::Boxer for Box { type Place = BoxPlace; - fn make_place(self) -> BoxPlace { make_place() } + fn make_place() -> BoxPlace { make_place() } } impl proto::Place for BoxPlace { + type Owner = Box; + fn pointer(&mut self) -> *mut T { match self.fake_box { Some(ref mut b) => &mut **b as *mut T, None => panic!("impossible"), } } - } - - impl proto::BoxPlace for BoxPlace { - fn make_place() -> BoxPlace { make_place() } - } - impl proto::InPlace for BoxPlace { - type Owner = Box; - unsafe fn finalize(self) -> Box { finalize(self) } - } - - impl proto::Boxed for Box { - type Data = T; - type Place = BoxPlace; - unsafe fn finalize(filled: BoxPlace) -> Self { finalize(filled) } + unsafe fn finalize(mut self) -> Box { + let mut ret = None; + mem::swap(&mut filled.fake_box, &mut ret); + ret.unwrap() + } } } @@ -515,6 +493,8 @@ mod impl_box_for_rc { struct RcPlace { fake_box: Option> } impl proto::Place for RcPlace { + type Owner = Rc; + fn pointer(&mut self) -> *mut T { if let Some(ref mut b) = self.fake_box { if let Some(r) = rc::get_mut(b) { @@ -523,9 +503,17 @@ mod impl_box_for_rc { } panic!("impossible"); } + + unsafe fn finalize(mut self) -> Rc { + let mut ret = None; + mem::swap(&mut filled.fake_box, &mut ret); + ret.unwrap() + } } - impl proto::BoxPlace for RcPlace { + unsafe impl proto::Boxer for RcPlace { + type Place = RcPlace; + fn make_place() -> RcPlace { unsafe { let t: T = mem::zeroed(); @@ -533,16 +521,6 @@ mod impl_box_for_rc { } } } - - impl proto::Boxed for Rc { - type Data = T; - type Place = RcPlace; - unsafe fn finalize(mut filled: RcPlace) -> Self { - let mut ret = None; - mem::swap(&mut filled.fake_box, &mut ret); - ret.unwrap() - } - } } // Third, we want something to demonstrate placement-`in`. Let us use @@ -562,33 +540,24 @@ mod impl_in_for_vec_emplace_back { fn emplace_back(&mut self) -> VecPlacer { VecPlacer { v: self } } } - impl<'a, T> proto::Placer for VecPlacer<'a, T> { + unsafe impl<'a, T> proto::Placer for VecPlacer<'a, T> { type Place = VecPlace<'a, T>; - fn make_place(self) -> VecPlace<'a, T> { VecPlace { v: self.v } } + fn make_place(self) -> VecPlace<'a, T> { + selv.v.reserve(1); + VecPlace { v: self.v } + } } impl<'a, T> proto::Place for VecPlace<'a, T> { + type Owner = (); fn pointer(&mut self) -> *mut T { unsafe { - let idx = self.v.len(); - self.v.push(mem::zeroed()); - &mut self.v[idx] + self.v.as_mut_ptr().offset(self.v.len()) } } - } - impl<'a, T> proto::InPlace for VecPlace<'a, T> { - type Owner = (); unsafe fn finalize(self) -> () { - mem::forget(self); - } - } - - #[unsafe_destructor] - impl<'a, T> Drop for VecPlace<'a, T> { - fn drop(&mut self) { - unsafe { - mem::forget(self.v.pop()) - } + // checked by reserve. + self.v.set_len(self.v.len() + 1) } } } @@ -634,28 +603,33 @@ fn main() { } macro_rules! box_ { ($value:expr) => { { - let mut place = ::BoxPlace::make(); + let mut place = ::Boxer::make_place(); let raw_place = ::Place::pointer(&mut place); let value = $value; unsafe { ::std::ptr::write(raw_place, value); ::Boxed::fin(place) } } } } + // (Support traits and impls for examples below.) -pub trait BoxPlace : Place { fn make() -> Self; } -pub trait Place { fn pointer(&mut self) -> *mut Data; } -pub trait Boxed { type Place; fn fin(filled: Self::Place) -> Self; } +trait Place { + type Owner; + fn pointer(&mut self) -> *mut Data; + unsafe fn finalize(self) -> Self::Owner; +} +unsafe trait Boxer: Sized { + type Place: Place; + fn make_place() -> Self; +} struct BP { _fake_box: Option> } - -impl BoxPlace for BP { fn make() -> BP { make_pl() } } -impl Place for BP { fn pointer(&mut self) -> *mut T { pointer(self) } } -impl Boxed for Box { type Place = BP; fn fin(x: BP) -> Self { finaliz(x) } } - -fn make_pl() -> BP { loop { } } -fn finaliz(mut _filled: BP) -> Box { loop { } } -fn pointer(_p: &mut BP) -> *mut T { loop { } } +unsafe impl Boxer for BP { fn make_place() -> BP { loop { } } } +impl Place for BP { + type Owner = Box; + fn pointer(&mut self) -> *mut T { loop { } } + fn finalize(x: BP) -> Self { loop { } } +} // START HERE @@ -701,7 +675,7 @@ including the cases where type-inference fails in the desugaring. /tmp/foo6.rs:7:1: 14:2 note: in expansion of box_! /tmp/foo6.rs:37:64: 37:76 note: expansion site /tmp/foo6.rs:9:25: 9:41 error: the trait `core::marker::Sized` is not implemented for the type `core::ops::Fn()` [E0277] -/tmp/foo6.rs:9 let mut place = ::BoxPlace::make(); +/tmp/foo6.rs:9 let mut place = ::Boxer::make_place(); ^~~~~~~~~~~~~~~~ /tmp/foo6.rs:7:1: 14:2 note: in expansion of box_! /tmp/foo6.rs:37:64: 37:76 note: expansion site @@ -713,7 +687,7 @@ error: aborting due to 2 previous errors /tmp/foo6.rs:7:1: 14:2 note: in expansion of box_! /tmp/foo6.rs:52:51: 52:64 note: expansion site /tmp/foo6.rs:9:25: 9:41 error: the trait `core::marker::Sized` is not implemented for the type `[T]` [E0277] -/tmp/foo6.rs:9 let mut place = ::BoxPlace::make(); +/tmp/foo6.rs:9 let mut place = ::Boxer::make_place(); ^~~~~~~~~~~~~~~~ /tmp/foo6.rs:7:1: 14:2 note: in expansion of box_! /tmp/foo6.rs:52:51: 52:64 note: expansion site