inline_const/
lib.rs

1//! You don't want to wait until [inline consts](https://rust-lang.github.io/rfcs/2920-inline-const.html) are stable?
2//! This crate offers much of the functionality of inline consts in a pure macro-based implementation, at a slight const of convenience:
3//! you need to explicitly annotate the type of the constant.
4//! ```rust
5//! use std::net::Ipv6Addr;
6//! 
7//! use inline_const::inline_const;
8//! 
9//! fn mock_ip(use_localhost: bool) -> &'static Ipv6Addr {
10//!     if use_localhost {
11//!         &Ipv6Addr::LOCALHOST
12//!     } else {
13//!         inline_const! { [&'static Ipv6Addr]
14//!             &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)
15//!         }
16//!     }
17//! }
18//! ```
19//! 
20//! Unlike the current unstable implementation of inline-const, this crate even supports consts that depend on generic parameters,
21//! albeit at some further annotation cost: you need to repeat the generic parameters that the constant refers to, and their lifetime bounds.
22//! ```rust
23//! use inline_const::inline_const;
24//! 
25//! fn make_static_vec<T: 'static>() -> &'static Vec<T>{
26//!     inline_const! { <T: 'static> [&'static Vec<T>] &Vec::new() }
27//! }
28//! ```
29
30#[cfg(all(const_generics, doctest))]
31#[macro_use]
32extern crate doc_comment;
33#[cfg(all(const_generics, doctest))]
34doctest!("../README.md");
35
36#[doc(hidden)]
37#[macro_export(local_inner_macros)]
38macro_rules! __generate_assoc_const {
39    (
40        $callback:ident @parsed
41        < $($generic_ty:ident $( : $lft_bound:lifetime )? ),* > < $(const $generic_const:ident : $generic_const_ty:ty),* >
42        [ $t:ty ] $e:expr ;
43        $($cont:tt)*
44    ) => {{
45        // We must actually use all the const parameters. To avoid adding `Sized` constraints, we
46        // use them behind a pointer indirection.
47        struct Const<$($generic_ty $(: $lft_bound)?,)* $(const $generic_const: $generic_const_ty,)*>($(*mut $generic_ty),*);
48        impl<$($generic_ty $(: $lft_bound)?,)* $(const $generic_const: $generic_const_ty,)*> Const<$($generic_ty,)* $($generic_const,)*> {
49            const C: $t = $e;
50        }
51        $callback!(Const::<$($generic_ty,)* $($generic_const,)*>::C, $($cont)*)
52    }};
53    (
54        $callback:ident @parse
55        < $($generic_ty:ident $( : $lft_bound:lifetime )? ),+ ; $(const $generic_const:ident : $generic_const_ty:ty),+ $(,)? >
56        $($cont:tt)*
57    ) => {
58        __generate_assoc_const!($callback @parsed <$($generic_ty $(: $lft_bound)? ),*> <$(const $generic_const: $generic_const_ty),*> $($cont)*)
59    };
60    (
61        $callback:ident @parse < $(const $generic_const:ident : $generic_const_ty:ty),+ $(,)? >
62        $($cont:tt)*
63    ) => {
64        __generate_assoc_const!($callback @parsed <> <$(const $generic_const: $generic_const_ty),*> $($cont)*)
65    };
66    (
67        $callback:ident @parse < $($generic_ty:ident $( : $lft_bound:lifetime )? ),* $(,)? > // covers the empty case
68        $($cont:tt)*
69    ) => {
70        __generate_assoc_const!($callback @parsed <$($generic_ty $(: $lft_bound)? ),*> <> $($cont)*)
71    };
72    (
73        $callback:ident @parse [ $t:ty ] $($cont:tt)*
74    ) => {
75        __generate_assoc_const!($callback @parsed <> <> [$t] $($cont)*)
76    };
77}
78
79/// Macro to generate a constant as an inline expression.
80/// 
81/// See [module-level docs](index.html) for examples.
82#[macro_export(local_inner_macros)]
83macro_rules! inline_const {
84    ( $($params:tt)* ) => {
85        __generate_assoc_const!(__inline_const_callback @parse $($params)* ; @emp)
86    };
87}
88#[doc(hidden)]
89#[macro_export]
90macro_rules! __inline_const_callback {
91    ($const:path, @emp) => {
92        $const
93    }
94}
95
96/// Macro to generate an array by repeating a constant `N` times.
97/// 
98/// Since recently, `[C; N]` works for any constant `C`, even for non-`Copy` types.
99/// However, without inline consts, this is somewhat annoying to use.
100/// The `const_array!` macro helps with that situation:
101/// 
102/// ```rust
103/// use inline_const::const_array;
104/// 
105/// fn make_i32_vecs() -> [Vec<i32>; 5] {
106///     // [Vec::new(); 5]: rejected since `Vec::new` is not a constant.
107///     const_array![ [Vec<i32>] Vec::new(); 5]
108/// }
109/// fn make_vecs<T>() -> [Vec<T>; 5] {
110///     // Generic parameters used in the const expression must be explicitly specified:
111///     const_array![<T> [Vec<T>] Vec::new(); 5]
112/// }
113/// ```
114#[macro_export(local_inner_macros)]
115macro_rules! const_array {
116    ( $($params:tt)* ) => {
117        // Conveniently, the surface user syntax already contains a `;` and then the remaining
118        // arguments, so we just re-use those for the `;` expected by __generate_assoc_const.
119        __generate_assoc_const!(__const_array_callback @parse $($params)*)
120    };
121}
122#[doc(hidden)]
123#[macro_export]
124macro_rules! __const_array_callback {
125    ($const:path, $N:expr) => {
126        [$const; $N]
127    }
128}