1use num_traits::{Saturating, NumCast, Num};
17use std::ops::{Mul, Div, Add, Sub};
18use std::marker::PhantomData;
19
20use {Color, FloatColor};
21use {Channel, FloatChannel};
22use {Hsv, ToHsv};
23use {ToRgb, Rgb};
24use alpha::{ToRgba, Rgba};
25use color_space::{Srgb, TransferFunction};
26
27
28#[derive(Serialize, Deserialize, Debug)]
29pub struct Luma<T, S = Srgb> { pub l: T, pub standard: PhantomData<S> }
30
31impl<T: Clone, S> Clone for Luma<T, S>{
32 fn clone(&self) -> Luma<T, S>{
33 Luma{ l: self.l.clone(), standard: PhantomData }
34 }
35}
36
37impl<T: Copy, S> Copy for Luma<T, S>{}
38
39impl<N: PartialEq, S> PartialEq for Luma<N, S>{
40 #[inline]
41 fn eq(&self, other: &Luma<N, S>) -> bool{
42 self.l.eq(&other.l)
43 }
44}
45
46impl<N: Clone + PartialEq + Eq + Num + NumCast, S> Eq for Luma<N, S>{}
47
48impl<T, S> Luma<T, S> {
49 pub const fn new(l: T) -> Luma<T, S> {
50 Luma { l, standard: PhantomData }
51 }
52}
53
54impl<T:Channel, S> Luma<T, S> {
55 pub fn from_hex(hex: u8) -> Luma<T> {
56 Luma::<u8>::new(hex).to_luma()
57 }
58}
59
60impl<T:Channel, S> Color<T> for Luma<T, S> {
61 #[inline]
63 fn clamp_s(self, lo: T, hi: T) -> Luma<T,S> {
64 Luma::new(self.l.clamp(lo, hi))
65 }
66
67 #[inline]
69 fn clamp_c(self, lo: Luma<T,S>, hi: Luma<T,S>) -> Luma<T,S> {
70 Luma::new(self.l.clamp(lo.l, hi.l))
71 }
72
73 #[inline]
75 fn inverse(self) -> Luma<T,S> {
76 Luma::new(self.l.invert_channel())
77 }
78
79 #[inline]
80 fn mix(self, other: Self, value: T) -> Self {
81 Luma::new(self.l.mix(other.l, value))
82 }
83}
84
85impl<T:FloatChannel, S> FloatColor<T> for Luma<T, S> {
86 #[inline]
88 fn saturate(self) -> Luma<T, S> {
89 Luma::new(self.l.saturate())
90 }
91}
92
93pub trait ToLuma {
94 type Standard: TransferFunction;
95 fn to_luma<U:Channel>(&self) -> Luma<U, Self::Standard>;
96}
97
98impl ToLuma for u8 {
99 type Standard = Srgb;
100 fn to_luma<U: Channel>(&self) -> Luma<U, Srgb> {
101 Luma::new(Channel::from(*self))
102 }
103}
104
105impl<T: Channel, S: TransferFunction> ToLuma for Luma<T, S> {
106 type Standard = S;
107 fn to_luma<U: Channel>(&self) -> Luma<U, S> {
108 Luma::new(Channel::from(self.l))
109 }
110}
111
112impl<T:Clone + Channel, S: TransferFunction> ToRgb for Luma<T, S> {
113 type Standard = S;
114 #[inline]
115 fn to_rgb<U:Channel>(&self) -> Rgb<U, S> {
116 let r = self.l.to_channel();
117 Rgb::new(r, r, r)
118 }
119}
120
121impl<T:Clone + Channel, S: TransferFunction> ToRgba for Luma<T, S> {
122 type Standard = S;
123 #[inline]
124 fn to_rgba<U:Channel>(&self) -> Rgba<U, S> {
125 let r = self.l.to_channel();
126 Rgba::new(Rgb::new(r, r, r), 1f32.to_channel())
127 }
128}
129
130impl<T:Channel + NumCast + Num, S: TransferFunction> ToHsv for Luma<T,S> {
131 type Standard = S;
132 #[inline]
133 fn to_hsv<U:Channel + NumCast + Num>(&self) -> Hsv<U, S> {
134 self.to_rgb::<U>().to_hsv()
135 }
136}
137
138impl<T:Channel, S> Mul for Luma<T, S> {
139 type Output = Luma<T, S>;
140
141 #[inline]
142 fn mul(self, rhs: Luma<T, S>) -> Luma<T, S> {
143 Luma::new(self.l.normalized_mul(rhs.l))
144 }
145}
146
147impl<T:Channel + Mul<T,Output=T>, S> Mul<T> for Luma<T, S> {
148 type Output = Luma<T, S>;
149
150 #[inline]
151 fn mul(self, rhs: T) -> Luma<T, S> {
152 Luma::new(self.l * rhs)
153 }
154}
155
156
157impl<T:Channel, S> Div for Luma<T, S> {
158 type Output = Luma<T, S>;
159
160 #[inline]
161 fn div(self, rhs: Luma<T, S>) -> Luma<T, S> {
162 Luma::new(self.l.normalized_div(rhs.l))
163 }
164}
165
166impl<T:Channel + Div<T,Output=T>, S> Div<T> for Luma<T, S> {
167 type Output = Luma<T, S>;
168
169 #[inline]
170 fn div(self, rhs: T) -> Luma<T, S> {
171 Luma::new(self.l / rhs)
172 }
173}
174
175impl<T:Channel + Add<T,Output=T>, S> Add for Luma<T, S> {
176 type Output = Luma<T, S>;
177
178 #[inline]
179 fn add(self, rhs: Luma<T, S>) -> Luma<T, S> {
180 Luma::new(self.l + rhs.l)
181 }
182}
183
184impl<T:Channel + Sub<T,Output=T>, S> Sub for Luma<T, S> {
185 type Output = Luma<T, S>;
186
187 #[inline]
188 fn sub(self, rhs: Luma<T, S>) -> Luma<T, S> {
189 Luma::new(self.l - rhs.l)
190 }
191}
192
193impl<T:Channel + Saturating, S> Saturating for Luma<T, S> {
194 fn saturating_add(self, v: Luma<T, S>) -> Luma<T, S> {
195 Luma::new(self.l.saturating_add(v.l))
196 }
197
198 fn saturating_sub(self, v: Luma<T, S>) -> Luma<T, S> {
199 Luma::new(self.l.saturating_sub(v.l))
200 }
201}