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