1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// reason: flagged in macro generated code
//! This crate allows performing const calculations with the help of a generic const `usize`
//! that is a reasonable upper bound of some desired associated const `usize`.
//!
//! The API of this crate is structed as follows:
//! - [`AcceptUpperBound`](crate::AcceptUpperBound) is the heart of this crate. Implementors use it to specify which
//! generic const they want to be passed to them and what to do with any given upper bound for it.
//! It can be implemented conveniently using [`impl_accept_upper_bound!`](crate::impl_accept_upper_bound).
//! - [`eval_with_upper_bound`](crate::eval_with_upper_bound) is used to get the result of evaluating an upper bound acceptor
//! with the best-effort upper bound that this crate can offer.
//!
//! While you cannot use this to write a function with a signature that returns e.g. `[T; M + N]`
//! with generic `M` and `N`, you can use it to temporarily get an array of size `M + N`, use it
//! to do something useful, then return the result of that computation.
//! For example, you can concatenate two strings at compile time, even if their value is dependent
//! on generic parameters:
//! ```
//! use generic_upper_bound as gub;
//! pub trait MyTrait {
//! const SOME_STR: &'static str;
//! }
//! struct Concat<A, B>(A, B);
//! gub::impl_accept_upper_bound! {
//! impl{A: MyTrait, B: MyTrait} Concat<A, B>;
//!
//! const DESIRED_GENERIC: usize = A::SOME_STR.len() + B::SOME_STR.len();
//!
//! const EVAL<const UPPER: usize>: &'static [u8] = &{
//! let l = A::SOME_STR.as_bytes();
//! let r = B::SOME_STR.as_bytes();
//! let mut out = [0; UPPER];
//! let mut off = 0;
//! // after 1.86, use split_at_mut and copy_from_slice
//! let mut i = 0;
//! while i < l.len() {
//! out[off] = l[i];
//! off += 1;
//! i += 1;
//! }
//! i = 0;
//! while i < r.len() {
//! out[off] = r[i];
//! off += 1;
//! i += 1;
//! }
//! out
//! };
//! }
//! impl<A: MyTrait, B: MyTrait> MyTrait for (A, B) {
//! // evaluate the upper bound acceptor, trim trailing nul bytes
//! // and convert to string
//! const SOME_STR: &'static str = match core::str::from_utf8(
//! gub::eval_with_upper_bound::<Concat<A, B>>()
//! .split_at(gub::desired_generic::<Concat<A, B>>())
//! .0,
//! ) {
//! Ok(s) => s,
//! _ => unreachable!(),
//! };
//! }
//! impl MyTrait for () {
//! const SOME_STR: &'static str = "ABC";
//! }
//! impl MyTrait for i32 { const SOME_STR: &'static str = "123";
//! }
//! let concatenated: &'static str = <((), i32)>::SOME_STR;
//! assert_eq!(concatenated, "ABC123");
//! ```
//! Note that this example can be generalized and optimized. For instance, it is possible to accept
//! any `&'a [&'b str]` as input and this will also be more efficient (most of the time)
//! due to the overhead from the inexact upper bound used for each concatenation (which will
//! likely affect the final binary size).
//!
//! See the [`const-util`](https://docs.rs/const-util/latest/const_util/) crate for an
//! implementation of this.
//!
//! # MSRV
//! The MSRV is 1.78. This is to allow this crate to be used as a workaround for the breaking change
//! to const promotion that was introduced by that version.
pub extern crate type_const;
pub use ;
/// Allows implementing a callback pattern that accepts an upper bound for a desired generic const
/// parameter.
///
/// The trait works by allowing implementors to specify, for each upper bound, a value that is
/// computed from that upper bound. This value is represented as a generic associated type with
/// bound [`Const`], as this is currently the only way to implement a `const` item with generics
/// in a trait.
///
/// When passed to [`eval_with_upper_bound`], [`Eval::<UPPER>::VALUE`](Const::VALUE) will be evaluated
/// with a parameter `UPPER` that satisfies `DESIRED_GENERIC <= UPPER < 2 * DESIRED_GENERIC`.
;
/// Returns [`AcceptUpperBound::DESIRED_GENERIC`].
pub const
/// Returns the parameter that [`eval_with_upper_bound`] passes to [`AcceptUpperBound::Eval`].
pub const
/// Evaluates [`AcceptUpperBound`].
///
/// In the language of `generic_const_exprs`, this function returns
/// `const_value::<F::Eval<{ get_upper_bound::<F>() }>>()`
pub const
/// Implements [`AcceptUpperBound`] by generating a hidden [`Const`] implementor.
///
/// Generic parameters are passed in braces (`{...}`) after `impl` and cannot have a trailing
/// comma. Where bounds are optionally passed in braces after the implementing type.
///
/// The example from the [crate level documentation](crate) can be written manually like this:
/// ```
/// use generic_upper_bound as gub;
/// pub trait MyTrait {
/// const SOME_STR: &'static str;
/// }
/// impl<A: MyTrait, B: MyTrait> MyTrait for (A, B) {
/// const SOME_STR: &'static str = match core::str::from_utf8(
/// gub::eval_with_upper_bound::<Concat<A, B>>()
/// .split_at(gub::desired_generic::<Concat<A, B>>())
/// .0,
/// ) {
/// Ok(s) => s,
/// _ => unreachable!(),
/// };
/// }
///
/// struct Concat<A, B>(A, B);
/// impl<A: MyTrait, B: MyTrait> gub::AcceptUpperBound for Concat<A, B> {
/// type Output = &'static [u8];
/// // Want to be passed at least the total length of the strings
/// const DESIRED_GENERIC: usize = A::SOME_STR.len() + B::SOME_STR.len();
/// // Decide on what to do with each generic const
/// type Eval<const UPPER: usize> = ConcatImpl<A, B, UPPER>;
/// }
/// struct ConcatImpl<A, B, const N: usize>(A, B);
/// impl<A: MyTrait, B: MyTrait, const N: usize> gub::Const for ConcatImpl<A, B, N> {
/// type Type = &'static [u8];
/// const VALUE: Self::Type = panic!("...");
/// }
/// ```
$Self:ty $?;
const DESIRED_GENERIC: $usize_d:ty = $DESIRED_GENERIC:expr;
const : $Output:ty = $EVAL:expr;
} => ;
}