]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 `'static` type (through runtime reflection) | |
12 | //! | |
13 | //! This module implements the `Any` trait, which enables dynamic typing | |
14 | //! of any `'static` type through runtime reflection. | |
15 | //! | |
16 | //! `Any` itself can be used to get a `TypeId`, and has more features when used | |
17 | //! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and | |
18 | //! `as_ref` methods, to test if the contained value is of a given type, and to | |
19 | //! get a reference to the inner value as a type. As`&mut Any`, there is also | |
20 | //! the `as_mut` method, for getting a mutable reference to the inner value. | |
21 | //! `Box<Any>` adds the `move` method, which will unwrap a `Box<T>` from the | |
22 | //! object. See the extension traits (`*Ext`) for the full details. | |
23 | //! | |
24 | //! Note that &Any is limited to testing whether a value is of a specified | |
25 | //! concrete type, and cannot be used to test whether a type implements a trait. | |
26 | //! | |
27 | //! # Examples | |
28 | //! | |
29 | //! Consider a situation where we want to log out a value passed to a function. | |
85aaf69f | 30 | //! We know the value we're working on implements Debug, but we don't know its |
1a4d82fc JJ |
31 | //! concrete type. We want to give special treatment to certain types: in this |
32 | //! case printing out the length of String values prior to their value. | |
33 | //! We don't know the concrete type of our value at compile time, so we need to | |
34 | //! use runtime reflection instead. | |
35 | //! | |
36 | //! ```rust | |
85aaf69f | 37 | //! use std::fmt::Debug; |
1a4d82fc JJ |
38 | //! use std::any::Any; |
39 | //! | |
85aaf69f SL |
40 | //! // Logger function for any type that implements Debug. |
41 | //! fn log<T: Any + Debug>(value: &T) { | |
1a4d82fc JJ |
42 | //! let value_any = value as &Any; |
43 | //! | |
44 | //! // try to convert our value to a String. If successful, we want to | |
45 | //! // output the String's length as well as its value. If not, it's a | |
46 | //! // different type: just print it out unadorned. | |
47 | //! match value_any.downcast_ref::<String>() { | |
48 | //! Some(as_string) => { | |
49 | //! println!("String ({}): {}", as_string.len(), as_string); | |
50 | //! } | |
51 | //! None => { | |
52 | //! println!("{:?}", value); | |
53 | //! } | |
54 | //! } | |
55 | //! } | |
56 | //! | |
57 | //! // This function wants to log its parameter out prior to doing work with it. | |
c34b1796 | 58 | //! fn do_work<T: Any + Debug>(value: &T) { |
1a4d82fc JJ |
59 | //! log(value); |
60 | //! // ...do some other work | |
61 | //! } | |
62 | //! | |
63 | //! fn main() { | |
64 | //! let my_string = "Hello World".to_string(); | |
65 | //! do_work(&my_string); | |
66 | //! | |
67 | //! let my_i8: i8 = 100; | |
68 | //! do_work(&my_i8); | |
69 | //! } | |
70 | //! ``` | |
71 | ||
85aaf69f | 72 | #![stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 73 | |
c34b1796 AL |
74 | use fmt; |
75 | use marker::Send; | |
85aaf69f SL |
76 | use mem::transmute; |
77 | use option::Option::{self, Some, None}; | |
1a4d82fc | 78 | use raw::TraitObject; |
85aaf69f | 79 | use intrinsics; |
c34b1796 | 80 | use marker::{Reflect, Sized}; |
1a4d82fc JJ |
81 | |
82 | /////////////////////////////////////////////////////////////////////////////// | |
83 | // Any trait | |
84 | /////////////////////////////////////////////////////////////////////////////// | |
85 | ||
c34b1796 | 86 | /// A type to emulate dynamic typing. See the [module-level documentation][mod] for more details. |
1a4d82fc | 87 | /// |
c34b1796 AL |
88 | /// Every type with no non-`'static` references implements `Any`. |
89 | /// | |
90 | /// [mod]: ../index.html | |
85aaf69f | 91 | #[stable(feature = "rust1", since = "1.0.0")] |
c34b1796 | 92 | pub trait Any: Reflect + 'static { |
1a4d82fc | 93 | /// Get the `TypeId` of `self` |
85aaf69f SL |
94 | #[unstable(feature = "core", |
95 | reason = "this method will likely be replaced by an associated static")] | |
1a4d82fc JJ |
96 | fn get_type_id(&self) -> TypeId; |
97 | } | |
98 | ||
c34b1796 AL |
99 | impl<T> Any for T |
100 | where T: Reflect + 'static | |
101 | { | |
1a4d82fc JJ |
102 | fn get_type_id(&self) -> TypeId { TypeId::of::<T>() } |
103 | } | |
104 | ||
105 | /////////////////////////////////////////////////////////////////////////////// | |
106 | // Extension methods for Any trait objects. | |
1a4d82fc JJ |
107 | /////////////////////////////////////////////////////////////////////////////// |
108 | ||
c34b1796 AL |
109 | #[stable(feature = "rust1", since = "1.0.0")] |
110 | impl fmt::Debug for Any { | |
111 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
112 | f.pad("Any") | |
113 | } | |
114 | } | |
115 | ||
1a4d82fc JJ |
116 | impl Any { |
117 | /// Returns true if the boxed type is the same as `T` | |
85aaf69f | 118 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 119 | #[inline] |
c34b1796 | 120 | pub fn is<T: Any>(&self) -> bool { |
1a4d82fc JJ |
121 | // Get TypeId of the type this function is instantiated with |
122 | let t = TypeId::of::<T>(); | |
123 | ||
124 | // Get TypeId of the type in the trait object | |
125 | let boxed = self.get_type_id(); | |
126 | ||
127 | // Compare both TypeIds on equality | |
128 | t == boxed | |
129 | } | |
130 | ||
131 | /// Returns some reference to the boxed value if it is of type `T`, or | |
132 | /// `None` if it isn't. | |
85aaf69f | 133 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 134 | #[inline] |
c34b1796 | 135 | pub fn downcast_ref<T: Any>(&self) -> Option<&T> { |
1a4d82fc JJ |
136 | if self.is::<T>() { |
137 | unsafe { | |
138 | // Get the raw representation of the trait object | |
139 | let to: TraitObject = transmute(self); | |
140 | ||
141 | // Extract the data pointer | |
142 | Some(transmute(to.data)) | |
143 | } | |
144 | } else { | |
145 | None | |
146 | } | |
147 | } | |
148 | ||
149 | /// Returns some mutable reference to the boxed value if it is of type `T`, or | |
150 | /// `None` if it isn't. | |
85aaf69f | 151 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 152 | #[inline] |
c34b1796 | 153 | pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { |
1a4d82fc JJ |
154 | if self.is::<T>() { |
155 | unsafe { | |
156 | // Get the raw representation of the trait object | |
157 | let to: TraitObject = transmute(self); | |
158 | ||
159 | // Extract the data pointer | |
160 | Some(transmute(to.data)) | |
161 | } | |
162 | } else { | |
163 | None | |
164 | } | |
165 | } | |
166 | } | |
85aaf69f | 167 | |
c34b1796 AL |
168 | impl Any+Send { |
169 | /// Forwards to the method defined on the type `Any`. | |
170 | #[stable(feature = "rust1", since = "1.0.0")] | |
171 | #[inline] | |
172 | pub fn is<T: Any>(&self) -> bool { | |
173 | Any::is::<T>(self) | |
174 | } | |
175 | ||
176 | /// Forwards to the method defined on the type `Any`. | |
177 | #[stable(feature = "rust1", since = "1.0.0")] | |
178 | #[inline] | |
179 | pub fn downcast_ref<T: Any>(&self) -> Option<&T> { | |
180 | Any::downcast_ref::<T>(self) | |
181 | } | |
182 | ||
183 | /// Forwards to the method defined on the type `Any`. | |
184 | #[stable(feature = "rust1", since = "1.0.0")] | |
185 | #[inline] | |
186 | pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { | |
187 | Any::downcast_mut::<T>(self) | |
188 | } | |
189 | } | |
190 | ||
191 | ||
85aaf69f SL |
192 | /////////////////////////////////////////////////////////////////////////////// |
193 | // TypeID and its methods | |
194 | /////////////////////////////////////////////////////////////////////////////// | |
195 | ||
196 | /// A `TypeId` represents a globally unique identifier for a type. | |
197 | /// | |
198 | /// Each `TypeId` is an opaque object which does not allow inspection of what's | |
199 | /// inside but does allow basic operations such as cloning, comparison, | |
200 | /// printing, and showing. | |
201 | /// | |
202 | /// A `TypeId` is currently only available for types which ascribe to `'static`, | |
203 | /// but this limitation may be removed in the future. | |
204 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | |
205 | #[stable(feature = "rust1", since = "1.0.0")] | |
206 | pub struct TypeId { | |
207 | t: u64, | |
208 | } | |
209 | ||
210 | impl TypeId { | |
211 | /// Returns the `TypeId` of the type this generic function has been | |
212 | /// instantiated with | |
c34b1796 AL |
213 | #[stable(feature = "rust1", since = "1.0.0")] |
214 | pub fn of<T: ?Sized + Any>() -> TypeId { | |
85aaf69f SL |
215 | TypeId { |
216 | t: unsafe { intrinsics::type_id::<T>() }, | |
217 | } | |
218 | } | |
219 | } |