Skip to main content

qrcode_generator/
error.rs

1use core::{error::Error, fmt};
2#[cfg(feature = "std")]
3use std::io;
4
5#[cfg(feature = "micro-qr")]
6use crate::{SymbolErrorCorrection, SymbolVersion};
7
8/// Errors returned while encoding a QR Code symbol.
9#[derive(Debug)]
10#[non_exhaustive]
11pub enum EncodeError {
12    /// The encoded bit stream exceeds the selected symbol capacity.
13    DataTooLong {
14        /// The exact number of bits the encoded data needs, or `None` when the encoder rejected the input before measuring it, for example from a capacity precheck or a character count over the indicator limit.
15        required_bits: Option<usize>,
16        /// The number of data bits the selected symbols hold.
17        capacity_bits: usize,
18    },
19    /// The input contains a byte that is not valid for the requested mode.
20    InvalidData { mode: &'static str, byte_offset: usize },
21    /// The input cannot be represented by the selected symbol family.
22    #[cfg(feature = "micro-qr")]
23    TextNotRepresentable { byte_offset: usize, family: &'static str },
24    /// The ECI assignment is outside the range supported by QR Code.
25    #[cfg(any(feature = "qr", feature = "rmqr"))]
26    InvalidEciAssignment(u32),
27    /// The FNC1 second-position application indicator is invalid.
28    #[cfg(any(feature = "qr", feature = "rmqr"))]
29    InvalidApplicationIndicator,
30    /// The selected version range is empty or invalid.
31    InvalidVersionRange,
32    /// The selected symbol family does not support a requested mode.
33    #[cfg(feature = "micro-qr")]
34    UnsupportedMode { mode: &'static str, family: &'static str },
35    /// The selected version does not support the requested error correction level.
36    #[cfg(feature = "micro-qr")]
37    UnsupportedErrorCorrection {
38        version:          SymbolVersion,
39        error_correction: SymbolErrorCorrection,
40    },
41    /// The requested mask number is outside the supported range.
42    InvalidMask,
43    /// A Structured Append sequence has fewer than one or more than 16 parts.
44    #[cfg(feature = "qr")]
45    InvalidStructuredAppendPartCount { count: usize },
46}
47
48impl fmt::Display for EncodeError {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        match self {
51            Self::DataTooLong {
52                required_bits,
53                capacity_bits,
54            } => {
55                if let Some(required_bits) = required_bits {
56                    write!(
57                        f,
58                        "the encoded data needs {required_bits} bits but the selected symbols \
59                         hold {capacity_bits} bits"
60                    )
61                } else {
62                    f.write_str("the encoded data exceeds the capacity of the selected symbols")
63                }
64            },
65            Self::InvalidData {
66                mode,
67                byte_offset,
68            } => {
69                write!(f, "invalid {mode} data at byte offset {byte_offset}")
70            },
71            #[cfg(feature = "micro-qr")]
72            Self::TextNotRepresentable {
73                byte_offset,
74                family,
75            } => {
76                write!(
77                    f,
78                    "the input at byte offset {byte_offset} cannot be represented by {family}"
79                )
80            },
81            #[cfg(any(feature = "qr", feature = "rmqr"))]
82            Self::InvalidEciAssignment(value) => {
83                write!(f, "ECI assignment {value} is outside 0..=999999")
84            },
85            #[cfg(any(feature = "qr", feature = "rmqr"))]
86            Self::InvalidApplicationIndicator => f.write_str("invalid FNC1 application indicator"),
87            Self::InvalidVersionRange => f.write_str("invalid symbol version range"),
88            #[cfg(feature = "micro-qr")]
89            Self::UnsupportedMode {
90                mode,
91                family,
92            } => {
93                write!(f, "{mode} mode is not supported by {family}")
94            },
95            #[cfg(feature = "micro-qr")]
96            Self::UnsupportedErrorCorrection {
97                version,
98                error_correction,
99            } => write!(f, "{error_correction:?} error correction is not supported by {version:?}"),
100            Self::InvalidMask => f.write_str("the mask number is outside the supported range"),
101            #[cfg(feature = "qr")]
102            Self::InvalidStructuredAppendPartCount {
103                count,
104            } => {
105                write!(f, "Structured Append requires 1..=16 parts, got {count}")
106            },
107        }
108    }
109}
110
111impl Error for EncodeError {}
112
113/// Errors returned while rendering a QR Code symbol.
114#[derive(Debug)]
115#[non_exhaustive]
116pub enum RenderError {
117    /// The requested output is too small for an integer module scale and quiet zone.
118    ImageSizeTooSmall,
119    /// The requested output dimensions overflow a supported image size.
120    ImageSizeTooLarge,
121    /// An input or output operation failed.
122    #[cfg(feature = "std")]
123    Io(io::Error),
124    #[cfg(feature = "image")]
125    /// PNG encoding failed.
126    Image(image::ImageError),
127}
128
129impl fmt::Display for RenderError {
130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131        match self {
132            Self::ImageSizeTooSmall => {
133                f.write_str("image size is too small to draw the whole symbol")
134            },
135            Self::ImageSizeTooLarge => f.write_str("image size is too large to generate"),
136            #[cfg(feature = "std")]
137            Self::Io(error) => fmt::Display::fmt(error, f),
138            #[cfg(feature = "image")]
139            Self::Image(error) => fmt::Display::fmt(error, f),
140        }
141    }
142}
143
144impl Error for RenderError {
145    fn source(&self) -> Option<&(dyn Error + 'static)> {
146        match self {
147            #[cfg(feature = "std")]
148            Self::Io(error) => Some(error),
149            #[cfg(feature = "image")]
150            Self::Image(error) => Some(error),
151            _ => None,
152        }
153    }
154}
155
156#[cfg(feature = "std")]
157impl From<io::Error> for RenderError {
158    #[inline]
159    fn from(error: io::Error) -> Self {
160        Self::Io(error)
161    }
162}
163
164#[cfg(feature = "image")]
165impl From<image::ImageError> for RenderError {
166    #[inline]
167    fn from(error: image::ImageError) -> Self {
168        Self::Image(error)
169    }
170}