blob: b09648d2634f853bc12463b1e47bf887cce63338 [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
17use anyhow::{anyhow, 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 Kongstadbb520722023-04-26 13:16:41 +020084 pub description: String,
Mårten Kongstadbb520722023-04-26 13:16:41 +020085}
86
Mårten Kongstadfa23d292023-05-11 14:47:02 +020087impl FlagDeclaration {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020088 #[allow(dead_code)] // only used in unit tests
Mårten Kongstadfa23d292023-05-11 14:47:02 +020089 pub fn try_from_text_proto(text_proto: &str) -> Result<FlagDeclaration> {
90 let proto: ProtoFlagDeclaration = crate::protos::try_from_text_proto(text_proto)
Mårten Kongstadbb520722023-04-26 13:16:41 +020091 .with_context(|| text_proto.to_owned())?;
92 proto.try_into()
93 }
Mårten Kongstadbb520722023-04-26 13:16:41 +020094}
95
Mårten Kongstadfa23d292023-05-11 14:47:02 +020096impl TryFrom<ProtoFlagDeclaration> for FlagDeclaration {
Mårten Kongstadbb520722023-04-26 13:16:41 +020097 type Error = Error;
98
Mårten Kongstadfa23d292023-05-11 14:47:02 +020099 fn try_from(proto: ProtoFlagDeclaration) -> Result<Self, Self::Error> {
Mårten Kongstad30950782023-05-09 13:31:29 +0200100 let Some(name) = proto.name else {
101 return Err(anyhow!("missing 'name' field"));
Mårten Kongstadbb520722023-04-26 13:16:41 +0200102 };
103 let Some(description) = proto.description else {
104 return Err(anyhow!("missing 'description' field"));
105 };
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200106 Ok(FlagDeclaration { name, description })
Mårten Kongstad30950782023-05-09 13:31:29 +0200107 }
108}
109
110#[derive(Debug, PartialEq, Eq)]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200111pub struct FlagDeclarations {
Mårten Kongstad30950782023-05-09 13:31:29 +0200112 pub namespace: String,
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200113 pub flags: Vec<FlagDeclaration>,
Mårten Kongstad30950782023-05-09 13:31:29 +0200114}
115
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200116impl FlagDeclarations {
117 pub fn try_from_text_proto(text_proto: &str) -> Result<FlagDeclarations> {
118 let proto: ProtoFlagDeclarations = crate::protos::try_from_text_proto(text_proto)
Mårten Kongstad30950782023-05-09 13:31:29 +0200119 .with_context(|| text_proto.to_owned())?;
120 let Some(namespace) = proto.namespace else {
121 return Err(anyhow!("missing 'namespace' field"));
122 };
123 let mut flags = vec![];
124 for proto_flag in proto.flag.into_iter() {
125 flags.push(proto_flag.try_into()?);
126 }
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200127 Ok(FlagDeclarations { namespace, flags })
Mårten Kongstadbb520722023-04-26 13:16:41 +0200128 }
129}
130
131#[derive(Debug, PartialEq, Eq)]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200132pub struct FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200133 pub namespace: String,
134 pub name: String,
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200135 pub state: FlagState,
Mårten Kongstad416330b2023-05-05 11:10:01 +0200136 pub permission: Permission,
Mårten Kongstadbb520722023-04-26 13:16:41 +0200137}
138
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200139impl FlagValue {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200140 #[allow(dead_code)] // only used in unit tests
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200141 pub fn try_from_text_proto(text_proto: &str) -> Result<FlagValue> {
142 let proto: ProtoFlagValue = crate::protos::try_from_text_proto(text_proto)?;
Mårten Kongstadbb520722023-04-26 13:16:41 +0200143 proto.try_into()
144 }
145
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200146 pub fn try_from_text_proto_list(text_proto: &str) -> Result<Vec<FlagValue>> {
147 let proto: ProtoFlagValues = crate::protos::try_from_text_proto(text_proto)?;
148 proto.flag_value.into_iter().map(|proto_flag| proto_flag.try_into()).collect()
Mårten Kongstadbb520722023-04-26 13:16:41 +0200149 }
150}
151
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200152impl TryFrom<ProtoFlagValue> for FlagValue {
Mårten Kongstadbb520722023-04-26 13:16:41 +0200153 type Error = Error;
154
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200155 fn try_from(proto: ProtoFlagValue) -> Result<Self, Self::Error> {
Mårten Kongstad30950782023-05-09 13:31:29 +0200156 let Some(namespace) = proto.namespace else {
157 return Err(anyhow!("missing 'namespace' field"));
158 };
159 let Some(name) = proto.name else {
160 return Err(anyhow!("missing 'name' field"));
Mårten Kongstadbb520722023-04-26 13:16:41 +0200161 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200162 let Some(proto_state) = proto.state else {
163 return Err(anyhow!("missing 'state' field"));
Mårten Kongstadbb520722023-04-26 13:16:41 +0200164 };
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200165 let state = proto_state.try_into()?;
Mårten Kongstad416330b2023-05-05 11:10:01 +0200166 let Some(proto_permission) = proto.permission else {
167 return Err(anyhow!("missing 'permission' field"));
168 };
169 let permission = proto_permission.try_into()?;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200170 Ok(FlagValue { namespace, name, state, permission })
Mårten Kongstadbb520722023-04-26 13:16:41 +0200171 }
172}
173
Mårten Kongstad30950782023-05-09 13:31:29 +0200174impl From<Cache> for ProtoParsedFlags {
Mårten Kongstada1029092023-05-08 11:51:59 +0200175 fn from(cache: Cache) -> Self {
Mårten Kongstad30950782023-05-09 13:31:29 +0200176 let mut proto = ProtoParsedFlags::new();
Mårten Kongstada1029092023-05-08 11:51:59 +0200177 for item in cache.into_iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200178 proto.parsed_flag.push(item.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200179 }
Mårten Kongstad30950782023-05-09 13:31:29 +0200180 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200181 }
182}
183
Mårten Kongstad30950782023-05-09 13:31:29 +0200184impl From<Item> for ProtoParsedFlag {
Mårten Kongstada1029092023-05-08 11:51:59 +0200185 fn from(item: Item) -> Self {
Mårten Kongstad30950782023-05-09 13:31:29 +0200186 let mut proto = crate::protos::ProtoParsedFlag::new();
187 proto.set_namespace(item.namespace.to_owned());
188 proto.set_name(item.name.clone());
189 proto.set_description(item.description.clone());
190 proto.set_state(item.state.into());
191 proto.set_permission(item.permission.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200192 for trace in item.trace.into_iter() {
Mårten Kongstad30950782023-05-09 13:31:29 +0200193 proto.trace.push(trace.into());
Mårten Kongstada1029092023-05-08 11:51:59 +0200194 }
Mårten Kongstad30950782023-05-09 13:31:29 +0200195 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200196 }
197}
198
Mårten Kongstad30950782023-05-09 13:31:29 +0200199impl From<Tracepoint> for ProtoTracepoint {
200 fn from(tracepoint: Tracepoint) -> Self {
201 let mut proto = ProtoTracepoint::new();
202 proto.set_source(format!("{}", tracepoint.source));
203 proto.set_state(tracepoint.state.into());
204 proto.set_permission(tracepoint.permission.into());
205 proto
Mårten Kongstada1029092023-05-08 11:51:59 +0200206 }
207}
208
Mårten Kongstadbb520722023-04-26 13:16:41 +0200209#[cfg(test)]
210mod tests {
211 use super::*;
212
213 #[test]
214 fn test_flag_try_from_text_proto() {
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200215 let expected = FlagDeclaration {
Mårten Kongstad30950782023-05-09 13:31:29 +0200216 name: "1234".to_owned(),
Mårten Kongstadbb520722023-04-26 13:16:41 +0200217 description: "Description of the flag".to_owned(),
Mårten Kongstadbb520722023-04-26 13:16:41 +0200218 };
219
220 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200221 name: "1234"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200222 description: "Description of the flag"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200223 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200224 let actual = FlagDeclaration::try_from_text_proto(s).unwrap();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200225
226 assert_eq!(expected, actual);
227 }
228
229 #[test]
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200230 fn test_flag_try_from_text_proto_bad_input() {
231 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200232 name: "a"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200233 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200234 let error = FlagDeclaration::try_from_text_proto(s).unwrap_err();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200235 assert!(format!("{:?}", error).contains("Message not initialized"));
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200236
237 let s = r#"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200238 description: "Description of the flag"
Mårten Kongstad09c28d12023-05-04 13:29:26 +0200239 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200240 let error = FlagDeclaration::try_from_text_proto(s).unwrap_err();
241 assert!(format!("{:?}", error).contains("Message not initialized"));
Mårten Kongstadbb520722023-04-26 13:16:41 +0200242 }
243
244 #[test]
Mårten Kongstad30950782023-05-09 13:31:29 +0200245 fn test_namespace_try_from_text_proto() {
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200246 let expected = FlagDeclarations {
Mårten Kongstad30950782023-05-09 13:31:29 +0200247 namespace: "ns".to_owned(),
248 flags: vec![
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200249 FlagDeclaration { name: "a".to_owned(), description: "A".to_owned() },
250 FlagDeclaration { name: "b".to_owned(), description: "B".to_owned() },
Mårten Kongstad30950782023-05-09 13:31:29 +0200251 ],
252 };
Mårten Kongstadbb520722023-04-26 13:16:41 +0200253
254 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200255 namespace: "ns"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200256 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200257 name: "a"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200258 description: "A"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200259 }
260 flag {
Mårten Kongstad30950782023-05-09 13:31:29 +0200261 name: "b"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200262 description: "B"
Mårten Kongstadbb520722023-04-26 13:16:41 +0200263 }
264 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200265 let actual = FlagDeclarations::try_from_text_proto(s).unwrap();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200266
267 assert_eq!(expected, actual);
268 }
269
270 #[test]
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200271 fn test_flag_declaration_try_from_text_proto_list() {
272 let expected = FlagValue {
Mårten Kongstad30950782023-05-09 13:31:29 +0200273 namespace: "ns".to_owned(),
274 name: "1234".to_owned(),
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200275 state: FlagState::Enabled,
276 permission: Permission::ReadOnly,
277 };
Mårten Kongstadbb520722023-04-26 13:16:41 +0200278
279 let s = r#"
Mårten Kongstad30950782023-05-09 13:31:29 +0200280 namespace: "ns"
281 name: "1234"
Mårten Kongstadc68c4ea2023-05-05 16:20:09 +0200282 state: ENABLED
Mårten Kongstad416330b2023-05-05 11:10:01 +0200283 permission: READ_ONLY
Mårten Kongstadbb520722023-04-26 13:16:41 +0200284 "#;
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200285 let actual = FlagValue::try_from_text_proto(s).unwrap();
Mårten Kongstadbb520722023-04-26 13:16:41 +0200286
287 assert_eq!(expected, actual);
288 }
Mårten Kongstadbb520722023-04-26 13:16:41 +0200289}