#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub struct DecisionVariable {
pub name: String,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub label: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub unit: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub min: Option<f64>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub max: Option<f64>,
}
impl DecisionVariable {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
label: None,
unit: None,
min: None,
max: None,
}
}
pub fn with_label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn with_unit(mut self, unit: impl Into<String>) -> Self {
self.unit = Some(unit.into());
self
}
pub fn with_bounds(mut self, min: f64, max: f64) -> Self {
self.min = Some(min);
self.max = Some(max);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_starts_with_only_name() {
let v = DecisionVariable::new("displacement");
assert_eq!(v.name, "displacement");
assert!(v.label.is_none());
assert!(v.unit.is_none());
assert!(v.min.is_none());
assert!(v.max.is_none());
}
#[test]
fn builder_methods_chain() {
let v = DecisionVariable::new("displacement")
.with_label("Engine size")
.with_unit("L")
.with_bounds(1.0, 6.0);
assert_eq!(v.label.as_deref(), Some("Engine size"));
assert_eq!(v.unit.as_deref(), Some("L"));
assert_eq!(v.min, Some(1.0));
assert_eq!(v.max, Some(6.0));
}
}