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, pub value: Option } impl SpecifiedValue { pub fn from_empty_spec() -> SpecifiedValue { SpecifiedValue { spec: String::new(), value: None } } 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 for SpecifiedValue { type Error = ParseFloatError; fn try_from(spec: String) -> Result { if spec.is_empty() { Ok(SpecifiedValue::from_empty_spec()) } else { spec.parse::().map( |value| SpecifiedValue { spec: spec, value: Some(value) } ) } } }