whiteout/
lib.rs

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