use closed_trait::{enumerate, sealed};
pub struct Boxed<T>(pub T);
pub struct Pair<T>(pub T, pub T);
#[enumerate(match_any)]
#[sealed(for<T> Boxed<T>: Store<T>, for<T> Pair<T>: Store<T>)]
pub trait Store<T> {
fn first(&self) -> &T;
}
impl<T> Store<T> for Boxed<T> {
fn first(&self) -> &T {
&self.0
}
}
impl<T> Store<T> for Pair<T> {
fn first(&self) -> &T {
&self.0
}
}
#[test]
fn the_enum_carries_the_traits_parameter() {
let store: AnyStore<i32> = Boxed(7).into();
assert_eq!(*match_any_store!(&store, s => s.first()), 7);
let store = AnyStore::from(Pair("a", "b"));
assert_eq!(*match_any_store!(&store, s => s.first()), "a");
}
#[test]
fn the_macro_matches_a_generic_enum() {
let store = AnyStore::from(Pair(3, 4));
assert_eq!(*match_any_store!(&store, s => s.first()), 3);
}
pub struct Borrowed<'a>(pub &'a str);
#[enumerate(match_any)]
#[sealed(for<'a> Borrowed<'a>: Borrow<'a>)]
pub trait Borrow<'a> {
fn text(&self) -> &'a str;
}
impl<'a> Borrow<'a> for Borrowed<'a> {
fn text(&self) -> &'a str {
self.0
}
}
#[test]
fn the_enum_carries_a_lifetime() {
let owned = String::from("borrowed");
let borrow = AnyBorrow::from(Borrowed(&owned));
assert_eq!(match_any_borrow!(&borrow, b => b.text()), "borrowed");
}
#[test]
fn a_trait_with_its_own_lifetime_still_borrows() {
let owned = String::from("borrowed");
let mut any = AnyBorrow::from(Borrowed(&owned));
assert_eq!(
match_any_borrow_ref!(any.as_ref(), b => b.text()),
"borrowed"
);
assert_eq!(
match_any_borrow_mut!(any.as_mut(), b => b.text()),
"borrowed"
);
use closed_trait::EnumerableRef;
let borrowed = Borrowed(&owned);
assert_eq!(
match_any_borrow_ref!(borrowed.as_enum_ref(), b => b.text()),
"borrowed"
);
}
#[test]
fn a_generic_trait_lends_uniquely() {
let mut store = AnyStore::from(Pair(3, 4));
assert_eq!(*match_any_store_mut!(store.as_mut(), s => s.first()), 3);
}
mod crowded_lifetimes {
use closed_trait::{enumerate, sealed};
pub struct Pair<'a, 'r>(pub &'a str, pub &'r str);
#[enumerate(match_any)]
#[sealed(for<'a, 'r> Pair<'a, 'r>: Held<'a, 'r>)]
pub trait Held<'a, 'r> {
fn first(&self) -> &'a str;
fn second(&self) -> &'r str;
}
impl<'a, 'r> Held<'a, 'r> for Pair<'a, 'r> {
fn first(&self) -> &'a str {
self.0
}
fn second(&self) -> &'r str {
self.1
}
}
}
#[test]
fn the_borrow_finds_a_name_the_trait_has_not_spent() {
use crowded_lifetimes::{AnyHeld, AnyHeldRef, Held, Pair, match_any_held_ref};
let (a, b) = (String::from("x"), String::from("y"));
let owned = AnyHeld::from(Pair(&a, &b));
let borrowed: AnyHeldRef<'_, '_, '_> = owned.as_ref();
assert_eq!(match_any_held_ref!(borrowed, p => p.first()), "x");
assert_eq!(match_any_held_ref!(borrowed, p => p.second()), "y");
}
mod crowded_types {
use super::*;
pub struct One<T>(pub T);
pub struct Two<A, B>(pub A, pub B);
#[sealed(for<S> One<S>: Held<S>)]
pub trait Held<S> {
fn held(&self) -> &S;
}
impl<S> Held<S> for One<S> {
fn held(&self) -> &S {
&self.0
}
}
#[sealed(for<S, S2> Two<S, S2>: Paired<S, S2>)]
pub trait Paired<S, S2> {
fn left(&self) -> &S;
fn right(&self) -> &S2;
}
impl<S, S2> Paired<S, S2> for Two<S, S2> {
fn left(&self) -> &S {
&self.0
}
fn right(&self) -> &S2 {
&self.1
}
}
}
#[test]
fn the_assertion_finds_a_name_the_trait_has_not_spent() {
use crowded_types::{Held, One, Paired, Two};
assert_eq!(*One(1u8).held(), 1);
let pair = Two(2u8, 'x');
assert_eq!(*pair.left(), 2);
assert_eq!(*pair.right(), 'x');
}
mod bound_entries {
use super::*;
pub struct Held<U>(pub U);
pub struct Wrapped<X>(pub X);
pub struct Plain;
#[enumerate(match_any)]
#[sealed(
for<U> Held<U>: Keep<U>,
for<U> Wrapped<Vec<U>>: Keep<U>,
for<U> Plain: Keep<U>,
)]
pub trait Keep<T> {
fn count(&self) -> usize;
}
impl<U> Keep<U> for Held<U> {
fn count(&self) -> usize {
1
}
}
impl<U> Keep<U> for Wrapped<Vec<U>> {
fn count(&self) -> usize {
self.0.len()
}
}
impl<U> Keep<U> for Plain {
fn count(&self) -> usize {
0
}
}
}
#[test]
fn a_bound_entry_reaches_the_enum_in_the_traits_parameters() {
use bound_entries::{AnyKeep, Held, Keep, Plain, Wrapped, match_any_keep};
use closed_trait::Enumerable;
let held: AnyKeep<u8> = Held(1u8).into_enum();
assert_eq!(match_any_keep!(held, k => Keep::<u8>::count(&k)), 1);
let wrapped: AnyKeep<u8> = Wrapped(vec![1u8, 2, 3]).into_enum();
assert_eq!(match_any_keep!(wrapped, k => Keep::<u8>::count(&k)), 3);
let plain: AnyKeep<u8> = Plain.into_enum();
assert_eq!(match_any_keep!(plain, k => Keep::<u8>::count(&k)), 0);
}
mod bound_shapes {
use super::*;
pub struct Slice<'b>(pub &'b str);
#[enumerate]
#[sealed(for<'b> Slice<'b>: Borrowed<'b>)]
pub trait Borrowed<'x> {
fn read(&self) -> &str;
}
impl<'b> Borrowed<'b> for Slice<'b> {
fn read(&self) -> &str {
self.0
}
}
pub struct Arr<const N: usize>(pub [u8; N]);
#[enumerate]
#[sealed(for<const N: usize> Arr<N>: Sized_<N>)]
pub trait Sized_<const M: usize> {
fn size(&self) -> usize;
}
impl<const N: usize> Sized_<N> for Arr<N> {
fn size(&self) -> usize {
N
}
}
pub struct Bounded<U>(pub U);
#[enumerate]
#[sealed(for<U: core::fmt::Debug> Bounded<U>: Guarded<U>)]
pub trait Guarded<T> {}
impl<U: core::fmt::Debug> Guarded<U> for Bounded<U> {}
pub struct Pair<U, V>(pub U, pub V);
#[enumerate]
#[sealed(for<U, V> Pair<U, V>: Swapped<V, U>)]
pub trait Swapped<A, B> {
fn first(&self) -> &B;
}
impl<U, V> Swapped<V, U> for Pair<U, V> {
fn first(&self) -> &U {
&self.0
}
}
}
#[test]
fn a_lifetime_binder_reaches_the_enum() {
use bound_shapes::{AnyBorrowed, Borrowed, Slice};
use closed_trait::Enumerable;
let held = String::from("x");
let any: AnyBorrowed<'_> = Slice(&held).into_enum();
let AnyBorrowed::Slice(slice) = any;
assert_eq!(slice.read(), "x");
}
#[test]
fn a_const_binder_reaches_the_enum() {
use bound_shapes::{AnySized_, Arr, Sized_};
use closed_trait::Enumerable;
let any: AnySized_<3> = Arr([1, 2, 3]).into_enum();
let AnySized_::Arr(arr) = any;
assert_eq!(arr.size(), 3);
}
#[test]
fn the_mapping_follows_the_instantiations_order_not_the_binders() {
use bound_shapes::{AnySwapped, Pair, Swapped};
use closed_trait::Enumerable;
let any: AnySwapped<char, u8> = Pair(1u8, 'x').into_enum();
let AnySwapped::Pair(pair) = any;
assert_eq!(*pair.first(), 1);
}
#[test]
fn a_bound_on_a_binder_reaches_the_variants_impls() {
use bound_shapes::{AnyGuarded, Bounded};
use closed_trait::Enumerable;
let any: AnyGuarded<u8> = Bounded(1u8).into_enum();
let AnyGuarded::Bounded(held) = any;
assert_eq!(held.0, 1);
}