Skip to main content

reddb_client/
error.rs

1//! Error type for `reddb-client`.
2//!
3//! Mirrors the JSON-RPC error codes used by `red rpc --stdio` so that
4//! client error mapping is consistent across all language drivers.
5//! See `PLAN_DRIVERS.md` § "Spec do protocolo stdio".
6
7use std::fmt;
8
9/// Result alias for the entire crate.
10pub type Result<T> = std::result::Result<T, ClientError>;
11
12/// Stable, machine-readable error code.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ErrorCode {
15    /// Caller passed an unsupported `connect()` URI scheme.
16    UnsupportedScheme,
17    /// URL parser rejected the connection string.
18    InvalidUri,
19    /// File backend reported an I/O failure.
20    IoError,
21    /// Engine query parser rejected the SQL.
22    QueryError,
23    /// Feature requested is gated behind a Cargo feature that wasn't enabled.
24    FeatureDisabled,
25    /// The user called a method on a closed connection.
26    ClientClosed,
27    /// Catch-all for unexpected engine failures.
28    Internal,
29    /// TCP / TLS / DNS layer reported a failure (RedWire client).
30    Network,
31    /// Wire-level decode failure or unexpected message kind.
32    Protocol,
33    /// Server refused the credentials the client supplied.
34    AuthRefused,
35    /// Engine returned an error string in response to a Query frame.
36    Engine,
37    /// HTTP 404 / collection or resource missing.
38    NotFound,
39    /// Server does not advertise support for parameterized transport frames.
40    ParamsUnsupported,
41    /// Helper input failed local validation before contacting the server.
42    InvalidArgument,
43    /// Server-side response did not match the helper contract.
44    InvalidResponse,
45}
46
47impl ErrorCode {
48    pub fn as_str(self) -> &'static str {
49        match self {
50            ErrorCode::UnsupportedScheme => "UNSUPPORTED_SCHEME",
51            ErrorCode::InvalidUri => "INVALID_URI",
52            ErrorCode::IoError => "IO_ERROR",
53            ErrorCode::QueryError => "QUERY_ERROR",
54            ErrorCode::FeatureDisabled => "FEATURE_DISABLED",
55            ErrorCode::ClientClosed => "CLIENT_CLOSED",
56            ErrorCode::Internal => "INTERNAL_ERROR",
57            ErrorCode::Network => "NETWORK_ERROR",
58            ErrorCode::Protocol => "PROTOCOL_ERROR",
59            ErrorCode::AuthRefused => "AUTH_REFUSED",
60            ErrorCode::Engine => "ENGINE_ERROR",
61            ErrorCode::NotFound => "NOT_FOUND",
62            ErrorCode::ParamsUnsupported => "PARAMS_UNSUPPORTED",
63            ErrorCode::InvalidArgument => "INVALID_ARGUMENT",
64            ErrorCode::InvalidResponse => "INVALID_RESPONSE",
65        }
66    }
67}
68
69impl fmt::Display for ErrorCode {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        f.write_str(self.as_str())
72    }
73}
74
75/// Error returned by every fallible call in this crate.
76#[derive(Debug, Clone)]
77pub struct ClientError {
78    pub code: ErrorCode,
79    pub message: String,
80}
81
82impl ClientError {
83    pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
84        Self {
85            code,
86            message: message.into(),
87        }
88    }
89
90    pub fn unsupported_scheme(scheme: impl AsRef<str>) -> Self {
91        Self::new(
92            ErrorCode::UnsupportedScheme,
93            format!(
94                "unsupported URI scheme: '{}'. Expected 'file://', 'memory://' or 'grpc://'.",
95                scheme.as_ref()
96            ),
97        )
98    }
99
100    pub fn feature_disabled(feature: &str) -> Self {
101        Self::new(
102            ErrorCode::FeatureDisabled,
103            format!(
104                "the '{feature}' feature is not enabled. Enable it in Cargo.toml: \
105                 reddb-io-client = {{ version = \"…\", features = [\"{feature}\"] }}"
106            ),
107        )
108    }
109}
110
111impl fmt::Display for ClientError {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        write!(f, "[{}] {}", self.code, self.message)
114    }
115}
116
117impl std::error::Error for ClientError {}