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