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.
11 //! Library to interface with chunks of memory allocated in C.
13 //! It is often desirable to safely interface with memory allocated from C,
14 //! encapsulating the unsafety into allocation and destruction time. Indeed,
15 //! allocating memory externally is currently the only way to give Rust shared
16 //! mut state with C programs that keep their own references; vectors are
17 //! unsuitable because they could be reallocated or moved at any time, and
18 //! importing C memory into a vector takes a one-time snapshot of the memory.
20 //! This module simplifies the usage of such external blocks of memory. Memory
21 //! is encapsulated into an opaque object after creation; the lifecycle of the
22 //! memory can be optionally managed by Rust, if an appropriate destructor
23 //! closure is provided. Safety is ensured by bounds-checking accesses, which
24 //! are marshalled through get and set functions.
26 //! There are three unsafe functions: the two constructors, and the
27 //! unwrap method. The constructors are unsafe for the
28 //! obvious reason (they act on a pointer that cannot be checked inside the
29 //! method), but `unwrap()` is somewhat more subtle in its unsafety.
30 //! It returns the contained pointer, but at the same time destroys the CVec
31 //! without running its destructor. This can be used to pass memory back to
32 //! C, but care must be taken that the ownership of underlying resources are
33 //! handled correctly, i.e. that allocated memory is eventually freed
41 use option::{Option, Some, None};
47 /// The type representing a foreign chunk of memory
51 dtor: Option<proc():Send>,
55 impl<T> Drop for CVec<T> {
57 match self.dtor.take() {
65 /// Create a `CVec` from a raw pointer to a buffer with a given length.
67 /// Panics if the given pointer is null. The returned vector will not attempt
68 /// to deallocate the vector when dropped.
72 /// * base - A raw pointer to a buffer
73 /// * len - The number of elements in the buffer
74 pub unsafe fn new(base: *mut T, len: uint) -> CVec<T> {
75 assert!(base != ptr::null_mut());
83 /// Create a `CVec` from a foreign buffer, with a given length,
84 /// and a function to run upon destruction.
86 /// Panics if the given pointer is null.
90 /// * base - A foreign pointer to a buffer
91 /// * len - The number of elements in the buffer
92 /// * dtor - A proc to run when the value is destructed, useful
93 /// for freeing the buffer, etc.
94 pub unsafe fn new_with_dtor(base: *mut T, len: uint,
95 dtor: proc():Send) -> CVec<T> {
96 assert!(base != ptr::null_mut());
104 /// View the stored data as a mutable slice.
105 pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
107 mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
111 /// Retrieves an element at a given index, returning `None` if the requested
112 /// index is greater than the length of the vector.
113 pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> {
115 Some(unsafe { &*self.base.offset(ofs as int) })
121 /// Retrieves a mutable element at a given index, returning `None` if the
122 /// requested index is greater than the length of the vector.
123 pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> {
125 Some(unsafe { &mut *self.base.offset(ofs as int) })
131 /// Unwrap the pointer without running the destructor
133 /// This method retrieves the underlying pointer, and in the process
134 /// destroys the CVec but without running the destructor. A use case
135 /// would be transferring ownership of the buffer to a C function, as
136 /// in this case you would not want to run the destructor.
138 /// Note that if you want to access the underlying pointer without
139 /// cancelling the destructor, you can simply call `transmute` on the return
140 /// value of `get(0)`.
141 pub unsafe fn into_inner(mut self) -> *mut T {
146 /// Deprecated, use into_inner() instead
147 #[deprecated = "renamed to into_inner()"]
148 pub unsafe fn unwrap(self) -> *mut T { self.into_inner() }
150 /// Returns the number of items in this vector.
151 pub fn len(&self) -> uint { self.len }
153 /// Returns whether this vector is empty.
154 pub fn is_empty(&self) -> bool { self.len() == 0 }
157 impl<T> AsSlice<T> for CVec<T> {
158 /// View the stored data as a slice.
159 fn as_slice<'a>(&'a self) -> &'a [T] {
161 mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
174 fn malloc(n: uint) -> CVec<u8> {
176 let mem = libc::malloc(n as libc::size_t);
177 if mem.is_null() { ::alloc::oom() }
179 CVec::new_with_dtor(mem as *mut u8, n,
180 proc() { libc::free(mem as *mut libc::c_void); })
186 let mut cv = malloc(16);
188 *cv.get_mut(3).unwrap() = 8;
189 *cv.get_mut(4).unwrap() = 9;
190 assert_eq!(*cv.get(3).unwrap(), 8);
191 assert_eq!(*cv.get(4).unwrap(), 9);
192 assert_eq!(cv.len(), 16);
197 fn test_panic_at_null() {
199 CVec::new(ptr::null_mut::<u8>(), 9);
204 fn test_overrun_get() {
207 assert!(cv.get(17).is_none());
211 fn test_overrun_set() {
212 let mut cv = malloc(16);
214 assert!(cv.get_mut(17).is_none());
220 let cv = CVec::new_with_dtor(1 as *mut int, 0,
221 proc() { panic!("Don't run this destructor!") });
223 assert_eq!(p, 1 as *mut int);