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