settings_light/
types.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::light_hardware_configuration::DisableConditions;
6use serde::{Deserialize, Serialize};
7use settings_common::inspect::event::Nameable;
8use std::collections::HashMap;
9
10#[derive(PartialEq, Default, Debug, Clone, Serialize, Deserialize)]
11pub struct LightInfo {
12    pub light_groups: HashMap<String, LightGroup>,
13}
14
15/// Name used when logging to inspect.
16impl Nameable for LightInfo {
17    const NAME: &str = "Light";
18}
19
20/// Internal representation of a light group.
21#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
22pub struct LightGroup {
23    pub name: String,
24    pub enabled: bool,
25    pub light_type: LightType,
26    pub lights: Vec<LightState>,
27
28    /// Each light in the underlying fuchsia.hardware.light API has a unique, fixed index. We need
29    /// to remember the index of the lights in this light group in order to write values back.
30    pub hardware_index: Vec<u32>,
31
32    /// A list of conditions under which the "enabled" field of the light group should be false,
33    /// which signals to clients the light's state is being overridden by external conditions, such
34    /// as an LED dedicated to showing that a device's mic is muted that is off when the mic is not
35    /// muted.
36    ///
37    /// Lights that are disabled can still have their value set, but the changes may not be
38    /// noticeable to the user until the condition disabling/overriding ends.
39    pub disable_conditions: Vec<DisableConditions>,
40}
41
42impl From<LightGroup> for fidl_fuchsia_settings::LightGroup {
43    fn from(src: LightGroup) -> Self {
44        fidl_fuchsia_settings::LightGroup {
45            name: Some(src.name),
46            enabled: Some(src.enabled),
47            type_: Some(src.light_type.into()),
48            lights: Some(src.lights.into_iter().map(LightState::into).collect()),
49            ..Default::default()
50        }
51    }
52}
53
54impl From<fidl_fuchsia_settings::LightGroup> for LightGroup {
55    fn from(src: fidl_fuchsia_settings::LightGroup) -> Self {
56        LightGroup {
57            name: src.name.unwrap(),
58            enabled: src.enabled.unwrap(),
59            light_type: src.type_.unwrap().into(),
60            lights: src.lights.unwrap().into_iter().map(LightState::from).collect(),
61            // These are not used in storage, but will be filled out by the controller.
62            hardware_index: vec![],
63            disable_conditions: vec![],
64        }
65    }
66}
67
68#[derive(PartialEq, Eq, Debug, Copy, Clone, Serialize, Deserialize)]
69pub enum LightType {
70    Brightness,
71    Rgb,
72    Simple,
73}
74
75impl From<fidl_fuchsia_settings::LightType> for LightType {
76    fn from(src: fidl_fuchsia_settings::LightType) -> Self {
77        match src {
78            fidl_fuchsia_settings::LightType::Brightness => LightType::Brightness,
79            fidl_fuchsia_settings::LightType::Rgb => LightType::Rgb,
80            fidl_fuchsia_settings::LightType::Simple => LightType::Simple,
81        }
82    }
83}
84
85impl From<LightType> for fidl_fuchsia_settings::LightType {
86    fn from(src: LightType) -> Self {
87        match src {
88            LightType::Brightness => fidl_fuchsia_settings::LightType::Brightness,
89            LightType::Rgb => fidl_fuchsia_settings::LightType::Rgb,
90            LightType::Simple => fidl_fuchsia_settings::LightType::Simple,
91        }
92    }
93}
94
95/// Converts between a Capability and a LightType for convenience for tests.
96impl From<fidl_fuchsia_hardware_light::Capability> for LightType {
97    fn from(src: fidl_fuchsia_hardware_light::Capability) -> Self {
98        match src {
99            fidl_fuchsia_hardware_light::Capability::Brightness => LightType::Brightness,
100            fidl_fuchsia_hardware_light::Capability::Rgb => LightType::Rgb,
101            fidl_fuchsia_hardware_light::Capability::Simple => LightType::Simple,
102        }
103    }
104}
105
106/// Converts between a LightType and a Capability for convenience for tests.
107impl From<LightType> for fidl_fuchsia_hardware_light::Capability {
108    fn from(src: LightType) -> Self {
109        match src {
110            LightType::Brightness => fidl_fuchsia_hardware_light::Capability::Brightness,
111            LightType::Rgb => fidl_fuchsia_hardware_light::Capability::Rgb,
112            LightType::Simple => fidl_fuchsia_hardware_light::Capability::Simple,
113        }
114    }
115}
116
117#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
118pub struct LightState {
119    pub value: Option<LightValue>,
120}
121
122impl LightState {
123    pub(crate) fn is_finite(&self) -> bool {
124        (self.value).as_ref().is_none_or(|val| val.is_finite())
125    }
126}
127
128impl From<fidl_fuchsia_settings::LightState> for LightState {
129    fn from(src: fidl_fuchsia_settings::LightState) -> Self {
130        LightState { value: src.value.map(LightValue::from) }
131    }
132}
133
134impl From<LightState> for fidl_fuchsia_settings::LightState {
135    fn from(src: LightState) -> Self {
136        fidl_fuchsia_settings::LightState {
137            value: src.value.map(fidl_fuchsia_settings::LightValue::from),
138            ..Default::default()
139        }
140    }
141}
142
143#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
144pub enum LightValue {
145    Brightness(f64),
146    Rgb(ColorRgb),
147    Simple(bool),
148}
149
150impl LightValue {
151    pub(crate) fn is_finite(&self) -> bool {
152        match self {
153            LightValue::Brightness(brightness) => brightness.is_finite(),
154            LightValue::Rgb(color_rgb) => color_rgb.is_finite(),
155            LightValue::Simple(_) => true,
156        }
157    }
158}
159
160impl From<fidl_fuchsia_settings::LightValue> for LightValue {
161    fn from(src: fidl_fuchsia_settings::LightValue) -> Self {
162        match src {
163            fidl_fuchsia_settings::LightValue::On(on) => LightValue::Simple(on),
164            fidl_fuchsia_settings::LightValue::Brightness(brightness) => {
165                LightValue::Brightness(brightness)
166            }
167            fidl_fuchsia_settings::LightValue::Color(color) => LightValue::Rgb(color.into()),
168        }
169    }
170}
171
172impl From<fidl_fuchsia_hardware_light::Rgb> for LightValue {
173    fn from(src: fidl_fuchsia_hardware_light::Rgb) -> Self {
174        LightValue::Rgb(ColorRgb {
175            red: src.red as f32,
176            green: src.green as f32,
177            blue: src.blue as f32,
178        })
179    }
180}
181
182impl From<LightValue> for fidl_fuchsia_settings::LightValue {
183    fn from(src: LightValue) -> Self {
184        match src {
185            LightValue::Simple(on) => fidl_fuchsia_settings::LightValue::On(on),
186            LightValue::Brightness(brightness) => {
187                fidl_fuchsia_settings::LightValue::Brightness(brightness)
188            }
189            LightValue::Rgb(color) => fidl_fuchsia_settings::LightValue::Color(color.into()),
190        }
191    }
192}
193
194#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
195pub struct ColorRgb {
196    pub red: f32,
197    pub green: f32,
198    pub blue: f32,
199}
200
201impl ColorRgb {
202    pub(crate) fn is_finite(&self) -> bool {
203        self.red.is_finite() && self.green.is_finite() && self.blue.is_finite()
204    }
205}
206
207impl From<fidl_fuchsia_ui_types::ColorRgb> for ColorRgb {
208    fn from(src: fidl_fuchsia_ui_types::ColorRgb) -> Self {
209        ColorRgb { red: src.red, green: src.green, blue: src.blue }
210    }
211}
212
213impl From<ColorRgb> for fidl_fuchsia_ui_types::ColorRgb {
214    fn from(src: ColorRgb) -> Self {
215        fidl_fuchsia_ui_types::ColorRgb { red: src.red, green: src.green, blue: src.blue }
216    }
217}
218
219/// Converts between internal RGB representation and underlying fuchsia.hardware.light
220/// representation.
221impl TryFrom<ColorRgb> for fidl_fuchsia_hardware_light::Rgb {
222    type Error = &'static str;
223    fn try_from(src: ColorRgb) -> Result<Self, Self::Error> {
224        if src.red > 1.0
225            || src.green > 1.0
226            || src.blue > 1.0
227            || src.red < 0.0
228            || src.green < 0.0
229            || src.blue < 0.0
230        {
231            return Err("values must be between 0.0 and 1.0 inclusive");
232        }
233
234        Ok(fidl_fuchsia_hardware_light::Rgb {
235            red: src.red as f64,
236            green: src.green as f64,
237            blue: src.blue as f64,
238        })
239    }
240}
241
242#[cfg(test)]
243mod tests {
244    use super::*;
245
246    #[fuchsia::test]
247    fn test_try_from_rgb() {
248        assert!(fidl_fuchsia_hardware_light::Rgb::try_from(ColorRgb {
249            red: -0.0,
250            green: 0.1,
251            blue: 1.0
252        })
253        .is_ok());
254
255        assert!(fidl_fuchsia_hardware_light::Rgb::try_from(ColorRgb {
256            red: 0.0 - f32::EPSILON,
257            green: 0.1,
258            blue: 0.2
259        })
260        .is_err());
261
262        assert!(fidl_fuchsia_hardware_light::Rgb::try_from(ColorRgb {
263            red: 0.3,
264            green: 1.0 + f32::EPSILON,
265            blue: 0.2
266        })
267        .is_err());
268
269        assert_eq!(
270            fidl_fuchsia_hardware_light::Rgb::try_from(ColorRgb {
271                red: 0.0,
272                green: 1.0,
273                blue: 0.5
274            }),
275            Ok(fidl_fuchsia_hardware_light::Rgb { red: 0.0, green: 1.0, blue: 0.5 })
276        );
277    }
278}