From ff27379df3037b605f607f9d510aa158cf8d38e1 Mon Sep 17 00:00:00 2001 From: Remi Rampin Date: Sun, 5 Jul 2015 18:17:37 -0400 Subject: [PATCH 1/2] Implement OsStr::from_bytes_slice() Should be from_bytes(), since that the name of the method in OsString; however this is already used in OsStrExt on Unix. Thus from_bytes_slice(), which makes it clear why the name is different (this one operates on slices without copying). --- src/libstd/ffi/os_str.rs | 18 ++++++++++ src/test/run-pass/osstr_conversions.rs | 49 ++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/test/run-pass/osstr_conversions.rs diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 97bf33335b02a..64631e0ad9a94 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -41,6 +41,7 @@ use mem; use string::String; use ops; use cmp; +use str; use hash::{Hash, Hasher}; use vec::Vec; @@ -265,6 +266,23 @@ impl OsStr { } } + /// Converts a byte slice to an `OsStr` slice. + /// + /// # Platform behavior + /// + /// On Unix systems, this is a no-op. + /// + /// On Windows systems, 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_slice(bytes: &[u8]) -> Option<&OsStr> { + if cfg!(windows) { + str::from_utf8(bytes).ok().map(|s| s.as_ref()) + } else { + Some(unsafe { mem::transmute(bytes) }) + } + } + /// Creates a `CString` containing this `OsStr` data. /// /// Fails if the `OsStr` contains interior nulls. diff --git a/src/test/run-pass/osstr_conversions.rs b/src/test/run-pass/osstr_conversions.rs new file mode 100644 index 0000000000000..01d0c0e75e385 --- /dev/null +++ b/src/test/run-pass/osstr_conversions.rs @@ -0,0 +1,49 @@ +// Copyright 2012-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. + +#![feature(convert)] + +use std::ffi::{OsStr, OsString}; + +fn main() { + // Valid UTF-8 + let vec1: Vec = b"t\xC3\xA9st".to_vec(); + let oso1: OsString = OsString::from_bytes(vec1).unwrap(); + assert!(oso1.to_bytes() == Some(b"t\xC3\xA9st")); + assert!(oso1.to_str() == Some("t\u{E9}st")); + // Not UTF-8 + let vec2: Vec = b"t\xE9st".to_vec(); + let oso2: OsString = OsString::from_bytes(vec2).unwrap(); + if cfg!(windows) { + assert!(oso2.to_bytes() == None); + } else { + assert!(oso2.to_bytes() == Some(b"t\xE9st")); + } + assert_eq!(oso2.to_str(), None); + + // Valid UTF-8 + let by1: &[u8] = b"t\xC3\xA9st"; + let oss1: &OsStr = OsStr::from_bytes_slice(by1).unwrap(); + assert_eq!(oss1.to_bytes().unwrap().as_ptr(), by1.as_ptr()); + assert_eq!(oss1.to_str().unwrap().as_ptr(), by1.as_ptr()); + // Not UTF-8 + let by2: &[u8] = b"t\xE9st"; + let oss2: &OsStr = OsStr::from_bytes_slice(by2).unwrap(); + if cfg!(windows) { + assert_eq!(oss2.to_bytes(), None); + } else { + assert_eq!(oss2.to_bytes().unwrap().as_ptr(), by2.as_ptr()); + } + assert_eq!(oss2.to_str(), None); + + if cfg!(windows) { + // FIXME: needs valid-windows-utf16-invalid-unicode test cases + } +} From 4693c2f07a1afe3452a08465a03bf61c143c004f Mon Sep 17 00:00:00 2001 From: Remi Rampin Date: Mon, 6 Jul 2015 12:55:34 -0400 Subject: [PATCH 2/2] Rename from_bytes_slice() to from_bytes_opt() This makes it possible to rename OsString::from_bytes() as well, since it is currently unstable (feature(convert)). --- src/libstd/ffi/os_str.rs | 2 +- src/test/run-pass/osstr_conversions.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 64631e0ad9a94..a99d01cd39d97 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -275,7 +275,7 @@ impl OsStr { /// On Windows systems, 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_slice(bytes: &[u8]) -> Option<&OsStr> { + pub fn from_bytes_opt(bytes: &[u8]) -> Option<&OsStr> { if cfg!(windows) { str::from_utf8(bytes).ok().map(|s| s.as_ref()) } else { diff --git a/src/test/run-pass/osstr_conversions.rs b/src/test/run-pass/osstr_conversions.rs index 01d0c0e75e385..cae0704399904 100644 --- a/src/test/run-pass/osstr_conversions.rs +++ b/src/test/run-pass/osstr_conversions.rs @@ -30,12 +30,12 @@ fn main() { // Valid UTF-8 let by1: &[u8] = b"t\xC3\xA9st"; - let oss1: &OsStr = OsStr::from_bytes_slice(by1).unwrap(); + let oss1: &OsStr = OsStr::from_bytes_opt(by1).unwrap(); assert_eq!(oss1.to_bytes().unwrap().as_ptr(), by1.as_ptr()); assert_eq!(oss1.to_str().unwrap().as_ptr(), by1.as_ptr()); // Not UTF-8 let by2: &[u8] = b"t\xE9st"; - let oss2: &OsStr = OsStr::from_bytes_slice(by2).unwrap(); + let oss2: &OsStr = OsStr::from_bytes_opt(by2).unwrap(); if cfg!(windows) { assert_eq!(oss2.to_bytes(), None); } else {