1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 * Library to interface with chunks of memory allocated in C.
14 * It is often desirable to safely interface with memory allocated from C,
15 * encapsulating the unsafety into allocation and destruction time. Indeed,
16 * allocating memory externally is currently the only way to give Rust shared
17 * mut state with C programs that keep their own references; vectors are
18 * unsuitable because they could be reallocated or moved at any time, and
19 * importing C memory into a vector takes a one-time snapshot of the memory.
21 * This module simplifies the usage of such external blocks of memory. Memory
22 * is encapsulated into an opaque object after creation; the lifecycle of the
23 * memory can be optionally managed by Rust, if an appropriate destructor
24 * closure is provided. Safety is ensured by bounds-checking accesses, which
25 * are marshalled through get and set functions.
27 * There are three unsafe functions: the two introduction forms, and the
28 * pointer elimination form. The introduction forms are unsafe for the
29 * obvious reason (they act on a pointer that cannot be checked inside the
30 * method), but the elimination form is somewhat more subtle in its unsafety.
31 * By using a pointer taken from a c_vec::t without keeping a reference to the
32 * c_vec::t itself around, the CVec could be garbage collected, and the
33 * memory within could be destroyed. There are legitimate uses for the
34 * pointer elimination form -- for instance, to pass memory back into C -- but
35 * great care must be taken to ensure that a reference to the c_vec::t is
36 * still held if needed.
44 * The type representing a foreign chunk of memory
58 impl Drop for DtorRes {
62 option::Some(f) => f()
67 fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
74 Section: Introduction forms
78 * Create a `CVec` from a foreign buffer with a given length.
82 * * base - A foreign pointer to a buffer
83 * * len - The number of elements in the buffer
85 pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
89 rsrc: @DtorRes(option::None)
94 * Create a `CVec` from a foreign buffer, with a given length,
95 * and a function to run upon destruction.
99 * * base - A foreign pointer to a buffer
100 * * len - The number of elements in the buffer
101 * * dtor - A function to run when the value is destructed, useful
102 * for freeing the buffer, etc.
104 pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: @fn())
109 rsrc: @DtorRes(option::Some(dtor))
118 * Retrieves an element at a given index
120 * Fails if `ofs` is greater or equal to the length of the vector
122 pub fn get<T:Clone>(t: CVec<T>, ofs: uint) -> T {
123 assert!(ofs < len(t));
125 (*ptr::mut_offset(t.base, ofs as int)).clone()
130 * Sets the value of an element at a given index
132 * Fails if `ofs` is greater or equal to the length of the vector
134 pub fn set<T>(t: CVec<T>, ofs: uint, v: T) {
135 assert!(ofs < len(t));
136 unsafe { *ptr::mut_offset(t.base, ofs as int) = v };
140 Section: Elimination forms
143 /// Returns the length of the vector
144 pub fn len<T>(t: CVec<T>) -> uint { t.len }
146 /// Returns a pointer to the first element of the vector
147 pub unsafe fn ptr<T>(t: CVec<T>) -> *mut T { t.base }
157 fn malloc(n: size_t) -> CVec<u8> {
159 let mem = libc::malloc(n);
161 assert!(mem as int != 0);
163 c_vec_with_dtor(mem as *mut u8, n as uint, || free(mem))
169 let cv = malloc(16u as size_t);
173 assert_eq!(get(cv, 3u), 8u8);
174 assert_eq!(get(cv, 4u), 9u8);
175 assert_eq!(len(cv), 16u);
180 #[ignore(cfg(windows))]
181 fn test_overrun_get() {
182 let cv = malloc(16u as size_t);
189 #[ignore(cfg(windows))]
190 fn test_overrun_set() {
191 let cv = malloc(16u as size_t);
197 fn test_and_I_mean_it() {
198 let cv = malloc(16u as size_t);
199 let p = unsafe { ptr(cv) };
203 assert_eq!(unsafe { *p }, 32u8);
204 set(cv, 2u, 34u8); /* safety */