Skip to main content

ccsds_ndm/
validation.rs

1// SPDX-FileCopyrightText: 2025 Jochim Maene <jochim.maene+github@gmail.com>
2//
3// SPDX-License-Identifier: MPL-2.0
4
5use crate::error::{CcsdsNdmError, Result, ValidationError};
6use crate::traits::Validate;
7use std::cell::{Cell, RefCell};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum ValidationMode {
11    Strict,
12    Lenient,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub enum MessageKind {
17    Opm,
18    Omm,
19    Oem,
20    Ocm,
21    Acm,
22    Aem,
23    Apm,
24    Cdm,
25    Tdm,
26    Rdm,
27    Ndm,
28}
29
30#[derive(Debug, Clone)]
31pub struct ValidationIssue {
32    pub message_kind: MessageKind,
33    pub error: ValidationError,
34}
35
36thread_local! {
37    static VALIDATION_MODE: Cell<ValidationMode> = const { Cell::new(ValidationMode::Strict) };
38    static VALIDATION_WARNINGS: RefCell<Vec<ValidationIssue>> = const { RefCell::new(Vec::new()) };
39}
40
41pub fn current_mode() -> ValidationMode {
42    VALIDATION_MODE.with(|mode| mode.get())
43}
44
45pub fn with_validation_mode<T>(mode: ValidationMode, f: impl FnOnce() -> Result<T>) -> Result<T> {
46    struct Guard {
47        prev: ValidationMode,
48    }
49
50    let prev = VALIDATION_MODE.with(|m| {
51        let prev = m.get();
52        m.set(mode);
53        prev
54    });
55
56    let _guard = Guard { prev };
57    let res = f();
58
59    VALIDATION_MODE.with(|m| m.set(_guard.prev));
60    res
61}
62
63pub fn take_warnings() -> Vec<ValidationIssue> {
64    VALIDATION_WARNINGS.with(|warnings| warnings.borrow_mut().drain(..).collect())
65}
66
67pub fn validate_with_mode(kind: MessageKind, value: &impl Validate) -> Result<()> {
68    match value.validate() {
69        Ok(()) => Ok(()),
70        Err(err) => handle_validation_error(kind, err),
71    }
72}
73
74pub fn handle_validation_error(kind: MessageKind, err: CcsdsNdmError) -> Result<()> {
75    match err {
76        CcsdsNdmError::Validation(val) => handle_validation_error_inner(kind, *val),
77        other => Err(other),
78    }
79}
80
81fn handle_validation_error_inner(kind: MessageKind, err: ValidationError) -> Result<()> {
82    match current_mode() {
83        ValidationMode::Strict => Err(err.into()),
84        ValidationMode::Lenient => {
85            VALIDATION_WARNINGS.with(|warnings| {
86                warnings.borrow_mut().push(ValidationIssue {
87                    message_kind: kind,
88                    error: err,
89                });
90            });
91            Ok(())
92        }
93    }
94}