1 use log::{error, info};
2 use paste::paste;
3 use std::sync::Mutex;
4
5 macro_rules! init_flags {
6 (flags: { $($flag:ident),* }, dependencies: { $($parent:ident => $child:ident),* }) => {
7 #[derive(Default)]
8 struct InitFlags {
9 $($flag: bool,)*
10 }
11
12 /// Sets all flags to true, for testing
13 pub fn set_all_for_testing() {
14 *FLAGS.lock().unwrap() = InitFlags { $($flag: true,)* };
15 }
16
17 impl InitFlags {
18 fn parse(flags: Vec<String>) -> Self {
19 $(let mut $flag = false;)*
20
21 for flag in flags {
22 let values: Vec<&str> = flag.split("=").collect();
23 if values.len() != 2 {
24 error!("Bad flag {}, must be in <FLAG>=<VALUE> format", flag);
25 continue;
26 }
27
28 match values[0] {
29 $(concat!("INIT_", stringify!($flag)) => $flag = values[1].parse().unwrap_or(false),)*
30 _ => {}
31 }
32 }
33
34 Self { $($flag,)* }.reconcile()
35 }
36
37 fn reconcile(mut self) -> Self {
38 // Loop to ensure dependencies can be specified in any order
39 loop {
40 let mut any_change = false;
41 $(if self.$parent && !self.$child {
42 self.$child = true;
43 any_change = true;
44 })*
45
46 if !any_change {
47 break;
48 }
49 }
50
51 // TODO: acl should not be off if l2cap is on, but need to reconcile legacy code
52 if self.gd_l2cap {
53 self.gd_acl = false;
54 self.gd_hci = true;
55 }
56
57 self
58 }
59
60 fn log(&self) {
61 info!(concat!("Flags loaded: ", $(stringify!($flag), "={} ",)*), $(self.$flag,)*);
62 }
63 }
64
65 paste! {
66 $(
67 #[allow(missing_docs)]
68 pub fn [<$flag _is_enabled>]() -> bool {
69 FLAGS.lock().unwrap().$flag
70 }
71 )*
72 }
73 };
74 }
75
76 init_flags!(
77 flags: {
78 gd_core,
79 gd_advertising,
80 gd_scanning,
81 gd_security,
82 gd_acl,
83 gd_l2cap,
84 gd_hci,
85 gd_controller,
86 gatt_robust_caching,
87 btaa_hci,
88 gd_rust,
89 gd_link_policy
90 },
91 dependencies: {
92 gd_core => gd_security,
93 gd_security => gd_acl,
94 gd_l2cap => gd_scanning,
95 gd_scanning => gd_advertising,
96 gd_advertising => gd_acl,
97 gd_acl => gd_controller,
98 gd_controller => gd_hci,
99 gd_link_policy => gd_acl
100 }
101 );
102
103 lazy_static! {
104 static ref FLAGS: Mutex<InitFlags> = Mutex::new(InitFlags::default());
105 }
106
107 /// Loads the flag values from the passed-in vector of string values
load(flags: Vec<String>)108 pub fn load(flags: Vec<String>) {
109 crate::init_logging();
110
111 let flags = InitFlags::parse(flags);
112 flags.log();
113 *FLAGS.lock().unwrap() = flags;
114 }
115