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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Unique and singleton types and tools for constructing them.

mod ghost_ref;
mod static_ref;
mod token;

pub use ::mischief_derive::{Singleton, Unique};

pub use self::{ghost_ref::*, static_ref::*, token::*};

/// A type which guarantees that only one value can ever exist at a time.
///
/// # Safety
///
/// Only one value of this type may ever exist simultaneously.
pub unsafe trait Unique {}

// SAFETY: Mutable references may not alias, so a mutable reference of a unique
// type must also be unique.
unsafe impl<T: Unique> Unique for &mut T {}

/// A type which guarantees that all simultaneous values share the same state.
///
/// # Safety
///
/// Any two simultaneous instances of this type must be interchangeable and
/// share the same state. A `Singleton` type might fulfill this obligation by
/// referencing shared state, referencing a [`Unique`], or requiring the
/// precondition to be checked manually.
pub unsafe trait Singleton {}

// SAFETY: All simultaneous shared references to a `Unique` type must be to the
// same value.
unsafe impl<T: Unique> Singleton for &T {}

#[cfg(feature = "alloc")]
// SAFETY: Every `Global` is guaranteed to share the same state.
unsafe impl Singleton for ::heresy::alloc::Global {}

/// Splits a unique value into several others.
#[macro_export]
macro_rules! split_unique {
    (fn $fn:ident($in:ty) -> $out:ident) => {
        $crate::split_unique!(@define $in => ($out,));
        $crate::split_unique!(@impl $fn($in) -> $out);
    };
    (fn $fn:ident($in:ty) -> ($($out:tt)*)) => {
        $crate::split_unique!(@define $in => ($($out)*));
        $crate::split_unique!(@impl $fn($in) -> ($($out)*));
    };
    (pub fn $fn:ident($in:ty) -> $out:ident) => {
        $crate::split_unique!(@define $in => ($out,) $($vis)*);
        $crate::split_unique!(@impl $fn($in) -> $out pub);
    };
    (pub fn $fn:ident($in:ty) -> ($($out:tt)*)) => {
        $crate::split_unique!(@define $in => ($($out)*) $($vis)*);
        $crate::split_unique!(@impl $fn($in) -> ($($out)*) pub);
    };
    (pub($($vis:tt)*) fn $fn:ident($in:ty) -> $out:ident) => {
        $crate::split_unique!(@define $in => ($out,) $($vis)*);
        $crate::split_unique!(@impl $fn($in) -> $out pub($($vis)*));
    };
    (pub($($vis:tt)*) fn $fn:ident($in:ty) -> ($($out:tt)*)) => {
        $crate::split_unique!(@define $in => ($($out)*) $($vis)*);
        $crate::split_unique!(@impl $fn($in) -> ($($out)*) pub($($vis)*));
    };

    (@impl $fn:ident($in:ty) -> $out:ident $($vis:tt)*) => {
        #[inline]
        $($vis)* fn $fn(unique: $in) -> $out {
            // Forgetting is semantically equivalent to moving into static
            // variable permanently.
            ::core::mem::forget(unique);
            $out(::core::marker::PhantomData)
        }
    };
    (@impl $fn:ident($in:ty) -> ($($out:ident),*) $($vis:tt)*) => {
        #[inline]
        $($vis)* fn $fn(unique: $in) -> ($($out),*) {
            // Forgetting is semantically equivalent to moving into static
            // variable permanently.
            ::core::mem::forget(unique);
            ($(
                $out(::core::marker::PhantomData)
            ),*)
        }
    };
    (@impl $fn:ident($in:ty) -> ($($out:ident,)*) $($vis:tt)*) => {
        #[inline]
        $($vis)* fn $fn(unique: $in) -> ($($out,)*) {
            // Forgetting is semantically equivalent to moving into static
            // variable permanently.
            ::core::mem::forget(unique);
            ($(
                $out(::core::marker::PhantomData),
            )*)
        }
    };

    (@define $in:ty => () $($vis:tt)*) => {};
    (@define
        $in:ty => ($out_first:ident $(, $out_rest:ident)* $(,)?) $($vis:tt)*
    ) => {
        $($vis)* struct $out_first(
            ::core::marker::PhantomData<&'static mut $in>,
        );

        // SAFETY: `$out` can only be acquired by exchanging another `Unique`
        // for it. That unique value is retained indefinitely, so the exchange
        // can only ever be performed once.
        unsafe impl $crate::Unique for $out_first {}

        $crate::split_unique!(@define $in => ($($out_rest,)*) $($vis:tt)*);
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn split_unique() {
        use crate::{runtime_token, Unique};

        #[inline]
        fn assert_unique<T: Unique>() {}

        runtime_token!(Foo);
        split_unique!(fn barify(Foo) -> (Bar, Baz, Bat));

        assert_unique::<Foo>();
        assert_unique::<Bar>();
        assert_unique::<Baz>();
        assert_unique::<Bat>();

        let (bar, baz, bat): (Bar, Baz, Bat) = barify(Foo::acquire());
        assert!(matches!(Foo::try_acquire(), Err(_)));

        let _ = (bar, baz, bat);

        assert!(matches!(Foo::try_acquire(), Err(_)));
    }
}