• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 use anyhow::Result;
18 use serde::Serialize;
19 use tinytemplate::TinyTemplate;
20 
21 use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
22 
23 use std::collections::HashMap;
24 
25 use crate::codegen;
26 use crate::codegen::CodegenMode;
27 use crate::commands::{should_include_flag, OutputFile};
28 
generate_rust_code<I>( package: &str, flag_ids: HashMap<String, u16>, parsed_flags_iter: I, codegen_mode: CodegenMode, ) -> Result<OutputFile> where I: Iterator<Item = ProtoParsedFlag>,29 pub fn generate_rust_code<I>(
30     package: &str,
31     flag_ids: HashMap<String, u16>,
32     parsed_flags_iter: I,
33     codegen_mode: CodegenMode,
34 ) -> Result<OutputFile>
35 where
36     I: Iterator<Item = ProtoParsedFlag>,
37 {
38     let template_flags: Vec<TemplateParsedFlag> = parsed_flags_iter
39         .map(|pf| TemplateParsedFlag::new(package, flag_ids.clone(), &pf))
40         .collect();
41     let has_readwrite = template_flags.iter().any(|item| item.readwrite);
42     let container = (template_flags.first().expect("zero template flags").container).to_string();
43     let context = TemplateContext {
44         package: package.to_string(),
45         template_flags,
46         modules: package.split('.').map(|s| s.to_string()).collect::<Vec<_>>(),
47         has_readwrite,
48         container,
49     };
50     let mut template = TinyTemplate::new();
51     template.add_template(
52         "rust_code_gen",
53         match codegen_mode {
54             CodegenMode::Test => include_str!("../../templates/rust_test.template"),
55             CodegenMode::Exported | CodegenMode::ForceReadOnly | CodegenMode::Production => {
56                 include_str!("../../templates/rust.template")
57             }
58         },
59     )?;
60     let contents = template.render("rust_code_gen", &context)?;
61     let path = ["src", "lib.rs"].iter().collect();
62     Ok(OutputFile { contents: contents.into(), path })
63 }
64 
65 #[derive(Serialize)]
66 struct TemplateContext {
67     pub package: String,
68     pub template_flags: Vec<TemplateParsedFlag>,
69     pub modules: Vec<String>,
70     pub has_readwrite: bool,
71     pub container: String,
72 }
73 
74 #[derive(Serialize)]
75 struct TemplateParsedFlag {
76     pub readwrite: bool,
77     pub default_value: String,
78     pub name: String,
79     pub container: String,
80     pub flag_offset: u16,
81     pub device_config_namespace: String,
82     pub device_config_flag: String,
83 }
84 
85 impl TemplateParsedFlag {
86     #[allow(clippy::nonminimal_bool)]
new(package: &str, flag_offsets: HashMap<String, u16>, pf: &ProtoParsedFlag) -> Self87     fn new(package: &str, flag_offsets: HashMap<String, u16>, pf: &ProtoParsedFlag) -> Self {
88         let flag_offset = match flag_offsets.get(pf.name()) {
89             Some(offset) => offset,
90             None => {
91                 // System/vendor/product RO+disabled flags have no offset in storage files.
92                 // Assign placeholder value.
93                 if !should_include_flag(pf) {
94                     &0
95                 }
96                 // All other flags _must_ have an offset.
97                 else {
98                     panic!("{}", format!("missing flag offset for {}", pf.name()));
99                 }
100             }
101         };
102 
103         Self {
104             readwrite: pf.permission() == ProtoFlagPermission::READ_WRITE,
105             default_value: match pf.state() {
106                 ProtoFlagState::ENABLED => "true".to_string(),
107                 ProtoFlagState::DISABLED => "false".to_string(),
108             },
109             name: pf.name().to_string(),
110             container: pf.container().to_string(),
111             flag_offset: *flag_offset,
112             device_config_namespace: pf.namespace().to_string(),
113             device_config_flag: codegen::create_device_config_ident(package, pf.name())
114                 .expect("values checked at flag parse time"),
115         }
116     }
117 }
118 
119 #[cfg(test)]
120 mod tests {
121     use super::*;
122 
123     const PROD_EXPECTED: &str = r#"
124 //! codegenerated rust flag lib
125 use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
126 use std::path::Path;
127 use std::io::Write;
128 use std::sync::LazyLock;
129 use log::{log, LevelFilter, Level};
130 
131 /// flag provider
132 pub struct FlagProvider;
133 
134 static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe {
135     get_mapped_storage_file("system", StorageFileType::PackageMap)
136     .and_then(|package_map| get_package_read_context(&package_map, "com.android.aconfig.test"))
137     .map(|context| context.map(|c| c.boolean_start_index))
138 });
139 
140 static FLAG_VAL_MAP: LazyLock<Result<Mmap, AconfigStorageError>> = LazyLock::new(|| unsafe {
141     get_mapped_storage_file("system", StorageFileType::FlagVal)
142 });
143 
144 /// flag value cache for disabled_rw
145 static CACHED_disabled_rw: LazyLock<bool> = LazyLock::new(|| {
146     // This will be called multiple times. Subsequent calls after the first are noops.
147     logger::init(
148         logger::Config::default()
149             .with_tag_on_device("aconfig_rust_codegen")
150             .with_max_level(LevelFilter::Info));
151 
152     let flag_value_result = FLAG_VAL_MAP
153         .as_ref()
154         .map_err(|err| format!("failed to get flag val map: {err}"))
155         .and_then(|flag_val_map| {
156             PACKAGE_OFFSET
157                .as_ref()
158                .map_err(|err| format!("failed to get package read offset: {err}"))
159                .and_then(|package_offset| {
160                    match package_offset {
161                        Some(offset) => {
162                            get_boolean_flag_value(&flag_val_map, offset + 0)
163                                .map_err(|err| format!("failed to get flag: {err}"))
164                        },
165                        None => {
166                            log!(Level::Error, "no context found for package com.android.aconfig.test");
167                            Err(format!("failed to flag package com.android.aconfig.test"))
168                        }
169                     }
170                 })
171             });
172 
173     match flag_value_result {
174         Ok(flag_value) => {
175             return flag_value;
176         },
177         Err(err) => {
178             log!(Level::Error, "aconfig_rust_codegen: error: {err}");
179             return false;
180         }
181     }
182 });
183 
184 /// flag value cache for disabled_rw_exported
185 static CACHED_disabled_rw_exported: LazyLock<bool> = LazyLock::new(|| {
186         // This will be called multiple times. Subsequent calls after the first are noops.
187         logger::init(
188             logger::Config::default()
189                 .with_tag_on_device("aconfig_rust_codegen")
190                 .with_max_level(LevelFilter::Info));
191 
192         let flag_value_result = FLAG_VAL_MAP
193             .as_ref()
194             .map_err(|err| format!("failed to get flag val map: {err}"))
195             .and_then(|flag_val_map| {
196                 PACKAGE_OFFSET
197                     .as_ref()
198                     .map_err(|err| format!("failed to get package read offset: {err}"))
199                     .and_then(|package_offset| {
200                         match package_offset {
201                             Some(offset) => {
202                                 get_boolean_flag_value(&flag_val_map, offset + 1)
203                                     .map_err(|err| format!("failed to get flag: {err}"))
204                             },
205                             None => {
206                                 log!(Level::Error, "no context found for package com.android.aconfig.test");
207                                 Err(format!("failed to flag package com.android.aconfig.test"))
208                             }
209                         }
210                     })
211                 });
212 
213         match flag_value_result {
214             Ok(flag_value) => {
215                  return flag_value;
216             },
217             Err(err) => {
218                 log!(Level::Error, "aconfig_rust_codegen: error: {err}");
219                 return false;
220             }
221         }
222 });
223 
224 /// flag value cache for disabled_rw_in_other_namespace
225 static CACHED_disabled_rw_in_other_namespace: LazyLock<bool> = LazyLock::new(|| {
226         // This will be called multiple times. Subsequent calls after the first are noops.
227         logger::init(
228             logger::Config::default()
229                 .with_tag_on_device("aconfig_rust_codegen")
230                 .with_max_level(LevelFilter::Info));
231 
232         let flag_value_result = FLAG_VAL_MAP
233             .as_ref()
234             .map_err(|err| format!("failed to get flag val map: {err}"))
235             .and_then(|flag_val_map| {
236                 PACKAGE_OFFSET
237                     .as_ref()
238                     .map_err(|err| format!("failed to get package read offset: {err}"))
239                     .and_then(|package_offset| {
240                         match package_offset {
241                             Some(offset) => {
242                                 get_boolean_flag_value(&flag_val_map, offset + 2)
243                                     .map_err(|err| format!("failed to get flag: {err}"))
244                             },
245                             None => {
246                                 log!(Level::Error, "no context found for package com.android.aconfig.test");
247                                 Err(format!("failed to flag package com.android.aconfig.test"))
248                             }
249                         }
250                     })
251                 });
252 
253         match flag_value_result {
254             Ok(flag_value) => {
255                  return flag_value;
256             },
257             Err(err) => {
258                 log!(Level::Error, "aconfig_rust_codegen: error: {err}");
259                 return false;
260             }
261         }
262 });
263 
264 
265 /// flag value cache for enabled_rw
266 static CACHED_enabled_rw: LazyLock<bool> = LazyLock::new(|| {
267         // This will be called multiple times. Subsequent calls after the first are noops.
268         logger::init(
269             logger::Config::default()
270                 .with_tag_on_device("aconfig_rust_codegen")
271                 .with_max_level(LevelFilter::Info));
272 
273         let flag_value_result = FLAG_VAL_MAP
274             .as_ref()
275             .map_err(|err| format!("failed to get flag val map: {err}"))
276             .and_then(|flag_val_map| {
277                 PACKAGE_OFFSET
278                     .as_ref()
279                     .map_err(|err| format!("failed to get package read offset: {err}"))
280                     .and_then(|package_offset| {
281                         match package_offset {
282                             Some(offset) => {
283                                 get_boolean_flag_value(&flag_val_map, offset + 7)
284                                     .map_err(|err| format!("failed to get flag: {err}"))
285                             },
286                             None => {
287                                 log!(Level::Error, "no context found for package com.android.aconfig.test");
288                                 Err(format!("failed to flag package com.android.aconfig.test"))
289                             }
290                         }
291                     })
292                 });
293 
294         match flag_value_result {
295             Ok(flag_value) => {
296                  return flag_value;
297             },
298             Err(err) => {
299                 log!(Level::Error, "aconfig_rust_codegen: error: {err}");
300                 return true;
301             }
302         }
303 });
304 
305 impl FlagProvider {
306 
307 
308     /// query flag disabled_ro
309     pub fn disabled_ro(&self) -> bool {
310         false
311     }
312 
313     /// query flag disabled_rw
314     pub fn disabled_rw(&self) -> bool {
315         *CACHED_disabled_rw
316     }
317 
318     /// query flag disabled_rw_exported
319     pub fn disabled_rw_exported(&self) -> bool {
320         *CACHED_disabled_rw_exported
321     }
322 
323     /// query flag disabled_rw_in_other_namespace
324     pub fn disabled_rw_in_other_namespace(&self) -> bool {
325         *CACHED_disabled_rw_in_other_namespace
326     }
327 
328     /// query flag enabled_fixed_ro
329     pub fn enabled_fixed_ro(&self) -> bool {
330         true
331     }
332 
333     /// query flag enabled_fixed_ro_exported
334     pub fn enabled_fixed_ro_exported(&self) -> bool {
335         true
336     }
337 
338     /// query flag enabled_ro
339     pub fn enabled_ro(&self) -> bool {
340         true
341     }
342 
343     /// query flag enabled_ro_exported
344     pub fn enabled_ro_exported(&self) -> bool {
345         true
346     }
347 
348     /// query flag enabled_rw
349     pub fn enabled_rw(&self) -> bool {
350         *CACHED_enabled_rw
351     }
352 
353 
354 }
355 
356 /// flag provider
357 pub static PROVIDER: FlagProvider = FlagProvider;
358 
359 
360 /// query flag disabled_ro
361 #[inline(always)]
362 pub fn disabled_ro() -> bool {
363    false
364 }
365 
366 /// query flag disabled_rw
367 #[inline(always)]
368 pub fn disabled_rw() -> bool {
369     PROVIDER.disabled_rw()
370 }
371 
372 /// query flag disabled_rw_exported
373 #[inline(always)]
374 pub fn disabled_rw_exported() -> bool {
375     PROVIDER.disabled_rw_exported()
376 }
377 
378 /// query flag disabled_rw_in_other_namespace
379 #[inline(always)]
380 pub fn disabled_rw_in_other_namespace() -> bool {
381     PROVIDER.disabled_rw_in_other_namespace()
382 }
383 
384 /// query flag enabled_fixed_ro
385 #[inline(always)]
386 pub fn enabled_fixed_ro() -> bool {
387     true
388 }
389 
390 /// query flag enabled_fixed_ro_exported
391 #[inline(always)]
392 pub fn enabled_fixed_ro_exported() -> bool {
393     true
394 }
395 
396 /// query flag enabled_ro
397 #[inline(always)]
398 pub fn enabled_ro() -> bool {
399     true
400 }
401 
402 /// query flag enabled_ro_exported
403 #[inline(always)]
404 pub fn enabled_ro_exported() -> bool {
405     true
406 }
407 
408 /// query flag enabled_rw
409 #[inline(always)]
410 pub fn enabled_rw() -> bool {
411     PROVIDER.enabled_rw()
412 }
413 "#;
414 
415     const TEST_EXPECTED: &str = r#"
416 //! codegenerated rust flag lib
417 use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
418 use std::collections::BTreeMap;
419 use std::path::Path;
420 use std::io::Write;
421 use std::sync::{LazyLock, Mutex};
422 use log::{log, LevelFilter, Level};
423 
424 /// flag provider
425 pub struct FlagProvider {
426     overrides: BTreeMap<&'static str, bool>,
427 }
428 
429 static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe {
430     get_mapped_storage_file("system", StorageFileType::PackageMap)
431     .and_then(|package_map| get_package_read_context(&package_map, "com.android.aconfig.test"))
432     .map(|context| context.map(|c| c.boolean_start_index))
433 });
434 
435 static FLAG_VAL_MAP: LazyLock<Result<Mmap, AconfigStorageError>> = LazyLock::new(|| unsafe {
436     get_mapped_storage_file("system", StorageFileType::FlagVal)
437 });
438 
439 /// flag value cache for disabled_rw
440 static CACHED_disabled_rw: LazyLock<bool> = LazyLock::new(|| {
441     // This will be called multiple times. Subsequent calls after the first are noops.
442     logger::init(
443         logger::Config::default()
444             .with_tag_on_device("aconfig_rust_codegen")
445             .with_max_level(LevelFilter::Info));
446 
447     let flag_value_result = FLAG_VAL_MAP
448         .as_ref()
449         .map_err(|err| format!("failed to get flag val map: {err}"))
450         .and_then(|flag_val_map| {
451             PACKAGE_OFFSET
452                .as_ref()
453                .map_err(|err| format!("failed to get package read offset: {err}"))
454                .and_then(|package_offset| {
455                    match package_offset {
456                        Some(offset) => {
457                            get_boolean_flag_value(&flag_val_map, offset + 0)
458                                .map_err(|err| format!("failed to get flag: {err}"))
459                        },
460                        None => {
461                            log!(Level::Error, "no context found for package com.android.aconfig.test");
462                            Err(format!("failed to flag package com.android.aconfig.test"))
463                        }
464                     }
465                 })
466             });
467 
468     match flag_value_result {
469         Ok(flag_value) => {
470             return flag_value;
471         },
472         Err(err) => {
473             log!(Level::Error, "aconfig_rust_codegen: error: {err}");
474             return false;
475         }
476     }
477 });
478 
479 /// flag value cache for disabled_rw_exported
480 static CACHED_disabled_rw_exported: LazyLock<bool> = LazyLock::new(|| {
481         // This will be called multiple times. Subsequent calls after the first are noops.
482         logger::init(
483             logger::Config::default()
484                 .with_tag_on_device("aconfig_rust_codegen")
485                 .with_max_level(LevelFilter::Info));
486 
487         let flag_value_result = FLAG_VAL_MAP
488             .as_ref()
489             .map_err(|err| format!("failed to get flag val map: {err}"))
490             .and_then(|flag_val_map| {
491                 PACKAGE_OFFSET
492                     .as_ref()
493                     .map_err(|err| format!("failed to get package read offset: {err}"))
494                     .and_then(|package_offset| {
495                         match package_offset {
496                             Some(offset) => {
497                                 get_boolean_flag_value(&flag_val_map, offset + 1)
498                                     .map_err(|err| format!("failed to get flag: {err}"))
499                             },
500                             None => {
501                                 log!(Level::Error, "no context found for package com.android.aconfig.test");
502                                 Err(format!("failed to flag package com.android.aconfig.test"))
503                             }
504                         }
505                     })
506                 });
507 
508         match flag_value_result {
509             Ok(flag_value) => {
510                  return flag_value;
511             },
512             Err(err) => {
513                 log!(Level::Error, "aconfig_rust_codegen: error: {err}");
514                 return false;
515             }
516         }
517 });
518 
519 /// flag value cache for disabled_rw_in_other_namespace
520 static CACHED_disabled_rw_in_other_namespace: LazyLock<bool> = LazyLock::new(|| {
521         // This will be called multiple times. Subsequent calls after the first are noops.
522         logger::init(
523             logger::Config::default()
524                 .with_tag_on_device("aconfig_rust_codegen")
525                 .with_max_level(LevelFilter::Info));
526 
527         let flag_value_result = FLAG_VAL_MAP
528             .as_ref()
529             .map_err(|err| format!("failed to get flag val map: {err}"))
530             .and_then(|flag_val_map| {
531                 PACKAGE_OFFSET
532                     .as_ref()
533                     .map_err(|err| format!("failed to get package read offset: {err}"))
534                     .and_then(|package_offset| {
535                         match package_offset {
536                             Some(offset) => {
537                                 get_boolean_flag_value(&flag_val_map, offset + 2)
538                                     .map_err(|err| format!("failed to get flag: {err}"))
539                             },
540                             None => {
541                                 log!(Level::Error, "no context found for package com.android.aconfig.test");
542                                 Err(format!("failed to flag package com.android.aconfig.test"))
543                             }
544                         }
545                     })
546                 });
547 
548         match flag_value_result {
549             Ok(flag_value) => {
550                  return flag_value;
551             },
552             Err(err) => {
553                 log!(Level::Error, "aconfig_rust_codegen: error: {err}");
554                 return false;
555             }
556         }
557 });
558 
559 
560 /// flag value cache for enabled_rw
561 static CACHED_enabled_rw: LazyLock<bool> = LazyLock::new(|| {
562         // This will be called multiple times. Subsequent calls after the first are noops.
563         logger::init(
564             logger::Config::default()
565                 .with_tag_on_device("aconfig_rust_codegen")
566                 .with_max_level(LevelFilter::Info));
567 
568         let flag_value_result = FLAG_VAL_MAP
569             .as_ref()
570             .map_err(|err| format!("failed to get flag val map: {err}"))
571             .and_then(|flag_val_map| {
572                 PACKAGE_OFFSET
573                     .as_ref()
574                     .map_err(|err| format!("failed to get package read offset: {err}"))
575                     .and_then(|package_offset| {
576                         match package_offset {
577                             Some(offset) => {
578                                 get_boolean_flag_value(&flag_val_map, offset + 7)
579                                     .map_err(|err| format!("failed to get flag: {err}"))
580                             },
581                             None => {
582                                 log!(Level::Error, "no context found for package com.android.aconfig.test");
583                                 Err(format!("failed to flag package com.android.aconfig.test"))
584                             }
585                         }
586                     })
587                 });
588 
589         match flag_value_result {
590             Ok(flag_value) => {
591                  return flag_value;
592             },
593             Err(err) => {
594                 log!(Level::Error, "aconfig_rust_codegen: error: {err}");
595                 return true;
596             }
597         }
598 });
599 
600 impl FlagProvider {
601     /// query flag disabled_ro
602     pub fn disabled_ro(&self) -> bool {
603         self.overrides.get("disabled_ro").copied().unwrap_or(
604             false
605         )
606     }
607 
608     /// set flag disabled_ro
609     pub fn set_disabled_ro(&mut self, val: bool) {
610         self.overrides.insert("disabled_ro", val);
611     }
612 
613     /// query flag disabled_rw
614     pub fn disabled_rw(&self) -> bool {
615         self.overrides.get("disabled_rw").copied().unwrap_or(
616             *CACHED_disabled_rw
617         )
618     }
619 
620     /// set flag disabled_rw
621     pub fn set_disabled_rw(&mut self, val: bool) {
622         self.overrides.insert("disabled_rw", val);
623     }
624 
625     /// query flag disabled_rw_exported
626     pub fn disabled_rw_exported(&self) -> bool {
627         self.overrides.get("disabled_rw_exported").copied().unwrap_or(
628             *CACHED_disabled_rw_exported
629         )
630     }
631 
632     /// set flag disabled_rw_exported
633     pub fn set_disabled_rw_exported(&mut self, val: bool) {
634         self.overrides.insert("disabled_rw_exported", val);
635     }
636 
637     /// query flag disabled_rw_in_other_namespace
638     pub fn disabled_rw_in_other_namespace(&self) -> bool {
639         self.overrides.get("disabled_rw_in_other_namespace").copied().unwrap_or(
640             *CACHED_disabled_rw_in_other_namespace
641         )
642     }
643 
644     /// set flag disabled_rw_in_other_namespace
645     pub fn set_disabled_rw_in_other_namespace(&mut self, val: bool) {
646         self.overrides.insert("disabled_rw_in_other_namespace", val);
647     }
648 
649     /// query flag enabled_fixed_ro
650     pub fn enabled_fixed_ro(&self) -> bool {
651         self.overrides.get("enabled_fixed_ro").copied().unwrap_or(
652             true
653         )
654     }
655 
656     /// set flag enabled_fixed_ro
657     pub fn set_enabled_fixed_ro(&mut self, val: bool) {
658         self.overrides.insert("enabled_fixed_ro", val);
659     }
660 
661     /// query flag enabled_fixed_ro_exported
662     pub fn enabled_fixed_ro_exported(&self) -> bool {
663         self.overrides.get("enabled_fixed_ro_exported").copied().unwrap_or(
664             true
665         )
666     }
667 
668     /// set flag enabled_fixed_ro_exported
669     pub fn set_enabled_fixed_ro_exported(&mut self, val: bool) {
670         self.overrides.insert("enabled_fixed_ro_exported", val);
671     }
672 
673     /// query flag enabled_ro
674     pub fn enabled_ro(&self) -> bool {
675         self.overrides.get("enabled_ro").copied().unwrap_or(
676             true
677         )
678     }
679 
680     /// set flag enabled_ro
681     pub fn set_enabled_ro(&mut self, val: bool) {
682         self.overrides.insert("enabled_ro", val);
683     }
684 
685     /// query flag enabled_ro_exported
686     pub fn enabled_ro_exported(&self) -> bool {
687         self.overrides.get("enabled_ro_exported").copied().unwrap_or(
688             true
689         )
690     }
691 
692     /// set flag enabled_ro_exported
693     pub fn set_enabled_ro_exported(&mut self, val: bool) {
694         self.overrides.insert("enabled_ro_exported", val);
695     }
696 
697     /// query flag enabled_rw
698     pub fn enabled_rw(&self) -> bool {
699         self.overrides.get("enabled_rw").copied().unwrap_or(
700             *CACHED_enabled_rw
701         )
702     }
703 
704     /// set flag enabled_rw
705     pub fn set_enabled_rw(&mut self, val: bool) {
706         self.overrides.insert("enabled_rw", val);
707     }
708 
709     /// clear all flag overrides
710     pub fn reset_flags(&mut self) {
711         self.overrides.clear();
712     }
713 }
714 
715 /// flag provider
716 pub static PROVIDER: Mutex<FlagProvider> = Mutex::new(
717     FlagProvider {overrides: BTreeMap::new()}
718 );
719 
720 /// query flag disabled_ro
721 #[inline(always)]
722 pub fn disabled_ro() -> bool {
723     PROVIDER.lock().unwrap().disabled_ro()
724 }
725 
726 /// set flag disabled_ro
727 #[inline(always)]
728 pub fn set_disabled_ro(val: bool) {
729     PROVIDER.lock().unwrap().set_disabled_ro(val);
730 }
731 
732 /// query flag disabled_rw
733 #[inline(always)]
734 pub fn disabled_rw() -> bool {
735     PROVIDER.lock().unwrap().disabled_rw()
736 }
737 
738 /// set flag disabled_rw
739 #[inline(always)]
740 pub fn set_disabled_rw(val: bool) {
741     PROVIDER.lock().unwrap().set_disabled_rw(val);
742 }
743 
744 /// query flag disabled_rw_exported
745 #[inline(always)]
746 pub fn disabled_rw_exported() -> bool {
747     PROVIDER.lock().unwrap().disabled_rw_exported()
748 }
749 
750 /// set flag disabled_rw_exported
751 #[inline(always)]
752 pub fn set_disabled_rw_exported(val: bool) {
753     PROVIDER.lock().unwrap().set_disabled_rw_exported(val);
754 }
755 
756 /// query flag disabled_rw_in_other_namespace
757 #[inline(always)]
758 pub fn disabled_rw_in_other_namespace() -> bool {
759     PROVIDER.lock().unwrap().disabled_rw_in_other_namespace()
760 }
761 
762 /// set flag disabled_rw_in_other_namespace
763 #[inline(always)]
764 pub fn set_disabled_rw_in_other_namespace(val: bool) {
765     PROVIDER.lock().unwrap().set_disabled_rw_in_other_namespace(val);
766 }
767 
768 /// query flag enabled_fixed_ro
769 #[inline(always)]
770 pub fn enabled_fixed_ro() -> bool {
771     PROVIDER.lock().unwrap().enabled_fixed_ro()
772 }
773 
774 /// set flag enabled_fixed_ro
775 #[inline(always)]
776 pub fn set_enabled_fixed_ro(val: bool) {
777     PROVIDER.lock().unwrap().set_enabled_fixed_ro(val);
778 }
779 
780 /// query flag enabled_fixed_ro_exported
781 #[inline(always)]
782 pub fn enabled_fixed_ro_exported() -> bool {
783     PROVIDER.lock().unwrap().enabled_fixed_ro_exported()
784 }
785 
786 /// set flag enabled_fixed_ro_exported
787 #[inline(always)]
788 pub fn set_enabled_fixed_ro_exported(val: bool) {
789     PROVIDER.lock().unwrap().set_enabled_fixed_ro_exported(val);
790 }
791 
792 /// query flag enabled_ro
793 #[inline(always)]
794 pub fn enabled_ro() -> bool {
795     PROVIDER.lock().unwrap().enabled_ro()
796 }
797 
798 /// set flag enabled_ro
799 #[inline(always)]
800 pub fn set_enabled_ro(val: bool) {
801     PROVIDER.lock().unwrap().set_enabled_ro(val);
802 }
803 
804 /// query flag enabled_ro_exported
805 #[inline(always)]
806 pub fn enabled_ro_exported() -> bool {
807     PROVIDER.lock().unwrap().enabled_ro_exported()
808 }
809 
810 /// set flag enabled_ro_exported
811 #[inline(always)]
812 pub fn set_enabled_ro_exported(val: bool) {
813     PROVIDER.lock().unwrap().set_enabled_ro_exported(val);
814 }
815 
816 /// query flag enabled_rw
817 #[inline(always)]
818 pub fn enabled_rw() -> bool {
819     PROVIDER.lock().unwrap().enabled_rw()
820 }
821 
822 /// set flag enabled_rw
823 #[inline(always)]
824 pub fn set_enabled_rw(val: bool) {
825     PROVIDER.lock().unwrap().set_enabled_rw(val);
826 }
827 
828 /// clear all flag override
829 pub fn reset_flags() {
830     PROVIDER.lock().unwrap().reset_flags()
831 }
832 "#;
833 
834     const FORCE_READ_ONLY_EXPECTED: &str = r#"
835 //! codegenerated rust flag lib
836 use aconfig_storage_read_api::{Mmap, AconfigStorageError, StorageFileType, PackageReadContext, get_mapped_storage_file, get_boolean_flag_value, get_package_read_context};
837 use std::path::Path;
838 use std::io::Write;
839 use std::sync::LazyLock;
840 use log::{log, LevelFilter, Level};
841 
842 /// flag provider
843 pub struct FlagProvider;
844 
845 impl FlagProvider {
846     /// query flag disabled_ro
847     pub fn disabled_ro(&self) -> bool {
848         false
849     }
850 
851     /// query flag disabled_rw
852     pub fn disabled_rw(&self) -> bool {
853         false
854     }
855 
856     /// query flag disabled_rw_in_other_namespace
857     pub fn disabled_rw_in_other_namespace(&self) -> bool {
858         false
859     }
860 
861     /// query flag enabled_fixed_ro
862     pub fn enabled_fixed_ro(&self) -> bool {
863         true
864     }
865 
866     /// query flag enabled_ro
867     pub fn enabled_ro(&self) -> bool {
868         true
869     }
870 
871     /// query flag enabled_rw
872     pub fn enabled_rw(&self) -> bool {
873         true
874     }
875 }
876 
877 /// flag provider
878 pub static PROVIDER: FlagProvider = FlagProvider;
879 
880 /// query flag disabled_ro
881 #[inline(always)]
882 pub fn disabled_ro() -> bool {
883     false
884 }
885 
886 /// query flag disabled_rw
887 #[inline(always)]
888 pub fn disabled_rw() -> bool {
889     false
890 }
891 
892 /// query flag disabled_rw_in_other_namespace
893 #[inline(always)]
894 pub fn disabled_rw_in_other_namespace() -> bool {
895     false
896 }
897 
898 /// query flag enabled_fixed_ro
899 #[inline(always)]
900 pub fn enabled_fixed_ro() -> bool {
901     true
902 }
903 
904 /// query flag enabled_ro
905 #[inline(always)]
906 pub fn enabled_ro() -> bool {
907     true
908 }
909 
910 /// query flag enabled_rw
911 #[inline(always)]
912 pub fn enabled_rw() -> bool {
913     true
914 }
915 "#;
916     use crate::commands::assign_flag_ids;
917 
test_generate_rust_code(mode: CodegenMode, expected: &str)918     fn test_generate_rust_code(mode: CodegenMode, expected: &str) {
919         let parsed_flags = crate::test::parse_test_flags();
920         let modified_parsed_flags =
921             crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
922         let flag_ids =
923             assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap();
924         let generated = generate_rust_code(
925             crate::test::TEST_PACKAGE,
926             flag_ids,
927             modified_parsed_flags.into_iter(),
928             mode,
929         )
930         .unwrap();
931         assert_eq!("src/lib.rs", format!("{}", generated.path.display()));
932         assert_eq!(
933             None,
934             crate::test::first_significant_code_diff(
935                 expected,
936                 &String::from_utf8(generated.contents).unwrap()
937             )
938         );
939     }
940 
941     #[test]
test_generate_rust_code_for_prod()942     fn test_generate_rust_code_for_prod() {
943         test_generate_rust_code(CodegenMode::Production, PROD_EXPECTED);
944     }
945 
946     #[test]
test_generate_rust_code_for_test()947     fn test_generate_rust_code_for_test() {
948         test_generate_rust_code(CodegenMode::Test, TEST_EXPECTED);
949     }
950 
951     #[test]
test_generate_rust_code_for_force_read_only()952     fn test_generate_rust_code_for_force_read_only() {
953         test_generate_rust_code(CodegenMode::ForceReadOnly, FORCE_READ_ONLY_EXPECTED);
954     }
955 }
956