blob: 5e7c8619561848584b51cd024398436806e7ef0d [file] [log] [blame]
Mårten Kongstadbb520722023-04-26 13:16:41 +02001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mårten Kongstade66b89f2023-05-15 10:29:25 +020017use anyhow::{anyhow, bail, Context, Error, Result};
Mårten Kongstad416330b2023-05-05 11:10:01 +020018use protobuf::{Enum, EnumOrUnknown};
19use serde::{Deserialize, Serialize};
Mårten Kongstadbb520722023-04-26 13:16:41 +020020
Mårten Kongstad30950782023-05-09 13:31:29 +020021use crate::cache::{Cache, Item, Tracepoint};
Mårten Kongstad09c28d12023-05-04 13:29:26 +020022use crate::protos::{
Mårten Kongstadfa23d292023-05-11 14:47:02 +020023 ProtoFlagDeclaration, ProtoFlagDeclarations, ProtoFlagPermission, ProtoFlagState,
24 ProtoFlagValue, ProtoFlagValues, ProtoParsedFlag, ProtoParsedFlags, ProtoTracepoint,
Mårten Kongstad09c28d12023-05-04 13:29:26 +020025};
26
Mårten Kongstad416330b2023-05-05 11:10:01 +020027#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)]
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020028pub enum FlagState {
29 Enabled,
30 Disabled,
31}
32
33impl TryFrom<EnumOrUnknown<ProtoFlagState>> for FlagState {
34 type Error = Error;
35
36 fn try_from(proto: EnumOrUnknown<ProtoFlagState>) -> Result<Self, Self::Error> {
37 match ProtoFlagState::from_i32(proto.value()) {
38 Some(ProtoFlagState::ENABLED) => Ok(FlagState::Enabled),
39 Some(ProtoFlagState::DISABLED) => Ok(FlagState::Disabled),
40 None => Err(anyhow!("unknown flag state enum value {}", proto.value())),
41 }
42 }
43}
44
Mårten Kongstada1029092023-05-08 11:51:59 +020045impl From<FlagState> for ProtoFlagState {
46 fn from(state: FlagState) -> Self {
47 match state {
48 FlagState::Enabled => ProtoFlagState::ENABLED,
49 FlagState::Disabled => ProtoFlagState::DISABLED,
50 }
51 }
52}
53
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +020054#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)]
Mårten Kongstad416330b2023-05-05 11:10:01 +020055pub enum Permission {
56 ReadOnly,
57 ReadWrite,
58}
59
Mårten Kongstad30950782023-05-09 13:31:29 +020060impl TryFrom<EnumOrUnknown<ProtoFlagPermission>> for Permission {
Mårten Kongstad416330b2023-05-05 11:10:01 +020061 type Error = Error;
62
Mårten Kongstad30950782023-05-09 13:31:29 +020063 fn try_from(proto: EnumOrUnknown<ProtoFlagPermission>) -> Result<Self, Self::Error> {
64 match ProtoFlagPermission::from_i32(proto.value()) {
65 Some(ProtoFlagPermission::READ_ONLY) => Ok(Permission::ReadOnly),
66 Some(ProtoFlagPermission::READ_WRITE) => Ok(Permission::ReadWrite),
Mårten Kongstad416330b2023-05-05 11:10:01 +020067 None => Err(anyhow!("unknown permission enum value {}", proto.value())),
68 }
69 }
70}
71
Mårten Kongstad30950782023-05-09 13:31:29 +020072impl From<Permission> for ProtoFlagPermission {
Mårten Kongstada1029092023-05-08 11:51:59 +020073 fn from(permission: Permission) -> Self {
74 match permission {
Mårten Kongstad30950782023-05-09 13:31:29 +020075 Permission::ReadOnly => ProtoFlagPermission::READ_ONLY,
76 Permission::ReadWrite => ProtoFlagPermission::READ_WRITE,
Mårten Kongstada1029092023-05-08 11:51:59 +020077 }
78 }
79}
80
Mårten Kongstad09c28d12023-05-04 13:29:26 +020081#[derive(Debug, PartialEq, Eq)]
Mårten Kongstadfa23d292023-05-11 14:47:02 +020082pub struct FlagDeclaration {
Mårten Kongstad30950782023-05-09 13:31:29 +020083 pub name: String,
Mårten Kongstad066575b2023-06-07 16:29:25 +020084 pub namespace: String,
Mårten Kongstadbb520722023-04-26 13:16:41 +020085 pub description: String,
Mårten Kongstadbb520722023-04-26 13:16:41 +020086}
87
Mårten Kongstadfa23d292023-05-11 14:47:02 +020088impl FlagDeclaration {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020089 #[allow(dead_code)] // only used in unit tests
Mårten Kongstadfa23d292023-05-11 14:47:02 +020090 pub fn try_from_text_proto(text_proto: &str) -> Result<FlagDeclaration> {
91 let proto: ProtoFlagDeclaration = crate::protos::try_from_text_proto(text_proto)
Mårten Kongstadbb520722023-04-26 13:16:41 +020092 .with_context(|| text_proto.to_owned())?;
93 proto.try_into()
94 }
Mårten Kongstadbb520722023-04-26 13:16:41 +020095}
96
Mårten Kongstadfa23d292023-05-11 14:47:02 +020097impl TryFrom<ProtoFlagDeclaration> for FlagDeclaration {
Mårten Kongstadbb520722023-04-26 13:16:41 +020098 type Error = Error;
99
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200100 fn try_from(proto: ProtoFlagDeclaration) -> Result<Self, Self::Error> {
Mårten Kongstad30950782023-05-09 13:31:29 +0200101 let Some(name) = proto.name else {
Mårten Kongstade66b89f2023-05-15 10:29:25 +0200102 bail!("missing 'name' field");
Mårten Kongstadbb520722023-04-26 13:16:41 +0200103 };
Mårten Kongstad066575b2023-06-07 16:29:25 +0200104 let Some(namespace) = proto.namespace else {
105 bail!("missing 'namespace' field");
106 };
Mårten Kongstadbb520722023-04-26 13:16:41 +0200107 let Some(description) = proto.description else {
Mårten Kongstade66b89f2023-05-15 10:29:25 +0200108 bail!("missing 'description' field");
Mårten Kongstadbb520722023-04-26 13:16:41 +0200109 };
Mårten Kongstad066575b2023-06-07 16:29:25 +0200110 Ok(FlagDeclaration { name, namespace, description })
Mårten Kongstad30950782023-05-09 13:31:29 +0200111 }
112}
113
114#[derive(Debug, PartialEq, Eq)]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200115pub struct FlagDeclarations {
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200116 pub package: String,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200117 pub flags: Vec<FlagDeclaration>,
Mårten Kongstad30950782023-05-09 13:31:29 +0200118}
119
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200120impl FlagDeclarations {
121 pub fn try_from_text_proto(text_proto: &str) -> Result<FlagDeclarations> {
122 let proto: ProtoFlagDeclarations = crate::protos::try_from_text_proto(text_proto)
Mårten Kongstad30950782023-05-09 13:31:29 +0200123 .with_context(|| text_proto.to_owned())?;
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200124 let Some(package) = proto.package else {
125 bail!("missing 'package' field");
Mårten Kongstad30950782023-05-09 13:31:29 +0200126 };
127 let mut flags = vec![];
128 for proto_flag in proto.flag.into_iter() {
129 flags.push(proto_flag.try_into()?);
130 }
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200131 Ok(FlagDeclarations { package, flags })
Mårten Kongstadbb520722023-04-26 13:16:41 +0200132 }
133}
134
135#[derive(Debug, PartialEq, Eq)]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200136pub struct FlagValue {
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200137 pub package: String,
Mårten Kongstad30950782023-05-09 13:31:29 +0200138 pub name: String,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200139 pub state: FlagState,
Mårten Kongstad416330b2023-05-05 11:10:01 +0200140 pub permission: Permission,
Mårten Kongstadbb520722023-04-26 13:16:41 +0200141}
142
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200143impl FlagValue {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200144 #[allow(dead_code)] // only used in unit tests
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200145 pub fn try_from_text_proto(text_proto: &str) -> Result<FlagValue> {
146 let proto: ProtoFlagValue = crate::protos::try_from_text_proto(text_proto)?;
Mårten Kongstadbb520722023-04-26 13:16:41 +0200147 proto.try_into()
148 }
149
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200150 pub fn try_from_text_proto_list(text_proto: &str) -> Result<Vec<FlagValue>> {
151 let proto: ProtoFlagValues = crate::protos::try_from_text_proto(text_proto)?;
152 proto.flag_value.into_iter().map(|proto_flag| proto_flag.try_into()).collect()
Mårten Kongstadbb520722023-04-26 13:16:41 +0200153 }
154}
155
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200156impl TryFrom<ProtoFlagValue> for FlagValue {
Mårten Kongstadbb520722023-04-26 13:16:41 +0200157 type Error = Error;
158
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200159 fn try_from(proto: ProtoFlagValue) -> Result<Self, Self::Error> {
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200160 let Some(package) = proto.package else {
161 bail!("missing 'package' field");
Mårten Kongstad30950782023-05-09 13:31:29 +0200162 };
163 let Some(name) = proto.name else {
Mårten Kongstade66b89f2023-05-15 10:29:25 +0200164 bail!("missing 'name' field");
Mårten Kongstadbb520722023-04-26 13:16:41 +0200165 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200166 let Some(proto_state) = proto.state else {
Mårten Kongstade66b89f2023-05-15 10:29:25 +0200167 bail!("missing 'state' field");
Mårten Kongstadbb520722023-04-26 13:16:41 +0200168 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200169 let state = proto_state.try_into()?;
Mårten Kongstad416330b2023-05-05 11:10:01 +0200170 let Some(proto_permission) = proto.permission else {
Mårten Kongstade66b89f2023-05-15 10:29:25 +0200171 bail!("missing 'permission' field");
Mårten Kongstad416330b2023-05-05 11:10:01 +0200172 };
173 let permission = proto_permission.try_into()?;
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200174 Ok(FlagValue { package, name, state, permission })
Mårten Kongstadbb520722023-04-26 13:16:41 +0200175 }
176}
177
Mårten Kongstad30950782023-05-09 13:31:29 +0200178impl From<Cache> for ProtoParsedFlags {
Mårten Kongstada1029092023-05-08 11:51:59 +0200179 fn from(cache: Cache) -> Self {
Mårten Kongstad30950782023-05-09 13:31:29 +0200180 let mut proto = ProtoParsedFlags::new();
Mårten Kongstada1029092023-05-08 11:51:59 +0200181 for item in cache.into_iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200182 proto.parsed_flag.push(item.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200183 }
Mårten Kongstad30950782023-05-09 13:31:29 +0200184 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200185 }
186}
187
Mårten Kongstad30950782023-05-09 13:31:29 +0200188impl From<Item> for ProtoParsedFlag {
Mårten Kongstada1029092023-05-08 11:51:59 +0200189 fn from(item: Item) -> Self {
Mårten Kongstad30950782023-05-09 13:31:29 +0200190 let mut proto = crate::protos::ProtoParsedFlag::new();
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200191 proto.set_package(item.package.to_owned());
Mårten Kongstad30950782023-05-09 13:31:29 +0200192 proto.set_name(item.name.clone());
Mårten Kongstad066575b2023-06-07 16:29:25 +0200193 proto.set_namespace(item.namespace.clone());
Mårten Kongstad30950782023-05-09 13:31:29 +0200194 proto.set_description(item.description.clone());
195 proto.set_state(item.state.into());
196 proto.set_permission(item.permission.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200197 for trace in item.trace.into_iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200198 proto.trace.push(trace.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200199 }
Mårten Kongstad30950782023-05-09 13:31:29 +0200200 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200201 }
202}
203
Mårten Kongstad30950782023-05-09 13:31:29 +0200204impl From<Tracepoint> for ProtoTracepoint {
205 fn from(tracepoint: Tracepoint) -> Self {
206 let mut proto = ProtoTracepoint::new();
207 proto.set_source(format!("{}", tracepoint.source));
208 proto.set_state(tracepoint.state.into());
209 proto.set_permission(tracepoint.permission.into());
210 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200211 }
212}
213
Mårten Kongstadbb520722023-04-26 13:16:41 +0200214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_flag_try_from_text_proto() {
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200220 let expected = FlagDeclaration {
Mårten Kongstad30950782023-05-09 13:31:29 +0200221 name: "1234".to_owned(),
Mårten Kongstad066575b2023-06-07 16:29:25 +0200222 namespace: "ns".to_owned(),
Mårten Kongstadbb520722023-04-26 13:16:41 +0200223 description: "Description of the flag".to_owned(),
Mårten Kongstadbb520722023-04-26 13:16:41 +0200224 };
225
226 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200227 name: "1234"
Mårten Kongstad066575b2023-06-07 16:29:25 +0200228 namespace: "ns"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200229 description: "Description of the flag"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200230 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200231 let actual = FlagDeclaration::try_from_text_proto(s).unwrap();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200232
233 assert_eq!(expected, actual);
234 }
235
236 #[test]
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200237 fn test_flag_try_from_text_proto_bad_input() {
238 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200239 name: "a"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200240 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200241 let error = FlagDeclaration::try_from_text_proto(s).unwrap_err();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200242 assert!(format!("{:?}", error).contains("Message not initialized"));
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200243
244 let s = r#"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200245 description: "Description of the flag"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200246 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200247 let error = FlagDeclaration::try_from_text_proto(s).unwrap_err();
248 assert!(format!("{:?}", error).contains("Message not initialized"));
Mårten Kongstadbb520722023-04-26 13:16:41 +0200249 }
250
251 #[test]
Mårten Kongstad9fb58962023-05-31 13:02:13 +0200252 fn test_package_try_from_text_proto() {
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200253 let expected = FlagDeclarations {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200254 package: "com.example".to_owned(),
Mårten Kongstad30950782023-05-09 13:31:29 +0200255 flags: vec![
Mårten Kongstad066575b2023-06-07 16:29:25 +0200256 FlagDeclaration {
257 name: "a".to_owned(),
258 namespace: "ns".to_owned(),
259 description: "A".to_owned(),
260 },
261 FlagDeclaration {
262 name: "b".to_owned(),
263 namespace: "ns".to_owned(),
264 description: "B".to_owned(),
265 },
Mårten Kongstad30950782023-05-09 13:31:29 +0200266 ],
267 };
Mårten Kongstadbb520722023-04-26 13:16:41 +0200268
269 let s = r#"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200270 package: "com.example"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200271 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200272 name: "a"
Mårten Kongstad066575b2023-06-07 16:29:25 +0200273 namespace: "ns"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200274 description: "A"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200275 }
276 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200277 name: "b"
Mårten Kongstad066575b2023-06-07 16:29:25 +0200278 namespace: "ns"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200279 description: "B"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200280 }
281 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200282 let actual = FlagDeclarations::try_from_text_proto(s).unwrap();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200283
284 assert_eq!(expected, actual);
285 }
286
287 #[test]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200288 fn test_flag_declaration_try_from_text_proto_list() {
289 let expected = FlagValue {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200290 package: "com.example".to_owned(),
Mårten Kongstad30950782023-05-09 13:31:29 +0200291 name: "1234".to_owned(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200292 state: FlagState::Enabled,
293 permission: Permission::ReadOnly,
294 };
Mårten Kongstadbb520722023-04-26 13:16:41 +0200295
296 let s = r#"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200297 package: "com.example"
Mårten Kongstad30950782023-05-09 13:31:29 +0200298 name: "1234"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200299 state: ENABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200300 permission: READ_ONLY
Mårten Kongstadbb520722023-04-26 13:16:41 +0200301 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200302 let actual = FlagValue::try_from_text_proto(s).unwrap();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200303
304 assert_eq!(expected, actual);
305 }
Mårten Kongstadbb520722023-04-26 13:16:41 +0200306}