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