(index<- ) ./libstd/any.rs
git branch: * master c7553ea auto merge of #13609 : richo/rust/str-type-vim, r=alexcrichton
modified: Sat Apr 19 11:22:39 2014
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 use str::StrSlice;
168
169 #[deriving(Eq, Show)]
170 struct Test;
171
172 static TEST: &'static str = "Test";
173
174 #[test]
175 fn any_referenced() {
176 let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);
177
178 assert!(a.is::<uint>());
179 assert!(!b.is::<uint>());
180 assert!(!c.is::<uint>());
181
182 assert!(!a.is::<&'static str>());
183 assert!(b.is::<&'static str>());
184 assert!(!c.is::<&'static str>());
185
186 assert!(!a.is::<Test>());
187 assert!(!b.is::<Test>());
188 assert!(c.is::<Test>());
189 }
190
191 #[test]
192 fn any_owning() {
193 let (a, b, c) = (~5u as ~Any, ~TEST as ~Any, ~Test as ~Any);
194
195 assert!(a.is::<uint>());
196 assert!(!b.is::<uint>());
197 assert!(!c.is::<uint>());
198
199 assert!(!a.is::<&'static str>());
200 assert!(b.is::<&'static str>());
201 assert!(!c.is::<&'static str>());
202
203 assert!(!a.is::<Test>());
204 assert!(!b.is::<Test>());
205 assert!(c.is::<Test>());
206 }
207
208 #[test]
209 fn any_as_ref() {
210 let a = &5u as &Any;
211
212 match a.as_ref::<uint>() {
213 Some(&5) => {}
214 x => fail!("Unexpected value {:?}", x)
215 }
216
217 match a.as_ref::<Test>() {
218 None => {}
219 x => fail!("Unexpected value {:?}", x)
220 }
221 }
222
223 #[test]
224 fn any_as_mut() {
225 let mut a = 5u;
226 let mut b = ~7u;
227
228 let a_r = &mut a as &mut Any;
229 let tmp: &mut uint = b;
230 let b_r = tmp as &mut Any;
231
232 match a_r.as_mut::<uint>() {
233 Some(x) => {
234 assert_eq!(*x, 5u);
235 *x = 612;
236 }
237 x => fail!("Unexpected value {:?}", x)
238 }
239
240 match b_r.as_mut::<uint>() {
241 Some(x) => {
242 assert_eq!(*x, 7u);
243 *x = 413;
244 }
245 x => fail!("Unexpected value {:?}", x)
246 }
247
248 match a_r.as_mut::<Test>() {
249 None => (),
250 x => fail!("Unexpected value {:?}", x)
251 }
252
253 match b_r.as_mut::<Test>() {
254 None => (),
255 x => fail!("Unexpected value {:?}", x)
256 }
257
258 match a_r.as_mut::<uint>() {
259 Some(&612) => {}
260 x => fail!("Unexpected value {:?}", x)
261 }
262
263 match b_r.as_mut::<uint>() {
264 Some(&413) => {}
265 x => fail!("Unexpected value {:?}", x)
266 }
267 }
268
269 #[test]
270 fn any_move() {
271 let a = ~8u as ~Any;
272 let b = ~Test as ~Any;
273
274 match a.move::<uint>() {
275 Ok(a) => { assert_eq!(a, ~8u); }
276 Err(..) => fail!()
277 }
278 match b.move::<Test>() {
279 Ok(a) => { assert_eq!(a, ~Test); }
280 Err(..) => fail!()
281 }
282
283 let a = ~8u as ~Any;
284 let b = ~Test as ~Any;
285
286 assert!(a.move::<~Test>().is_err());
287 assert!(b.move::<~uint>().is_err());
288 }
289
290 #[test]
291 fn test_show() {
292 let a = ~8u as ~Any;
293 let b = ~Test as ~Any;
294 assert_eq!(format!("{}", a), "~Any".to_owned());
295 assert_eq!(format!("{}", b), "~Any".to_owned());
296
297 let a = &8u as &Any;
298 let b = &Test as &Any;
299 assert_eq!(format!("{}", a), "&Any".to_owned());
300 assert_eq!(format!("{}", b), "&Any".to_owned());
301 }
302 }
303
304 #[cfg(test)]
305 mod bench {
306 extern crate test;
307
308 use any::{Any, AnyRefExt};
309 use option::Some;
310 use self::test::Bencher;
311
312 #[bench]
313 fn bench_as_ref(b: &mut Bencher) {
314 b.iter(|| {
315 let mut x = 0; let mut y = &mut x as &mut Any;
316 test::black_box(&mut y);
317 test::black_box(y.as_ref::<int>() == Some(&0));
318 });
319 }
320 }
libstd/any.rs:120:55-120:55 -trait- definition:
/// Extension methods for an owning `Any` trait object
pub trait AnyOwnExt {
/// Returns the boxed value if it is of type `T`, or
references:- 2123: /// `Err(Self)` if it isn't.
124: fn move<T: 'static>(self) -> Result<~T, Self>;
125: }
127: impl AnyOwnExt for ~Any {
128: #[inline]
libstd/any.rs:39:23-39:23 -trait- definition:
/// for dynamic typing
pub trait Any {
/// Get the `TypeId` of `self`
references:- 16151: impl fmt::Show for ~Any {
152: fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
--
157: impl<'a> fmt::Show for &'a Any {
158: fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
libstd/option.rs:
241: #[inline]
242: pub fn expect<M: Any + Send>(self, msg: M) -> T {
243: match self {
libstd/task.rs:
58: /// children tasks complete, recommend using a result future.
59: pub type TaskResult = Result<(), ~Any:Send>;
--
242: pub fn try<T:Send>(f: proc():Send -> T) -> Result<T, ~Any:Send> {
243: /*!
libstd/rt/mod.rs:
166: // FIXME: This is a serious code smell and this should not exist at all.
167: fn wrap(~self) -> ~Any;
168: }
libstd/rt/unwind.rs:
375: fn begin_unwind_inner(msg: ~Any:Send, file: &'static str, line: uint) -> ! {
376: let mut task;
libstd/any.rs:
127: impl AnyOwnExt for ~Any {
128: #[inline]
libstd/any.rs:31:31-31:31 -enum- definition:
/// A type with no inhabitants
pub enum Void { }
///////////////////////////////////////////////////////////////////////////////
references:- 4libstd/fmt/mod.rs:
537: pub struct Argument<'a> {
538: formatter: extern "Rust" fn(&any::Void, &mut Formatter) -> Result,
539: value: &'a any::Void,
540: }
--
849: let v = self.curarg.next().unwrap().value;
850: unsafe { Some(*(v as *any::Void as *uint)) }
851: }