1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
//! `whiteout` provides macros that erase the type of any value into //! an `impl Trait` for a given trait. //! //! # Examples //! //! Single values can be erased using the `erase!` macro. //! //! ``` //!# #[macro_use] //!# extern crate whiteout; //!# fn main() { //! let a = erase!(10, std::ops::Add<i64, Output=i64>); //! let b = erase!(5, std::ops::Add<i64, Output=i64>); //! assert_eq!(a + 10, 20); //! assert_eq!(b + 10, 15); //! // This fails, the types are opaque //! // assert_eq!(a + b, 15); //!# } //! ``` //! //! These erased values can't be used together, though; they have different //! anonymized types. Therefore, you sometimes need the `eraser!` macro. //! //! ``` //! #[macro_use] //! extern crate whiteout; //! //! // Define a custom trait into which types will be erased. //! trait MyTrait: //! std::ops::Add<Self, Output=Self> // Allow the operation we need //! + std::convert::From<i32> // Allow converting from concrete values //! + std::fmt::Debug // Allow printing (for use with assert!()) //! + PartialEq // Allow comparison (for use with assert_eq!()) //! {} //! //! // Implement MyTrait for all possible types. //! impl<T> MyTrait for T //! where T: std::ops::Add<Self, Output=Self> //! + std::convert::From<i32> //! + std::fmt::Debug //! + PartialEq //! {} //! //! // Create an eraser function for the custom trait //! eraser!(erase_my_trait, MyTrait); //! //! fn main() { //! // Use the eraser function. //! // If we used erase!(10, MyTrait); for these //! // they would be of different types. //! let a = erase_my_trait(10); //! let b = erase_my_trait(5); //! assert_eq!(a + b, 15.into()); //! } //! ``` //! //! /// `eraser!(name, trait)` creates a function with the given identifier that /// erases values to an anonymous type that is `impl Trait` for the given trait. /// /// # Examples /// /// ``` /// #[macro_use] /// extern crate whiteout; /// /// // Define a custom trait into which types will be erased. /// trait MyTrait: /// std::ops::Add<Self, Output=Self> // Allow the operation we need /// + std::convert::From<i32> // Allow converting from concrete values /// + std::fmt::Debug // Allow printing (for use with assert!()) /// + PartialEq // Allow comparison (for use with assert_eq!()) /// {} /// /// // Implement MyTrait for all possible types. /// impl<T> MyTrait for T /// where T: std::ops::Add<Self, Output=Self> /// + std::convert::From<i32> /// + std::fmt::Debug /// + PartialEq /// {} /// /// // Create an eraser function for the custom trait /// eraser!(erase_my_trait, MyTrait); /// /// fn main() { /// // Use the eraser function. /// // If we used erase!(10, MyTrait); for these /// // they would be of different types. /// let a = erase_my_trait(10); /// let b = erase_my_trait(5); /// assert_eq!(a + b, 15.into()); /// } /// ``` /// /// #[macro_export] macro_rules! eraser { ($name:ident, $($tr:tt)*) => { // This function takes any type implementing T and returns impl T fn $name<T: $($tr)*>(val: T) -> impl $($tr)* { // Do nothing to the value val } } } /// `erase!(value, trait)` turns a value of any type that implements trait into /// an erasted type which is `impl Trait` for that trait. /// /// # Examples /// /// /// ``` ///# #[macro_use] ///# extern crate whiteout; ///# fn main() { /// let a = erase!(10, std::ops::Add<i64, Output=i64>); /// let b = erase!(5, std::ops::Add<i64, Output=i64>); /// assert_eq!(a + 10, 20); /// assert_eq!(b + 10, 15); /// // This fails, the types are opaque /// // assert_eq!(a + b, 15); ///# } /// ``` /// #[macro_export] macro_rules! erase { ($val:expr, $($tr:tt)*) => { // Creates a block to operate in { eraser!(f, $($tr)*); // Immediately use this function f($val) } } }