use std::borrow::Cow;
use crate::{renderer::RenderContext, value::Value, variable_container::VariableContainer};
use super::StorageMethod;
#[derive(Debug)]
pub struct CalculatedValue {
value: StorageMethod,
modifiers: Vec<(*const str, Vec<StorageMethod>)>,
}
impl CalculatedValue {
pub fn new(value: StorageMethod, modifiers: Vec<(*const str, Vec<StorageMethod>)>) -> Self {
Self { value, modifiers }
}
pub fn calc<VC: VariableContainer>(
&self,
context: &RenderContext<VC>,
) -> crate::error::Result<Value> {
let mut var = match &self.value {
StorageMethod::Const(var) => Cow::Borrowed(var),
StorageMethod::Variable(var_name) => {
let var_name = unsafe { var_name.as_ref().unwrap() };
let var = context.variables.get(var_name);
Cow::Borrowed(var.ok_or(crate::error::Error::UnknownVariable(var_name))?)
}
};
for (modifier_name, args) in &self.modifiers {
let modifier_name = unsafe { modifier_name.as_ref().unwrap() };
let modifier = context
.modifier
.get(modifier_name)
.ok_or(crate::error::Error::UnknownModifier(modifier_name))?;
let args = storage_methods_to_values(args, &context.variables)?;
var = match modifier(&var, args) {
Ok(v) => Cow::Owned(v),
Err(e) => {
let error = e.to_string();
error!("{}", error);
return Err(crate::error::Error::Modifier(e));
}
};
}
Ok(var.into_owned())
}
}
fn storage_methods_to_values<'a, 't>(
args: &'a [StorageMethod],
variables: &'a dyn VariableContainer,
) -> crate::error::Result<'t, Vec<&'a Value>> {
let mut real_args = Vec::with_capacity(args.len());
for arg in args {
let arg = match arg {
StorageMethod::Const(value) => value,
StorageMethod::Variable(var) =>
unsafe {
let var = var.as_ref().unwrap();
variables
.get(var)
.ok_or(crate::error::Error::UnknownVariable(var))?
},
};
real_args.push(arg);
}
Ok(real_args)
}
impl PartialEq for CalculatedValue {
fn eq(&self, other: &Self) -> bool {
if self.value != other.value {
return false;
}
self.modifiers.iter().zip(&other.modifiers).all(|(s, o)|
unsafe {
s.0.as_ref() == o.0.as_ref() && s.1 == o.1
})
}
}