-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement From<&[T]> and others for Arc/Rc (RFC 1845) #42565
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
cc @rust-lang/libs -- not sure who is best suited to review this, or what policy you all want to use to decide, but this is splitting up crates and moving things around and I don't think I'm the right person for it. =) |
Assigning to @sfackler from libs team to decide on whether we want this. |
src/libshared_ptr/arc.rs
Outdated
} | ||
|
||
impl<T: ?Sized> Arc<T> { | ||
fn from_box(v: Box<T>) -> Arc<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why isn't this using allocate_slice
? I imagine an
unsafe fn for_raw_ptr(ptr: *const T) -> *mut ArcInner<T> {
}
That mirrors the unsized part of ptr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
allocate_slice
uses the slice length to calculate the size of the allocation. For general unsized T
, size is determined differently. That determination is only made in from_box
, so it didn't seem to warrant another function.
Also, offset
is used to calculate size, but also must be in scope for the call to ptr::copy_nonoverlapping
.
I suppose that both T: ?Sized
and [T]
could use a common allocation function (like for_raw_ptr
). Allocating [T]
uses a trick (called "dubious" in an existing comment) to get alignment, but the speed advantage over manually calculating it is likely negligible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The align_of
trick is a bit ugly, but I think it's better than hardcoding layout calculations (as allocate_for_ptr
does) and is probably going to be well-defined.
I think the "official" way of creating "franken-raw-pointers" is by transmuting to std::raw::TraitObject
rather than odd ptr::write
s etc.
Also allocate_for_ptr
& init_rcbox
are always used together. I'll rather merge them and create a ready-to-be-used RcBox
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I picked up the "franken-raw-pointer" method from the RFC's example implementation. It's used, I think, because the unsized T
may be a trait object or a slice or perhaps some theoretical unsized type that is structured differently from either of those. Still, it can be changed to TraitObject
if that reads better (which happens to work for slice, too).
I agree that calculating offset is not great, but the offset_of
macro fails to compile with unsized T
and I didn't see a way around it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it turns out the Franken-pointer method is used because a ?Sized
T
might, in fact, be sized, which means that transmute to TraitObject
will fail. So, the weird ptr::write
thing correctly handles a fat pointer or a normal raw pointer.
I'll defer to @alexcrichton on the implementation details - I haven't done enough work with DST representations. |
So I haven't read 100% of this but I'm a little confused why exactly this is being moved to another crate to depend on At first glance it looks a bit like you're using Mind providing a bit more explanation on that @murarth ? (in general, it makes sense to not make |
So I looked through the code again and I'm definitely not convinced that this needs to depend on |
@clarcharr: The RFC specifies implementing |
@murarth ah, I see. I don't really think that this is a good enough reason to warrant changing crates at the moment; in the future we should be able to put the implementation in libcollections directly. Right now all of the |
☔ The latest upstream changes (presumably #42419) made this pull request unmergeable. Please resolve the merge conflicts. |
Thanks for the PR @murarth! My main point of hesitation here is the addition of a crate rather than the removal of a crate. I feel similarly to others in #40475 that the best solution to this is to just merge the Would you be up for deleting the What do you think? |
@alexcrichton: Merging |
Ok! So to clarify, @murarth you're thinking we should basically put this PR "on the backburner" until the merge goes through? I'd still be ok laying some groundwork here (e.g. with |
@alexcrichton: Yes, I think it will be less work in the end just to wait for the |
Ok sounds good to me! Feel free to r? me on a PR-for-a-merge and I'll try to review quickly as it'd be susceptible to bitrot. |
☔ The latest upstream changes (presumably #42433) made this pull request unmergeable. Please resolve the merge conflicts. |
I did some tinkering and found a basis for an unsized-capable The "elaborate" version gives the same result, but avoids overflowing the pointer if the value happens to be at the very end of the address space. I'm not sure if that's a realistic condition that's worth checking for. |
Merge crate `collections` into `alloc` This is a necessary step in order to merge #42565
Rebased. Also significantly simplified |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great to me, thanks @murarth!
src/liballoc/arc.rs
Outdated
let v_ptr = &v[..] as *const [T]; | ||
let ptr = Self::allocate_for_ptr(v_ptr); | ||
|
||
ptr::copy_nonoverlapping( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this use Arc::from_box(v.into_boxed_slice())
perhaps?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or alternatively, could this call copy_from_slice
(or share the implementation there) before it's followed by set_len(0)
?
src/liballoc/arc.rs
Outdated
} | ||
|
||
impl<T: Clone> Arc<[T]> { | ||
fn clone_from_slice(v: &[T]) -> Arc<[T]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and copy_from_slice
are only used in one location, right? Could they just be inlined into From
below?
src/liballoc/arc.rs
Outdated
#[unstable(feature = "shared_from_slice", issue = "40475")] | ||
impl<'a, T: Clone> From<&'a [T]> for Arc<[T]> { | ||
#[inline] | ||
default fn from(v: &[T]) -> Arc<[T]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We currently try to avoid exposing the usage of specialization right now, mind changing this to use a local ArcFromSlice
trait which can be locally specialized?
src/liballoc/arc.rs
Outdated
@@ -1211,8 +1360,49 @@ impl<T> From<T> for Arc<T> { | |||
} | |||
} | |||
|
|||
#[unstable(feature = "shared_from_slice", issue = "40475")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now we unfortunately don't have stability checking on impl blocks, so you can go ahead and tag these impls as #[stable]
src/liballoc/arc.rs
Outdated
} | ||
|
||
#[unstable(feature = "shared_from_slice", issue = "40475")] | ||
impl<'a> From<&'a str> for Arc<str> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While we're at it, should we perhaps have From<String> for Arc<str>
as well?
src/liballoc/arc.rs
Outdated
impl<'a> From<&'a str> for Arc<str> { | ||
#[inline] | ||
fn from(v: &str) -> Arc<str> { | ||
unsafe { from_arc_utf8_unchecked(Arc::copy_from_slice(v.as_bytes())) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd personally be ok just using transmute
here, exposing from_arc_utf8_unchecked
is unlikely to be stabilized in the long run I think.
Looks fantastic! If it's ok with you I'd like to double-check with @rust-lang/libs though that we're ok on merging this. I'm going to tag this as |
@bors: r+ |
📌 Commit 8e0d01b has been approved by |
⌛ Testing commit 8e0d01b with merge 944675da03018dc4746039b8076dc169fe26ae22... |
💔 Test failed - status-travis |
⌛ Testing commit 8e0d01b with merge 6decb846e857cfb9f99f2a3c74834be18d69cf0b... |
💔 Test failed - status-travis |
@bors retry A Mac is unscheduled, an another Mac failed to download the LLVM archive correctly.
BTW Travis is having problem with Macs currently:
|
⌛ Testing commit 8e0d01b with merge 2aabed68e72aa9c0e64f6b5cfd40aea152ee4cb7... |
💔 Test failed - status-travis |
@bors: retry
|
Implement From<&[T]> and others for Arc/Rc (RFC 1845) * Implements `From<`{`&[T]`, `&str`, `String`, `Box<T> where T: ?Sized`, `Vec<T>`}`>` for `Arc`/`Rc` * Removes `rustc_private`-marked methods `Rc::__from_array` and `Rc::__from_str`, replacing their use with `Rc::from` Tracking issue: #40475
☀️ Test successful - status-appveyor, status-travis |
Changelog: Version 1.21.0 (2017-10-12) ========================== Language -------- - [You can now use static references for literals.][43838] Example: ```rust fn main() { let x: &'static u32 = &0; } ``` - [Relaxed path syntax. Optional `::` before `<` is now allowed in all contexts.][43540] Example: ```rust my_macro!(Vec<i32>::new); // Always worked my_macro!(Vec::<i32>::new); // Now works ``` Compiler -------- - [Upgraded jemalloc to 4.5.0][43911] - [Enabled unwinding panics on Redox][43917] - [Now runs LLVM in parallel during translation phase.][43506] This should reduce peak memory usage. Libraries --------- - [Generate builtin impls for `Clone` for all arrays and tuples that are `T: Clone`][43690] - [`Stdin`, `Stdout`, and `Stderr` now implement `AsRawFd`.][43459] - [`Rc` and `Arc` now implement `From<&[T]> where T: Clone`, `From<str>`, `From<String>`, `From<Box<T>> where T: ?Sized`, and `From<Vec<T>>`.][42565] Stabilized APIs --------------- [`std::mem::discriminant`] Cargo ----- - [You can now call `cargo install` with multiple package names][cargo/4216] - [Cargo commands inside a virtual workspace will now implicitly pass `--all`][cargo/4335] - [Added a `[patch]` section to `Cargo.toml` to handle prepublication dependencies][cargo/4123] [RFC 1969] - [`include` & `exclude` fields in `Cargo.toml` now accept gitignore like patterns][cargo/4270] - [Added the `--all-targets` option][cargo/4400] - [Using required dependencies as a feature is now deprecated and emits a warning][cargo/4364] Misc ---- - [Cargo docs are moving][43916] to [doc.rust-lang.org/cargo](https://doc.rust-lang.org/cargo) - [The rustdoc book is now available][43863] at [doc.rust-lang.org/rustdoc](https://doc.rust-lang.org/rustdoc) - [Added a preview of RLS has been made available through rustup][44204] Install with `rustup component add rls-preview` - [`std::os` documentation for Unix, Linux, and Windows now appears on doc.rust-lang.org][43348] Previously only showed `std::os::unix`. Compatibility Notes ------------------- - [Changes in method matching against higher-ranked types][43880] This may cause breakage in subtyping corner cases. [A more in-depth explanation is available.][info/43880] - [rustc's JSON error output's byte position start at top of file.][42973] Was previously relative to the rustc's internal `CodeMap` struct which required the unstable library `libsyntax` to correctly use. - [`unused_results` lint no longer ignores booleans][43728] [42565]: rust-lang/rust#42565 [42973]: rust-lang/rust#42973 [43348]: rust-lang/rust#43348 [43459]: rust-lang/rust#43459 [43506]: rust-lang/rust#43506 [43540]: rust-lang/rust#43540 [43690]: rust-lang/rust#43690 [43728]: rust-lang/rust#43728 [43838]: rust-lang/rust#43838 [43863]: rust-lang/rust#43863 [43880]: rust-lang/rust#43880 [43911]: rust-lang/rust#43911 [43916]: rust-lang/rust#43916 [43917]: rust-lang/rust#43917 [44204]: rust-lang/rust#44204 [cargo/4123]: rust-lang/cargo#4123 [cargo/4216]: rust-lang/cargo#4216 [cargo/4270]: rust-lang/cargo#4270 [cargo/4335]: rust-lang/cargo#4335 [cargo/4364]: rust-lang/cargo#4364 [cargo/4400]: rust-lang/cargo#4400 [RFC 1969]: rust-lang/rfcs#1969 [info/43880]: rust-lang/rust#44224 (comment) [`std::mem::discriminant`]: https://doc.rust-lang.org/std/mem/fn.discriminant.html
Turns out this has a soundness bug :( #54908 |
libcollections was recently merged into liballoc: rust-lang/rust#42648 I went ahead and also added an "alloc" feature which no_std users can use to opt into liballoc features (i.e. any code using Vec). This should have no effect on anything but no_std usage. It does make it possible for people without allocators to use curve25519-dalek if they want though. Might be nice for "bare metal" development. All that said, from what I can gather liballoc, while not "stable", should likely stick around for the forseeable future. Some backstory on the liballoc/libcollections merge here: rust-lang/rust#42565
From<
{&[T]
,&str
,String
,Box<T> where T: ?Sized
,Vec<T>
}>
forArc
/Rc
rustc_private
-marked methodsRc::__from_array
andRc::__from_str
, replacing their use withRc::from
Tracking issue: #40475