diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-03-14 11:16:10 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-03-14 13:59:02 -0700 |
| commit | 58e4ab2b33f559107dbdfa9d3cab882cf8029481 (patch) | |
| tree | 749ec81e1a287e6ce082c201d97cec7243612a79 /src/libstd | |
| parent | e99d523707c8058383e7a551e49d59ce622d5765 (diff) | |
| download | rust-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.rs | 216 | ||||
| -rw-r--r-- | src/libstd/io/mod.rs | 29 | ||||
| -rw-r--r-- | src/libstd/io/tempfile.rs | 93 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 4 | ||||
| -rw-r--r-- | src/libstd/os.rs | 1 |
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()); |
