blob: 4e4c7dd58a839916b4c1b66f7d1d2bfaae8a1715 [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();
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020035 let context = TemplateContext {
36 package: package.to_string(),
Mårten Kongstad403658f2023-06-14 09:51:56 +020037 template_flags,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020038 modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
39 };
Mårten Kongstadf73b9632023-05-24 15:43:47 +020040 let mut template = TinyTemplate::new();
Dennis Shen3cfbcf52023-07-17 14:57:23 +000041 template.add_template(
42 "rust_code_gen",
43 match codegen_mode {
44 CodegenMode::Production => include_str!("../templates/rust_prod.template"),
45 CodegenMode::Test => include_str!("../templates/rust_test.template"),
46 },
47 )?;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020048 let contents = template.render("rust_code_gen", &context)?;
49 let path = ["src", "lib.rs"].iter().collect();
50 Ok(OutputFile { contents: contents.into(), path })
51}
52
53#[derive(Serialize)]
54struct TemplateContext {
Mårten Kongstad9fb58962023-05-31 13:02:13 +020055 pub package: String,
Mårten Kongstad403658f2023-06-14 09:51:56 +020056 pub template_flags: Vec<TemplateParsedFlag>,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020057 pub modules: Vec<String>,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020058}
59
60#[derive(Serialize)]
61struct TemplateParsedFlag {
Dennis Shen3cfbcf52023-07-17 14:57:23 +000062 pub readwrite: bool,
63 pub default_value: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020064 pub name: String,
Mårten Kongstad066575b2023-06-07 16:29:25 +020065 pub device_config_namespace: String,
66 pub device_config_flag: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020067}
68
Mårten Kongstad066575b2023-06-07 16:29:25 +020069impl TemplateParsedFlag {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020070 #[allow(clippy::nonminimal_bool)]
Mårten Kongstad403658f2023-06-14 09:51:56 +020071 fn new(package: &str, pf: &ProtoParsedFlag) -> Self {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020072 let template = TemplateParsedFlag {
Dennis Shen3cfbcf52023-07-17 14:57:23 +000073 readwrite: pf.permission() == ProtoFlagPermission::READ_WRITE,
74 default_value: match pf.state() {
75 ProtoFlagState::ENABLED => "true".to_string(),
76 ProtoFlagState::DISABLED => "false".to_string(),
77 },
Mårten Kongstad403658f2023-06-14 09:51:56 +020078 name: pf.name().to_string(),
79 device_config_namespace: pf.namespace().to_string(),
80 device_config_flag: codegen::create_device_config_ident(package, pf.name())
81 .expect("values checked at flag parse time"),
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020082 };
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020083 template
84 }
Mårten Kongstadf73b9632023-05-24 15:43:47 +020085}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020090
Dennis Shen3cfbcf52023-07-17 14:57:23 +000091 const PROD_EXPECTED: &str = r#"
92//! codegenerated rust flag lib
93
94/// flag provider
Mårten Kongstad2d5309c2023-07-20 11:33:19 +020095pub struct FlagProvider;
Dennis Shen3cfbcf52023-07-17 14:57:23 +000096
97impl FlagProvider {
98 /// query flag disabled_ro
99 pub fn disabled_ro(&self) -> bool {
100 false
101 }
102
103 /// query flag disabled_rw
104 pub fn disabled_rw(&self) -> bool {
105 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000106 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000107 "com.android.aconfig.test.disabled_rw",
108 "false") == "true"
109 }
110
Zhi Dou71f1b352023-08-21 22:49:46 +0000111 /// query flag enabled_fixed_ro
112 pub fn enabled_fixed_ro(&self) -> bool {
113 true
114 }
115
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000116 /// query flag enabled_ro
117 pub fn enabled_ro(&self) -> bool {
118 true
119 }
120
121 /// query flag enabled_rw
122 pub fn enabled_rw(&self) -> bool {
123 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000124 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000125 "com.android.aconfig.test.enabled_rw",
126 "true") == "true"
127 }
128}
129
130/// flag provider
131pub static PROVIDER: FlagProvider = FlagProvider;
132
133/// query flag disabled_ro
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200134#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000135pub fn disabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200136 false
137}
138
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000139/// query flag disabled_rw
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200140#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000141pub fn disabled_rw() -> bool {
142 PROVIDER.disabled_rw()
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200143}
144
Zhi Dou71f1b352023-08-21 22:49:46 +0000145/// query flag enabled_fixed_ro
146#[inline(always)]
147pub fn enabled_fixed_ro() -> bool {
148 true
149}
150
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000151/// query flag enabled_ro
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200152#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000153pub fn enabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200154 true
155}
156
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000157/// query flag enabled_rw
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200158#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000159pub fn enabled_rw() -> bool {
160 PROVIDER.enabled_rw()
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200161}
162"#;
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000163
164 const TEST_EXPECTED: &str = r#"
165//! codegenerated rust flag lib
166
167use std::collections::BTreeMap;
168use std::sync::Mutex;
169
170/// flag provider
171pub struct FlagProvider {
172 overrides: BTreeMap<&'static str, bool>,
173}
174
175impl FlagProvider {
176 /// query flag disabled_ro
177 pub fn disabled_ro(&self) -> bool {
178 self.overrides.get("disabled_ro").copied().unwrap_or(
179 false
180 )
181 }
182
183 /// set flag disabled_ro
184 pub fn set_disabled_ro(&mut self, val: bool) {
185 self.overrides.insert("disabled_ro", val);
186 }
187
188 /// query flag disabled_rw
189 pub fn disabled_rw(&self) -> bool {
190 self.overrides.get("disabled_rw").copied().unwrap_or(
191 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000192 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000193 "com.android.aconfig.test.disabled_rw",
194 "false") == "true"
195 )
196 }
197
198 /// set flag disabled_rw
199 pub fn set_disabled_rw(&mut self, val: bool) {
200 self.overrides.insert("disabled_rw", val);
201 }
202
Zhi Dou71f1b352023-08-21 22:49:46 +0000203 /// query flag enabled_fixed_ro
204 pub fn enabled_fixed_ro(&self) -> bool {
205 self.overrides.get("enabled_fixed_ro").copied().unwrap_or(
206 true
207 )
208 }
209
210 /// set flag enabled_fixed_ro
211 pub fn set_enabled_fixed_ro(&mut self, val: bool) {
212 self.overrides.insert("enabled_fixed_ro", val);
213 }
214
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000215 /// query flag enabled_ro
216 pub fn enabled_ro(&self) -> bool {
217 self.overrides.get("enabled_ro").copied().unwrap_or(
218 true
219 )
220 }
221
222 /// set flag enabled_ro
223 pub fn set_enabled_ro(&mut self, val: bool) {
224 self.overrides.insert("enabled_ro", val);
225 }
226
227 /// query flag enabled_rw
228 pub fn enabled_rw(&self) -> bool {
229 self.overrides.get("enabled_rw").copied().unwrap_or(
230 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000231 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000232 "com.android.aconfig.test.enabled_rw",
233 "true") == "true"
234 )
235 }
236
237 /// set flag enabled_rw
238 pub fn set_enabled_rw(&mut self, val: bool) {
239 self.overrides.insert("enabled_rw", val);
240 }
241
242 /// clear all flag overrides
243 pub fn reset_flags(&mut self) {
244 self.overrides.clear();
245 }
246}
247
248/// flag provider
249pub static PROVIDER: Mutex<FlagProvider> = Mutex::new(
250 FlagProvider {overrides: BTreeMap::new()}
251);
252
253/// query flag disabled_ro
254#[inline(always)]
255pub fn disabled_ro() -> bool {
256 PROVIDER.lock().unwrap().disabled_ro()
257}
258
259/// set flag disabled_ro
260#[inline(always)]
261pub fn set_disabled_ro(val: bool) {
262 PROVIDER.lock().unwrap().set_disabled_ro(val);
263}
264
265/// query flag disabled_rw
266#[inline(always)]
267pub fn disabled_rw() -> bool {
268 PROVIDER.lock().unwrap().disabled_rw()
269}
270
271/// set flag disabled_rw
272#[inline(always)]
273pub fn set_disabled_rw(val: bool) {
274 PROVIDER.lock().unwrap().set_disabled_rw(val);
275}
276
Zhi Dou71f1b352023-08-21 22:49:46 +0000277/// query flag enabled_fixed_ro
278#[inline(always)]
279pub fn enabled_fixed_ro() -> bool {
280 PROVIDER.lock().unwrap().enabled_fixed_ro()
281}
282
283/// set flag enabled_fixed_ro
284#[inline(always)]
285pub fn set_enabled_fixed_ro(val: bool) {
286 PROVIDER.lock().unwrap().set_enabled_fixed_ro(val);
287}
288
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000289/// query flag enabled_ro
290#[inline(always)]
291pub fn enabled_ro() -> bool {
292 PROVIDER.lock().unwrap().enabled_ro()
293}
294
295/// set flag enabled_ro
296#[inline(always)]
297pub fn set_enabled_ro(val: bool) {
298 PROVIDER.lock().unwrap().set_enabled_ro(val);
299}
300
301/// query flag enabled_rw
302#[inline(always)]
303pub fn enabled_rw() -> bool {
304 PROVIDER.lock().unwrap().enabled_rw()
305}
306
307/// set flag enabled_rw
308#[inline(always)]
309pub fn set_enabled_rw(val: bool) {
310 PROVIDER.lock().unwrap().set_enabled_rw(val);
311}
312
313/// clear all flag override
314pub fn reset_flags() {
315 PROVIDER.lock().unwrap().reset_flags()
316}
317"#;
318
319 fn test_generate_rust_code(mode: CodegenMode) {
320 let parsed_flags = crate::test::parse_test_flags();
321 let generated =
322 generate_rust_code(crate::test::TEST_PACKAGE, parsed_flags.parsed_flag.iter(), mode)
323 .unwrap();
324 assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
Mårten Kongstadb0255072023-06-08 10:15:43 +0200325 assert_eq!(
326 None,
327 crate::test::first_significant_code_diff(
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000328 match mode {
329 CodegenMode::Production => PROD_EXPECTED,
330 CodegenMode::Test => TEST_EXPECTED,
331 },
Mårten Kongstadb0255072023-06-08 10:15:43 +0200332 &String::from_utf8(generated.contents).unwrap()
333 )
334 );
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200335 }
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000336
337 #[test]
338 fn test_generate_rust_code_for_prod() {
339 test_generate_rust_code(CodegenMode::Production);
340 }
341
342 #[test]
343 fn test_generate_rust_code_for_test() {
344 test_generate_rust_code(CodegenMode::Test);
345 }
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200346}