blob: f931418a7b0ca708ee4260d93f817e48d048eb1f [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;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020022use crate::commands::OutputFile;
Mårten Kongstad403658f2023-06-14 09:51:56 +020023use crate::protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
Mårten Kongstadf73b9632023-05-24 15:43:47 +020024
Mårten Kongstad403658f2023-06-14 09:51:56 +020025pub fn generate_rust_code<'a, I>(package: &str, parsed_flags_iter: I) -> Result<OutputFile>
26where
27 I: Iterator<Item = &'a ProtoParsedFlag>,
28{
29 let template_flags: Vec<TemplateParsedFlag> =
30 parsed_flags_iter.map(|pf| TemplateParsedFlag::new(package, pf)).collect();
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020031 let context = TemplateContext {
32 package: package.to_string(),
Mårten Kongstad403658f2023-06-14 09:51:56 +020033 template_flags,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020034 modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
35 };
Mårten Kongstadf73b9632023-05-24 15:43:47 +020036 let mut template = TinyTemplate::new();
37 template.add_template("rust_code_gen", include_str!("../templates/rust.template"))?;
38 let contents = template.render("rust_code_gen", &context)?;
39 let path = ["src", "lib.rs"].iter().collect();
40 Ok(OutputFile { contents: contents.into(), path })
41}
42
43#[derive(Serialize)]
44struct TemplateContext {
Mårten Kongstad9fb58962023-05-31 13:02:13 +020045 pub package: String,
Mårten Kongstad403658f2023-06-14 09:51:56 +020046 pub template_flags: Vec<TemplateParsedFlag>,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020047 pub modules: Vec<String>,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020048}
49
50#[derive(Serialize)]
51struct TemplateParsedFlag {
52 pub name: String,
Mårten Kongstad066575b2023-06-07 16:29:25 +020053 pub device_config_namespace: String,
54 pub device_config_flag: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020055
56 // TinyTemplate's conditionals are limited to single <bool> expressions; list all options here
57 // Invariant: exactly one of these fields will be true
58 pub is_read_only_enabled: bool,
59 pub is_read_only_disabled: bool,
60 pub is_read_write: bool,
61}
62
Mårten Kongstad066575b2023-06-07 16:29:25 +020063impl TemplateParsedFlag {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020064 #[allow(clippy::nonminimal_bool)]
Mårten Kongstad403658f2023-06-14 09:51:56 +020065 fn new(package: &str, pf: &ProtoParsedFlag) -> Self {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020066 let template = TemplateParsedFlag {
Mårten Kongstad403658f2023-06-14 09:51:56 +020067 name: pf.name().to_string(),
68 device_config_namespace: pf.namespace().to_string(),
69 device_config_flag: codegen::create_device_config_ident(package, pf.name())
70 .expect("values checked at flag parse time"),
71 is_read_only_enabled: pf.permission() == ProtoFlagPermission::READ_ONLY
72 && pf.state() == ProtoFlagState::ENABLED,
73 is_read_only_disabled: pf.permission() == ProtoFlagPermission::READ_ONLY
74 && pf.state() == ProtoFlagState::DISABLED,
75 is_read_write: pf.permission() == ProtoFlagPermission::READ_WRITE,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020076 };
77 #[rustfmt::skip]
78 debug_assert!(
79 (template.is_read_only_enabled && !template.is_read_only_disabled && !template.is_read_write) ||
80 (!template.is_read_only_enabled && template.is_read_only_disabled && !template.is_read_write) ||
81 (!template.is_read_only_enabled && !template.is_read_only_disabled && template.is_read_write),
82 "TemplateParsedFlag invariant failed: {} {} {}",
83 template.is_read_only_enabled,
84 template.is_read_only_disabled,
85 template.is_read_write,
86 );
87 template
88 }
Mårten Kongstadf73b9632023-05-24 15:43:47 +020089}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020094
95 #[test]
96 fn test_generate_rust_code() {
Mårten Kongstad403658f2023-06-14 09:51:56 +020097 let parsed_flags = crate::test::parse_test_flags();
98 let generated =
99 generate_rust_code(crate::test::TEST_PACKAGE, parsed_flags.parsed_flag.iter()).unwrap();
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200100 assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
101 let expected = r#"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200102pub mod com {
103pub mod android {
104pub mod aconfig {
105pub mod test {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200106#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200107pub const fn r#disabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200108 false
109}
110
111#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200112pub fn r#disabled_rw() -> bool {
Mårten Kongstad066575b2023-06-07 16:29:25 +0200113 flags_rust::GetServerConfigurableFlag("aconfig_test", "com.android.aconfig.test.disabled_rw", "false") == "true"
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200114}
115
116#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200117pub const fn r#enabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200118 true
119}
120
121#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200122pub fn r#enabled_rw() -> bool {
Mårten Kongstad066575b2023-06-07 16:29:25 +0200123 flags_rust::GetServerConfigurableFlag("aconfig_test", "com.android.aconfig.test.enabled_rw", "false") == "true"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200124}
125
126}
127}
128}
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200129}
130"#;
Mårten Kongstadb0255072023-06-08 10:15:43 +0200131 assert_eq!(
132 None,
133 crate::test::first_significant_code_diff(
134 expected,
135 &String::from_utf8(generated.contents).unwrap()
136 )
137 );
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200138 }
139}