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