use ifc_model::Value;
use crate::error::GeometryResult;
use crate::slots::Slots;
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum TrimMeasure {
Parameter(f64),
Length(f64),
}
impl TrimMeasure {
pub fn parameter(self) -> Option<f64> {
match self {
Self::Parameter(value) => Some(value),
Self::Length(_) => None,
}
}
}
pub(super) fn read_trim(
slots: &Slots<'_>,
index: usize,
attribute: &'static str,
) -> GeometryResult<Option<TrimMeasure>> {
let Some(value) = slots.opt(index) else {
return Ok(None);
};
const EXPECTED: &str = "an IfcParameterValue or IFCLENGTHMEASURE(..)";
let kind_error = || slots.kind_error(attribute, EXPECTED, value);
let measure = match value {
Value::Typed {
type_name,
value: inner,
} => {
let number = inner.as_f64().ok_or_else(kind_error)?;
if type_name.eq_ignore_ascii_case("IFCPARAMETERVALUE") {
TrimMeasure::Parameter(number)
} else if type_name.eq_ignore_ascii_case("IFCLENGTHMEASURE") {
TrimMeasure::Length(number)
} else {
return Err(kind_error());
}
}
other => TrimMeasure::Parameter(other.as_f64().ok_or_else(kind_error)?),
};
Ok(Some(measure))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::solid::testkit::entity;
use ifc_model::EntityId;
fn typed(name: &str, value: f64) -> Value {
Value::Typed {
type_name: name.into(),
value: Box::new(Value::Real(value)),
}
}
fn read(value: Value) -> GeometryResult<Option<TrimMeasure>> {
let e = entity("IFCSURFACECURVESWEPTAREASOLID", vec![value]);
read_trim(&Slots::new(EntityId(1), &e), 0, "StartParam")
}
#[test]
fn the_select_member_decides_the_kind() {
assert_eq!(read(Value::Null).unwrap(), None);
assert_eq!(
read(Value::Real(0.5)).unwrap(),
Some(TrimMeasure::Parameter(0.5))
);
assert_eq!(
read(Value::Integer(2)).unwrap(),
Some(TrimMeasure::Parameter(2.0))
);
assert_eq!(
read(typed("IFCPARAMETERVALUE", 0.5)).unwrap(),
Some(TrimMeasure::Parameter(0.5))
);
assert_eq!(
read(typed("IfcLengthMeasure", 5.0)).unwrap(),
Some(TrimMeasure::Length(5.0))
);
}
#[test]
fn a_wrapper_outside_the_select_is_refused() {
for value in [
typed("IFCNONNEGATIVELENGTHMEASURE", 1.0),
typed("IFCREAL", 1.0),
Value::Text("1".into()),
] {
assert!(read(value).is_err());
}
}
}