use std::sync::{Arc, Weak};
use crate::context::IExpressionContext;
use crate::util::{Utf16String, ValidateError};
use super::{
ConversionResult, ConversionValue, StandardConversionError, StandardExpressions, TargetClass,
TemplateValue,
};
pub struct Conversions {
context: Weak<dyn IExpressionContext>,
}
impl Conversions {
pub fn new(context: Option<Arc<dyn IExpressionContext>>) -> Result<Self, ValidateError> {
let context = context.ok_or_else(|| ValidateError::IllegalArgument {
message: Some("Context cannot be null".to_owned()),
})?;
Ok(Self {
context: Arc::downgrade(&context),
})
}
pub fn convert_by_class_name<'a>(
&'a self,
target: Option<&'a TemplateValue>,
class_name: Option<&Utf16String>,
) -> Result<ConversionResult<'a>, StandardConversionError> {
let class_name = class_name.ok_or_else(|| {
StandardConversionError::Validation(ValidateError::IllegalArgument {
message: Some("Class name cannot be null".to_owned()),
})
})?;
let class_name = class_name.to_string_lossy();
let target_class = if class_name == "String" || class_name == "java.lang.String" {
TargetClass::String
} else if class_name.contains('.') {
TargetClass::Other(class_name)
} else {
TargetClass::Other(format!("java.lang.{class_name}"))
};
self.convert(target, Some(&target_class))
}
pub fn convert<'a>(
&'a self,
target: Option<&'a TemplateValue>,
target_class: Option<&TargetClass>,
) -> Result<ConversionResult<'a>, StandardConversionError> {
let context = self.context.upgrade().ok_or_else(|| {
StandardConversionError::runtime(
"org.thymeleaf.exceptions.TemplateProcessingException",
"Expression context is no longer available",
)
})?;
let service = StandardExpressions::get_conversion_service(context.get_configuration())
.map_err(|error| {
StandardConversionError::runtime(
"org.thymeleaf.exceptions.TemplateProcessingException",
error.to_string(),
)
})?;
let value = match target {
None | Some(TemplateValue::Null) => ConversionValue::Null,
Some(TemplateValue::String(value) | TemplateValue::SafeHtml(value)) => {
ConversionValue::String(value)
}
Some(value) => ConversionValue::Object(value),
};
service.convert(Some(context.as_any()), value, target_class)
}
}