use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
#[error("connection")]
Connect(#[from] Connect),
#[error("underlying I/O")]
IO(#[from] std::io::Error),
#[error("protocol")]
Protocol(#[from] Protocol),
#[error("serialization")]
Serialization(#[source] serde_json::Error),
#[cfg(any(feature = "native_tls", feature = "rustls"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "native_tls", feature = "rustls"))))]
#[error("tls stream")]
Stream(#[from] Stream),
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Connect {
#[error("unknown scheme: {scheme}")]
BadScheme {
scheme: String,
},
#[error("no hostname given")]
MissingHostname,
#[error("server requires authentication")]
AuthenticationNeeded,
#[error("server version mismatch (theirs: {theirs}, ours: {ours})")]
VersionMismatch {
ours: usize,
theirs: usize,
},
#[error("parse URL")]
ParseUrl(#[source] url::ParseError),
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Protocol {
#[error("request was malformed: {desc}")]
Malformed {
desc: String,
},
#[cfg(feature = "ent")]
#[cfg_attr(docsrs, doc(cfg(feature = "ent")))]
#[error("server reported unique constraint violation: {msg}")]
UniqueConstraintViolation {
msg: String,
},
#[error("an internal server error occurred: {msg}")]
Internal {
msg: String,
},
#[error("expected {expected}, got unexpected response: {received}")]
BadType {
expected: &'static str,
received: String,
},
#[error("server sent malformed {typed_as} response: {error} in {bytes:?}")]
BadResponse {
typed_as: &'static str,
error: &'static str,
bytes: Vec<u8>,
},
}
impl Protocol {
pub(crate) fn new(line: String) -> Self {
let mut parts = line.splitn(2, ' ');
let code = parts.next();
let error = parts.next();
if error.is_none() {
return Protocol::Internal {
msg: code.unwrap().to_string(),
};
}
let error = error.unwrap().to_string();
match code {
Some("ERR") => Protocol::Internal { msg: error },
Some("MALFORMED") => Protocol::Malformed { desc: error },
#[cfg(feature = "ent")]
Some("NOTUNIQUE") => Protocol::UniqueConstraintViolation { msg: error },
Some(c) => Protocol::Internal {
msg: format!("{} {}", c, error),
},
None => Protocol::Internal {
msg: "empty error response".to_string(),
},
}
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Stream {
#[cfg(feature = "native_tls")]
#[cfg_attr(docsrs, doc(cfg(feature = "native_tls")))]
#[error("underlying tls stream")]
NativeTls(#[source] tokio_native_tls::native_tls::Error),
#[cfg(feature = "rustls")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
#[error("underlying tls stream")]
RustTls(#[source] tokio_rustls::rustls::Error),
}