2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/*!
|
|
|
|
* 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 introduction forms, and the
|
|
|
|
* pointer elimination form. The introduction forms are unsafe for the
|
|
|
|
* obvious reason (they act on a pointer that cannot be checked inside the
|
|
|
|
* method), but the elimination form is somewhat more subtle in its unsafety.
|
|
|
|
* By using a pointer taken from a c_vec::t without keeping a reference to the
|
2012-08-11 09:08:42 -05:00
|
|
|
* c_vec::t itself around, the CVec could be garbage collected, and the
|
2012-07-04 16:53:12 -05:00
|
|
|
* memory within could be destroyed. There are legitimate uses for the
|
|
|
|
* pointer elimination form -- for instance, to pass memory back into C -- but
|
|
|
|
* great care must be taken to ensure that a reference to the c_vec::t is
|
|
|
|
* still held if needed.
|
|
|
|
*/
|
2011-11-23 04:15:04 -06:00
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2013-05-24 21:35:29 -05:00
|
|
|
use core::option;
|
|
|
|
use core::ptr;
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* The type representing a foreign chunk of memory
|
|
|
|
*
|
|
|
|
*/
|
2013-02-04 18:48:52 -06:00
|
|
|
pub struct CVec<T> {
|
|
|
|
priv base: *mut T,
|
|
|
|
priv len: uint,
|
|
|
|
priv rsrc: @DtorRes
|
2011-11-23 04:15:04 -06:00
|
|
|
}
|
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
struct DtorRes {
|
2013-03-01 16:15:15 -06:00
|
|
|
dtor: Option<@fn()>,
|
2012-11-13 20:38:18 -06:00
|
|
|
}
|
|
|
|
|
2013-03-20 20:18:57 -05:00
|
|
|
#[unsafe_destructor]
|
2013-02-14 13:47:00 -06:00
|
|
|
impl Drop for DtorRes {
|
2013-06-20 20:06:13 -05:00
|
|
|
fn drop(&self) {
|
2013-04-09 00:31:42 -05:00
|
|
|
match self.dtor {
|
|
|
|
option::None => (),
|
|
|
|
option::Some(f) => f()
|
2012-11-28 17:42:16 -06:00
|
|
|
}
|
2012-11-13 20:38:18 -06:00
|
|
|
}
|
2011-11-23 04:15:04 -06:00
|
|
|
}
|
|
|
|
|
2013-03-01 16:15:15 -06:00
|
|
|
fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
|
2012-09-04 19:22:09 -05:00
|
|
|
DtorRes {
|
|
|
|
dtor: dtor
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-23 04:15:04 -06:00
|
|
|
/*
|
|
|
|
Section: Introduction forms
|
|
|
|
*/
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
2012-08-11 09:08:42 -05:00
|
|
|
* Create a `CVec` from a foreign buffer with a given length.
|
2012-07-04 16:53:12 -05:00
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * base - A foreign pointer to a buffer
|
|
|
|
* * len - The number of elements in the buffer
|
|
|
|
*/
|
2013-05-08 14:50:27 -05:00
|
|
|
pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
|
2013-02-04 18:48:52 -06:00
|
|
|
return CVec{
|
2012-03-13 16:39:28 -05:00
|
|
|
base: base,
|
|
|
|
len: len,
|
2012-08-11 09:08:42 -05:00
|
|
|
rsrc: @DtorRes(option::None)
|
2013-02-04 18:48:52 -06:00
|
|
|
};
|
2011-11-23 04:15:04 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
2012-08-11 09:08:42 -05:00
|
|
|
* Create a `CVec` from a foreign buffer, with a given length,
|
2012-07-04 16:53:12 -05:00
|
|
|
* and a function to run upon destruction.
|
|
|
|
*
|
|
|
|
* # Arguments
|
|
|
|
*
|
|
|
|
* * base - A foreign pointer to a buffer
|
|
|
|
* * len - The number of elements in the buffer
|
|
|
|
* * dtor - A function to run when the value is destructed, useful
|
|
|
|
* for freeing the buffer, etc.
|
|
|
|
*/
|
2013-05-08 14:50:27 -05:00
|
|
|
pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: @fn())
|
2012-08-11 09:08:42 -05:00
|
|
|
-> CVec<T> {
|
2013-02-04 18:48:52 -06:00
|
|
|
return CVec{
|
2012-03-13 16:39:28 -05:00
|
|
|
base: base,
|
|
|
|
len: len,
|
2012-08-11 09:08:42 -05:00
|
|
|
rsrc: @DtorRes(option::Some(dtor))
|
2013-02-04 18:48:52 -06:00
|
|
|
};
|
2011-11-23 04:15:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Section: Operations
|
|
|
|
*/
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Retrieves an element at a given index
|
|
|
|
*
|
|
|
|
* Fails if `ofs` is greater or equal to the length of the vector
|
|
|
|
*/
|
2013-02-20 19:07:17 -06:00
|
|
|
pub fn get<T:Copy>(t: CVec<T>, ofs: uint) -> T {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(ofs < len(t));
|
2013-06-15 19:15:52 -05:00
|
|
|
return unsafe { copy *ptr::mut_offset(t.base, ofs) };
|
2011-11-23 04:15:04 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Sets the value of an element at a given index
|
|
|
|
*
|
|
|
|
* Fails if `ofs` is greater or equal to the length of the vector
|
|
|
|
*/
|
2013-02-20 19:07:17 -06:00
|
|
|
pub fn set<T:Copy>(t: CVec<T>, ofs: uint, v: T) {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(ofs < len(t));
|
2013-02-04 18:48:52 -06:00
|
|
|
unsafe { *ptr::mut_offset(t.base, ofs) = v };
|
2011-11-23 04:15:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Section: Elimination forms
|
|
|
|
*/
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Returns the length of the vector
|
2013-03-21 23:34:30 -05:00
|
|
|
pub fn len<T>(t: CVec<T>) -> uint { t.len }
|
2011-11-23 04:15:04 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Returns a pointer to the first element of the vector
|
2013-05-08 14:50:27 -05:00
|
|
|
pub unsafe fn ptr<T>(t: CVec<T>) -> *mut T { t.base }
|
2012-01-17 21:05:07 -06:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2013-01-08 21:37:25 -06:00
|
|
|
|
|
|
|
use c_vec::*;
|
|
|
|
|
2012-12-27 20:24:18 -06:00
|
|
|
use core::libc::*;
|
|
|
|
use core::libc;
|
2012-01-17 21:05:07 -06:00
|
|
|
|
2012-08-11 09:08:42 -05:00
|
|
|
fn malloc(n: size_t) -> CVec<u8> {
|
2013-01-11 11:22:23 -06:00
|
|
|
unsafe {
|
|
|
|
let mem = libc::malloc(n);
|
2012-01-17 21:05:07 -06:00
|
|
|
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(mem as int != 0);
|
2012-01-17 21:05:07 -06:00
|
|
|
|
2013-04-18 19:40:53 -05:00
|
|
|
return c_vec_with_dtor(mem as *mut u8, n as uint,
|
|
|
|
|| unsafe { free(mem) });
|
2013-01-11 11:22:23 -06:00
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_basic() {
|
2012-06-04 19:26:17 -05:00
|
|
|
let cv = malloc(16u as size_t);
|
2012-01-17 21:05:07 -06:00
|
|
|
|
|
|
|
set(cv, 3u, 8u8);
|
|
|
|
set(cv, 4u, 9u8);
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(get(cv, 3u), 8u8);
|
|
|
|
assert_eq!(get(cv, 4u), 9u8);
|
|
|
|
assert_eq!(len(cv), 16u);
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
2012-06-07 23:38:25 -05:00
|
|
|
#[ignore(cfg(windows))]
|
2012-01-17 21:05:07 -06:00
|
|
|
fn test_overrun_get() {
|
2012-06-04 19:26:17 -05:00
|
|
|
let cv = malloc(16u as size_t);
|
2012-01-17 21:05:07 -06:00
|
|
|
|
|
|
|
get(cv, 17u);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
2012-06-07 23:38:25 -05:00
|
|
|
#[ignore(cfg(windows))]
|
2012-01-17 21:05:07 -06:00
|
|
|
fn test_overrun_set() {
|
2012-06-04 19:26:17 -05:00
|
|
|
let cv = malloc(16u as size_t);
|
2012-01-17 21:05:07 -06:00
|
|
|
|
|
|
|
set(cv, 17u, 0u8);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_and_I_mean_it() {
|
2012-06-04 19:26:17 -05:00
|
|
|
let cv = malloc(16u as size_t);
|
2013-05-08 14:50:27 -05:00
|
|
|
let p = unsafe { ptr(cv) };
|
2012-01-17 21:05:07 -06:00
|
|
|
|
|
|
|
set(cv, 0u, 32u8);
|
|
|
|
set(cv, 1u, 33u8);
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(unsafe { *p }, 32u8);
|
2012-01-17 21:05:07 -06:00
|
|
|
set(cv, 2u, 34u8); /* safety */
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
}
|