Merge "aconfig: add exported mode in rust codegen" into main
diff --git a/tools/aconfig/Android.bp b/tools/aconfig/Android.bp
index 05fbad1..0e3c37c 100644
--- a/tools/aconfig/Android.bp
+++ b/tools/aconfig/Android.bp
@@ -259,3 +259,21 @@
     ],
     test_suites: ["general-tests"],
 }
+
+rust_aconfig_library {
+    name: "libaconfig_test_rust_library_with_exported_mode",
+    crate_name: "aconfig_test_rust_library",
+    aconfig_declarations: "aconfig.test.flags",
+    mode: "exported",
+}
+
+rust_test {
+    name: "aconfig.exported_mode.test.rust",
+    srcs: [
+        "tests/aconfig_exported_mode_test.rs"
+    ],
+    rustlibs: [
+        "libaconfig_test_rust_library_with_exported_mode",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/tools/aconfig/src/codegen/rust.rs b/tools/aconfig/src/codegen/rust.rs
index 7c49c50..99965d1 100644
--- a/tools/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/src/codegen/rust.rs
@@ -45,9 +45,7 @@
         match codegen_mode {
             CodegenMode::Production => include_str!("../../templates/rust_prod.template"),
             CodegenMode::Test => include_str!("../../templates/rust_test.template"),
-            CodegenMode::Exported => {
-                todo!("exported mode not yet supported for rust, see b/313894653.")
-            }
+            CodegenMode::Exported => include_str!("../../templates/rust_exported.template"),
         },
     )?;
     let contents = template.render("rust_code_gen", &context)?;
@@ -489,14 +487,79 @@
 }
 "#;
 
+    const EXPORTED_EXPECTED: &str = r#"
+//! codegenerated rust flag lib
+
+/// flag provider
+pub struct FlagProvider;
+
+lazy_static::lazy_static! {
+    /// flag value cache for disabled_rw_exported
+    static ref CACHED_disabled_rw_exported: bool = flags_rust::GetServerConfigurableFlag(
+        "aconfig_flags.aconfig_test",
+        "com.android.aconfig.test.disabled_rw_exported",
+        "false") == "true";
+
+    /// flag value cache for enabled_fixed_ro_exported
+    static ref CACHED_enabled_fixed_ro_exported: bool = flags_rust::GetServerConfigurableFlag(
+        "aconfig_flags.aconfig_test",
+        "com.android.aconfig.test.enabled_fixed_ro_exported",
+        "false") == "true";
+
+    /// flag value cache for enabled_ro_exported
+    static ref CACHED_enabled_ro_exported: bool = flags_rust::GetServerConfigurableFlag(
+        "aconfig_flags.aconfig_test",
+        "com.android.aconfig.test.enabled_ro_exported",
+        "false") == "true";
+
+}
+
+impl FlagProvider {
+    /// query flag disabled_rw_exported
+    pub fn disabled_rw_exported(&self) -> bool {
+        *CACHED_disabled_rw_exported
+    }
+
+    /// query flag enabled_fixed_ro_exported
+    pub fn enabled_fixed_ro_exported(&self) -> bool {
+        *CACHED_enabled_fixed_ro_exported
+    }
+
+    /// query flag enabled_ro_exported
+    pub fn enabled_ro_exported(&self) -> bool {
+        *CACHED_enabled_ro_exported
+    }
+}
+
+/// flag provider
+pub static PROVIDER: FlagProvider = FlagProvider;
+
+/// query flag disabled_rw_exported
+#[inline(always)]
+pub fn disabled_rw_exported() -> bool {
+    PROVIDER.disabled_rw_exported()
+}
+
+/// query flag enabled_fixed_ro_exported
+#[inline(always)]
+pub fn enabled_fixed_ro_exported() -> bool {
+    PROVIDER.enabled_fixed_ro_exported()
+}
+
+/// query flag enabled_ro_exported
+#[inline(always)]
+pub fn enabled_ro_exported() -> bool {
+    PROVIDER.enabled_ro_exported()
+}
+"#;
+
     fn test_generate_rust_code(mode: CodegenMode) {
         let parsed_flags = crate::test::parse_test_flags();
-        let generated = generate_rust_code(
-            crate::test::TEST_PACKAGE,
-            parsed_flags.parsed_flag.into_iter(),
-            mode,
-        )
-        .unwrap();
+        let modified_parsed_flags =
+            crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode);
+        let generated =
+            generate_rust_code(crate::test::TEST_PACKAGE, modified_parsed_flags.into_iter(), mode)
+                .unwrap();
         assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
         assert_eq!(
             None,
@@ -504,8 +567,7 @@
                 match mode {
                     CodegenMode::Production => PROD_EXPECTED,
                     CodegenMode::Test => TEST_EXPECTED,
-                    CodegenMode::Exported =>
-                        todo!("exported mode not yet supported for rust, see b/313894653."),
+                    CodegenMode::Exported => EXPORTED_EXPECTED,
                 },
                 &String::from_utf8(generated.contents).unwrap()
             )
@@ -521,4 +583,9 @@
     fn test_generate_rust_code_for_test() {
         test_generate_rust_code(CodegenMode::Test);
     }
+
+    #[test]
+    fn test_generate_rust_code_for_exported() {
+        test_generate_rust_code(CodegenMode::Exported);
+    }
 }
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index 38c9fde..5a94e02 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -217,12 +217,12 @@
 
 pub fn create_rust_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<OutputFile> {
     let parsed_flags = input.try_parse_flags()?;
-    let filtered_parsed_flags = filter_parsed_flags(parsed_flags, codegen_mode);
-    let Some(package) = find_unique_package(&filtered_parsed_flags) else {
+    let modified_parsed_flags = modify_parsed_flags_based_on_mode(parsed_flags, codegen_mode);
+    let Some(package) = find_unique_package(&modified_parsed_flags) else {
         bail!("no parsed flags, or the parsed flags use different packages");
     };
     let package = package.to_string();
-    generate_rust_code(&package, filtered_parsed_flags.into_iter(), codegen_mode)
+    generate_rust_code(&package, modified_parsed_flags.into_iter(), codegen_mode)
 }
 
 pub fn create_storage(caches: Vec<Input>, container: &str) -> Result<Vec<OutputFile>> {
diff --git a/tools/aconfig/templates/rust_exported.template b/tools/aconfig/templates/rust_exported.template
new file mode 100644
index 0000000..b31bcef
--- /dev/null
+++ b/tools/aconfig/templates/rust_exported.template
@@ -0,0 +1,36 @@
+//! codegenerated rust flag lib
+
+/// flag provider
+pub struct FlagProvider;
+
+lazy_static::lazy_static! \{
+    {{ for flag in template_flags }}
+    /// flag value cache for {flag.name}
+    static ref CACHED_{flag.name}: bool = flags_rust::GetServerConfigurableFlag(
+        "aconfig_flags.{flag.device_config_namespace}",
+        "{flag.device_config_flag}",
+        "false") == "true";
+    {{ endfor }}
+}
+
+impl FlagProvider \{
+
+    {{ for flag in template_flags }}
+    /// query flag {flag.name}
+    pub fn {flag.name}(&self) -> bool \{
+        *CACHED_{flag.name}
+    }
+    {{ endfor }}
+
+}
+
+/// flag provider
+pub static PROVIDER: FlagProvider = FlagProvider;
+
+{{ for flag in template_flags }}
+/// query flag {flag.name}
+#[inline(always)]
+pub fn {flag.name}() -> bool \{
+    PROVIDER.{flag.name}()
+}
+{{ endfor }}
diff --git a/tools/aconfig/tests/aconfig_exported_mode_test.rs b/tools/aconfig/tests/aconfig_exported_mode_test.rs
new file mode 100644
index 0000000..4b48047
--- /dev/null
+++ b/tools/aconfig/tests/aconfig_exported_mode_test.rs
@@ -0,0 +1,7 @@
+#[cfg(not(feature = "cargo"))]
+#[test]
+fn test_flags() {
+    assert!(!aconfig_test_rust_library::disabled_rw_exported());
+    assert!(!aconfig_test_rust_library::enabled_fixed_ro_exported());
+    assert!(!aconfig_test_rust_library::enabled_ro_exported());
+}