]> git.lizzy.rs Git - rust.git/blob - src/libstd/any.rs
auto merge of #13600 : brandonw/rust/master, r=brson
[rust.git] / src / libstd / any.rs
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.
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 //! Traits for dynamic typing of any type (through runtime reflection)
12 //!
13 //! This module implements the `Any` trait, which enables dynamic typing
14 //! of any type, through runtime reflection.
15 //!
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. `~Any` adds the `move` method, which will unwrap a `~T` from the object.  See the
21 //! extension traits (`*Ext`) for the full details.
22
23 use cast::{transmute, transmute_copy};
24 use fmt;
25 use option::{Option, Some, None};
26 use raw::TraitObject;
27 use result::{Result, Ok, Err};
28 use intrinsics::TypeId;
29 use intrinsics;
30
31 /// A type with no inhabitants
32 pub enum Void { }
33
34 ///////////////////////////////////////////////////////////////////////////////
35 // Any trait
36 ///////////////////////////////////////////////////////////////////////////////
37
38 /// The `Any` trait is implemented by all types, and can be used as a trait object
39 /// for dynamic typing
40 pub trait Any {
41     /// Get the `TypeId` of `self`
42     fn get_type_id(&self) -> TypeId;
43 }
44
45 impl<T: 'static> Any for T {
46     /// Get the `TypeId` of `self`
47     fn get_type_id(&self) -> TypeId {
48         TypeId::of::<T>()
49     }
50 }
51
52 ///////////////////////////////////////////////////////////////////////////////
53 // Extension methods for Any trait objects.
54 // Implemented as three extension traits so that the methods can be generic.
55 ///////////////////////////////////////////////////////////////////////////////
56
57 /// Extension methods for a referenced `Any` trait object
58 pub trait AnyRefExt<'a> {
59     /// Returns true if the boxed type is the same as `T`
60     fn is<T: 'static>(self) -> bool;
61
62     /// Returns some reference to the boxed value if it is of type `T`, or
63     /// `None` if it isn't.
64     fn as_ref<T: 'static>(self) -> Option<&'a T>;
65 }
66
67 impl<'a> AnyRefExt<'a> for &'a Any {
68     #[inline]
69     fn is<T: 'static>(self) -> bool {
70         // Get TypeId of the type this function is instantiated with
71         let t = TypeId::of::<T>();
72
73         // Get TypeId of the type in the trait object
74         let boxed = self.get_type_id();
75
76         // Compare both TypeIds on equality
77         t == boxed
78     }
79
80     #[inline]
81     fn as_ref<T: 'static>(self) -> Option<&'a T> {
82         if self.is::<T>() {
83             unsafe {
84                 // Get the raw representation of the trait object
85                 let to: TraitObject = transmute_copy(&self);
86
87                 // Extract the data pointer
88                 Some(transmute(to.data))
89             }
90         } else {
91             None
92         }
93     }
94 }
95
96 /// Extension methods for a mutable referenced `Any` trait object
97 pub trait AnyMutRefExt<'a> {
98     /// Returns some mutable reference to the boxed value if it is of type `T`, or
99     /// `None` if it isn't.
100     fn as_mut<T: 'static>(self) -> Option<&'a mut T>;
101 }
102
103 impl<'a> AnyMutRefExt<'a> for &'a mut Any {
104     #[inline]
105     fn as_mut<T: 'static>(self) -> Option<&'a mut T> {
106         if self.is::<T>() {
107             unsafe {
108                 // Get the raw representation of the trait object
109                 let to: TraitObject = transmute_copy(&self);
110
111                 // Extract the data pointer
112                 Some(transmute(to.data))
113             }
114         } else {
115             None
116         }
117     }
118 }
119
120 /// Extension methods for an owning `Any` trait object
121 pub trait AnyOwnExt {
122     /// Returns the boxed value if it is of type `T`, or
123     /// `Err(Self)` if it isn't.
124     fn move<T: 'static>(self) -> Result<~T, Self>;
125 }
126
127 impl AnyOwnExt for ~Any {
128     #[inline]
129     fn move<T: 'static>(self) -> Result<~T, ~Any> {
130         if self.is::<T>() {
131             unsafe {
132                 // Get the raw representation of the trait object
133                 let to: TraitObject = transmute_copy(&self);
134
135                 // Prevent destructor on self being run
136                 intrinsics::forget(self);
137
138                 // Extract the data pointer
139                 Ok(transmute(to.data))
140             }
141         } else {
142             Err(self)
143         }
144     }
145 }
146
147 ///////////////////////////////////////////////////////////////////////////////
148 // Trait implementations
149 ///////////////////////////////////////////////////////////////////////////////
150
151 impl fmt::Show for ~Any {
152     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153         f.pad("~Any")
154     }
155 }
156
157 impl<'a> fmt::Show for &'a Any {
158     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159         f.pad("&Any")
160     }
161 }
162
163 #[cfg(test)]
164 mod tests {
165     use prelude::*;
166     use super::*;
167
168     #[deriving(Eq, Show)]
169     struct Test;
170
171     static TEST: &'static str = "Test";
172
173     #[test]
174     fn any_referenced() {
175         let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);
176
177         assert!(a.is::<uint>());
178         assert!(!b.is::<uint>());
179         assert!(!c.is::<uint>());
180
181         assert!(!a.is::<&'static str>());
182         assert!(b.is::<&'static str>());
183         assert!(!c.is::<&'static str>());
184
185         assert!(!a.is::<Test>());
186         assert!(!b.is::<Test>());
187         assert!(c.is::<Test>());
188     }
189
190     #[test]
191     fn any_owning() {
192         let (a, b, c) = (~5u as ~Any, ~TEST as ~Any, ~Test as ~Any);
193
194         assert!(a.is::<uint>());
195         assert!(!b.is::<uint>());
196         assert!(!c.is::<uint>());
197
198         assert!(!a.is::<&'static str>());
199         assert!(b.is::<&'static str>());
200         assert!(!c.is::<&'static str>());
201
202         assert!(!a.is::<Test>());
203         assert!(!b.is::<Test>());
204         assert!(c.is::<Test>());
205     }
206
207     #[test]
208     fn any_as_ref() {
209         let a = &5u as &Any;
210
211         match a.as_ref::<uint>() {
212             Some(&5) => {}
213             x => fail!("Unexpected value {:?}", x)
214         }
215
216         match a.as_ref::<Test>() {
217             None => {}
218             x => fail!("Unexpected value {:?}", x)
219         }
220     }
221
222     #[test]
223     fn any_as_mut() {
224         let mut a = 5u;
225         let mut b = ~7u;
226
227         let a_r = &mut a as &mut Any;
228         let tmp: &mut uint = b;
229         let b_r = tmp as &mut Any;
230
231         match a_r.as_mut::<uint>() {
232             Some(x) => {
233                 assert_eq!(*x, 5u);
234                 *x = 612;
235             }
236             x => fail!("Unexpected value {:?}", x)
237         }
238
239         match b_r.as_mut::<uint>() {
240             Some(x) => {
241                 assert_eq!(*x, 7u);
242                 *x = 413;
243             }
244             x => fail!("Unexpected value {:?}", x)
245         }
246
247         match a_r.as_mut::<Test>() {
248             None => (),
249             x => fail!("Unexpected value {:?}", x)
250         }
251
252         match b_r.as_mut::<Test>() {
253             None => (),
254             x => fail!("Unexpected value {:?}", x)
255         }
256
257         match a_r.as_mut::<uint>() {
258             Some(&612) => {}
259             x => fail!("Unexpected value {:?}", x)
260         }
261
262         match b_r.as_mut::<uint>() {
263             Some(&413) => {}
264             x => fail!("Unexpected value {:?}", x)
265         }
266     }
267
268     #[test]
269     fn any_move() {
270         let a = ~8u as ~Any;
271         let b = ~Test as ~Any;
272
273         match a.move::<uint>() {
274             Ok(a) => { assert_eq!(a, ~8u); }
275             Err(..) => fail!()
276         }
277         match b.move::<Test>() {
278             Ok(a) => { assert_eq!(a, ~Test); }
279             Err(..) => fail!()
280         }
281
282         let a = ~8u as ~Any;
283         let b = ~Test as ~Any;
284
285         assert!(a.move::<~Test>().is_err());
286         assert!(b.move::<~uint>().is_err());
287     }
288
289     #[test]
290     fn test_show() {
291         let a = ~8u as ~Any;
292         let b = ~Test as ~Any;
293         assert_eq!(format!("{}", a), ~"~Any");
294         assert_eq!(format!("{}", b), ~"~Any");
295
296         let a = &8u as &Any;
297         let b = &Test as &Any;
298         assert_eq!(format!("{}", a), ~"&Any");
299         assert_eq!(format!("{}", b), ~"&Any");
300     }
301 }
302
303 #[cfg(test)]
304 mod bench {
305     extern crate test;
306
307     use any::{Any, AnyRefExt};
308     use option::Some;
309     use self::test::Bencher;
310
311     #[bench]
312     fn bench_as_ref(b: &mut Bencher) {
313         b.iter(|| {
314             let mut x = 0; let mut y = &mut x as &mut Any;
315             test::black_box(&mut y);
316             test::black_box(y.as_ref::<int>() == Some(&0));
317         });
318     }
319 }