1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/// A convenience struct for applying implementing `TypeEq` trait. Since the trait
/// connects two types, this allows neither to be Self, and prevents issues with
/// asymmetry.
/// 
/// # Examples
/// 
/// ```
/// # use std::marker::PhantomData;
/// use type_eq::{Constrain, TypeEq};
/// struct Example<A, B> { 
///     # _marker: PhantomData<(A, B)>,
///     // ... 
/// }
/// 
/// impl<A, B> Example<A, B> {
/// 
///     // This method is only defined when A and B are the same type
///     fn a_eq_b(&self) where Constrain: TypeEq<A, B> { }
/// 
///     // This method is only defined when it's called with a parameter T which is
///     // the same type as A
///     fn a_eq_t<T>(&self, _t: T) where Constrain: TypeEq<A, T> { }
/// 
///     // This method must be called with an explicit type. Since T is contrained to
///     // be the same type as A and B, this can allow the caller a more convenient way of 
///     // determining those types 
///     fn infer_a<T>(&self) where Constrain: TypeEq<A, T> + TypeEq<B, T> { }
/// }
/// ```
pub struct Constrain;

/// A trait that determines that two type parameters are the same type.
/// There is only one implementation of this trait, `Constrain`, which ensures that all types 
/// satisfy the condition of being equal to themselves. There should not be a reason to implement 
/// this for other types, which is why it is marked as `unsafe`.
pub unsafe trait TypeEq<A, B> {
    fn as_eq(&self, a: A) -> B;
}

unsafe impl<A> TypeEq<A, A> for Constrain {
    fn as_eq(&self, a: A) -> A { a }
}

/// Type-level properties. This trait can be used to associate marker types with properties of
/// the implementating type.
/// 
/// # Examples
/// ```
/// use type_eq::{Constrain, Has, TypeEq};
/// 
/// // marler type for the "name" property
/// struct Name;
/// 
/// struct Foo;
/// 
/// impl Has<Name> for Foo {
///     type Val = &'static str;
///     fn get<P>(&self) -> Self::Val 
///     where
///         Constrain: TypeEq<Name, P>,
///     {
///         "Foo"
///     }
/// }
/// 
/// assert_eq!("Foo", Foo.get::<Name>());
/// 
/// ```
/// 
pub trait Has<Prop> {
    type Val: Sized;
    fn get<P>(&self) -> Self::Val
    where
        Constrain: TypeEq<Prop, P>;
}