Skip to main content

type_sets/
lib.rs

1//! `type-sets` implements compile-time set operations on tuples.
2//!
3//! A tuple of types is treated as a set: the order doesn't matter, so `(A, B)` and `(B, A)`
4//! are the same set. Sets can have up to 24 members. See [`AsTypeSet`].
5//!
6//! # Basic example
7//! Most operations are traits that you use as bounds:
8//!
9//! ```rust
10//! use type_sets::Contains;
11//!
12//! /// Only accepts messages that are in the set `S`.
13//! fn send<S: Contains<M>, M>(message: M) {
14//!     // ...
15//! }
16//! ```
17//!
18//! With the `assertions` feature, the [`assert`](mod@assert) module checks set relations at
19//! compile time:
20//!
21//! ```rust
22//! # use type_sets::*;
23//! assert::contains::<(i32, i16), i32>();
24//! assert::subset::<(i32,), (i32, i64)>();
25//! assert::superset::<(i32, i16), (i32,)>();
26//! assert::eq::<(i32, i16), (i16, i32)>();
27//! ```
28//!
29//! # Operations
30//! - [`Contains<E>`]: the set contains the type `E`.
31//! - [`Subset<S>`]: every member of the set is also in `S`.
32//! - [`Superset<S>`]: the set contains every member of `S`.
33//! - [`SetEqual<R>`]: the two sets have the same members.
34//! - [`IsEmpty`]: the set has no members.
35//! - [`Insert<T, E>`]: the set `T` with `E` added.
36//! - [`Union<T, R>`]: all members of `T` and `R`.
37//! - [`Members`]: the members of a set as [`TypeId`]s, available at runtime.
38//!
39//! See each trait's documentation for details.
40//!
41//! # Feature flags
42//! - `assertions`: enables the [`assert`](mod@assert) module.
43//!
44//! # Libraries using type-sets
45//! - [zestors](https://github.com/Zestors/zestors): an actor framework with Erlang/OTP-style
46//!   supervision. An actor's interface is a set of message types. Sending a message checks that
47//!   the interface [`Contains`] it, and addresses can be converted into dynamic addresses for
48//!   any [`Subset`] of the interface.
49//! - [axum-error-sets](https://docs.rs/axum-error-sets): typed, composable HTTP error sets
50//!   for axum. Each handler declares the set of status codes it can return, and smaller sets
51//!   convert into any [`Superset`].
52
53use generate_sets::*;
54use std::{any::TypeId, convert::Infallible};
55
56/// Implemented for any set that contains a member `E`.
57///
58/// # Example
59///
60/// ```rust
61/// # use type_sets::*;
62/// assert::contains::<(i32,), i32>();
63/// assert::contains::<(i16, i32), i32>();
64/// assert::contains::<(i32, i16), i32>();
65/// // assert::contains::<(i8, i16), i32>(); // fails to compile
66/// ```
67#[diagnostic::on_unimplemented(
68    message = "`{Self}` does not contain `{E}`",
69    label = "type does not contain this element",
70    note = "a type implements `Contains<E>` when `E` is one of its set members"
71)]
72pub trait Contains<E>: Contains0 {}
73
74#[diagnostic::do_not_recommend]
75impl<E, T: ?Sized> Contains<E> for T where T: Contains1<E> {}
76
77/// Implemented for any set that is a subset of set `S`.
78///
79/// # Example
80///
81/// ```rust
82/// # use type_sets::*;
83/// assert::subset::<(i32,), (i32,)>();
84/// assert::subset::<(i16, i32), (i16, i32)>();
85/// assert::subset::<(i32, i16), (i16, i32)>();
86/// assert::subset::<(i32,), (i32, i16)>();
87/// // assert::subset::<(i8, i16), (i16, i32)>(); // fails to compile
88/// ```
89#[diagnostic::on_unimplemented(
90    message = "`{Self}` is not a subset of `{S}`",
91    label = "this set is not a subset of the required set",
92    note = "every member of the left-hand set must also be present in the right-hand set"
93)]
94pub trait Subset<S: ?Sized> {}
95
96#[diagnostic::do_not_recommend]
97impl<T, R> Subset<R> for T
98where
99    T: AsTypeSet<Set: Subset<R::Set>>,
100    R: AsTypeSet,
101{
102}
103
104/// Implemented for any set that is a superset of set `S`.
105///
106/// # Example
107///
108/// ```rust
109/// # use type_sets::*;
110/// assert::superset::<(i32, i16), (i32,)>();
111/// assert::superset::<(i16, i32), (i32,)>();
112/// assert::superset::<(i32,), (i32,)>();
113/// assert::superset::<(i32, i16), (i16, i32)>();
114/// // assert::superset::<(i8, i16), (i32,)>(); // fails to compile
115/// ```
116#[diagnostic::on_unimplemented(
117    message = "`{Self}` is not a superset of `{S}`",
118    label = "this set does not contain all required members",
119    note = "every member of the right-hand set must also be present in the left-hand set"
120)]
121pub trait Superset<S: ?Sized> {}
122
123#[diagnostic::do_not_recommend]
124impl<S1: ?Sized, S2: ?Sized> Superset<S2> for S1 where S2: Subset<S1> {}
125
126/// The main trait for representing a set of types.
127///
128/// This is implemented for tuples up to 24 elements.
129///
130/// # Examples
131/// - `(A,)`
132/// - `(A, B)`
133/// - `(A, B, C)`
134pub trait AsTypeSet {
135    /// The underlying set type, which is a private marker-trait.
136    type Set: ?Sized;
137}
138
139/// Trait for retrieving the members of a type set as [`TypeId`]s.
140///
141/// # Example
142///
143/// ```rust
144/// # use type_sets::*;
145/// let members = <(i32, i16) as Members>::members();
146///
147/// assert_eq!(members, &[
148///     std::any::TypeId::of::<i32>(),
149///     std::any::TypeId::of::<i16>(),
150/// ]);
151/// ```
152pub trait Members {
153    /// Returns a static slice of [`TypeId`]s representing the members of the set.
154    fn members() -> &'static [TypeId];
155}
156
157impl<T> Members for T
158where
159    T: AsTypeSet<Set: Members>,
160{
161    fn members() -> &'static [TypeId] {
162        <T::Set as Members>::members()
163    }
164}
165
166/// Indicates that two sets are equal, i.e., they contain the same members.
167///
168/// This is the same as `T: Subset<R> + Superset<R>`
169///
170/// # Example
171///
172/// ```rust
173/// # use type_sets::*;
174/// assert::eq::<(i32, i16), (i16, i32)>();
175/// assert::eq::<(i32,), (i32,)>();
176/// // assert::eq::<(i32,), (i16,)>(); // fails to compile
177/// ```
178#[diagnostic::on_unimplemented(
179    message = "`{Self}` and `{R}` do not represent the same set",
180    label = "the sets contain different members",
181    note = "two sets are equal when every member of one is also a member of the other"
182)]
183pub trait SetEqual<R: ?Sized> {}
184
185/// Indicates that a set is empty, i.e., it contains no members.
186///
187/// This is the same as `T: Subset<()>`
188pub trait IsEmpty: Subset<()> {}
189impl<T> IsEmpty for T where T: Subset<()> {}
190
191/// Trait for adding a new member to a type set.
192///
193/// See [`Insert`] for a convenient type alias to add a member to a set.
194pub trait Push {
195    /// The resulting set after adding the new member.
196    type Output<E>;
197}
198
199/// Type alias for adding a new member to a type set.
200///
201/// # Example
202///
203/// ```rust
204/// # use type_sets::*;
205/// assert::eq::<Insert<(i32,), i16>, (i16, i32)>();
206/// ```
207pub type Insert<T, E> = <T as Push>::Output<E>;
208
209// pub trait Shrink {
210//     type Output;
211//     type Popped;
212// }
213
214// pub type Pop<T> = <T as Shrink>::Output;
215// pub type Last<T> = <T as Shrink>::Popped;
216
217#[diagnostic::do_not_recommend]
218impl<T: AsTypeSet, R: AsTypeSet> SetEqual<R> for T where T: Subset<R> + Superset<R> {}
219
220mod generate_sets;
221
222// pub use intersection::*;
223// mod intersection;
224
225pub use union::*;
226mod union;
227
228/// Functions that check set relations at compile time. Each one compiles only if the relation
229/// holds, and does nothing at runtime.
230///
231/// Requires the `assertions` feature.
232#[cfg(feature = "assertions")]
233pub mod assert {
234    use super::*;
235
236    /// Asserts that two sets are equal. (Contain the same members.)
237    pub fn eq<T, R>()
238    where
239        T: SetEqual<R>,
240    {
241    }
242
243    /// Asserts that the first set is a superset of the second set.
244    pub fn superset<T, R>()
245    where
246        T: Superset<R>,
247    {
248    }
249
250    /// Asserts that the first set is a subset of the second set.
251    pub fn subset<T, R>()
252    where
253        T: Subset<R>,
254    {
255    }
256
257    /// Asserts that the set contains the specified member.
258    pub fn contains<T, E>()
259    where
260        T: Contains<E>,
261    {
262    }
263
264    /// Asserts that the set is empty (contains no members).
265    pub fn is_empty<T>()
266    where
267        T: IsEmpty,
268    {
269    }
270}