hpr_io/ork/warning.rs
1//! What a reader accepted but wants to say out loud.
2
3use serde::{Deserialize, Serialize};
4
5/// Something the reader accepted and flagged, rather than failing over.
6///
7/// The roadmap asks the `.ork` importer for "graceful warnings instead of failures": a real design
8/// written by an older OpenRocket, or by another program, should still open. Every departure from
9/// what the file format documents is reported here, with the place in the file it happened.
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
11pub struct Warning {
12 /// Where it happened: a zip entry name, or a slash-separated path of element names from the
13 /// root, such as `openrocket/rocket/subcomponents/nosecone`.
14 pub at: String,
15 /// Whether anything was lost.
16 pub kind: WarningKind,
17 /// What was read, and how.
18 pub message: String,
19}
20
21/// How serious a [`Warning`] is.
22///
23/// The same three levels `hpr_motor::WarningKind` uses for `.eng` and `.rse` files. The two enums
24/// are kept apart because their readers report different places (a line number there, a path into
25/// an archive or an element tree here) and because `hpr-io` does not otherwise need `hpr-motor`.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27#[serde(rename_all = "snake_case")]
28#[non_exhaustive]
29pub enum WarningKind {
30 /// A whole part of the file was left out of the result, such as an archive entry compressed
31 /// by a method this reader does not implement.
32 Skipped,
33 /// A value was dropped or ignored.
34 Dropped,
35 /// Something unusual was read as it stands, such as a schema version newer than any documented.
36 Unusual,
37}
38
39impl Warning {
40 /// Records a warning at `at`.
41 pub(crate) fn new(
42 at: impl Into<String>,
43 kind: WarningKind,
44 message: impl Into<String>,
45 ) -> Self {
46 Self {
47 at: at.into(),
48 kind,
49 message: message.into(),
50 }
51 }
52}
53
54/// A value read from a `.ork` file and the warnings its reader raised, in the order they arose.
55#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56pub struct Imported<T> {
57 /// The value read.
58 pub value: T,
59 /// The warnings, in file order.
60 pub warnings: Vec<Warning>,
61}
62
63impl<T> Imported<T> {
64 /// Wraps a value with no warnings.
65 pub(crate) fn clean(value: T) -> Self {
66 Self {
67 value,
68 warnings: Vec::new(),
69 }
70 }
71
72 /// Counts the warnings of one kind.
73 pub fn count(&self, kind: WarningKind) -> usize {
74 self.warnings.iter().filter(|w| w.kind == kind).count()
75 }
76}