use crate::context::calculator::ContextCalculator;
use crate::context::compute::ComputeContext;
use crate::context::error::OxiflowError;
use crate::context::value::ContextValue;
use crate::context::variable::ContextVariable;
use crate::model::traits::RequiresContext;
#[derive(Debug, Clone)]
pub struct TimeCalculator;
impl RequiresContext for TimeCalculator {
fn required_variables(&self) -> Vec<ContextVariable> {
vec![]
}
fn priority(&self) -> u32 {
0
}
}
impl ContextCalculator for TimeCalculator {
fn provides(&self) -> ContextVariable {
ContextVariable::Time
}
fn compute(
&self,
_state: &ContextValue,
ctx: &ComputeContext,
) -> Result<ContextValue, OxiflowError> {
Ok(ContextValue::Scalar(ctx.time()))
}
fn name(&self) -> &str {
"time (built-in)"
}
}
#[derive(Debug, Clone)]
pub struct TimeStepCalculator;
impl RequiresContext for TimeStepCalculator {
fn required_variables(&self) -> Vec<ContextVariable> {
vec![]
}
fn priority(&self) -> u32 {
0
}
}
impl ContextCalculator for TimeStepCalculator {
fn provides(&self) -> ContextVariable {
ContextVariable::TimeStep
}
fn compute(
&self,
_state: &ContextValue,
ctx: &ComputeContext,
) -> Result<ContextValue, OxiflowError> {
Ok(ContextValue::Scalar(ctx.time_step()))
}
fn name(&self) -> &str {
"time_step (built-in)"
}
}
#[cfg(test)]
mod tests {
use super::*;
fn ctx(t: f64, dt: f64) -> ComputeContext {
ComputeContext::new(t, dt)
}
#[test]
fn time_calculator_provides_time() {
assert_eq!(TimeCalculator.provides(), ContextVariable::Time);
}
#[test]
fn time_calculator_returns_current_time() {
let result = TimeCalculator
.compute(&ContextValue::Scalar(0.0), &ctx(2.5, 0.01))
.unwrap();
assert_eq!(result.as_scalar().unwrap(), 2.5);
}
#[test]
fn time_calculator_priority_is_zero() {
assert_eq!(TimeCalculator.priority(), 0);
}
#[test]
fn time_calculator_has_no_required_variables() {
assert!(TimeCalculator.required_variables().is_empty());
}
#[test]
fn time_calculator_name() {
assert_eq!(TimeCalculator.name(), "time (built-in)");
}
#[test]
fn timestep_calculator_provides_timestep() {
assert_eq!(TimeStepCalculator.provides(), ContextVariable::TimeStep);
}
#[test]
fn timestep_calculator_returns_current_dt() {
let result = TimeStepCalculator
.compute(&ContextValue::Scalar(0.0), &ctx(0.0, 0.05))
.unwrap();
assert_eq!(result.as_scalar().unwrap(), 0.05);
}
#[test]
fn timestep_calculator_priority_is_zero() {
assert_eq!(TimeStepCalculator.priority(), 0);
}
#[test]
fn timestep_calculator_has_no_required_variables() {
assert!(TimeStepCalculator.required_variables().is_empty());
}
#[test]
fn timestep_calculator_name() {
assert_eq!(TimeStepCalculator.name(), "time_step (built-in)");
}
#[test]
fn both_are_object_safe() {
let calcs: Vec<Box<dyn ContextCalculator>> =
vec![Box::new(TimeCalculator), Box::new(TimeStepCalculator)];
assert_eq!(calcs[0].provides(), ContextVariable::Time);
assert_eq!(calcs[1].provides(), ContextVariable::TimeStep);
}
}