1use std::io::Read;
9
10#[cfg(feature = "tokio")]
11use paper_utils::stream::AsyncStreamReader;
12use paper_utils::stream::StreamReader;
13use thiserror::Error;
14#[cfg(feature = "tokio")]
15use tokio::io::AsyncRead;
16
17pub type PaperClientResult<T> = Result<T, PaperClientError>;
18
19#[derive(Debug, PartialEq, Error)]
20pub enum PaperClientError {
21 #[error(transparent)]
22 ServerError(#[from] PaperServerError),
23
24 #[error(transparent)]
25 CacheError(#[from] PaperCacheError),
26
27 #[error("invalid PaperCache address")]
28 InvalidAddress,
29
30 #[error("could not connect to PaperServer")]
31 UnreachableServer,
32
33 #[error("could not send command to PaperServer")]
34 InvalidCommand,
35
36 #[error("could not parse supplied value as PaperValue")]
37 InvalidValue,
38
39 #[error("could not receive response from PaperServer")]
40 InvalidResponse,
41
42 #[error("an internal error occurred")]
43 Internal,
44
45 #[error("disconnected from PaperServer")]
46 Disconnected,
47}
48
49#[derive(Debug, PartialEq, Error)]
50pub enum PaperCacheError {
51 #[error("an internal error occurred")]
52 Internal,
53
54 #[error("the key was not found in the cache")]
55 KeyNotFound,
56
57 #[error("the value size cannot be zero")]
58 ZeroValueSize,
59
60 #[error("the value size cannot exceed the cache size")]
61 ExceedingValueSize,
62
63 #[error("the cache size cannot be zero")]
64 ZeroCacheSize,
65
66 #[error("unconfigured policy")]
67 UnconfiguredPolicy,
68
69 #[error("invalid policy")]
70 InvalidPolicy,
71}
72
73#[derive(Debug, PartialEq, Error)]
74pub enum PaperServerError {
75 #[error("an internal error occurred")]
76 Internal,
77
78 #[error("the maximum number of connections was exceeded")]
79 MaxConnectionsExceeded,
80
81 #[error("unauthorized")]
82 Unauthorized,
83}
84
85impl PaperClientError {
86 pub fn from_reader<R>(mut reader: StreamReader<R>) -> Self
87 where
88 R: Read,
89 {
90 let Ok(code) = reader.read_u8() else {
91 return PaperClientError::InvalidResponse;
92 };
93
94 if code == 0 {
95 let Ok(cache_code) = reader.read_u8() else {
96 return PaperClientError::InvalidResponse;
97 };
98
99 let cache_error = PaperCacheError::from_code(cache_code);
100
101 return PaperClientError::CacheError(cache_error);
102 }
103
104 let server_error = PaperServerError::from_code(code);
105 PaperClientError::ServerError(server_error)
106 }
107
108 #[cfg(feature = "tokio")]
109 pub async fn from_reader_async<R>(mut reader: AsyncStreamReader<'_, R>) -> Self
110 where
111 R: AsyncRead + Unpin,
112 {
113 let Ok(code) = reader.read_u8().await else {
114 return PaperClientError::InvalidResponse;
115 };
116
117 if code == 0 {
118 let Ok(cache_code) = reader.read_u8().await else {
119 return PaperClientError::InvalidResponse;
120 };
121
122 let cache_error = PaperCacheError::from_code(cache_code);
123
124 return PaperClientError::CacheError(cache_error);
125 }
126
127 let server_error = PaperServerError::from_code(code);
128 PaperClientError::ServerError(server_error)
129 }
130}
131
132impl PaperServerError {
133 fn from_code(code: u8) -> Self {
134 match code {
135 2 => PaperServerError::MaxConnectionsExceeded,
136 3 => PaperServerError::Unauthorized,
137
138 _ => PaperServerError::Internal,
139 }
140 }
141}
142
143impl PaperCacheError {
144 fn from_code(code: u8) -> Self {
145 match code {
146 1 => PaperCacheError::KeyNotFound,
147
148 2 => PaperCacheError::ZeroValueSize,
149 3 => PaperCacheError::ExceedingValueSize,
150
151 4 => PaperCacheError::ZeroCacheSize,
152
153 5 => PaperCacheError::UnconfiguredPolicy,
154 6 => PaperCacheError::InvalidPolicy,
155
156 _ => PaperCacheError::Internal,
157 }
158 }
159}