2025-03-10 23:43:24 +00:00
|
|
|
use std::num::ParseFloatError;
|
|
|
|
|
|
|
|
// a real number described by a specification string. since the structure is
|
|
|
|
// read-only, we can guarantee that `spec` always specifies `value` in the
|
|
|
|
// following format
|
|
|
|
// ┌──────────────────────────────────────────────────────┬───────────┐
|
|
|
|
// │ `spec` │ `value` │
|
|
|
|
// ┝━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━┥
|
|
|
|
// │ a string that parses to the floating-point value `x` │ `Some(x)` │
|
|
|
|
// ├──────────────────────────────────────────────────────┼───────────┤
|
|
|
|
// │ the empty string │ `None` │
|
|
|
|
// └──────────────────────────────────────────────────────┴───────────┘
|
|
|
|
#[readonly::make]
|
|
|
|
pub struct SpecifiedValue {
|
|
|
|
pub spec: String,
|
2025-08-04 23:34:33 +00:00
|
|
|
pub value: Option<f64>,
|
2025-03-10 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SpecifiedValue {
|
2025-08-07 23:24:07 +00:00
|
|
|
pub fn from_empty_spec() -> Self {
|
|
|
|
Self { spec: String::new(), value: None }
|
2025-03-10 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_present(&self) -> bool {
|
|
|
|
matches!(self.value, Some(_))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// a `SpecifiedValue` can be constructed from a specification string, formatted
|
|
|
|
// as described in the comment on the structure definition. the result is `Ok`
|
|
|
|
// if the specification is properly formatted, and `Error` if not
|
|
|
|
impl TryFrom<String> for SpecifiedValue {
|
|
|
|
type Error = ParseFloatError;
|
|
|
|
|
|
|
|
fn try_from(spec: String) -> Result<Self, Self::Error> {
|
|
|
|
if spec.is_empty() {
|
2025-08-07 23:24:07 +00:00
|
|
|
Ok(Self::from_empty_spec())
|
2025-03-10 23:43:24 +00:00
|
|
|
} else {
|
|
|
|
spec.parse::<f64>().map(
|
2025-08-07 23:24:07 +00:00
|
|
|
|value| Self { spec, value: Some(value) }
|
2025-03-10 23:43:24 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|