coap_zero/message/
codes.rs

1// Copyright Open Logistics Foundation
2//
3// Licensed under the Open Logistics Foundation License 1.3.
4// For details on the licensing terms, see the LICENSE file.
5// SPDX-License-Identifier: OLFL-1.3
6
7//! Codes (Response and Request) for CoAP Messages
8//!
9//! All codes according to <https://www.rfc-editor.org/rfc/rfc7252> are supported.
10
11use super::Error;
12use bondrewd::Bitfields;
13
14/// Code as it is used in an EncodedMessage
15#[derive(Bitfields, Debug, PartialEq, Eq, Copy, Clone)]
16#[bondrewd(default_endianness = "big", enforce_bytes = 1)]
17pub(crate) struct EncodedCode {
18    #[bondrewd(bit_length = 3)]
19    pub(crate) class: u8,
20    #[bondrewd(bit_length = 5)]
21    pub(crate) detail: u8,
22}
23
24impl From<Code> for EncodedCode {
25    fn from(code: Code) -> EncodedCode {
26        let (class, detail) = match code {
27            Code::Empty => (0, 0),
28            Code::Request(code) => match code {
29                RequestCode::Get => (0, 1),
30                RequestCode::Post => (0, 2),
31                RequestCode::Put => (0, 3),
32                RequestCode::Delete => (0, 4),
33            },
34            Code::Response(code) => match code {
35                ResponseCode::Success(code) => match code {
36                    SuccessCode::Created => (2, 1),
37                    SuccessCode::Deleted => (2, 2),
38                    SuccessCode::Valid => (2, 3),
39                    SuccessCode::Changed => (2, 4),
40                    SuccessCode::Content => (2, 5),
41                },
42                ResponseCode::ClientError(code) => match code {
43                    ClientErrorCode::BadRequest => (4, 0),
44                    ClientErrorCode::Unauthorized => (4, 1),
45                    ClientErrorCode::BadOption => (4, 2),
46                    ClientErrorCode::Forbidden => (4, 3),
47                    ClientErrorCode::NotFound => (4, 4),
48                    ClientErrorCode::MethodNotAllowed => (4, 5),
49                    ClientErrorCode::NotAcceptable => (4, 6),
50                    ClientErrorCode::PreconditionFailed => (4, 12),
51                    ClientErrorCode::RequestEntityTooLarge => (4, 13),
52                    ClientErrorCode::UnsupportedContentFormat => (4, 15),
53                },
54                ResponseCode::ServerError(code) => match code {
55                    ServerErrorCode::InternalServerError => (5, 0),
56                    ServerErrorCode::NotImplemented => (5, 1),
57                    ServerErrorCode::BadGateway => (5, 2),
58                    ServerErrorCode::ServiceUnavailable => (5, 3),
59                    ServerErrorCode::GatewayTimeout => (5, 4),
60                    ServerErrorCode::ProxyingNotSupported => (5, 5),
61                },
62            },
63        };
64
65        EncodedCode { class, detail }
66    }
67}
68
69/// CoAP Message Codes according to <https://www.rfc-editor.org/rfc/rfc7252>
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum Code {
72    /// 0.00
73    Empty,
74    /// Any request code (0.0X)
75    Request(RequestCode),
76    /// Any response code (2.0X, 4.0X, 5.0X)
77    Response(ResponseCode),
78}
79
80/// Method Codes according to <https://www.rfc-editor.org/rfc/rfc7252#section-5.8>
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum RequestCode {
83    /// 0.01
84    Get,
85    /// 0.02
86    Post,
87    /// 0.03
88    Put,
89    /// 0.04
90    Delete,
91}
92
93/// Response Codes according to <https://www.rfc-editor.org/rfc/rfc7252#section-5.9>
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum ResponseCode {
96    /// 2.0X
97    Success(SuccessCode),
98    /// 4.0X
99    ClientError(ClientErrorCode),
100    /// 5.0X
101    ServerError(ServerErrorCode),
102}
103
104/// Success Codes according to <https://www.rfc-editor.org/rfc/rfc7252#section-5.9.1>
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum SuccessCode {
107    /// 2.01
108    Created,
109    /// 2.02
110    Deleted,
111    /// 2.03
112    Valid,
113    /// 2.04
114    Changed,
115    /// 2.05
116    Content,
117}
118
119/// Client Error Codes according to <https://www.rfc-editor.org/rfc/rfc7252#section-5.9.2>
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121pub enum ClientErrorCode {
122    /// 4.00
123    BadRequest,
124    /// 4.01
125    Unauthorized,
126    /// 4.02
127    BadOption,
128    /// 4.03
129    Forbidden,
130    /// 4.04
131    NotFound,
132    /// 4.05
133    MethodNotAllowed,
134    /// 4.06
135    NotAcceptable,
136    /// 4.12
137    PreconditionFailed,
138    /// 4.13
139    RequestEntityTooLarge,
140    /// 4.15
141    UnsupportedContentFormat,
142}
143
144/// Server Error Codes according to <https://www.rfc-editor.org/rfc/rfc7252#section-5.9.3>
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub enum ServerErrorCode {
147    /// 5.00
148    InternalServerError,
149    /// 5.01
150    NotImplemented,
151    /// 5.02
152    BadGateway,
153    /// 5.03
154    ServiceUnavailable,
155    /// 5.04
156    GatewayTimeout,
157    /// 5.05
158    ProxyingNotSupported,
159}
160
161impl From<RequestCode> for Code {
162    fn from(code: RequestCode) -> Code {
163        Code::Request(code)
164    }
165}
166
167impl TryFrom<Code> for RequestCode {
168    type Error = ();
169
170    fn try_from(value: Code) -> Result<Self, Self::Error> {
171        match value {
172            Code::Request(code) => Ok(code),
173            _ => Err(()),
174        }
175    }
176}
177
178impl From<ResponseCode> for Code {
179    fn from(code: ResponseCode) -> Code {
180        Code::Response(code)
181    }
182}
183
184impl TryFrom<Code> for ResponseCode {
185    type Error = ();
186
187    fn try_from(value: Code) -> Result<Self, Self::Error> {
188        match value {
189            Code::Response(code) => Ok(code),
190            _ => Err(()),
191        }
192    }
193}
194
195impl From<SuccessCode> for ResponseCode {
196    fn from(code: SuccessCode) -> ResponseCode {
197        ResponseCode::Success(code)
198    }
199}
200
201impl From<SuccessCode> for Code {
202    fn from(code: SuccessCode) -> Code {
203        ResponseCode::Success(code).into()
204    }
205}
206
207impl TryFrom<Code> for SuccessCode {
208    type Error = ();
209
210    fn try_from(value: Code) -> Result<Self, Self::Error> {
211        match value {
212            Code::Response(ResponseCode::Success(code)) => Ok(code),
213            _ => Err(()),
214        }
215    }
216}
217
218impl From<ClientErrorCode> for ResponseCode {
219    fn from(code: ClientErrorCode) -> ResponseCode {
220        ResponseCode::ClientError(code)
221    }
222}
223
224impl From<ClientErrorCode> for Code {
225    fn from(code: ClientErrorCode) -> Code {
226        ResponseCode::ClientError(code).into()
227    }
228}
229
230impl TryFrom<Code> for ClientErrorCode {
231    type Error = ();
232
233    fn try_from(value: Code) -> Result<Self, Self::Error> {
234        match value {
235            Code::Response(ResponseCode::ClientError(code)) => Ok(code),
236            _ => Err(()),
237        }
238    }
239}
240
241impl From<ServerErrorCode> for ResponseCode {
242    fn from(code: ServerErrorCode) -> ResponseCode {
243        ResponseCode::ServerError(code)
244    }
245}
246
247impl From<ServerErrorCode> for Code {
248    fn from(code: ServerErrorCode) -> Code {
249        ResponseCode::ServerError(code).into()
250    }
251}
252
253impl TryFrom<Code> for ServerErrorCode {
254    type Error = ();
255
256    fn try_from(value: Code) -> Result<Self, Self::Error> {
257        match value {
258            Code::Response(ResponseCode::ServerError(code)) => Ok(code),
259            _ => Err(()),
260        }
261    }
262}
263
264impl TryFrom<EncodedCode> for Code {
265    type Error = Error;
266
267    fn try_from(code: EncodedCode) -> Result<Code, Self::Error> {
268        let code = match (code.class, code.detail) {
269            // Empty
270            (0, 0) => Code::Empty,
271            // Request Codes
272            (0, 1) => RequestCode::Get.into(),
273            (0, 2) => RequestCode::Post.into(),
274            (0, 3) => RequestCode::Put.into(),
275            (0, 4) => RequestCode::Delete.into(),
276            // Success Codes
277            (2, 1) => SuccessCode::Created.into(),
278            (2, 2) => SuccessCode::Deleted.into(),
279            (2, 3) => SuccessCode::Valid.into(),
280            (2, 4) => SuccessCode::Changed.into(),
281            (2, 5) => SuccessCode::Content.into(),
282            // Client Error Codes
283            (4, 0) => ClientErrorCode::BadRequest.into(),
284            (4, 1) => ClientErrorCode::Unauthorized.into(),
285            (4, 2) => ClientErrorCode::BadOption.into(),
286            (4, 3) => ClientErrorCode::Forbidden.into(),
287            (4, 4) => ClientErrorCode::NotFound.into(),
288            (4, 5) => ClientErrorCode::MethodNotAllowed.into(),
289            (4, 6) => ClientErrorCode::NotAcceptable.into(),
290            (4, 12) => ClientErrorCode::PreconditionFailed.into(),
291            (4, 13) => ClientErrorCode::RequestEntityTooLarge.into(),
292            (4, 15) => ClientErrorCode::UnsupportedContentFormat.into(),
293            // Server Error Codes
294            (5, 0) => ServerErrorCode::InternalServerError.into(),
295            (5, 1) => ServerErrorCode::NotImplemented.into(),
296            (5, 2) => ServerErrorCode::BadGateway.into(),
297            (5, 3) => ServerErrorCode::ServiceUnavailable.into(),
298            (5, 4) => ServerErrorCode::GatewayTimeout.into(),
299            (5, 5) => ServerErrorCode::ProxyingNotSupported.into(),
300            // Unknown
301            (_, _) => return Err(Error::InvalidCode),
302        };
303
304        Ok(code)
305    }
306}