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 {}