Struct TypeNe

Source
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>

Source

pub const unsafe fn new_unchecked() -> TypeNe<L, R>

Constructs a TypeNe<L, R>.

§Safety

You must ensure that L != R.

Source§

impl TypeNe<(), ()>

Source

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>

Source

pub fn with_any() -> Option<Self>
where L: Sized + Any, R: Sized + Any,

👎Deprecated: fallout of 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());
 
Source

pub const fn to_cmp(self) -> TypeCmp<L, R>

Converts this TypeNe into a TypeCmp

§Example
use typewit::{TypeCmp, TypeNe, type_ne};
 
const NE: TypeNe<u8, i8> = type_ne!(u8, i8);
const TC: TypeCmp<u8, i8> = NE.to_cmp();
 
assert!(matches!(TC, TypeCmp::Ne(_)));
Source

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();
 
Source

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);
}
Source

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>

§Why InjTypeFn

Both map and project require that the function is injective so that TypeNe’s arguments stay unequal.

pub const fn map<F>( self: TypeNe<L, R>, _func: F, ) -> TypeNe<CallInjFn<Invoke<F>, L>, CallInjFn<Invoke<F>, R>>
where Invoke<F>: InjTypeFn<L> + InjTypeFn<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>>
where Invoke<F>: InjTypeFn<L> + InjTypeFn<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>>
where Invoke<F>: RevTypeFn<L> + RevTypeFn<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>>
where Invoke<F>: RevTypeFn<L> + RevTypeFn<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>
where Invoke<F>: TypeFn<LA, Output = L> + TypeFn<RA, Output = R>,

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>
where Invoke<F>: TypeFn<LA, Output = L> + TypeFn<RA, Output = R>,

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>

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>

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
}

Trait Implementations§

Source§

impl<L: ?Sized, R: ?Sized> Clone for TypeNe<L, R>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<L: ?Sized, R: ?Sized> Debug for TypeNe<L, R>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<L: ?Sized, R: ?Sized> Hash for TypeNe<L, R>

Source§

fn hash<H>(&self, _state: &mut H)
where H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<L: ?Sized, R: ?Sized> Ord for TypeNe<L, R>

Source§

fn cmp(&self, _: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<L: ?Sized, R: ?Sized> PartialEq for TypeNe<L, R>

Source§

fn eq(&self, _: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<L: ?Sized, R: ?Sized> PartialOrd for TypeNe<L, R>

Source§

fn partial_cmp(&self, _: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<L: ?Sized, R: ?Sized> Copy for TypeNe<L, R>

Source§

impl<L: ?Sized, R: ?Sized> Eq for TypeNe<L, R>

Auto Trait Implementations§

§

impl<L, R> Freeze for TypeNe<L, R>
where L: ?Sized, R: ?Sized,

§

impl<L, R> RefUnwindSafe for TypeNe<L, R>
where L: ?Sized, R: ?Sized,

§

impl<L, R> Send for TypeNe<L, R>
where L: ?Sized, R: ?Sized,

§

impl<L, R> Sync for TypeNe<L, R>
where L: ?Sized, R: ?Sized,

§

impl<L, R> Unpin for TypeNe<L, R>
where L: ?Sized, R: ?Sized,

§

impl<L, R> UnwindSafe for TypeNe<L, R>
where L: ?Sized, R: ?Sized,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = const WITNESS: W = W::MAKE;

A constant of the type witness
Source§

impl<T> Identity for T
where T: ?Sized,

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = const TYPE_EQ: TypeEq<Self, Self::Type> = TypeEq::NEW;

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.