Skip to content

Commit 67ed903

Browse files
Swiftb0yzesterer
authored andcommitted
feat: make ColorGenerator const friendly
This allows precomputing a set of colors ahead of time (for people that are into that). To avoid generating the same colors for each instance, users can leverage the `const_random` crate to properly seed their generator. I don't actually know how useful this is. I just saw a "constexpr all the things" opportunity and wanted to see if there was anything obvious preventing this. One usecase I could think about is users wanting to generate a couple colors ahead of time, give each one semantic meaning and then use their meaning consistently. Something like this: ```rust struct ColorPalette { types: Color, identifiers: Color, other: Color, } const COLORS: ColorPalette = { let mut gen = ColorGenerator::new(); ColorPalette { types: gen.next(), identifiers: gen.next(), others: gen.next(), } } ```
1 parent 596665a commit 67ed903

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

src/draw.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -223,32 +223,35 @@ pub struct ColorGenerator {
223223

224224
impl Default for ColorGenerator {
225225
fn default() -> Self {
226-
Self::from_state([30000, 15000, 35000], 0.5)
226+
Self::new()
227227
}
228228
}
229229

230230
impl ColorGenerator {
231231
/// Create a new [`ColorGenerator`] with the given pre-chosen state.
232232
///
233233
/// The minimum brightness can be used to control the colour brightness (0.0 - 1.0). The default is 0.5.
234-
pub fn from_state(state: [u16; 3], min_brightness: f32) -> Self {
234+
pub const fn from_state(state: [u16; 3], min_brightness: f32) -> Self {
235235
Self {
236236
state,
237237
min_brightness: min_brightness.max(0.0).min(1.0),
238238
}
239239
}
240240

241241
/// Create a new [`ColorGenerator`] with the default state.
242-
pub fn new() -> Self {
243-
Self::default()
242+
pub const fn new() -> Self {
243+
Self::from_state([30000, 15000, 35000], 0.5)
244244
}
245245

246246
/// Generate the next colour in the sequence.
247247
#[allow(clippy::should_implement_trait)]
248-
pub fn next(&mut self) -> Color {
249-
for i in 0..3 {
248+
pub const fn next(&mut self) -> Color {
249+
// `for i in n..m` not supported in const fn, so workaround that
250+
let mut i = 0;
251+
while i < 3 {
250252
// magic constant, one of only two that have this property!
251253
self.state[i] = (self.state[i] as usize).wrapping_add(40503 * (i * 4 + 1130)) as u16;
254+
i += 1;
252255
}
253256
Color::Fixed(
254257
16 + ((self.state[2] as f32 / 65535.0 * (1.0 - self.min_brightness)
@@ -263,3 +266,19 @@ impl ColorGenerator {
263266
)
264267
}
265268
}
269+
270+
#[cfg(test)]
271+
mod tests {
272+
use super::*;
273+
274+
#[test]
275+
fn const_colors() {
276+
const COLORS: [Color; 3] = {
277+
let mut gen = ColorGenerator::new();
278+
[gen.next(), gen.next(), gen.next()]
279+
};
280+
assert_ne!(COLORS[0], COLORS[1]);
281+
assert_ne!(COLORS[1], COLORS[2]);
282+
assert_ne!(COLORS[2], COLORS[0]);
283+
}
284+
}

0 commit comments

Comments
 (0)