1use std::{
13 ffi::CStr,
14 fmt::{Display, Formatter},
15};
16
17use num_derive::FromPrimitive;
18use num_traits::FromPrimitive;
19
20use libcoap_sys::{
21 coap_option_num_t, coap_pdu_code_t, coap_pdu_type_t,
22 coap_pdu_type_t::{COAP_MESSAGE_ACK, COAP_MESSAGE_CON, COAP_MESSAGE_NON, COAP_MESSAGE_RST},
23 coap_request_t, coap_response_phrase, COAP_MEDIATYPE_ANY, COAP_MEDIATYPE_APPLICATION_CBOR,
24 COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT, COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0,
25 COAP_MEDIATYPE_APPLICATION_COSE_KEY, COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET, COAP_MEDIATYPE_APPLICATION_COSE_MAC,
26 COAP_MEDIATYPE_APPLICATION_COSE_MAC0, COAP_MEDIATYPE_APPLICATION_COSE_SIGN, COAP_MEDIATYPE_APPLICATION_COSE_SIGN1,
27 COAP_MEDIATYPE_APPLICATION_CWT, COAP_MEDIATYPE_APPLICATION_DOTS_CBOR, COAP_MEDIATYPE_APPLICATION_EXI,
28 COAP_MEDIATYPE_APPLICATION_JSON, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, COAP_MEDIATYPE_APPLICATION_OCTET_STREAM,
29 COAP_MEDIATYPE_APPLICATION_RDF_XML, COAP_MEDIATYPE_APPLICATION_SENML_CBOR, COAP_MEDIATYPE_APPLICATION_SENML_EXI,
30 COAP_MEDIATYPE_APPLICATION_SENML_JSON, COAP_MEDIATYPE_APPLICATION_SENML_XML,
31 COAP_MEDIATYPE_APPLICATION_SENSML_CBOR, COAP_MEDIATYPE_APPLICATION_SENSML_EXI,
32 COAP_MEDIATYPE_APPLICATION_SENSML_JSON, COAP_MEDIATYPE_APPLICATION_SENSML_XML, COAP_MEDIATYPE_APPLICATION_XML,
33 COAP_MEDIATYPE_TEXT_PLAIN, COAP_OPTION_ACCEPT, COAP_OPTION_BLOCK1, COAP_OPTION_BLOCK2, COAP_OPTION_CONTENT_FORMAT,
34 COAP_OPTION_ETAG, COAP_OPTION_HOP_LIMIT, COAP_OPTION_IF_MATCH, COAP_OPTION_IF_NONE_MATCH,
35 COAP_OPTION_LOCATION_PATH, COAP_OPTION_LOCATION_QUERY, COAP_OPTION_MAXAGE, COAP_OPTION_NORESPONSE,
36 COAP_OPTION_OBSERVE, COAP_OPTION_PROXY_SCHEME, COAP_OPTION_PROXY_URI, COAP_OPTION_SIZE1, COAP_OPTION_SIZE2,
37 COAP_OPTION_URI_HOST, COAP_OPTION_URI_PATH, COAP_OPTION_URI_PORT, COAP_OPTION_URI_QUERY,
38};
39
40use crate::error::{MessageCodeError, UnknownOptionError};
41
42pub type ETag = Box<[u8]>;
43pub type MaxAge = u32;
44pub type LocationPath = String;
45pub type LocationQuery = String;
46pub type UriHost = String;
47pub type UriPort = u16;
48pub type UriPath = String;
49pub type UriQuery = String;
50pub type ContentFormat = u16;
51pub type ProxyUri = String;
52pub type ProxyScheme = String;
53pub type Size = u32;
54pub type Block = u32;
55pub type HopLimit = u16;
56pub type NoResponse = u8;
57pub type Observe = u32;
58
59pub type CoapOptionNum = coap_option_num_t;
60pub type CoapToken = Box<[u8]>;
61
62#[derive(Clone, Debug, Eq, PartialEq, Hash)]
65pub enum CoapMatch {
66 ETag(ETag),
67 Empty,
68}
69
70#[repr(u16)]
79#[non_exhaustive]
80#[derive(FromPrimitive, Copy, Clone, Debug, PartialEq, Eq, Hash)]
81pub enum CoapOptionType {
82 IfMatch = COAP_OPTION_IF_MATCH as u16,
84 UriHost = COAP_OPTION_URI_HOST as u16,
86 ETag = COAP_OPTION_ETAG as u16,
88 IfNoneMatch = COAP_OPTION_IF_NONE_MATCH as u16,
90 UriPort = COAP_OPTION_URI_PORT as u16,
92 LocationPath = COAP_OPTION_LOCATION_PATH as u16,
94 UriPath = COAP_OPTION_URI_PATH as u16,
96 ContentFormat = COAP_OPTION_CONTENT_FORMAT as u16,
98 MaxAge = COAP_OPTION_MAXAGE as u16,
100 UriQuery = COAP_OPTION_URI_QUERY as u16,
102 Accept = COAP_OPTION_ACCEPT as u16,
104 LocationQuery = COAP_OPTION_LOCATION_QUERY as u16,
106 ProxyUri = COAP_OPTION_PROXY_URI as u16,
108 ProxyScheme = COAP_OPTION_PROXY_SCHEME as u16,
110 Size1 = COAP_OPTION_SIZE1 as u16,
112 Size2 = COAP_OPTION_SIZE2 as u16,
114 Block1 = COAP_OPTION_BLOCK1 as u16,
116 Block2 = COAP_OPTION_BLOCK2 as u16,
118 HopLimit = COAP_OPTION_HOP_LIMIT as u16,
120 NoResponse = COAP_OPTION_NORESPONSE as u16,
122 Observe = COAP_OPTION_OBSERVE as u16,
124 }
127
128impl CoapOptionType {
129 pub fn to_raw_option_num(self) -> coap_option_num_t {
131 self as u16
132 }
133
134 pub fn max_len(&self) -> usize {
136 match self {
137 CoapOptionType::IfMatch => 8,
138 CoapOptionType::UriHost => 255,
139 CoapOptionType::ETag => 8,
140 CoapOptionType::IfNoneMatch => 0,
141 CoapOptionType::UriPort => 2,
142 CoapOptionType::LocationPath => 255,
143 CoapOptionType::UriPath => 255,
144 CoapOptionType::ContentFormat => 2,
145 CoapOptionType::MaxAge => 4,
146 CoapOptionType::UriQuery => 255,
147 CoapOptionType::Accept => 2,
148 CoapOptionType::LocationQuery => 255,
149 CoapOptionType::ProxyUri => 1034,
150 CoapOptionType::ProxyScheme => 255,
151 CoapOptionType::Size1 => 4,
152 CoapOptionType::Size2 => 4,
153 CoapOptionType::Block1 => 3,
155 CoapOptionType::Block2 => 3,
156 CoapOptionType::HopLimit => 1,
157 CoapOptionType::NoResponse => 1,
158 CoapOptionType::Observe => 3,
159 }
160 }
161
162 pub fn min_len(&self) -> usize {
164 match self {
165 CoapOptionType::IfMatch => 0,
166 CoapOptionType::UriHost => 1,
167 CoapOptionType::ETag => 1,
168 CoapOptionType::IfNoneMatch => 0,
169 CoapOptionType::UriPort => 0,
170 CoapOptionType::LocationPath => 0,
171 CoapOptionType::UriPath => 0,
172 CoapOptionType::ContentFormat => 0,
173 CoapOptionType::MaxAge => 0,
174 CoapOptionType::UriQuery => 0,
175 CoapOptionType::Accept => 0,
176 CoapOptionType::LocationQuery => 0,
177 CoapOptionType::ProxyUri => 1,
178 CoapOptionType::ProxyScheme => 1,
179 CoapOptionType::Size1 => 0,
180 CoapOptionType::Size2 => 0,
181 CoapOptionType::Block1 => 0,
183 CoapOptionType::Block2 => 0,
184 CoapOptionType::HopLimit => 1,
185 CoapOptionType::NoResponse => 0,
186 CoapOptionType::Observe => 0,
187 }
188 }
189}
190
191impl TryFrom<coap_option_num_t> for CoapOptionType {
192 type Error = UnknownOptionError;
193
194 fn try_from(num: coap_option_num_t) -> Result<Self, Self::Error> {
195 <CoapOptionType as FromPrimitive>::from_u16(num).ok_or(UnknownOptionError::Unknown)
196 }
197}
198
199#[repr(u16)]
206#[derive(Copy, Clone, FromPrimitive, Eq, PartialEq, Hash, Debug)]
207#[non_exhaustive]
208pub enum CoapContentFormat {
209 Any = COAP_MEDIATYPE_ANY as u16,
210 Cbor = COAP_MEDIATYPE_APPLICATION_CBOR as u16,
211 DotsCbor = COAP_MEDIATYPE_APPLICATION_DOTS_CBOR as u16,
212 SenMlCbor = COAP_MEDIATYPE_APPLICATION_SENML_CBOR as u16,
213 SenMlExi = COAP_MEDIATYPE_APPLICATION_SENML_EXI as u16,
214 CoseEncrypt = COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT as u16,
215 CoseEncrypt0 = COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0 as u16,
216 CoseKey = COAP_MEDIATYPE_APPLICATION_COSE_KEY as u16,
217 CoseKeySet = COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET as u16,
218 CoseMac = COAP_MEDIATYPE_APPLICATION_COSE_MAC as u16,
219 CoseMac0 = COAP_MEDIATYPE_APPLICATION_COSE_MAC0 as u16,
220 CoseSign = COAP_MEDIATYPE_APPLICATION_COSE_SIGN as u16,
221 CoseSign1 = COAP_MEDIATYPE_APPLICATION_COSE_SIGN1 as u16,
222 Cwt = COAP_MEDIATYPE_APPLICATION_CWT as u16,
223 Exi = COAP_MEDIATYPE_APPLICATION_EXI as u16,
224 Json = COAP_MEDIATYPE_APPLICATION_JSON as u16,
225 LinkFormat = COAP_MEDIATYPE_APPLICATION_LINK_FORMAT as u16,
226 OctetStream = COAP_MEDIATYPE_APPLICATION_OCTET_STREAM as u16,
227 RdfXml = COAP_MEDIATYPE_APPLICATION_RDF_XML as u16,
228 SenMlJson = COAP_MEDIATYPE_APPLICATION_SENML_JSON as u16,
229 SenMlXml = COAP_MEDIATYPE_APPLICATION_SENML_XML as u16,
230 SensMlCbor = COAP_MEDIATYPE_APPLICATION_SENSML_CBOR as u16,
231 SensMlExi = COAP_MEDIATYPE_APPLICATION_SENSML_EXI as u16,
232 SensMlJson = COAP_MEDIATYPE_APPLICATION_SENSML_JSON as u16,
233 SensMlXml = COAP_MEDIATYPE_APPLICATION_SENSML_XML as u16,
234 ApplicationXml = COAP_MEDIATYPE_APPLICATION_XML as u16,
235 TextPlain = COAP_MEDIATYPE_TEXT_PLAIN as u16,
236 Other,
237}
238
239impl From<ContentFormat> for CoapContentFormat {
240 fn from(value: u16) -> Self {
241 <CoapContentFormat as FromPrimitive>::from_u16(value).unwrap_or(CoapContentFormat::Other)
242 }
243}
244
245#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
251#[repr(u8)]
252pub enum CoapMessageCode {
253 Empty,
254 Request(CoapRequestCode),
255 Response(CoapResponseCode),
256}
257
258impl CoapMessageCode {
259 pub fn to_raw_pdu_code(self) -> coap_pdu_code_t {
262 match self {
263 CoapMessageCode::Empty => coap_pdu_code_t::COAP_EMPTY_CODE,
264 CoapMessageCode::Request(req) => req.to_raw_pdu_code(),
265 CoapMessageCode::Response(rsp) => rsp.to_raw_pdu_code(),
266 }
267 }
268}
269
270impl From<CoapRequestCode> for CoapMessageCode {
271 fn from(code: CoapRequestCode) -> Self {
272 CoapMessageCode::Request(code)
273 }
274}
275
276impl From<CoapResponseCode> for CoapMessageCode {
277 fn from(code: CoapResponseCode) -> Self {
278 CoapMessageCode::Response(code)
279 }
280}
281
282impl TryFrom<coap_pdu_code_t> for CoapMessageCode {
283 type Error = MessageCodeError;
284
285 fn try_from(code: coap_pdu_code_t) -> Result<Self, Self::Error> {
286 match code {
287 coap_pdu_code_t::COAP_EMPTY_CODE => Ok(CoapMessageCode::Empty),
288 code => CoapRequestCode::try_from(code)
289 .map(CoapMessageCode::Request)
290 .or_else(|_| CoapResponseCode::try_from(code).map(CoapMessageCode::Response)),
291 }
292 }
293}
294
295#[repr(u8)]
300#[non_exhaustive]
301#[derive(FromPrimitive, Clone, Copy, Eq, PartialEq, Hash, Debug)]
302pub enum CoapRequestCode {
303 Get = coap_pdu_code_t::COAP_REQUEST_CODE_GET as u8,
304 Put = coap_pdu_code_t::COAP_REQUEST_CODE_PUT as u8,
305 Delete = coap_pdu_code_t::COAP_REQUEST_CODE_DELETE as u8,
306 Post = coap_pdu_code_t::COAP_REQUEST_CODE_POST as u8,
307 Fetch = coap_pdu_code_t::COAP_REQUEST_CODE_FETCH as u8,
308 IPatch = coap_pdu_code_t::COAP_REQUEST_CODE_IPATCH as u8,
309 Patch = coap_pdu_code_t::COAP_REQUEST_CODE_PATCH as u8,
310}
311
312impl CoapRequestCode {
313 pub fn to_raw_request(self) -> coap_request_t {
319 match self {
320 CoapRequestCode::Get => coap_request_t::COAP_REQUEST_GET,
321 CoapRequestCode::Put => coap_request_t::COAP_REQUEST_PUT,
322 CoapRequestCode::Delete => coap_request_t::COAP_REQUEST_FETCH,
323 CoapRequestCode::Post => coap_request_t::COAP_REQUEST_POST,
324 CoapRequestCode::Fetch => coap_request_t::COAP_REQUEST_FETCH,
325 CoapRequestCode::IPatch => coap_request_t::COAP_REQUEST_IPATCH,
326 CoapRequestCode::Patch => coap_request_t::COAP_REQUEST_PATCH,
327 }
328 }
329
330 pub fn to_raw_pdu_code(self) -> coap_pdu_code_t {
333 match self {
334 CoapRequestCode::Get => coap_pdu_code_t::COAP_REQUEST_CODE_GET,
335 CoapRequestCode::Put => coap_pdu_code_t::COAP_REQUEST_CODE_PUT,
336 CoapRequestCode::Delete => coap_pdu_code_t::COAP_REQUEST_CODE_FETCH,
337 CoapRequestCode::Post => coap_pdu_code_t::COAP_REQUEST_CODE_POST,
338 CoapRequestCode::Fetch => coap_pdu_code_t::COAP_REQUEST_CODE_FETCH,
339 CoapRequestCode::IPatch => coap_pdu_code_t::COAP_REQUEST_CODE_IPATCH,
340 CoapRequestCode::Patch => coap_pdu_code_t::COAP_REQUEST_CODE_PATCH,
341 }
342 }
343}
344
345impl From<coap_request_t> for CoapRequestCode {
346 fn from(req: coap_request_t) -> Self {
347 match req {
348 coap_request_t::COAP_REQUEST_GET => CoapRequestCode::Get,
349 coap_request_t::COAP_REQUEST_POST => CoapRequestCode::Post,
350 coap_request_t::COAP_REQUEST_PUT => CoapRequestCode::Put,
351 coap_request_t::COAP_REQUEST_DELETE => CoapRequestCode::Delete,
352 coap_request_t::COAP_REQUEST_FETCH => CoapRequestCode::Fetch,
353 coap_request_t::COAP_REQUEST_PATCH => CoapRequestCode::Patch,
354 coap_request_t::COAP_REQUEST_IPATCH => CoapRequestCode::IPatch,
355 _ => panic!("unknown request type"),
356 }
357 }
358}
359
360impl TryFrom<coap_pdu_code_t> for CoapRequestCode {
361 type Error = MessageCodeError;
362
363 fn try_from(req: coap_pdu_code_t) -> Result<Self, Self::Error> {
364 <CoapRequestCode as FromPrimitive>::from_u32(req as u32).ok_or(MessageCodeError::NotARequestCode)
365 }
366}
367
368#[repr(u8)]
373#[non_exhaustive]
374#[derive(Clone, Copy, FromPrimitive, Debug, Eq, PartialEq, Hash)]
375pub enum CoapResponseCode {
376 Content = coap_pdu_code_t::COAP_RESPONSE_CODE_CONTENT as u8,
377 BadGateway = coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_GATEWAY as u8,
378 Continue = coap_pdu_code_t::COAP_RESPONSE_CODE_CONTINUE as u8,
379 Conflict = coap_pdu_code_t::COAP_RESPONSE_CODE_CONFLICT as u8,
380 BadRequest = coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_REQUEST as u8,
381 BadOption = coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_OPTION as u8,
382 Changed = coap_pdu_code_t::COAP_RESPONSE_CODE_CHANGED as u8,
383 Created = coap_pdu_code_t::COAP_RESPONSE_CODE_CREATED as u8,
384 Deleted = coap_pdu_code_t::COAP_RESPONSE_CODE_DELETED as u8,
385 Forbidden = coap_pdu_code_t::COAP_RESPONSE_CODE_FORBIDDEN as u8,
386 GatewayTimeout = coap_pdu_code_t::COAP_RESPONSE_CODE_GATEWAY_TIMEOUT as u8,
387 HopLimitReached = coap_pdu_code_t::COAP_RESPONSE_CODE_HOP_LIMIT_REACHED as u8,
388 Incomplete = coap_pdu_code_t::COAP_RESPONSE_CODE_INCOMPLETE as u8,
389 InternalError = coap_pdu_code_t::COAP_RESPONSE_CODE_INTERNAL_ERROR as u8,
390 NotAcceptable = coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_ACCEPTABLE as u8,
391 NotAllowed = coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_ALLOWED as u8,
392 NotFound = coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_FOUND as u8,
393 NotImplemented = coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_IMPLEMENTED as u8,
394 PreconditionFailed = coap_pdu_code_t::COAP_RESPONSE_CODE_PRECONDITION_FAILED as u8,
395 ProxyingNotSupported = coap_pdu_code_t::COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED as u8,
396 RequestTooLarge = coap_pdu_code_t::COAP_RESPONSE_CODE_REQUEST_TOO_LARGE as u8,
397 ServiceUnavailable = coap_pdu_code_t::COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE as u8,
398 TooManyRequests = coap_pdu_code_t::COAP_RESPONSE_CODE_TOO_MANY_REQUESTS as u8,
399 Unauthorized = coap_pdu_code_t::COAP_RESPONSE_CODE_UNAUTHORIZED as u8,
400 Unprocessable = coap_pdu_code_t::COAP_RESPONSE_CODE_UNPROCESSABLE as u8,
401 UnsupportedContentFormat = coap_pdu_code_t::COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT as u8,
402 Valid = coap_pdu_code_t::COAP_RESPONSE_CODE_VALID as u8,
403}
404
405impl CoapResponseCode {
406 pub fn to_raw_pdu_code(self) -> coap_pdu_code_t {
409 match self {
410 CoapResponseCode::Content => coap_pdu_code_t::COAP_RESPONSE_CODE_CONTENT,
411 CoapResponseCode::BadGateway => coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_GATEWAY,
412 CoapResponseCode::Continue => coap_pdu_code_t::COAP_RESPONSE_CODE_CONTINUE,
413 CoapResponseCode::Conflict => coap_pdu_code_t::COAP_RESPONSE_CODE_CONFLICT,
414 CoapResponseCode::BadRequest => coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_REQUEST,
415 CoapResponseCode::BadOption => coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_OPTION,
416 CoapResponseCode::Changed => coap_pdu_code_t::COAP_RESPONSE_CODE_CHANGED,
417 CoapResponseCode::Created => coap_pdu_code_t::COAP_RESPONSE_CODE_CREATED,
418 CoapResponseCode::Deleted => coap_pdu_code_t::COAP_RESPONSE_CODE_DELETED,
419 CoapResponseCode::Forbidden => coap_pdu_code_t::COAP_RESPONSE_CODE_FORBIDDEN,
420 CoapResponseCode::GatewayTimeout => coap_pdu_code_t::COAP_RESPONSE_CODE_GATEWAY_TIMEOUT,
421 CoapResponseCode::HopLimitReached => coap_pdu_code_t::COAP_RESPONSE_CODE_HOP_LIMIT_REACHED,
422 CoapResponseCode::Incomplete => coap_pdu_code_t::COAP_RESPONSE_CODE_INCOMPLETE,
423 CoapResponseCode::InternalError => coap_pdu_code_t::COAP_RESPONSE_CODE_INTERNAL_ERROR,
424 CoapResponseCode::NotAcceptable => coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_ACCEPTABLE,
425 CoapResponseCode::NotAllowed => coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_ALLOWED,
426 CoapResponseCode::NotFound => coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_FOUND,
427 CoapResponseCode::NotImplemented => coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_IMPLEMENTED,
428 CoapResponseCode::PreconditionFailed => coap_pdu_code_t::COAP_RESPONSE_CODE_PRECONDITION_FAILED,
429 CoapResponseCode::ProxyingNotSupported => coap_pdu_code_t::COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED,
430 CoapResponseCode::RequestTooLarge => coap_pdu_code_t::COAP_RESPONSE_CODE_REQUEST_TOO_LARGE,
431 CoapResponseCode::ServiceUnavailable => coap_pdu_code_t::COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE,
432 CoapResponseCode::TooManyRequests => coap_pdu_code_t::COAP_RESPONSE_CODE_TOO_MANY_REQUESTS,
433 CoapResponseCode::Unauthorized => coap_pdu_code_t::COAP_RESPONSE_CODE_UNAUTHORIZED,
434 CoapResponseCode::Unprocessable => coap_pdu_code_t::COAP_RESPONSE_CODE_UNPROCESSABLE,
435 CoapResponseCode::UnsupportedContentFormat => {
436 coap_pdu_code_t::COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT
437 },
438 CoapResponseCode::Valid => coap_pdu_code_t::COAP_RESPONSE_CODE_VALID,
439 }
440 }
441}
442
443impl Display for CoapResponseCode {
444 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
445 let response_phrase = unsafe {
446 let raw_phrase = coap_response_phrase(*self as u8);
447 if raw_phrase.is_null() {
448 "unknown response code"
449 } else {
450 CStr::from_ptr(raw_phrase)
451 .to_str()
452 .unwrap_or("unable to retrieve phrase for response code")
453 }
454 };
455
456 write!(f, "{}", response_phrase)
457 }
458}
459
460impl TryFrom<coap_pdu_code_t> for CoapResponseCode {
461 type Error = MessageCodeError;
462
463 fn try_from(value: coap_pdu_code_t) -> Result<Self, Self::Error> {
464 <CoapResponseCode as FromPrimitive>::from_u32(value as u32).ok_or(MessageCodeError::NotAResponseCode)
465 }
466}
467
468#[repr(u8)]
471#[derive(Copy, Clone, Hash, Eq, PartialEq, FromPrimitive, Debug)]
472pub enum CoapMessageType {
473 Con = COAP_MESSAGE_CON as u8,
475 Non = COAP_MESSAGE_NON as u8,
477 Ack = COAP_MESSAGE_ACK as u8,
479 Rst = COAP_MESSAGE_RST as u8,
481}
482
483impl CoapMessageType {
484 pub fn to_raw_pdu_type(&self) -> coap_pdu_type_t {
487 match self {
488 CoapMessageType::Con => COAP_MESSAGE_CON,
489 CoapMessageType::Non => COAP_MESSAGE_NON,
490 CoapMessageType::Ack => COAP_MESSAGE_ACK,
491 CoapMessageType::Rst => COAP_MESSAGE_RST,
492 }
493 }
494}
495
496impl From<coap_pdu_type_t> for CoapMessageType {
497 fn from(raw_type: coap_pdu_type_t) -> Self {
498 num_traits::FromPrimitive::from_u32(raw_type as u32).expect("unknown PDU type")
499 }
500}