(index<- )        ./libcore/any.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 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. `Box<Any>` adds the `move` method, which will unwrap a `Box<T>` from the object.  See
  21  //! the extension traits (`*Ext`) for the full details.
  22  
  23  use cast::{transmute, transmute_copy};
  24  use option::{Option, Some, None};
  25  use owned::Box;
  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 toTraitObject = 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 toTraitObject = 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<Box<T>, Self>;
 125  }
 126  
 127  impl AnyOwnExt for Box<Any> {
 128      #[inline]
 129      fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
 130          if self.is::<T>() {
 131              unsafe {
 132                  // Get the raw representation of the trait object
 133                  let toTraitObject = 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  #[cfg(test)]
 148  mod tests {
 149      use prelude::*;
 150      use super::*;
 151      use owned::Box;
 152      use realstd::str::StrAllocating;
 153  
 154      #[deriving(Eq, Show)]
 155      struct Test;
 156  
 157      static TEST: &'static str = "Test";
 158  
 159      #[test]
 160      fn any_referenced() {
 161          let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);
 162  
 163          assert!(a.is::<uint>());
 164          assert!(!b.is::<uint>());
 165          assert!(!c.is::<uint>());
 166  
 167          assert!(!a.is::<&'static str>());
 168          assert!(b.is::<&'static str>());
 169          assert!(!c.is::<&'static str>());
 170  
 171          assert!(!a.is::<Test>());
 172          assert!(!b.is::<Test>());
 173          assert!(c.is::<Test>());
 174      }
 175  
 176      #[test]
 177      fn any_owning() {
 178          let (a, b, c) = (box 5u as Box<Any>, box TEST as Box<Any>, box Test as Box<Any>);
 179  
 180          assert!(a.is::<uint>());
 181          assert!(!b.is::<uint>());
 182          assert!(!c.is::<uint>());
 183  
 184          assert!(!a.is::<&'static str>());
 185          assert!(b.is::<&'static str>());
 186          assert!(!c.is::<&'static str>());
 187  
 188          assert!(!a.is::<Test>());
 189          assert!(!b.is::<Test>());
 190          assert!(c.is::<Test>());
 191      }
 192  
 193      #[test]
 194      fn any_as_ref() {
 195          let a = &5u as &Any;
 196  
 197          match a.as_ref::<uint>() {
 198              Some(&5) => {}
 199              x => fail!("Unexpected value {:?}", x)
 200          }
 201  
 202          match a.as_ref::<Test>() {
 203              None => {}
 204              x => fail!("Unexpected value {:?}", x)
 205          }
 206      }
 207  
 208      #[test]
 209      fn any_as_mut() {
 210          let mut a = 5u;
 211          let mut b = box 7u;
 212  
 213          let a_r = &mut a as &mut Any;
 214          let tmp: &mut uint = b;
 215          let b_r = tmp as &mut Any;
 216  
 217          match a_r.as_mut::<uint>() {
 218              Some(x) => {
 219                  assert_eq!(*x, 5u);
 220                  *x = 612;
 221              }
 222              x => fail!("Unexpected value {:?}", x)
 223          }
 224  
 225          match b_r.as_mut::<uint>() {
 226              Some(x) => {
 227                  assert_eq!(*x, 7u);
 228                  *x = 413;
 229              }
 230              x => fail!("Unexpected value {:?}", x)
 231          }
 232  
 233          match a_r.as_mut::<Test>() {
 234              None => (),
 235              x => fail!("Unexpected value {:?}", x)
 236          }
 237  
 238          match b_r.as_mut::<Test>() {
 239              None => (),
 240              x => fail!("Unexpected value {:?}", x)
 241          }
 242  
 243          match a_r.as_mut::<uint>() {
 244              Some(&612) => {}
 245              x => fail!("Unexpected value {:?}", x)
 246          }
 247  
 248          match b_r.as_mut::<uint>() {
 249              Some(&413) => {}
 250              x => fail!("Unexpected value {:?}", x)
 251          }
 252      }
 253  
 254      #[test]
 255      fn any_move() {
 256          let a = box 8u as Box<Any>;
 257          let b = box Test as Box<Any>;
 258  
 259          match a.move::<uint>() {
 260              Ok(a) => { assert_eq!(a, box 8u); }
 261              Err(..) => fail!()
 262          }
 263          match b.move::<Test>() {
 264              Ok(a) => { assert_eq!(a, box Test); }
 265              Err(..) => fail!()
 266          }
 267  
 268          let a = box 8u as Box<Any>;
 269          let b = box Test as Box<Any>;
 270  
 271          assert!(a.move::<Box<Test>>().is_err());
 272          assert!(b.move::<Box<uint>>().is_err());
 273      }
 274  
 275      #[test]
 276      fn test_show() {
 277          let a = box 8u as Box<::realcore::any::Any>;
 278          let b = box Test as Box<::realcore::any::Any>;
 279          assert_eq!(format!("{}", a), "Box<Any>".to_owned());
 280          assert_eq!(format!("{}", b), "Box<Any>".to_owned());
 281  
 282          let a = &8u as &::realcore::any::Any;
 283          let b = &Test as &::realcore::any::Any;
 284          assert_eq!(format!("{}", a), "&Any".to_owned());
 285          assert_eq!(format!("{}", b), "&Any".to_owned());
 286      }
 287  }
 288  
 289  #[cfg(test)]
 290  mod bench {
 291      extern crate test;
 292  
 293      use any::{Any, AnyRefExt};
 294      use option::Some;
 295      use self::test::Bencher;
 296  
 297      #[bench]
 298      fn bench_as_ref(b: &mut Bencher) {
 299          b.iter(|| {
 300              let mut x = 0; let mut y = &mut x as &mut Any;
 301              test::black_box(&mut y);
 302              test::black_box(y.as_ref::<int>() == Some(&0));
 303          });
 304      }
 305  }