datacake_rpc/net/
status.rs

1use std::error::Error;
2use std::fmt::{Debug, Display, Formatter};
3
4use rkyv::{Archive, Deserialize, Serialize};
5
6#[repr(C)]
7#[derive(Serialize, Deserialize, Archive, PartialEq, Eq)]
8#[archive(compare(PartialEq), check_bytes)]
9#[archive_attr(derive(PartialEq, Eq, Debug))]
10/// Status information around the cause of a message request failing.
11///
12/// This includes a generic status code and message.
13pub struct Status {
14    /// The generic error code of the request.
15    pub code: ErrorCode,
16    /// The display message for the error.
17    pub message: String,
18}
19
20impl Status {
21    /// The server is running but the specified service does not exist
22    /// or cannot handle messages at this time.
23    pub fn unavailable(msg: impl Display) -> Self {
24        Self {
25            code: ErrorCode::ServiceUnavailable,
26            message: msg.to_string(),
27        }
28    }
29
30    /// An internal error occurred while processing the message.
31    pub fn internal(msg: impl Display) -> Self {
32        Self {
33            code: ErrorCode::InternalError,
34            message: msg.to_string(),
35        }
36    }
37
38    /// The provided message data is invalid or unable to be deserialized
39    /// by the server processing it.
40    pub fn invalid() -> Self {
41        Self {
42            code: ErrorCode::InvalidPayload,
43            message: "Invalid message payload was provided to be deserialized."
44                .to_string(),
45        }
46    }
47
48    /// The connection is closed or interrupted during the operation.
49    pub fn connection(msg: impl Display) -> Self {
50        Self {
51            code: ErrorCode::ConnectionError,
52            message: msg.to_string(),
53        }
54    }
55
56    /// The operation took too long to be completed and was aborted.
57    pub fn timeout() -> Self {
58        Self {
59            code: ErrorCode::Timeout,
60            message: "The operation took to long to be completed.".to_string(),
61        }
62    }
63}
64
65impl Display for Status {
66    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
67        write!(f, "{:?}: {}", self.code, self.message)
68    }
69}
70
71impl Debug for Status {
72    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
73        f.debug_struct("Status")
74            .field("code", &self.code)
75            .field("message", &self.message)
76            .finish()
77    }
78}
79
80impl Error for Status {}
81
82#[repr(C)]
83#[derive(Serialize, Deserialize, Archive, PartialEq, Eq, Debug)]
84#[archive(compare(PartialEq), check_bytes)]
85#[archive_attr(derive(Debug, PartialEq, Eq))]
86/// A generic error code describing the high level reason why the request failed.
87pub enum ErrorCode {
88    /// The server is running but the specified service does not exist
89    /// or cannot handle messages at this time.
90    ServiceUnavailable,
91    /// An internal error occurred while processing the message.
92    InternalError,
93    /// The provided message data is invalid or unable to be deserialized
94    /// by the server processing it.
95    InvalidPayload,
96    /// The connection is closed or interrupted during the operation.
97    ConnectionError,
98    /// The operation took too long to be completed and was aborted.
99    Timeout,
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    fn test_status_variant(status: Status) {
107        println!("Testing: {:?}", &status);
108        let bytes = rkyv::to_bytes::<_, 1024>(&status).expect("Serialize OK");
109        let archived =
110            rkyv::check_archived_root::<'_, Status>(&bytes).expect("Archive OK");
111        assert_eq!(
112            archived, &status,
113            "Archived value and original value should match"
114        );
115        let copy: Status = rkyv::from_bytes(&bytes).expect("Deserialize OK");
116        assert_eq!(
117            copy, status,
118            "Deserialized value and original value should match"
119        );
120    }
121
122    #[test]
123    fn test_variants() {
124        test_status_variant(Status::invalid());
125        test_status_variant(Status::connection("Test connection failed."));
126        test_status_variant(Status::unavailable("Test unavailable."));
127        test_status_variant(Status::internal("Test internal error."));
128    }
129}