blob: cfe7316ff561eab478f0d0bd3f2128db69e2e95d [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};
Mårten Kongstad066575b2023-06-07 16:29:25 +020023use crate::codegen;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020024use crate::commands::OutputFile;
25
26pub fn generate_rust_code(cache: &Cache) -> Result<OutputFile> {
Mårten Kongstad9fb58962023-05-31 13:02:13 +020027 let package = cache.package();
Mårten Kongstad066575b2023-06-07 16:29:25 +020028 let parsed_flags: Vec<TemplateParsedFlag> =
29 cache.iter().map(|item| TemplateParsedFlag::new(package, item)).collect();
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020030 let context = TemplateContext {
31 package: package.to_string(),
32 parsed_flags,
33 modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
34 };
Mårten Kongstadf73b9632023-05-24 15:43:47 +020035 let mut template = TinyTemplate::new();
36 template.add_template("rust_code_gen", include_str!("../templates/rust.template"))?;
37 let contents = template.render("rust_code_gen", &context)?;
38 let path = ["src", "lib.rs"].iter().collect();
39 Ok(OutputFile { contents: contents.into(), path })
40}
41
42#[derive(Serialize)]
43struct TemplateContext {
Mårten Kongstad9fb58962023-05-31 13:02:13 +020044 pub package: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020045 pub parsed_flags: Vec<TemplateParsedFlag>,
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020046 pub modules: Vec<String>,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020047}
48
49#[derive(Serialize)]
50struct TemplateParsedFlag {
51 pub name: String,
Mårten Kongstad066575b2023-06-07 16:29:25 +020052 pub device_config_namespace: String,
53 pub device_config_flag: String,
Mårten Kongstadf73b9632023-05-24 15:43:47 +020054
55 // TinyTemplate's conditionals are limited to single <bool> expressions; list all options here
56 // Invariant: exactly one of these fields will be true
57 pub is_read_only_enabled: bool,
58 pub is_read_only_disabled: bool,
59 pub is_read_write: bool,
60}
61
Mårten Kongstad066575b2023-06-07 16:29:25 +020062impl TemplateParsedFlag {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020063 #[allow(clippy::nonminimal_bool)]
Mårten Kongstad066575b2023-06-07 16:29:25 +020064 fn new(package: &str, item: &Item) -> Self {
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020065 let template = TemplateParsedFlag {
66 name: item.name.clone(),
Mårten Kongstad066575b2023-06-07 16:29:25 +020067 device_config_namespace: item.namespace.to_string(),
68 device_config_flag: codegen::create_device_config_ident(package, &item.name)
69 .expect("values checked at cache creation time"),
Mårten Kongstadfbd71e22023-05-31 13:29:35 +020070 is_read_only_enabled: item.permission == Permission::ReadOnly
71 && item.state == FlagState::Enabled,
72 is_read_only_disabled: item.permission == Permission::ReadOnly
73 && item.state == FlagState::Disabled,
74 is_read_write: item.permission == Permission::ReadWrite,
75 };
76 #[rustfmt::skip]
77 debug_assert!(
78 (template.is_read_only_enabled && !template.is_read_only_disabled && !template.is_read_write) ||
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 "TemplateParsedFlag invariant failed: {} {} {}",
82 template.is_read_only_enabled,
83 template.is_read_only_disabled,
84 template.is_read_write,
85 );
86 template
87 }
Mårten Kongstadf73b9632023-05-24 15:43:47 +020088}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
Mårten Kongstadf73b9632023-05-24 15:43:47 +020093
94 #[test]
95 fn test_generate_rust_code() {
Mårten Kongstad83a87602023-06-02 11:20:15 +020096 let cache = crate::test::create_cache();
Mårten Kongstadf73b9632023-05-24 15:43:47 +020097 let generated = generate_rust_code(&cache).unwrap();
98 assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
99 let expected = r#"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200100pub mod com {
101pub mod android {
102pub mod aconfig {
103pub mod test {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200104#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200105pub const fn r#disabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200106 false
107}
108
109#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200110pub fn r#disabled_rw() -> bool {
Mårten Kongstad066575b2023-06-07 16:29:25 +0200111 flags_rust::GetServerConfigurableFlag("aconfig_test", "com.android.aconfig.test.disabled_rw", "false") == "true"
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200112}
113
114#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200115pub const fn r#enabled_ro() -> bool {
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200116 true
117}
118
119#[inline(always)]
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200120pub fn r#enabled_rw() -> bool {
Mårten Kongstad066575b2023-06-07 16:29:25 +0200121 flags_rust::GetServerConfigurableFlag("aconfig_test", "com.android.aconfig.test.enabled_rw", "false") == "true"
Mårten Kongstadfbd71e22023-05-31 13:29:35 +0200122}
123
124}
125}
126}
Mårten Kongstadf73b9632023-05-24 15:43:47 +0200127}
128"#;
129 assert_eq!(expected.trim(), String::from_utf8(generated.contents).unwrap().trim());
130 }
131}