typewit/type_ne_.rs
1use core::{
2 any::{Any, TypeId},
3 cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd},
4 hash::{Hash, Hasher},
5 fmt::{self, Debug},
6};
7
8use crate::TypeEq;
9
10#[cfg(feature = "rust_1_61")]
11use crate::{BaseTypeWitness, SomeTypeArgIsNe};
12
13
14/// Marker type, for constructing `TypeNe` in [`TypeNe::with_fn`] constructor.
15pub enum LeftArg {}
16
17/// Marker type, for constructing `TypeNe` in [`TypeNe::with_fn`] constructor.
18pub enum RightArg {}
19
20
21
22pub use self::type_ne_::TypeNe;
23
24mod type_ne_ {
25 use core::marker::PhantomData;
26
27 /// Value-level proof that `L` is a different type to `R`
28 ///
29 /// The opposite of [`TypeEq`](crate::TypeEq).
30 ///
31 /// # Example
32 ///
33 /// ```rust
34 /// use typewit::{const_marker::Usize, TypeNe};
35 ///
36 /// assert_eq!(
37 /// array_ref_chunks(&[3, 5, 8, 13, 21, 34, 55], AssertNotZero::V),
38 /// Chunks {chunks: vec![&[3, 5, 8], &[13, 21, 34]], tail: &[55]}
39 /// );
40 ///
41 ///
42 /// fn array_ref_chunks<T, const LEN: usize>(
43 /// slice: &[T],
44 /// _not_zero: TypeNe<Usize<LEN>, Usize<0>>,
45 /// ) -> Chunks<'_, T, LEN> {
46 /// let mut chunks = slice.chunks_exact(LEN);
47 ///
48 /// Chunks {
49 /// chunks: chunks.by_ref().map(|c| <&[T; LEN]>::try_from(c).unwrap()).collect(),
50 /// tail: chunks.remainder(),
51 /// }
52 /// }
53 ///
54 /// #[derive(Debug, PartialEq, Eq)]
55 /// struct Chunks<'a, T, const LEN: usize> {
56 /// chunks: Vec<&'a [T; LEN]>,
57 /// tail: &'a [T],
58 /// }
59 ///
60 /// struct AssertNotZero<const N: usize>;
61 ///
62 /// impl<const N: usize> AssertNotZero<N> {
63 /// const V: TypeNe<Usize<N>, Usize<0>> = Usize::<N>.equals(Usize::<0>).unwrap_ne();
64 /// }
65 ///
66 /// ```
67 ///
68 /// If you attempt to pass `0` as the length of the array chunks,
69 /// you'll get this compile-time error:
70 /// ```text
71 /// error[E0080]: evaluation of `main::_doctest_main_src_type_ne_rs_41_0::AssertNotZero::<0>::V` failed
72 /// --> src/type_ne.rs:71:43
73 /// |
74 /// 33 | const V: TypeNe<Usize<N>, Usize<0>> = Usize::<N>.equals(Usize::<0>).unwrap_ne();
75 /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'called `TypeCmp::unwrap_ne` on a `TypeEq` value', src/type_ne.rs:33:73
76 ///
77 /// error[E0080]: erroneous constant used
78 /// --> src/type_ne.rs:45:50
79 /// |
80 /// 7 | array_ref_chunks(&[3, 5, 8, 13, 21, 34, 55], AssertNotZero::<0>::V),
81 /// | ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
82 ///
83 /// ```
84 pub struct TypeNe<L: ?Sized, R: ?Sized>(PhantomData<TypeNeHelper<L, R>>);
85
86 // Declared to work around this error in old Rust versions:
87 // > error[E0658]: function pointers cannot appear in constant functions
88 struct TypeNeHelper<L: ?Sized, R: ?Sized>(
89 #[allow(dead_code)]
90 fn(PhantomData<L>) -> PhantomData<L>,
91 #[allow(dead_code)]
92 fn(PhantomData<R>) -> PhantomData<R>,
93 );
94
95 impl<L: ?Sized, R: ?Sized> TypeNe<L, R> {
96 /// Constructs a `TypeNe<L, R>`.
97 ///
98 /// # Safety
99 ///
100 /// You must ensure that `L != R`.
101 ///
102 #[inline(always)]
103 pub const unsafe fn new_unchecked() -> TypeNe<L, R> {
104 TypeNe(PhantomData)
105 }
106 }
107
108
109}
110
111impl TypeNe<(), ()> {
112 /// Constructs a `TypeNe` by mapping from a
113 /// `TypeNe<`[`LeftArg`]`, `[`RightArg`]`>`
114 /// with an [injective type-level function](crate::InjTypeFn).
115 ///
116 /// # Alternative
117 ///
118 /// The [`type_ne`](macro@crate::type_ne) macro can be used as syntactic sugar
119 /// for calling this constructor with a one-off type-level function.
120 ///
121 /// # Example
122 ///
123 /// ```rust
124 /// use typewit::type_ne::{TypeNe, LeftArg, RightArg};
125 ///
126 /// const NE: TypeNe<Option<String>, Vec<u16>> = TypeNe::with_fn(MakeNe::NEW);
127 ///
128 /// typewit::inj_type_fn! {
129 /// struct MakeNe<T, U>;
130 ///
131 /// impl LeftArg => Option<T>;
132 /// impl RightArg => Vec<U>;
133 /// }
134 /// ```
135 pub const fn with_fn<F>(
136 _func: F,
137 ) -> TypeNe<CallInjFn<InvokeAlias<F>, LeftArg>, CallInjFn<InvokeAlias<F>, RightArg>>
138 where
139 InvokeAlias<F>: InjTypeFn<LeftArg> + InjTypeFn<RightArg>
140 {
141 core::mem::forget(_func);
142
143 // SAFETY: LeftArg isn't RightArg, dummy.
144 let this: TypeNe<LeftArg, RightArg> = unsafe { TypeNe::new_unchecked() };
145
146 projected_type_cmp!{this, LeftArg, RightArg, InvokeAlias<F>}
147 }
148}
149
150
151impl<L: ?Sized, R: ?Sized> TypeNe<L, R> {
152 /// Constructs `TypeNe<L, R>` if `L != R`, otherwise returns None.
153 ///
154 /// # Example
155 ///
156 /// ```rust
157 /// use typewit::TypeNe;
158 ///
159 ///
160 /// let _ne: TypeNe<u8, i8> = TypeNe::with_any().unwrap();
161 ///
162 /// assert!(TypeNe::<u8, u8>::with_any().is_none());
163 ///
164 /// ```
165 #[deprecated = concat!(
166 "fallout of `https://github.com/rust-lang/rust/issues/97156`,",
167 "`TypeId::of::<L>() != TypeId::of::<R>()` does not imply `L != R`"
168 )]
169 pub fn with_any() -> Option<Self>
170 where
171 L: Sized + Any,
172 R: Sized + Any,
173 {
174 if TypeId::of::<L>() != TypeId::of::<R>() {
175 // SAFETY: unsound for the deprecated reason
176 unsafe { Some(TypeNe::new_unchecked()) }
177 } else {
178 None
179 }
180 }
181
182 /// Converts this `TypeNe` into a [`TypeCmp`](crate::TypeCmp)
183 ///
184 /// # Example
185 ///
186 /// ```rust
187 /// use typewit::{TypeCmp, TypeNe, type_ne};
188 ///
189 /// const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
190 /// const TC: TypeCmp<u8, i8> = NE.to_cmp();
191 ///
192 /// assert!(matches!(TC, TypeCmp::Ne(_)));
193 /// ```
194 #[inline(always)]
195 pub const fn to_cmp(self) -> crate::TypeCmp<L, R> {
196 crate::TypeCmp::Ne(self)
197 }
198
199 /// Swaps the type arguments of this `TypeNe`
200 ///
201 /// # Example
202 ///
203 /// ```rust
204 /// use typewit::{TypeNe, type_ne};
205 ///
206 /// const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
207 ///
208 /// const N3: TypeNe<i8, u8> = NE.flip();
209 ///
210 /// ```
211 pub const fn flip(self: TypeNe<L, R>) -> TypeNe<R, L> {
212 // SAFETY: type inequality is commutative
213 unsafe { TypeNe::<R, L>::new_unchecked() }
214 }
215
216 /// Joins a proof of `L != R` with a proof of `J == L`,
217 /// creating a proof of `J != R`.
218 ///
219 /// # Example
220 ///
221 /// ```rust
222 /// use typewit::{TypeEq, TypeNe, type_ne};
223 ///
224 /// const NE: TypeNe<str, [u8]> = type_ne!(str, [u8]);
225 ///
226 /// const fn foo<A: ?Sized>(eq: TypeEq<A, str>) {
227 /// let _ne: TypeNe<A, [u8]> = NE.join_left(eq);
228 /// }
229 /// ```
230 pub const fn join_left<J: ?Sized>(self: TypeNe<L, R>, _eq: TypeEq<J, L>) -> TypeNe<J, R> {
231 // SAFETY: (L != R, J == L) implies J != R
232 unsafe { TypeNe::<J, R>::new_unchecked() }
233 }
234
235 /// Joins a proof of `L != R` with a proof of `R == J`,
236 /// creating a proof of `L != J`.
237 ///
238 /// # Example
239 ///
240 /// ```rust
241 /// use typewit::{TypeEq, TypeNe, type_ne};
242 ///
243 /// const NE: TypeNe<String, Vec<u8>> = type_ne!(String, Vec<u8>);
244 ///
245 /// const fn foo<A>(eq: TypeEq<Vec<u8>, A>) {
246 /// let _ne: TypeNe<String, A> = NE.join_right(eq);
247 /// }
248 /// ```
249 pub const fn join_right<J: ?Sized>(self: TypeNe<L, R>, _eq: TypeEq<R, J>) -> TypeNe<L, J> {
250 // SAFETY: (L != R, R == J) implies L != J
251 unsafe { TypeNe::<L, J>::new_unchecked() }
252 }
253}
254
255#[cfg(feature = "rust_1_61")]
256#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))]
257impl<L, R> TypeNe<L, R> {
258 /// Combines this `TypeNe<L, R>` with an
259 /// [`A: BaseTypeWitness`](BaseTypeWitness) to produce a
260 /// `TypeNe<(L, A::L), (R, A::R)>`.
261 ///
262 /// # Example
263 ///
264 /// ```rust
265 /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
266 ///
267 /// const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
268 /// const EQ: TypeEq<u16, u16> = TypeEq::NEW;
269 /// const TC: TypeCmp<u32, u64> = TypeCmp::Ne(type_ne!(u32, u64));
270 ///
271 /// let _: TypeNe<(u8, i8), (i8, u8)> = NE.zip(NE.flip());
272 /// let _: TypeNe<(u8, u16), (i8, u16)> = NE.zip(EQ);
273 /// let _: TypeNe<(u8, u32), (i8, u64)> = NE.zip(TC);
274 ///
275 /// ```
276 pub const fn zip<A>(
277 self: TypeNe<L, R>,
278 other: A,
279 ) -> TypeNe<(L, A::L), (R, A::R)>
280 where
281 A: BaseTypeWitness,
282 {
283 SomeTypeArgIsNe::A(TypeEq::NEW).zip2(self, other)
284 }
285
286 /// Combines this `TypeNe<L, R>` with
287 /// two [`BaseTypeWitness`](BaseTypeWitness)es to produce a
288 /// `TypeNe<(L, A::L, B::L), (R, A::R, B::R)>`.
289 ///
290 /// # Example
291 ///
292 /// ```rust
293 /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
294 ///
295 /// const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
296 /// const EQ: TypeEq<u16, u16> = TypeEq::NEW;
297 /// const TC: TypeCmp<u32, u64> = TypeCmp::Ne(type_ne!(u32, u64));
298 ///
299 /// let _: TypeNe<(u8, i8, u8), (i8, u8, i8)> = NE.zip3(NE.flip(), NE);
300 /// let _: TypeNe<(u8, u16, u16), (i8, u16, u16)> = NE.zip3(EQ, EQ.flip());
301 /// let _: TypeNe<(u8, u32, u64), (i8, u64, u32)> = NE.zip3(TC, TC.flip());
302 ///
303 /// ```
304 pub const fn zip3<A, B>(
305 self: TypeNe<L, R>,
306 other1: A,
307 other2: B,
308 ) -> TypeNe<(L, A::L, B::L), (R, A::R, B::R)>
309 where
310 A: BaseTypeWitness,
311 B: BaseTypeWitness,
312 A::L: Sized,
313 A::R: Sized,
314 {
315 SomeTypeArgIsNe::A(TypeEq::NEW).zip3(self, other1, other2)
316 }
317
318 /// Combines this `TypeNe<L, R>` with
319 /// three [`BaseTypeWitness`](BaseTypeWitness)es to produce a
320 /// `TypeNe<(L, A::L, B::L, C::L), (R, A::R, B::R, C::R)> `.
321 ///
322 /// # Example
323 ///
324 /// ```rust
325 /// use typewit::{TypeCmp, TypeEq, TypeNe, type_ne};
326 ///
327 /// const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
328 /// const EQ: TypeEq<u16, u16> = TypeEq::NEW;
329 /// const TC: TypeCmp<u32, u64> = TypeCmp::Ne(type_ne!(u32, u64));
330 ///
331 /// let _: TypeNe<(u8, i8, u8, i8), (i8, u8, i8, u8)> = NE.zip4(NE.flip(), NE, NE.flip());
332 /// let _: TypeNe<(u8, u16, u16, u16), (i8, u16, u16, u16)> = NE.zip4(EQ, EQ.flip(), EQ);
333 /// let _: TypeNe<(u8, u32, u64, u32), (i8, u64, u32, u64)> = NE.zip4(TC, TC.flip(), TC);
334 ///
335 /// ```
336 pub const fn zip4<A, B, C>(
337 self: TypeNe<L, R>,
338 other1: A,
339 other2: B,
340 other3: C,
341 ) -> TypeNe<(L, A::L, B::L, C::L), (R, A::R, B::R, C::R)>
342 where
343 A: BaseTypeWitness,
344 B: BaseTypeWitness,
345 C: BaseTypeWitness,
346 A::L: Sized,
347 A::R: Sized,
348 B::L: Sized,
349 B::R: Sized,
350 {
351 SomeTypeArgIsNe::A(TypeEq::NEW).zip4(self, other1, other2, other3)
352 }
353}
354
355
356
357// using this instead of `mod extra_type_ne_methods;`
358// to document the impls in the submodule below the constructors.
359include!{"./type_ne/extra_type_ne_methods.rs"}
360
361
362
363impl<L: ?Sized, R: ?Sized> Copy for TypeNe<L, R> {}
364
365impl<L: ?Sized, R: ?Sized> Clone for TypeNe<L, R> {
366 fn clone(&self) -> Self {
367 *self
368 }
369}
370
371impl<L: ?Sized, R: ?Sized> Debug for TypeNe<L, R> {
372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
373 f.write_str("TypeNe")
374 }
375}
376
377impl<L: ?Sized, R: ?Sized> PartialEq for TypeNe<L, R> {
378 fn eq(&self, _: &Self) -> bool {
379 true
380 }
381}
382
383impl<L: ?Sized, R: ?Sized> PartialOrd for TypeNe<L, R> {
384 fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
385 Some(Ordering::Equal)
386 }
387}
388
389impl<L: ?Sized, R: ?Sized> Ord for TypeNe<L, R> {
390 fn cmp(&self, _: &Self) -> Ordering {
391 Ordering::Equal
392 }
393}
394
395impl<L: ?Sized, R: ?Sized> Eq for TypeNe<L, R> {}
396
397impl<L: ?Sized, R: ?Sized> Hash for TypeNe<L, R> {
398 fn hash<H>(&self, _state: &mut H)
399 where H: Hasher
400 {}
401}
402
403
404