blob: 502cec8cd3c6a80ab74fef1bda64b51ad01a64b6 [file] [log] [blame]
Mårten Kongstadf73b9632023-05-24 15:43:47 +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::Result;
18use serde::Serialize;
19use tinytemplate::TinyTemplate;
20
Mårten Kongstad066575b2023-06-07 16:29:25 +020021use crate::codegen;
Dennis Shen3cfbcf52023-07-17 14:57:23 +000022use crate::commands::{CodegenMode, OutputFile};
Mårten Kongstad403658f2023-06-14 09:51:56 +020023use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
Mårten Kongstadf73b9632023-05-24 15:43:47 +020024
Dennis Shen3cfbcf52023-07-17 14:57:23 +000025pub fn generate_rust_code<'a, I>(
26 package: &str,
27 parsed_flags_iter: I,
28 codegen_mode: CodegenMode,
29) -> Result<OutputFile>
Mårten Kongstad403658f2023-06-14 09:51:56 +020030where
31 I: Iterator<Item = &'a ProtoParsedFlag>,
32{
33 let template_flags: Vec<TemplateParsedFlag> =
34 parsed_flags_iter.map(|pf| TemplateParsedFlag::new(package, pf)).collect();
Dennis Shen737b8e32023-11-08 19:58:47 +000035 let has_readwrite = template_flags.iter().any(|item| item.readwrite);
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020036 let context = TemplateContext {
37 package: package.to_string(),
Mårten Kongstad403658f2023-06-14 09:51:56 +020038 template_flags,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020039 modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
Dennis Shen737b8e32023-11-08 19:58:47 +000040 has_readwrite,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020041 };
Mårten Kongstadf73b9632023-05-24 15:43:47 +020042 let mut template = TinyTemplate::new();
Dennis Shen3cfbcf52023-07-17 14:57:23 +000043 template.add_template(
44 "rust_code_gen",
45 match codegen_mode {
46 CodegenMode::Production => include_str!("../templates/rust_prod.template"),
47 CodegenMode::Test => include_str!("../templates/rust_test.template"),
Ted Bauer4a6af782023-11-29 15:44:24 +000048 CodegenMode::Exported => {
49 todo!("exported mode not yet supported for rust, see b/313894653.")
50 }
Dennis Shen3cfbcf52023-07-17 14:57:23 +000051 },
52 )?;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020053 let contents = template.render("rust_code_gen", &context)?;
54 let path = ["src", "lib.rs"].iter().collect();
55 Ok(OutputFile { contents: contents.into(), path })
56}
57
58#[derive(Serialize)]
59struct TemplateContext {
Mårten Kongstad9fb58962023-05-31 13:02:13 +020060 pub package: String,
Mårten Kongstad403658f2023-06-14 09:51:56 +020061 pub template_flags: Vec<TemplateParsedFlag>,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020062 pub modules: Vec<String>,
Dennis Shen737b8e32023-11-08 19:58:47 +000063 pub has_readwrite: bool,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020064}
65
66#[derive(Serialize)]
67struct TemplateParsedFlag {
Dennis Shen3cfbcf52023-07-17 14:57:23 +000068 pub readwrite: bool,
69 pub default_value: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020070 pub name: String,
Mårten Kongstad066575b2023-06-07 16:29:25 +020071 pub device_config_namespace: String,
72 pub device_config_flag: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020073}
74
Mårten Kongstad066575b2023-06-07 16:29:25 +020075impl TemplateParsedFlag {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020076 #[allow(clippy::nonminimal_bool)]
Mårten Kongstad403658f2023-06-14 09:51:56 +020077 fn new(package: &str, pf: &ProtoParsedFlag) -> Self {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020078 let template = TemplateParsedFlag {
Dennis Shen3cfbcf52023-07-17 14:57:23 +000079 readwrite: pf.permission() == ProtoFlagPermission::READ_WRITE,
80 default_value: match pf.state() {
81 ProtoFlagState::ENABLED => "true".to_string(),
82 ProtoFlagState::DISABLED => "false".to_string(),
83 },
Mårten Kongstad403658f2023-06-14 09:51:56 +020084 name: pf.name().to_string(),
85 device_config_namespace: pf.namespace().to_string(),
86 device_config_flag: codegen::create_device_config_ident(package, pf.name())
87 .expect("values checked at flag parse time"),
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020088 };
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020089 template
90 }
Mårten Kongstadf73b9632023-05-24 15:43:47 +020091}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020096
Dennis Shen3cfbcf52023-07-17 14:57:23 +000097 const PROD_EXPECTED: &str = r#"
98//! codegenerated rust flag lib
99
100/// flag provider
Mårten Kongstad2d5309c2023-07-20 11:33:19 +0200101pub struct FlagProvider;
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000102
Dennis Shen737b8e32023-11-08 19:58:47 +0000103lazy_static::lazy_static! {
104 /// flag value cache for disabled_rw
105 static ref CACHED_disabled_rw: bool = flags_rust::GetServerConfigurableFlag(
106 "aconfig_flags.aconfig_test",
107 "com.android.aconfig.test.disabled_rw",
108 "false") == "true";
109
Ted Bauer4a6af782023-11-29 15:44:24 +0000110 /// flag value cache for disabled_rw_exported
111 static ref CACHED_disabled_rw_exported: bool = flags_rust::GetServerConfigurableFlag(
112 "aconfig_flags.aconfig_test",
113 "com.android.aconfig.test.disabled_rw_exported",
114 "false") == "true";
115
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100116 /// flag value cache for disabled_rw_in_other_namespace
117 static ref CACHED_disabled_rw_in_other_namespace: bool = flags_rust::GetServerConfigurableFlag(
Ted Bauerc3073782023-11-15 18:04:54 +0000118 "aconfig_flags.other_namespace",
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100119 "com.android.aconfig.test.disabled_rw_in_other_namespace",
Ted Bauerc3073782023-11-15 18:04:54 +0000120 "false") == "true";
121
Dennis Shen737b8e32023-11-08 19:58:47 +0000122 /// flag value cache for enabled_rw
123 static ref CACHED_enabled_rw: bool = flags_rust::GetServerConfigurableFlag(
124 "aconfig_flags.aconfig_test",
125 "com.android.aconfig.test.enabled_rw",
126 "true") == "true";
Ted Bauer4a6af782023-11-29 15:44:24 +0000127
Dennis Shen737b8e32023-11-08 19:58:47 +0000128}
129
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000130impl FlagProvider {
131 /// query flag disabled_ro
132 pub fn disabled_ro(&self) -> bool {
133 false
134 }
135
136 /// query flag disabled_rw
137 pub fn disabled_rw(&self) -> bool {
Dennis Shen737b8e32023-11-08 19:58:47 +0000138 *CACHED_disabled_rw
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000139 }
140
Ted Bauer4a6af782023-11-29 15:44:24 +0000141 /// query flag disabled_rw_exported
142 pub fn disabled_rw_exported(&self) -> bool {
143 *CACHED_disabled_rw_exported
144 }
145
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100146 /// query flag disabled_rw_in_other_namespace
147 pub fn disabled_rw_in_other_namespace(&self) -> bool {
148 *CACHED_disabled_rw_in_other_namespace
Ted Bauerc3073782023-11-15 18:04:54 +0000149 }
150
Zhi Dou71f1b352023-08-21 22:49:46 +0000151 /// query flag enabled_fixed_ro
152 pub fn enabled_fixed_ro(&self) -> bool {
153 true
154 }
155
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000156 /// query flag enabled_ro
157 pub fn enabled_ro(&self) -> bool {
158 true
159 }
160
161 /// query flag enabled_rw
162 pub fn enabled_rw(&self) -> bool {
Dennis Shen737b8e32023-11-08 19:58:47 +0000163 *CACHED_enabled_rw
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000164 }
165}
166
167/// flag provider
168pub static PROVIDER: FlagProvider = FlagProvider;
169
170/// query flag disabled_ro
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200171#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000172pub fn disabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200173 false
174}
175
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000176/// query flag disabled_rw
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200177#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000178pub fn disabled_rw() -> bool {
179 PROVIDER.disabled_rw()
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200180}
181
Ted Bauer4a6af782023-11-29 15:44:24 +0000182/// query flag disabled_rw_exported
183#[inline(always)]
184pub fn disabled_rw_exported() -> bool {
185 PROVIDER.disabled_rw_exported()
186}
187
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100188/// query flag disabled_rw_in_other_namespace
Ted Bauerc3073782023-11-15 18:04:54 +0000189#[inline(always)]
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100190pub fn disabled_rw_in_other_namespace() -> bool {
191 PROVIDER.disabled_rw_in_other_namespace()
Ted Bauerc3073782023-11-15 18:04:54 +0000192}
193
Zhi Dou71f1b352023-08-21 22:49:46 +0000194/// query flag enabled_fixed_ro
195#[inline(always)]
196pub fn enabled_fixed_ro() -> bool {
197 true
198}
199
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000200/// query flag enabled_ro
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200201#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000202pub fn enabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200203 true
204}
205
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000206/// query flag enabled_rw
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200207#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000208pub fn enabled_rw() -> bool {
209 PROVIDER.enabled_rw()
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200210}
211"#;
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000212
213 const TEST_EXPECTED: &str = r#"
214//! codegenerated rust flag lib
215
216use std::collections::BTreeMap;
217use std::sync::Mutex;
218
219/// flag provider
220pub struct FlagProvider {
221 overrides: BTreeMap<&'static str, bool>,
222}
223
224impl FlagProvider {
225 /// query flag disabled_ro
226 pub fn disabled_ro(&self) -> bool {
227 self.overrides.get("disabled_ro").copied().unwrap_or(
228 false
229 )
230 }
231
232 /// set flag disabled_ro
233 pub fn set_disabled_ro(&mut self, val: bool) {
234 self.overrides.insert("disabled_ro", val);
235 }
236
237 /// query flag disabled_rw
238 pub fn disabled_rw(&self) -> bool {
239 self.overrides.get("disabled_rw").copied().unwrap_or(
240 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000241 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000242 "com.android.aconfig.test.disabled_rw",
243 "false") == "true"
244 )
245 }
246
247 /// set flag disabled_rw
248 pub fn set_disabled_rw(&mut self, val: bool) {
249 self.overrides.insert("disabled_rw", val);
250 }
251
Ted Bauer4a6af782023-11-29 15:44:24 +0000252 /// query flag disabled_rw_exported
253 pub fn disabled_rw_exported(&self) -> bool {
254 self.overrides.get("disabled_rw_exported").copied().unwrap_or(
255 flags_rust::GetServerConfigurableFlag(
256 "aconfig_flags.aconfig_test",
257 "com.android.aconfig.test.disabled_rw_exported",
258 "false") == "true"
259 )
260 }
261
262 /// set flag disabled_rw_exported
263 pub fn set_disabled_rw_exported(&mut self, val: bool) {
264 self.overrides.insert("disabled_rw_exported", val);
265 }
266
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100267 /// query flag disabled_rw_in_other_namespace
268 pub fn disabled_rw_in_other_namespace(&self) -> bool {
269 self.overrides.get("disabled_rw_in_other_namespace").copied().unwrap_or(
Ted Bauerc3073782023-11-15 18:04:54 +0000270 flags_rust::GetServerConfigurableFlag(
271 "aconfig_flags.other_namespace",
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100272 "com.android.aconfig.test.disabled_rw_in_other_namespace",
Ted Bauerc3073782023-11-15 18:04:54 +0000273 "false") == "true"
274 )
275 }
276
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100277 /// set flag disabled_rw_in_other_namespace
278 pub fn set_disabled_rw_in_other_namespace(&mut self, val: bool) {
279 self.overrides.insert("disabled_rw_in_other_namespace", val);
Ted Bauerc3073782023-11-15 18:04:54 +0000280 }
281
Zhi Dou71f1b352023-08-21 22:49:46 +0000282 /// query flag enabled_fixed_ro
283 pub fn enabled_fixed_ro(&self) -> bool {
284 self.overrides.get("enabled_fixed_ro").copied().unwrap_or(
285 true
286 )
287 }
288
289 /// set flag enabled_fixed_ro
290 pub fn set_enabled_fixed_ro(&mut self, val: bool) {
291 self.overrides.insert("enabled_fixed_ro", val);
292 }
293
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000294 /// query flag enabled_ro
295 pub fn enabled_ro(&self) -> bool {
296 self.overrides.get("enabled_ro").copied().unwrap_or(
297 true
298 )
299 }
300
301 /// set flag enabled_ro
302 pub fn set_enabled_ro(&mut self, val: bool) {
303 self.overrides.insert("enabled_ro", val);
304 }
305
306 /// query flag enabled_rw
307 pub fn enabled_rw(&self) -> bool {
308 self.overrides.get("enabled_rw").copied().unwrap_or(
309 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000310 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000311 "com.android.aconfig.test.enabled_rw",
312 "true") == "true"
313 )
314 }
315
316 /// set flag enabled_rw
317 pub fn set_enabled_rw(&mut self, val: bool) {
318 self.overrides.insert("enabled_rw", val);
319 }
320
321 /// clear all flag overrides
322 pub fn reset_flags(&mut self) {
323 self.overrides.clear();
324 }
325}
326
327/// flag provider
328pub static PROVIDER: Mutex<FlagProvider> = Mutex::new(
329 FlagProvider {overrides: BTreeMap::new()}
330);
331
332/// query flag disabled_ro
333#[inline(always)]
334pub fn disabled_ro() -> bool {
335 PROVIDER.lock().unwrap().disabled_ro()
336}
337
338/// set flag disabled_ro
339#[inline(always)]
340pub fn set_disabled_ro(val: bool) {
341 PROVIDER.lock().unwrap().set_disabled_ro(val);
342}
343
344/// query flag disabled_rw
345#[inline(always)]
346pub fn disabled_rw() -> bool {
347 PROVIDER.lock().unwrap().disabled_rw()
348}
349
350/// set flag disabled_rw
351#[inline(always)]
352pub fn set_disabled_rw(val: bool) {
353 PROVIDER.lock().unwrap().set_disabled_rw(val);
354}
355
Ted Bauer4a6af782023-11-29 15:44:24 +0000356/// query flag disabled_rw_exported
357#[inline(always)]
358pub fn disabled_rw_exported() -> bool {
359 PROVIDER.lock().unwrap().disabled_rw_exported()
360}
361
362/// set flag disabled_rw_exported
363#[inline(always)]
364pub fn set_disabled_rw_exported(val: bool) {
365 PROVIDER.lock().unwrap().set_disabled_rw_exported(val);
366}
367
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100368/// query flag disabled_rw_in_other_namespace
Ted Bauerc3073782023-11-15 18:04:54 +0000369#[inline(always)]
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100370pub fn disabled_rw_in_other_namespace() -> bool {
371 PROVIDER.lock().unwrap().disabled_rw_in_other_namespace()
Ted Bauerc3073782023-11-15 18:04:54 +0000372}
373
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100374/// set flag disabled_rw_in_other_namespace
Ted Bauerc3073782023-11-15 18:04:54 +0000375#[inline(always)]
Mårten Kongstadbc76a3d2023-11-17 09:37:06 +0100376pub fn set_disabled_rw_in_other_namespace(val: bool) {
377 PROVIDER.lock().unwrap().set_disabled_rw_in_other_namespace(val);
Ted Bauerc3073782023-11-15 18:04:54 +0000378}
379
Zhi Dou71f1b352023-08-21 22:49:46 +0000380/// query flag enabled_fixed_ro
381#[inline(always)]
382pub fn enabled_fixed_ro() -> bool {
383 PROVIDER.lock().unwrap().enabled_fixed_ro()
384}
385
386/// set flag enabled_fixed_ro
387#[inline(always)]
388pub fn set_enabled_fixed_ro(val: bool) {
389 PROVIDER.lock().unwrap().set_enabled_fixed_ro(val);
390}
391
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000392/// query flag enabled_ro
393#[inline(always)]
394pub fn enabled_ro() -> bool {
395 PROVIDER.lock().unwrap().enabled_ro()
396}
397
398/// set flag enabled_ro
399#[inline(always)]
400pub fn set_enabled_ro(val: bool) {
401 PROVIDER.lock().unwrap().set_enabled_ro(val);
402}
403
404/// query flag enabled_rw
405#[inline(always)]
406pub fn enabled_rw() -> bool {
407 PROVIDER.lock().unwrap().enabled_rw()
408}
409
410/// set flag enabled_rw
411#[inline(always)]
412pub fn set_enabled_rw(val: bool) {
413 PROVIDER.lock().unwrap().set_enabled_rw(val);
414}
415
416/// clear all flag override
417pub fn reset_flags() {
418 PROVIDER.lock().unwrap().reset_flags()
419}
420"#;
421
422 fn test_generate_rust_code(mode: CodegenMode) {
423 let parsed_flags = crate::test::parse_test_flags();
424 let generated =
425 generate_rust_code(crate::test::TEST_PACKAGE, parsed_flags.parsed_flag.iter(), mode)
426 .unwrap();
427 assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
Mårten Kongstadb0255072023-06-08 10:15:43 +0200428 assert_eq!(
429 None,
430 crate::test::first_significant_code_diff(
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000431 match mode {
432 CodegenMode::Production => PROD_EXPECTED,
433 CodegenMode::Test => TEST_EXPECTED,
Ted Bauer4a6af782023-11-29 15:44:24 +0000434 CodegenMode::Exported =>
435 todo!("exported mode not yet supported for rust, see b/313894653."),
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000436 },
Mårten Kongstadb0255072023-06-08 10:15:43 +0200437 &String::from_utf8(generated.contents).unwrap()
438 )
439 );
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200440 }
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000441
442 #[test]
443 fn test_generate_rust_code_for_prod() {
444 test_generate_rust_code(CodegenMode::Production);
445 }
446
447 #[test]
448 fn test_generate_rust_code_for_test() {
449 test_generate_rust_code(CodegenMode::Test);
450 }
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200451}