From 3158047a459b6d60d0f8f6bf5c299db0910e029a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20L=C3=B6bel?= Date: Mon, 3 Mar 2014 01:01:13 +0100 Subject: [PATCH] Cleaned up `std::any` - Added `TraitObject` representation to `std::raw`. - Added doc to `std::raw`. - Removed `Any::as_void_ptr()` and `Any::as_mut_void_ptr()` methods as they are uneccessary now after the removal of headers on owned boxes. This reduces the number of virtual calls needed. - Made the `..Ext` implementations work directly with the repr of a trait object. - Removed `Any`-related traits from the prelude. - Added bench for `Any` --- src/libgreen/simple.rs | 1 + src/libgreen/task.rs | 1 + src/libnative/task.rs | 1 + src/librustc/lib.rs | 1 + src/libserialize/json.rs | 1 + src/libstd/any.rs | 156 +++++------------- src/libstd/prelude.rs | 1 - src/libstd/raw.rs | 18 +- src/libsync/sync/mod.rs | 7 + src/test/run-fail/fail-macro-any.rs | 2 +- .../run-pass/unit-like-struct-drop-run.rs | 1 + 11 files changed, 70 insertions(+), 120 deletions(-) diff --git a/src/libgreen/simple.rs b/src/libgreen/simple.rs index 297c22e2cd6ce..27ad3b9b91973 100644 --- a/src/libgreen/simple.rs +++ b/src/libgreen/simple.rs @@ -11,6 +11,7 @@ //! A small module implementing a simple "runtime" used for bootstrapping a rust //! scheduler pool and then interacting with it. +use std::any::Any; use std::cast; use std::rt::Runtime; use std::rt::local::Local; diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index bf0ea14ca8753..47c1445fb2251 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -18,6 +18,7 @@ //! contains the rust task itself in order to juggle around ownership of the //! values. +use std::any::Any; use std::cast; use std::rt::env; use std::rt::Runtime; diff --git a/src/libnative/task.rs b/src/libnative/task.rs index 5682697ebfc81..aa3afd4c1a5f3 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -14,6 +14,7 @@ //! by rust tasks. This implements the necessary API traits laid out by std::rt //! in order to spawn new tasks and deschedule the current task. +use std::any::Any; use std::cast; use std::rt::env; use std::rt::local::Local; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4018e70b4f58b..74592139e7d73 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -46,6 +46,7 @@ use middle::lint; use d = driver::driver; +use std::any::AnyRefExt; use std::cmp; use std::io; use std::os; diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 5fd5767d89094..517f4e9ab69f9 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2229,6 +2229,7 @@ mod tests { B(~str) } fn check_err>(to_parse: &'static str, expected_error: &str) { + use std::any::AnyRefExt; use std::task; let res = task::try(proc() { // either fails in `decode` (which is what we want), or diff --git a/src/libstd/any.rs b/src/libstd/any.rs index 709da1ee34dad..80ead34b68adb 100644 --- a/src/libstd/any.rs +++ b/src/libstd/any.rs @@ -20,9 +20,10 @@ //! value. `~Any` adds the `move` method, which will unwrap a `~T` from the object. See the //! extension traits (`*Ext`) for the full details. -use cast::transmute; +use cast::{transmute, transmute_copy}; use fmt; use option::{Option, Some, None}; +use raw::TraitObject; use result::{Result, Ok, Err}; use intrinsics::TypeId; use intrinsics; @@ -39,12 +40,6 @@ pub enum Void { } pub trait Any { /// Get the `TypeId` of `self` fn get_type_id(&self) -> TypeId; - - /// Get a void pointer to `self` - fn as_void_ptr(&self) -> *Void; - - /// Get a mutable void pointer to `self` - fn as_mut_void_ptr(&mut self) -> *mut Void; } impl Any for T { @@ -52,21 +47,11 @@ impl Any for T { fn get_type_id(&self) -> TypeId { TypeId::of::() } - - /// Get a void pointer to `self` - fn as_void_ptr(&self) -> *Void { - self as *T as *Void - } - - /// Get a mutable void pointer to `self` - fn as_mut_void_ptr(&mut self) -> *mut Void { - self as *mut T as *mut Void - } } /////////////////////////////////////////////////////////////////////////////// // Extension methods for Any trait objects. -// Implemented as three extension traits so that generics work. +// Implemented as three extension traits so that the methods can be generic. /////////////////////////////////////////////////////////////////////////////// /// Extension methods for a referenced `Any` trait object @@ -95,7 +80,13 @@ impl<'a> AnyRefExt<'a> for &'a Any { #[inline] fn as_ref(self) -> Option<&'a T> { if self.is::() { - Some(unsafe { transmute(self.as_void_ptr()) }) + unsafe { + // Get the raw representation of the trait object + let to: TraitObject = transmute_copy(&self); + + // Extract the data pointer + Some(transmute(to.data)) + } } else { None } @@ -113,7 +104,13 @@ impl<'a> AnyMutRefExt<'a> for &'a mut Any { #[inline] fn as_mut(self) -> Option<&'a mut T> { if self.is::() { - Some(unsafe { transmute(self.as_mut_void_ptr()) }) + unsafe { + // Get the raw representation of the trait object + let to: TraitObject = transmute_copy(&self); + + // Extract the data pointer + Some(transmute(to.data)) + } } else { None } @@ -132,13 +129,14 @@ impl AnyOwnExt for ~Any { fn move(self) -> Result<~T, ~Any> { if self.is::() { unsafe { - // Extract the pointer to the boxed value, temporary alias with self - let ptr: ~T = transmute(self.as_void_ptr()); + // Get the raw representation of the trait object + let to: TraitObject = transmute_copy(&self); // Prevent destructor on self being run intrinsics::forget(self); - Ok(ptr) + // Extract the data pointer + Ok(transmute(to.data)) } } else { Err(self) @@ -172,100 +170,6 @@ mod tests { static TEST: &'static str = "Test"; - #[test] - fn any_as_void_ptr() { - let (a, b, c) = (~5u as ~Any, ~TEST as ~Any, ~Test as ~Any); - let a_r: &Any = a; - let b_r: &Any = b; - let c_r: &Any = c; - - assert_eq!(a.as_void_ptr(), a_r.as_void_ptr()); - assert_eq!(b.as_void_ptr(), b_r.as_void_ptr()); - assert_eq!(c.as_void_ptr(), c_r.as_void_ptr()); - - let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any); - let a_r: &Any = a; - let b_r: &Any = b; - let c_r: &Any = c; - - assert_eq!(a.as_void_ptr(), a_r.as_void_ptr()); - assert_eq!(b.as_void_ptr(), b_r.as_void_ptr()); - assert_eq!(c.as_void_ptr(), c_r.as_void_ptr()); - - let mut x = Test; - let mut y: &'static str = "Test"; - let (a, b, c) = (&mut 5u as &mut Any, - &mut y as &mut Any, - &mut x as &mut Any); - let a_r: &Any = a; - let b_r: &Any = b; - let c_r: &Any = c; - - assert_eq!(a.as_void_ptr(), a_r.as_void_ptr()); - assert_eq!(b.as_void_ptr(), b_r.as_void_ptr()); - assert_eq!(c.as_void_ptr(), c_r.as_void_ptr()); - - let (a, b, c) = (5u, "hello", Test); - let (a_r, b_r, c_r) = (&a as &Any, &b as &Any, &c as &Any); - - assert_eq!(a.as_void_ptr(), a_r.as_void_ptr()); - assert_eq!(b.as_void_ptr(), b_r.as_void_ptr()); - assert_eq!(c.as_void_ptr(), c_r.as_void_ptr()); - } - - #[test] - fn any_as_mut_void_ptr() { - let y: &'static str = "Test"; - let mut a = ~5u as ~Any; - let mut b = ~y as ~Any; - let mut c = ~Test as ~Any; - - let a_ptr = a.as_mut_void_ptr(); - let b_ptr = b.as_mut_void_ptr(); - let c_ptr = c.as_mut_void_ptr(); - - let a_r: &mut Any = a; - let b_r: &mut Any = b; - let c_r: &mut Any = c; - - assert_eq!(a_ptr, a_r.as_mut_void_ptr()); - assert_eq!(b_ptr, b_r.as_mut_void_ptr()); - assert_eq!(c_ptr, c_r.as_mut_void_ptr()); - - let mut x = Test; - let mut y: &'static str = "Test"; - let a = &mut 5u as &mut Any; - let b = &mut y as &mut Any; - let c = &mut x as &mut Any; - - let a_ptr = a.as_mut_void_ptr(); - let b_ptr = b.as_mut_void_ptr(); - let c_ptr = c.as_mut_void_ptr(); - - let a_r: &mut Any = a; - let b_r: &mut Any = b; - let c_r: &mut Any = c; - - assert_eq!(a_ptr, a_r.as_mut_void_ptr()); - assert_eq!(b_ptr, b_r.as_mut_void_ptr()); - assert_eq!(c_ptr, c_r.as_mut_void_ptr()); - - let y: &'static str = "Test"; - let mut a = 5u; - let mut b = y; - let mut c = Test; - - let a_ptr = a.as_mut_void_ptr(); - let b_ptr = b.as_mut_void_ptr(); - let c_ptr = c.as_mut_void_ptr(); - - let (a_r, b_r, c_r) = (&mut a as &mut Any, &mut b as &mut Any, &mut c as &mut Any); - - assert_eq!(a_ptr, a_r.as_mut_void_ptr()); - assert_eq!(b_ptr, b_r.as_mut_void_ptr()); - assert_eq!(c_ptr, c_r.as_mut_void_ptr()); - } - #[test] fn any_referenced() { let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any); @@ -395,3 +299,21 @@ mod tests { assert_eq!(format!("{}", b), ~"&Any"); } } + +#[cfg(test)] +mod bench { + extern crate test; + + use any::{Any, AnyRefExt}; + use option::Some; + use self::test::BenchHarness; + + #[bench] + fn bench_as_ref(bh: &mut BenchHarness) { + bh.iter(|| { + let mut x = 0; let mut y = &mut x as &mut Any; + test::black_box(&mut y); + test::black_box(y.as_ref::() == Some(&0)); + }); + } +} diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 5ea00c2f67d64..19848f650973f 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -35,7 +35,6 @@ pub use mem::drop; // Reexported types and traits -pub use any::{Any, AnyOwnExt, AnyRefExt, AnyMutRefExt}; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, IntoBytes}; pub use c_str::ToCStr; pub use char::Char; diff --git a/src/libstd/raw.rs b/src/libstd/raw.rs index c7ba2ad393285..94ad268f51206 100644 --- a/src/libstd/raw.rs +++ b/src/libstd/raw.rs @@ -10,6 +10,13 @@ #[allow(missing_doc)]; +//! Contains struct definitions for the layout of compiler built-in types. +//! +//! They can be used as targets of transmutes in unsafe code for manipulating +//! the raw representations directly. +//! +//! Their definitition should always match the ABI defined in `rustc::back::abi`. + use cast; /// The representation of a Rust managed box @@ -49,13 +56,22 @@ pub struct Procedure { env: *(), } +/// The representation of a Rust trait object. +/// +/// This struct does not have a `Repr` implementation +/// because there is no way to refer to all trait objects generically. +pub struct TraitObject { + vtable: *(), + data: *(), +} + /// This trait is meant to map equivalences between raw structs and their /// corresponding rust values. pub trait Repr { /// This function "unwraps" a rust value (without consuming it) into its raw /// struct representation. This can be used to read/write different values /// for the struct. This is a safe method because by default it does not - /// give write-access to the struct returned. + /// enable write-access to the fields of the return value in safe code. #[inline] fn repr(&self) -> T { unsafe { cast::transmute_copy(self) } } } diff --git a/src/libsync/sync/mod.rs b/src/libsync/sync/mod.rs index 7078f01945e96..9fe585c263fb0 100644 --- a/src/libsync/sync/mod.rs +++ b/src/libsync/sync/mod.rs @@ -976,6 +976,8 @@ mod tests { } #[test] fn test_mutex_killed_simple() { + use std::any::Any; + // Mutex must get automatically unlocked if failed/killed within. let m = Mutex::new(); let m2 = m.clone(); @@ -992,6 +994,8 @@ mod tests { #[ignore(reason = "linked failure")] #[test] fn test_mutex_killed_cond() { + use std::any::Any; + // Getting killed during cond wait must not corrupt the mutex while // unwinding (e.g. double unlock). let m = Mutex::new(); @@ -1019,6 +1023,7 @@ mod tests { #[ignore(reason = "linked failure")] #[test] fn test_mutex_killed_broadcast() { + use std::any::Any; use std::unstable::finally::Finally; let m = Mutex::new(); @@ -1329,6 +1334,8 @@ mod tests { } #[cfg(test)] fn rwlock_kill_helper(mode1: RWLockMode, mode2: RWLockMode) { + use std::any::Any; + // Mutex must get automatically unlocked if failed/killed within. let x = RWLock::new(); let x2 = x.clone(); diff --git a/src/test/run-fail/fail-macro-any.rs b/src/test/run-fail/fail-macro-any.rs index 58f3522ce7a97..9bedd8c8cc82b 100644 --- a/src/test/run-fail/fail-macro-any.rs +++ b/src/test/run-fail/fail-macro-any.rs @@ -11,5 +11,5 @@ // error-pattern:failed at '~Any' fn main() { - fail!(~413 as ~Any); + fail!(~413 as ~::std::any::Any); } diff --git a/src/test/run-pass/unit-like-struct-drop-run.rs b/src/test/run-pass/unit-like-struct-drop-run.rs index 04507dd01ce5c..29dbe35752aa1 100644 --- a/src/test/run-pass/unit-like-struct-drop-run.rs +++ b/src/test/run-pass/unit-like-struct-drop-run.rs @@ -10,6 +10,7 @@ // Make sure the destructor is run for unit-like structs. +use std::any::AnyOwnExt; use std::task; struct Foo;