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