kataglyphis_rustprojecttemplate/config.rs
1// src/config.rs — Centralised environment-variable configuration.
2//
3// All `KATAGLYPHIS_*` env vars are read here so that the configuration surface
4// is discoverable and documented in a single place.
5//
6// Each accessor caches the parsed value in a `OnceLock` so that the env var is
7// read at most once per process lifetime.
8//
9// The `env_cached!` macro eliminates the repetitive `OnceLock` + `get_or_init`
10// boilerplate that every accessor previously duplicated.
11
12use std::sync::OnceLock;
13
14use log::warn;
15
16// ── Helper macro ───────────────────────────────────────────────────
17
18/// Define an env-var accessor that parses once and caches in a `OnceLock`.
19///
20/// # Variants
21///
22/// ```ignore
23/// // Value type (returned by copy), public by default:
24/// env_cached!(fn_name -> Type, { || init_expr });
25///
26/// // Value type with explicit visibility:
27/// env_cached!(pub(crate) fn_name -> Type, { || init_expr });
28///
29/// // Reference type (returned by &'static ref):
30/// env_cached!(ref fn_name -> Type, { || init_expr });
31/// ```
32macro_rules! env_cached {
33 // Copy variant — returns `T` by value (requires `T: Copy`).
34 ($(#[$attr:meta])* fn $name:ident -> $ty:ty, $init:expr) => {
35 $(#[$attr])*
36 pub fn $name() -> $ty {
37 static CACHE: OnceLock<$ty> = OnceLock::new();
38 *CACHE.get_or_init($init)
39 }
40 };
41 // Copy variant with explicit visibility.
42 ($(#[$attr:meta])* $vis:vis fn $name:ident -> $ty:ty, $init:expr) => {
43 $(#[$attr])*
44 $vis fn $name() -> $ty {
45 static CACHE: OnceLock<$ty> = OnceLock::new();
46 *CACHE.get_or_init($init)
47 }
48 };
49 // Reference variant — returns `&'static T` to avoid cloning.
50 ($(#[$attr:meta])* ref fn $name:ident -> $ty:ty, $init:expr) => {
51 $(#[$attr])*
52 pub fn $name() -> &'static $ty {
53 static CACHE: OnceLock<$ty> = OnceLock::new();
54 CACHE.get_or_init($init)
55 }
56 };
57}
58
59// ── Preprocessing ──────────────────────────────────────────────────
60
61#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
62#[cfg_attr(not(onnx), allow(dead_code))]
63pub(crate) enum PreprocessMode {
64 Letterbox,
65 #[default]
66 Stretch,
67}
68
69env_cached!(
70 /// `KATAGLYPHIS_PREPROCESS`: `"letterbox"` | `"stretch"` (default `"stretch"`).
71 #[cfg_attr(not(onnx), allow(dead_code))]
72 pub(crate) fn preprocess_mode -> PreprocessMode, || {
73 let raw = std::env::var("KATAGLYPHIS_PREPROCESS").unwrap_or_else(|_| "stretch".to_string());
74 match raw.trim().to_ascii_lowercase().as_str() {
75 "letterbox" | "boxed" | "pad" => PreprocessMode::Letterbox,
76 "stretch" | "resize" => PreprocessMode::Stretch,
77 other => {
78 warn!("Unknown preprocess mode '{other}', defaulting to stretch");
79 PreprocessMode::Stretch
80 }
81 }
82 }
83);
84
85env_cached!(
86 /// `KATAGLYPHIS_SWAP_XY`: set to `"1"` to swap X/Y in YOLO output coords.
87 fn swap_xy_enabled -> bool, || {
88 std::env::var("KATAGLYPHIS_SWAP_XY").ok().as_deref() == Some("1")
89 }
90);
91
92// ── ONNX backend selection ─────────────────────────────────────────
93
94env_cached!(
95 /// `KATAGLYPHIS_ONNX_BACKEND`: `"ort"` / `"onnxruntime"` | `"tract"` | unset (auto).
96 ///
97 /// Returns `None` when the variable is unset, signalling automatic backend
98 /// selection. The returned reference is `&'static` so callers can use
99 /// `.as_deref()` without allocation.
100 ref fn onnx_backend -> Option<String>, || {
101 std::env::var("KATAGLYPHIS_ONNX_BACKEND")
102 .ok()
103 .map(|v| v.to_lowercase())
104 }
105);
106
107env_cached!(
108 /// `KATAGLYPHIS_ORT_DEVICE`: `"cpu"` (default) | `"cuda"` | `"auto"`.
109 ///
110 /// Returns a `&'static String` to avoid cloning on every call.
111 ref fn ort_device -> String, || {
112 std::env::var("KATAGLYPHIS_ORT_DEVICE")
113 .unwrap_or_else(|_| "cpu".to_string())
114 .to_ascii_lowercase()
115 }
116);
117
118// ── Inference / GUI ────────────────────────────────────────────────
119
120env_cached!(
121 /// `KATAGLYPHIS_ONNX_MODEL`: override path to the ONNX model file.
122 ///
123 /// Returns a `&'static Option<String>` to avoid cloning on every call.
124 ref fn onnx_model_override -> Option<String>, || {
125 std::env::var("KATAGLYPHIS_ONNX_MODEL").ok()
126 }
127);
128
129env_cached!(
130 /// `KATAGLYPHIS_SCORE_THRESHOLD`: detection confidence threshold (default `0.5`).
131 fn score_threshold -> f32, || {
132 std::env::var("KATAGLYPHIS_SCORE_THRESHOLD")
133 .ok()
134 .and_then(|v| v.parse::<f32>().ok())
135 .unwrap_or(0.5)
136 }
137);
138
139env_cached!(
140 /// `KATAGLYPHIS_INFER_EVERY_MS`: minimum interval between inference requests (default `0`).
141 fn infer_every_ms -> u64, || {
142 std::env::var("KATAGLYPHIS_INFER_EVERY_MS")
143 .ok()
144 .and_then(|v| v.parse::<u64>().ok())
145 .unwrap_or(0)
146 }
147);
148
149// ── Logging ────────────────────────────────────────────────────────
150
151env_cached!(
152 /// `KATAGLYPHIS_LOG_LEVEL`: `error` | `warn` | `info` (default) | `debug` | `trace`.
153 fn log_level -> log::LevelFilter, || {
154 std::env::var("KATAGLYPHIS_LOG_LEVEL")
155 .ok()
156 .and_then(|v| match v.to_ascii_lowercase().as_str() {
157 "error" => Some(log::LevelFilter::Error),
158 "warn" | "warning" => Some(log::LevelFilter::Warn),
159 "info" => Some(log::LevelFilter::Info),
160 "debug" => Some(log::LevelFilter::Debug),
161 "trace" => Some(log::LevelFilter::Trace),
162 _ => None,
163 })
164 .unwrap_or(log::LevelFilter::Info)
165 }
166);