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}