Skip to content

Commit 05fd1c7

Browse files
committed
impl Add<char> and AddAssign<char> for String
1 parent e8f43b7 commit 05fd1c7

File tree

3 files changed

+156
-1
lines changed

3 files changed

+156
-1
lines changed

src/liballoc/string.rs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,6 +1982,123 @@ impl Add<&str> for String {
19821982
}
19831983
}
19841984

1985+
#[allow(missing_docs)]
1986+
#[stable(feature = "add_string_and_dbl_ref_str", since = "1.41.0")]
1987+
impl Add<&&str> for String {
1988+
type Output = String;
1989+
1990+
#[inline]
1991+
fn add(mut self, other: &&str) -> String {
1992+
self.push_str(other);
1993+
self
1994+
}
1995+
}
1996+
1997+
/// Implements the `+` operator for concatenating two `String`s.
1998+
///
1999+
/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if
2000+
/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on
2001+
/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by
2002+
/// repeated concatenation.
2003+
///
2004+
/// The string on the right-hand side is only borrowed; its contents are copied into the returned
2005+
/// `String`.
2006+
///
2007+
/// # Examples
2008+
///
2009+
/// Concatenating two `String`s takes the first by value and borrows the second:
2010+
///
2011+
/// ```
2012+
/// let a = String::from("hello");
2013+
/// let b = String::from(" world");
2014+
/// let c = a + &b;
2015+
/// // `a` is moved and can no longer be used here.
2016+
/// ```
2017+
///
2018+
/// If you want to keep using the first `String`, you can clone it and append to the clone instead:
2019+
///
2020+
/// ```
2021+
/// let a = String::from("hello");
2022+
/// let b = String::from(" world");
2023+
/// let c = a.clone() + &b;
2024+
/// // `a` is still valid here.
2025+
/// ```
2026+
///
2027+
/// Concatenating `&str` slices can be done by converting the first to a `String`:
2028+
///
2029+
/// ```
2030+
/// let a = "hello";
2031+
/// let b = " world";
2032+
/// let c = a.to_string() + b;
2033+
/// ```
2034+
#[stable(feature = "add_string_and_ref_string", since = "1.41.0")]
2035+
impl Add<&String> for String {
2036+
type Output = String;
2037+
2038+
#[inline]
2039+
fn add(mut self, other: &String) -> String {
2040+
self.push_str(other);
2041+
self
2042+
}
2043+
}
2044+
2045+
#[allow(missing_docs)]
2046+
#[stable(feature = "add_string_and_dbl_ref_string", since = "1.41.0")]
2047+
impl Add<&&String> for String {
2048+
type Output = String;
2049+
2050+
#[inline]
2051+
fn add(mut self, other: &&String) -> String {
2052+
self.push_str(other);
2053+
self
2054+
}
2055+
}
2056+
2057+
/// Implements the `+` operator for concatenating a string and a char together.
2058+
///
2059+
/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if
2060+
/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on
2061+
/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by
2062+
/// repeated concatenation.
2063+
///
2064+
/// # Examples
2065+
///
2066+
/// Concatenating a `String` with a `char` takes the `String` by value and copies the `char`:
2067+
///
2068+
/// ```
2069+
/// let a = String::from("hello world! ");
2070+
/// let b = '👋';
2071+
/// let c = a + b;
2072+
/// // `a` is moved and can no longer be used here.
2073+
/// ```
2074+
///
2075+
/// If you want to keep using the initial `String`, you can clone it and append to the clone instead:
2076+
///
2077+
/// ```
2078+
/// let a = String::from("hello world! ");
2079+
/// let b = '👋';
2080+
/// let c = a.clone() + b;
2081+
/// // `a` is still valid here.
2082+
/// ```
2083+
///
2084+
/// Concatenating `char` to a `&str` slice can be done by converting the `&str` to a `String`:
2085+
///
2086+
/// ```
2087+
/// let a = "hello world! ";
2088+
/// let b = '👋';
2089+
/// let c = a.to_string() + b;
2090+
/// ```
2091+
#[stable(feature = "add_string_and_char", since = "1.41.0")]
2092+
impl Add<char> for String {
2093+
type Output = String;
2094+
2095+
#[inline]
2096+
fn add(mut self, other: char) -> String {
2097+
self.push(other);
2098+
self
2099+
}
2100+
}
2101+
19852102
/// Implements the `+=` operator for appending to a `String`.
19862103
///
19872104
/// This has the same behavior as the [`push_str`][String::push_str] method.
@@ -1993,6 +2110,28 @@ impl AddAssign<&str> for String {
19932110
}
19942111
}
19952112

2113+
/// Implements the `+=` operator for appending to a `String`.
2114+
///
2115+
/// This has the same behavior as the [`push_str`][String::push_str] method.
2116+
#[stable(feature = "stringaddassign_string", since = "1.41.0")]
2117+
impl AddAssign<&String> for String {
2118+
#[inline]
2119+
fn add_assign(&mut self, other: &String) {
2120+
self.push_str(other);
2121+
}
2122+
}
2123+
2124+
/// Implements the `+=` operator for appending a `char` to a `String`.
2125+
///
2126+
/// This has the same behavior as the [`push`][String::push] method.
2127+
#[stable(feature = "stringaddassign_char", since = "1.41.0")]
2128+
impl AddAssign<char> for String {
2129+
#[inline]
2130+
fn add_assign(&mut self, other: char) {
2131+
self.push(other);
2132+
}
2133+
}
2134+
19962135
#[stable(feature = "rust1", since = "1.0.0")]
19972136
impl ops::Index<ops::Range<usize>> for String {
19982137
type Output = str;

src/libsyntax/parse/parser/expr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,9 @@ impl<'a> Parser<'a> {
10841084
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix })
10851085
= next_token.kind {
10861086
if self.token.span.hi() == next_token.span.lo() {
1087-
let s = String::from("0.") + &symbol.as_str();
1087+
// FIXME: Should just be `&symbol.as_str()` but can't as of now due to Deref coercion
1088+
// Issue: https://github.com/rust-lang/rust/issues/51916
1089+
let s = String::from("0.") + &symbol.as_str().get_str();
10881090
let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
10891091
return Some(Token::new(kind, self.token.span.to(next_token.span)));
10901092
}

src/libsyntax_pos/symbol.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,15 @@ pub struct SymbolStr {
11041104
string: &'static str,
11051105
}
11061106

1107+
/// FIXME: This is not needed once we are able to fix the Deref coercion issue.
1108+
/// Issue: https://github.com/rust-lang/rust/issues/51916
1109+
impl SymbolStr {
1110+
#[inline]
1111+
pub fn get_str(&self) -> &str {
1112+
self.string
1113+
}
1114+
}
1115+
11071116
// This impl allows a `SymbolStr` to be directly equated with a `String` or
11081117
// `&str`.
11091118
impl<T: std::ops::Deref<Target = str>> std::cmp::PartialEq<T> for SymbolStr {
@@ -1120,6 +1129,11 @@ impl !Sync for SymbolStr {}
11201129
/// - `&*ss` is a `&str`;
11211130
/// - `&ss as &str` is a `&str`, which means that `&ss` can be passed to a
11221131
/// function expecting a `&str`.
1132+
///
1133+
/// FIXME: This has no meaning anymore since the addition of implementations
1134+
/// of `Add<char> for String`, `Add<&&str> for String`, and `Add<&&String> for String`.
1135+
/// Due to the outstanding Deref coercion issue this Deref implementation gets ignored.
1136+
/// Issue: https://github.com/rust-lang/rust/issues/51916
11231137
impl std::ops::Deref for SymbolStr {
11241138
type Target = str;
11251139
#[inline]

0 commit comments

Comments
 (0)