use std::borrow::Cow;
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ContextVariable {
Time,
TimeStep,
SpatialGradient {
dimension: usize,
component: Option<usize>,
},
External {
name: Cow<'static, str>,
},
}
impl std::fmt::Display for ContextVariable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Time => write!(f, "Time"),
Self::TimeStep => write!(f, "TimeStep"),
Self::SpatialGradient {
dimension,
component: None,
} => {
write!(f, "SpatialGradient(dim={})", dimension)
}
Self::SpatialGradient {
dimension,
component: Some(c),
} => {
write!(f, "SpatialGradient(dim={},comp={})", dimension, c)
}
Self::External { name } => write!(f, "External({})", name),
#[allow(unreachable_patterns)]
_ => write!(f, "Unknown"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn time_equals_time() {
assert_eq!(ContextVariable::Time, ContextVariable::Time);
}
#[test]
fn time_differs_from_timestep() {
assert_ne!(ContextVariable::Time, ContextVariable::TimeStep);
}
#[test]
fn spatial_gradient_same_dimension_equal() {
let a = ContextVariable::SpatialGradient {
dimension: 0,
component: None,
};
let b = ContextVariable::SpatialGradient {
dimension: 0,
component: None,
};
assert_eq!(a, b);
}
#[test]
fn spatial_gradient_different_dimension_not_equal() {
let a = ContextVariable::SpatialGradient {
dimension: 0,
component: None,
};
let b = ContextVariable::SpatialGradient {
dimension: 1,
component: None,
};
assert_ne!(a, b);
}
#[test]
fn external_same_name_equal() {
let a = ContextVariable::External {
name: "temperature".into(),
};
let b = ContextVariable::External {
name: "temperature".into(),
};
assert_eq!(a, b);
}
#[test]
fn external_different_name_not_equal() {
let a = ContextVariable::External {
name: "temperature".into(),
};
let b = ContextVariable::External {
name: "pressure".into(),
};
assert_ne!(a, b);
}
#[test]
fn clone_preserves_equality() {
let vars = [
ContextVariable::Time,
ContextVariable::TimeStep,
ContextVariable::SpatialGradient {
dimension: 2,
component: None,
},
ContextVariable::External {
name: "feed".into(),
},
];
for v in &vars {
assert_eq!(v.clone(), *v);
}
}
#[test]
fn usable_as_hashmap_key() {
let mut map: HashMap<ContextVariable, f64> = HashMap::new();
map.insert(ContextVariable::Time, 1.5);
map.insert(ContextVariable::TimeStep, 0.01);
map.insert(
ContextVariable::SpatialGradient {
dimension: 0,
component: None,
},
0.3,
);
map.insert(
ContextVariable::External {
name: "T_amb".into(),
},
298.15,
);
assert_eq!(map[&ContextVariable::Time], 1.5);
assert_eq!(map[&ContextVariable::TimeStep], 0.01);
assert_eq!(
map[&ContextVariable::SpatialGradient {
dimension: 0,
component: None
}],
0.3
);
assert_eq!(
map[&ContextVariable::External {
name: "T_amb".into()
}],
298.15
);
}
#[test]
fn gradient_dimensions_are_distinct_keys() {
let mut map: HashMap<ContextVariable, f64> = HashMap::new();
map.insert(
ContextVariable::SpatialGradient {
dimension: 0,
component: None,
},
1.0,
);
map.insert(
ContextVariable::SpatialGradient {
dimension: 1,
component: None,
},
2.0,
);
assert_eq!(
map[&ContextVariable::SpatialGradient {
dimension: 0,
component: None
}],
1.0
);
assert_eq!(
map[&ContextVariable::SpatialGradient {
dimension: 1,
component: None
}],
2.0
);
}
#[test]
fn display_time() {
assert_eq!(format!("{}", ContextVariable::Time), "Time");
}
#[test]
fn display_timestep() {
assert_eq!(format!("{}", ContextVariable::TimeStep), "TimeStep");
}
#[test]
fn display_spatial_gradient() {
let v = ContextVariable::SpatialGradient {
dimension: 1,
component: None,
};
assert_eq!(format!("{}", v), "SpatialGradient(dim=1)");
}
#[test]
fn display_external() {
let v = ContextVariable::External {
name: "T_amb".into(),
};
assert_eq!(format!("{}", v), "External(T_amb)");
}
#[test]
fn debug_is_non_empty() {
let s = format!(
"{:?}",
ContextVariable::SpatialGradient {
dimension: 0,
component: None
}
);
assert!(s.contains("SpatialGradient"));
assert!(s.contains('0'));
}
}