blob: e972185eaaf07b88b47972b45ab4ce9030e04801 [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 Kongstadf73b9632023-05-24 15:43:47 +020027 let parsed_flags: Vec<TemplateParsedFlag> =
Mårten Kongstad9fb58962023-05-31 13:02:13 +020028 cache.iter().map(|item| create_template_parsed_flag(package, item)).collect();
29 let context = TemplateContext { package: package.to_string(), parsed_flags };
Mårten Kongstadf73b9632023-05-24 15:43:47 +020030 let mut template = TinyTemplate::new();
31 template.add_template("rust_code_gen", include_str!("../templates/rust.template"))?;
32 let contents = template.render("rust_code_gen", &context)?;
33 let path = ["src", "lib.rs"].iter().collect();
34 Ok(OutputFile { contents: contents.into(), path })
35}
36
37#[derive(Serialize)]
38struct TemplateContext {
Mårten Kongstad9fb58962023-05-31 13:02:13 +020039 pub package: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020040 pub parsed_flags: Vec<TemplateParsedFlag>,
41}
42
43#[derive(Serialize)]
44struct TemplateParsedFlag {
45 pub name: String,
46 pub fn_name: String,
47
48 // TinyTemplate's conditionals are limited to single <bool> expressions; list all options here
49 // Invariant: exactly one of these fields will be true
50 pub is_read_only_enabled: bool,
51 pub is_read_only_disabled: bool,
52 pub is_read_write: bool,
53}
54
55#[allow(clippy::nonminimal_bool)]
Mårten Kongstad9fb58962023-05-31 13:02:13 +020056fn create_template_parsed_flag(package: &str, item: &Item) -> TemplateParsedFlag {
Mårten Kongstadf73b9632023-05-24 15:43:47 +020057 let template = TemplateParsedFlag {
58 name: item.name.clone(),
Mårten Kongstad9fb58962023-05-31 13:02:13 +020059 fn_name: format!("{}_{}", package, &item.name),
Mårten Kongstadf73b9632023-05-24 15:43:47 +020060 is_read_only_enabled: item.permission == Permission::ReadOnly
61 && item.state == FlagState::Enabled,
62 is_read_only_disabled: item.permission == Permission::ReadOnly
63 && item.state == FlagState::Disabled,
64 is_read_write: item.permission == Permission::ReadWrite,
65 };
66 #[rustfmt::skip]
67 debug_assert!(
68 (template.is_read_only_enabled && !template.is_read_only_disabled && !template.is_read_write) ||
69 (!template.is_read_only_enabled && template.is_read_only_disabled && !template.is_read_write) ||
70 (!template.is_read_only_enabled && !template.is_read_only_disabled && template.is_read_write),
71 "TemplateParsedFlag invariant failed: {} {} {}",
72 template.is_read_only_enabled,
73 template.is_read_only_disabled,
74 template.is_read_write,
75 );
76 template
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020082
83 #[test]
84 fn test_generate_rust_code() {
Mårten Kongstad83a87602023-06-02 11:20:15 +020085 let cache = crate::test::create_cache();
Mårten Kongstadf73b9632023-05-24 15:43:47 +020086 let generated = generate_rust_code(&cache).unwrap();
87 assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
88 let expected = r#"
89#[inline(always)]
90pub const fn r#test_disabled_ro() -> bool {
91 false
92}
93
94#[inline(always)]
95pub fn r#test_disabled_rw() -> bool {
Dennis Shen64616732023-05-30 14:20:50 +000096 flags_rust::GetServerConfigurableFlag("test", "disabled_rw", "false") == "true"
Mårten Kongstadf73b9632023-05-24 15:43:47 +020097}
98
99#[inline(always)]
100pub const fn r#test_enabled_ro() -> bool {
101 true
102}
103
104#[inline(always)]
105pub fn r#test_enabled_rw() -> bool {
Dennis Shen64616732023-05-30 14:20:50 +0000106 flags_rust::GetServerConfigurableFlag("test", "enabled_rw", "false") == "true"
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200107}
108"#;
109 assert_eq!(expected.trim(), String::from_utf8(generated.contents).unwrap().trim());
110 }
111}