-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
impl Add<{str, Cow<str>}> for Cow<str> #36430
Conversation
r? @alexcrichton – or do we need to discuss this first? |
if self == "" { | ||
Cow::Borrowed(rhs) | ||
} else if rhs == "" { | ||
self.clone() |
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 can just be self
, right?
Thanks for the PR! Could you expand on the rationale for this as well? E.g. it seems specifically for the optimization where one side is empty? |
Exactly. I have found this optimization while looking at Raph Levien's xi-editor, and thought it'd be a good idea to have it in libcollections. |
There's a relevant discussion happening in the internals forum right now: https://internals.rust-lang.org/t/implement-add-for-string-string/4088/7 Personally, I am opposed to adding further As an addendum to that, it may be a good idea to lay out what basic mathematical operator properties we like for the operator trait implementations to respect (commutativity, associativity, etc.). Obviously, as they are safe traits, such properties couldn't be relied on in safe code, but including an explanation of them in the docs would (hopefully) encourage the creation of implementations which respect users' intuitions for those operators. |
I know where you come from, but |
Yeah, you may be right given that string concatenation via |
I've tagged for discussion in libs triage, but I agree that it's probably too late to remove Also @llogiq can you add |
That took way longer than usual due to my notebook (which was broken by my kids) failing when it gets hot – for example during a Rust build. @alexcrichton should I add anything else? |
Ah nope, just waiting on the libs team to discuss. Our conclusion was that this should be good to go. Want to squash the commits as well? |
scratch that, the kid's sleeping, found the time to squash. 😀 |
This does not actually add anything that wasn't there, but is merely an optimization for the given cases, which would have incurred additional heap allocation for adding empty strings, and improving the ergonomics of `Cow` with strings.
@bors: r+ Oh wow, congratulations! I can definitely take over from here :) |
📌 Commit dd13a80 has been approved by |
impl Add<{str, Cow<str>}> for Cow<str> cc #35837
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.
It might be worth adding tests for Cow
+ &str
as well.
@@ -270,3 +270,49 @@ impl<'a, T: ?Sized + ToOwned> AsRef<T> for Cow<'a, T> { | |||
self | |||
} | |||
} | |||
|
|||
#[stable(feature = "cow_add", since = "1.13.0")] |
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.
These will need to be 1.14.0 now.
} else if rhs == "" { | ||
self | ||
} else { | ||
Cow::Owned(self.into_owned() + rhs) |
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.
If self
is a Cow::Borrowed
it would be better to use String::with_capacity
to create the new string so we avoid an extra reallocation.
impl<'a> AddAssign<&'a str> for Cow<'a, str> { | ||
fn add_assign(&mut self, rhs: &'a str) { | ||
if rhs == "" { return; } | ||
self.to_mut().push_str(rhs); |
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 doesn't behave the same as the Add
implementations. If self
is empty this should result in a Cow::Borrowed
like with Add
not Cow::Owned
.
@@ -0,0 +1,65 @@ | |||
// Copyright 2012-2013-2014 The Rust Project Developers. See the COPYRIGHT |
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.
You'll need to add mod cow_str;
to src/libcollectionstest/lib.rs
for this file to be used.
Also I'm pretty sure "2012-2013-2014" isn't the correct year 😉.
assert_eq!("Hello, Rustaceans!", borrowed1 + owned2); | ||
|
||
assert_eq!("Hello, World!", owned1 + borrowed2); | ||
assert_eq!("Hello, Rustaceans!", owned1 + owned2); |
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.
These two should presumably start with "Hi, ".
Also owned1
and owned2
have been consumed by this point so will need cloning or something earlier.
} | ||
} | ||
|
||
fn check_cow_add_assign() { |
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 will need #[test]
.
impl<'a> Add<&'a str> for Cow<'a, str> { | ||
type Output = Cow<'a, str>; | ||
|
||
fn add(self, rhs: &'a str) -> Self { |
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 think it would be worth adding documentation to these implementations as the semantics aren't really obvious. Especially explaining why the lifetimes have been restricted like they have.
type Output = Cow<'a, str>; | ||
|
||
fn add(self, rhs: &'a str) -> Self { | ||
if self == "" { |
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.
nit: might be better to use .is_empty()
.
cc #35837