about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-03-14 11:16:10 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-03-14 13:59:02 -0700
commit58e4ab2b33f559107dbdfa9d3cab882cf8029481 (patch)
tree749ec81e1a287e6ce082c201d97cec7243612a79 /src/libstd
parente99d523707c8058383e7a551e49d59ce622d5765 (diff)
downloadrust-58e4ab2b33f559107dbdfa9d3cab882cf8029481.tar.gz
rust-58e4ab2b33f559107dbdfa9d3cab882cf8029481.zip
extra: Put the nail in the coffin, delete libextra
This commit shreds all remnants of libextra from the compiler and standard
distribution. Two modules, c_vec/tempfile, were moved into libstd after some
cleanup, and the other modules were moved to separate crates as seen fit.

Closes #8784
Closes #12413
Closes #12576
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/c_vec.rs216
-rw-r--r--src/libstd/io/mod.rs29
-rw-r--r--src/libstd/io/tempfile.rs93
-rw-r--r--src/libstd/lib.rs4
-rw-r--r--src/libstd/os.rs1
5 files changed, 321 insertions, 22 deletions
diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs
new file mode 100644
index 00000000000..00d250a5fc7
--- /dev/null
+++ b/src/libstd/c_vec.rs
@@ -0,0 +1,216 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Library to interface with chunks of memory allocated in C.
+//!
+//! It is often desirable to safely interface with memory allocated from C,
+//! encapsulating the unsafety into allocation and destruction time.  Indeed,
+//! allocating memory externally is currently the only way to give Rust shared
+//! mut state with C programs that keep their own references; vectors are
+//! unsuitable because they could be reallocated or moved at any time, and
+//! importing C memory into a vector takes a one-time snapshot of the memory.
+//!
+//! This module simplifies the usage of such external blocks of memory.  Memory
+//! is encapsulated into an opaque object after creation; the lifecycle of the
+//! memory can be optionally managed by Rust, if an appropriate destructor
+//! closure is provided.  Safety is ensured by bounds-checking accesses, which
+//! are marshalled through get and set functions.
+//!
+//! There are three unsafe functions: the two constructors, and the
+//! unwrap method. The constructors are unsafe for the
+//! obvious reason (they act on a pointer that cannot be checked inside the
+//! method), but `unwrap()` is somewhat more subtle in its unsafety.
+//! It returns the contained pointer, but at the same time destroys the CVec
+//! without running its destructor. This can be used to pass memory back to
+//! C, but care must be taken that the ownership of underlying resources are
+//! handled correctly, i.e. that allocated memory is eventually freed
+//! if necessary.
+
+use cast;
+use container::Container;
+use ptr;
+use ptr::RawPtr;
+use raw;
+use option::{Option, Some, None};
+use ops::Drop;
+
+/// The type representing a foreign chunk of memory
+pub struct CVec<T> {
+    priv base: *mut T,
+    priv len: uint,
+    priv dtor: Option<proc()>,
+}
+
+#[unsafe_destructor]
+impl<T> Drop for CVec<T> {
+    fn drop(&mut self) {
+        match self.dtor.take() {
+            None => (),
+            Some(f) => f()
+        }
+    }
+}
+
+impl<T> CVec<T> {
+    /// Create a `CVec` from a raw pointer to a buffer with a given length.
+    ///
+    /// Fails if the given pointer is null. The returned vector will not attempt
+    /// to deallocate the vector when dropped.
+    ///
+    /// # Arguments
+    ///
+    /// * base - A raw pointer to a buffer
+    /// * len - The number of elements in the buffer
+    pub unsafe fn new(base: *mut T, len: uint) -> CVec<T> {
+        assert!(base != ptr::mut_null());
+        CVec {
+            base: base,
+            len: len,
+            dtor: None,
+        }
+    }
+
+    /// Create a `CVec` from a foreign buffer, with a given length,
+    /// and a function to run upon destruction.
+    ///
+    /// Fails if the given pointer is null.
+    ///
+    /// # Arguments
+    ///
+    /// * base - A foreign pointer to a buffer
+    /// * len - The number of elements in the buffer
+    /// * dtor - A proc to run when the value is destructed, useful
+    ///          for freeing the buffer, etc.
+    pub unsafe fn new_with_dtor(base: *mut T, len: uint,
+                                dtor: proc()) -> CVec<T> {
+        assert!(base != ptr::mut_null());
+        CVec {
+            base: base,
+            len: len,
+            dtor: Some(dtor),
+        }
+    }
+
+    /// View the stored data as a slice.
+    pub fn as_slice<'a>(&'a self) -> &'a [T] {
+        unsafe {
+            cast::transmute(raw::Slice { data: self.base as *T, len: self.len })
+        }
+    }
+
+    /// View the stored data as a mutable slice.
+    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
+        unsafe {
+            cast::transmute(raw::Slice { data: self.base as *T, len: self.len })
+        }
+    }
+
+    /// Retrieves an element at a given index, returning `None` if the requested
+    /// index is greater than the length of the vector.
+    pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> {
+        if ofs < self.len {
+            Some(unsafe { &*self.base.offset(ofs as int) })
+        } else {
+            None
+        }
+    }
+
+    /// Retrieves a mutable element at a given index, returning `None` if the
+    /// requested index is greater than the length of the vector.
+    pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> {
+        if ofs < self.len {
+            Some(unsafe { &mut *self.base.offset(ofs as int) })
+        } else {
+            None
+        }
+    }
+
+    /// Unwrap the pointer without running the destructor
+    ///
+    /// This method retrieves the underlying pointer, and in the process
+    /// destroys the CVec but without running the destructor. A use case
+    /// would be transferring ownership of the buffer to a C function, as
+    /// in this case you would not want to run the destructor.
+    ///
+    /// Note that if you want to access the underlying pointer without
+    /// cancelling the destructor, you can simply call `transmute` on the return
+    /// value of `get(0)`.
+    pub unsafe fn unwrap(mut self) -> *mut T {
+        self.dtor = None;
+        self.base
+    }
+}
+
+impl<T> Container for CVec<T> {
+    fn len(&self) -> uint { self.len }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::*;
+
+    use super::CVec;
+    use libc;
+    use ptr;
+    use rt::global_heap::malloc_raw;
+
+    fn malloc(n: uint) -> CVec<u8> {
+        unsafe {
+            let mem = malloc_raw(n);
+
+            CVec::new_with_dtor(mem as *mut u8, n,
+                proc() { libc::free(mem as *mut libc::c_void); })
+        }
+    }
+
+    #[test]
+    fn test_basic() {
+        let mut cv = malloc(16);
+
+        *cv.get_mut(3).unwrap() = 8;
+        *cv.get_mut(4).unwrap() = 9;
+        assert_eq!(*cv.get(3).unwrap(), 8);
+        assert_eq!(*cv.get(4).unwrap(), 9);
+        assert_eq!(cv.len(), 16);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_fail_at_null() {
+        unsafe {
+            CVec::new(ptr::mut_null::<u8>(), 9);
+        }
+    }
+
+    #[test]
+    fn test_overrun_get() {
+        let cv = malloc(16);
+
+        assert!(cv.get(17).is_none());
+    }
+
+    #[test]
+    fn test_overrun_set() {
+        let mut cv = malloc(16);
+
+        assert!(cv.get_mut(17).is_none());
+    }
+
+    #[test]
+    fn test_unwrap() {
+        unsafe {
+            let cv = CVec::new_with_dtor(1 as *mut int, 0,
+                proc() { fail!("Don't run this destructor!") });
+            let p = cv.unwrap();
+            assert_eq!(p, 1 as *mut int);
+        }
+    }
+
+}
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 869643336a9..28f6d13070e 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -241,40 +241,31 @@ pub use self::net::tcp::TcpStream;
 pub use self::net::udp::UdpStream;
 pub use self::pipe::PipeStream;
 pub use self::process::{Process, ProcessConfig};
+pub use self::tempfile::TempDir;
 
 pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter};
 pub use self::buffered::{BufferedReader, BufferedWriter, BufferedStream,
                          LineBufferedWriter};
 pub use self::comm_adapters::{ChanReader, ChanWriter};
 
+// this comes first to get the iotest! macro
 pub mod test;
 
+mod buffered;
+mod comm_adapters;
+mod mem;
+mod result;
+mod tempfile;
+pub mod extensions;
 pub mod fs;
-
+pub mod net;
 pub mod pipe;
-
 pub mod process;
-
-pub mod net;
-
-mod mem;
-
+pub mod signal;
 pub mod stdio;
-
-mod result;
-
-pub mod extensions;
-
 pub mod timer;
-
-mod buffered;
-
-pub mod signal;
-
 pub mod util;
 
-mod comm_adapters;
-
 /// The default buffer size for various I/O operations
 // libuv recommends 64k buffers to maximize throughput
 // https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
diff --git a/src/libstd/io/tempfile.rs b/src/libstd/io/tempfile.rs
new file mode 100644
index 00000000000..34d6b19199a
--- /dev/null
+++ b/src/libstd/io/tempfile.rs
@@ -0,0 +1,93 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Temporary files and directories
+
+use io::fs;
+use io;
+use iter::{Iterator, range};
+use libc;
+use ops::Drop;
+use option::{Option, None, Some};
+use os;
+use path::{Path, GenericPath};
+use result::{Ok, Err};
+use sync::atomics;
+
+/// A wrapper for a path to temporary directory implementing automatic
+/// scope-based deletion.
+pub struct TempDir {
+    priv path: Option<Path>
+}
+
+impl TempDir {
+    /// Attempts to make a temporary directory inside of `tmpdir` whose name
+    /// will have the suffix `suffix`. The directory will be automatically
+    /// deleted once the returned wrapper is destroyed.
+    ///
+    /// If no directory can be created, None is returned.
+    pub fn new_in(tmpdir: &Path, suffix: &str) -> Option<TempDir> {
+        if !tmpdir.is_absolute() {
+            return TempDir::new_in(&os::make_absolute(tmpdir), suffix);
+        }
+
+        static mut CNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
+
+        for _ in range(0u, 1000) {
+            let filename = format!("rs-{}-{}-{}",
+                                   unsafe { libc::getpid() },
+                                   unsafe { CNT.fetch_add(1, atomics::SeqCst) },
+                                   suffix);
+            let p = tmpdir.join(filename);
+            match fs::mkdir(&p, io::UserRWX) {
+                Err(..) => {}
+                Ok(()) => return Some(TempDir { path: Some(p) })
+            }
+        }
+        None
+    }
+
+    /// Attempts to make a temporary directory inside of `os::tmpdir()` whose
+    /// name will have the suffix `suffix`. The directory will be automatically
+    /// deleted once the returned wrapper is destroyed.
+    ///
+    /// If no directory can be created, None is returned.
+    pub fn new(suffix: &str) -> Option<TempDir> {
+        TempDir::new_in(&os::tmpdir(), suffix)
+    }
+
+    /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper.
+    /// This discards the wrapper so that the automatic deletion of the
+    /// temporary directory is prevented.
+    pub fn unwrap(self) -> Path {
+        let mut tmpdir = self;
+        tmpdir.path.take_unwrap()
+    }
+
+    /// Access the wrapped `std::path::Path` to the temporary directory.
+    pub fn path<'a>(&'a self) -> &'a Path {
+        self.path.get_ref()
+    }
+}
+
+impl Drop for TempDir {
+    fn drop(&mut self) {
+        for path in self.path.iter() {
+            if path.exists() {
+                // FIXME: is failing the right thing to do?
+                fs::rmdir_recursive(path).unwrap();
+            }
+        }
+    }
+}
+
+// the tests for this module need to change the path using change_dir,
+// and this doesn't play nicely with other tests so these unit tests are located
+// in src/test/run-pass/tempfile.rs
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 24a77b71fba..6b1773ec7ff 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -74,9 +74,8 @@
 #[cfg(test)] extern crate native;
 #[cfg(test)] extern crate green;
 
-// Make extra and rand accessible for benchmarking/testcases
+// Make and rand accessible for benchmarking/testcases
 #[cfg(test)] extern crate rand;
-#[cfg(test)] extern crate extra = "extra";
 
 // Make std testable by not duplicating lang items. See #2912
 #[cfg(test)] extern crate realstd = "std";
@@ -172,6 +171,7 @@ pub mod sync;
 #[unstable]
 pub mod libc;
 pub mod c_str;
+pub mod c_vec;
 pub mod os;
 pub mod io;
 pub mod path;
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 3a86aa3d6b6..b8f00d1b692 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -1392,7 +1392,6 @@ mod tests {
     use rand::Rng;
     use rand;
 
-
     #[test]
     pub fn last_os_error() {
         debug!("{}", os::last_os_error());