(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, lenuint) -> 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, lenuint,
  93                                  dtorproc():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, ofsuint) -> 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, ofsuint) -> 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  }