blob: e27aa9cb448ae31a40b62979405a18dfcdecfb46 [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
21use crate::aconfig::{FlagState, Permission};
22use crate::cache::{Cache, Item};
23use crate::commands::OutputFile;
24
25pub fn generate_rust_code(cache: &Cache) -> Result<OutputFile> {
Mårten Kongstad9fb58962023-05-31 13:02:13 +020026 let package = cache.package();
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020027 let parsed_flags: Vec<TemplateParsedFlag> = cache.iter().map(|item| item.into()).collect();
28 let context = TemplateContext {
29 package: package.to_string(),
30 parsed_flags,
31 modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
32 };
Mårten Kongstadf73b9632023-05-24 15:43:47 +020033 let mut template = TinyTemplate::new();
34 template.add_template("rust_code_gen", include_str!("../templates/rust.template"))?;
35 let contents = template.render("rust_code_gen", &context)?;
36 let path = ["src", "lib.rs"].iter().collect();
37 Ok(OutputFile { contents: contents.into(), path })
38}
39
40#[derive(Serialize)]
41struct TemplateContext {
Mårten Kongstad9fb58962023-05-31 13:02:13 +020042 pub package: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020043 pub parsed_flags: Vec<TemplateParsedFlag>,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020044 pub modules: Vec<String>,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020045}
46
47#[derive(Serialize)]
48struct TemplateParsedFlag {
49 pub name: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020050
51 // TinyTemplate's conditionals are limited to single <bool> expressions; list all options here
52 // Invariant: exactly one of these fields will be true
53 pub is_read_only_enabled: bool,
54 pub is_read_only_disabled: bool,
55 pub is_read_write: bool,
56}
57
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020058impl From<&Item> for TemplateParsedFlag {
59 #[allow(clippy::nonminimal_bool)]
60 fn from(item: &Item) -> Self {
61 let template = TemplateParsedFlag {
62 name: item.name.clone(),
63 is_read_only_enabled: item.permission == Permission::ReadOnly
64 && item.state == FlagState::Enabled,
65 is_read_only_disabled: item.permission == Permission::ReadOnly
66 && item.state == FlagState::Disabled,
67 is_read_write: item.permission == Permission::ReadWrite,
68 };
69 #[rustfmt::skip]
70 debug_assert!(
71 (template.is_read_only_enabled && !template.is_read_only_disabled && !template.is_read_write) ||
72 (!template.is_read_only_enabled && template.is_read_only_disabled && !template.is_read_write) ||
73 (!template.is_read_only_enabled && !template.is_read_only_disabled && template.is_read_write),
74 "TemplateParsedFlag invariant failed: {} {} {}",
75 template.is_read_only_enabled,
76 template.is_read_only_disabled,
77 template.is_read_write,
78 );
79 template
80 }
Mårten Kongstadf73b9632023-05-24 15:43:47 +020081}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020086
87 #[test]
88 fn test_generate_rust_code() {
Mårten Kongstad83a87602023-06-02 11:20:15 +020089 let cache = crate::test::create_cache();
Mårten Kongstadf73b9632023-05-24 15:43:47 +020090 let generated = generate_rust_code(&cache).unwrap();
91 assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
92 let expected = r#"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020093pub mod com {
94pub mod android {
95pub mod aconfig {
96pub mod test {
Mårten Kongstadf73b9632023-05-24 15:43:47 +020097#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020098pub const fn r#disabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +020099 false
100}
101
102#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200103pub fn r#disabled_rw() -> bool {
104 flags_rust::GetServerConfigurableFlag("com.android.aconfig.test", "disabled_rw", "false") == "true"
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200105}
106
107#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200108pub const fn r#enabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200109 true
110}
111
112#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200113pub fn r#enabled_rw() -> bool {
114 flags_rust::GetServerConfigurableFlag("com.android.aconfig.test", "enabled_rw", "false") == "true"
115}
116
117}
118}
119}
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200120}
121"#;
122 assert_eq!(expected.trim(), String::from_utf8(generated.contents).unwrap().trim());
123 }
124}