1use std::sync::RwLock;
2
3use serde::Deserialize;
4use serde::Serialize;
5
6#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS)]
14#[ts(export)]
15pub enum RuntimeFlag {
16 #[default]
18 Unset,
19 On,
21 Off,
23}
24
25#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS)]
31#[ts(export)]
32pub struct KclRuntimeFlags {
33 #[serde(default)]
34 pub use_cek_executor: RuntimeFlag,
35 #[serde(default)]
36 pub use_new_lexer_parser: RuntimeFlag,
37}
38
39impl KclRuntimeFlags {
40 pub const DEFAULT: Self = Self {
41 use_cek_executor: RuntimeFlag::Unset,
42 use_new_lexer_parser: RuntimeFlag::Unset,
43 };
44}
45
46impl Default for KclRuntimeFlags {
47 fn default() -> Self {
48 Self::DEFAULT
49 }
50}
51
52static KCL_RUNTIME_FLAGS: RwLock<KclRuntimeFlags> = RwLock::new(KclRuntimeFlags::DEFAULT);
53
54pub fn set_kcl_runtime_flags(flags: KclRuntimeFlags) {
55 match KCL_RUNTIME_FLAGS.write() {
56 Ok(mut guard) => *guard = flags,
57 Err(poisoned) => {
58 let mut guard = poisoned.into_inner();
59 *guard = flags;
60 }
61 }
62}
63
64pub fn kcl_runtime_flags() -> KclRuntimeFlags {
65 match KCL_RUNTIME_FLAGS.read() {
66 Ok(guard) => *guard,
67 Err(poisoned) => *poisoned.into_inner(),
68 }
69}
70
71pub(crate) trait RuntimeFlagResolve {
72 fn on() -> Self;
73 fn off() -> Self;
74 fn resolve_default() -> Self;
77 fn parse_env_var(value: &str) -> Self;
78}
79
80pub(crate) fn resolve_from_sources<T: RuntimeFlagResolve>(
81 runtime_flag: RuntimeFlag,
82 test_override: Option<T>,
83 env_value: Option<&str>,
84) -> T {
85 match runtime_flag {
86 RuntimeFlag::On => return T::on(),
87 RuntimeFlag::Off => return T::off(),
88 RuntimeFlag::Unset => {}
89 }
90
91 if let Some(mode) = test_override {
92 return mode;
93 }
94
95 env_value.map(T::parse_env_var).unwrap_or_else(T::resolve_default)
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn deserializing_empty_flags_defaults_to_unset() {
104 let flags: KclRuntimeFlags = serde_json::from_str("{}").unwrap();
105 assert_eq!(flags, KclRuntimeFlags::DEFAULT);
106 }
107
108 #[test]
109 fn deserializing_partial_flags_defaults_missing_fields_to_unset() {
110 let flags: KclRuntimeFlags = serde_json::from_str(r#"{"use_new_lexer_parser":"On"}"#).unwrap();
111 assert_eq!(
112 flags,
113 KclRuntimeFlags {
114 use_cek_executor: RuntimeFlag::Unset,
115 use_new_lexer_parser: RuntimeFlag::On,
116 }
117 );
118 }
119}