1use smol_str::SmolStr;
2use transformable::Transformable;
3
4#[viewit::viewit(
6 vis_all = "pub(crate)",
7 getters(vis_all = "pub"),
8 setters(vis_all = "pub", prefix = "with")
9)]
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
12#[cfg_attr(feature = "serde", serde(transparent))]
13#[cfg_attr(
14 feature = "rkyv",
15 derive(::rkyv::Serialize, ::rkyv::Deserialize, ::rkyv::Archive)
16)]
17#[cfg_attr(
18 feature = "rkyv",
19 rkyv(derive(Debug, PartialEq, Eq, Hash), compare(PartialEq))
20)]
21#[repr(transparent)]
22pub struct ErrorResponse {
23 #[viewit(
24 getter(
25 const,
26 style = "ref",
27 attrs(doc = "Returns the msg of the error response")
28 ),
29 setter(attrs(doc = "Sets the msg of the error response (Builder pattern)"))
30 )]
31 message: SmolStr,
32}
33
34impl ErrorResponse {
35 pub fn new(message: impl Into<SmolStr>) -> Self {
37 Self {
38 message: message.into(),
39 }
40 }
41
42 pub fn set_message(&mut self, msg: impl Into<SmolStr>) -> &mut Self {
44 self.message = msg.into();
45 self
46 }
47}
48
49impl core::fmt::Display for ErrorResponse {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 write!(f, "{}", self.message)
52 }
53}
54
55impl std::error::Error for ErrorResponse {}
56
57impl From<ErrorResponse> for SmolStr {
58 fn from(err: ErrorResponse) -> Self {
59 err.message
60 }
61}
62
63impl From<SmolStr> for ErrorResponse {
64 fn from(msg: SmolStr) -> Self {
65 Self { message: msg }
66 }
67}
68
69impl Transformable for ErrorResponse {
70 type Error = <SmolStr as Transformable>::Error;
71
72 fn encode(&self, dst: &mut [u8]) -> Result<usize, Self::Error> {
73 self.message.encode(dst)
74 }
75
76 fn encoded_len(&self) -> usize {
77 self.message.encoded_len()
78 }
79
80 fn decode(src: &[u8]) -> Result<(usize, Self), Self::Error>
81 where
82 Self: Sized,
83 {
84 let (len, message) = SmolStr::decode(src)?;
85 Ok((len, Self { message }))
86 }
87
88 async fn encode_to_async_writer<W: futures::io::AsyncWrite + Send + Unpin>(
89 &self,
90 writer: &mut W,
91 ) -> std::io::Result<usize> {
92 <SmolStr as Transformable>::encode_to_async_writer(&self.message, writer).await
93 }
94
95 fn encode_to_writer<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<usize> {
96 <SmolStr as Transformable>::encode_to_writer(&self.message, writer)
97 }
98
99 fn decode_from_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<(usize, Self)>
100 where
101 Self: Sized,
102 {
103 <SmolStr as Transformable>::decode_from_reader(reader).map(|(n, message)| (n, Self { message }))
104 }
105
106 async fn decode_from_async_reader<R: futures::io::AsyncRead + Send + Unpin>(
107 reader: &mut R,
108 ) -> std::io::Result<(usize, Self)>
109 where
110 Self: Sized,
111 {
112 <SmolStr as Transformable>::decode_from_async_reader(reader)
113 .await
114 .map(|(n, message)| (n, Self { message }))
115 }
116}
117
118#[cfg(test)]
119const _: () = {
120 use rand::{distr::Alphanumeric, Rng};
121
122 impl ErrorResponse {
123 fn generate(size: usize) -> Self {
124 let rng = rand::rng();
125 let err = rng
126 .sample_iter(&Alphanumeric)
127 .take(size)
128 .collect::<Vec<u8>>();
129 let err = String::from_utf8(err).unwrap();
130 Self::new(err)
131 }
132 }
133};
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_error_response() {
141 for i in 0..100 {
142 let err = ErrorResponse::generate(i);
143 let mut buf = vec![0; err.encoded_len()];
144 let encoded_len = err.encode(&mut buf).unwrap();
145 assert_eq!(encoded_len, err.encoded_len());
146 let (decoded_len, decoded) = ErrorResponse::decode(&buf).unwrap();
147 assert_eq!(decoded_len, encoded_len);
148 assert_eq!(decoded, err);
149 }
150 }
151}