mx_message/
parse_result.rs

1// Plasmatic MX Message Parsing Library
2// https://github.com/GoPlasmatic/MXMessage
3//
4// Copyright (c) 2025 Plasmatic
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9//     http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17// You may obtain a copy of this library at
18// https://github.com/GoPlasmatic/MXMessage
19
20use crate::error::ValidationError;
21use serde::{Deserialize, Serialize};
22
23/// Result of parsing with error collection support
24#[derive(Debug, Clone, PartialEq)]
25pub enum ParseResult<T> {
26    /// All fields parsed successfully
27    Success(T),
28    /// Some errors occurred but structure is valid
29    PartialSuccess(T, Vec<ValidationError>),
30    /// Too many critical errors to continue
31    Failure(Vec<ValidationError>),
32}
33
34impl<T> ParseResult<T> {
35    /// Check if the parse was successful (no errors)
36    pub fn is_success(&self) -> bool {
37        matches!(self, ParseResult::Success(_))
38    }
39
40    /// Check if the parse resulted in failure
41    pub fn is_failure(&self) -> bool {
42        matches!(self, ParseResult::Failure(_))
43    }
44
45    /// Get the parsed value if available
46    pub fn value(&self) -> Option<&T> {
47        match self {
48            ParseResult::Success(val) | ParseResult::PartialSuccess(val, _) => Some(val),
49            ParseResult::Failure(_) => None,
50        }
51    }
52
53    /// Get all errors if any
54    pub fn errors(&self) -> Vec<&ValidationError> {
55        match self {
56            ParseResult::Success(_) => vec![],
57            ParseResult::PartialSuccess(_, errors) | ParseResult::Failure(errors) => {
58                errors.iter().collect()
59            }
60        }
61    }
62
63    /// Convert to Result for compatibility
64    pub fn to_result(self) -> Result<T, Vec<ValidationError>> {
65        match self {
66            ParseResult::Success(val) => Ok(val),
67            ParseResult::PartialSuccess(val, _) => Ok(val),
68            ParseResult::Failure(errors) => Err(errors),
69        }
70    }
71}
72
73/// Configuration for parsing behavior
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct ParserConfig {
76    /// If true, stop at first error. If false, collect all errors.
77    pub fail_fast: bool,
78    /// If true, validate optional fields. If false, skip validation on None fields.
79    pub validate_optional_fields: bool,
80    /// If true, attempt to collect all possible errors even when structure is invalid.
81    pub collect_all_errors: bool,
82}
83
84impl Default for ParserConfig {
85    fn default() -> Self {
86        ParserConfig {
87            fail_fast: false,
88            validate_optional_fields: true,
89            collect_all_errors: true,
90        }
91    }
92}
93
94impl ParserConfig {
95    /// Create a new parser configuration with fail_fast enabled
96    pub fn fail_fast() -> Self {
97        ParserConfig {
98            fail_fast: true,
99            validate_optional_fields: true,
100            collect_all_errors: false,
101        }
102    }
103
104    /// Create a new parser configuration for lenient parsing
105    pub fn lenient() -> Self {
106        ParserConfig {
107            fail_fast: false,
108            validate_optional_fields: false,
109            collect_all_errors: false,
110        }
111    }
112}
113
114/// Helper struct for collecting validation errors
115#[derive(Debug, Default)]
116pub struct ErrorCollector {
117    errors: Vec<ValidationError>,
118    has_critical_errors: bool,
119}
120
121impl ErrorCollector {
122    pub fn new() -> Self {
123        ErrorCollector {
124            errors: Vec::new(),
125            has_critical_errors: false,
126        }
127    }
128
129    /// Add an error to the collection
130    pub fn add_error(&mut self, error: ValidationError) {
131        self.errors.push(error);
132    }
133
134    /// Add a critical error (e.g., missing required field)
135    pub fn add_critical_error(&mut self, error: ValidationError) {
136        self.has_critical_errors = true;
137        self.errors.push(error);
138    }
139
140    /// Check if there are any errors
141    pub fn has_errors(&self) -> bool {
142        !self.errors.is_empty()
143    }
144
145    /// Check if there are critical errors
146    pub fn has_critical_errors(&self) -> bool {
147        self.has_critical_errors
148    }
149
150    /// Get all collected errors
151    pub fn errors(self) -> Vec<ValidationError> {
152        self.errors
153    }
154
155    /// Get the count of errors
156    pub fn error_count(&self) -> usize {
157        self.errors.len()
158    }
159}