Skip to content

Commit 10ec6be

Browse files
committed
Map to_* Self -> Self. Add component methods.
1 parent a33ad56 commit 10ec6be

File tree

1 file changed

+72
-54
lines changed

1 file changed

+72
-54
lines changed

crates/processing_pyo3/src/color.rs

Lines changed: 72 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,38 @@ fn to_srgba(color: &Color) -> Srgba {
4242
color.to_srgba()
4343
}
4444

45+
fn components(color: &Color) -> [f32; 4] {
46+
use bevy::color::ColorToComponents;
47+
match *color {
48+
Color::Srgba(c) => c.to_f32_array(),
49+
Color::LinearRgba(c) => c.to_f32_array(),
50+
Color::Hsla(c) => c.to_f32_array(),
51+
Color::Hsva(c) => c.to_f32_array(),
52+
Color::Hwba(c) => c.to_f32_array(),
53+
Color::Laba(c) => c.to_f32_array(),
54+
Color::Lcha(c) => c.to_f32_array(),
55+
Color::Oklaba(c) => c.to_f32_array(),
56+
Color::Oklcha(c) => c.to_f32_array(),
57+
Color::Xyza(c) => c.to_f32_array(),
58+
}
59+
}
60+
61+
fn components_no_alpha(color: &Color) -> [f32; 3] {
62+
use bevy::color::ColorToComponents;
63+
match *color {
64+
Color::Srgba(c) => c.to_f32_array_no_alpha(),
65+
Color::LinearRgba(c) => c.to_f32_array_no_alpha(),
66+
Color::Hsla(c) => c.to_f32_array_no_alpha(),
67+
Color::Hsva(c) => c.to_f32_array_no_alpha(),
68+
Color::Hwba(c) => c.to_f32_array_no_alpha(),
69+
Color::Laba(c) => c.to_f32_array_no_alpha(),
70+
Color::Lcha(c) => c.to_f32_array_no_alpha(),
71+
Color::Oklaba(c) => c.to_f32_array_no_alpha(),
72+
Color::Oklcha(c) => c.to_f32_array_no_alpha(),
73+
Color::Xyza(c) => c.to_f32_array_no_alpha(),
74+
}
75+
}
76+
4577
#[pymethods]
4678
impl PyColor {
4779
// Varargs ctor for positional calls like color(255, 0, 0). ColorLike handles single-value extraction.
@@ -151,54 +183,44 @@ impl PyColor {
151183
parse_hex(s).map(Self)
152184
}
153185

154-
fn to_srgba(&self) -> (f32, f32, f32, f32) {
155-
let s: Srgba = self.0.into();
156-
(s.red, s.green, s.blue, s.alpha)
186+
fn to_srgba(&self) -> Self {
187+
Self(Color::Srgba(self.0.into()))
157188
}
158189

159-
fn to_linear(&self) -> (f32, f32, f32, f32) {
160-
let l: LinearRgba = self.0.into();
161-
(l.red, l.green, l.blue, l.alpha)
190+
fn to_linear(&self) -> Self {
191+
Self(Color::LinearRgba(self.0.into()))
162192
}
163193

164-
fn to_hsla(&self) -> (f32, f32, f32, f32) {
165-
let h: Hsla = self.0.into();
166-
(h.hue, h.saturation, h.lightness, h.alpha)
194+
fn to_hsla(&self) -> Self {
195+
Self(Color::Hsla(self.0.into()))
167196
}
168197

169-
fn to_hsva(&self) -> (f32, f32, f32, f32) {
170-
let h: Hsva = self.0.into();
171-
(h.hue, h.saturation, h.value, h.alpha)
198+
fn to_hsva(&self) -> Self {
199+
Self(Color::Hsva(self.0.into()))
172200
}
173201

174-
fn to_hwba(&self) -> (f32, f32, f32, f32) {
175-
let h: Hwba = self.0.into();
176-
(h.hue, h.whiteness, h.blackness, h.alpha)
202+
fn to_hwba(&self) -> Self {
203+
Self(Color::Hwba(self.0.into()))
177204
}
178205

179-
fn to_oklab(&self) -> (f32, f32, f32, f32) {
180-
let o: Oklaba = self.0.into();
181-
(o.lightness, o.a, o.b, o.alpha)
206+
fn to_oklab(&self) -> Self {
207+
Self(Color::Oklaba(self.0.into()))
182208
}
183209

184-
fn to_oklch(&self) -> (f32, f32, f32, f32) {
185-
let o: Oklcha = self.0.into();
186-
(o.lightness, o.chroma, o.hue, o.alpha)
210+
fn to_oklch(&self) -> Self {
211+
Self(Color::Oklcha(self.0.into()))
187212
}
188213

189-
fn to_lab(&self) -> (f32, f32, f32, f32) {
190-
let l: Laba = self.0.into();
191-
(l.lightness, l.a, l.b, l.alpha)
214+
fn to_lab(&self) -> Self {
215+
Self(Color::Laba(self.0.into()))
192216
}
193217

194-
fn to_lch(&self) -> (f32, f32, f32, f32) {
195-
let l: Lcha = self.0.into();
196-
(l.lightness, l.chroma, l.hue, l.alpha)
218+
fn to_lch(&self) -> Self {
219+
Self(Color::Lcha(self.0.into()))
197220
}
198221

199-
fn to_xyz(&self) -> (f32, f32, f32, f32) {
200-
let x: Xyza = self.0.into();
201-
(x.x, x.y, x.z, x.alpha)
222+
fn to_xyz(&self) -> Self {
223+
Self(Color::Xyza(self.0.into()))
202224
}
203225

204226
#[getter]
@@ -317,39 +339,39 @@ impl PyColor {
317339
}
318340

319341
fn to_vec3(&self) -> crate::math::PyVec3 {
320-
let s = to_srgba(&self.0);
321-
crate::math::PyVec3(bevy::math::Vec3::new(s.red, s.green, s.blue))
342+
let c = components_no_alpha(&self.0);
343+
crate::math::PyVec3(bevy::math::Vec3::from_array(c))
322344
}
323345

324346
fn to_vec4(&self) -> PyVec4 {
325-
let s = to_srgba(&self.0);
326-
PyVec4(bevy::math::Vec4::new(s.red, s.green, s.blue, s.alpha))
347+
let c = components(&self.0);
348+
PyVec4(bevy::math::Vec4::from_array(c))
327349
}
328350

329351
fn to_list(&self) -> Vec<f32> {
330-
let s = to_srgba(&self.0);
331-
vec![s.red, s.green, s.blue, s.alpha]
352+
components(&self.0).to_vec()
332353
}
333354

334355
fn to_tuple<'py>(&self, py: Python<'py>) -> Bound<'py, PyTuple> {
335-
let s = to_srgba(&self.0);
336-
PyTuple::new(py, [s.red, s.green, s.blue, s.alpha]).unwrap()
356+
PyTuple::new(py, components(&self.0)).unwrap()
337357
}
338358

339359
fn __repr__(&self) -> String {
340-
let s = to_srgba(&self.0);
341-
format!("Color({}, {}, {}, {})", s.red, s.green, s.blue, s.alpha)
360+
let c = components(&self.0);
361+
format!("Color({}, {}, {}, {})", c[0], c[1], c[2], c[3])
342362
}
343363

344364
fn __str__(&self) -> String {
345365
self.__repr__()
346366
}
347367

348368
fn __eq__(&self, other: &Self) -> bool {
369+
// Compare in sRGBA so colors in different spaces can be equal
349370
to_srgba(&self.0) == to_srgba(&other.0)
350371
}
351372

352373
fn __hash__(&self) -> u64 {
374+
// Hash in sRGBA so equal colors hash the same regardless of space
353375
let s = to_srgba(&self.0);
354376
let mut hasher = std::collections::hash_map::DefaultHasher::new();
355377
hash_f32(s.red, &mut hasher);
@@ -364,21 +386,17 @@ impl PyColor {
364386
}
365387

366388
fn __getitem__(&self, idx: isize) -> PyResult<f32> {
367-
let s = to_srgba(&self.0);
389+
let c = components(&self.0);
368390
let idx = if idx < 0 { 4 + idx } else { idx };
369-
match idx {
370-
0 => Ok(s.red),
371-
1 => Ok(s.green),
372-
2 => Ok(s.blue),
373-
3 => Ok(s.alpha),
374-
_ => Err(PyTypeError::new_err("index out of range")),
391+
if idx < 0 || idx >= 4 {
392+
return Err(PyTypeError::new_err("index out of range"));
375393
}
394+
Ok(c[idx as usize])
376395
}
377396

378397
fn __iter__(slf: PyRef<'_, Self>) -> PyVecIter {
379-
let s = to_srgba(&slf.0);
380398
PyVecIter {
381-
values: vec![s.red, s.green, s.blue, s.alpha],
399+
values: components(&slf.0).to_vec(),
382400
index: 0,
383401
}
384402
}
@@ -432,7 +450,7 @@ mod tests {
432450
#[test]
433451
fn test_hex_roundtrip() {
434452
let c = parse_hex("#FF00FF").unwrap();
435-
let s = c.to_srgba();
453+
let s = to_srgba(&c);
436454
assert!((s.red - 1.0).abs() < 0.01);
437455
assert!((s.green - 0.0).abs() < 0.01);
438456
assert!((s.blue - 1.0).abs() < 0.01);
@@ -442,7 +460,7 @@ mod tests {
442460
#[test]
443461
fn test_hex_with_alpha() {
444462
let c = parse_hex("#FF000080").unwrap();
445-
let s = c.to_srgba();
463+
let s = to_srgba(&c);
446464
assert!((s.red - 1.0).abs() < 0.01);
447465
assert!((s.alpha - 128.0 / 255.0).abs() < 0.01);
448466
}
@@ -500,7 +518,7 @@ mod tests {
500518
assert!(s.green < 0.01);
501519
assert!(s.blue < 0.01);
502520

503-
let (h, sat, l, a) = c.to_hsla();
521+
let [h, sat, l, a] = components(&c.to_hsla().0);
504522
assert!((h - 0.0).abs() < 0.5);
505523
assert!((sat - 1.0).abs() < 0.01);
506524
assert!((l - 0.5).abs() < 0.01);
@@ -510,7 +528,7 @@ mod tests {
510528
#[test]
511529
fn test_oklch_roundtrip() {
512530
let c = PyColor::oklch(0.7, 0.15, 30.0, 1.0);
513-
let (l, ch, h, a) = c.to_oklch();
531+
let [l, ch, h, a] = components(&c.to_oklch().0);
514532
assert!((l - 0.7).abs() < 0.01);
515533
assert!((ch - 0.15).abs() < 0.01);
516534
assert!((h - 30.0).abs() < 0.5);
@@ -520,7 +538,7 @@ mod tests {
520538
#[test]
521539
fn test_linear_roundtrip() {
522540
let c = PyColor::linear(0.5, 0.25, 0.1, 0.8);
523-
let (r, g, b, a) = c.to_linear();
541+
let [r, g, b, a] = components(&c.to_linear().0);
524542
assert!((r - 0.5).abs() < 0.01);
525543
assert!((g - 0.25).abs() < 0.01);
526544
assert!((b - 0.1).abs() < 0.01);

0 commit comments

Comments
 (0)