#equality #type #meta-programming #type-level #inequality

nightly spidermeme

Traits to test for type equality and type inequality

1 unstable release

0.1.0 May 13, 2021

#1698 in Rust patterns

MIT/Apache

18KB

WARNING: This crate currently depends on nightly rust unstable features.

spidermeme

Rust traits to check for type equality and type inequality.
Useful as a building block for more complicated compile-time constraints.

docs.rs ci Coverage


 ______________________________________________________________________________
|_________________________ _______      |    |                              ___|
| ______________   ___    |  ___  |     |    |             ___           .-` | |
||                /   \   | |   | |     |    |            /   \         | _..| |
||                | o o   | |   | |     |    |            o   |         ||  || |
||  N  Y  P  D    \   / __  |___| |     |    |         __ \   / __      ||  || |
||             ..-'   ''  \    o--|     |    |        |  |______  \     ||  || |
||____________ |   \______\_____  |     |    |       .'  |      \  \    ||  || |
|_____________ |---__________/    |     |  _______.-' _.-/      \  |    ||  || |
|              \         | \____  |     |    \_____.-' \        /\ |    ||_ || |
|               \       / \____|  |     |               \       /| | ___|  ''| |
|                \     /          |     |    |           \      /__/ --..'--.| |
|       _____     =====   |_______|     |    |            ======\   ..   `-----|
|      /     \   /     \  |____________ |    |           /       \  | ''| |   _|
|     /  ___  \  /  _   \ |             |____|_________ /         | |   | |  | |
|    |  |   |   /  / \   \                             /    //   /  |   | |  | |
|___ |  |___|  /  / __ \  \                           /   / /   / | '-. | |  | |
|     \       /_/        \_\                         /  /'  /  /   `-. '' |  |_|
|      \____ / /          \ \                       |  /    \  \      `-. |    |
|            //           \ \__                     \__\     \__\        `-----|
|           /|             \___\                     \  |     \ \              |
|          /_|                                       \ /      \ /              |
|____________________________________________________\_/______|_|______________|

Provided traits

spidermeme::SameTypeAs<T>

An automatically implemented marker trait to check if two types are equal.

spidermeme::NotSameTypeAs<T>

An automatically implemented marker trait to check if two types aren't equal.

Examples

use spidermeme::{SameTypeAs, NotSameTypeAs};

struct MyPair<T1, T2>(T1, T2);

trait ProcessPair {
    fn process(&self);
}

impl<T1, T2> ProcessPair for MyPair<T1, T2> {
    fn process(&self) {
        println!("Pair of two different types.");
    }
}

impl<T1, T2> MyPair<T1, T2>
where
    T1: SameTypeAs<T2>,
{
    fn process(&self) {
        println!("Pair of same type.");
    }
}

struct UniquePair<T1, T2>
where
    T1: NotSameTypeAs<T2>,
{
    a: T1,
    b: T2,
}

impl<T1, T2> UniquePair<T1, T2>
where
    T1: NotSameTypeAs<T2>,
{
    pub fn new(a: T1, b: T2) -> Self {
        Self { a, b }
    }
}

fn main() {
    // Prints "Pair of same type."
    MyPair(1_i32, 2_i32).process();

    // Prints "Pair of two different types."
    MyPair(1_i32, 2_i16).process();

    // Valid.
    let x = UniquePair::<i32, f64>::new(1, 2.0);

    // The following fails to compile:
    // let y = UniquePair::<i32, i32>::new(1, 2);
}

How type equality works

Type equality is pretty straightforward. The SameTypeAs trait has a blanket implementation using the same generic parameter. The basic principle looks like this when simplified:

pub trait Same<T> {}
impl<T> Same<T> for T {}

This was inspired by numerous comments floating around on the web.

How type inequality works

Type inequality uses negative_impls and auto_traits. A naive implementation would be like the following:

#![feature(negative_impls)]
#![feature(auto_traits)]
pub auto trait DifferentNaive {}
impl<T> !DifferentNaive for (T, T) {}

However, this will give false negatives, as the auto trait will not be implemented for types that contain (T, T). For example, the naive implementation will fail in the following example because ((i32, i32), (f64, f64)) contains (i32, i32) and (f64, f64), both of which implement the DifferentNaive trait:

use static_assertions::assert_impl_all;
assert_impl_all!(((i32, i32), (f64, f64)): DifferentNaive);

This crate works around this by using a private named tuple instead of the primitive tuple, so that it is guaranteed that downstream crates will not test types that contain this named tuple.

Known problems / quirks

  1. Using both SameTypeAs and NotSameTypeAs to implement two impls for the same type will give: error[E0119]: conflicting implementations, probably due to the current limitations of Rust(?).

  2. References to the same type, but with different lifetimes, are treated the same. This could be thought of as a "feature" if you squint hard enough.

  3. For type equality in serious projects, you should probably try some other crates by people who probably know better type theory and rust's type system.

Unstable features

#![feature(negative_impls)]
#![feature(auto_traits)]
#![feature(extended_key_value_attributes)]

No runtime deps