Stabilize std::convert and related code

* Marks `#[stable]` the contents of the `std::convert` module.

* Added methods `PathBuf::as_path`, `OsString::as_os_str`,
  `String::as_str`, `Vec::{as_slice, as_mut_slice}`.

* Deprecates `OsStr::from_str` in favor of a new, stable, and more
  general `OsStr::new`.

* Adds unstable methods `OsString::from_bytes` and `OsStr::{to_bytes,
  to_cstring}` for ergonomic FFI usage.

[breaking-change]
This commit is contained in:
Aaron Turon 2015-03-30 15:15:27 -07:00
parent 6cf3b0b74a
commit 9fc51efe33
25 changed files with 132 additions and 70 deletions

View File

@ -18,7 +18,6 @@
#![feature(std_misc)]
#![feature(test)]
#![feature(path_ext)]
#![feature(convert)]
#![feature(str_char)]
#![deny(warnings)]

View File

@ -38,7 +38,6 @@
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(step_by)]
#![feature(str_char)]
#![feature(convert)]
#![feature(slice_patterns)]
#![feature(debug_builders)]
#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))]

View File

@ -364,6 +364,14 @@ impl String {
self.vec
}
/// Extract a string slice containing the entire string.
#[inline]
#[unstable(feature = "convert",
reason = "waiting on RFC revision")]
pub fn as_str(&self) -> &str {
self
}
/// Pushes the given string onto this string buffer.
///
/// # Examples
@ -848,7 +856,6 @@ impl<'a, 'b> PartialEq<Cow<'a, str>> for &'b str {
#[allow(deprecated)]
impl Str for String {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn as_slice(&self) -> &str {
unsafe { mem::transmute(&*self.vec) }
}

View File

@ -423,11 +423,18 @@ impl<T> Vec<T> {
}
}
/// Extract a slice containing the entire vector.
#[inline]
#[unstable(feature = "convert",
reason = "waiting on RFC revision")]
pub fn as_slice(&self) -> &[T] {
self
}
/// Deprecated: use `&mut s[..]` instead.
#[inline]
#[unstable(feature = "collections",
reason = "will be replaced by slice syntax")]
#[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")]
#[unstable(feature = "convert",
reason = "waiting on RFC revision")]
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self[..]
}
@ -1640,13 +1647,6 @@ impl<T> AsRef<Vec<T>> for Vec<T> {
}
}
#[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] {

View File

@ -14,33 +14,40 @@
//! conversions from one type to another. They follow the standard
//! Rust conventions of `as`/`to`/`into`/`from`.
#![unstable(feature = "convert",
reason = "recently added, experimental traits")]
#![stable(feature = "rust1", since = "1.0.0")]
use marker::Sized;
/// A cheap, reference-to-reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
/// Perform the conversion.
#[stable(feature = "rust1", since = "1.0.0")]
fn as_ref(&self) -> &T;
}
/// A cheap, mutable reference-to-mutable reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
/// Perform the conversion.
#[stable(feature = "rust1", since = "1.0.0")]
fn as_mut(&mut self) -> &mut T;
}
/// A conversion that consumes `self`, which may or may not be
/// expensive.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
/// Perform the conversion.
#[stable(feature = "rust1", since = "1.0.0")]
fn into(self) -> T;
}
/// Construct `Self` via a conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
/// Perform the conversion.
#[stable(feature = "rust1", since = "1.0.0")]
fn from(T) -> Self;
}
@ -48,14 +55,8 @@ pub trait From<T> {
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////
// As implies Into
impl<'a, T: ?Sized, U: ?Sized> Into<&'a U> for &'a T where T: AsRef<U> {
fn into(self) -> &'a U {
self.as_ref()
}
}
// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
fn as_ref(&self) -> &U {
<T as AsRef<U>>::as_ref(*self)
@ -63,6 +64,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
}
// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
fn as_ref(&self) -> &U {
<T as AsRef<U>>::as_ref(*self)
@ -77,14 +79,8 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
// }
// }
// AsMut implies Into
impl<'a, T: ?Sized, U: ?Sized> Into<&'a mut U> for &'a mut T where T: AsMut<U> {
fn into(self) -> &'a mut U {
(*self).as_mut()
}
}
// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
fn as_mut(&mut self) -> &mut U {
(*self).as_mut()
@ -100,28 +96,38 @@ impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
// }
// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
fn into(self) -> U {
U::from(self)
}
}
// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
fn from(t: T) -> T { t }
}
////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
fn as_ref(&self) -> &[T] {
self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
fn as_mut(&mut self) -> &mut [T] {
self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
fn as_ref(&self) -> &str {
self

View File

@ -41,7 +41,6 @@
#![feature(path_ext)]
#![feature(str_words)]
#![feature(str_char)]
#![feature(convert)]
#![feature(into_cow)]
#![feature(slice_patterns)]
#![cfg_attr(test, feature(test))]

View File

@ -46,7 +46,6 @@
#![feature(path_ext)]
#![feature(std_misc)]
#![feature(step_by)]
#![feature(convert)]
#![cfg_attr(test, feature(test, rand))]
extern crate syntax;

View File

@ -38,7 +38,6 @@
#![feature(io)]
#![feature(set_stdio)]
#![feature(unicode)]
#![feature(convert)]
extern crate arena;
extern crate flate;

View File

@ -39,7 +39,6 @@
#![feature(unicode)]
#![feature(path_ext)]
#![feature(fs)]
#![feature(convert)]
#![feature(path_relative_from)]
#![allow(trivial_casts)]

View File

@ -36,7 +36,6 @@
#![feature(file_path)]
#![feature(path_ext)]
#![feature(path_relative_from)]
#![feature(convert)]
#![feature(slice_patterns)]
extern crate arena;

View File

@ -36,7 +36,6 @@ Core encoding and decoding interfaces.
#![feature(std_misc)]
#![feature(unicode)]
#![feature(str_char)]
#![feature(convert)]
#![cfg_attr(test, feature(test, old_io))]
// test harness access

View File

@ -190,7 +190,6 @@ mod dl {
use ffi::{CStr, OsStr};
use str;
use libc;
use os::unix::prelude::*;
use ptr;
pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {

View File

@ -327,7 +327,6 @@ pub struct JoinPathsError {
/// # Examples
///
/// ```
/// # #![feature(convert)]
/// use std::env;
/// use std::path::PathBuf;
///

View File

@ -35,6 +35,7 @@
use core::prelude::*;
use borrow::{Borrow, Cow, ToOwned};
use ffi::CString;
use fmt::{self, Debug};
use mem;
use string::String;
@ -42,6 +43,7 @@ use ops;
use cmp;
use hash::{Hash, Hasher};
use old_path::{Path, GenericPath};
use vec::Vec;
use sys::os_str::{Buf, Slice};
use sys_common::{AsInner, IntoInner, FromInner};
@ -83,6 +85,37 @@ impl OsString {
OsString { inner: Buf::from_string(String::new()) }
}
/// Construct an `OsString` from a byte sequence.
///
/// # Platform behavior
///
/// On Unix systems, any byte sequence can be successfully
/// converted into an `OsString`.
///
/// On Windows system, only UTF-8 byte sequences will successfully
/// convert; non UTF-8 data will produce `None`.
#[unstable(feature = "convert", reason = "recently added")]
pub fn from_bytes<B>(bytes: B) -> Option<OsString> where B: Into<Vec<u8>> {
#[cfg(unix)]
fn from_bytes_inner(vec: Vec<u8>) -> Option<OsString> {
use os::unix::ffi::OsStringExt;
Some(OsString::from_vec(vec))
}
#[cfg(windows)]
fn from_bytes_inner(vec: Vec<u8>) -> Option<OsString> {
String::from_utf8(vec).ok().map(OsString::from)
}
from_bytes_inner(bytes.into())
}
/// Convert to an `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(&self) -> &OsStr {
self
}
/// Convert the `OsString` into a `String` if it contains valid Unicode data.
///
/// On failure, ownership of the original `OsString` is returned.
@ -211,8 +244,16 @@ impl Hash for OsString {
}
impl OsStr {
/// Coerce into an `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
s.as_ref()
}
/// Coerce directly from a `&str` slice to a `&OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.0.0",
reason = "use `OsStr::new` instead")]
pub fn from_str(s: &str) -> &OsStr {
unsafe { mem::transmute(Slice::from_str(s)) }
}
@ -239,6 +280,36 @@ impl OsStr {
OsString { inner: self.inner.to_owned() }
}
/// Yield this `OsStr` as a byte slice.
///
/// # Platform behavior
///
/// On Unix systems, this is a no-op.
///
/// On Windows systems, this returns `None` unless the `OsStr` is
/// valid unicode, in which case it produces UTF-8-encoded
/// data. This may entail checking validity.
#[unstable(feature = "convert", reason = "recently added")]
pub fn to_bytes(&self) -> Option<&[u8]> {
if cfg!(windows) {
self.to_str().map(|s| s.as_bytes())
} else {
Some(self.bytes())
}
}
/// Create a `CString` containing this `OsStr` data.
///
/// Fails if the `OsStr` contains interior nulls.
///
/// This is a convenience for creating a `CString` from
/// `self.to_bytes()`, and inherits the platform behavior of the
/// `to_bytes` method.
#[unstable(feature = "convert", reason = "recently added")]
pub fn to_cstring(&self) -> Option<CString> {
self.to_bytes().and_then(|b| CString::new(b).ok())
}
/// Get the underlying byte representation.
///
/// Note: it is *crucial* that this API is private, to avoid
@ -258,14 +329,14 @@ impl PartialEq for OsStr {
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq<str> for OsStr {
fn eq(&self, other: &str) -> bool {
*self == *OsStr::from_str(other)
*self == *OsStr::new(other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq<OsStr> for str {
fn eq(&self, other: &OsStr) -> bool {
*other == *OsStr::from_str(self)
*other == *OsStr::new(self)
}
}
@ -292,7 +363,7 @@ impl PartialOrd for OsStr {
impl PartialOrd<str> for OsStr {
#[inline]
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
self.partial_cmp(OsStr::from_str(other))
self.partial_cmp(OsStr::new(other))
}
}
@ -359,7 +430,7 @@ impl AsOsStr for OsString {
#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
impl AsOsStr for str {
fn as_os_str(&self) -> &OsStr {
OsStr::from_str(self)
unsafe { mem::transmute(Slice::from_str(self)) }
}
}
@ -367,7 +438,7 @@ impl AsOsStr for str {
#[deprecated(since = "1.0.0", reason = "trait is deprecated")]
impl AsOsStr for String {
fn as_os_str(&self) -> &OsStr {
OsStr::from_str(&self[..])
unsafe { mem::transmute(Slice::from_str(self)) }
}
}
@ -388,14 +459,14 @@ impl AsRef<OsStr> for OsString {
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for str {
fn as_ref(&self) -> &OsStr {
OsStr::from_str(self)
unsafe { mem::transmute(Slice::from_str(self)) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for String {
fn as_ref(&self) -> &OsStr {
OsStr::from_str(&self[..])
unsafe { mem::transmute(Slice::from_str(self)) }
}
}

View File

@ -122,12 +122,11 @@
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(macro_reexport)]
#![feature(unique)]
#![feature(convert)]
#![feature(allow_internal_unstable)]
#![feature(str_char)]
#![feature(into_cow)]
#![feature(slice_patterns)]
#![feature(std_misc)]
#![feature(slice_patterns)]
#![feature(debug_builders)]
#![cfg_attr(test, feature(test, rustc_private, std_misc))]

View File

@ -35,7 +35,6 @@
//! To build or modify paths, use `PathBuf`:
//!
//! ```rust
//! # #![feature(convert)]
//! use std::path::PathBuf;
//!
//! let mut path = PathBuf::from("c:\\");
@ -521,9 +520,9 @@ impl<'a> Component<'a> {
pub fn as_os_str(self) -> &'a OsStr {
match self {
Component::Prefix(p) => p.as_os_str(),
Component::RootDir => OsStr::from_str(MAIN_SEP_STR),
Component::CurDir => OsStr::from_str("."),
Component::ParentDir => OsStr::from_str(".."),
Component::RootDir => OsStr::new(MAIN_SEP_STR),
Component::CurDir => OsStr::new("."),
Component::ParentDir => OsStr::new(".."),
Component::Normal(path) => path,
}
}
@ -893,7 +892,6 @@ impl<'a> cmp::Ord for Components<'a> {
/// # Examples
///
/// ```
/// # #![feature(convert)]
/// use std::path::PathBuf;
///
/// let mut path = PathBuf::from("c:\\");
@ -918,6 +916,12 @@ impl PathBuf {
PathBuf { inner: OsString::new() }
}
/// Coerce to a `Path` slice.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_path(&self) -> &Path {
self
}
/// Extend `self` with `path`.
///
/// If `path` is absolute, it replaces the current path.
@ -985,7 +989,6 @@ impl PathBuf {
/// # Examples
///
/// ```
/// # #![feature(convert)]
/// use std::path::PathBuf;
///
/// let mut buf = PathBuf::from("/");

View File

@ -138,7 +138,7 @@ pub mod io {
/// Unix-specific extension to the primitives in the `std::ffi` module
#[stable(feature = "rust1", since = "1.0.0")]
pub mod ffi {
use ffi::{CString, NulError, OsStr, OsString};
use ffi::{OsStr, OsString};
use mem;
use prelude::v1::*;
use sys::os_str::Buf;
@ -175,10 +175,6 @@ pub mod ffi {
/// Get the underlying byte view of the `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8];
/// Convert the `OsStr` slice into a `CString`.
#[stable(feature = "rust1", since = "1.0.0")]
fn to_cstring(&self) -> Result<CString, NulError>;
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -189,9 +185,6 @@ pub mod ffi {
fn as_bytes(&self) -> &[u8] {
&self.as_inner().inner
}
fn to_cstring(&self) -> Result<CString, NulError> {
CString::new(self.as_bytes())
}
}
}

View File

@ -276,8 +276,8 @@ impl File {
}
fn cstr(path: &Path) -> io::Result<CString> {
let cstring = try!(path.as_os_str().to_cstring());
Ok(cstring)
path.as_os_str().to_cstring().ok_or(
io::Error::new(io::ErrorKind::InvalidInput, "path contained a null", None))
}
pub fn mkdir(p: &Path) -> io::Result<()> {

View File

@ -54,7 +54,7 @@ impl Command {
self.args.push(arg.to_cstring().unwrap())
}
pub fn args<'a, I: Iterator<Item = &'a OsStr>>(&mut self, args: I) {
self.args.extend(args.map(|s| OsStrExt::to_cstring(s).unwrap()))
self.args.extend(args.map(|s| s.to_cstring().unwrap()))
}
fn init_env_map(&mut self) {
if self.env.is_none() {

View File

@ -37,7 +37,6 @@
#![feature(unicode)]
#![feature(path_ext)]
#![feature(str_char)]
#![feature(convert)]
#![feature(into_cow)]
#![feature(slice_patterns)]

View File

@ -62,7 +62,6 @@
#![feature(std_misc)]
#![feature(str_char)]
#![feature(path_ext)]
#![feature(convert)]
#![cfg_attr(windows, feature(libc))]
#[macro_use] extern crate log;

View File

@ -44,7 +44,6 @@
#![feature(libc)]
#![feature(set_stdio)]
#![feature(os)]
#![feature(convert)]
#![cfg_attr(test, feature(old_io))]
extern crate getopts;

View File

@ -15,7 +15,6 @@
#![feature(rustdoc)]
#![feature(rustc_private)]
#![feature(path_relative_from)]
#![feature(convert)]
extern crate rustdoc;
extern crate rustc_back;

View File

@ -11,7 +11,6 @@
// pretty-expanded FIXME #23616
#![feature(path)]
#![feature(convert)]
use std::env::*;
use std::path::PathBuf;

View File

@ -12,8 +12,6 @@
// pretty-expanded FIXME #23616
#![feature(convert)]
use std::default::Default;
use std::io;
use std::fs;