Files
rust/src/libstd/c_vec.rs
T
Steve Klabnik 7828c3dd28 Rename fail! to panic!
https://github.com/rust-lang/rfcs/pull/221

The current terminology of "task failure" often causes problems when
writing or speaking about code. You often want to talk about the
possibility of an operation that returns a Result "failing", but cannot
because of the ambiguity with task failure. Instead, you have to speak
of "the failing case" or "when the operation does not succeed" or other
circumlocutions.

Likewise, we use a "Failure" header in rustdoc to describe when
operations may fail the task, but it would often be helpful to separate
out a section describing the "Err-producing" case.

We have been steadily moving away from task failure and toward Result as
an error-handling mechanism, so we should optimize our terminology
accordingly: Result-producing functions should be easy to describe.

To update your code, rename any call to `fail!` to `panic!` instead.
Assuming you have not created your own macro named `panic!`, this
will work on UNIX based systems:

    grep -lZR 'fail!' . | xargs -0 -l sed -i -e 's/fail!/panic!/g'

You can of course also do this by hand.

[breaking-change]
2014-10-29 11:43:07 -04:00

223 lines
6.7 KiB
Rust

// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Library to interface with chunks of memory allocated in C.
//!
//! It is often desirable to safely interface with memory allocated from C,
//! encapsulating the unsafety into allocation and destruction time. Indeed,
//! allocating memory externally is currently the only way to give Rust shared
//! mut state with C programs that keep their own references; vectors are
//! unsuitable because they could be reallocated or moved at any time, and
//! importing C memory into a vector takes a one-time snapshot of the memory.
//!
//! This module simplifies the usage of such external blocks of memory. Memory
//! is encapsulated into an opaque object after creation; the lifecycle of the
//! memory can be optionally managed by Rust, if an appropriate destructor
//! closure is provided. Safety is ensured by bounds-checking accesses, which
//! are marshalled through get and set functions.
//!
//! There are three unsafe functions: the two constructors, and the
//! unwrap method. The constructors are unsafe for the
//! obvious reason (they act on a pointer that cannot be checked inside the
//! method), but `unwrap()` is somewhat more subtle in its unsafety.
//! It returns the contained pointer, but at the same time destroys the CVec
//! without running its destructor. This can be used to pass memory back to
//! C, but care must be taken that the ownership of underlying resources are
//! handled correctly, i.e. that allocated memory is eventually freed
//! if necessary.
#![experimental]
use collections::Collection;
use kinds::Send;
use mem;
use ops::Drop;
use option::{Option, Some, None};
use ptr::RawPtr;
use ptr;
use raw;
use slice::AsSlice;
/// The type representing a foreign chunk of memory
pub struct CVec<T> {
base: *mut T,
len: uint,
dtor: Option<proc():Send>,
}
#[unsafe_destructor]
impl<T> Drop for CVec<T> {
fn drop(&mut self) {
match self.dtor.take() {
None => (),
Some(f) => f()
}
}
}
impl<T> CVec<T> {
/// Create a `CVec` from a raw pointer to a buffer with a given length.
///
/// Fails if the given pointer is null. The returned vector will not attempt
/// to deallocate the vector when dropped.
///
/// # Arguments
///
/// * base - A raw pointer to a buffer
/// * len - The number of elements in the buffer
pub unsafe fn new(base: *mut T, len: uint) -> CVec<T> {
assert!(base != ptr::null_mut());
CVec {
base: base,
len: len,
dtor: None,
}
}
/// Create a `CVec` from a foreign buffer, with a given length,
/// and a function to run upon destruction.
///
/// Fails if the given pointer is null.
///
/// # Arguments
///
/// * base - A foreign pointer to a buffer
/// * len - The number of elements in the buffer
/// * dtor - A proc to run when the value is destructed, useful
/// for freeing the buffer, etc.
pub unsafe fn new_with_dtor(base: *mut T, len: uint,
dtor: proc():Send) -> CVec<T> {
assert!(base != ptr::null_mut());
CVec {
base: base,
len: len,
dtor: Some(dtor),
}
}
/// View the stored data as a mutable slice.
pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
unsafe {
mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
}
}
/// Retrieves an element at a given index, returning `None` if the requested
/// index is greater than the length of the vector.
pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> {
if ofs < self.len {
Some(unsafe { &*self.base.offset(ofs as int) })
} else {
None
}
}
/// Retrieves a mutable element at a given index, returning `None` if the
/// requested index is greater than the length of the vector.
pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> {
if ofs < self.len {
Some(unsafe { &mut *self.base.offset(ofs as int) })
} else {
None
}
}
/// Unwrap the pointer without running the destructor
///
/// This method retrieves the underlying pointer, and in the process
/// destroys the CVec but without running the destructor. A use case
/// would be transferring ownership of the buffer to a C function, as
/// in this case you would not want to run the destructor.
///
/// Note that if you want to access the underlying pointer without
/// cancelling the destructor, you can simply call `transmute` on the return
/// value of `get(0)`.
pub unsafe fn unwrap(mut self) -> *mut T {
self.dtor = None;
self.base
}
}
impl<T> AsSlice<T> for CVec<T> {
/// View the stored data as a slice.
fn as_slice<'a>(&'a self) -> &'a [T] {
unsafe {
mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
}
}
}
impl<T> Collection for CVec<T> {
fn len(&self) -> uint { self.len }
}
#[cfg(test)]
mod tests {
use prelude::*;
use super::CVec;
use libc;
use ptr;
fn malloc(n: uint) -> CVec<u8> {
unsafe {
let mem = libc::malloc(n as libc::size_t);
if mem.is_null() { panic!("out of memory") }
CVec::new_with_dtor(mem as *mut u8, n,
proc() { libc::free(mem as *mut libc::c_void); })
}
}
#[test]
fn test_basic() {
let mut cv = malloc(16);
*cv.get_mut(3).unwrap() = 8;
*cv.get_mut(4).unwrap() = 9;
assert_eq!(*cv.get(3).unwrap(), 8);
assert_eq!(*cv.get(4).unwrap(), 9);
assert_eq!(cv.len(), 16);
}
#[test]
#[should_fail]
fn test_panic_at_null() {
unsafe {
CVec::new(ptr::null_mut::<u8>(), 9);
}
}
#[test]
fn test_overrun_get() {
let cv = malloc(16);
assert!(cv.get(17).is_none());
}
#[test]
fn test_overrun_set() {
let mut cv = malloc(16);
assert!(cv.get_mut(17).is_none());
}
#[test]
fn test_unwrap() {
unsafe {
let cv = CVec::new_with_dtor(1 as *mut int, 0,
proc() { panic!("Don't run this destructor!") });
let p = cv.unwrap();
assert_eq!(p, 1 as *mut int);
}
}
}