blob: 0234eb25d58ea998f9e0f061b8a66c69b09757e9 [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
111 /// query flag enabled_ro
112 pub fn enabled_ro(&self) -> bool {
113 true
114 }
115
116 /// query flag enabled_rw
117 pub fn enabled_rw(&self) -> bool {
118 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000119 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000120 "com.android.aconfig.test.enabled_rw",
121 "true") == "true"
122 }
123}
124
125/// flag provider
126pub static PROVIDER: FlagProvider = FlagProvider;
127
128/// query flag disabled_ro
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200129#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000130pub fn disabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200131 false
132}
133
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000134/// query flag disabled_rw
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200135#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000136pub fn disabled_rw() -> bool {
137 PROVIDER.disabled_rw()
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200138}
139
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000140/// query flag enabled_ro
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200141#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000142pub fn enabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200143 true
144}
145
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000146/// query flag enabled_rw
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200147#[inline(always)]
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000148pub fn enabled_rw() -> bool {
149 PROVIDER.enabled_rw()
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200150}
151"#;
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000152
153 const TEST_EXPECTED: &str = r#"
154//! codegenerated rust flag lib
155
156use std::collections::BTreeMap;
157use std::sync::Mutex;
158
159/// flag provider
160pub struct FlagProvider {
161 overrides: BTreeMap<&'static str, bool>,
162}
163
164impl FlagProvider {
165 /// query flag disabled_ro
166 pub fn disabled_ro(&self) -> bool {
167 self.overrides.get("disabled_ro").copied().unwrap_or(
168 false
169 )
170 }
171
172 /// set flag disabled_ro
173 pub fn set_disabled_ro(&mut self, val: bool) {
174 self.overrides.insert("disabled_ro", val);
175 }
176
177 /// query flag disabled_rw
178 pub fn disabled_rw(&self) -> bool {
179 self.overrides.get("disabled_rw").copied().unwrap_or(
180 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000181 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000182 "com.android.aconfig.test.disabled_rw",
183 "false") == "true"
184 )
185 }
186
187 /// set flag disabled_rw
188 pub fn set_disabled_rw(&mut self, val: bool) {
189 self.overrides.insert("disabled_rw", val);
190 }
191
192 /// query flag enabled_ro
193 pub fn enabled_ro(&self) -> bool {
194 self.overrides.get("enabled_ro").copied().unwrap_or(
195 true
196 )
197 }
198
199 /// set flag enabled_ro
200 pub fn set_enabled_ro(&mut self, val: bool) {
201 self.overrides.insert("enabled_ro", val);
202 }
203
204 /// query flag enabled_rw
205 pub fn enabled_rw(&self) -> bool {
206 self.overrides.get("enabled_rw").copied().unwrap_or(
207 flags_rust::GetServerConfigurableFlag(
Dennis Shenb352b9d2023-08-16 17:33:33 +0000208 "aconfig_flags.aconfig_test",
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000209 "com.android.aconfig.test.enabled_rw",
210 "true") == "true"
211 )
212 }
213
214 /// set flag enabled_rw
215 pub fn set_enabled_rw(&mut self, val: bool) {
216 self.overrides.insert("enabled_rw", val);
217 }
218
219 /// clear all flag overrides
220 pub fn reset_flags(&mut self) {
221 self.overrides.clear();
222 }
223}
224
225/// flag provider
226pub static PROVIDER: Mutex<FlagProvider> = Mutex::new(
227 FlagProvider {overrides: BTreeMap::new()}
228);
229
230/// query flag disabled_ro
231#[inline(always)]
232pub fn disabled_ro() -> bool {
233 PROVIDER.lock().unwrap().disabled_ro()
234}
235
236/// set flag disabled_ro
237#[inline(always)]
238pub fn set_disabled_ro(val: bool) {
239 PROVIDER.lock().unwrap().set_disabled_ro(val);
240}
241
242/// query flag disabled_rw
243#[inline(always)]
244pub fn disabled_rw() -> bool {
245 PROVIDER.lock().unwrap().disabled_rw()
246}
247
248/// set flag disabled_rw
249#[inline(always)]
250pub fn set_disabled_rw(val: bool) {
251 PROVIDER.lock().unwrap().set_disabled_rw(val);
252}
253
254/// query flag enabled_ro
255#[inline(always)]
256pub fn enabled_ro() -> bool {
257 PROVIDER.lock().unwrap().enabled_ro()
258}
259
260/// set flag enabled_ro
261#[inline(always)]
262pub fn set_enabled_ro(val: bool) {
263 PROVIDER.lock().unwrap().set_enabled_ro(val);
264}
265
266/// query flag enabled_rw
267#[inline(always)]
268pub fn enabled_rw() -> bool {
269 PROVIDER.lock().unwrap().enabled_rw()
270}
271
272/// set flag enabled_rw
273#[inline(always)]
274pub fn set_enabled_rw(val: bool) {
275 PROVIDER.lock().unwrap().set_enabled_rw(val);
276}
277
278/// clear all flag override
279pub fn reset_flags() {
280 PROVIDER.lock().unwrap().reset_flags()
281}
282"#;
283
284 fn test_generate_rust_code(mode: CodegenMode) {
285 let parsed_flags = crate::test::parse_test_flags();
286 let generated =
287 generate_rust_code(crate::test::TEST_PACKAGE, parsed_flags.parsed_flag.iter(), mode)
288 .unwrap();
289 assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
Mårten Kongstadb0255072023-06-08 10:15:43 +0200290 assert_eq!(
291 None,
292 crate::test::first_significant_code_diff(
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000293 match mode {
294 CodegenMode::Production => PROD_EXPECTED,
295 CodegenMode::Test => TEST_EXPECTED,
296 },
Mårten Kongstadb0255072023-06-08 10:15:43 +0200297 &String::from_utf8(generated.contents).unwrap()
298 )
299 );
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200300 }
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000301
302 #[test]
303 fn test_generate_rust_code_for_prod() {
304 test_generate_rust_code(CodegenMode::Production);
305 }
306
307 #[test]
308 fn test_generate_rust_code_for_test() {
309 test_generate_rust_code(CodegenMode::Test);
310 }
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200311}