From dd13a80344838df06fb5df13e36af4bcac04f4b0 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 12 Sep 2016 23:35:20 +0200 Subject: [PATCH] impl {Add, AddAssign}<{str, Cow}> for Cow 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. --- src/libcollections/borrow.rs | 48 ++++++++++++++++++++++- src/libcollectionstest/cow_str.rs | 65 +++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/libcollectionstest/cow_str.rs diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 700f88dc0f267..6b45c25eb2139 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -14,7 +14,7 @@ use core::cmp::Ordering; use core::hash::{Hash, Hasher}; -use core::ops::Deref; +use core::ops::{Add, AddAssign, Deref}; use fmt; @@ -270,3 +270,49 @@ impl<'a, T: ?Sized + ToOwned> AsRef for Cow<'a, T> { self } } + +#[stable(feature = "cow_add", since = "1.13.0")] +impl<'a> Add<&'a str> for Cow<'a, str> { + type Output = Cow<'a, str>; + + fn add(self, rhs: &'a str) -> Self { + if self == "" { + Cow::Borrowed(rhs) + } else if rhs == "" { + self + } else { + Cow::Owned(self.into_owned() + rhs) + } + } +} + +#[stable(feature = "cow_add", since = "1.13.0")] +impl<'a> Add> for Cow<'a, str> { + type Output = Cow<'a, str>; + + fn add(self, rhs: Cow<'a, str>) -> Self { + if self == "" { + rhs + } else if rhs == "" { + self + } else { + Cow::Owned(self.into_owned() + rhs.borrow()) + } + } +} + +#[stable(feature = "cow_add", since = "1.13.0")] +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); + } +} + +#[stable(feature = "cow_add", since = "1.13.0")] +impl<'a> AddAssign> for Cow<'a, str> { + fn add_assign(&mut self, rhs: Cow<'a, str>) { + if rhs == "" { return; } + self.to_mut().push_str(rhs.borrow()); + } +} diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollectionstest/cow_str.rs new file mode 100644 index 0000000000000..82533ba077541 --- /dev/null +++ b/src/libcollectionstest/cow_str.rs @@ -0,0 +1,65 @@ +// Copyright 2012-2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::borrow::Cow; + +// check that Cow<'a, str> implements addition +#[test] +fn check_cow_add() { + borrowed1 = Cow::Borrowed("Hello, "); + borrowed2 = Cow::Borrowed("World!"); + borrow_empty = Cow::Borrowed(""); + + owned1 = Cow::Owned("Hi, ".into()); + owned2 = Cow::Owned("Rustaceans!".into()); + owned_empty = Cow::Owned("".into()); + + assert_eq!("Hello, World!", borrowed1 + borrowed2); + assert_eq!("Hello, Rustaceans!", borrowed1 + owned2); + + assert_eq!("Hello, World!", owned1 + borrowed2); + assert_eq!("Hello, Rustaceans!", owned1 + owned2); + + if let Cow::Owned(_) = borrowed1 + borrow_empty { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrow_empty + borrowed1 { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrowed1 + owned_empty { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = owned_empty + borrowed1 { + panic!("Adding empty strings to a borrow should note allocate"); + } +} + +fn check_cow_add_assign() { + borrowed1 = Cow::Borrowed("Hello, "); + borrowed2 = Cow::Borrowed("World!"); + borrow_empty = Cow::Borrowed(""); + + owned1 = Cow::Owned("Hi, ".into()); + owned2 = Cow::Owned("Rustaceans!".into()); + owned_empty = Cow::Owned("".into()); + + let borrowed1clone = borrowed1.clone(); + borrowed1clone += borrow_empty; + assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr()); + + borrowed1clone += owned_empty; + assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr()); + + owned1 += borrowed2; + borrowed1 += owned2; + + assert_eq!("Hello, World!", owned1); + assert_eq!("Hello, Rustaceans!", borrowed1); +}