Coverage Report

Created: 2025-07-12 06:22

/rust/registry/src/index.crates.io-6f17d22bba15001f/nu-ansi-term-0.46.0/src/rgb.rs
Line
Count
Source (jump to first uncovered line)
1
// Code liberally borrowed from here
2
// https://github.com/navierr/coloriz
3
use std::ops;
4
use std::u32;
5
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6
pub struct Rgb {
7
    /// Red
8
    pub r: u8,
9
    /// Green
10
    pub g: u8,
11
    /// Blue
12
    pub b: u8,
13
}
14
15
impl Rgb {
16
    /// Creates a new [Rgb] color
17
    #[inline]
18
0
    pub const fn new(r: u8, g: u8, b: u8) -> Self {
19
0
        Self { r, g, b }
20
0
    }
21
22
    /// Creates a new [Rgb] color with a hex code
23
    #[inline]
24
0
    pub const fn from_hex(hex: u32) -> Self {
25
0
        Self::new((hex >> 16) as u8, (hex >> 8) as u8, hex as u8)
26
0
    }
27
28
0
    pub fn from_hex_string(hex: String) -> Self {
29
0
        if hex.chars().count() == 8 && hex.starts_with("0x") {
30
            // eprintln!("hex:{:?}", hex);
31
0
            let (_, value_string) = hex.split_at(2);
32
0
            // eprintln!("value_string:{:?}", value_string);
33
0
            let int_val = u64::from_str_radix(value_string, 16);
34
0
            match int_val {
35
0
                Ok(num) => Self::new(
36
0
                    ((num & 0xff0000) >> 16) as u8,
37
0
                    ((num & 0xff00) >> 8) as u8,
38
0
                    (num & 0xff) as u8,
39
0
                ),
40
                // Don't fail, just make the color black
41
                // Should we fail?
42
0
                _ => Self::new(0, 0, 0),
43
            }
44
        } else {
45
            // Don't fail, just make the color black.
46
            // Should we fail?
47
0
            Self::new(0, 0, 0)
48
        }
49
0
    }
50
51
    /// Creates a new [Rgb] color with three [f32] values
52
0
    pub fn from_f32(r: f32, g: f32, b: f32) -> Self {
53
0
        Self::new(
54
0
            (r.clamp(0.0, 1.0) * 255.0) as u8,
55
0
            (g.clamp(0.0, 1.0) * 255.0) as u8,
56
0
            (b.clamp(0.0, 1.0) * 255.0) as u8,
57
0
        )
58
0
    }
59
60
    /// Creates a grayscale [Rgb] color
61
    #[inline]
62
0
    pub const fn gray(x: u8) -> Self {
63
0
        Self::new(x, x, x)
64
0
    }
65
66
    /// Creates a grayscale [Rgb] color with a [f32] value
67
0
    pub fn gray_f32(x: f32) -> Self {
68
0
        Self::from_f32(x, x, x)
69
0
    }
70
71
    /// Creates a new [Rgb] color from a [HSL] color
72
    // pub fn from_hsl(hsl: HSL) -> Self {
73
    //     if hsl.s == 0.0 {
74
    //         return Self::gray_f32(hsl.l);
75
    //     }
76
77
    //     let q = if hsl.l < 0.5 {
78
    //         hsl.l * (1.0 + hsl.s)
79
    //     } else {
80
    //         hsl.l + hsl.s - hsl.l * hsl.s
81
    //     };
82
    //     let p = 2.0 * hsl.l - q;
83
    //     let h2c = |t: f32| {
84
    //         let t = t.clamp(0.0, 1.0);
85
    //         if 6.0 * t < 1.0 {
86
    //             p + 6.0 * (q - p) * t
87
    //         } else if t < 0.5 {
88
    //             q
89
    //         } else if 1.0 < 1.5 * t {
90
    //             p + 6.0 * (q - p) * (1.0 / 1.5 - t)
91
    //         } else {
92
    //             p
93
    //         }
94
    //     };
95
96
    //     Self::from_f32(h2c(hsl.h + 1.0 / 3.0), h2c(hsl.h), h2c(hsl.h - 1.0 / 3.0))
97
    // }
98
99
    /// Computes the linear interpolation between `self` and `other` for `t`
100
0
    pub fn lerp(&self, other: Self, t: f32) -> Self {
101
0
        let t = t.clamp(0.0, 1.0);
102
0
        self * (1.0 - t) + other * t
103
0
    }
104
}
105
106
impl From<(u8, u8, u8)> for Rgb {
107
0
    fn from((r, g, b): (u8, u8, u8)) -> Self {
108
0
        Self::new(r, g, b)
109
0
    }
110
}
111
112
impl From<(f32, f32, f32)> for Rgb {
113
0
    fn from((r, g, b): (f32, f32, f32)) -> Self {
114
0
        Self::from_f32(r, g, b)
115
0
    }
116
}
117
118
use crate::ANSIColorCode;
119
use crate::TargetGround;
120
impl ANSIColorCode for Rgb {
121
0
    fn ansi_color_code(&self, target: TargetGround) -> String {
122
0
        format!("{};2;{};{};{}", target.code() + 8, self.r, self.g, self.b)
123
0
    }
124
}
125
126
overload::overload!(
127
    (lhs: ?Rgb) + (rhs: ?Rgb) -> Rgb {
128
        Rgb::new(
129
            lhs.r.saturating_add(rhs.r),
130
            lhs.g.saturating_add(rhs.g),
131
            lhs.b.saturating_add(rhs.b)
132
        )
133
    }
134
);
135
136
overload::overload!(
137
    (lhs: ?Rgb) - (rhs: ?Rgb) -> Rgb {
138
        Rgb::new(
139
            lhs.r.saturating_sub(rhs.r),
140
            lhs.g.saturating_sub(rhs.g),
141
            lhs.b.saturating_sub(rhs.b)
142
        )
143
    }
144
);
145
146
overload::overload!(
147
    (lhs: ?Rgb) * (rhs: ?f32) -> Rgb {
148
        Rgb::new(
149
            (lhs.r as f32 * rhs.clamp(0.0, 1.0)) as u8,
150
            (lhs.g as f32 * rhs.clamp(0.0, 1.0)) as u8,
151
            (lhs.b as f32 * rhs.clamp(0.0, 1.0)) as u8
152
        )
153
    }
154
);
155
156
overload::overload!(
157
    (lhs: ?f32) * (rhs: ?Rgb) -> Rgb {
158
        Rgb::new(
159
            (rhs.r as f32 * lhs.clamp(0.0, 1.0)) as u8,
160
            (rhs.g as f32 * lhs.clamp(0.0, 1.0)) as u8,
161
            (rhs.b as f32 * lhs.clamp(0.0, 1.0)) as u8
162
        )
163
    }
164
);
165
166
overload::overload!(
167
    -(rgb: ?Rgb) -> Rgb {
168
        Rgb::new(
169
            255 - rgb.r,
170
            255 - rgb.g,
171
            255 - rgb.b)
172
    }
173
);