core_extensions/macros/
phantomdata.rs

1use std_::marker::PhantomData;
2
3/// Maps a `PhantomData<T>` to a `PhantomData<U>` by using a `FnOnce(T) -> U` closure.
4///
5/// # Example
6///
7/// ```rust
8/// use core_extensions::{as_phantom, map_phantomdata};
9///
10/// use std::{
11///     borrow::Borrow,
12///     fmt::Debug,
13///     marker::PhantomData,
14/// };
15///
16/// fn assert_impls<T>(_: PhantomData<T>) 
17/// where
18///     T: AsRef<str> + Borrow<str> + Debug
19/// {}
20///
21/// let tuple = (100, ["hello"]);
22///
23/// // ghost is a `PhantomData<&'static str>`
24/// let ghost = map_phantomdata!(as_phantom(&tuple), |x| x.1[0] );
25///
26/// assert_impls(ghost);
27///
28/// ```
29///
30/// ### Const callable
31///
32/// This macro works in `const`ants, but not in `const fn`s (as of Rust 1.51.0).
33///
34/// ```rust
35/// use core_extensions::{as_phantom, map_phantomdata};
36///
37/// use std::marker::PhantomData;
38/// 
39/// const fn size_of_phantom<T>(_: PhantomData<T>) -> usize {
40///     std::mem::size_of::<T>()
41/// }
42///
43/// const SIZE: usize = {
44///     let tup = (0u8, 116, [3u128, 4]);
45///
46///     size_of_phantom(map_phantomdata!(as_phantom(&tup), |x| x.2[0] ))
47/// };
48///
49/// assert_eq!(SIZE, 16);
50///
51/// ```
52///
53#[cfg_attr(feature = "docsrs", doc(cfg(feature = "phantom")))]
54#[macro_export]
55macro_rules! map_phantomdata {
56    ($expr:expr, $closure:expr) => (
57        $crate::macros::phantomdata::ClosureTypes {
58            param: $expr,
59            closure: $closure,            
60            returns: $crate::std_::marker::PhantomData,
61        }.returns
62    )
63}
64
65
66#[doc(hidden)]
67#[repr(transparent)]
68pub struct ClosureTypes<P, C: FnOnce(P) -> R, R> {
69    pub param: PhantomData<P>,
70    pub returns: PhantomData<R>,
71    pub closure: C,
72}
73
74
75
76/// Gets the type of an expression as a `PhantomData`, without evaluating the expression.
77///
78/// # Example
79///
80/// ```rust
81/// use core_extensions::expr_as_phantom;
82///
83/// use std::marker::PhantomData;
84///
85/// fn type_name<T>(_: PhantomData<T>) -> &'static str {
86///     std::any::type_name::<T>()
87/// }
88///
89/// let mut list = vec![0, 1];
90///
91/// // This block passed to the `expr_as_phantom` macro doesn't run.
92/// let name = type_name(expr_as_phantom!({
93///     list.extend(2..1_000u16);
94///     list
95/// }));
96/// 
97/// assert!(name.contains("Vec"));
98/// 
99/// assert_eq!(list, [0, 1])
100///
101/// ```
102///
103/// ### Const callable
104///
105/// This macro works in `const` contexts, since Rust 1.46.0.
106///
107#[cfg_attr(feature = "rust_1_46", doc = " ```rust")]
108#[cfg_attr(not(feature = "rust_1_46"), doc = " ```ignore")]
109/// use core_extensions::{as_phantom, expr_as_phantom};
110///
111/// use std::marker::PhantomData;
112/// 
113/// const fn size_of_phantom<T>(_: PhantomData<T>) -> usize {
114///     std::mem::size_of::<T>()
115/// }
116///
117/// const fn size() -> usize {
118///     let tup = (0u8, 116, [3u64, 4]);
119///
120///     size_of_phantom(expr_as_phantom!( tup.2[0] ))
121/// }
122///
123/// assert_eq!(size(), 8);
124///
125/// ```
126///
127///
128#[cfg_attr(feature = "docsrs", doc(cfg(feature = "phantom")))]
129#[macro_export]
130macro_rules! expr_as_phantom {
131    ($e:expr) => ({
132        let mut marker = $crate::std_::marker::PhantomData;
133
134        if false {
135            loop {}
136
137            marker = $crate::as_phantom(&$e);
138        }
139        
140        marker
141    })
142}
143
144
145/// Gets the return type of a parameterless closure as a `PhantomData`
146///
147/// # Example
148///
149#[cfg_attr(feature = "iterators", doc = " ```rust")]
150#[cfg_attr(not(feature = "iterators"), doc = " ```ignore")]
151/// use core_extensions::{IteratorExt, return_type_phantom};
152///
153/// use std::{
154///     collections::HashSet,
155///     iter::FromIterator,
156///     marker::PhantomData,
157/// };
158///
159/// fn collect<I, F>(_: PhantomData<F>, iter: I) -> F
160/// where
161///     I: IntoIterator,
162///     F: FromIterator<I::Item>
163/// {
164///     iter.into_iter().collect()
165/// }
166///
167/// let ty = return_type_phantom!(||{
168///     let mut set = HashSet::new();
169///     set.insert(100);
170///     set
171/// });
172/// 
173/// // `set` is a `HashSet<i32>`
174/// let set = collect(ty, 1..=10);
175/// 
176/// assert_eq!(set.into_iter().sum_same(), 55);
177///
178/// ```
179///
180/// ### Const callable
181///
182/// This macro works in `const`ants, but not in `const fn`s (as of Rust 1.51.0).
183///
184/// ```rust
185/// use core_extensions::return_type_phantom;
186///
187/// use std::marker::PhantomData;
188/// 
189/// const fn size_of_phantom<T>(_: PhantomData<T>) -> usize {
190///     std::mem::size_of::<T>()
191/// }
192///
193/// const SIZE: usize = {
194///     let tup = (0u8, 116, [3u128, 4]);
195///
196///     size_of_phantom(return_type_phantom!(|| tup.2[0] ))
197/// };
198///
199/// assert_eq!(SIZE, 16);
200///
201/// ```
202///
203#[cfg_attr(feature = "docsrs", doc(cfg(feature = "phantom")))]
204#[macro_export]
205macro_rules! return_type_phantom {
206    ($closure:expr) => (
207        $crate::macros::phantomdata::UnitClosureReturnType {
208            closure: $closure,            
209            returns: $crate::std_::marker::PhantomData,
210        }.returns
211    )
212}
213
214#[doc(hidden)]
215#[repr(transparent)]
216pub struct UnitClosureReturnType<C: FnOnce() -> R, R> {
217    pub closure: C,
218    pub returns: PhantomData<R>,
219}
220