vortex_protocol/tlv/
error.rs1use crate::error::{Error as VortexError, Result as VortexResult};
18use bytes::{BufMut, Bytes, BytesMut};
19
20const CODE_SIZE: usize = 1;
22
23#[repr(u8)]
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum Code {
27 Unknown = 0,
29
30 InvalidArgument = 1,
32
33 NotFound = 2,
35
36 Internal = 3,
38
39 Reserved(u8), }
42
43impl TryFrom<u8> for Code {
45 type Error = VortexError;
46
47 fn try_from(value: u8) -> VortexResult<Self> {
49 match value {
50 0 => Ok(Code::Unknown),
51 1 => Ok(Code::InvalidArgument),
52 2 => Ok(Code::NotFound),
53 3 => Ok(Code::Internal),
54 4..=255 => Ok(Code::Reserved(value)),
55 }
56 }
57}
58
59impl From<Code> for u8 {
61 fn from(code: Code) -> u8 {
63 match code {
64 Code::Unknown => 0,
65 Code::InvalidArgument => 1,
66 Code::NotFound => 2,
67 Code::Internal => 3,
68 Code::Reserved(value) => value,
69 }
70 }
71}
72
73#[derive(Debug, Clone)]
85pub struct Error {
86 code: Code,
87 message: String,
88}
89
90impl Error {
92 pub fn new(code: Code, message: String) -> Self {
94 Self { code, message }
95 }
96
97 pub fn code(&self) -> Code {
99 self.code
100 }
101
102 pub fn message(&self) -> &str {
104 &self.message
105 }
106
107 pub fn len(&self) -> usize {
110 self.message.len() + CODE_SIZE
111 }
112
113 pub fn is_empty(&self) -> bool {
115 self.len() == 0
116 }
117}
118
119impl From<Error> for Bytes {
121 fn from(err: Error) -> Self {
123 let mut bytes = BytesMut::with_capacity(err.len());
124 bytes.put_u8(err.code.into());
125 bytes.extend_from_slice(err.message.as_bytes());
126 bytes.freeze()
127 }
128}
129
130impl TryFrom<Bytes> for Error {
132 type Error = VortexError;
133
134 fn try_from(bytes: Bytes) -> VortexResult<Self> {
136 if bytes.len() < CODE_SIZE {
137 return Err(VortexError::InvalidLength(format!(
138 "expected at least {} bytes for Error, got {}",
139 CODE_SIZE,
140 bytes.len()
141 )));
142 }
143
144 Ok(Error {
145 code: Code::try_from(
146 bytes
147 .first()
148 .ok_or(VortexError::InvalidPacket(
149 "insufficient bytes for code".to_string(),
150 ))?
151 .to_owned(),
152 )?,
153 message: String::from_utf8(
154 bytes
155 .get(CODE_SIZE..)
156 .ok_or(VortexError::InvalidPacket(
157 "insufficient bytes for message".to_string(),
158 ))?
159 .to_vec(),
160 )?,
161 })
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168 use bytes::Bytes;
169
170 #[test]
171 fn test_new() {
172 let code = Code::InvalidArgument;
173 let message = "Invalid argument".to_string();
174 let error = Error::new(code, message.clone());
175
176 assert_eq!(error.code(), code);
177 assert_eq!(error.message(), message);
178 assert_eq!(error.len(), message.len() + CODE_SIZE);
179 }
180
181 #[test]
182 fn test_is_non_empty() {
183 let error_non_empty = Error::new(Code::Unknown, "Error message".to_string());
184 assert!(!error_non_empty.is_empty());
185 }
186
187 #[test]
188 fn test_to_bytes_and_from_bytes() {
189 let code = Code::NotFound;
190 let message = "Resource not found".to_string();
191 let error = Error::new(code, message.clone());
192
193 let bytes: Bytes = error.into();
194 let error = Error::try_from(bytes).unwrap();
195
196 assert_eq!(error.code(), code);
197 assert_eq!(error.message(), message);
198 }
199
200 #[test]
201 fn test_from_bytes_invalid_input() {
202 let invalid_bytes = Bytes::from("");
203 assert!(Error::try_from(invalid_bytes).is_err());
204 }
205}