pub struct TypeNe<L: ?Sized, R: ?Sized>(/* private fields */);
Expand description
Value-level proof that L
is a different type to R
The opposite of TypeEq
.
§Example
use typewit::{const_marker::Usize, TypeNe};
assert_eq!(
array_ref_chunks(&[3, 5, 8, 13, 21, 34, 55], AssertNotZero::V),
Chunks {chunks: vec![&[3, 5, 8], &[13, 21, 34]], tail: &[55]}
);
fn array_ref_chunks<T, const LEN: usize>(
slice: &[T],
_not_zero: TypeNe<Usize<LEN>, Usize<0>>,
) -> Chunks<'_, T, LEN> {
let mut chunks = slice.chunks_exact(LEN);
Chunks {
chunks: chunks.by_ref().map(|c| <&[T; LEN]>::try_from(c).unwrap()).collect(),
tail: chunks.remainder(),
}
}
#[derive(Debug, PartialEq, Eq)]
struct Chunks<'a, T, const LEN: usize> {
chunks: Vec<&'a [T; LEN]>,
tail: &'a [T],
}
struct AssertNotZero<const N: usize>;
impl<const N: usize> AssertNotZero<N> {
const V: TypeNe<Usize<N>, Usize<0>> = Usize::<N>.equals(Usize::<0>).unwrap_ne();
}
If you attempt to pass 0
as the length of the array chunks,
you’ll get this compile-time error:
error[E0080]: evaluation of `main::_doctest_main_src_type_ne_rs_41_0::AssertNotZero::<0>::V` failed
--> src/type_ne.rs:71:43
|
33 | const V: TypeNe<Usize<N>, Usize<0>> = Usize::<N>.equals(Usize::<0>).unwrap_ne();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'called `TypeCmp::unwrap_ne` on a `TypeEq` value', src/type_ne.rs:33:73
error[E0080]: erroneous constant used
--> src/type_ne.rs:45:50
|
7 | array_ref_chunks(&[3, 5, 8, 13, 21, 34, 55], AssertNotZero::<0>::V),
| ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
Implementations§
Source§impl<L: ?Sized, R: ?Sized> TypeNe<L, R>
impl<L: ?Sized, R: ?Sized> TypeNe<L, R>
Sourcepub const unsafe fn new_unchecked() -> TypeNe<L, R>
pub const unsafe fn new_unchecked() -> TypeNe<L, R>
Source§impl TypeNe<(), ()>
impl TypeNe<(), ()>
Sourcepub const fn with_fn<F>(
_func: F,
) -> TypeNe<CallInjFn<Invoke<F>, LeftArg>, CallInjFn<Invoke<F>, RightArg>>
pub const fn with_fn<F>( _func: F, ) -> TypeNe<CallInjFn<Invoke<F>, LeftArg>, CallInjFn<Invoke<F>, RightArg>>
Constructs a TypeNe
by mapping from a
TypeNe<
LeftArg
,
RightArg
>
with an injective type-level function.
§Alternative
The type_ne
macro can be used as syntactic sugar
for calling this constructor with a one-off type-level function.
§Example
use typewit::type_ne::{TypeNe, LeftArg, RightArg};
const NE: TypeNe<Option<String>, Vec<u16>> = TypeNe::with_fn(MakeNe::NEW);
typewit::inj_type_fn! {
struct MakeNe<T, U>;
impl LeftArg => Option<T>;
impl RightArg => Vec<U>;
}
Source§impl<L: ?Sized, R: ?Sized> TypeNe<L, R>
impl<L: ?Sized, R: ?Sized> TypeNe<L, R>
Sourcepub fn with_any() -> Option<Self>
👎Deprecated: fallout of https://github.com/rust-lang/rust/issues/97156
,TypeId::of::<L>() != TypeId::of::<R>()
does not imply L != R
pub fn with_any() -> Option<Self>
https://github.com/rust-lang/rust/issues/97156
,TypeId::of::<L>() != TypeId::of::<R>()
does not imply L != R
Constructs TypeNe<L, R>
if L != R
, otherwise returns None.
§Example
use typewit::TypeNe;
let _ne: TypeNe<u8, i8> = TypeNe::with_any().unwrap();
assert!(TypeNe::<u8, u8>::with_any().is_none());
Sourcepub const fn flip(self: TypeNe<L, R>) -> TypeNe<R, L>
pub const fn flip(self: TypeNe<L, R>) -> TypeNe<R, L>
Swaps the type arguments of this TypeNe
§Example
use typewit::{TypeNe, type_ne};
const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
const N3: TypeNe<i8, u8> = NE.flip();
Sourcepub const fn join_left<J: ?Sized>(
self: TypeNe<L, R>,
_eq: TypeEq<J, L>,
) -> TypeNe<J, R>
pub const fn join_left<J: ?Sized>( self: TypeNe<L, R>, _eq: TypeEq<J, L>, ) -> TypeNe<J, R>
Joins a proof of L != R
with a proof of J == L
,
creating a proof of J != R
.
§Example
use typewit::{TypeEq, TypeNe, type_ne};
const NE: TypeNe<str, [u8]> = type_ne!(str, [u8]);
const fn foo<A: ?Sized>(eq: TypeEq<A, str>) {
let _ne: TypeNe<A, [u8]> = NE.join_left(eq);
}
Sourcepub const fn join_right<J: ?Sized>(
self: TypeNe<L, R>,
_eq: TypeEq<R, J>,
) -> TypeNe<L, J>
pub const fn join_right<J: ?Sized>( self: TypeNe<L, R>, _eq: TypeEq<R, J>, ) -> TypeNe<L, J>
Joins a proof of L != R
with a proof of R == J
,
creating a proof of L != J
.
§Example
use typewit::{TypeEq, TypeNe, type_ne};
const NE: TypeNe<String, Vec<u8>> = type_ne!(String, Vec<u8>);
const fn foo<A>(eq: TypeEq<Vec<u8>, A>) {
let _ne: TypeNe<String, A> = NE.join_right(eq);
}
§impl<L: ?Sized, R: ?Sized> TypeNe<L, R>
impl<L: ?Sized, R: ?Sized> TypeNe<L, R>
pub const fn map<F>(
self: TypeNe<L, R>,
_func: F,
) -> TypeNe<CallInjFn<Invoke<F>, L>, CallInjFn<Invoke<F>, R>>
pub const fn map<F>( self: TypeNe<L, R>, _func: F, ) -> TypeNe<CallInjFn<Invoke<F>, L>, CallInjFn<Invoke<F>, R>>
Maps the type arguments of this TypeNe
by using the F
injective type-level function.
Use this function over project
if you want the type of the passed in function to be inferred.
§Example
use typewit::{TypeNe, inj_type_fn, type_ne};
const NE: TypeNe<u8, u16> = type_ne!(u8, u16);
const N3: TypeNe<[u8; 0], [u16; 0]> = NE.map(ArrayFn::NEW);
inj_type_fn!{
struct ArrayFn<const LEN: usize>;
impl<T> T => [T; LEN]
}
pub const fn project<F>(
self: TypeNe<L, R>,
) -> TypeNe<CallInjFn<Invoke<F>, L>, CallInjFn<Invoke<F>, R>>
pub const fn project<F>( self: TypeNe<L, R>, ) -> TypeNe<CallInjFn<Invoke<F>, L>, CallInjFn<Invoke<F>, R>>
Maps the type arguments of this TypeNe
by using the F
injective type-level function.
Use this function over map
if you want to specify the type of the passed in function explicitly.
§Example
use typewit::{TypeNe, inj_type_fn, type_ne};
const NE: TypeNe<u8, u16> = type_ne!(u8, u16);
const N3: TypeNe<Vec<u8>, Vec<u16>> = NE.project::<VecFn>();
inj_type_fn!{
struct VecFn;
impl<T> T => Vec<T>
}
pub const fn unmap<F>(
self,
func: F,
) -> TypeNe<UncallFn<Invoke<F>, L>, UncallFn<Invoke<F>, R>>
pub const fn unmap<F>( self, func: F, ) -> TypeNe<UncallFn<Invoke<F>, L>, UncallFn<Invoke<F>, R>>
Maps the type arguments of this TypeNe
by using the reversed
version of the F
type-level function.
Use this function over unproject
if you want the type of the passed in function to be inferred.
§Example
use typewit::{TypeNe, inj_type_fn, type_ne};
use std::cmp::Ordering as CmpOrdering;
use std::sync::atomic::Ordering as MemOrdering;
const NE: TypeNe<[CmpOrdering], [MemOrdering]> = type_ne!([CmpOrdering], [MemOrdering]);
const N3: TypeNe<CmpOrdering, MemOrdering> = NE.unmap(SliceFn);
inj_type_fn!{
struct SliceFn;
impl<T> T => [T]
}
pub const fn unproject<F>(
self,
) -> TypeNe<UncallFn<Invoke<F>, L>, UncallFn<Invoke<F>, R>>
pub const fn unproject<F>( self, ) -> TypeNe<UncallFn<Invoke<F>, L>, UncallFn<Invoke<F>, R>>
Maps the type arguments of this TypeNe
by using the reversed
version of the F
type-level function.
Use this function over unmap
if you want to specify the type of the passed in function explicitly.
§Example
use typewit::{TypeNe, inj_type_fn, type_ne};
const NE: TypeNe<Option<()>, Option<bool>> = type_ne!(Option<()>, Option<bool>);
const N3: TypeNe<(), bool> = NE.unproject::<OptionFn>();
inj_type_fn!{
struct OptionFn;
impl<T> T => Option<T>
}
pub const fn map_to_arg<F, LA, RA>(
self: TypeNe<L, R>,
func: F,
) -> TypeNe<LA, RA>
pub const fn map_to_arg<F, LA, RA>( self: TypeNe<L, R>, func: F, ) -> TypeNe<LA, RA>
Maps the L
and R
arguments of this TypeNe<L, R>
back to any argument of the F
type-level function that would produce them.
Use this function over project_to_arg
if you want the type of the passed in function to be inferred.
This operation is possible because Call<F, LA> != Call<F, RA>
implies LA != RA
,
i.e.: the return values being different implies that the arguments are different.
As opposed to unmap
,
this only requires F
to implement TypeFn
,
and the return type is determined by the caller.
§Example
Projecting from item type to collections
use typewit::TypeNe;
use std::ops::{Range, RangeInclusive};
with_typene(typewit::type_ne!(u8, i8));
const fn with_typene(ne: TypeNe<u8, i8>) {
let _: TypeNe<Vec<u8>, [i8; 1]> = ne.map_to_arg(IntoIterFn);
let _: TypeNe<Option<u8>, Result<i8, ()>> = ne.map_to_arg(IntoIterFn);
let _: TypeNe<Range<u8>, RangeInclusive<i8>> = ne.map_to_arg(IntoIterFn);
}
typewit::type_fn!{
struct IntoIterFn;
impl<I: IntoIterator> I => I::Item
}
pub const fn project_to_arg<F, LA, RA>(self: TypeNe<L, R>) -> TypeNe<LA, RA>
pub const fn project_to_arg<F, LA, RA>(self: TypeNe<L, R>) -> TypeNe<LA, RA>
Maps the L
and R
arguments of this TypeNe<L, R>
back to any argument of the F
type-level function that would produce them.
Use this function over map_to_arg
if you want to specify the type of the passed in function explicitly.
This operation is possible because Call<F, LA> != Call<F, RA>
implies LA != RA
,
i.e.: the return values being different implies that the arguments are different.
As opposed to unproject
,
this only requires F
to implement TypeFn
,
and the return type is determined by the caller.
§Example
Projecting from types to smart pointers that point to them.
use typewit::TypeNe;
use std::sync::Arc;
with_typene(typewit::type_ne!(str, [u8]));
const fn with_typene(ne: TypeNe<str, [u8]>) {
let _: TypeNe<&str, &[u8]> = ne.project_to_arg::<TargetFn, _, _>();
let _: TypeNe<Arc<str>, Box<[u8]>> = ne.project_to_arg::<TargetFn, _, _>();
let _: TypeNe<String, Vec<u8>> = ne.project_to_arg::<TargetFn, _, _>();
}
typewit::type_fn!{
struct TargetFn;
impl<I: std::ops::Deref> I => I::Target
}
pub const fn in_ref<'a>(self) -> TypeNe<&'a L, &'a R>
pub const fn in_ref<'a>(self) -> TypeNe<&'a L, &'a R>
Converts a TypeNe<L, R>
to TypeNe<&L, &R>
§Example
use typewit::{TypeNe, inj_type_fn, type_ne};
const NE: TypeNe<i32, u32> = type_ne!(i32, u32);
let foo: i32 = 3;
let bar: u32 = 5;
baz(&foo, &bar, NE.in_ref());
const fn baz<'a, T, U>(foo: &'a T, bar: &'a U, _ne: TypeNe<&'a T, &'a U>) {
// stuff
}
pub fn in_mut<'a>(self) -> TypeNe<&'a mut L, &'a mut R>
pub fn in_mut<'a>(self) -> TypeNe<&'a mut L, &'a mut R>
Converts a TypeNe<L, R>
to TypeNe<&mut L, &mut R>
§Constness
This requires the "rust_1_83"
feature to be a const fn
.
§Example
use typewit::{TypeNe, inj_type_fn, type_ne};
const NE: TypeNe<String, Vec<u8>> = type_ne!(String, Vec<u8>);
let mut foo: String = "hello".to_string();
let mut bar: Vec<u8> = vec![3, 5, 8];
baz(&mut foo, &mut bar, NE.in_mut());
fn baz<'a, T, U>(foo: &'a mut T, bar: &'a mut U, _ne: TypeNe<&'a mut T, &'a mut U>) {
// stuff
}