use std::sync::Arc;
use indexmap::IndexSet;
use crate::cache::ICacheEntryValidity;
use crate::util::{PatternSpec, PatternSpecError, Utf16String};
use crate::{ITemplateResource, TemplateMode};
use super::{TemplateResolution, TemplateResolverError};
pub struct AbstractTemplateResolver {
name: Option<Utf16String>,
order: Option<i32>,
check_existence: bool,
use_decoupled_logic: bool,
resolvable_pattern_spec: PatternSpec,
}
impl AbstractTemplateResolver {
pub const DEFAULT_EXISTENCE_CHECK: bool = false;
pub const DEFAULT_USE_DECOUPLED_LOGIC: bool = false;
#[must_use]
pub fn new(class_name: &str) -> Self {
Self {
name: Some(Utf16String::from_rust_str(class_name)),
order: None,
check_existence: Self::DEFAULT_EXISTENCE_CHECK,
use_decoupled_logic: Self::DEFAULT_USE_DECOUPLED_LOGIC,
resolvable_pattern_spec: PatternSpec::new(),
}
}
#[must_use]
pub fn get_name(&self) -> Option<&Utf16String> {
self.name.as_ref()
}
pub fn set_name(&mut self, name: Option<Utf16String>) {
self.name = name;
}
#[must_use]
pub const fn get_order(&self) -> Option<i32> {
self.order
}
pub const fn set_order(&mut self, order: Option<i32>) {
self.order = order;
}
#[must_use]
pub const fn get_resolvable_pattern_spec(&self) -> &PatternSpec {
&self.resolvable_pattern_spec
}
#[must_use]
pub fn get_resolvable_patterns(&self) -> &IndexSet<Option<String>> {
self.resolvable_pattern_spec.get_patterns()
}
pub fn set_resolvable_patterns(
&mut self,
patterns: Option<&[Option<&str>]>,
) -> Result<(), PatternSpecError> {
self.resolvable_pattern_spec.set_patterns(patterns)
}
#[must_use]
pub const fn get_check_existence(&self) -> bool {
self.check_existence
}
pub const fn set_check_existence(&mut self, check_existence: bool) {
self.check_existence = check_existence;
}
#[must_use]
pub const fn get_use_decoupled_logic(&self) -> bool {
self.use_decoupled_logic
}
pub const fn set_use_decoupled_logic(&mut self, use_decoupled_logic: bool) {
self.use_decoupled_logic = use_decoupled_logic;
}
pub fn resolve_template<R, M, V>(
&self,
template: &Utf16String,
compute_template_resource: R,
compute_template_mode: M,
compute_validity: V,
) -> Result<Option<TemplateResolution>, TemplateResolverError>
where
R: FnOnce() -> Result<Option<Arc<dyn ITemplateResource>>, TemplateResolverError>,
M: FnOnce() -> TemplateMode,
V: FnOnce() -> Arc<dyn ICacheEntryValidity>,
{
if !self.compute_resolvable(template) {
return Ok(None);
}
let Some(template_resource) = compute_template_resource()? else {
return Ok(None);
};
if self.check_existence && !template_resource.exists() {
return Ok(None);
}
TemplateResolution::with_options(
Some(template_resource),
self.check_existence,
Some(compute_template_mode()),
self.use_decoupled_logic,
Some(compute_validity()),
)
.map(Some)
.map_err(TemplateResolverError::from)
}
#[must_use]
pub fn compute_resolvable(&self, template: &Utf16String) -> bool {
self.resolvable_pattern_spec.is_empty()
|| self
.resolvable_pattern_spec
.matches(Some(&template.to_string_lossy()))
.expect("validated resolver patterns cannot fail during matching")
}
}