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
/// To annotate values with type-level names
use std::marker::PhantomData;

struct _Named<Name, A> {
    value: A,
    _phantom: PhantomData<Name>,
}

struct _Name;

/// A trait describing a value annotated with a type-level `name`.
///
/// While this is most useful alongside the combinators provided by the `proof`
/// module, names can also be used as a type-level witness that two values are
/// the same. This is useful for things like sorted lists or nonstandard binary
/// maps, where it is important to ensure that the comparison function used is
/// consistent.
///
/// This trait has been sealed, as library consumers should not implement this
/// trait for themselves. Instead, see `name`.
pub trait Named<A>: private::Sealed {
    type Name;
    fn out_ref(&self) -> &A;
    fn out(self) -> A;
}

impl<Name, A> _Named<Name, A> {
    fn into(x: A) -> Self {
        _Named {
            value: x,
            _phantom: PhantomData,
        }
    }
}

impl<Name, A> Named<A> for _Named<Name, A> {
    type Name = Name;
    fn out_ref(&self) -> &A {
        &self.value
    }

    fn out(self) -> A {
        self.value
    }
}

/// Annotate a value with a type-level name.
///
/// This function returns an
/// existential `impl Named<A>` to ensure that names are fresh per invocation.
/// This prevents consumers from providing their own names, which would violate
/// the invariant that named values represent a property of that value.
///
/// Note that the above does not *quite* work correctly in Rust, as the
/// existential names are not necessarily unique between identical invocations.
pub fn name<A>(x: A) -> impl Named<A> {
    // We do need to specify a type for the `Name` parameter in `_Named`, but
    // it's rendered opaque by the existential quantification.
    _Named::<_Name, A>::into(x)
}

mod private {
    use super::_Named;
    pub trait Sealed {}
    impl<Name, A> Sealed for _Named<Name, A> {}
}