settings/
base.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
5//! Service-wide definitions.
6//!
7//! # Summary
8//!
9//! The base mod houses the core definitions for communicating information
10//! across the service. Note that there are currently references to types in
11//! other nested base mods. It is the long-term intention that the common
12//! general (non-domain specific or overarching) definitions are migrated here,
13//! while particular types, such as setting-specific definitions, are moved to
14//! a common base mod underneath the parent setting mod.
15
16use crate::accessibility::types::AccessibilityInfo;
17use crate::audio::types::AudioInfo;
18use crate::display::types::DisplayInfo;
19use crate::do_not_disturb::types::DoNotDisturbInfo;
20use crate::ingress::fidl;
21#[cfg(test)]
22use serde::Deserialize;
23use serde::Serialize;
24use std::collections::HashSet;
25
26/// The setting types supported by the service.
27#[derive(PartialEq, Debug, Eq, Hash, Clone, Copy, Serialize)]
28pub enum SettingType {
29    /// This value is reserved for testing purposes.
30    #[cfg(test)]
31    Unknown,
32    Accessibility,
33    Audio,
34    Display,
35    DoNotDisturb,
36    FactoryReset,
37    Input,
38    Intl,
39    Keyboard,
40    Light,
41    NightMode,
42    Privacy,
43    Setup,
44}
45
46/// [Entity] defines the types of components that exist within the setting service. Entities can be
47/// any part of the system that can be interacted with. Others can reference [Entities](Entity) to
48/// declare associations, such as dependencies.
49#[derive(PartialEq, Debug, Eq, Hash, Clone, Copy)]
50pub enum Entity {
51    /// A component that handles requests for the specified [SettingType].
52    Handler(SettingType),
53}
54
55/// A [Dependency] declares a reliance of a particular configuration/feature/component/etc. within
56/// the setting service. [Dependencies](Dependency) are used to generate the necessary component map
57/// to support a particular service configuration. It can used to determine if the platform/product
58/// configuration can support the requested service configuration.
59#[derive(PartialEq, Debug, Eq, Hash, Clone, Copy)]
60pub(crate) enum Dependency {
61    /// An [Entity] is a component within the setting service.
62    Entity(Entity),
63}
64
65impl Dependency {
66    /// Returns whether the [Dependency] can be handled by the provided environment. Currently, this
67    /// only involves [SettingType] handlers.
68    pub(crate) fn is_fulfilled(&self, entities: &HashSet<Entity>) -> bool {
69        match self {
70            Dependency::Entity(entity) => entities.contains(entity),
71        }
72    }
73}
74
75/// This macro takes an enum, which has variants associated with exactly one data, and
76/// generates the same enum and implements a for_inspect method.
77/// The for_inspect method returns variants' names and formated data contents.
78#[macro_export]
79macro_rules! generate_inspect_with_info {
80    ($(#[$metas:meta])* pub enum $name:ident {
81        $(
82            $(#[doc = $str:expr])*
83            $(#[cfg($test:meta)])?
84            $variant:ident ( $data:ty )
85        ),* $(,)?
86    }
87    ) => {
88        $(#[$metas])*
89        pub enum $name {
90            $(
91                $(#[doc = $str])*
92                $(#[cfg($test)])?
93                $variant($data),
94            )*
95        }
96
97        impl $name {
98            /// Returns the name of the enum and its value, debug-formatted, for writing to inspect.
99            pub(crate) fn for_inspect(&self) -> (&'static str, String) {
100                match self {
101                    $(
102                        $(#[cfg($test)])?
103                        $name::$variant(info) => (stringify!($variant), format!("{:?}", info)),
104                    )*
105                }
106            }
107        }
108    };
109}
110
111generate_inspect_with_info! {
112    /// Enumeration over the possible info types available in the service.
113    #[derive(PartialEq, Debug, Clone)]
114    pub enum SettingInfo {
115        /// This value is reserved for testing purposes.
116        #[cfg(test)]
117        Unknown(UnknownInfo),
118        Accessibility(AccessibilityInfo),
119        Audio(AudioInfo),
120        Brightness(DisplayInfo),
121        DoNotDisturb(DoNotDisturbInfo),
122    }
123}
124
125pub(crate) trait HasSettingType {
126    const SETTING_TYPE: SettingType;
127}
128
129macro_rules! conversion_impls {
130    ($($(#[cfg($test:meta)])? $variant:ident($info_ty:ty) => $ty_variant:ident ),+ $(,)?) => {
131        $(
132            $(#[cfg($test)])?
133            impl HasSettingType for $info_ty {
134                const SETTING_TYPE: SettingType = SettingType::$ty_variant;
135            }
136
137            $(#[cfg($test)])?
138            impl TryFrom<SettingInfo> for $info_ty {
139                type Error = ();
140
141                fn try_from(setting_info: SettingInfo) -> Result<Self, ()> {
142                    match setting_info {
143                        SettingInfo::$variant(info) => Ok(info),
144                        _ => Err(()),
145                    }
146                }
147            }
148        )+
149    }
150}
151
152conversion_impls! {
153    #[cfg(test)] Unknown(UnknownInfo) => Unknown,
154    Accessibility(AccessibilityInfo) => Accessibility,
155    Audio(AudioInfo) => Audio,
156    Brightness(DisplayInfo) => Display,
157    DoNotDisturb(DoNotDisturbInfo) => DoNotDisturb,
158}
159
160impl From<&SettingInfo> for SettingType {
161    fn from(info: &SettingInfo) -> SettingType {
162        match info {
163            #[cfg(test)]
164            SettingInfo::Unknown(_) => SettingType::Unknown,
165            SettingInfo::Accessibility(_) => SettingType::Accessibility,
166            SettingInfo::Audio(_) => SettingType::Audio,
167            SettingInfo::Brightness(_) => SettingType::Display,
168            SettingInfo::DoNotDisturb(_) => SettingType::DoNotDisturb,
169        }
170    }
171}
172
173/// This struct is reserved for testing purposes. Some tests need to verify data changes, bool value
174/// can be used for this purpose.
175#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
176#[cfg(test)]
177#[derive(Default)]
178pub struct UnknownInfo(pub bool);
179
180/// Returns the default interfaces supported by any product if none are supplied.
181pub fn get_default_interfaces() -> HashSet<fidl::InterfaceSpec> {
182    [
183        fidl::InterfaceSpec::Accessibility,
184        fidl::InterfaceSpec::Intl,
185        fidl::InterfaceSpec::Privacy,
186        fidl::InterfaceSpec::Setup,
187    ]
188    .into()
189}
190
191/// Returns all known setting types. New additions to SettingType should also
192/// be inserted here.
193#[cfg(test)]
194pub(crate) fn get_all_setting_types() -> HashSet<SettingType> {
195    [
196        SettingType::Accessibility,
197        SettingType::Audio,
198        SettingType::Display,
199        SettingType::DoNotDisturb,
200        SettingType::FactoryReset,
201        SettingType::Input,
202        SettingType::Intl,
203        SettingType::Keyboard,
204        SettingType::Light,
205        SettingType::NightMode,
206        SettingType::Privacy,
207        SettingType::Setup,
208    ]
209    .into()
210}
211
212#[cfg(test)]
213mod testing {
214    use settings_storage::device_storage::DeviceStorageCompatible;
215    use settings_storage::storage_factory::NoneT;
216
217    use super::{SettingInfo, UnknownInfo};
218
219    impl DeviceStorageCompatible for UnknownInfo {
220        type Loader = NoneT;
221        const KEY: &'static str = "unknown_info";
222    }
223
224    impl From<UnknownInfo> for SettingInfo {
225        fn from(info: UnknownInfo) -> SettingInfo {
226            SettingInfo::Unknown(info)
227        }
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234
235    #[allow(clippy::bool_assert_comparison)]
236    #[fuchsia::test]
237    fn test_dependency_fulfillment() {
238        let target_entity = Entity::Handler(SettingType::Unknown);
239        let dependency = Dependency::Entity(target_entity);
240        let mut available_entities = HashSet::new();
241
242        // Verify that an empty entity set does not fulfill dependency.
243        assert_eq!(dependency.is_fulfilled(&available_entities), false);
244
245        // Verify an entity set without the target entity does not fulfill dependency.
246        let _ = available_entities.insert(Entity::Handler(SettingType::FactoryReset));
247        assert_eq!(dependency.is_fulfilled(&available_entities), false);
248
249        // Verify an entity set with target entity does fulfill dependency.
250        let _ = available_entities.insert(target_entity);
251        assert!(dependency.is_fulfilled(&available_entities));
252    }
253}