1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
//! Macros for the common implementation of color type methods
//!
//! These are used internally and not exposed.

macro_rules! impl_channel_clamp {
    ($name: ident, $param: ty) => {
        fn clamp(&self, min: T, max: T) -> Self {
            if self.0 > max {
                $name(max)
            } else if self.0 < min {
                $name(min)
            } else {
                self.clone()
            }
        }
    }
}

macro_rules! impl_abs_diff_eq {
    ({$($name: ident),+}) => {
        type Epsilon = T::Epsilon;

        fn default_epsilon() -> Self::Epsilon {
            T::default_epsilon()
        }
        fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
            true $(&& self.$name.abs_diff_eq(&other.$name, epsilon.clone()))*
        }
    }
}

macro_rules! impl_rel_eq {
    ({$($name: ident),*}) => {
        fn default_max_relative() -> Self::Epsilon {
            T::default_max_relative()
        }
        fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon,
                       max_relative: Self::Epsilon) -> bool {
            true $(&& self.$name.relative_eq(&other.$name, epsilon.clone(),
                max_relative.clone()))*
        }
    }
}

macro_rules! impl_ulps_eq {
    ({$($name: ident),*}) => {
        fn default_max_ulps() -> u32 {
            T::default_max_ulps()
        }
        fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon,
                   max_ulps: u32) -> bool {
            true $(&& self.$name.ulps_eq(&other.$name, epsilon.clone(), max_ulps))*
        }
    }
}

macro_rules! impl_color_as_slice {
    ($T: ty) => {
        fn as_slice(&self) -> &[Self::ChannelFormat] {
            unsafe {
                let ptr: *const Self::ChannelFormat = mem::transmute(self);
                slice::from_raw_parts(ptr, Self::num_channels() as usize)
            }
        }
    }
}

macro_rules! impl_color_from_slice_square {
    ($name: ident<$T:ident> {$($fields:ident:$chan:ident - $i:expr),*}, phantom={$($phantom:ident),*}) => {
        fn from_slice(vals: &[$T]) -> Self {
            $name::new($(vals[$i].clone()),*)
        }
    };
    ($name: ident<$T:ident> {$($fields:ident:$chan:ident - $i:expr),*}) => {
        impl_color_from_slice_square!($name<$T> {$($fields:$chan - $i),*}, phantom={});
    };
}

macro_rules! impl_color_transform_body_channel_forward {
    ($name: ident {$($fields: ident),*} $f: ident, $s: ident,
        phantom={$($phantom:ident),*}) =>
    {
        $name {
            $($fields: $s.$fields.$f()),*,
            $($phantom: PhantomData),*
        }
    };
    ($name: ident {$($fields: ident),*} $f: ident, $s: ident) => {
        impl_color_transform_body_channel_forward!($name {$($fields),*} $f, $s, phantom={})
    };
}

macro_rules! impl_color_invert {
    ($name: ident {$($fields: ident),*}, phantom={$($phantom:ident),*}) => {
        fn invert(self) -> Self {
            impl_color_transform_body_channel_forward!($name {$($fields),*} invert, self,
            phantom={$($phantom),*})
        }
    };
    ($name: ident {$($fields: ident),*}) => {
        impl_color_invert!($name {$($fields),*}, phantom={});
    };
}

macro_rules! impl_color_bounded {
    ($name: ident {$($fields: ident),*}, phantom={$($phantom:ident),*}) => {
        fn normalize(self) -> Self {
            impl_color_transform_body_channel_forward!($name {$($fields),*} normalize,
                self, phantom={$($phantom),*})
        }

        fn is_normalized(&self) -> bool {
            true $(&& self.$fields.is_normalized())*
        }
    };
    ($name: ident {$($fields: ident),*}) => {
        impl_color_bounded!($name {$($fields),*}, phantom={});
    }
}

macro_rules! impl_color_lerp_square {
    ($name:ident {$($fields:ident),*}, copy={$($copy:ident),*}, phantom={$($phantom:ident),*}) => {
        fn lerp(&self, right: &Self, pos: Self::Position) -> Self {
            $name {
                $($fields: self.$fields.lerp(&right.$fields, pos.clone())),*,
                $($copy: self.$copy.clone()),*
                $($phantom: PhantomData),*
            }
        }
    };
    ($name:ident {$($fields:ident),*}) => {
        impl_color_lerp_square!($name {$($fields),*}, copy={}, phantom={});
    };
    ($name:ident {$($fields:ident),*}, copy={$($copy:ident),*}) => {
        impl_color_lerp_square!($name {$($fields),*}, copy={$($copy),*}, phantom={});
    };
    ($name:ident {$($fields:ident),*}, phantom={$($phantom:ident),*}) => {
        impl_color_lerp_square!($name {$($fields),*}, copy={}, phantom={$($phantom),*});
    };
}

macro_rules! impl_color_lerp_angular {
    ($name: ident<$T: ident> {$ang_field: ident, $($fields: ident),*}) => {
        impl_color_lerp_angular!($name<$T> {$ang_field, $($fields),*}, copy={});
    };
    ($name: ident<$T: ident> {$ang_field: ident, $($fields: ident),*}, copy={$($copy:ident),*}) => {

        fn lerp(&self, right: &Self, pos: Self::Position) -> Self {
            let tpos: $T::Position = num_traits::cast(pos).unwrap();
            $name {
                $ang_field: self.$ang_field.lerp(&right.$ang_field, pos),
                $($fields: self.$fields.lerp(&right.$fields, tpos.clone())),*,
                $($copy: self.$copy.clone()),*
            }
        }
    };
}

macro_rules! impl_color_default {
    ($name:ident {$($fields:ident:$ChanType:ident),*}, phantom={$($phantom:ident),*}) => {
        fn default() -> Self {
            $name {
                $($fields: $ChanType::default()),*,
                $($phantom: PhantomData),*
            }
        }
    };
    ($name:ident {$($fields:ident:$ChanType:ident),*}) => {
        impl_color_default!($name {$($fields:$ChanType),*}, phantom={});
    };
}

macro_rules! impl_color_color_cast_square {
    ($name:ident {$($fields:ident),*}, chan_traits={$($chan_traits:ident),*},
     phantom={$($phantom:ident),*},
        types={$($ts:ident),*}) =>
    {
        /// Convert the internal channel scalar format
        pub fn color_cast<TOut>(&self) -> $name<TOut, $($ts),*>
            where T: ChannelFormatCast<TOut>,
                  TOut: $($chan_traits +)*
        {
            $name {
                $($fields: self.$fields.clone().channel_cast()),*,
                $($phantom: PhantomData),*
            }
        }
    };

    ($name:ident {$($fields:ident),*}, chan_traits={$($chan_traits:ident),*}) => {
        impl_color_color_cast_square!($name {$($fields),*}, chan_traits={$($chan_traits),*},
            phantom={}, types={});
    };
}

macro_rules! impl_color_color_cast_angular {
    ($name:ident {$($fields:ident),*}, chan_traits={$($chan_traits:ident),*}) => {
        /// Convert the internal channel scalar format
        pub fn color_cast<TOut, AOut>(&self) -> $name<TOut, AOut>
            where T: ChannelFormatCast<TOut>,
                  A: ChannelFormatCast<AOut>,
                  AOut: AngularChannelScalar,
                  TOut: $($chan_traits + )*
        {
            $name {
                $($fields: self.$fields.clone().channel_cast()),*
            }
        }
    }
}

macro_rules! impl_color_get_hue_angular {
    ($name:ident) => {
        type InternalAngle = A;
        fn get_hue<U>(&self) -> U
            where U: Angle<Scalar = A::Scalar> + FromAngle<A>
        {
            <A as IntoAngle<U>>::into_angle(self.hue.0.clone())
        }
    }
}

macro_rules! impl_color_homogeneous_color_square {
    ($name:ident<$T:ident> {$($fields:ident),*}, phantom={$($phantom:ident),*}) => {
        fn clamp(self, min: $T, max: $T) -> Self {
            $name {
                $($fields: self.$fields.clamp(min.clone(), max.clone())),*,
                $($phantom: PhantomData),*
            }
        }
    };
    ($name:ident<$T:ident> {$($fields:ident),*}) => {
        impl_color_homogeneous_color_square!($name<$T> {$($fields),*}, phantom={});
    };
}

macro_rules! impl_color_broadcast {
    ($name:ident<$T:ident> {$($fields:ident),*}, chan=$chan:ident,
    phantom={$($phantom:ident),*}) =>
    {
        fn broadcast(value: $T) -> Self {
            $name {
                $($fields: $chan(value.clone())),*,
                $($phantom: PhantomData),*
            }
        }
    };
    ($name:ident<$T:ident> {$($fields:ident),*}, chan=$chan:ident) => {
        impl_color_broadcast!($name<$T> {$($fields),*}, chan=$chan, phantom={});
    };
}