-
Notifications
You must be signed in to change notification settings - Fork 13.7k
collections: Add shallow_copy
method to Cow which always reborrows data
#33777
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
Conversation
r? @aturon (rust_highfive has picked a reviewer for you, use r? to override) |
Is there an advantage over just using the deref'd |
@birkenfeld You continue to have clone-on-write semantics without having to manually wrap the |
@ipetkov My apoogies -- I totally missed this PR in my inbox. This looks like a very plausible addition! Before we land, I'll let @rust-lang/libs weigh in. |
I'd personally be a little confused by this method as it seems like it's not actually copying anything? That is, this is the equivalent of |
I can see the use. "shallow copy" is a strange thing to say in Rust since all copies are shallow - "shallow clone" would make more sense, but also less. |
@alexcrichton pretty much. The idea for this stemmed from my misunderstanding (for quite a while actually) around cloning a @brson I originally called it |
Hm actually cloning a |
@alexcrichton You could, but you'd have to manually rewrap it (or the harder step, realize that's all you need to maintain clone-on-write semantics). I was using this somewhat in a crate of mine and I figured this could have been useful upstream (i.e. downstream crates use this method from |
This does look like the obviously right thing for |
/// } | ||
/// ``` | ||
#[unstable(feature = "cow_shallow_copy", issue="0")] | ||
pub fn shallow_copy(&'a self) -> Cow<'a, B> { |
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.
Using 'a
like this is usually a red flag that deserves some scrutiny (when 'a
is the parameter used in the type, and not a method level parameter). I think fn shallow_copy(&self) -> Cow<B>
would be a more natural
…data * Feature gated behind `cow_shallow_copy`
Ah as @bluss pointed out in #34284, this is not the same as |
@alexcrichton seems like there isn't much we can do at the current moment to improve this, besides adding documentation to avoid pitfalls and misconceptions. Thanks to everyone for the feedback, feel free to close if there is nothing further to discuss. |
The libs team got a chance to discuss this today and the conclusion was that we're going to close this for now. There are enough open questions about this API that it doesn't seem quite appropriate for the standard library just yet, but thanks regardless for the PR @ipetkov! |
I was also looking for something like this today as well. What kind of documentation would help? I'd be willing to open a PR. An explanation that to duplicate a Cow, you should just
Is requiring |
I'll try to put the I don't think requiring The natural signature is: impl<'a, T> Cow<'a, T> {
fn shallow_copy<'b>(&'b self) -> Cow<'b, T>;
} (This matches the current state of the PR) And this signature is general enough that it allows |
Has someone implemented @bluss signature proposal? |
I suggest to reopen this. I find even the restricted version very useful. Here is my use case: use std::borrow::Cow;
pub trait CloneExt<'b> {
/// Clone a `Cow` without memory allocation.
/// Note, the original must outlive the clone! Use case:
/// ```
/// use tpnote_lib::clone_ext::CloneExt;
/// use std::borrow::Cow;
/// fn do_something_or_nothing(v: Cow<str>) -> Cow<str> {
/// if v.len() > 3 {
/// let s = "Hello ".to_string() + &*v;
/// Cow::Owned(s)
/// } else {
/// v
/// }
/// }
/// // Sometimes, we only have a `&Cow`, but we need a `Cow`!
/// let a: &Cow<str> = &Cow::Owned("world!".to_string());
/// let b: Cow<str> = a.shallow_clone();
/// assert_eq!(do_something_or_nothing(b), "Hello world!");
///
/// let a: &Cow<str> = &Cow::Owned("ld!".to_string());
/// let b: Cow<str> = a.shallow_clone();
/// assert_eq!(do_something_or_nothing(b), "ld!");
/// ```
fn shallow_clone(&'b self) -> Cow<'b, str>;
}
impl<'b> CloneExt<'b> for Cow<'b, str> {
fn shallow_clone(&'b self) -> Cow<'b, str> {
match *self {
Self::Borrowed(b) => Self::Borrowed(b),
Self::Owned(ref o) => Self::Borrowed(o.as_ref()),
}
}
} Add a |
@getreu Please open an API change proposal (ACP) with the motivation and a proposal that the libs-api team can consider. It's been many years since this was closed so a fresh proposal is warranted. Feel free to also link back to this issue and the internals thread. |
Found myself needing a method to unconditionally borrow the underlying data inside of a
Cow
(there by doing a "shallow copy" instead of a full clone), and I think it could be useful to others.Its a small addition so I figured I'd start the discussion here instead of going through an RFC first.
Currently feature gated behind
cow_shallow_copy
.