mssql_codec/error.rs
1//! Codec error types.
2
3use thiserror::Error;
4
5/// Errors that can occur during packet encoding/decoding.
6#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum CodecError {
9 /// IO error during read/write operations.
10 #[error("IO error: {0}")]
11 Io(#[from] std::io::Error),
12
13 /// Protocol-level error from tds-protocol.
14 #[error("protocol error: {0}")]
15 Protocol(#[from] tds_protocol::ProtocolError),
16
17 /// Packet too large.
18 #[error("packet too large: {size} bytes (max {max})")]
19 PacketTooLarge {
20 /// Actual packet size.
21 size: usize,
22 /// Maximum allowed size.
23 max: usize,
24 },
25
26 /// Assembled response message exceeded the configured size limit.
27 #[error("response message too large: {size} bytes exceeds the {limit}-byte limit")]
28 MessageTooLarge {
29 /// Bytes accumulated when the limit was exceeded.
30 size: usize,
31 /// The configured limit.
32 limit: usize,
33 },
34
35 /// Incomplete packet data.
36 #[error("incomplete packet: need {needed} more bytes")]
37 IncompletePacket {
38 /// Bytes needed to complete the packet.
39 needed: usize,
40 },
41
42 /// Invalid packet header.
43 #[error("invalid packet header")]
44 InvalidHeader,
45
46 /// Connection closed unexpectedly.
47 #[error("connection closed")]
48 ConnectionClosed,
49
50 /// The in-flight request was cancelled via an Attention signal and the
51 /// server acknowledged the cancellation (DONE_ATTN). The connection is
52 /// drained and remains usable for new requests.
53 #[error("request cancelled")]
54 Cancelled,
55
56 /// Encoding error.
57 #[error("encoding error: {0}")]
58 Encoding(String),
59
60 /// Decoding error.
61 #[error("decoding error: {0}")]
62 Decoding(String),
63}
64
65impl CodecError {
66 /// Check if this error is transient and may succeed on retry.
67 ///
68 /// IO errors and connection closures are typically transient.
69 /// Protocol, encoding, and header errors are terminal.
70 #[must_use]
71 pub fn is_transient(&self) -> bool {
72 match self {
73 Self::Io(_) | Self::ConnectionClosed => true,
74 Self::Protocol(e) => e.is_transient(),
75 _ => false,
76 }
77 }
78
79 /// Check if this error is terminal and will never succeed on retry.
80 #[must_use]
81 pub fn is_terminal(&self) -> bool {
82 !self.is_transient()
83 }
84}