1 // Copyright 2013-2014 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.
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.
11 //! Traits for dynamic typing of any `'static` type (through runtime reflection)
13 //! This module implements the `Any` trait, which enables dynamic typing
14 //! of any `'static` type through runtime reflection.
16 //! `Any` itself can be used to get a `TypeId`, and has more features when used as a trait object.
17 //! As `&Any` (a borrowed trait object), it has the `is` and `as_ref` methods, to test if the
18 //! contained value is of a given type, and to get a reference to the inner value as a type. As
19 //! `&mut Any`, there is also the `as_mut` method, for getting a mutable reference to the inner
20 //! value. `Box<Any>` adds the `move` method, which will unwrap a `Box<T>` from the object. See
21 //! the extension traits (`*Ext`) for the full details.
23 use mem::{transmute, transmute_copy};
24 use option::{Option, Some, None};
26 use intrinsics::TypeId;
28 /// A type with no inhabitants
31 ///////////////////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////////////////
35 /// The `Any` trait is implemented by all `'static` types, and can be used for dynamic typing
37 /// Every type with no non-`'static` references implements `Any`, so `Any` can be used as a trait
38 /// object to emulate the effects dynamic typing.
40 /// Get the `TypeId` of `self`
41 fn get_type_id(&self) -> TypeId;
44 impl<T: 'static> Any for T {
45 /// Get the `TypeId` of `self`
46 fn get_type_id(&self) -> TypeId {
51 ///////////////////////////////////////////////////////////////////////////////
52 // Extension methods for Any trait objects.
53 // Implemented as three extension traits so that the methods can be generic.
54 ///////////////////////////////////////////////////////////////////////////////
56 /// Extension methods for a referenced `Any` trait object
57 pub trait AnyRefExt<'a> {
58 /// Returns true if the boxed type is the same as `T`
59 fn is<T: 'static>(self) -> bool;
61 /// Returns some reference to the boxed value if it is of type `T`, or
62 /// `None` if it isn't.
63 fn as_ref<T: 'static>(self) -> Option<&'a T>;
66 impl<'a> AnyRefExt<'a> for &'a Any {
68 fn is<T: 'static>(self) -> bool {
69 // Get TypeId of the type this function is instantiated with
70 let t = TypeId::of::<T>();
72 // Get TypeId of the type in the trait object
73 let boxed = self.get_type_id();
75 // Compare both TypeIds on equality
80 fn as_ref<T: 'static>(self) -> Option<&'a T> {
83 // Get the raw representation of the trait object
84 let to: TraitObject = transmute_copy(&self);
86 // Extract the data pointer
87 Some(transmute(to.data))
95 /// Extension methods for a mutable referenced `Any` trait object
96 pub trait AnyMutRefExt<'a> {
97 /// Returns some mutable reference to the boxed value if it is of type `T`, or
98 /// `None` if it isn't.
99 fn as_mut<T: 'static>(self) -> Option<&'a mut T>;
102 impl<'a> AnyMutRefExt<'a> for &'a mut Any {
104 fn as_mut<T: 'static>(self) -> Option<&'a mut T> {
107 // Get the raw representation of the trait object
108 let to: TraitObject = transmute_copy(&self);
110 // Extract the data pointer
111 Some(transmute(to.data))
123 use realstd::owned::{Box, AnyOwnExt};
124 use realstd::str::Str;
126 #[deriving(PartialEq, Show)]
129 static TEST: &'static str = "Test";
132 fn any_referenced() {
133 let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);
135 assert!(a.is::<uint>());
136 assert!(!b.is::<uint>());
137 assert!(!c.is::<uint>());
139 assert!(!a.is::<&'static str>());
140 assert!(b.is::<&'static str>());
141 assert!(!c.is::<&'static str>());
143 assert!(!a.is::<Test>());
144 assert!(!b.is::<Test>());
145 assert!(c.is::<Test>());
150 let (a, b, c) = (box 5u as Box<Any>, box TEST as Box<Any>, box Test as Box<Any>);
152 assert!(a.is::<uint>());
153 assert!(!b.is::<uint>());
154 assert!(!c.is::<uint>());
156 assert!(!a.is::<&'static str>());
157 assert!(b.is::<&'static str>());
158 assert!(!c.is::<&'static str>());
160 assert!(!a.is::<Test>());
161 assert!(!b.is::<Test>());
162 assert!(c.is::<Test>());
169 match a.as_ref::<uint>() {
171 x => fail!("Unexpected value {}", x)
174 match a.as_ref::<Test>() {
176 x => fail!("Unexpected value {}", x)
185 let a_r = &mut a as &mut Any;
186 let tmp: &mut uint = b;
187 let b_r = tmp as &mut Any;
189 match a_r.as_mut::<uint>() {
194 x => fail!("Unexpected value {}", x)
197 match b_r.as_mut::<uint>() {
202 x => fail!("Unexpected value {}", x)
205 match a_r.as_mut::<Test>() {
207 x => fail!("Unexpected value {}", x)
210 match b_r.as_mut::<Test>() {
212 x => fail!("Unexpected value {}", x)
215 match a_r.as_mut::<uint>() {
217 x => fail!("Unexpected value {}", x)
220 match b_r.as_mut::<uint>() {
222 x => fail!("Unexpected value {}", x)
228 use realstd::any::Any;
229 use realstd::result::{Ok, Err};
230 let a = box 8u as Box<Any>;
231 let b = box Test as Box<Any>;
233 match a.move::<uint>() {
234 Ok(a) => { assert!(a == box 8u); }
237 match b.move::<Test>() {
238 Ok(a) => { assert!(a == box Test); }
242 let a = box 8u as Box<Any>;
243 let b = box Test as Box<Any>;
245 assert!(a.move::<Box<Test>>().is_err());
246 assert!(b.move::<Box<uint>>().is_err());
251 use realstd::to_str::ToStr;
252 let a = box 8u as Box<::realstd::any::Any>;
253 let b = box Test as Box<::realstd::any::Any>;
254 let a_str = a.to_str();
255 let b_str = b.to_str();
256 assert_eq!(a_str.as_slice(), "Box<Any>");
257 assert_eq!(b_str.as_slice(), "Box<Any>");
260 let b = &Test as &Any;
261 let s = format!("{}", a);
262 assert_eq!(s.as_slice(), "&Any");
263 let s = format!("{}", b);
264 assert_eq!(s.as_slice(), "&Any");
269 let test = [0u, ..8];
270 let test = &test as &Any;
271 assert!(test.is::<[uint, ..8]>());
272 assert!(!test.is::<[uint, ..10]>());
280 use any::{Any, AnyRefExt};
282 use self::test::Bencher;
285 fn bench_as_ref(b: &mut Bencher) {
287 let mut x = 0; let mut y = &mut x as &mut Any;
288 test::black_box(&mut y);
289 test::black_box(y.as_ref::<int>() == Some(&0));