Coverage Report

Created: 2025-07-23 06:21

/rust/registry/src/index.crates.io-6f17d22bba15001f/nu-ansi-term-0.49.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::u32;
4
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5
pub struct Rgb {
6
    /// Red
7
    pub r: u8,
8
    /// Green
9
    pub g: u8,
10
    /// Blue
11
    pub b: u8,
12
}
13
14
impl Rgb {
15
    /// Creates a new [Rgb] color
16
    #[inline]
17
0
    pub const fn new(r: u8, g: u8, b: u8) -> Self {
18
0
        Self { r, g, b }
19
0
    }
20
21
    /// Creates a new [Rgb] color with a hex code
22
    #[inline]
23
0
    pub const fn from_hex(hex: u32) -> Self {
24
0
        Self::new((hex >> 16) as u8, (hex >> 8) as u8, hex as u8)
25
0
    }
26
27
0
    pub fn from_hex_string(hex: String) -> Self {
28
0
        if hex.chars().count() == 8 && hex.starts_with("0x") {
29
            // eprintln!("hex:{:?}", hex);
30
0
            let (_, value_string) = hex.split_at(2);
31
0
            // eprintln!("value_string:{:?}", value_string);
32
0
            let int_val = u64::from_str_radix(value_string, 16);
33
0
            match int_val {
34
0
                Ok(num) => Self::new(
35
0
                    ((num & 0xff0000) >> 16) as u8,
36
0
                    ((num & 0xff00) >> 8) as u8,
37
0
                    (num & 0xff) as u8,
38
0
                ),
39
                // Don't fail, just make the color black
40
                // Should we fail?
41
0
                _ => Self::new(0, 0, 0),
42
            }
43
        } else {
44
            // Don't fail, just make the color black.
45
            // Should we fail?
46
0
            Self::new(0, 0, 0)
47
        }
48
0
    }
49
50
    /// Creates a new [Rgb] color with three [f32] values
51
0
    pub fn from_f32(r: f32, g: f32, b: f32) -> Self {
52
0
        Self::new(
53
0
            (r.clamp(0.0, 1.0) * 255.0) as u8,
54
0
            (g.clamp(0.0, 1.0) * 255.0) as u8,
55
0
            (b.clamp(0.0, 1.0) * 255.0) as u8,
56
0
        )
57
0
    }
58
59
    /// Creates a grayscale [Rgb] color
60
    #[inline]
61
0
    pub const fn gray(x: u8) -> Self {
62
0
        Self::new(x, x, x)
63
0
    }
64
65
    /// Creates a grayscale [Rgb] color with a [f32] value
66
0
    pub fn gray_f32(x: f32) -> Self {
67
0
        Self::from_f32(x, x, x)
68
0
    }
69
70
    /// Creates a new [Rgb] color from a [HSL] color
71
    // pub fn from_hsl(hsl: HSL) -> Self {
72
    //     if hsl.s == 0.0 {
73
    //         return Self::gray_f32(hsl.l);
74
    //     }
75
76
    //     let q = if hsl.l < 0.5 {
77
    //         hsl.l * (1.0 + hsl.s)
78
    //     } else {
79
    //         hsl.l + hsl.s - hsl.l * hsl.s
80
    //     };
81
    //     let p = 2.0 * hsl.l - q;
82
    //     let h2c = |t: f32| {
83
    //         let t = t.clamp(0.0, 1.0);
84
    //         if 6.0 * t < 1.0 {
85
    //             p + 6.0 * (q - p) * t
86
    //         } else if t < 0.5 {
87
    //             q
88
    //         } else if 1.0 < 1.5 * t {
89
    //             p + 6.0 * (q - p) * (1.0 / 1.5 - t)
90
    //         } else {
91
    //             p
92
    //         }
93
    //     };
94
95
    //     Self::from_f32(h2c(hsl.h + 1.0 / 3.0), h2c(hsl.h), h2c(hsl.h - 1.0 / 3.0))
96
    // }
97
98
    /// Computes the linear interpolation between `self` and `other` for `t`
99
0
    pub fn lerp(&self, other: Self, t: f32) -> Self {
100
0
        let t = t.clamp(0.0, 1.0);
101
0
        self * (1.0 - t) + other * t
102
0
    }
103
}
104
105
impl From<(u8, u8, u8)> for Rgb {
106
0
    fn from((r, g, b): (u8, u8, u8)) -> Self {
107
0
        Self::new(r, g, b)
108
0
    }
109
}
110
111
impl From<(f32, f32, f32)> for Rgb {
112
0
    fn from((r, g, b): (f32, f32, f32)) -> Self {
113
0
        Self::from_f32(r, g, b)
114
0
    }
115
}
116
117
use crate::ANSIColorCode;
118
use crate::TargetGround;
119
impl ANSIColorCode for Rgb {
120
0
    fn ansi_color_code(&self, target: TargetGround) -> String {
121
0
        format!("{};2;{};{};{}", target.code() + 8, self.r, self.g, self.b)
122
0
    }
123
}
124
125
0
const fn rgb_add(lhs: &Rgb, rhs: &Rgb) -> Rgb {
126
0
    Rgb::new(
127
0
        lhs.r.saturating_add(rhs.r),
128
0
        lhs.g.saturating_add(rhs.g),
129
0
        lhs.b.saturating_add(rhs.b),
130
0
    )
131
0
}
132
133
0
const fn rgb_sub(lhs: &Rgb, rhs: &Rgb) -> Rgb {
134
0
    Rgb::new(
135
0
        lhs.r.saturating_sub(rhs.r),
136
0
        lhs.g.saturating_sub(rhs.g),
137
0
        lhs.b.saturating_sub(rhs.b),
138
0
    )
139
0
}
140
141
0
fn rgb_mul_f32(lhs: &Rgb, rhs: &f32) -> Rgb {
142
0
    Rgb::new(
143
0
        (lhs.r as f32 * rhs.clamp(0.0, 1.0)) as u8,
144
0
        (lhs.g as f32 * rhs.clamp(0.0, 1.0)) as u8,
145
0
        (lhs.b as f32 * rhs.clamp(0.0, 1.0)) as u8,
146
0
    )
147
0
}
148
149
0
const fn rgb_negate(rgb: &Rgb) -> Rgb {
150
0
    Rgb::new(255 - rgb.r, 255 - rgb.g, 255 - rgb.b)
151
0
}
152
153
impl std::ops::Add<Rgb> for Rgb {
154
    type Output = Rgb;
155
156
0
    fn add(self, rhs: Rgb) -> Self::Output {
157
0
        rgb_add(&self, &rhs)
158
0
    }
159
}
160
161
impl std::ops::Add<&Rgb> for Rgb {
162
    type Output = Rgb;
163
164
0
    fn add(self, rhs: &Rgb) -> Self::Output {
165
0
        rgb_add(&self, rhs)
166
0
    }
167
}
168
169
impl std::ops::Add<Rgb> for &Rgb {
170
    type Output = Rgb;
171
172
0
    fn add(self, rhs: Rgb) -> Self::Output {
173
0
        rgb_add(self, &rhs)
174
0
    }
175
}
176
177
impl std::ops::Add<&Rgb> for &Rgb {
178
    type Output = Rgb;
179
180
0
    fn add(self, rhs: &Rgb) -> Self::Output {
181
0
        rgb_add(self, rhs)
182
0
    }
183
}
184
185
impl std::ops::Sub<Rgb> for Rgb {
186
    type Output = Rgb;
187
188
0
    fn sub(self, rhs: Rgb) -> Self::Output {
189
0
        rgb_sub(&self, &rhs)
190
0
    }
191
}
192
193
impl std::ops::Sub<&Rgb> for Rgb {
194
    type Output = Rgb;
195
196
0
    fn sub(self, rhs: &Rgb) -> Self::Output {
197
0
        rgb_sub(&self, rhs)
198
0
    }
199
}
200
201
impl std::ops::Sub<Rgb> for &Rgb {
202
    type Output = Rgb;
203
204
0
    fn sub(self, rhs: Rgb) -> Self::Output {
205
0
        rgb_sub(self, &rhs)
206
0
    }
207
}
208
209
impl std::ops::Sub<&Rgb> for &Rgb {
210
    type Output = Rgb;
211
212
0
    fn sub(self, rhs: &Rgb) -> Self::Output {
213
0
        rgb_sub(self, rhs)
214
0
    }
215
}
216
217
impl std::ops::Mul<f32> for Rgb {
218
    type Output = Rgb;
219
220
0
    fn mul(self, rhs: f32) -> Self::Output {
221
0
        rgb_mul_f32(&self, &rhs)
222
0
    }
223
}
224
225
impl std::ops::Mul<&f32> for Rgb {
226
    type Output = Rgb;
227
228
0
    fn mul(self, rhs: &f32) -> Self::Output {
229
0
        rgb_mul_f32(&self, rhs)
230
0
    }
231
}
232
233
impl std::ops::Mul<f32> for &Rgb {
234
    type Output = Rgb;
235
236
0
    fn mul(self, rhs: f32) -> Self::Output {
237
0
        rgb_mul_f32(self, &rhs)
238
0
    }
239
}
240
241
impl std::ops::Mul<&f32> for &Rgb {
242
    type Output = Rgb;
243
244
0
    fn mul(self, rhs: &f32) -> Self::Output {
245
0
        rgb_mul_f32(self, rhs)
246
0
    }
247
}
248
249
impl std::ops::Mul<Rgb> for f32 {
250
    type Output = Rgb;
251
252
0
    fn mul(self, rhs: Rgb) -> Self::Output {
253
0
        rgb_mul_f32(&rhs, &self)
254
0
    }
255
}
256
257
impl std::ops::Mul<&Rgb> for f32 {
258
    type Output = Rgb;
259
260
0
    fn mul(self, rhs: &Rgb) -> Self::Output {
261
0
        rgb_mul_f32(rhs, &self)
262
0
    }
263
}
264
265
impl std::ops::Mul<Rgb> for &f32 {
266
    type Output = Rgb;
267
268
0
    fn mul(self, rhs: Rgb) -> Self::Output {
269
0
        rgb_mul_f32(&rhs, self)
270
0
    }
271
}
272
273
impl std::ops::Mul<&Rgb> for &f32 {
274
    type Output = Rgb;
275
276
0
    fn mul(self, rhs: &Rgb) -> Self::Output {
277
0
        rgb_mul_f32(rhs, self)
278
0
    }
279
}
280
281
impl std::ops::Neg for Rgb {
282
    type Output = Rgb;
283
284
0
    fn neg(self) -> Self::Output {
285
0
        rgb_negate(&self)
286
0
    }
287
}
288
289
impl std::ops::Neg for &Rgb {
290
    type Output = Rgb;
291
292
0
    fn neg(self) -> Self::Output {
293
0
        rgb_negate(self)
294
0
    }
295
}