Skip to content

Commit

Permalink
Add generic conversion traits
Browse files Browse the repository at this point in the history
This commit:

* Introduces `std::convert`, providing an implementation of
RFC 529.

* Deprecates the `AsPath`, `AsOsStr`, and `IntoBytes` traits, all
in favor of the corresponding generic conversion traits.

  Consequently, various IO APIs now take `AsRef<Path>` rather than
`AsPath`, and so on. Since the types provided by `std` implement both
traits, this should cause relatively little breakage.

* Deprecates many `from_foo` constructors in favor of `from`.

* Changes `PathBuf::new` to take no argument (creating an empty buffer,
  as per convention). The previous behavior is now available as
  `PathBuf::from`.

* De-stabilizes `IntoCow`. It's not clear whether we need this separate trait.

Closes #22751
Closes #14433

[breaking-change]
  • Loading branch information
aturon committed Mar 23, 2015
1 parent b0aad7d commit 8389253
Show file tree
Hide file tree
Showing 69 changed files with 666 additions and 196 deletions.
10 changes: 6 additions & 4 deletions src/compiletest/compiletest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#![feature(std_misc)]
#![feature(test)]
#![feature(path_ext)]
#![feature(convert)]
#![feature(str_char)]

#![deny(warnings)]

Expand Down Expand Up @@ -115,7 +117,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {

fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
match m.opt_str(nm) {
Some(s) => PathBuf::new(&s),
Some(s) => PathBuf::from(&s),
None => panic!("no option (=path) found for {}", nm),
}
}
Expand All @@ -130,18 +132,18 @@ pub fn parse_config(args: Vec<String> ) -> Config {
compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
run_lib_path: matches.opt_str("run-lib-path").unwrap(),
rustc_path: opt_path(matches, "rustc-path"),
clang_path: matches.opt_str("clang-path").map(|s| PathBuf::new(&s)),
clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)),
valgrind_path: matches.opt_str("valgrind-path"),
force_valgrind: matches.opt_present("force-valgrind"),
llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::new(&s)),
llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::from(&s)),
src_base: opt_path(matches, "src-base"),
build_base: opt_path(matches, "build-base"),
aux_base: opt_path(matches, "aux-base"),
stage_id: matches.opt_str("stage-id").unwrap(),
mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"),
run_ignored: matches.opt_present("ignored"),
filter: filter,
logfile: matches.opt_str("logfile").map(|s| PathBuf::new(&s)),
logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
runtool: matches.opt_str("runtool"),
host_rustcflags: matches.opt_str("host-rustcflags"),
target_rustcflags: matches.opt_str("target-rustcflags"),
Expand Down
4 changes: 2 additions & 2 deletions src/compiletest/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {

fn parse_pp_exact(line: &str, testfile: &Path) -> Option<PathBuf> {
match parse_name_value_directive(line, "pp-exact") {
Some(s) => Some(PathBuf::new(&s)),
Some(s) => Some(PathBuf::from(&s)),
None => {
if parse_name_directive(line, "pp-exact") {
testfile.file_name().map(|s| PathBuf::new(s))
testfile.file_name().map(|s| PathBuf::from(s))
} else {
None
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiletest/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1440,7 +1440,7 @@ fn aux_output_dir_name(config: &Config, testfile: &Path) -> PathBuf {
}

fn output_testname(testfile: &Path) -> PathBuf {
PathBuf::new(testfile.file_stem().unwrap())
PathBuf::from(testfile.file_stem().unwrap())
}

fn output_base_name(config: &Config, testfile: &Path) -> PathBuf {
Expand Down
11 changes: 9 additions & 2 deletions src/libcollections/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use core::clone::Clone;
use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use core::convert::AsRef;
use core::hash::{Hash, Hasher};
use core::marker::Sized;
use core::ops::Deref;
Expand Down Expand Up @@ -291,10 +292,9 @@ impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned
}

/// Trait for moving into a `Cow`
#[stable(feature = "rust1", since = "1.0.0")]
#[unstable(feature = "into_cow", reason = "may be replaced by `convert::Into`")]
pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
/// Moves `self` into `Cow`
#[stable(feature = "rust1", since = "1.0.0")]
fn into_cow(self) -> Cow<'a, B>;
}

Expand All @@ -304,3 +304,10 @@ impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
self
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Clone> AsRef<T> for Cow<'a, T> {
fn as_ref(&self) -> &T {
self
}
}
1 change: 1 addition & 0 deletions src/libcollections/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#![feature(unsafe_no_drop_flag)]
#![feature(step_by)]
#![feature(str_char)]
#![feature(convert)]
#![cfg_attr(test, feature(rand, rustc_private, test))]
#![cfg_attr(test, allow(deprecated))] // rand

Expand Down
11 changes: 6 additions & 5 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
#![stable(feature = "rust1", since = "1.0.0")]

use alloc::boxed::Box;
use core::convert::AsRef;
use core::clone::Clone;
use core::cmp::Ordering::{self, Greater, Less};
use core::cmp::{self, Ord, PartialEq};
Expand Down Expand Up @@ -1088,23 +1089,23 @@ pub trait SliceConcatExt<T: ?Sized, U> {
fn connect(&self, sep: &T) -> U;
}

impl<T: Clone, V: AsSlice<T>> SliceConcatExt<T, Vec<T>> for [V] {
impl<T: Clone, V: AsRef<[T]>> SliceConcatExt<T, Vec<T>> for [V] {
fn concat(&self) -> Vec<T> {
let size = self.iter().fold(0, |acc, v| acc + v.as_slice().len());
let size = self.iter().fold(0, |acc, v| acc + v.as_ref().len());
let mut result = Vec::with_capacity(size);
for v in self {
result.push_all(v.as_slice())
result.push_all(v.as_ref())
}
result
}

fn connect(&self, sep: &T) -> Vec<T> {
let size = self.iter().fold(0, |acc, v| acc + v.as_slice().len());
let size = self.iter().fold(0, |acc, v| acc + v.as_ref().len());
let mut result = Vec::with_capacity(size + self.len());
let mut first = true;
for v in self {
if first { first = false } else { result.push(sep.clone()) }
result.push_all(v.as_slice())
result.push_all(v.as_ref())
}
result
}
Expand Down
28 changes: 12 additions & 16 deletions src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ use core::iter::AdditiveIterator;
use core::iter::{Iterator, IteratorExt, Extend};
use core::option::Option::{self, Some, None};
use core::result::Result;
use core::slice::AsSlice;
use core::str as core_str;
use unicode::str::{UnicodeStr, Utf16Encoder};

use core::convert::AsRef;
use vec_deque::VecDeque;
use borrow::{Borrow, ToOwned};
use string::String;
Expand All @@ -86,51 +86,47 @@ pub use core::str::{Searcher, ReverseSearcher, DoubleEndedSearcher, SearchStep};
Section: Creating a string
*/

impl<S: Str> SliceConcatExt<str, String> for [S] {
impl<S: AsRef<str>> SliceConcatExt<str, String> for [S] {
fn concat(&self) -> String {
let s = self.as_slice();

if s.is_empty() {
if self.is_empty() {
return String::new();
}

// `len` calculation may overflow but push_str will check boundaries
let len = s.iter().map(|s| s.as_slice().len()).sum();
let len = self.iter().map(|s| s.as_ref().len()).sum();
let mut result = String::with_capacity(len);

for s in s {
result.push_str(s.as_slice())
for s in self {
result.push_str(s.as_ref())
}

result
}

fn connect(&self, sep: &str) -> String {
let s = self.as_slice();

if s.is_empty() {
if self.is_empty() {
return String::new();
}

// concat is faster
if sep.is_empty() {
return s.concat();
return self.concat();
}

// this is wrong without the guarantee that `self` is non-empty
// `len` calculation may overflow but push_str but will check boundaries
let len = sep.len() * (s.len() - 1)
+ s.iter().map(|s| s.as_slice().len()).sum();
let len = sep.len() * (self.len() - 1)
+ self.iter().map(|s| s.as_ref().len()).sum();
let mut result = String::with_capacity(len);
let mut first = true;

for s in s {
for s in self {
if first {
first = false;
} else {
result.push_str(sep);
}
result.push_str(s.as_slice());
result.push_str(s.as_ref());
}
result
}
Expand Down
23 changes: 23 additions & 0 deletions src/libcollections/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,7 @@ impl<'a, 'b> PartialEq<Cow<'a, str>> for &'b str {
}

#[unstable(feature = "collections", reason = "waiting on Str stabilization")]
#[allow(deprecated)]
impl Str for String {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -973,6 +974,27 @@ impl<T: fmt::Display + ?Sized> ToString for T {
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for String {
fn as_ref(&self) -> &str {
self
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<&'a str> for String {
fn from(s: &'a str) -> String {
s.to_string()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Into<Vec<u8>> for String {
fn into(self) -> Vec<u8> {
self.into_bytes()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl IntoCow<'static, str> for String {
#[inline]
Expand All @@ -989,6 +1011,7 @@ impl<'a> IntoCow<'a, str> for &'a str {
}
}

#[allow(deprecated)]
impl<'a> Str for Cow<'a, str> {
#[inline]
fn as_slice<'b>(&'b self) -> &'b str {
Expand Down
52 changes: 45 additions & 7 deletions src/libcollections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1369,7 +1369,7 @@ impl<T> ops::Index<ops::RangeFull> for Vec<T> {
type Output = [T];
#[inline]
fn index(&self, _index: &ops::RangeFull) -> &[T] {
self.as_slice()
self
}
}

Expand Down Expand Up @@ -1406,7 +1406,13 @@ impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> {
impl<T> ops::Deref for Vec<T> {
type Target = [T];

fn deref(&self) -> &[T] { self.as_slice() }
fn deref(&self) -> &[T] {
unsafe {
let p = *self.ptr;
assume(p != 0 as *mut T);
slice::from_raw_parts(p, self.len)
}
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -1548,6 +1554,7 @@ impl<T: Ord> Ord for Vec<T> {
}
}

#[allow(deprecated)]
impl<T> AsSlice<T> for Vec<T> {
/// Returns a slice into `self`.
///
Expand All @@ -1562,11 +1569,7 @@ impl<T> AsSlice<T> for Vec<T> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn as_slice(&self) -> &[T] {
unsafe {
let p = *self.ptr;
assume(p != 0 as *mut T);
slice::from_raw_parts(p, self.len)
}
self
}
}

Expand Down Expand Up @@ -1614,6 +1617,41 @@ impl<T: fmt::Debug> fmt::Debug for Vec<T> {
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<Vec<T>> for Vec<T> {
fn as_ref(&self) -> &Vec<T> {
self
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Into<Vec<T>> for Vec<T> {
fn into(self) -> Vec<T> {
self
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for Vec<T> {
fn as_ref(&self) -> &[T] {
self
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Clone> From<&'a [T]> for Vec<T> {
fn from(s: &'a [T]) -> Vec<T> {
s.to_vec()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<&'a str> for Vec<u8> {
fn from(s: &'a str) -> Vec<u8> {
s.as_bytes().to_vec()
}
}

////////////////////////////////////////////////////////////////////////////////
// Clone-on-write
////////////////////////////////////////////////////////////////////////////////
Expand Down
Loading

0 comments on commit 8389253

Please sign in to comment.