1use hsluv::hsluv_to_rgb;
8use sha1::{Digest, Sha1};
9
10fn str_to_angle(s: &str) -> f64 {
12 let bytes = s.as_bytes();
13 let result = Sha1::digest(bytes);
14 let checksum: u16 = result.first().map_or(0, |&x| u16::from(x))
15 + 256 * result.get(1).map_or(0, |&x| u16::from(x));
16 f64::from(checksum) / 65536.0 * 360.0
17}
18
19fn rgb_to_u32((r, g, b): (f64, f64, f64)) -> u32 {
24 let r = ((r * 256.0) as u32).min(255);
25 let g = ((g * 256.0) as u32).min(255);
26 let b = ((b * 256.0) as u32).min(255);
27 65536 * r + 256 * g + b
28}
29
30pub fn str_to_color(s: &str) -> u32 {
35 rgb_to_u32(hsluv_to_rgb((str_to_angle(s), 100.0, 50.0)))
36}
37
38pub fn color_int_to_hex_string(color: u32) -> String {
40 format!("{color:#08x}").replace("0x", "#")
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn test_str_to_angle() {
49 assert!((str_to_angle("Romeo") - 327.255249).abs() < 1e-6);
52 assert!((str_to_angle("juliet@capulet.lit") - 209.410400).abs() < 1e-6);
53 assert!((str_to_angle("😺") - 331.199341).abs() < 1e-6);
54 assert!((str_to_angle("council") - 359.994507).abs() < 1e-6);
55 assert!((str_to_angle("Board") - 171.430664).abs() < 1e-6);
56 }
57
58 #[test]
59 fn test_rgb_to_u32() {
60 assert_eq!(rgb_to_u32((0.0, 0.0, 0.0)), 0);
61 assert_eq!(rgb_to_u32((1.0, 1.0, 1.0)), 0xffffff);
62 assert_eq!(rgb_to_u32((0.0, 0.0, 1.0)), 0x0000ff);
63 assert_eq!(rgb_to_u32((0.0, 1.0, 0.0)), 0x00ff00);
64 assert_eq!(rgb_to_u32((1.0, 0.0, 0.0)), 0xff0000);
65 assert_eq!(rgb_to_u32((1.0, 0.5, 0.0)), 0xff8000);
66 }
67}