Skip to main content

fyaml/
error.rs

1//! Error types for fyaml operations.
2//!
3//! This module provides structured error types for YAML parsing and manipulation,
4//! with rich diagnostic information including line and column numbers.
5//!
6//! # Parse Errors
7//!
8//! When parsing fails, [`Error::ParseError`] provides detailed location information:
9//!
10//! ```
11//! use fyaml::Document;
12//!
13//! let result = Document::parse_str("[unclosed");
14//! if let Err(e) = result {
15//!     // Access structured error info
16//!     if let fyaml::Error::ParseError(parse_err) = &e {
17//!         println!("Error: {}", parse_err.message());
18//!         if let Some((line, col)) = parse_err.location() {
19//!             println!("At line {}, column {}", line, col);
20//!         }
21//!     }
22//!     // Or just display it nicely
23//!     println!("{}", e);  // "Parse error at 2:1: flow sequence without a closing bracket"
24//! }
25//! ```
26
27use std::fmt;
28
29/// Detailed parse error with location information.
30///
31/// Contains the error message from libfyaml along with optional line and column
32/// numbers indicating where the error occurred in the input.
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct ParseError {
35    /// The error message from libfyaml.
36    pub(crate) message: String,
37    /// Line number (1-based), if available.
38    pub(crate) line: Option<u32>,
39    /// Column number (1-based), if available.
40    pub(crate) column: Option<u32>,
41}
42
43impl ParseError {
44    /// Creates a new parse error with just a message.
45    pub fn new(message: impl Into<String>) -> Self {
46        Self {
47            message: message.into(),
48            line: None,
49            column: None,
50        }
51    }
52
53    /// Creates a new parse error with location information.
54    pub fn with_location(message: impl Into<String>, line: u32, column: u32) -> Self {
55        Self {
56            message: message.into(),
57            line: Some(line),
58            column: Some(column),
59        }
60    }
61
62    /// Returns the error message.
63    pub fn message(&self) -> &str {
64        &self.message
65    }
66
67    /// Returns the line number (1-based), if available.
68    pub fn line(&self) -> Option<u32> {
69        self.line
70    }
71
72    /// Returns the column number (1-based), if available.
73    pub fn column(&self) -> Option<u32> {
74        self.column
75    }
76
77    /// Returns the location as (line, column), if both are available.
78    pub fn location(&self) -> Option<(u32, u32)> {
79        match (self.line, self.column) {
80            (Some(l), Some(c)) => Some((l, c)),
81            _ => None,
82        }
83    }
84}
85
86impl fmt::Display for ParseError {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        match (self.line, self.column) {
89            (Some(line), Some(col)) => write!(f, "at {}:{}: {}", line, col, self.message),
90            (Some(line), None) => write!(f, "at line {}: {}", line, self.message),
91            _ => write!(f, "{}", self.message),
92        }
93    }
94}
95
96impl std::error::Error for ParseError {}
97
98/// Error type for fyaml operations.
99#[derive(Debug, Clone, PartialEq, Eq)]
100pub enum Error {
101    /// FFI call returned an error or unexpected result.
102    Ffi(&'static str),
103
104    /// YAML parsing failed (simple message, no location info).
105    Parse(&'static str),
106
107    /// YAML parsing failed with detailed location information.
108    ParseError(ParseError),
109
110    /// I/O operation failed.
111    Io(&'static str),
112
113    /// Memory allocation failed.
114    Alloc(&'static str),
115
116    /// UTF-8 conversion failed.
117    Utf8(std::str::Utf8Error),
118
119    /// Attempted to mutate document while iterators are active.
120    MutationWhileIterating,
121
122    /// Operation requires a different node type.
123    TypeMismatch {
124        expected: &'static str,
125        got: &'static str,
126    },
127
128    /// Nodes must belong to the same document.
129    DocumentMismatch,
130
131    /// Scalar length exceeds sanity limit.
132    ScalarTooLarge(usize),
133}
134
135impl Error {
136    /// Returns the parse error details if this is a parse error.
137    pub fn as_parse_error(&self) -> Option<&ParseError> {
138        match self {
139            Error::ParseError(e) => Some(e),
140            _ => None,
141        }
142    }
143}
144
145impl fmt::Display for Error {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        match self {
148            Error::Ffi(msg) => write!(f, "FFI error: {}", msg),
149            Error::Parse(msg) => write!(f, "Parse error: {}", msg),
150            Error::ParseError(e) => write!(f, "Parse error {}", e),
151            Error::Io(msg) => write!(f, "I/O error: {}", msg),
152            Error::Alloc(msg) => write!(f, "Allocation error: {}", msg),
153            Error::Utf8(e) => write!(f, "UTF-8 error: {}", e),
154            Error::MutationWhileIterating => {
155                write!(f, "Cannot mutate document while iterating")
156            }
157            Error::TypeMismatch { expected, got } => {
158                write!(f, "Type mismatch: expected {}, got {}", expected, got)
159            }
160            Error::DocumentMismatch => {
161                write!(f, "Nodes must belong to the same document")
162            }
163            Error::ScalarTooLarge(len) => {
164                write!(f, "Scalar length {} exceeds sanity limit", len)
165            }
166        }
167    }
168}
169
170impl std::error::Error for Error {
171    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
172        match self {
173            Error::Utf8(e) => Some(e),
174            Error::ParseError(e) => Some(e),
175            _ => None,
176        }
177    }
178}
179
180impl From<std::str::Utf8Error> for Error {
181    fn from(e: std::str::Utf8Error) -> Self {
182        Error::Utf8(e)
183    }
184}
185
186impl From<ParseError> for Error {
187    fn from(e: ParseError) -> Self {
188        Error::ParseError(e)
189    }
190}
191
192/// Result type alias using fyaml's Error.
193pub type Result<T> = std::result::Result<T, Error>;