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