Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upUser-defined placement-box #18233
Conversation
pnkfelix
added some commits
Sep 26, 2014
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
agh failed (okay, fixed now; earlier review request still stands. :) |
This comment has been minimized.
This comment has been minimized.
|
(on reflection, I'm not sure why I thought printing from drop would be any better than failing from drop. I will revise those to just call |
thestinger
reviewed
Oct 22, 2014
| ExchangeHeapSingleton { _force_singleton: () }; | ||
|
|
||
| /// This the singleton type used solely for `boxed::HEAP`. | ||
| pub struct ExchangeHeapSingleton { _force_singleton: () } |
This comment has been minimized.
This comment has been minimized.
thestinger
Oct 22, 2014
Contributor
The term exchange heap really shouldn't be used. It's not how dynamic allocation works in Rust. It's wrong to refer to this as HEAP at all. The Box<T> type represents a dynamic allocation from the same allocator as other types like Vec<T> and Rc<T>. Rust doesn't draw any distinction between memory on a "heap" and other memory mappings.
This comment has been minimized.
This comment has been minimized.
|
The |
This comment has been minimized.
This comment has been minimized.
|
There needs to be a clear plan on how this is going to work for use cases like vector or hash table inserts before I'm comfortable with it, because I don't want to see Rust end up with an inadequate language feature that needs to be duplicated. |
pnkfelix
added some commits
Oct 23, 2014
This comment has been minimized.
This comment has been minimized.
|
@thestinger Good point, that is an important use case. I don't see any trouble expressing something like |
This comment has been minimized.
This comment has been minimized.
|
If it can support |
nikomatsakis
self-assigned this
Oct 30, 2014
nikomatsakis
reviewed
Nov 6, 2014
| /// the fact that the `align_of` intrinsic currently requires the | ||
| /// input type to be Sized (which I do not think is strictly | ||
| /// necessary). | ||
| pub struct IntermediateBox<Sized? T>{ |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
Since this is public, we'll be committing to the continued existence of this type, at least. I'm ok with this but cc @aturon. We'll probably want to bikeshed the name :)
This comment has been minimized.
This comment has been minimized.
pnkfelix
Nov 6, 2014
Author
Member
(Of course there's no way to avoid having this be public, at least not without private trait methods at the very least...)
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
On Thu, Nov 06, 2014 at 07:48:41AM -0800, Felix S Klock II wrote:
(Of course there's no way to avoid having this be public, at least not without private trait methods at the very least...)
Yes. And I think that's ok.
nikomatsakis
reviewed
Nov 6, 2014
| heap::EMPTY as *mut u8 | ||
| } else { | ||
| unsafe { | ||
| heap::allocate(size, align) |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
heap::allocate() can return null on failure, we should check for this and panic
nikomatsakis
reviewed
Nov 6, 2014
| fn drop(&mut self) { | ||
| if self.size > 0 { | ||
| unsafe { | ||
| heap::deallocate(self.ptr as *mut u8, self.size, self.align) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
pnkfelix
Nov 6, 2014
Author
Member
(agreed, that was probably an artifact of an earlier version of the IntermediateBox structure.)
nikomatsakis
reviewed
Nov 6, 2014
|
|
||
| impl<T: Default> Default for Box<T> { | ||
| fn default() -> Box<T> { box Default::default() } | ||
| fn default() -> Box<T> { | ||
| box (HEAP) { let t : T = Default::default(); t } |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
pnkfelix
Nov 6, 2014
Author
Member
I think the type-inference applied to the desugaring might reject that, but I'll double check.
nikomatsakis
reviewed
Nov 6, 2014
|
|
||
| /// Some free functions called by expansions of `box <value_expr>` and | ||
| /// `box (<place>) <value_expr>`. | ||
| pub mod placer { |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
Is there a way for us to mark these macro-artifacts as unstable? cc @aturon
This comment has been minimized.
This comment has been minimized.
nikomatsakis
reviewed
Nov 6, 2014
| /// order to avoid requiring (or expanding into) declarations like | ||
| /// `use std::ops::Placer;` and `use std::ops::PlacementAgent;` | ||
|
|
||
| /// Calls `p.make_place()` as work-around for lack of UFCS. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
reviewed
Nov 6, 2014
| } | ||
|
|
||
| /// Calls `a.pointer()` as work-around for lack of UFCS. | ||
| pub unsafe fn pointer<Sized? Data, Owner, A>(a: &A) -> *mut Data |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
reviewed
Nov 6, 2014
| } | ||
|
|
||
| /// Calls `a.finalize()` as work-around for lack of UFCS. | ||
| pub unsafe fn finalize<Sized? Data, Owner, A>(a: A) -> Owner |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
reviewed
Nov 6, 2014
|
|
||
| /// The first argument, `<place>` in `box (<place>) <value>`, must | ||
| /// implement `Placer`. | ||
| pub fn parenthesized_input_to_box_must_be_placer<'a, Sized? Data, Owner, A, P>(p: &'a mut P) -> &'a mut P |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
pnkfelix
Nov 14, 2014
Author
Member
you're right; I had thought we would need e.g. impl Trait to assert that the input placer expression had a suitable type, but we can make the assertion via UFCS. The only question is whether the resulting error messages will be usable. We will see about that.
nikomatsakis
reviewed
Nov 6, 2014
| /// Interface to user-implementations of `box (<placer_expr>) <value_expr>`. | ||
| /// | ||
| /// `box (P) V` effectively expands into: | ||
| /// `{ let b = P.make_place(); let v = V; unsafe { b.pointer() = v; b.finalize() } }` |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
Only question is whether b.pointer() should be evaluated before V or not. Also, we should add a FIXME regarding the matter of temporary lifetimes.
This comment has been minimized.
This comment has been minimized.
pnkfelix
Nov 14, 2014
Author
Member
I switched b.pointer() to evaluate before V.
Can you refresh my memory as to which matter of temporary lifetimes you were referring to here?
This comment has been minimized.
This comment has been minimized.
pnkfelix
Nov 14, 2014
Author
Member
(oh, maybe that was about the "vector should be tied up" note below... which may indeed go away with the revisions to take the placer by value in Placer::make_place(self);)
nikomatsakis
reviewed
Nov 6, 2014
| @@ -501,7 +501,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> { | |||
| } | |||
|
|
|||
| ast::ExprBox(ref place, ref base) => { | |||
| self.consume_expr(&**place); | |||
| place.as_ref().map(|e|self.consume_expr(&**e)); | |||
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
The expr place is not consumed, actually, but rather &mut borrowed, no? Probably this doesn't matter because anything with a place that is not None winds up being macro-expanded away, in which case maybe we can just add a call to span_bug
This comment has been minimized.
This comment has been minimized.
pnkfelix
Nov 14, 2014
Author
Member
i was just blindly doing a mechanical transformation here. (But now I think we've further revised the protocol so that make_place takes self by-value ... and of course yes, in principle we should never get here except with place = None, so I will just put the asserting span_bug in.)
nikomatsakis
reviewed
Nov 6, 2014
| // implement the Placer trait. Likewise, the actual | ||
| // expansion below actually calls free functions in | ||
| // `std::ops::placer`, in order to avoid the need for UFCS | ||
| // (and also to hopefully produce better error messags). |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
I think just using Placer::place(&mut <place_expr>) and so on will have a similar effect
nikomatsakis
reviewed
Nov 6, 2014
| // mod ptr { pub use ... as write; } } | ||
| // ``` | ||
| // | ||
| // as appropriate. |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
So sad. What are the other cases that do similar things? I guess it is backwards compat to fix this, so it's just fine.
This comment has been minimized.
This comment has been minimized.
pnkfelix
Nov 14, 2014
Author
Member
You can see the other cases listed with a grep like this:
% ack 'mod std {' lib*/lib.rs
liballoc/lib.rs
129:mod std {
libcollections/lib.rs
114:mod std {
libcore/lib.rs
139:mod std {
librand/lib.rs
488:mod std {
librustrt/lib.rs
171:mod std {
libstd/lib.rs
261:mod std {
libsync/lib.rs
78:mod std {
libunicode/lib.rs
80:mod std {
In libcollections it is even nice enough to point out the motivating cases:
#[cfg(not(test))]
mod std {
pub use core::fmt; // necessary for panic!()
pub use core::option; // necessary for panic!()
pub use core::clone; // deriving(Clone)
pub use core::cmp; // deriving(Eq, Ord, etc.)
pub use hash; // deriving(Hash)
}
nikomatsakis
reviewed
Nov 6, 2014
| // So for now pnkfelix is leaving out the `force_placer` | ||
| // invocation, which means we may get different type | ||
| // inference failures that are hard to diagnose, but at | ||
| // least we will be able to get something running. |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
reviewed
Nov 6, 2014
| struct EmplaceBackAgent<T> { | ||
| vec_ptr: *mut Vec<T>, | ||
| offset: uint, | ||
| } |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
I feel like this agent should carry a lifetime that ensures that the vector is "tied up" somehow
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
gereeter
Nov 6, 2014
Contributor
With the current design, make_place could be called repeatedly, and so that would result in aliasing &muts. However, there are other problems with calling make_place repeatedly. Since reserve_additional reserves space relative to the length of the vector, multiple make_places will only reserve space for a single extra element. The asserts in .pointer prevent unsafety, but it still is an issue. Arguably worse, the implication of the description of .pointer implies that different PlacementAgents should return different pointers, but this is violated by having multiple EmplaceBackAgents on the same Vec.
Personally, I'm in favor of just making make_place take the Placer by value. This shouldn't hurt ergonomics, as HEAP and RC would be Copy.
nikomatsakis
reviewed
Nov 6, 2014
| // we had some space reserved, it did not touch the state of | ||
| // the vector itself. | ||
| } | ||
| } |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 6, 2014
Contributor
can you move this emplace_back implementation into the auxiliary directory, and transform this test to test that it executes correctly, and add a compile-fail test that tries to do something bogus like:
let mut v: Vec<int> = vec![];
box(v.emplace_back()) { v.push(22); 23 }
This comment has been minimized.
This comment has been minimized.
|
It probably makes sense to leave these for follow-up PRs, but it'd be nice to have placer implementations for:
We should perhaps make a tracker issue (after this lands) for those sorts of things. Not a huge deal as they can be added as we like. |
This comment has been minimized.
This comment has been minimized.
|
(added link to Proto RFC on discuss to the description; you can see it here: http://discuss.rust-lang.org/t/pre-rfc-placement-box-with-placer-trait/729/5 ) |
pnkfelix
referenced this pull request
Nov 18, 2014
Closed
Require public trait items to be marked `pub` #227
This comment has been minimized.
This comment has been minimized.
|
This needs a rebase. |
This comment has been minimized.
This comment has been minimized.
|
(closing; I no longer think this is on the 1.0 timeframe) |
pnkfelix
closed this
Dec 16, 2014
This comment has been minimized.
This comment has been minimized.
|
see #22086 |
pnkfelix commentedOct 22, 2014
Add support for user-defined placement-box expressions (i.e.
box (<place>) <value>for types other thanBox<T>).This is a prototype design that @nikomatsakis and @pnkfelix have been working on. It works by desugaring an instance of placement-box into a protocol where we first create the intermediate storage with a pseudo-out-pointer, then initialize the storage, and then convert the out-pointer into the desired box type.
The code was originally written to handle both
box (<place>) <value>andbox <value>via the same uniform desugaring, and it is easy to revise support for the latter; but as is, this PR only putsbox (<place>) <value>into the desugaring. The reason for this is that the error messages get a lot nastier to handle from the desugared form, and pnkfelix did not want to hold this work up further trying to resolve that.The final design for this will require an RFC; this code is entirely experimental for now.
Proto RFC: http://discuss.rust-lang.org/t/pre-rfc-placement-box-with-placer-trait/729/5