From 3ed618443437307749e4c773f260c2b4b94673f5 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Sun, 14 Feb 2021 15:01:46 -0800 Subject: [PATCH 1/3] Implement Extend and FromIterator for OsString Add the following trait impls: - `impl Extend for OsString` - `impl<'a> Extend<&'a OsStr> for OsString` - `impl FromIterator for OsString` - `impl<'a> FromIterator<&'a OsStr> for OsString` Because `OsString` is a platform string with no particular semantics, concatenating them together seems acceptable. --- library/std/src/ffi/os_str.rs | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c9c8f68cd9cce..b7aff83eaf50e 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -5,6 +5,7 @@ use crate::borrow::{Borrow, Cow}; use crate::cmp; use crate::fmt; use crate::hash::{Hash, Hasher}; +use crate::iter::{Extend, FromIterator}; use crate::ops; use crate::rc::Rc; use crate::str::FromStr; @@ -1182,3 +1183,47 @@ impl FromStr for OsString { Ok(OsString::from(s)) } } + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl Extend for OsString { + #[inline] + fn extend>(&mut self, iter: T) { + for s in iter { + self.push(&s); + } + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl<'a> Extend<&'a OsStr> for OsString { + #[inline] + fn extend>(&mut self, iter: T) { + for s in iter { + self.push(s); + } + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl FromIterator for OsString { + #[inline] + fn from_iter>(iter: I) -> Self { + let mut buf = Self::new(); + for s in iter { + buf.push(&s); + } + buf + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl<'a> FromIterator<&'a OsStr> for OsString { + #[inline] + fn from_iter>(iter: I) -> Self { + let mut buf = Self::new(); + for s in iter { + buf.push(s); + } + buf + } +} From 2fcb8b5c201d22060f1ba46cc2291cacca593e02 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 16 Feb 2021 14:14:59 -0800 Subject: [PATCH 2/3] Optimize FromIterator to reuse the first allocation --- library/std/src/ffi/os_str.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index b7aff83eaf50e..8240aafae74e7 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1208,11 +1208,18 @@ impl<'a> Extend<&'a OsStr> for OsString { impl FromIterator for OsString { #[inline] fn from_iter>(iter: I) -> Self { - let mut buf = Self::new(); - for s in iter { - buf.push(&s); + let mut iterator = iter.into_iter(); + + // Because we're iterating over `OsString`s, we can avoid at least + // one allocation by getting the first string from the iterator + // and appending to it all the subsequent strings. + match iterator.next() { + None => OsString::new(), + Some(mut buf) => { + buf.extend(iterator); + buf + } } - buf } } From 05ea200213fe30967fff38ebac887c52803aabd5 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Wed, 3 Mar 2021 11:52:14 -0800 Subject: [PATCH 3/3] Add impls for iterators of Cow --- library/std/src/ffi/os_str.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 8240aafae74e7..8bdd9a88473f9 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1204,6 +1204,16 @@ impl<'a> Extend<&'a OsStr> for OsString { } } +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl<'a> Extend> for OsString { + #[inline] + fn extend>>(&mut self, iter: T) { + for s in iter { + self.push(&s); + } + } +} + #[stable(feature = "osstring_extend", since = "1.52.0")] impl FromIterator for OsString { #[inline] @@ -1234,3 +1244,27 @@ impl<'a> FromIterator<&'a OsStr> for OsString { buf } } + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl<'a> FromIterator> for OsString { + #[inline] + fn from_iter>>(iter: I) -> Self { + let mut iterator = iter.into_iter(); + + // Because we're iterating over `OsString`s, we can avoid at least + // one allocation by getting the first owned string from the iterator + // and appending to it all the subsequent strings. + match iterator.next() { + None => OsString::new(), + Some(Cow::Owned(mut buf)) => { + buf.extend(iterator); + buf + } + Some(Cow::Borrowed(buf)) => { + let mut buf = OsString::from(buf); + buf.extend(iterator); + buf + } + } + } +}