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 enable_z0006_lint: RuntimeFlag,
35 #[serde(default)]
36 pub use_cek_executor: RuntimeFlag,
37 #[serde(default)]
38 pub use_new_lexer_parser: RuntimeFlag,
39}
40
41impl KclRuntimeFlags {
42 pub const DEFAULT: Self = Self {
43 enable_z0006_lint: RuntimeFlag::Unset,
44 use_cek_executor: RuntimeFlag::Unset,
45 use_new_lexer_parser: RuntimeFlag::Unset,
46 };
47}
48
49impl Default for KclRuntimeFlags {
50 fn default() -> Self {
51 Self::DEFAULT
52 }
53}
54
55static KCL_RUNTIME_FLAGS: RwLock<KclRuntimeFlags> = RwLock::new(KclRuntimeFlags::DEFAULT);
56
57pub fn set_kcl_runtime_flags(flags: KclRuntimeFlags) {
58 match KCL_RUNTIME_FLAGS.write() {
59 Ok(mut guard) => *guard = flags,
60 Err(poisoned) => {
61 let mut guard = poisoned.into_inner();
62 *guard = flags;
63 }
64 }
65}
66
67pub fn kcl_runtime_flags() -> KclRuntimeFlags {
68 match KCL_RUNTIME_FLAGS.read() {
69 Ok(guard) => *guard,
70 Err(poisoned) => *poisoned.into_inner(),
71 }
72}
73
74pub(crate) fn z0006_refactor_metadata_enabled() -> bool {
75 kcl_runtime_flags().enable_z0006_lint == RuntimeFlag::On
76}
77
78pub(crate) trait RuntimeFlagResolve {
79 fn on() -> Self;
80 fn off() -> Self;
81 fn resolve_default() -> Self;
84 fn parse_env_var(value: &str) -> Self;
85}
86
87pub(crate) fn resolve_from_sources<T: RuntimeFlagResolve>(
88 runtime_flag: RuntimeFlag,
89 test_override: Option<T>,
90 env_value: Option<&str>,
91) -> T {
92 match runtime_flag {
93 RuntimeFlag::On => return T::on(),
94 RuntimeFlag::Off => return T::off(),
95 RuntimeFlag::Unset => {}
96 }
97
98 if let Some(mode) = test_override {
99 return mode;
100 }
101
102 env_value.map(T::parse_env_var).unwrap_or_else(T::resolve_default)
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn deserializing_empty_flags_defaults_to_unset() {
111 let flags: KclRuntimeFlags = serde_json::from_str("{}").unwrap();
112 assert_eq!(flags, KclRuntimeFlags::DEFAULT);
113 }
114
115 #[test]
116 fn deserializing_partial_flags_defaults_missing_fields_to_unset() {
117 let flags: KclRuntimeFlags = serde_json::from_str(r#"{"use_new_lexer_parser":"On"}"#).unwrap();
118 assert_eq!(
119 flags,
120 KclRuntimeFlags {
121 enable_z0006_lint: RuntimeFlag::Unset,
122 use_cek_executor: RuntimeFlag::Unset,
123 use_new_lexer_parser: RuntimeFlag::On,
124 }
125 );
126 }
127}