async_coap/message/
display.rs

1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16use super::*;
17use core::fmt::{Display, Formatter};
18
19/// Provides an implementation of [`core::fmt::Debug`] and [`core::fmt::Display`] for
20/// any type implementing [`MessageRead`].
21#[derive(Debug)]
22pub struct MessageDisplay<'a, T: MessageRead + ?Sized>(pub &'a T);
23
24impl<'a, T: MessageRead + ?Sized> Display for MessageDisplay<'a, T> {
25    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
26        write!(f, "<{:?} {:?}", self.0.msg_type(), self.0.msg_code())?;
27        write!(f, " MID:{:04X}", self.0.msg_id())?;
28
29        let mut content_format: Option<u16> = None;
30
31        let token = self.0.msg_token();
32        if !token.is_empty() {
33            write!(f, " TOK:{}", token)?;
34        }
35
36        for option in self.0.options() {
37            match option {
38                Ok((number, bytes)) => {
39                    if number == OptionNumber::CONTENT_FORMAT {
40                        content_format = try_decode_u16(bytes);
41                    }
42                    f.write_str(" ")?;
43                    number.fmt_with_value(f, bytes)?;
44                }
45                Err(e) => return write!(f, " ERR:{:?}>", e),
46            }
47        }
48
49        let payload = self.0.payload();
50        if !payload.is_empty() {
51            let payload_str_opt = if let Some(i) = content_format {
52                if ContentFormat(i).is_utf8() {
53                    std::str::from_utf8(payload).ok()
54                } else {
55                    None
56                }
57            } else {
58                std::str::from_utf8(payload).ok()
59            };
60
61            if let Some(payload_str) = payload_str_opt {
62                write!(f, " {:?}", payload_str)?;
63            } else {
64                write!(f, " {:?}", payload)?;
65            }
66        }
67
68        write!(f, ">")
69    }
70}
71
72/// Helper struct for formatting a CoAP buffer for display.
73#[derive(Copy, Clone)]
74pub struct CoapByteDisplayFormatter<'buf>(pub &'buf [u8]);
75
76impl<'buf> std::fmt::Display for CoapByteDisplayFormatter<'buf> {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        if let Ok(x) = StandardMessageParser::new(self.0) {
79            MessageDisplay(&x).fmt(f)
80        } else {
81            write!(f, "<CORRUPTED {:02x?}>", self.0)
82        }
83    }
84}
85
86impl<'buf> std::fmt::Debug for CoapByteDisplayFormatter<'buf> {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        if let Ok(x) = StandardMessageParser::new(self.0) {
89            write!(
90                f,
91                "CoapByteDisplayFormatter({}, {:02x?})",
92                MessageDisplay(&x),
93                self.0
94            )
95        } else {
96            write!(f, "<CORRUPTED {:02x?}>", self.0)
97        }
98    }
99}