use crate::frx_load::{self, LoadedRules};
use crate::{BUILTIN_NAMES, BUILTIN_PRECOMPILED};
use anyhow::{anyhow, Result};
use std::cell::Cell;
use crate::rules_list::RulesEntry;
use std::path::Path;
struct LoadRequest {
entries: Vec<RulesEntry>,
builtin: bool,
implicit: 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_listed(
request.entries.as_slice(), request.builtin, request.implicit, 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 entry: RulesEntry = frx_load::single_entry(path, builtin, explicit);
let request: LoadRequest = LoadRequest { entries: vec![entry], builtin, implicit: !explicit };
return protected_request(request, execute_pending);
}
pub(crate) fn load_entries(entries: &[RulesEntry], builtin: bool) -> Result<LoadedRules> {
let request: LoadRequest = LoadRequest { entries: entries.to_vec(), builtin, implicit: false };
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;