use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Error)]
#[repr(u32)]
#[non_exhaustive]
pub enum StatusCode {
#[error("Ok")]
#[default]
Ok = 0,
#[error("Eof")]
Eof = 1,
#[error("NoSuchFile")]
NoSuchFile = 2,
#[error("PermissionDenied")]
PermissionDenied = 3,
#[error("Failure")]
Failure = 4,
#[error("BadMessage")]
BadMessage = 5,
#[error("NoConnection")]
NoConnection = 6,
#[error("ConnectionLost")]
ConnectionLost = 7,
#[error("OpUnsupported")]
OpUnsupported = 8,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Status {
pub code: StatusCode,
pub error: String,
pub language: String,
}
impl StatusCode {
pub fn to_status(self, msg: impl Into<String>) -> Status {
let msg = msg.into();
let msg = if msg.is_empty() {
self.to_string()
} else {
msg
};
Status {
code: self,
error: msg,
language: "en".into(),
}
}
}
impl std::fmt::Display for Status {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.error.is_empty() {
write!(f, "{}", self.code)
} else {
write!(
f,
"{}: {}",
self.code,
String::from_utf8_lossy(self.error.as_ref())
)
}
}
}
impl std::error::Error for Status {}
#[cfg(test)]
mod test {
use crate::{
message::test_utils::{encode_decode, fail_decode},
wire::Error,
};
use super::{Status, StatusCode};
const STATUS_VALID: &[u8] = b"\0\0\0\x01\0\0\0\x03eof\0\0\0\x02en";
#[test]
fn encode_success() {
for (code, encoded) in [
(StatusCode::Ok, b"\0\0\0\x00"),
(StatusCode::Eof, b"\0\0\0\x01"),
(StatusCode::NoSuchFile, b"\0\0\0\x02"),
(StatusCode::PermissionDenied, b"\0\0\0\x03"),
(StatusCode::Failure, b"\0\0\0\x04"),
(StatusCode::BadMessage, b"\0\0\0\x05"),
(StatusCode::NoConnection, b"\0\0\0\x06"),
(StatusCode::ConnectionLost, b"\0\0\0\x07"),
(StatusCode::OpUnsupported, b"\0\0\0\x08"),
] {
encode_decode(code, encoded);
}
encode_decode(
Status {
code: StatusCode::Eof,
error: String::from("eof"),
language: String::from("en"),
},
STATUS_VALID,
);
}
#[test]
fn decode_failure() {
for i in 0..STATUS_VALID.len() {
assert_eq!(
fail_decode::<Status>(&STATUS_VALID[..i]),
Error::NotEnoughData
);
}
}
}