use std::io;
use std::sync::{Arc, RwLock, RwLockReadGuard};
use indexmap::IndexMap;
use crate::expression::TemplateValue;
use crate::model::IModel;
use crate::util::{FastStringWriter, Utf16String, ValidateError};
pub type FragmentParameterMap = IndexMap<Option<Utf16String>, Option<Arc<TemplateValue>>>;
pub struct Fragment {
template_model: Option<Arc<dyn IModel>>,
parameters: Option<Arc<RwLock<FragmentParameterMap>>>,
synthetic_parameters: bool,
}
impl Fragment {
pub const EMPTY_FRAGMENT: Self = Self {
template_model: None,
parameters: None,
synthetic_parameters: false,
};
pub fn new(
template_model: Option<Arc<dyn IModel>>,
parameters: Option<Arc<RwLock<FragmentParameterMap>>>,
synthetic_parameters: bool,
) -> Result<Self, ValidateError> {
let template_model = template_model.ok_or_else(|| ValidateError::IllegalArgument {
message: Some("Template model cannot be null".to_owned()),
})?;
let synthetic_parameters = parameters.as_ref().is_some_and(|values| {
!read_recovering_poison(values).is_empty() && synthetic_parameters
});
Ok(Self {
template_model: Some(template_model),
parameters,
synthetic_parameters,
})
}
pub fn empty_fragment() -> &'static Self {
&Self::EMPTY_FRAGMENT
}
pub fn get_template_model(&self) -> Option<&dyn IModel> {
self.template_model.as_deref()
}
#[must_use]
pub fn get_template_model_arc(&self) -> Option<Arc<dyn IModel>> {
self.template_model.clone()
}
pub fn get_parameters(&self) -> Option<RwLockReadGuard<'_, FragmentParameterMap>> {
self.parameters
.as_ref()
.map(|parameters| read_recovering_poison(parameters))
}
#[must_use]
pub fn get_parameters_arc(&self) -> Option<Arc<RwLock<FragmentParameterMap>>> {
self.parameters.clone()
}
pub fn has_synthetic_parameters(&self) -> bool {
self.synthetic_parameters
}
pub fn write(&self, writer: &mut dyn crate::util::TemplateWriter) -> io::Result<()> {
if let Some(template_model) = &self.template_model {
template_model.write(writer)?;
}
Ok(())
}
pub fn to_utf16_string(&self) -> io::Result<Utf16String> {
let mut writer = FastStringWriter::new();
self.write(&mut writer)?;
Ok(writer.to_string())
}
}
impl super::TemplateObject for Fragment {
fn class_name(&self) -> &str {
"org.thymeleaf.standard.expression.Fragment"
}
fn to_utf16_string(&self) -> Utf16String {
self.to_utf16_string()
.unwrap_or_else(|_| Utf16String::from_rust_str(""))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
fn read_recovering_poison<T>(lock: &RwLock<T>) -> RwLockReadGuard<'_, T> {
lock.read()
.unwrap_or_else(std::sync::PoisonError::into_inner)
}