]>
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 | ||
1a4d82fc JJ |
11 | //! This module implements the `Any` trait, which enables dynamic typing |
12 | //! of any `'static` type through runtime reflection. | |
13 | //! | |
14 | //! `Any` itself can be used to get a `TypeId`, and has more features when used | |
15 | //! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and | |
e9174d1e SL |
16 | //! `downcast_ref` methods, to test if the contained value is of a given type, |
17 | //! and to get a reference to the inner value as a type. As `&mut Any`, there | |
18 | //! is also the `downcast_mut` method, for getting a mutable reference to the | |
9cc50fc6 SL |
19 | //! inner value. `Box<Any>` adds the `downcast` method, which attempts to |
20 | //! convert to a `Box<T>`. See the [`Box`] documentation for the full details. | |
1a4d82fc JJ |
21 | //! |
22 | //! Note that &Any is limited to testing whether a value is of a specified | |
23 | //! concrete type, and cannot be used to test whether a type implements a trait. | |
24 | //! | |
54a0048b | 25 | //! [`Box`]: ../../std/boxed/struct.Box.html |
9cc50fc6 | 26 | //! |
1a4d82fc JJ |
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 | ||
9346a6ac | 86 | /// A type to emulate dynamic typing. |
1a4d82fc | 87 | /// |
3157f602 | 88 | /// Most types implement `Any`. However, any type which contains a non-`'static` reference does not. |
9346a6ac | 89 | /// See the [module-level documentation][mod] for more details. |
c34b1796 | 90 | /// |
9346a6ac | 91 | /// [mod]: index.html |
85aaf69f | 92 | #[stable(feature = "rust1", since = "1.0.0")] |
c34b1796 | 93 | pub trait Any: Reflect + 'static { |
9346a6ac | 94 | /// Gets the `TypeId` of `self`. |
62682a34 | 95 | #[unstable(feature = "get_type_id", |
e9174d1e SL |
96 | reason = "this method will likely be replaced by an associated static", |
97 | issue = "27745")] | |
1a4d82fc JJ |
98 | fn get_type_id(&self) -> TypeId; |
99 | } | |
100 | ||
92a42be0 | 101 | #[stable(feature = "rust1", since = "1.0.0")] |
9cc50fc6 | 102 | impl<T: Reflect + 'static + ?Sized > Any for T { |
1a4d82fc JJ |
103 | fn get_type_id(&self) -> TypeId { TypeId::of::<T>() } |
104 | } | |
105 | ||
106 | /////////////////////////////////////////////////////////////////////////////// | |
107 | // Extension methods for Any trait objects. | |
1a4d82fc JJ |
108 | /////////////////////////////////////////////////////////////////////////////// |
109 | ||
c34b1796 AL |
110 | #[stable(feature = "rust1", since = "1.0.0")] |
111 | impl fmt::Debug for Any { | |
112 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
113 | f.pad("Any") | |
114 | } | |
115 | } | |
116 | ||
9346a6ac AL |
117 | // Ensure that the result of e.g. joining a thread can be printed and |
118 | // hence used with `unwrap`. May eventually no longer be needed if | |
119 | // dispatch works with upcasting. | |
120 | #[stable(feature = "rust1", since = "1.0.0")] | |
121 | impl fmt::Debug for Any + Send { | |
122 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
123 | f.pad("Any") | |
124 | } | |
125 | } | |
126 | ||
1a4d82fc JJ |
127 | impl Any { |
128 | /// Returns true if the boxed type is the same as `T` | |
85aaf69f | 129 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 130 | #[inline] |
c34b1796 | 131 | pub fn is<T: Any>(&self) -> bool { |
1a4d82fc JJ |
132 | // Get TypeId of the type this function is instantiated with |
133 | let t = TypeId::of::<T>(); | |
134 | ||
135 | // Get TypeId of the type in the trait object | |
136 | let boxed = self.get_type_id(); | |
137 | ||
138 | // Compare both TypeIds on equality | |
139 | t == boxed | |
140 | } | |
141 | ||
142 | /// Returns some reference to the boxed value if it is of type `T`, or | |
143 | /// `None` if it isn't. | |
85aaf69f | 144 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 145 | #[inline] |
c34b1796 | 146 | pub fn downcast_ref<T: Any>(&self) -> Option<&T> { |
1a4d82fc JJ |
147 | if self.is::<T>() { |
148 | unsafe { | |
149 | // Get the raw representation of the trait object | |
150 | let to: TraitObject = transmute(self); | |
151 | ||
152 | // Extract the data pointer | |
e9174d1e | 153 | Some(&*(to.data as *const T)) |
1a4d82fc JJ |
154 | } |
155 | } else { | |
156 | None | |
157 | } | |
158 | } | |
159 | ||
160 | /// Returns some mutable reference to the boxed value if it is of type `T`, or | |
161 | /// `None` if it isn't. | |
85aaf69f | 162 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 163 | #[inline] |
c34b1796 | 164 | pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { |
1a4d82fc JJ |
165 | if self.is::<T>() { |
166 | unsafe { | |
167 | // Get the raw representation of the trait object | |
168 | let to: TraitObject = transmute(self); | |
169 | ||
170 | // Extract the data pointer | |
e9174d1e | 171 | Some(&mut *(to.data as *const T as *mut T)) |
1a4d82fc JJ |
172 | } |
173 | } else { | |
174 | None | |
175 | } | |
176 | } | |
177 | } | |
85aaf69f | 178 | |
c34b1796 AL |
179 | impl Any+Send { |
180 | /// Forwards to the method defined on the type `Any`. | |
181 | #[stable(feature = "rust1", since = "1.0.0")] | |
182 | #[inline] | |
183 | pub fn is<T: Any>(&self) -> bool { | |
184 | Any::is::<T>(self) | |
185 | } | |
186 | ||
187 | /// Forwards to the method defined on the type `Any`. | |
188 | #[stable(feature = "rust1", since = "1.0.0")] | |
189 | #[inline] | |
190 | pub fn downcast_ref<T: Any>(&self) -> Option<&T> { | |
191 | Any::downcast_ref::<T>(self) | |
192 | } | |
193 | ||
194 | /// Forwards to the method defined on the type `Any`. | |
195 | #[stable(feature = "rust1", since = "1.0.0")] | |
196 | #[inline] | |
197 | pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { | |
198 | Any::downcast_mut::<T>(self) | |
199 | } | |
200 | } | |
201 | ||
202 | ||
85aaf69f SL |
203 | /////////////////////////////////////////////////////////////////////////////// |
204 | // TypeID and its methods | |
205 | /////////////////////////////////////////////////////////////////////////////// | |
206 | ||
207 | /// A `TypeId` represents a globally unique identifier for a type. | |
208 | /// | |
209 | /// Each `TypeId` is an opaque object which does not allow inspection of what's | |
210 | /// inside but does allow basic operations such as cloning, comparison, | |
211 | /// printing, and showing. | |
212 | /// | |
213 | /// A `TypeId` is currently only available for types which ascribe to `'static`, | |
214 | /// but this limitation may be removed in the future. | |
215 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | |
216 | #[stable(feature = "rust1", since = "1.0.0")] | |
217 | pub struct TypeId { | |
218 | t: u64, | |
219 | } | |
220 | ||
221 | impl TypeId { | |
222 | /// Returns the `TypeId` of the type this generic function has been | |
223 | /// instantiated with | |
c34b1796 | 224 | #[stable(feature = "rust1", since = "1.0.0")] |
bd371182 | 225 | pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId { |
85aaf69f SL |
226 | TypeId { |
227 | t: unsafe { intrinsics::type_id::<T>() }, | |
228 | } | |
229 | } | |
230 | } |