Skip to main content

hpr_motor/
text.rs

1//! Shared pieces of the text formats: parse warnings and number reading.
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::MotorError;
6
7/// Something a lenient reader accepted but flagged, such as a missing entry separator.
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct ParseWarning {
10    /// The 1-based line number the warning is about.
11    pub line: usize,
12    /// Whether data was lost.
13    pub kind: WarningKind,
14    /// What was accepted, and how it was read.
15    pub message: String,
16}
17
18/// How serious a [`ParseWarning`] is.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
20#[serde(rename_all = "snake_case")]
21#[non_exhaustive]
22pub enum WarningKind {
23    /// A whole motor entry had an error and was left out of the result.
24    Skipped,
25    /// A value was dropped or ignored, such as an unknown attribute or a partial mass column.
26    Dropped,
27    /// Something unusual was read as it stands, such as a curve that doesn't end at zero thrust.
28    Unusual,
29}
30
31impl ParseWarning {
32    pub(crate) fn new(line: usize, kind: WarningKind, message: impl Into<String>) -> Self {
33        Self {
34            line,
35            kind,
36            message: message.into(),
37        }
38    }
39}
40
41/// A parsed value and the warnings its reader raised.
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
43pub struct Parsed<T> {
44    /// The value read.
45    pub value: T,
46    /// Warnings, in file order.
47    pub warnings: Vec<ParseWarning>,
48}
49
50/// Reads a finite `f64`. Rust's parser also accepts `inf` and `NaN`, which no motor file means.
51pub(crate) fn finite(text: &str, what: &'static str) -> Result<f64, MotorError> {
52    match text.trim().parse::<f64>() {
53        Ok(value) if value.is_finite() => Ok(value),
54        _ => Err(MotorError::Parse {
55            what,
56            text: text.to_owned(),
57        }),
58    }
59}
60
61/// Checks a value the writers will print: finite, and non-negative when `non_negative`.
62pub(crate) fn check_writable(
63    value: f64,
64    what: &'static str,
65    non_negative: bool,
66) -> Result<(), MotorError> {
67    if value.is_finite() && !(non_negative && value < 0.0) {
68        Ok(())
69    } else {
70        Err(MotorError::Domain { what, value })
71    }
72}