tstr/macros.rs
1#[macro_use]
2mod cmp_macros;
3
4/// The type of a type-level string, always a [`TStr`].
5///
6/// # Arguments
7///
8/// You can use any of these as arguments:
9///
10/// - String literals (eg: `TS!("hello")`, `TS!(r#"world"#)`)
11///
12/// - Integers (eg: `TS!(0)`, `TS!(100)`):
13/// converting the integer to decimal, then stringifying it.
14///
15/// - Single identifiers (eg: `TS!(foo)`, `TS!(bar)`): stringifying the identifier.
16///
17/// - A comma separated list of the other valid arguments to this macro
18/// (eg: `TS!(foo, "bar", 0)`), this evaluates to a tuple of `TStr`s.
19///
20/// - `concat!(...)`-like syntax: concatenates its arguments,
21/// accepting the same arguments as this macro.
22///
23/// - `stringify!(...)`-like syntax: stringifies its arguments.
24///
25/// # Examples
26///
27/// ### ToVariant
28///
29/// This example demonstrates how you can use type-level strings to create a
30/// `GetVariant` trait which gets the data in a variant if the enum is that variant.
31///
32/// ```rust
33/// use tstr::TS;
34///
35/// fn main(){
36/// let foo = Enum::Foo(3, 5);
37/// let bar = Enum::Bar("hello".to_string());
38///
39/// assert_eq!(foo.to_variant(Foo::NEW), Some((3, 5)));
40/// assert_eq!(foo.to_variant(Bar::NEW), None);
41///
42/// assert_eq!(bar.to_variant(Foo::NEW), None);
43/// assert_eq!(bar.to_variant(Bar::NEW), Some("hello".to_string()));
44/// }
45///
46/// type Foo = TS!(Foo);
47///
48/// type Bar = TS!(Bar);
49///
50/// trait ToVariant<V> {
51/// type Output;
52///
53/// fn to_variant(&self, variant: V) -> Option<Self::Output>;
54/// }
55///
56/// enum Enum {
57/// Foo(u32, u64),
58/// Bar(String),
59/// }
60///
61/// impl ToVariant<TS!(Foo)> for Enum {
62/// type Output = (u32, u64);
63///
64/// fn to_variant(&self, variant: TS!(Foo)) -> Option<Self::Output> {
65/// match self {
66/// Self::Foo(l, r) => Some((*l, *r)),
67/// _ => None,
68/// }
69/// }
70/// }
71///
72/// impl ToVariant<TS!(Bar)> for Enum {
73/// type Output = String;
74///
75/// fn to_variant(&self, variant: TS!(Bar)) -> Option<Self::Output> {
76/// match self {
77/// Self::Bar(s) => Some(s.clone()),
78/// _ => None,
79/// }
80/// }
81/// }
82///
83///
84/// ```
85///
86/// ### Equivalences
87///
88/// This example demonstrates which invocations of `TS` produce the same type.
89///
90/// ```rust
91/// use tstr::TS;
92///
93/// type Hello1 = TS!("hello");
94/// type Hello2 = TS!(hello); // This is equivalent to `TS!("hello")`
95///
96/// type HundredA = TS!("100");
97/// type HundredB = TS!(100); // equivalent to `TS!("100")`
98/// type HundredC = TS!(0x64); // equivalent to `TS!("100")`
99/// type HundredD = TS!(0b1100100); // equivalent to `TS!("100")`
100///
101/// type Tup = TS!(foo, 1, "bar"); // equivalent to `(TS!(foo), TS!(1), TS!(bar))`
102///
103/// // Equivalent to TS!("foo4bar200")
104/// type Conc = TS!(concat!(foo, 0b100, "bar", 200));
105///
106/// ```
107///
108/// [`TStr`]: ./struct.TStr.html
109#[macro_export]
110macro_rules! TS {
111 ($($expr:expr),* $(,)* ) => {
112 $crate::__ts_impl!(($crate) $($expr)*)
113 };
114}
115
116/// A type-level string [`TStr`] value.
117///
118/// # Arguments
119///
120/// You can use anything that the [`tstr::TS`] macro accepts
121///
122/// # Examples
123///
124/// ### Indexing
125///
126/// This uses types from the `for_examples` module,
127/// which can be seen in the docs with the "for_examples" feature.
128///
129/// ```rust
130/// use tstr::ts;
131/// use tstr::for_examples::{Foo, Bar};
132///
133/// let this = Foo::new(3, 5, "8");
134/// assert_eq!(this[ts!(bar)], 3);
135/// assert_eq!(this[ts!(baz)], 5);
136/// assert_eq!(this[ts!(qux)], "8");
137///
138/// let other = Bar::new(13, false, Some('C'));
139/// assert_eq!(other[ts!(bar)], 13);
140/// assert_eq!(other[ts!(baz)], false);
141/// assert_eq!(other[ts!(boom)], Some('C'));
142///
143/// ```
144/// ### Equivalences
145///
146/// This example demonstrates which invocations of `ts` produce the same values.
147///
148/// ```rust
149/// use tstr::ts;
150///
151/// let hello1 = ts!("hello");
152/// let hello2 = ts!(hello); // This is equivalent to `ts!("hello")`
153///
154/// let hundreda = ts!("100");
155/// let hundredb = ts!(100); // equivalent to `ts!("100")`
156/// let hundredc = ts!(0x64); // equivalent to `ts!("100")`
157/// let hundredd = ts!(0b1100100); // equivalent to `ts!("100")`
158///
159/// let tup = ts!(foo, 1, "bar"); // equivalent to `(ts!(foo), ts!(1), ts!(bar))`
160///
161/// // Equivalent to ts!("foo4bar200")
162/// let conc = ts!(concat!(foo, 0b100, "bar", 200));
163/// # const _: tstr::TS!("foo4bar200") = ts!(concat!(foo, 0b100, "bar", 200));
164/// ```
165///
166///
167/// [`TStr`]: ./struct.TStr.html
168/// [`tstr::TS`]: ./macro.TS.html#arguments
169#[macro_export]
170macro_rules! ts {
171 ($($expr:expr),* $(,)* ) => {{
172 let __look_at_the_notes__ =
173 <$crate::__ts_impl!(($crate) $($expr)*) as $crate::MakeTStr>::MAKE;
174 __look_at_the_notes__
175 }};
176}
177
178/// Declares `const` and `type` aliases for type-level strings.
179///
180/// # String Arguments
181///
182/// You can alias either one type-level string, or a tuple of type-level strings
183///
184/// ```rust
185/// tstr::alias!{
186/// // Aliases the "bar" type-level string as both a const and a type, named Bar.
187/// pub Bar = bar;
188///
189/// // Aliases the "0" type-level string.
190/// pub N0 = 0;
191///
192/// // Aliases the ("foo", "baz") tuple of type-level strings,
193/// // Equivalent to `TS!(foo, baz)` and `ts!("foo", "baz")`
194/// pub Tup = (foo, baz);
195/// }
196///
197/// # const _: (tstr::TS!(foo), tstr::TS!(baz)) = Tup;
198/// ```
199///
200/// # Examples
201///
202/// ### Indexing
203///
204/// This uses types from the `for_examples` module,
205/// which can be seen in the docs with the "for_examples" feature.
206///
207/// ```rust
208/// use std::ops::Index;
209///
210/// use tstr::for_examples::{Foo, Bar};
211///
212/// tstr::alias!{
213/// // Declares both an NBar type alias and an NBar constant of that type.
214/// pub NBar = bar;
215///
216/// // Declares both an NBaz type alias and an NBaz constant of that type.
217/// pub NBaz = "baz";
218///
219/// // Declares both an NQux type alias and an NQux constant of that type.
220/// pub NQux = "qux";
221///
222/// }
223///
224/// // The macro can also be invoked like this
225/// tstr::alias!{ pub NBoom = boom }
226///
227/// let this = Foo::new(3, 5, "8");
228/// assert_eq!(get_bar_baz(&this), (3, 5));
229///
230/// let other = Bar::new(13, false, Some('C'));
231/// assert_eq!(get_bar_baz(&other), (13, false));
232///
233///
234/// type IndexOut<T, N> = <T as Index<N>>::Output;
235///
236/// fn get_bar_baz<T>(this: &T) -> (IndexOut<T, NBar>, IndexOut<T, NBaz>)
237/// where
238/// T: Index<NBar> + Index<NBaz>,
239/// IndexOut<T, NBar>: Copy,
240/// IndexOut<T, NBaz>: Copy,
241/// {
242/// (this[NBar], this[NBaz])
243/// }
244///
245/// ```
246///
247#[macro_export]
248macro_rules! alias {
249 (
250 $(
251 $(#[$attr:meta])*
252 $vis:vis $name:ident = $expr:tt
253 );*
254 $(;)?
255 ) => (
256 $(
257 $crate::__priv_alias!{
258 @decide-docs
259 (
260 $(#[$attr])*
261 $vis,
262 $name,
263 )
264 [$expr]
265 }
266 )*
267 );
268}
269
270#[doc(hidden)]
271#[macro_export]
272macro_rules! __priv_alias {
273 (@decide-docs
274 $other:tt
275 [($($expr:expr),* $(,)*)]
276 )=>{
277 $crate::__priv_alias!{
278 @inner
279 $other
280 [$($expr),*]
281 concat!(
282 "An alias for `(",
283 $(stringify!($expr), ", ",)*
284 ")` as a tuple of type level strings.\n\n",
285 "Generated by the [`::tstr::alias`] macro."
286 )
287 }
288 };
289 (@decide-docs
290 $other:tt
291 [$expr:expr]
292 )=>{
293 $crate::__priv_alias!{
294 @inner
295 $other
296 [$expr]
297 concat!(
298 "An alias for `", stringify!($expr), "` as a type level string.\n\n",
299 "Generated by the [`::tstr::alias`] macro."
300 )
301 }
302 };
303 (@inner
304 (
305 $(#[$attr:meta])*
306 $vis:vis, $name:ident,
307 )
308 [$($expr:expr),*]
309 $autodoc:expr
310 )=>{
311 $(#[$attr])*
312 #[allow(broken_intra_doc_links)]
313 #[doc = $autodoc]
314 $vis type $name = $crate::TS!($($expr),*);
315
316 $(#[$attr])*
317 #[allow(non_upper_case_globals, broken_intra_doc_links)]
318 #[doc = $autodoc]
319 $vis const $name: $name = <$name as $crate::MakeTStr>::MAKE;
320 };
321}