sqlite_diff_rs/wire/error.rs
1//! [`DecodeError`]: shared failure mode for every decoder in the
2//! [`wire`](super) module.
3//!
4//! Per-format `ConversionError` types (in `pg_walstream::ConversionError`,
5//! `wal2json::ConversionError`, `maxwell::ConversionError`) wrap this
6//! via a `Decode(DecodeError)` variant so users can pattern-match on
7//! the outer error and route to a common inner arm.
8
9use alloc::string::String;
10
11/// Failure modes shared across every `wire::Decoder` implementation.
12#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
13#[non_exhaustive]
14pub enum DecodeError {
15 /// The [`TypeMap`](super::TypeMap) contains no decoder for the
16 /// wire type carried by this column.
17 #[error("no decoder registered for column {column:?}")]
18 NoDecoderForType {
19 /// Column whose type was unrecognized.
20 column: String,
21 },
22
23 /// The decoder skeleton exists but its implementation is not yet populated.
24 #[error("decoder {decoder} is not yet implemented")]
25 NotYetImplemented {
26 /// The unpopulated decoder's type name.
27 decoder: &'static str,
28 },
29
30 /// Column payload was expected to be valid UTF-8 and was not.
31 #[error("column {column:?} carried non-UTF-8 bytes")]
32 InvalidUtf8 {
33 /// Offending column name.
34 column: String,
35 },
36
37 /// Column payload did not parse as a UUID (36-char hyphenated or
38 /// braced form).
39 #[error("column {column:?} carried a malformed UUID (source length {source_len})")]
40 InvalidUuid {
41 /// Offending column name.
42 column: String,
43 /// Length of the string the decoder tried to parse.
44 source_len: usize,
45 },
46
47 /// Column payload was expected to be a `\xHEX` PG BYTEA escape and
48 /// contained an invalid character at the reported byte offset.
49 #[error("column {column:?} carried a malformed \\x hex escape at offset {at}")]
50 InvalidHexEscape {
51 /// Offending column name.
52 column: String,
53 /// Zero-based byte offset of the first invalid character.
54 at: usize,
55 },
56
57 /// Integer payload exceeded `i64` range and its shape (MySQL
58 /// `bigint unsigned`, PG `numeric` cast, ...) did not permit a
59 /// silent fallback to `Text`.
60 #[error("column {column:?} integer digits overflowed i64: {digits}")]
61 IntegerOverflow {
62 /// Offending column name.
63 column: String,
64 /// The raw digit string as received on the wire.
65 digits: String,
66 },
67
68 /// Column carried a decimal that was delivered as a JSON number,
69 /// which cannot preserve precision above ~15 significant digits.
70 #[error("column {column:?} carried a decimal as a lossy JSON number")]
71 DecimalPrecisionLoss {
72 /// Offending column name.
73 column: String,
74 },
75
76 /// JSON payload failed to serialize into the target text form.
77 /// Only observable when a JSON decoder receives a value that
78 /// `serde_json` cannot round-trip through `to_string`.
79 #[error("column {column:?} JSON value did not serialize: {error}")]
80 JsonNotSerializable {
81 /// Offending column name.
82 column: String,
83 /// `serde_json` error message.
84 error: String,
85 },
86
87 /// Payload kind was not what this decoder expected. Emitted when a
88 /// decoder registered for one shape (e.g. JSON string) receives a
89 /// different one (e.g. JSON object).
90 #[error("column {column:?} payload kind mismatch: expected {expected}, got {actual}")]
91 WrongPayloadKind {
92 /// Offending column name.
93 column: String,
94 /// Expected payload kind name.
95 expected: &'static str,
96 /// Actual payload kind name.
97 actual: &'static str,
98 },
99
100 /// Free-form failure emitted by user-supplied decoders.
101 #[error("column {column:?}: {message}")]
102 Custom {
103 /// Offending column name.
104 column: String,
105 /// Failure message from the decoder.
106 message: String,
107 },
108}