libnotcurses_sys/
rgb.rs

1//!
2
3use c_api::{NcRgb_u32, NcRgba_u32};
4
5/// 24 bits broken into 3x RGB components.
6///
7/// Unlike with [`NcChannel`], operations involving `NcRgb`
8/// ignores the last 4th byte (the alpha component).
9///
10/// ## Diagram
11///
12/// ```txt
13/// -------- RRRRRRRR GGGGGGGG BBBBBBBB
14/// ```
15/// `type in C: no data type`
16///
17/// See also: [`NcRgba`] and [`NcChannel`] types.
18///
19/// [`NcChannel`]: crate::NcChannel
20#[repr(transparent)]
21#[derive(Clone, Copy, Default, PartialEq, Eq)]
22pub struct NcRgb(pub c_api::NcRgb_u32);
23impl NcRgb {
24    /// New const RGB color.
25    pub const fn new(r: u8, g: u8, b: u8) -> Self {
26        Self((r as NcRgb_u32) << 16 | (g as NcRgb_u32) << 8 | b as NcRgb_u32)
27    }
28}
29
30/// 32 bits broken into 3x RGB components + alpha component.
31///
32/// ## Diagram
33///
34/// ```txt
35/// AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
36/// ```
37/// `type in C: no data type`
38///
39/// See also: [`NcRgb`] and [`NcChannel`] types.
40///
41/// [`NcRgba`]: crate::NcRgba
42/// [`NcChannel`]: crate::NcChannel
43#[repr(transparent)]
44#[derive(Clone, Copy, Default, PartialEq, Eq)]
45pub struct NcRgba(pub c_api::NcRgba_u32);
46impl NcRgba {
47    /// New const RGBA color.
48    pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
49        Self(
50            (a as NcRgba_u32) << 24
51                | (r as NcRgba_u32) << 16
52                | (g as NcRgba_u32) << 8
53                | b as NcRgba_u32,
54        )
55    }
56}
57mod core_impls {
58    use super::{
59        c_api::{NcRgb_u32, NcRgba_u32},
60        NcRgb, NcRgba,
61    };
62    use core::fmt;
63
64    crate::from_primitive![NcRgb, NcRgb_u32];
65    crate::unit_impl_from![NcRgb, NcRgb_u32];
66    crate::unit_impl_fmt![bases; NcRgb];
67
68    impl fmt::Display for NcRgb {
69        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70            write!(f, "{self:06X}")
71        }
72    }
73    impl fmt::Debug for NcRgb {
74        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75            write!(f, "NcRgb({self})")
76        }
77    }
78
79    impl From<[u8; 3]> for NcRgb {
80        fn from(array: [u8; 3]) -> Self {
81            // u32::from_be_bytes(array).into()
82            Self(
83                (array[0] as NcRgb_u32) << 16
84                    | (array[1] as NcRgb_u32) << 8
85                    | array[2] as NcRgb_u32,
86            )
87        }
88    }
89    impl From<&[u8; 3]> for NcRgb {
90        fn from(array: &[u8; 3]) -> Self {
91            Self(
92                (array[0] as NcRgb_u32) << 16
93                    | (array[1] as NcRgb_u32) << 8
94                    | array[2] as NcRgb_u32,
95            )
96        }
97    }
98    impl From<NcRgb> for [u8; 3] {
99        #[inline]
100        fn from(rgb: NcRgb) -> Self {
101            [
102                ((rgb.0 & 0xff0000) >> 16) as u8,
103                ((rgb.0 & 0x00ff00) >> 8) as u8,
104                (rgb.0 & 0x0000ff) as u8,
105            ]
106        }
107    }
108    impl From<NcRgb> for (u8, u8, u8) {
109        #[inline]
110        fn from(rgb: NcRgb) -> Self {
111            (
112                ((rgb.0 & 0xff0000) >> 16) as u8,
113                ((rgb.0 & 0x00ff00) >> 8) as u8,
114                (rgb.0 & 0x0000ff) as u8,
115            )
116        }
117    }
118    impl From<(u8, u8, u8)> for NcRgb {
119        fn from(tuple: (u8, u8, u8)) -> Self {
120            Self((tuple.0 as NcRgb_u32) << 16 | (tuple.1 as NcRgb_u32) << 8 | tuple.2 as NcRgb_u32)
121        }
122    }
123
124    //
125
126    crate::from_primitive![NcRgba, NcRgba_u32];
127    crate::unit_impl_from![NcRgba, NcRgba_u32];
128    crate::unit_impl_fmt![bases; NcRgba];
129
130    impl fmt::Display for NcRgba {
131        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132            write!(f, "{self:08X}")
133        }
134    }
135    impl fmt::Debug for NcRgba {
136        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137            write!(f, "NcRgba({self})")
138        }
139    }
140
141    /// [R, G, B, A]
142    impl From<[u8; 4]> for NcRgba {
143        fn from(array: [u8; 4]) -> Self {
144            u32::from_be_bytes(array).into()
145        }
146    }
147    impl From<&[u8; 4]> for NcRgba {
148        fn from(array: &[u8; 4]) -> Self {
149            u32::from_be_bytes(*array).into()
150        }
151    }
152    /// [R, G, B, A]
153    impl From<NcRgba> for [u8; 4] {
154        #[inline]
155        fn from(rgba: NcRgba) -> Self {
156            rgba.0.to_be_bytes()
157        }
158    }
159
160    /// (R, G, B, A)
161    impl From<(u8, u8, u8, u8)> for NcRgba {
162        fn from(tuple: (u8, u8, u8, u8)) -> Self {
163            u32::from_be_bytes([tuple.0, tuple.1, tuple.2, tuple.3]).into()
164        }
165    }
166    /// (R, G, B, A)
167    impl From<NcRgba> for (u8, u8, u8, u8) {
168        #[inline]
169        fn from(rgba: NcRgba) -> Self {
170            let a = rgba.0.to_be_bytes();
171            (a[0], a[1], a[2], a[3])
172        }
173    }
174
175    #[cfg(test)]
176    mod test {
177        use super::{NcRgb, NcRgba};
178
179        #[test]
180        fn rgbx_from() {
181            let rgb = NcRgb(0x112233_u32);
182            let rgb_arr = [0x11, 0x22, 0x33];
183            let rgb_tup = (0x11, 0x22, 0x33);
184
185            assert_eq!(rgb, NcRgb::from(rgb_arr));
186            assert_eq!(rgb, NcRgb::from(rgb_tup));
187            assert_eq!(rgb_arr, <[u8; 3]>::from(rgb));
188            assert_eq!(rgb_tup, <(u8, u8, u8)>::from(rgb));
189
190            let rgba = NcRgba(0x112233AA_u32);
191            let rgba_arr = [0x11, 0x22, 0x33, 0xAA];
192            let rgba_tup = (0x11, 0x22, 0x33, 0xAA);
193
194            assert_eq!(rgba, NcRgba::from(rgba_arr));
195            assert_eq!(rgba, NcRgba::from(rgba_tup));
196            assert_eq!(rgba_arr, <[u8; 4]>::from(rgba));
197            assert_eq!(rgba_tup, <(u8, u8, u8, u8)>::from(rgba));
198        }
199    }
200}
201
202pub(crate) mod c_api {
203    /// 24 bits broken into 3x RGB components.
204    ///
205    /// It's recommended to use [`NcRgb`] instead.
206    ///
207    /// Unlike with [`NcChannel_u32`], operations involving `NcRgb_u32`
208    /// ignores the last 4th byte (the alpha component).
209    ///
210    /// ## Diagram
211    ///
212    /// ```txt
213    /// -------- RRRRRRRR GGGGGGGG BBBBBBBB
214    /// ```
215    /// `type in C: no data type`
216    ///
217    /// See also: [`NcRgba_u32`] and [`NcChannel_u32`] types.
218    ///
219    /// [`NcRgb`]: crate::NcRgb
220    /// [`NcChannel_u32`]: crate::c_api::NcChannel_u32
221    pub type NcRgb_u32 = u32;
222
223    /// 32 bits broken into 3x RGB components plus one alpha component.
224    ///
225    /// It's recommended to use [`NcRgba`] instead.
226    ///
227    /// ## Diagram
228    ///
229    /// ```txt
230    /// AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
231    /// ```
232    /// `type in C: no data type`
233    ///
234    /// See also: [`NcRgb_u32`] and [`NcChannel_u32`] types.
235    ///
236    /// [`NcRgba`]: crate::NcRgba
237    /// [`NcChannel_u32`]: crate::c_api::NcChannel_u32
238    pub type NcRgba_u32 = u32;
239
240    // MAYBE?
241    // // NcBgra
242    // //
243    // /// 32 bits broken into 3x 8bpp BGR channels + 8ppp alpha.
244    // ///
245    // /// ## Diagram
246    // ///
247    // /// ```txt
248    // /// AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR
249    // /// ```
250    // ///
251    // /// `type in C: no data type`
252    // ///
253    // /// See also: [`NcRgba`], [`NcRgb`] and [`NcChannel`] types.
254    // pub type NcBgra = u32;
255}