@@ -140,24 +140,21 @@ impl BackendStyle for RGBColor {
140140pub struct HSLColor ( pub f64 , pub f64 , pub f64 ) ;
141141
142142impl HSLColor {
143+ /// Creates an `HSLColor` from degrees, wrapping into `[0, 360)` before normalizing.
144+ /// Prefer this helper when specifying hue in degrees.
143145 #[ inline]
144146 pub fn from_degrees ( h_deg : f64 , s : f64 , l : f64 ) -> Self {
145- Self ( h_deg / 360.0 , s, l)
147+ Self ( h_deg. rem_euclid ( 360.0 ) / 360.0 , s, l)
146148 }
147149}
148150
149151impl Color for HSLColor {
150152 #[ inline( always) ]
151153 #[ allow( clippy:: many_single_char_names) ]
152154 fn to_backend_color ( & self ) -> BackendColor {
153- // Hue: do not clamp; normalize
154- // - If >1.0, treat as degrees (divide by 360), then wrap to [0,1)
155- // - Else, wrap value to [0,1) to accept negatives
156- let h = if self . 0 > 1.0 {
157- ( self . 0 / 360.0 ) . rem_euclid ( 1.0 )
158- } else {
159- self . 0 . rem_euclid ( 1.0 )
160- } ;
155+ // Hue is expected normalized in [0,1); wrap to keep negative or slightly
156+ // out-of-range inputs usable, but do not reinterpret raw degrees.
157+ let h = self . 0 . rem_euclid ( 1.0 ) ;
161158
162159 // Saturation & lightness remain clamped to valid ranges
163160 let s = self . 1 . clamp ( 0.0 , 1.0 ) ;
@@ -209,23 +206,31 @@ mod hue_robustness_tests {
209206 use super :: * ;
210207
211208 #[ test]
212- fn degrees_passed_directly_should_work_for_common_cases ( ) {
213- let red = HSLColor ( 0.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
209+ fn degrees_passed_via_helper_should_work_for_common_cases ( ) {
210+ let red = HSLColor :: from_degrees ( 0.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
214211 assert_eq ! ( red, ( 255 , 0 , 0 ) ) ;
215212
216- let green = HSLColor ( 120.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
213+ let green = HSLColor :: from_degrees ( 120.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
217214 assert_eq ! ( green, ( 0 , 255 , 0 ) ) ;
218215
219- let blue = HSLColor ( 240.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
216+ let blue = HSLColor :: from_degrees ( 240.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
220217 assert_eq ! ( blue, ( 0 , 0 , 255 ) ) ;
221218 }
222219
223220 #[ test]
224- fn from_degrees_and_direct_degrees_are_equivalent ( ) {
225- for & deg in & [ 0.0 , 30.0 , 60.0 , 120.0 , 180.0 , 240.0 , 300.0 , 360.0 ] {
226- let a = HSLColor ( deg, 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
227- let b = HSLColor :: from_degrees ( deg, 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
228- assert_eq ! ( a, b) ;
229- }
221+ fn from_degrees_wraps_and_matches_normalized ( ) {
222+ let normalized = HSLColor ( 120.0 / 360.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
223+ let via_helper = HSLColor :: from_degrees ( 120.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
224+ assert_eq ! ( normalized, via_helper) ;
225+
226+ let wrap_positive =
227+ HSLColor :: from_degrees ( 720.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
228+ let wrap_negative =
229+ HSLColor :: from_degrees ( -120.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
230+ let canonical =
231+ HSLColor :: from_degrees ( 0.0 , 1.0 , 0.5 ) . to_backend_color ( ) . rgb ;
232+
233+ assert_eq ! ( wrap_positive, canonical) ;
234+ assert_eq ! ( wrap_negative, HSLColor :: from_degrees( 240.0 , 1.0 , 0.5 ) . to_backend_color( ) . rgb) ;
230235 }
231236}
0 commit comments