]> git.lizzy.rs Git - rust.git/blob - src/libstd/c_vec.rs
rollup merge of #18407 : thestinger/arena
[rust.git] / src / libstd / c_vec.rs
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.
4 //
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.
10
11 //! Library to interface with chunks of memory allocated in C.
12 //!
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.
19 //!
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.
25 //!
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
34 //! if necessary.
35
36 #![experimental]
37
38 use collections::Collection;
39 use kinds::Send;
40 use mem;
41 use ops::Drop;
42 use option::{Option, Some, None};
43 use ptr::RawPtr;
44 use ptr;
45 use raw;
46 use slice::AsSlice;
47
48 /// The type representing a foreign chunk of memory
49 pub struct CVec<T> {
50     base: *mut T,
51     len: uint,
52     dtor: Option<proc():Send>,
53 }
54
55 #[unsafe_destructor]
56 impl<T> Drop for CVec<T> {
57     fn drop(&mut self) {
58         match self.dtor.take() {
59             None => (),
60             Some(f) => f()
61         }
62     }
63 }
64
65 impl<T> CVec<T> {
66     /// Create a `CVec` from a raw pointer to a buffer with a given length.
67     ///
68     /// Fails if the given pointer is null. The returned vector will not attempt
69     /// to deallocate the vector when dropped.
70     ///
71     /// # Arguments
72     ///
73     /// * base - A raw pointer to a buffer
74     /// * len - The number of elements in the buffer
75     pub unsafe fn new(base: *mut T, len: uint) -> CVec<T> {
76         assert!(base != ptr::null_mut());
77         CVec {
78             base: base,
79             len: len,
80             dtor: None,
81         }
82     }
83
84     /// Create a `CVec` from a foreign buffer, with a given length,
85     /// and a function to run upon destruction.
86     ///
87     /// Fails if the given pointer is null.
88     ///
89     /// # Arguments
90     ///
91     /// * base - A foreign pointer to a buffer
92     /// * len - The number of elements in the buffer
93     /// * dtor - A proc to run when the value is destructed, useful
94     ///          for freeing the buffer, etc.
95     pub unsafe fn new_with_dtor(base: *mut T, len: uint,
96                                 dtor: proc():Send) -> CVec<T> {
97         assert!(base != ptr::null_mut());
98         CVec {
99             base: base,
100             len: len,
101             dtor: Some(dtor),
102         }
103     }
104
105     /// View the stored data as a mutable slice.
106     pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
107         unsafe {
108             mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
109         }
110     }
111
112     /// Retrieves an element at a given index, returning `None` if the requested
113     /// index is greater than the length of the vector.
114     pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> {
115         if ofs < self.len {
116             Some(unsafe { &*self.base.offset(ofs as int) })
117         } else {
118             None
119         }
120     }
121
122     /// Retrieves a mutable element at a given index, returning `None` if the
123     /// requested index is greater than the length of the vector.
124     pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> {
125         if ofs < self.len {
126             Some(unsafe { &mut *self.base.offset(ofs as int) })
127         } else {
128             None
129         }
130     }
131
132     /// Unwrap the pointer without running the destructor
133     ///
134     /// This method retrieves the underlying pointer, and in the process
135     /// destroys the CVec but without running the destructor. A use case
136     /// would be transferring ownership of the buffer to a C function, as
137     /// in this case you would not want to run the destructor.
138     ///
139     /// Note that if you want to access the underlying pointer without
140     /// cancelling the destructor, you can simply call `transmute` on the return
141     /// value of `get(0)`.
142     pub unsafe fn unwrap(mut self) -> *mut T {
143         self.dtor = None;
144         self.base
145     }
146 }
147
148 impl<T> AsSlice<T> for CVec<T> {
149     /// View the stored data as a slice.
150     fn as_slice<'a>(&'a self) -> &'a [T] {
151         unsafe {
152             mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
153         }
154     }
155 }
156
157 impl<T> Collection for CVec<T> {
158     fn len(&self) -> uint { self.len }
159 }
160
161 #[cfg(test)]
162 mod tests {
163     use prelude::*;
164
165     use super::CVec;
166     use libc;
167     use ptr;
168
169     fn malloc(n: uint) -> CVec<u8> {
170         unsafe {
171             let mem = libc::malloc(n as libc::size_t);
172             if mem.is_null() { panic!("out of memory") }
173
174             CVec::new_with_dtor(mem as *mut u8, n,
175                 proc() { libc::free(mem as *mut libc::c_void); })
176         }
177     }
178
179     #[test]
180     fn test_basic() {
181         let mut cv = malloc(16);
182
183         *cv.get_mut(3).unwrap() = 8;
184         *cv.get_mut(4).unwrap() = 9;
185         assert_eq!(*cv.get(3).unwrap(), 8);
186         assert_eq!(*cv.get(4).unwrap(), 9);
187         assert_eq!(cv.len(), 16);
188     }
189
190     #[test]
191     #[should_fail]
192     fn test_panic_at_null() {
193         unsafe {
194             CVec::new(ptr::null_mut::<u8>(), 9);
195         }
196     }
197
198     #[test]
199     fn test_overrun_get() {
200         let cv = malloc(16);
201
202         assert!(cv.get(17).is_none());
203     }
204
205     #[test]
206     fn test_overrun_set() {
207         let mut cv = malloc(16);
208
209         assert!(cv.get_mut(17).is_none());
210     }
211
212     #[test]
213     fn test_unwrap() {
214         unsafe {
215             let cv = CVec::new_with_dtor(1 as *mut int, 0,
216                 proc() { panic!("Don't run this destructor!") });
217             let p = cv.unwrap();
218             assert_eq!(p, 1 as *mut int);
219         }
220     }
221
222 }