Skip to main content

qubit_codec_text/error/
charset_encode_error.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8use core::fmt;
9use std::error::Error;
10
11use crate::{
12    Charset,
13    CharsetEncodeErrorKind,
14};
15
16/// Error reported by a charset encoder.
17///
18/// The error always carries the target charset, error kind, and operation
19/// index associated with the failure. For buffer errors this is the
20/// caller-supplied output index. Errors tied to a raw code point or character
21/// value expose that value through [`Self::kind`] and [`Self::value`].
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub struct CharsetEncodeError {
24    /// Target charset of the operation that produced this error.
25    charset: Charset,
26    /// Failure category describing why encoding could not proceed.
27    kind: CharsetEncodeErrorKind,
28    /// Output unit index or input code point index where failure occurred.
29    index: usize,
30}
31
32/// Result type returned by charset encoders.
33///
34/// # Type Parameters
35///
36/// - `T`: Successful value produced by an encoding operation.
37pub type CharsetEncodeResult<T> = Result<T, CharsetEncodeError>;
38
39impl CharsetEncodeError {
40    /// Creates an encoding error.
41    ///
42    /// # Parameters
43    ///
44    /// - `charset`: The target charset.
45    /// - `kind`: The failure category.
46    /// - `index`: The operation index associated with the failure.
47    ///
48    /// # Returns
49    ///
50    /// Returns an encoding error carrying the supplied context.
51    #[inline(always)]
52    pub const fn new(
53        charset: Charset,
54        kind: CharsetEncodeErrorKind,
55        index: usize,
56    ) -> Self {
57        Self {
58            charset,
59            kind,
60            index,
61        }
62    }
63
64    /// Returns required output units for this encoding error, if reported.
65    ///
66    /// # Returns
67    ///
68    /// Returns `Some(required)` for [`CharsetEncodeErrorKind::BufferTooSmall`],
69    /// otherwise `None`.
70    #[inline(always)]
71    pub const fn required(self) -> Option<usize> {
72        self.kind.required()
73    }
74
75    /// Returns available output units for this encoding error, if reported.
76    ///
77    /// # Returns
78    ///
79    /// Returns `Some(available)` for
80    /// [`CharsetEncodeErrorKind::BufferTooSmall`], otherwise `None`.
81    #[inline(always)]
82    pub const fn available(self) -> Option<usize> {
83        self.kind.available()
84    }
85
86    /// Returns output length for this encoding error, if reported.
87    ///
88    /// # Returns
89    ///
90    /// Returns `Some(output_len)` for
91    /// [`CharsetEncodeErrorKind::InvalidOutputIndex`], otherwise `None`.
92    #[inline(always)]
93    pub const fn output_len(self) -> Option<usize> {
94        self.kind.output_len()
95    }
96
97    /// Returns the target charset.
98    ///
99    /// # Returns
100    ///
101    /// Returns the stored [`Charset`].
102    #[inline(always)]
103    pub const fn charset(self) -> Charset {
104        self.charset
105    }
106
107    /// Returns the encoding error kind.
108    ///
109    /// # Returns
110    ///
111    /// Returns the stored [`CharsetEncodeErrorKind`].
112    #[inline(always)]
113    pub const fn kind(self) -> CharsetEncodeErrorKind {
114        self.kind
115    }
116
117    /// Returns the operation index associated with this error.
118    ///
119    /// # Returns
120    ///
121    /// Returns the stored index.
122    #[inline(always)]
123    pub const fn index(self) -> usize {
124        self.index
125    }
126
127    /// Returns the raw value associated with this error.
128    ///
129    /// # Returns
130    ///
131    /// Returns `Some(value)` when the error kind carries a raw code point or
132    /// character value, or `None` for kinds without an associated value.
133    #[inline(always)]
134    pub const fn value(self) -> Option<u32> {
135        self.kind.value()
136    }
137
138    /// Offsets this error by a base unit index.
139    ///
140    /// # Parameters
141    ///
142    /// - `base`: The base index to add to the stored index.
143    ///
144    /// # Returns
145    ///
146    /// Returns a copy of this error with its index shifted by `base`.
147    ///
148    /// If the shifted index cannot be represented, it is saturated to
149    /// [`usize::MAX`].
150    #[inline(always)]
151    pub const fn offset_by(self, base: usize) -> Self {
152        Self {
153            charset: self.charset,
154            kind: self.kind,
155            index: match self.index.checked_add(base) {
156                Some(index) => index,
157                None => usize::MAX,
158            },
159        }
160    }
161}
162
163impl fmt::Display for CharsetEncodeError {
164    /// Formats this encoding error.
165    ///
166    /// # Parameters
167    ///
168    /// - `formatter`: The formatter receiving the diagnostic message.
169    ///
170    /// # Errors
171    ///
172    /// Returns any formatting error reported by `formatter`.
173    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
174        if let Some(value) = self.kind.value() {
175            write!(
176                formatter,
177                "{} encoding error at index {} for value 0x{:x}: {}",
178                self.charset, self.index, value, self.kind,
179            )
180        } else {
181            write!(
182                formatter,
183                "{} encoding error at index {}: {}",
184                self.charset, self.index, self.kind,
185            )
186        }
187    }
188}
189
190impl Error for CharsetEncodeError {}