-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: From<&[T]> for Rc<[T]> + From<&str> for Rc<str> #1845
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 |
0000-from-slice-to-rc-slice.md
Outdated
```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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ubsan implementation detail, but: de-generify this / not ?
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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ubsan Add associated functions on Rc
to the list of unresolved questions?
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.
Yes, please. Thanks!
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: |
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.
@ubsan Include Arc
(and Box
?) or not ?
@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));
// ... etc I 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.