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
//! `whiteout` provides macros that erase the type of any value into //! an `impl Trait` for a given trait. Obviously, this requires //! `#![feature(conservative_impl_trait)]` to be enabled on your //! crate root. //! //! # Examples //! //! Single values can be erased using the `erase!` macro. //! //! ``` //! #![feature(conservative_impl_trait)] //! #[macro_use] //! extern crate whiteout; //! fn main() { //! let a = erase!(10, std::ops::Add<i64, Output=i64>); //! assert_eq!(a + 10, 20); //! } //! ``` //! //! These erased values can't be used together, though; they have different //! anonymized types. Therefore, you sometimes need the `eraser!` macro. //! //! ``` //! #![feature(conservative_impl_trait)] //! #[macro_use] //! extern crate whiteout; //! //! // Define a custom trait and a blanket impl. //! trait MyTrait: //! std::ops::Add<Self, Output=Self> //! + std::convert::From<i32> //! + std::fmt::Debug //! + PartialEq //! {} //! //! 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 our 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(10); //! assert_eq!(a + b, 20.into()); //! } //! ``` //! //! #![feature(conservative_impl_trait)] /// `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 #[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. #[macro_export] macro_rules! erase { ($val:expr, $($tr:tt)*) => { // Creates a block to operate in { eraser!(f, $($tr)*); // Immediately use this function f($val) } } }