typetoken/lib.rs
1//! a type token that can be used to uniquly tag an instance of a type.
2//!
3//! these are singleton types, only a single instance
4//! of a given token type may exist.
5//! to make checking this at compile time possible, tokens cannot be returned
6//! from functions.
7
8/// marker trait that a type is a type token.
9///
10/// this trait is safe to use in trait bounds, but MUST NOT be implemented by any code
11/// outside of the `typetoken` crate.
12pub unsafe trait Token {}
13
14/// The heart of crate, generates a token singleton.
15///
16/// Every macro use site corresponds to a unique type,
17/// and creates a value of that type.
18/// the generated type will implement [`Token`].
19///
20/// The value contains an exclusive borrow also local to the macro use site
21/// (and thus the type contains the lifetime of that borrow),
22/// therefore no two values of the same type can exist at the same time.
23///
24/// The downside of this approach is that the token cannot outlive the
25/// stack frame of function it was defined in. for this reason, it is
26/// generally advisable to construct tokens in `main()` if possible.
27///
28/// ## Examples
29///
30/// To get any use out of this crate, you generally need some generic interface
31/// that takes two items of the tame generic type.
32/// ```rust
33/// # #[macro_use] extern crate typetoken;
34/// use typetoken::Token;
35/// fn assert_same_token<T: Token>(_: &T, _: &T) {}
36/// fn main() {
37/// token!(token1);
38/// token!(token2);
39/// assert_same_token(&token1, &token1);
40/// assert_same_token(&token2, &token2);
41/// }
42/// ```
43///
44/// If used with a correctly designed interface, this can
45/// catch programmer mistakes.
46/// ```compile_fail
47/// # #[macro_use] extern crate typetoken;
48/// # use typetoken::Token;
49/// # fn assert_same_token<T: Token>(_: &T, _: &T) {}
50/// # fn main() {
51/// token!(token1);
52/// token!(token2);
53/// assert_same_token(&token1, &token1);
54/// assert_same_token(&token2, &token1); // oops, wrong token, compile error
55/// # }
56/// ```
57///
58/// Tokens should be unique in all circumstances, even if you do silly
59/// things like define them on the same line
60/// (this will make your error messages more confusing, so probably don't)
61/// ```compile_fail
62/// # #[macro_use] extern crate typetoken;
63/// # use typetoken::Token;
64/// # fn assert_same_token<T: Token>(_: &T, _: &T) {}
65/// # fn main() {
66/// token!(token1); token!(token2);
67/// assert_same_token(&token1, &token1);
68/// assert_same_token(&token2, &token1); // oops, wrong token, compile error
69/// # }
70/// ```
71///
72/// see the [`examples/`](https://codeberg.org/binarycat/typetoken/src/branch/trunk/examples)
73/// directory for more practical usecases.
74#[macro_export]
75macro_rules! token {
76 ($name:ident) => {
77 // mutable reference to regular reference disables lifetime covariance.
78 // https://doc.rust-lang.org/nomicon/subtyping.html#variance
79 let _guard_1 = ();
80 let mut _guard_2 = &_guard_1;
81 let $name = {
82 // because it is in a block, this cannot be constructed outside
83 // the macro.
84 // TODO: is there an attribute to give an item a different name in error messages?
85 struct TokenType<'a, const N: u32> {
86 // make TokenType<'a> invariant with TokenType<'b>
87 //
88 // also leverage the exclusive nature of mutable borrows, this
89 // prevents doing something like running `token!` in a loop and
90 // collecting identical tokens.
91 //
92 // quinedot: The exclusive borrow means you can't get multiple
93 // values out from the same macro call site at the same time
94 // -- by returning from a function, yes, but also by being in
95 // a loop, say. The idea is to plug a hole of many
96 // unique-type-based singleton attempts: every (monomorphized)
97 // expression has a particular type; if that code runs more than
98 // once, the same type results each run, even if that type is
99 // unique to the expression. So creating a value of
100 // a "unique type" is not enough to
101 // actually be a singleton at run time.
102 //
103 // thus, the extra lifetime paramater is required.
104 _invariant: &'a mut &'a (),
105 }
106 // not actually required to provide any of listed guarantees,
107 // but makes error messages slightly more readable.
108 const THIS_LINE: u32 = line!();
109 // the only "impl Token" that should ever exist
110 unsafe impl<'a> $crate::Token for TokenType<'a, THIS_LINE> {}
111 TokenType::<THIS_LINE>{ _invariant: &mut _guard_2 }
112 };
113 }
114}
115