Skip to content

Commit 1e40c80

Browse files
committed
Fix issues with the Add/AddAssign impls for Cow<str>
* Correct the stability attributes. * Make Add and AddAssign actually behave the same. * Use String::with_capacity when allocating a new string. * Fix the tests.
1 parent acfe959 commit 1e40c80

File tree

3 files changed

+143
-53
lines changed

3 files changed

+143
-53
lines changed

src/libcollections/borrow.rs

+37-24
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use core::hash::{Hash, Hasher};
1717
use core::ops::{Add, AddAssign, Deref};
1818

1919
use fmt;
20+
use string::String;
2021

2122
use self::Cow::*;
2223

@@ -284,48 +285,60 @@ impl<'a, T: ?Sized + ToOwned> AsRef<T> for Cow<'a, T> {
284285
}
285286
}
286287

287-
#[stable(feature = "cow_add", since = "1.13.0")]
288+
#[stable(feature = "cow_add", since = "1.14.0")]
288289
impl<'a> Add<&'a str> for Cow<'a, str> {
289290
type Output = Cow<'a, str>;
290291

291-
fn add(self, rhs: &'a str) -> Self {
292-
if self == "" {
293-
Cow::Borrowed(rhs)
294-
} else if rhs == "" {
295-
self
296-
} else {
297-
Cow::Owned(self.into_owned() + rhs)
298-
}
292+
#[inline]
293+
fn add(mut self, rhs: &'a str) -> Self::Output {
294+
self += rhs;
295+
self
299296
}
300297
}
301298

302-
#[stable(feature = "cow_add", since = "1.13.0")]
299+
#[stable(feature = "cow_add", since = "1.14.0")]
303300
impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
304301
type Output = Cow<'a, str>;
305302

306-
fn add(self, rhs: Cow<'a, str>) -> Self {
307-
if self == "" {
308-
rhs
309-
} else if rhs == "" {
310-
self
311-
} else {
312-
Cow::Owned(self.into_owned() + rhs.borrow())
313-
}
303+
#[inline]
304+
fn add(mut self, rhs: Cow<'a, str>) -> Self::Output {
305+
self += rhs;
306+
self
314307
}
315308
}
316309

317-
#[stable(feature = "cow_add", since = "1.13.0")]
310+
#[stable(feature = "cow_add", since = "1.14.0")]
318311
impl<'a> AddAssign<&'a str> for Cow<'a, str> {
319312
fn add_assign(&mut self, rhs: &'a str) {
320-
if rhs == "" { return; }
321-
self.to_mut().push_str(rhs);
313+
if self.is_empty() {
314+
*self = Cow::Borrowed(rhs)
315+
} else if rhs.is_empty() {
316+
return;
317+
} else {
318+
if let Cow::Borrowed(lhs) = *self {
319+
let mut s = String::with_capacity(lhs.len() + rhs.len());
320+
s.push_str(lhs);
321+
*self = Cow::Owned(s);
322+
}
323+
self.to_mut().push_str(rhs);
324+
}
322325
}
323326
}
324327

325-
#[stable(feature = "cow_add", since = "1.13.0")]
328+
#[stable(feature = "cow_add", since = "1.14.0")]
326329
impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
327330
fn add_assign(&mut self, rhs: Cow<'a, str>) {
328-
if rhs == "" { return; }
329-
self.to_mut().push_str(rhs.borrow());
331+
if self.is_empty() {
332+
*self = rhs
333+
} else if rhs.is_empty() {
334+
return;
335+
} else {
336+
if let Cow::Borrowed(lhs) = *self {
337+
let mut s = String::with_capacity(lhs.len() + rhs.len());
338+
s.push_str(lhs);
339+
*self = Cow::Owned(s);
340+
}
341+
self.to_mut().push_str(&rhs);
342+
}
330343
}
331344
}

src/libcollectionstest/cow_str.rs

+105-29
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012-2013-2014 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -12,54 +12,130 @@ use std::borrow::Cow;
1212

1313
// check that Cow<'a, str> implements addition
1414
#[test]
15-
fn check_cow_add() {
16-
borrowed1 = Cow::Borrowed("Hello, ");
17-
borrowed2 = Cow::Borrowed("World!");
18-
borrow_empty = Cow::Borrowed("");
15+
fn check_cow_add_cow() {
16+
let borrowed1 = Cow::Borrowed("Hello, ");
17+
let borrowed2 = Cow::Borrowed("World!");
18+
let borrow_empty = Cow::Borrowed("");
1919

20-
owned1 = Cow::Owned("Hi, ".into());
21-
owned2 = Cow::Owned("Rustaceans!".into());
22-
owned_empty = Cow::Owned("".into());
20+
let owned1: Cow<str> = Cow::Owned(String::from("Hi, "));
21+
let owned2: Cow<str> = Cow::Owned(String::from("Rustaceans!"));
22+
let owned_empty: Cow<str> = Cow::Owned(String::new());
2323

24-
assert_eq!("Hello, World!", borrowed1 + borrowed2);
25-
assert_eq!("Hello, Rustaceans!", borrowed1 + owned2);
24+
assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone());
25+
assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone());
2626

27-
assert_eq!("Hello, World!", owned1 + borrowed2);
28-
assert_eq!("Hello, Rustaceans!", owned1 + owned2);
27+
assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone());
28+
assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone());
2929

30-
if let Cow::Owned(_) = borrowed1 + borrow_empty {
30+
if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() {
3131
panic!("Adding empty strings to a borrow should note allocate");
3232
}
33-
if let Cow::Owned(_) = borrow_empty + borrowed1 {
33+
if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() {
3434
panic!("Adding empty strings to a borrow should note allocate");
3535
}
36-
if let Cow::Owned(_) = borrowed1 + owned_empty {
36+
if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() {
3737
panic!("Adding empty strings to a borrow should note allocate");
3838
}
39-
if let Cow::Owned(_) = owned_empty + borrowed1 {
39+
if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() {
4040
panic!("Adding empty strings to a borrow should note allocate");
4141
}
4242
}
4343

44-
fn check_cow_add_assign() {
45-
borrowed1 = Cow::Borrowed("Hello, ");
46-
borrowed2 = Cow::Borrowed("World!");
47-
borrow_empty = Cow::Borrowed("");
44+
#[test]
45+
fn check_cow_add_str() {
46+
let borrowed = Cow::Borrowed("Hello, ");
47+
let borrow_empty = Cow::Borrowed("");
48+
49+
let owned: Cow<str> = Cow::Owned(String::from("Hi, "));
50+
let owned_empty: Cow<str> = Cow::Owned(String::new());
4851

49-
owned1 = Cow::Owned("Hi, ".into());
50-
owned2 = Cow::Owned("Rustaceans!".into());
51-
owned_empty = Cow::Owned("".into());
52+
assert_eq!("Hello, World!", borrowed.clone() + "World!");
5253

53-
let borrowed1clone = borrowed1.clone();
54-
borrowed1clone += borrow_empty;
55-
assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr());
54+
assert_eq!("Hi, World!", owned.clone() + "World!");
5655

57-
borrowed1clone += owned_empty;
58-
assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr());
56+
if let Cow::Owned(_) = borrowed.clone() + "" {
57+
panic!("Adding empty strings to a borrow should note allocate");
58+
}
59+
if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " {
60+
panic!("Adding empty strings to a borrow should note allocate");
61+
}
62+
if let Cow::Owned(_) = owned_empty.clone() + "Hello, " {
63+
panic!("Adding empty strings to a borrow should note allocate");
64+
}
65+
}
66+
67+
#[test]
68+
fn check_cow_add_assign_cow() {
69+
let mut borrowed1 = Cow::Borrowed("Hello, ");
70+
let borrowed2 = Cow::Borrowed("World!");
71+
let borrow_empty = Cow::Borrowed("");
72+
73+
let mut owned1: Cow<str> = Cow::Owned(String::from("Hi, "));
74+
let owned2: Cow<str> = Cow::Owned(String::from("Rustaceans!"));
75+
let owned_empty: Cow<str> = Cow::Owned(String::new());
76+
77+
let mut s = borrowed1.clone();
78+
s += borrow_empty.clone();
79+
assert_eq!("Hello, ", s);
80+
if let Cow::Owned(_) = s {
81+
panic!("Adding empty strings to a borrow should note allocate");
82+
}
83+
let mut s = borrow_empty.clone();
84+
s += borrowed1.clone();
85+
assert_eq!("Hello, ", s);
86+
if let Cow::Owned(_) = s {
87+
panic!("Adding empty strings to a borrow should note allocate");
88+
}
89+
let mut s = borrowed1.clone();
90+
s += owned_empty.clone();
91+
assert_eq!("Hello, ", s);
92+
if let Cow::Owned(_) = s {
93+
panic!("Adding empty strings to a borrow should note allocate");
94+
}
95+
let mut s = owned_empty.clone();
96+
s += borrowed1.clone();
97+
assert_eq!("Hello, ", s);
98+
if let Cow::Owned(_) = s {
99+
panic!("Adding empty strings to a borrow should note allocate");
100+
}
59101

60102
owned1 += borrowed2;
61103
borrowed1 += owned2;
62104

63-
assert_eq!("Hello, World!", owned1);
105+
assert_eq!("Hi, World!", owned1);
64106
assert_eq!("Hello, Rustaceans!", borrowed1);
65107
}
108+
109+
#[test]
110+
fn check_cow_add_assign_str() {
111+
let mut borrowed = Cow::Borrowed("Hello, ");
112+
let borrow_empty = Cow::Borrowed("");
113+
114+
let mut owned: Cow<str> = Cow::Owned(String::from("Hi, "));
115+
let owned_empty: Cow<str> = Cow::Owned(String::new());
116+
117+
let mut s = borrowed.clone();
118+
s += "";
119+
assert_eq!("Hello, ", s);
120+
if let Cow::Owned(_) = s {
121+
panic!("Adding empty strings to a borrow should note allocate");
122+
}
123+
let mut s = borrow_empty.clone();
124+
s += "World!";
125+
assert_eq!("World!", s);
126+
if let Cow::Owned(_) = s {
127+
panic!("Adding empty strings to a borrow should note allocate");
128+
}
129+
let mut s = owned_empty.clone();
130+
s += "World!";
131+
assert_eq!("World!", s);
132+
if let Cow::Owned(_) = s {
133+
panic!("Adding empty strings to a borrow should note allocate");
134+
}
135+
136+
owned += "World!";
137+
borrowed += "World!";
138+
139+
assert_eq!("Hi, World!", owned);
140+
assert_eq!("Hello, World!", borrowed);
141+
}

src/libcollectionstest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ mod bench;
4242

4343
mod binary_heap;
4444
mod btree;
45+
mod cow_str;
4546
mod enum_set;
4647
mod fmt;
4748
mod linked_list;

0 commit comments

Comments
 (0)