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