2025-12-11 22:50:23 +09:00
|
|
|
|
#![cfg(feature = "normalized_dev")]
|
|
|
|
|
|
|
|
|
|
|
|
use once_cell::sync::Lazy;
|
2025-12-12 16:40:20 +09:00
|
|
|
|
use std::cell::Cell;
|
2025-12-12 03:15:45 +09:00
|
|
|
|
use std::sync::{Mutex, MutexGuard};
|
2025-12-11 22:50:23 +09:00
|
|
|
|
|
|
|
|
|
|
/// RAII guard for normalized_dev env toggling (NYASH_JOINIR_NORMALIZED_DEV_RUN).
|
2025-12-12 03:15:45 +09:00
|
|
|
|
/// ネストを許可し、最初の呼び出し時の状態だけを保存・復元する。
|
2025-12-11 22:50:23 +09:00
|
|
|
|
pub struct NormalizedDevEnvGuard {
|
2025-12-12 03:15:45 +09:00
|
|
|
|
active: bool,
|
2025-12-11 22:50:23 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-12 03:15:45 +09:00
|
|
|
|
#[derive(Default)]
|
|
|
|
|
|
struct EnvState {
|
|
|
|
|
|
stack: Vec<Option<String>>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static NORMALIZED_ENV_STATE: Lazy<Mutex<EnvState>> = Lazy::new(|| Mutex::new(EnvState::default()));
|
|
|
|
|
|
static NORMALIZED_TEST_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
|
2025-12-11 22:50:23 +09:00
|
|
|
|
|
2025-12-12 16:40:20 +09:00
|
|
|
|
thread_local! {
|
|
|
|
|
|
// Per-thread depth counter for test_ctx() to allow re-entrant dev env toggling
|
|
|
|
|
|
// without self-deadlocking on NORMALIZED_TEST_LOCK.
|
|
|
|
|
|
static IN_NORMALIZED_TEST_CTX: Cell<u32> = Cell::new(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn enter_test_ctx() {
|
|
|
|
|
|
IN_NORMALIZED_TEST_CTX.with(|c| c.set(c.get().saturating_add(1)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn exit_test_ctx() {
|
|
|
|
|
|
IN_NORMALIZED_TEST_CTX.with(|c| {
|
|
|
|
|
|
let v = c.get();
|
|
|
|
|
|
if v > 0 {
|
|
|
|
|
|
c.set(v - 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn in_test_ctx() -> bool {
|
|
|
|
|
|
IN_NORMALIZED_TEST_CTX.with(|c| c.get() > 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-11 22:50:23 +09:00
|
|
|
|
impl NormalizedDevEnvGuard {
|
|
|
|
|
|
pub fn new(enabled: bool) -> Self {
|
2025-12-12 03:15:45 +09:00
|
|
|
|
let mut state = NORMALIZED_ENV_STATE
|
2025-12-11 22:50:23 +09:00
|
|
|
|
.lock()
|
|
|
|
|
|
.expect("normalized env mutex poisoned");
|
2025-12-12 03:15:45 +09:00
|
|
|
|
|
|
|
|
|
|
// Save current value before overriding.
|
2025-12-11 22:50:23 +09:00
|
|
|
|
let prev = std::env::var("NYASH_JOINIR_NORMALIZED_DEV_RUN").ok();
|
2025-12-12 03:15:45 +09:00
|
|
|
|
state.stack.push(prev);
|
|
|
|
|
|
|
2025-12-11 22:50:23 +09:00
|
|
|
|
if enabled {
|
|
|
|
|
|
std::env::set_var("NYASH_JOINIR_NORMALIZED_DEV_RUN", "1");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
std::env::remove_var("NYASH_JOINIR_NORMALIZED_DEV_RUN");
|
|
|
|
|
|
}
|
2025-12-12 03:15:45 +09:00
|
|
|
|
|
|
|
|
|
|
Self { active: true }
|
2025-12-11 22:50:23 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Drop for NormalizedDevEnvGuard {
|
|
|
|
|
|
fn drop(&mut self) {
|
2025-12-12 03:15:45 +09:00
|
|
|
|
if !self.active {
|
|
|
|
|
|
return;
|
2025-12-11 22:50:23 +09:00
|
|
|
|
}
|
2025-12-12 03:15:45 +09:00
|
|
|
|
let mut state = NORMALIZED_ENV_STATE
|
|
|
|
|
|
.lock()
|
|
|
|
|
|
.expect("normalized env mutex poisoned");
|
|
|
|
|
|
if let Some(prev) = state.stack.pop() {
|
|
|
|
|
|
if let Some(prev) = prev {
|
|
|
|
|
|
std::env::set_var("NYASH_JOINIR_NORMALIZED_DEV_RUN", prev);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
std::env::remove_var("NYASH_JOINIR_NORMALIZED_DEV_RUN");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// normalized_dev feature + env の ON/OFF をまとめた判定。
|
|
|
|
|
|
pub fn normalized_dev_enabled() -> bool {
|
|
|
|
|
|
crate::config::env::normalized_dev_enabled()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// normalized_dev かつ test/debug ログが有効なときだけ true。
|
|
|
|
|
|
pub fn normalized_dev_logs_enabled() -> bool {
|
|
|
|
|
|
crate::config::env::normalized_dev_enabled() && crate::config::env::joinir_test_debug_enabled()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// テスト用コンテキスト:env を ON にしつつロックで並列汚染を防ぐ。
|
|
|
|
|
|
pub struct NormalizedTestContext<'a> {
|
|
|
|
|
|
_lock: MutexGuard<'a, ()>,
|
|
|
|
|
|
_env_guard: NormalizedDevEnvGuard,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> NormalizedTestContext<'a> {
|
|
|
|
|
|
fn new(lock: MutexGuard<'a, ()>) -> Self {
|
2025-12-12 16:40:20 +09:00
|
|
|
|
enter_test_ctx();
|
2025-12-12 03:15:45 +09:00
|
|
|
|
let env_guard = NormalizedDevEnvGuard::new(true);
|
|
|
|
|
|
NormalizedTestContext {
|
|
|
|
|
|
_lock: lock,
|
|
|
|
|
|
_env_guard: env_guard,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-12 16:40:20 +09:00
|
|
|
|
impl Drop for NormalizedTestContext<'_> {
|
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
|
exit_test_ctx();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-12 03:15:45 +09:00
|
|
|
|
/// テストで使う共通ガード。
|
|
|
|
|
|
pub fn test_ctx() -> NormalizedTestContext<'static> {
|
|
|
|
|
|
let lock = NORMALIZED_TEST_LOCK
|
|
|
|
|
|
.lock()
|
|
|
|
|
|
.unwrap_or_else(|e| e.into_inner());
|
|
|
|
|
|
NormalizedTestContext::new(lock)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 簡易ラッパー:クロージャを normalized_dev ON で実行。
|
|
|
|
|
|
pub fn with_dev_env<F, R>(f: F) -> R
|
|
|
|
|
|
where
|
|
|
|
|
|
F: FnOnce() -> R,
|
|
|
|
|
|
{
|
2025-12-12 16:40:20 +09:00
|
|
|
|
if in_test_ctx() {
|
|
|
|
|
|
let _env_guard = NormalizedDevEnvGuard::new(true);
|
|
|
|
|
|
f()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let _ctx = test_ctx();
|
|
|
|
|
|
f()
|
|
|
|
|
|
}
|
2025-12-12 03:15:45 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// env が既に ON のときはそのまま、OFF のときだけ with_dev_env を噛ませる。
|
|
|
|
|
|
pub fn with_dev_env_if_unset<F, R>(f: F) -> R
|
|
|
|
|
|
where
|
|
|
|
|
|
F: FnOnce() -> R,
|
|
|
|
|
|
{
|
|
|
|
|
|
if normalized_dev_enabled() {
|
|
|
|
|
|
f()
|
2025-12-12 16:40:20 +09:00
|
|
|
|
} else if in_test_ctx() {
|
|
|
|
|
|
let _env_guard = NormalizedDevEnvGuard::new(true);
|
|
|
|
|
|
f()
|
2025-12-12 03:15:45 +09:00
|
|
|
|
} else {
|
|
|
|
|
|
with_dev_env(f)
|
2025-12-11 22:50:23 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|