RFC: From<&[T]> for Rc<[T]> + From<&str> for Rc<str>#1845
RFC: From<&[T]> for Rc<[T]> + From<&str> for Rc<str>#1845alexcrichton merged 10 commits intorust-lang:masterfrom Centril:rc_from_slice_squash
Conversation
…ug for T: Clone, ...
|
I don't like that From is used, and I'm of the opinion that IMO, the API should look something like: impl<T: Clone> Rc<[T]> {
fn from_slice(s: &[T]) -> Self;
}
impl Rc<str> {
fn from_str(s: &str) -> Self;
} |
|
(Maybe you didn't intend to discuss this, if so, ignore this paragraph...) The choice to de-generalize Regarding Specialization immediately requires us to use Also, using
|
|
The examples of uses of There isn't a risk of conflict with associated functions (except with user-implemented traits, I guess). |
|
Adding non-static trait in addition would be TMTOWTDI but I don't mind it - to each their own I guess. If you were referring to How do you feel about doing this for And while we're at it: should we do this for |
| ```rust | ||
|
|
||
| #[inline(always)] | ||
| unsafe fn slice_to_rc<'a, T, U, W, C>(src: &'a [T], cast: C, write_elems: W) |
There was a problem hiding this comment.
@ubsan implementation detail, but: de-generify this / not ?
There was a problem hiding this comment.
I didn't understand the point of slice_to_rc; ignore that thing. That's fine.
0000-from-slice-to-rc-slice.md
Outdated
|
|
||
| Should the implementations use [`AsRef`][AsRef] or not? Might this be a case of making things a bit too ergonomic? This RFC currently leans towards not using it. | ||
|
|
||
| Should these trait implementations of [`From`][From] be added as functions on [`&str`][str] like `.into_rc_str()` and on [`&[T]`][slice] like `.into_rc_slice()`? |
There was a problem hiding this comment.
@ubsan Add associated functions on Rc to the list of unresolved questions?
0000-from-slice-to-rc-slice.md
Outdated
| difference being that this version uses the [`From`][From] trait, and is | ||
| converted into a shared smart pointer instead. | ||
|
|
||
| Because of the similarities between the layout of [`Rc`][Rc] and [`Arc`][Arc], almost identical implementations could be added for `From<&[T]> for Arc<[T]>` and `From<&str> for Arc<str>`. However, in this case the synchronization overhead while doing `.clone()` is probably greater than the overhead of doing `Arc<Box<str>>`. But once the clones have been made, `Arc<str>` would probably be cheaper to dereference due to locality. While the motivating use cases for `Arc<str>` are probably fewer, one could perhaps use it for multi threaded interning with a type such as: |
|
@Centril ah, I didn't get that I'm personally of the opinion that including |
|
Added stuff about What do we name the feature now if |
|
Renamed feature to "shared_from_slice" Also, libs team and @sfackler, thoughts on this RFC? |
|
I would personally prefer to see conversions for |
|
@abonander With the current layout of struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
value: T
}is allocated together on the heap and not separately, one can't reuse the allocation of a Given this, |
|
@Centril you can move the values from the By all means, have both kinds of conversions, but I don't think it's "more general" to restrict the element type to |
|
The point @abonander is making is that |
|
@abonander @seanmonstar ah - now I get it =) In case I didn't get it fully: how would an implementation of Would |
|
I guess |
|
To repeat what I've said in the past: with custom allocators you could define an allocator wrapper, say |
|
Avoiding the genericity of your suggested solution for simplicity: // Technically this could even take `&mut Vec<T>`, since it doesn't need to consume the vector, just drain elements from it
unsafe fn vec_to_rc<T>(mut src: Vec<T>) -> Rc<[T]>{
// Compute space to allocate for `RcBox<U>`.
let susize = mem::size_of::<usize>();
let num_elems = src.len();
let aligned_len = 2 + (mem::size_of::<T>() * num_elems + susize - 1) / susize;
// Allocate enough space for `RcBox<T>`.
let vec = RawVec::<usize>::with_capacity(aligned_len);
let ptr = vec.ptr();
forget(vec);
// Initialize fields of `RcBox<T>`.
ptr::write(ptr, 1); // strong: Cell::new(1)
ptr::write(ptr.offset(1), 1); // weak: Cell::new(1)
// This prevents `src` from trying to invoke the drop glue on the elements
src.set_len(0);
ptr::copy_nonoverlapping(src.as_ptr(), ptr.offset(2) as *mut T, num_elems);
// Combine the allocation address and the slice length into a
// fat pointer to `RcBox`.
let rcbox_ptr = slice::from_raw_parts_mut(ptr, num_elems)
// `as *mut [T]` may be redundant but removing it
// triggers a timeout on the playpen
as *mut [usize] as *mut [T] as *mut RcBox<[T]>;
debug_assert_eq!(aligned_len * susize, mem::size_of_val(&*rcbox_ptr));
Rc { ptr: Shared::new(rcbox_ptr) }
}In your suggested solution, using As for coming from an iterator, you could round-drip through |
|
@eddyb that'd be slick! Tho, I take it that this would require an overhaul of stuff? Would this change anything for @abonander regarding |
|
for i in 0 .. dest.len() {
dest[i] = src[i].clone();
}And overwriting by assignment implicitly drops the existing value.
|
|
@Centril It'd let them be |
|
@abonander Ah, right =) Anyways: I'm certainly amenable to adding the API:s you proposed in this RFC. Could you please specify the details so that I can add them? I'll take a look at those tomorrow, after my exam =) @eddyb that's neat - tho... could that be done as a separate RFC since it is probably a much larger and more-into-the-future change? |
|
@Centril Since copying is necessary anyway, having just And then in a future RFC, maybe have |
|
Something I've been wondering for things like this: Is it ok to call Then you could just use the easy way (which would also negate the need for the assertion at the end I think): fn from_slice(value: &[T]) -> Rc<[T]> {
let fake: *mut RcBox<[T]> = mem::transmute([0, value.len()]);
let ptr = allocate(size_of_val(&*fake), align_of_val(&*fake));
// ... etcI also don't really understand why let rcbox_ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]);
(*rcbox_ptr).strong = Cell::new(1);
(*rcbox_ptr).weak = Cell::new(1);
// ... etc |
|
I agree, (*rcbox_ptr).strong.set(1);
(*rcbox_ptr).weak.set(1);I'm more ambivalent about calling |
|
Thanks for the updates @Centril! |
|
🔔 This is now entering its final comment period, as per the review above. 🔔 |
1 similar comment
|
🔔 This is now entering its final comment period, as per the review above. 🔔 |
|
This will make easy to implement Rc::make_mut for unsized types. @Centril Please consider this change if you make the PR implementing this RFC. |
|
@malbarbo Could you please clarify the signature of the function you want to add and how it would behave? |
|
@Centril I'm sorry for being lazy. The function |
|
The final comment period is now complete. |
|
@alexcrichton Even tho the FCP is complete, I think @malbarbo raises something I (and you?) have to a address but haven't had time to do so... I'll take a look at it today =) |
|
@Centril sure yeah if you want to write something up in the RFC I'll merge right after. My guess is that unfortunately we can't as |
|
@alexcrichton This might be wrong, but, ..., what if we do: impl<T> Rc<[T]> where T: Clone {
fn make_mut_slice(this: &mut Rc<[T]>) -> &mut [T]
}This should be safe as long as the referent that got the |
|
Yeah I think that'd work, but we probably want to save that for a future PR perhaps? |
|
@alexcrichton Yeah, seems reasonable =) Should I add that to the list of unresolved questions? |
|
Yeah sounds good! |
|
@alexcrichton Done... Ready to merge I guess =) |
|
Thanks @Centril! Tracking issue: rust-lang/rust#40475 |
This is the RFC for the issue #1844.
Rendered
A special thanks to @ubsan for helping me write my first RFC.