Skip to main content

ferrocat_icu/
error.rs

1use core::fmt;
2
3/// High-level classification of ICU parse failures.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum IcuErrorKind {
6    /// The input violates the supported ICU syntax.
7    SyntaxError,
8}
9
10/// Byte offset plus line/column location inside the original input.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct IcuPosition {
13    /// Zero-based byte offset from the start of the input.
14    pub offset: usize,
15    /// One-based line number.
16    pub line: usize,
17    /// One-based column number.
18    pub column: usize,
19}
20
21/// Error returned when parsing ICU messages fails.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct IcuParseError {
24    /// High-level failure kind.
25    pub kind: IcuErrorKind,
26    /// Human-readable parser error message.
27    pub message: String,
28    /// Source location for the parser failure.
29    pub position: IcuPosition,
30}
31
32impl IcuParseError {
33    /// Creates a syntax error at `offset` within `input`.
34    #[must_use]
35    pub fn syntax(message: impl Into<String>, input: &str, offset: usize) -> Self {
36        Self {
37            kind: IcuErrorKind::SyntaxError,
38            message: message.into(),
39            position: position_for_offset(input, offset),
40        }
41    }
42}
43
44impl fmt::Display for IcuParseError {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        write!(
47            f,
48            "{} at line {}, column {}",
49            self.message, self.position.line, self.position.column
50        )
51    }
52}
53
54impl std::error::Error for IcuParseError {}
55
56fn position_for_offset(input: &str, offset: usize) -> IcuPosition {
57    let clamped = offset.min(input.len());
58    let mut line = 1usize;
59    let mut column = 1usize;
60
61    for ch in input[..clamped].chars() {
62        if ch == '\n' {
63            line += 1;
64            column = 1;
65        } else {
66            column += 1;
67        }
68    }
69
70    IcuPosition {
71        offset: clamped,
72        line,
73        column,
74    }
75}