Skip to main content

pleiades_data/coverage/
generation.rs

1use super::*;
2
3/// Structured generation policy for the packaged artifact.
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub enum PackagedArtifactGenerationPolicy {
6    /// Same-body source epochs are fit with adjacent quadratic windows.
7    AdjacentSameBodyQuadraticWindows,
8}
9
10/// Validation error for the packaged-artifact generation policy.
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
12pub enum PackagedArtifactGenerationPolicyValidationError {
13    /// A policy field is out of sync with the current packaged-artifact posture.
14    FieldOutOfSync { field: &'static str },
15}
16
17impl PackagedArtifactGenerationPolicyValidationError {
18    /// Returns the compact release-facing summary for the validation error.
19    pub fn summary_line(&self) -> String {
20        match self {
21            Self::FieldOutOfSync { field } => format!(
22                "the packaged artifact generation policy field `{field}` is out of sync with the current posture"
23            ),
24        }
25    }
26}
27
28impl fmt::Display for PackagedArtifactGenerationPolicyValidationError {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        f.write_str(&self.summary_line())
31    }
32}
33
34impl std::error::Error for PackagedArtifactGenerationPolicyValidationError {}
35
36impl PackagedArtifactGenerationPolicy {
37    /// Returns the compact label used in release-facing summaries.
38    pub const fn label(self) -> &'static str {
39        match self {
40            Self::AdjacentSameBodyQuadraticWindows => "adjacent same-body quadratic windows",
41        }
42    }
43
44    /// Returns the explanatory note used in release-facing summaries.
45    pub fn note(self) -> &'static str {
46        match self {
47            Self::AdjacentSameBodyQuadraticWindows => {
48                packaged_artifact_generation_policy_note_text()
49            }
50        }
51    }
52
53    /// Returns the segment-strategy text used in release-facing summaries.
54    pub fn segment_strategy(self) -> &'static str {
55        self.note()
56    }
57
58    /// Returns the compact release-facing summary for the generation policy.
59    pub fn summary_line(self) -> String {
60        format!("{}; {}", self.label(), self.note())
61    }
62
63    /// Returns `Ok(())` when the generation policy still matches the current packaged-artifact posture.
64    pub fn validate(self) -> Result<(), PackagedArtifactGenerationPolicyValidationError> {
65        if self != Self::AdjacentSameBodyQuadraticWindows {
66            return Err(
67                PackagedArtifactGenerationPolicyValidationError::FieldOutOfSync { field: "policy" },
68            );
69        }
70
71        Ok(())
72    }
73}
74
75impl fmt::Display for PackagedArtifactGenerationPolicy {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        f.write_str(self.label())
78    }
79}
80
81/// Structured summary for the packaged-artifact generation policy.
82#[derive(Clone, Copy, Debug, PartialEq, Eq)]
83pub struct PackagedArtifactGenerationPolicySummary {
84    /// Policy describing how the packaged artifact is generated.
85    pub policy: PackagedArtifactGenerationPolicy,
86}
87
88/// Validation error for the packaged-artifact generation policy summary.
89#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
90pub enum PackagedArtifactGenerationPolicySummaryValidationError {
91    /// A summary field is out of sync with the current packaged-artifact posture.
92    FieldOutOfSync { field: &'static str },
93}
94
95impl PackagedArtifactGenerationPolicySummaryValidationError {
96    /// Returns the compact release-facing summary for the validation error.
97    pub fn summary_line(&self) -> String {
98        match self {
99            Self::FieldOutOfSync { field } => format!(
100                "the packaged artifact generation policy summary field `{field}` is out of sync with the current posture"
101            ),
102        }
103    }
104}
105
106impl fmt::Display for PackagedArtifactGenerationPolicySummaryValidationError {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        f.write_str(&self.summary_line())
109    }
110}
111
112impl std::error::Error for PackagedArtifactGenerationPolicySummaryValidationError {}
113
114pub(crate) fn validate_packaged_artifact_generation_policy_residual_bodies(
115    policy: PackagedArtifactGenerationPolicy,
116    residual_bodies: &[CelestialBody],
117) -> Result<(), PackagedArtifactGenerationPolicySummaryValidationError> {
118    match policy {
119        PackagedArtifactGenerationPolicy::AdjacentSameBodyQuadraticWindows => {
120            let expected_residual_bodies = packaged_artifact().residual_bodies();
121            if residual_bodies != expected_residual_bodies.as_slice() {
122                return Err(
123                    PackagedArtifactGenerationPolicySummaryValidationError::FieldOutOfSync {
124                        field: "residual_bodies",
125                    },
126                );
127            }
128        }
129    }
130
131    Ok(())
132}
133
134impl PackagedArtifactGenerationPolicySummary {
135    /// Returns the packaged-artifact generation policy as a compact human-readable line.
136    pub fn summary_line(self) -> String {
137        self.policy.summary_line()
138    }
139
140    /// Returns `Ok(())` when the summary still matches the current packaged-artifact posture.
141    pub fn validate(&self) -> Result<(), PackagedArtifactGenerationPolicySummaryValidationError> {
142        self.policy.validate().map_err(|error| match error {
143            PackagedArtifactGenerationPolicyValidationError::FieldOutOfSync { field } => {
144                PackagedArtifactGenerationPolicySummaryValidationError::FieldOutOfSync { field }
145            }
146        })?;
147
148        validate_packaged_artifact_generation_policy_residual_bodies(
149            self.policy,
150            &packaged_artifact().residual_bodies(),
151        )
152    }
153}
154
155impl fmt::Display for PackagedArtifactGenerationPolicySummary {
156    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157        f.write_str(&self.summary_line())
158    }
159}
160
161const PACKAGED_ARTIFACT_GENERATION_POLICY_SUMMARY: PackagedArtifactGenerationPolicySummary =
162    PackagedArtifactGenerationPolicySummary {
163        policy: PackagedArtifactGenerationPolicy::AdjacentSameBodyQuadraticWindows,
164    };
165
166/// Returns the current packaged-artifact generation policy summary record.
167///
168/// # Examples
169///
170/// ```
171/// use pleiades_data::packaged_artifact_generation_policy_summary_details;
172///
173/// let summary = packaged_artifact_generation_policy_summary_details();
174/// assert!(summary.validate().is_ok());
175/// ```
176pub fn packaged_artifact_generation_policy_summary_details(
177) -> PackagedArtifactGenerationPolicySummary {
178    let summary = PACKAGED_ARTIFACT_GENERATION_POLICY_SUMMARY;
179    debug_assert!(summary.validate().is_ok());
180    summary
181}
182
183/// Returns the current packaged-artifact residual-bearing body coverage summary record.
184pub fn packaged_artifact_generation_residual_bodies_summary_details(
185) -> ArtifactResidualBodyCoverageSummary {
186    let artifact = packaged_artifact();
187    let summary = artifact.residual_body_coverage_summary();
188    debug_assert!(summary.validate(artifact).is_ok());
189    summary
190}
191
192/// Returns the current packaged-artifact generation policy summary.
193pub fn packaged_artifact_generation_policy_summary() -> &'static str {
194    static SUMMARY: OnceLock<String> = OnceLock::new();
195    SUMMARY
196        .get_or_init(|| {
197            let summary = packaged_artifact_generation_policy_summary_details();
198            match summary.validate() {
199                Ok(()) => summary.to_string(),
200                Err(error) => format!("Packaged-artifact generation policy: unavailable ({error})"),
201            }
202        })
203        .as_str()
204}