same_as/lib.rs
1//! Type equality in stable Rust.
2//! # Use
3//! A toy example that demonstrates the basics:
4//! ```rust
5//! use same_as::SameAs;
6//! trait Eat<T> { fn eat<U: SameAs<T>>(_: U); } // Please don't actually write this
7//! struct MrCreosote;
8//! impl Eat<u8> for MrCreosote { fn eat<U: SameAs<u8>>(_: U) {} }
9//! MrCreosote::eat(0_u8); // wafer-thin type
10//! ```
11//! This won't compile:
12//! ```compile_fail
13//! // ...
14//! # use same_as::SameAs;
15//! # trait Eat<T> { fn eat<U: SameAs<T>>(_: U); }
16//! struct MrCreosote;
17//! impl Eat<u8> for MrCreosote { fn eat<U: SameAs<u8>>(_: U) {} }
18//! MrCreosote::eat(0_u16); // kaboom
19//! ```
20//! # But why is type equality necessary?
21//! Sometimes you need it where Rust can't leverage it now, e.g. defining a Haskell-style monad in Rust:
22//! ```rust
23//! # use same_as::SameAs;
24//! pub trait Monad<A>: SameAs<Self::Constructor<A>> { // <-- Enforces that e.g. for `Maybe<A>`, `Self::Constructor` is effectively just the type constructor `Maybe`.
25//! type Constructor<B>: Monad<B>; // In this `impl`, `Self` is really `Self<A>`, but we want to make `Self<B>` below.
26//! fn bind<B, F: Fn(A) -> B>(self, f: F) -> Self::Constructor<B>;
27//! }
28//! ```
29//! So this would work:
30//! ```rust
31//! # use same_as::SameAs;
32//! # pub trait Monad<A>: SameAs<Self::Constructor<A>> { type Constructor<B>; }
33//! pub enum Maybe<A> { Nothing, Just(A) }
34//! impl<A> Monad<A> for Maybe<A> { type Constructor<B> = Maybe<B>; }
35//! ```
36//! but we can prove that this won't, and so we can safely simulate type constructors in Rust:
37//! ```compile_fail
38//! # use same_as::SameAs;
39//! # pub trait Monad<A>: SameAs<Self::Constructor<A>> { type Constructor<B>; }
40//! pub enum Maybe<A> { Nothing, Just(A) } // deception! vvvvvv
41//! impl<A> Monad<A> for Maybe<A> { type Constructor<B> = Option<B>; }
42//! ```
43
44#![no_std]
45#![deny(warnings)]
46#![warn(
47 clippy::all,
48 clippy::missing_docs_in_private_items,
49 clippy::nursery,
50 clippy::pedantic,
51 clippy::restriction,
52 clippy::cargo,
53 missing_docs,
54 rustdoc::all
55)]
56#![allow(clippy::blanket_clippy_restriction_lints)]
57
58/// Sealed trait so end-users can't override the one implementation.
59mod sealed {
60 /// Type equality.
61 pub trait SameAs<T> {}
62 impl<T> SameAs<T> for T {}
63}
64
65/// Type equality.
66pub trait SameAs<T>: sealed::SameAs<T> {}
67impl<T> SameAs<T> for T {}