1use alloc::borrow::Cow;
2
3use serde::Serialize;
4
5use crate::device::DeviceInfo;
6
7pub const SERIALIZATION_ERROR: &str = "Serialization-Error";
13
14#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize)]
16#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
17pub enum ResponseKind {
18 #[default]
21 Ok,
22 Serial,
25 Info,
28 #[cfg(feature = "stream")]
30 Stream,
31}
32
33impl core::fmt::Display for ResponseKind {
34 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
35 match self {
36 Self::Ok => "Ok",
37 Self::Serial => "Serial",
38 Self::Info => "Info",
39 #[cfg(feature = "stream")]
40 Self::Stream => "Stream",
41 }
42 .fmt(f)
43 }
44}
45
46#[derive(Debug, PartialEq, Serialize)]
49#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
50pub struct OkResponse {
51 action_terminated_correctly: bool,
52}
53
54impl OkResponse {
55 #[must_use]
57 pub const fn ok() -> Self {
58 Self {
59 action_terminated_correctly: true,
60 }
61 }
62}
63
64#[derive(Debug, PartialEq, Serialize)]
67#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
68pub struct SerialResponse<T: Serialize>(T);
69
70impl<T: Serialize> SerialResponse<T> {
71 #[must_use]
73 pub const fn new(data: T) -> Self {
74 Self(data)
75 }
76}
77
78#[derive(Debug, PartialEq, Serialize)]
81#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
82pub struct InfoResponse(DeviceInfo);
83
84impl InfoResponse {
85 #[must_use]
87 pub const fn new(info: DeviceInfo) -> Self {
88 Self(info)
89 }
90}
91
92#[derive(Debug, PartialEq, Serialize)]
94#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
95pub enum ErrorKind {
96 InvalidData,
98 Internal,
101}
102
103#[derive(Debug, PartialEq, Serialize)]
109#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
110pub struct ErrorResponse<'a> {
111 pub error: ErrorKind,
113 pub description: Cow<'a, str>,
115 pub info: Option<Cow<'a, str>>,
117}
118
119impl<'a> ErrorResponse<'a> {
120 #[must_use]
124 #[inline]
125 pub fn with_description(error: ErrorKind, description: &'a str) -> Self {
126 Self {
127 error,
128 description: Cow::Borrowed(description),
129 info: None,
130 }
131 }
132
133 #[must_use]
138 #[inline]
139 pub fn with_description_error(error: ErrorKind, description: &'a str, info: &'a str) -> Self {
140 Self {
141 error,
142 description: Cow::Borrowed(description),
143 info: Some(Cow::Borrowed(info)),
144 }
145 }
146
147 #[must_use]
151 #[inline]
152 pub fn invalid_data(description: &'a str) -> Self {
153 Self::with_description(ErrorKind::InvalidData, description)
154 }
155
156 #[must_use]
162 #[inline]
163 pub fn invalid_data_with_error(description: &'a str, info: &'a str) -> Self {
164 Self::with_description_error(ErrorKind::InvalidData, description, info)
165 }
166
167 #[must_use]
171 #[inline]
172 pub fn internal(description: &'a str) -> Self {
173 Self::with_description(ErrorKind::Internal, description)
174 }
175
176 #[must_use]
182 #[inline]
183 pub fn internal_with_error(description: &'a str, info: &'a str) -> Self {
184 Self::with_description_error(ErrorKind::Internal, description, info)
185 }
186}
187
188#[cfg(test)]
189#[cfg(feature = "deserialize")]
190mod tests {
191 use serde::Deserialize;
192
193 use crate::{deserialize, serialize};
194
195 use super::{OkResponse, SerialResponse, Serialize};
196
197 use super::{Cow, DeviceInfo, ErrorKind, ErrorResponse, InfoResponse};
198
199 #[test]
200 fn test_ok_response() {
201 assert_eq!(
202 deserialize::<OkResponse>(serialize(OkResponse::ok())),
203 OkResponse {
204 action_terminated_correctly: true,
205 }
206 );
207 }
208
209 #[test]
210 fn test_serial_value_response() {
211 #[derive(Debug, PartialEq, Serialize, Deserialize)]
212 struct SerialValue {
213 value: u32,
214 }
215
216 assert_eq!(
217 deserialize::<SerialValue>(serialize(SerialResponse::new(SerialValue { value: 42 }))),
218 SerialValue { value: 42 },
219 );
220 }
221
222 #[test]
223 fn test_serial_cow_response() {
224 #[derive(Debug, PartialEq, Serialize, Deserialize)]
225 struct SerialCow<'a> {
226 value: Cow<'a, str>,
227 }
228
229 assert_eq!(
230 deserialize::<SerialCow>(serialize(SerialResponse::new(SerialCow {
231 value: Cow::Borrowed("hi")
232 }))),
233 SerialCow {
234 value: Cow::Owned("hi".into())
235 },
236 );
237 }
238
239 #[test]
240 fn test_info_response() {
241 let energy = crate::energy::Energy::init_with_water_use_efficiency(
242 crate::energy::WaterUseEfficiency::init_with_gpp(42.0),
243 );
244
245 assert_eq!(
246 deserialize::<DeviceInfo>(serialize(InfoResponse::new(
247 DeviceInfo::empty().add_energy(energy)
248 ))),
249 DeviceInfo {
250 energy: crate::energy::Energy {
251 energy_efficiencies: None,
252 carbon_footprints: None,
253 water_use_efficiency: Some(crate::energy::WaterUseEfficiency {
254 gpp: Some(42.0),
255 penman_monteith_equation: None,
256 wer: None,
257 }),
258 },
259 economy: crate::economy::Economy::empty(),
260 }
261 );
262 }
263
264 #[test]
265 fn test_error_response() {
266 let error = ErrorResponse::with_description(
267 ErrorKind::InvalidData,
268 "Invalid data error description",
269 );
270
271 assert_eq!(
272 deserialize::<ErrorResponse>(serialize(error)),
273 ErrorResponse {
274 error: ErrorKind::InvalidData,
275 description: Cow::Borrowed("Invalid data error description"),
276 info: None,
277 }
278 );
279 }
280}