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}