use crate::frx_load::{self, LoadedRules};
use crate::{BUILTIN_NAMES, BUILTIN_PRECOMPILED};
use anyhow::{anyhow, Result};
use std::cell::Cell;
use std::path::{Path, PathBuf};
struct LoadRequest {
path: PathBuf,
builtin: bool,
explicit: bool,
}
std::thread_local! {
static PENDING: Cell<Option<LoadRequest>> = const { Cell::new(None) };
}
fn execute_pending() -> Result<LoadedRules> {
let Some(request): Option<LoadRequest> = PENDING.take() else {
return Err(anyhow!("Forbidden-strings rule loading had no pending request."));
};
return frx_load::load(
request.path.as_path(), request.builtin, request.explicit, BUILTIN_PRECOMPILED, BUILTIN_NAMES,
);
}
fn protected_request(request: LoadRequest, operation: fn() -> Result<LoadedRules>) -> Result<LoadedRules> {
if let Some(previous) = PENDING.replace(Some(request)) {
PENDING.set(Some(previous));
return Err(anyhow!("Forbidden-strings rule loading already has a pending request on this thread."));
}
let outcome = std::panic::catch_unwind(operation);
let _unused: Option<LoadRequest> = PENDING.take();
match outcome {
Ok(result) => return result,
Err(_payload) => return Err(anyhow!("Forbidden-strings rule loading panicked; no rule set was accepted.")),
}
}
pub(crate) fn load(path: &Path, builtin: bool, explicit: bool) -> Result<LoadedRules> {
let request: LoadRequest = LoadRequest { path: path.to_path_buf(), builtin, explicit };
return protected_request(request, execute_pending);
}
#[cfg(test)]
#[path = "load_request_tests.rs"]
mod tests;
#[cfg(test)]
#[path = "load_request_nested_tests.rs"]
mod nested_tests;