typewit/type_fn.rs
1//! Type-level functions.
2//!
3//! Type-level functions come in two flavors:
4//! [injective](#injective), and [non-injective](#non-injective)
5//!
6//!
7//! # Injective
8//!
9//! An injective function is any function `f` for which `a != b` implies `f(a) != f(b)`.
10//! <br>(For both injective and non-injective functions, `f(a) != f(b)` implies `a != b`)
11//!
12//! The [`InjTypeFn`] trait encodes injective type-level functions,
13//! requiring the type to implement both [`TypeFn`] and [`RevTypeFn`].
14//!
15//!
16//! ### Example: injective function
17//!
18//! ```rust
19//! # use typewit::CallInjFn;
20//! #
21//! typewit::inj_type_fn!{
22//! struct Upcast;
23//!
24//! impl u8 => u16;
25//! impl u16 => u32;
26//! impl u32 => u64;
27//! impl u64 => u128;
28//! }
29//! let _: CallInjFn<Upcast, u8> = 3u16;
30//! let _: CallInjFn<Upcast, u16> = 5u32;
31//! ```
32//!
33//! Because `Upcast` is injective,
34//! it is possible to query the argument from the returned value:
35//!
36//! ```rust
37//! # use typewit::UncallFn;
38//! #
39//! let _: UncallFn<Upcast, u16> = 3u8;
40//! let _: UncallFn<Upcast, u128> = 5u64;
41//! #
42//! # typewit::inj_type_fn!{
43//! # struct Upcast;
44//! #
45//! # impl u8 => u16;
46//! # impl u16 => u32;
47//! # impl u32 => u64;
48//! # impl u64 => u128;
49//! # }
50//! ```
51//!
52//! # Non-injective
53//!
54//! The [`TypeFn`] trait allows implementors to be non-injective.
55//!
56//! ### Example: non-injective function
57//!
58//! ```rust
59//! typewit::type_fn!{
60//! struct Bar;
61//!
62//! impl<T> Vec<T> => T;
63//! impl<T> Box<T> => T;
64//! }
65//! ```
66//! `Bar` is *non*-injective because it maps both `Vec<T>` and `Box<T>` to `T`.
67//!
68//!
69//! [`TypeFn`]: crate::type_fn::TypeFn
70//! [`CallFn`]: crate::type_fn::CallFn
71//!
72
73use core::marker::PhantomData;
74
75mod injective;
76
77pub use self::injective::*;
78
79pub(crate) use self::injective::simple_inj_type_fn;
80
81#[doc(no_inline)]
82pub use crate::inj_type_fn;
83
84#[doc(no_inline)]
85pub use crate::type_fn;
86
87
88/// A function that operates purely on the level of types.
89///
90/// These can be used in `typewit` to
91/// [map the type arguments of `TypeEq`](crate::TypeEq::project).
92///
93/// Type-level functions can also be declared with the
94/// [`type_fn`](macro@crate::type_fn) macro.
95///
96/// # Properties
97///
98/// These are properties about `TypeFn` implementors that users can rely on.
99///
100/// For any given `F: TypeFn<A> + TypeFn<B>` these hold:
101///
102/// 1. If `A == B`, then `CallFn<F, A> == CallFn<F, B>`.
103/// 2. If `CallFn<F, A> != CallFn<F, B>`, then `A != B`.
104///
105/// # Examples
106///
107/// ### Manual Implementation
108///
109/// ```rust
110/// use typewit::{TypeFn, CallFn};
111///
112/// let string: CallFn<AddOutput<String>, &str> = "foo".to_string() + ", bar";
113/// let _: String = string;
114/// assert_eq!(string, "foo, bar");
115///
116///
117/// struct AddOutput<Lhs>(core::marker::PhantomData<Lhs>);
118///
119/// // This part is optional,
120/// // only necessary to pass the function as a value, not just as a type.
121/// impl<Lhs> AddOutput<Lhs> {
122/// const NEW: Self = Self(core::marker::PhantomData);
123/// }
124///
125/// impl<Lhs, Rhs> TypeFn<Rhs> for AddOutput<Lhs>
126/// where
127/// Lhs: core::ops::Add<Rhs>
128/// {
129/// type Output = Lhs::Output;
130/// }
131/// ```
132///
133/// ### Macro-based Implementation
134///
135/// This example uses the [`type_fn`](macro@crate::type_fn) macro
136/// to declare the type-level function,
137/// and is otherwise equivalent to the manual one.
138///
139/// ```rust
140/// use typewit::CallFn;
141///
142/// let string: CallFn<AddOutput<String>, &str> = "foo".to_string() + ", bar";
143/// let _: String = string;
144/// assert_eq!(string, "foo, bar");
145///
146/// typewit::type_fn! {
147/// struct AddOutput<Lhs>;
148///
149/// impl<Rhs> Rhs => Lhs::Output
150/// where Lhs: core::ops::Add<Rhs>
151/// }
152/// ```
153///
154#[cfg_attr(feature = "rust_1_83", diagnostic::on_unimplemented(
155 message = "{Self} is not a type-level function over `{T}`",
156))]
157pub trait TypeFn<T: ?Sized> {
158 /// The return value of the function
159 type Output: ?Sized;
160
161 /// Helper constant for adding asserts in the `TypeFn` impl;
162 const TYPE_FN_ASSERTS: () = ();
163}
164
165/// Calls the `F` [type-level function](TypeFn) with `T` as its argument.
166///
167/// For `F:`[`InjTypeFn<T>`](crate::InjTypeFn), it's better to
168/// use [`CallInjFn`] instead of this type alias.
169///
170///
171/// # Example
172///
173/// ```rust
174/// use typewit::CallFn;
175/// use core::ops::Mul;
176///
177/// assert_eq!(mul(3u8, &5u8), 15u8);
178///
179/// fn mul<L, R>(l: L, r: R) -> CallFn<MulOutput<L>, R>
180/// where
181/// L: core::ops::Mul<R>
182/// {
183/// l * r
184/// }
185///
186/// // Declares `struct MulOutput<Lhs>`,
187/// // a type-level function from `Rhs` to the return type of `Lhs * Rhs`.
188/// typewit::type_fn! {
189/// struct MulOutput<Lhs>;
190///
191/// impl<Rhs> Rhs => <Lhs as Mul<Rhs>>::Output
192/// where Lhs: core::ops::Mul<Rhs>
193/// }
194/// ```
195///
196pub type CallFn<F, T> = <F as TypeFn<T>>::Output;
197
198///////////////////////////////////////////////////////
199
200/// Type-level function from `T` to `&'a T`
201pub struct GRef<'a>(PhantomData<fn() -> &'a ()>);
202
203impl<'a> GRef<'a> {
204 /// Make a value of this type-level function
205 pub const NEW: Self = Self(PhantomData);
206}
207
208simple_inj_type_fn!{
209 impl['a, T: 'a + ?Sized] (T => &'a T) for GRef<'a>
210}
211
212////////////////
213
214/// Type-level function from `T` to `&'a mut T`
215pub struct GRefMut<'a>(PhantomData<fn() -> &'a mut ()>);
216
217impl<'a> GRefMut<'a> {
218 /// Make a value of this type-level function
219 pub const NEW: Self = Self(PhantomData);
220}
221
222simple_inj_type_fn!{
223 impl['a, T: 'a + ?Sized] (T => &'a mut T) for GRefMut<'a>
224}
225
226////////////////
227
228/// Type-level function from `T` to `Box<T>`
229#[cfg(feature = "alloc")]
230#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
231pub struct GBox;
232
233#[cfg(feature = "alloc")]
234simple_inj_type_fn!{
235 impl[T: ?Sized] (T => alloc::boxed::Box<T>) for GBox
236}
237
238////////////////
239
240/// Type-level identity function
241pub struct FnIdentity;
242
243simple_inj_type_fn!{
244 impl[T: ?Sized] (T => T) for FnIdentity
245}
246
247////////////////
248
249/// Type-level function which implements `TypeFn` by delegating to `F`
250///
251/// This is mostly a workaround to write `F: TypeFn<T>` bounds in Rust 1.57.0
252/// (trait bounds in `const fn`s were stabilized in Rust 1.61.0).
253///
254/// Because `Foo<F>: Trait`-style bounds unintentionally work in 1.57.0,
255/// this crate uses `Invoke<F>: TypeFn<T>`
256/// when the `"rust_1_61"` feature is disabled,
257/// and `F: TypeFn<T>` when it is enabled.
258///
259pub struct Invoke<F>(PhantomData<fn() -> F>);
260
261impl<F> Copy for Invoke<F> {}
262
263impl<F> Clone for Invoke<F> {
264 fn clone(&self) -> Self {
265 *self
266 }
267}
268
269impl<F> Invoke<F> {
270 /// Constructs an `Invoke`
271 pub const NEW: Self = Self(PhantomData);
272}
273
274
275impl<F, T: ?Sized> TypeFn<T> for Invoke<F>
276where
277 F: TypeFn<T>
278{
279 type Output = CallFn<F, T>;
280}
281
282impl<F, R: ?Sized> RevTypeFn<R> for Invoke<F>
283where
284 F: RevTypeFn<R>,
285{
286 type Arg = UncallFn<F, R>;
287}
288
289
290////////////////////////////////////////////////////////////////////////////////
291
292impl<F, T: ?Sized> TypeFn<T> for PhantomData<F>
293where
294 F: TypeFn<T>
295{
296 type Output = CallFn<F, T>;
297}
298
299impl<F, R: ?Sized> RevTypeFn<R> for PhantomData<F>
300where
301 F: RevTypeFn<R>,
302{
303 type Arg = UncallFn<F, R>;
304}
305
306
307
308////////////////////////////////////////////////////////////////////////////////
309
310
311mod uses_const_marker {
312 use crate::const_marker::Usize;
313
314 /// TypeFn from `(T, Usize<N>)` to `[T; N]`
315 pub(crate) struct PairToArrayFn;
316
317 super::simple_inj_type_fn!{
318 impl[T, const N: usize] ((T, Usize<N>) => [T; N]) for PairToArrayFn
319 }
320}
321
322pub(crate) use uses_const_marker::*;
323
324
325
326// This type alias makes it so that docs for newer Rust versions don't
327// show `Invoke<F>`, keeping the method bounds the same as in 1.0.0.
328#[cfg(not(feature = "rust_1_61"))]
329pub(crate) type InvokeAlias<F> = Invoke<F>;
330
331#[cfg(feature = "rust_1_61")]
332pub(crate) type InvokeAlias<F> = F;