use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use rkyv::{Archive, Deserialize, Serialize};
#[repr(C)]
#[derive(Serialize, Deserialize, Archive, PartialEq, Eq)]
#[archive(compare(PartialEq), check_bytes)]
#[archive_attr(derive(PartialEq, Eq, Debug))]
pub struct Status {
pub code: ErrorCode,
pub message: String,
}
impl Status {
pub fn unavailable(msg: impl Display) -> Self {
Self {
code: ErrorCode::ServiceUnavailable,
message: msg.to_string(),
}
}
pub fn internal(msg: impl Display) -> Self {
Self {
code: ErrorCode::InternalError,
message: msg.to_string(),
}
}
pub fn invalid() -> Self {
Self {
code: ErrorCode::InvalidPayload,
message: "Invalid message payload was provided to be deserialized."
.to_string(),
}
}
pub fn connection(msg: impl Display) -> Self {
Self {
code: ErrorCode::ConnectionError,
message: msg.to_string(),
}
}
pub fn timeout() -> Self {
Self {
code: ErrorCode::Timeout,
message: "The operation took to long to be completed.".to_string(),
}
}
}
impl Display for Status {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}: {}", self.code, self.message)
}
}
impl Debug for Status {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Status")
.field("code", &self.code)
.field("message", &self.message)
.finish()
}
}
impl Error for Status {}
#[repr(C)]
#[derive(Serialize, Deserialize, Archive, PartialEq, Eq, Debug)]
#[archive(compare(PartialEq), check_bytes)]
#[archive_attr(derive(Debug, PartialEq, Eq))]
pub enum ErrorCode {
ServiceUnavailable,
InternalError,
InvalidPayload,
ConnectionError,
Timeout,
}
#[cfg(test)]
mod tests {
use super::*;
fn test_status_variant(status: Status) {
println!("Testing: {:?}", &status);
let bytes = rkyv::to_bytes::<_, 1024>(&status).expect("Serialize OK");
let archived =
rkyv::check_archived_root::<'_, Status>(&bytes).expect("Archive OK");
assert_eq!(
archived, &status,
"Archived value and original value should match"
);
let copy: Status = rkyv::from_bytes(&bytes).expect("Deserialize OK");
assert_eq!(
copy, status,
"Deserialized value and original value should match"
);
}
#[test]
fn test_variants() {
test_status_variant(Status::invalid());
test_status_variant(Status::connection("Test connection failed."));
test_status_variant(Status::unavailable("Test unavailable."));
test_status_variant(Status::internal("Test internal error."));
}
}