type-sets 0.2.0

Sets implemented in the rust type-system
Documentation
//! `type-sets` implements various compile-time set-operations on tuples.
//!
//! # Basic example
//!
//! ```rust
//! # use type_sets::*;
//! assert::contains::<(i32, i16), i32>();
//! assert::subset::<(i32,), (i32, i64)>();
//! assert::superset::<(i32, i16), (i32,)>();
//! assert::eq::<(i32, i16), (i16, i32)>();
//! ```
//!
//! # Operations
//! - [`Contains<E>`]: Checks if a set contains a specific member.
//! - [`Subset<S>`]: Checks if a set is a subset of another set.
//! - [`Superset<S>`]: Checks if a set is a superset of another set.
//! - [`SetEqual<R>`]: Checks if two sets are equal.
//! - [`IsEmpty`]: Checks if a set is empty.
//! - [`Insert<T, E>`]: Adds a new member to a set.
//! - [`Union<T, R>`]: Computes the union of two sets.
//!
//! See the individual trait documentation for more details on each operation.

use generate_sets::*;
use std::{any::TypeId, convert::Infallible};

/// Implemented for any set that contains a member `E`.
///
/// # Example
///
/// ```rust
/// # use type_sets::*;
/// assert::contains::<(i32,), i32>();
/// assert::contains::<(i16, i32), i32>();
/// assert::contains::<(i32, i16), i32>();
/// // assert::contains::<(i8, i16), i32>(); // fails to compile
/// ```
#[diagnostic::on_unimplemented(
    message = "`{Self}` does not contain `{E}`",
    label = "type does not contain this element",
    note = "a type implements `Contains<E>` when `E` is one of its set members"
)]
pub trait Contains<E>: Contains0 {}

#[diagnostic::do_not_recommend]
impl<E, T: ?Sized> Contains<E> for T where T: Contains1<E> {}

/// Implemented for any set that is a subset of set `S`.
///
/// # Example
///
/// ```rust
/// # use type_sets::*;
/// assert::subset::<(i32,), (i32,)>();
/// assert::subset::<(i16, i32), (i16, i32)>();
/// assert::subset::<(i32, i16), (i16, i32)>();
/// assert::subset::<(i32,), (i32, i16)>();
/// // assert::subset::<(i8, i16), (i16, i32)>(); // fails to compile
/// ```
#[diagnostic::on_unimplemented(
    message = "`{Self}` is not a subset of `{S}`",
    label = "this set is not a subset of the required set",
    note = "every member of the left-hand set must also be present in the right-hand set"
)]
pub trait Subset<S: ?Sized> {}

#[diagnostic::do_not_recommend]
impl<T, R> Subset<R> for T
where
    T: AsTypeSet<Set: Subset<R::Set>>,
    R: AsTypeSet,
{
}

/// Implemented for any set that is a superset of set `S`.
///
/// # Example
///
/// ```rust
/// # use type_sets::*;
/// assert::superset::<(i32, i16), (i32,)>();
/// assert::superset::<(i16, i32), (i32,)>();
/// assert::superset::<(i32,), (i32,)>();
/// assert::superset::<(i32, i16), (i16, i32)>();
/// // assert::superset::<(i8, i16), (i32,)>(); // fails to compile
/// ```
#[diagnostic::on_unimplemented(
    message = "`{Self}` is not a superset of `{S}`",
    label = "this set does not contain all required members",
    note = "every member of the right-hand set must also be present in the left-hand set"
)]
pub trait Superset<S: ?Sized> {}

#[diagnostic::do_not_recommend]
impl<S1: ?Sized, S2: ?Sized> Superset<S2> for S1 where S2: Subset<S1> {}

/// The main trait for representing a set of types.
///
/// This is implemented for tuples up to 24 elements.
///
/// # Examples
/// - `(A,)`
/// - `(A, B)`
/// - `(A, B, C)`
pub trait AsTypeSet {
    /// The underlying set type, which is a private marker-trait.
    type Set: ?Sized;
}

/// Trait for retrieving the members of a type set as [`TypeId`]s.
///
/// # Example
///
/// ```rust
/// # use type_sets::*;
/// let members = <(i32, i16) as Members>::members();
///
/// assert_eq!(members, &[
///     std::any::TypeId::of::<i32>(),
///     std::any::TypeId::of::<i16>(),
/// ]);
/// ```
pub trait Members {
    /// Returns a static slice of [`TypeId`]s representing the members of the set.
    fn members() -> &'static [TypeId];
}

impl<T> Members for T
where
    T: AsTypeSet<Set: Members>,
{
    fn members() -> &'static [TypeId] {
        <T::Set as Members>::members()
    }
}

/// Indicates that two sets are equal, i.e., they contain the same members.
///
/// This is the same as `T: Subset<R> + Superset<R>`
///
/// # Example
///
/// ```rust
/// # use type_sets::*;
/// assert::eq::<(i32, i16), (i16, i32)>();
/// assert::eq::<(i32,), (i32,)>();
/// // assert::eq::<(i32,), (i16,)>(); // fails to compile
/// ```
#[diagnostic::on_unimplemented(
    message = "`{Self}` and `{R}` do not represent the same set",
    label = "the sets contain different members",
    note = "two sets are equal when every member of one is also a member of the other"
)]
pub trait SetEqual<R: ?Sized> {}

/// Indicates that a set is empty, i.e., it contains no members.
///
/// This is the same as `T: Subset<()>`
pub trait IsEmpty: Subset<()> {}
impl<T> IsEmpty for T where T: Subset<()> {}

/// Trait for adding a new member to a type set.
///
/// See [`Insert`] for a convenient type alias to add a member to a set.
pub trait Push {
    /// The resulting set after adding the new member.
    type Output<E>;
}

/// Type alias for adding a new member to a type set.
///
/// # Example
///
/// ```rust
/// # use type_sets::*;
/// assert::eq::<Insert<(i32,), i16>, (i16, i32)>();
/// ```
pub type Insert<T, E> = <T as Push>::Output<E>;

// pub trait Shrink {
//     type Output;
//     type Popped;
// }

// pub type Pop<T> = <T as Shrink>::Output;
// pub type Last<T> = <T as Shrink>::Popped;

#[diagnostic::do_not_recommend]
impl<T: AsTypeSet, R: AsTypeSet> SetEqual<R> for T where T: Subset<R> + Superset<R> {}

mod generate_sets;

// pub use intersection::*;
// mod intersection;

pub use union::*;
mod union;

#[cfg(feature = "assertions")]
pub mod assert {
    use super::*;

    /// Asserts that two sets are equal. (Contain the same members.)
    pub fn eq<T, R>()
    where
        T: SetEqual<R>,
    {
    }

    /// Asserts that the first set is a superset of the second set.
    pub fn superset<T, R>()
    where
        T: Superset<R>,
    {
    }

    /// Asserts that the first set is a subset of the second set.
    pub fn subset<T, R>()
    where
        T: Subset<R>,
    {
    }

    /// Asserts that the set contains the specified member.
    pub fn contains<T, E>()
    where
        T: Contains<E>,
    {
    }

    /// Asserts that the set is empty (contains no members).
    pub fn is_empty<T>()
    where
        T: IsEmpty,
    {
    }
}