use std::sync::Arc;
use crate::context::IExpressionContext;
use crate::exceptions::TemplateProcessingException;
use crate::util::{Utf16String, ValidateError};
use super::{
Each, ExpressionCache, StandardExpressionPreprocessor, StandardExpressionResult,
expression_parsing_util::ExpressionParsingUtil,
};
pub struct EachUtils;
impl EachUtils {
pub fn parse_each(
context: &dyn IExpressionContext,
input: Option<&Utf16String>,
) -> StandardExpressionResult<Arc<Each>> {
let input = input.ok_or_else(|| {
Box::new(ValidateError::IllegalArgument {
message: Some("Input cannot be null".to_owned()),
}) as super::StandardExpressionError
})?;
let preprocessed = StandardExpressionPreprocessor::preprocess(context, input)?;
let configuration = context.get_configuration();
if let Some(cached) = ExpressionCache::get_each_from_cache(configuration, &preprocessed) {
return Ok(cached);
}
let parsed = ExpressionParsingUtil::parse_each(&trim(&preprocessed)).ok_or_else(|| {
Box::new(TemplateProcessingException::new(Some(format!(
"Could not parse as each: \"{}\"",
input.to_string_lossy()
)))) as super::StandardExpressionError
})?;
let parsed = Arc::new(parsed);
ExpressionCache::put_each_into_cache(configuration, &preprocessed, Arc::clone(&parsed));
Ok(parsed)
}
}
fn trim(input: &Utf16String) -> Utf16String {
let units = input.as_utf16();
let start = units
.iter()
.position(|unit| *unit > 0x20)
.unwrap_or(units.len());
let end = units
.iter()
.rposition(|unit| *unit > 0x20)
.map_or(start, |position| position + 1);
Utf16String::from_utf16(units[start..end].to_vec())
}