Skip to content

Commit

Permalink
std: Align raw modules with unsafe conventions
Browse files Browse the repository at this point in the history
This commit is an implementation of [RFC 240][rfc] when applied to the standard
library. It primarily deprecates the entirety of `string::raw`, `vec::raw`,
`slice::raw`, and `str::raw` in favor of associated functions, methods, and
other free functions. The detailed renaming is:

* slice::raw::buf_as_slice => slice::with_raw_buf
* slice::raw::mut_buf_as_slice => slice::with_raw_mut_buf
* slice::shift_ptr => deprecated with no replacement
* slice::pop_ptr => deprecated with no replacement
* str::raw::from_utf8 => str::from_utf8_unchecked
* str::raw::c_str_to_static_slice => str::from_c_str
* str::raw::slice_bytes => deprecated for slice_unchecked (slight semantic diff)
* str::raw::slice_unchecked => str.slice_unchecked
* string::raw::from_parts => String::from_raw_parts
* string::raw::from_buf_len => String::from_raw_buf_len
* string::raw::from_buf => String::from_raw_buf
* string::raw::from_utf8 => String::from_utf8_unchecked
* vec::raw::from_buf => Vec::from_raw_buf

All previous functions exist in their `#[deprecated]` form, and the deprecation
messages indicate how to migrate to the newer variants.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0240-unsafe-api-location.md
[breaking-change]

Closes #17863
  • Loading branch information
alexcrichton committed Nov 22, 2014
1 parent 399ff25 commit 8ca27a6
Show file tree
Hide file tree
Showing 15 changed files with 304 additions and 208 deletions.
2 changes: 1 addition & 1 deletion src/libcollections/slice.rs
Expand Up @@ -106,7 +106,7 @@ pub use core::slice::{OrdSlicePrelude, SlicePrelude, Items, MutItems};
pub use core::slice::{ImmutableIntSlice, MutableIntSlice};
pub use core::slice::{MutSplits, MutChunks, Splits};
pub use core::slice::{bytes, mut_ref_slice, ref_slice, CloneSlicePrelude};
pub use core::slice::{Found, NotFound};
pub use core::slice::{Found, NotFound, from_raw_buf, from_raw_mut_buf};

// Functional utilities

Expand Down
16 changes: 4 additions & 12 deletions src/libcollections/str.rs
Expand Up @@ -79,6 +79,7 @@ pub use core::str::{Utf16Item, ScalarValue, LoneSurrogate, utf16_items};
pub use core::str::{truncate_utf16_at_nul, utf8_char_width, CharRange};
pub use core::str::{FromStr, from_str};
pub use core::str::{Str, StrPrelude};
pub use core::str::{from_utf8_unchecked, from_c_str};
pub use unicode::str::{UnicodeStrPrelude, Words, Graphemes, GraphemeIndices};

// FIXME(conventions): ensure bit/char conventions are followed by str's API
Expand Down Expand Up @@ -392,11 +393,11 @@ pub fn replace(s: &str, from: &str, to: &str) -> String {
let mut result = String::new();
let mut last_end = 0;
for (start, end) in s.match_indices(from) {
result.push_str(unsafe{raw::slice_bytes(s, last_end, start)});
result.push_str(unsafe { s.slice_unchecked(last_end, start) });
result.push_str(to);
last_end = end;
}
result.push_str(unsafe{raw::slice_bytes(s, last_end, s.len())});
result.push_str(unsafe { s.slice_unchecked(last_end, s.len()) });
result
}

Expand Down Expand Up @@ -669,16 +670,7 @@ pub trait StrAllocating: Str {
/// assert_eq!(s.replace("cookie monster", "little lamb"), s);
/// ```
fn replace(&self, from: &str, to: &str) -> String {
let me = self.as_slice();
let mut result = String::new();
let mut last_end = 0;
for (start, end) in me.match_indices(from) {
result.push_str(unsafe{raw::slice_bytes(me, last_end, start)});
result.push_str(to);
last_end = end;
}
result.push_str(unsafe{raw::slice_bytes(me, last_end, me.len())});
result
replace(self.as_slice(), from, to)
}

/// Given a string, makes a new string with repeated copies of it.
Expand Down
76 changes: 56 additions & 20 deletions src/libcollections/string.rs
Expand Up @@ -297,6 +297,52 @@ impl String {
chs.iter().map(|c| *c).collect()
}

/// Creates a new `String` from a length, capacity, and pointer.
///
/// This is unsafe because:
/// * We call `Vec::from_raw_parts` to get a `Vec<u8>`;
/// * We assume that the `Vec` contains valid UTF-8.
#[inline]
#[unstable = "function just moved from string::raw"]
pub unsafe fn from_raw_parts(buf: *mut u8, length: uint, capacity: uint) -> String {
String {
vec: Vec::from_raw_parts(buf, length, capacity),
}
}

/// Creates a `String` from a null-terminated `*const u8` buffer.
///
/// This function is unsafe because we dereference memory until we find the
/// NUL character, which is not guaranteed to be present. Additionally, the
/// slice is not checked to see whether it contains valid UTF-8
#[unstable = "just renamed from `mod raw`"]
pub unsafe fn from_raw_buf(buf: *const u8) -> String {
String::from_str(str::from_c_str(buf as *const i8))
}

/// Creates a `String` from a `*const u8` buffer of the given length.
///
/// This function is unsafe because it blindly assumes the validity of the
/// pointer `buf` for `len` bytes of memory. This function will copy the
/// memory from `buf` into a new allocation (owned by the returned
/// `String`).
///
/// This function is also unsafe because it does not validate that the
/// buffer is valid UTF-8 encoded data.
#[unstable = "just renamed from `mod raw`"]
pub unsafe fn from_raw_buf_len(buf: *const u8, len: uint) -> String {
String::from_utf8_unchecked(Vec::from_raw_buf(buf, len))
}

/// Converts a vector of bytes to a new `String` without checking if
/// it contains valid UTF-8. This is unsafe because it assumes that
/// the UTF-8-ness of the vector has already been validated.
#[inline]
#[unstable = "awaiting stabilization"]
pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String {
String { vec: bytes }
}

/// Return the underlying byte buffer, encoded as UTF-8.
///
/// # Example
Expand Down Expand Up @@ -823,12 +869,8 @@ impl<T: fmt::Show> ToString for T {
}

/// Unsafe operations
#[unstable = "waiting on raw module conventions"]
#[deprecated]
pub mod raw {
use core::mem;
use core::ptr::RawPtr;
use core::raw::Slice;

use super::String;
use vec::Vec;

Expand All @@ -838,45 +880,39 @@ pub mod raw {
/// * We call `Vec::from_raw_parts` to get a `Vec<u8>`;
/// * We assume that the `Vec` contains valid UTF-8.
#[inline]
#[deprecated = "renamed to String::from_raw_parts"]
pub unsafe fn from_parts(buf: *mut u8, length: uint, capacity: uint) -> String {
String {
vec: Vec::from_raw_parts(buf, length, capacity),
}
String::from_raw_parts(buf, length, capacity)
}

/// Creates a `String` from a `*const u8` buffer of the given length.
///
/// This function is unsafe because of two reasons:
///
/// * A raw pointer is dereferenced and transmuted to `&[u8]`;
/// * The slice is not checked to see whether it contains valid UTF-8.
#[deprecated = "renamed to String::from_raw_buf_len"]
pub unsafe fn from_buf_len(buf: *const u8, len: uint) -> String {
use slice::CloneSliceAllocPrelude;
let slice: &[u8] = mem::transmute(Slice {
data: buf,
len: len,
});
self::from_utf8(slice.to_vec())
String::from_raw_buf_len(buf, len)
}

/// Creates a `String` from a null-terminated `*const u8` buffer.
///
/// This function is unsafe because we dereference memory until we find the NUL character,
/// which is not guaranteed to be present. Additionally, the slice is not checked to see
/// whether it contains valid UTF-8
#[deprecated = "renamed to String::from_raw_buf"]
pub unsafe fn from_buf(buf: *const u8) -> String {
let mut len = 0;
while *buf.offset(len) != 0 {
len += 1;
}
self::from_buf_len(buf, len as uint)
String::from_raw_buf(buf)
}

/// Converts a vector of bytes to a new `String` without checking if
/// it contains valid UTF-8. This is unsafe because it assumes that
/// the UTF-8-ness of the vector has already been validated.
#[inline]
#[deprecated = "renamed to String::from_utf8_unchecked"]
pub unsafe fn from_utf8(bytes: Vec<u8>) -> String {
String { vec: bytes }
String::from_utf8_unchecked(bytes)
}
}

Expand Down
28 changes: 19 additions & 9 deletions src/libcollections/vec.rs
Expand Up @@ -234,12 +234,27 @@ impl<T> Vec<T> {
/// }
/// }
/// ```
#[experimental]
#[unstable = "needs finalization"]
pub unsafe fn from_raw_parts(ptr: *mut T, length: uint,
capacity: uint) -> Vec<T> {
Vec { ptr: ptr, len: length, cap: capacity }
}

/// Creates a vector by copying the elements from a raw pointer.
///
/// This function will copy `elts` contiguous elements starting at `ptr`
/// into a new allocation owned by the returned `Vec`. The elements of the
/// buffer are copied into the vector without cloning, as if `ptr::read()`
/// were called on them.
#[inline]
#[unstable = "just renamed from raw::from_buf"]
pub unsafe fn from_raw_buf(ptr: *const T, elts: uint) -> Vec<T> {
let mut dst = Vec::with_capacity(elts);
dst.set_len(elts);
ptr::copy_nonoverlapping_memory(dst.as_mut_ptr(), ptr, elts);
dst
}

/// Consumes the `Vec`, partitioning it based on a predicate.
///
/// Partitions the `Vec` into two `Vec`s `(A,B)`, where all elements of `A`
Expand Down Expand Up @@ -1366,23 +1381,18 @@ pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> {
}

/// Unsafe vector operations.
#[unstable]
#[deprecated]
pub mod raw {
use super::Vec;
use core::ptr;
use core::slice::SlicePrelude;

/// Constructs a vector from an unsafe pointer to a buffer.
///
/// The elements of the buffer are copied into the vector without cloning,
/// as if `ptr::read()` were called on them.
#[inline]
#[unstable]
#[deprecated = "renamed to Vec::from_raw_buf"]
pub unsafe fn from_buf<T>(ptr: *const T, elts: uint) -> Vec<T> {
let mut dst = Vec::with_capacity(elts);
dst.set_len(elts);
ptr::copy_nonoverlapping_memory(dst.as_mut_ptr(), ptr, elts);
dst
Vec::from_raw_buf(ptr, elts)
}
}

Expand Down
50 changes: 47 additions & 3 deletions src/libcore/slice.rs
Expand Up @@ -1547,15 +1547,55 @@ pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] {
}
}

/// Forms a slice from a pointer and a length.
///
/// The pointer given is actually a reference to the base of the slice. This
/// reference is used to give a concrete lifetime to tie the returned slice to.
/// Typically this should indicate that the slice is valid for as long as the
/// pointer itself is valid.
///
/// The `len` argument is the number of **elements**, not the number of bytes.
///
/// This function is unsafe as there is no guarantee that the given pointer is
/// valid for `len` elements, nor whether the lifetime provided is a suitable
/// lifetime for the returned slice.
///
/// # Example
///
/// ```rust
/// use std::slice;
///
/// // manifest a slice out of thin air!
/// let ptr = 0x1234 as *const uint;
/// let amt = 10;
/// unsafe {
/// let slice = slice::from_raw_buf(&ptr, amt);
/// }
/// ```
#[inline]
#[unstable = "just renamed from `mod raw`"]
pub unsafe fn from_raw_buf<'a, T>(p: &'a *const T, len: uint) -> &'a [T] {
transmute(RawSlice { data: *p, len: len })
}


/// Performs the same functionality as `from_raw_buf`, except that a mutable
/// slice is returned.
///
/// This function is unsafe for the same reasons as `from_raw_buf`, as well as
/// not being able to provide a non-aliasing guarantee of the returned mutable
/// slice.
#[inline]
#[unstable = "just renamed from `mod raw`"]
pub unsafe fn from_raw_mut_buf<'a, T>(p: &'a *mut T, len: uint) -> &'a mut [T] {
transmute(RawSlice { data: *p as *const T, len: len })
}

//
// Submodules
//

/// Unsafe operations
#[experimental = "needs review"]
#[deprecated]
pub mod raw {
use mem::transmute;
use ptr::RawPtr;
Expand All @@ -1567,6 +1607,7 @@ pub mod raw {
* not bytes).
*/
#[inline]
#[deprecated = "renamed to slice::from_raw_buf"]
pub unsafe fn buf_as_slice<T,U>(p: *const T, len: uint, f: |v: &[T]| -> U)
-> U {
f(transmute(Slice {
Expand All @@ -1580,6 +1621,7 @@ pub mod raw {
* not bytes).
*/
#[inline]
#[deprecated = "renamed to slice::from_raw_mut_buf"]
pub unsafe fn mut_buf_as_slice<T,
U>(
p: *mut T,
Expand All @@ -1598,6 +1640,7 @@ pub mod raw {
* if the slice is empty. O(1).
*/
#[inline]
#[deprecated = "inspect `Slice::{data, len}` manually (increment data by 1)"]
pub unsafe fn shift_ptr<T>(slice: &mut Slice<T>) -> Option<*const T> {
if slice.len == 0 { return None; }
let head: *const T = slice.data;
Expand All @@ -1611,7 +1654,8 @@ pub mod raw {
* slice so it no longer contains that element. Returns None
* if the slice is empty. O(1).
*/
#[inline]
#[inline]
#[deprecated = "inspect `Slice::{data, len}` manually (decrement len by 1)"]
pub unsafe fn pop_ptr<T>(slice: &mut Slice<T>) -> Option<*const T> {
if slice.len == 0 { return None; }
let tail: *const T = slice.data.offset((slice.len - 1) as int);
Expand Down

5 comments on commit 8ca27a6

@bors
Copy link
Contributor

@bors bors commented on 8ca27a6 Nov 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from aturon
at alexcrichton@8ca27a6

@bors
Copy link
Contributor

@bors bors commented on 8ca27a6 Nov 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging alexcrichton/rust/issue-17863 = 8ca27a6 into auto

@bors
Copy link
Contributor

@bors bors commented on 8ca27a6 Nov 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alexcrichton/rust/issue-17863 = 8ca27a6 merged ok, testing candidate = 641e2a1

@bors
Copy link
Contributor

@bors bors commented on 8ca27a6 Nov 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors
Copy link
Contributor

@bors bors commented on 8ca27a6 Nov 23, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 641e2a1

Please sign in to comment.