defmt/encoding/
mod.rs

1#[cfg(all(feature = "encoding-raw", feature = "encoding-rzcobs"))]
2compile_error!("Multiple `encoding-*` features are enabled. You may only enable one.");
3
4#[cfg_attr(feature = "encoding-raw", path = "raw.rs")]
5#[cfg_attr(not(feature = "encoding-raw"), path = "rzcobs.rs")]
6mod inner;
7
8// This wrapper struct is to avoid copypasting the public docs in all the impls.
9
10/// Encode raw defmt frames for sending over the wire.
11///
12/// defmt emits "log frames", which are sequences of bytes. The raw log frame data
13/// is then *encoded* prior to sending over the wire.
14///
15/// `Encoder` will encode the frames according to the currently selected
16/// `encoding-*` Cargo feature. See `Cargo.toml` for the supported encodings
17/// and their tradeoffs.
18///
19/// Encodings may perform two functions:
20///
21/// - Framing: Adds extra data to allow the encoder to know when each frame starts
22///   and ends in the stream. Unframed log frames already contain enough information for
23///   the decoder to know when they end, so framing is optional. However, without framing
24///   the decoder must receive all bytes intact or it may "lose sync". With framing, it can
25///   recover from missing/corrupted data, and can start decoding from the "middle" of an
26///   already-running stream.
27/// - Compression: The frame data has rather low entropy (for example, it contains many
28///   zero bytes due to encoding all integers in fixed with, and will likely contain many
29///   repetitions). Compression can decrease the on-the-wire required bandwidth.
30///
31/// defmt provides the `Encoder` separately instead of feeding already-encoded bytes
32/// to the `Logger` because `Logger` implementations may decide to allow
33/// concurrent logging from multiple "contexts" such as threads or interrupt
34/// priority levels. In this case, the Logger implementation needs to create one
35/// Encoder for each such context.
36pub struct Encoder {
37    inner: inner::Encoder,
38}
39
40impl Encoder {
41    /// Create a new `Encoder`.
42    #[allow(clippy::new_without_default)]
43    pub const fn new() -> Self {
44        Self {
45            inner: inner::Encoder::new(),
46        }
47    }
48
49    /// Start encoding a log frame.
50    ///
51    /// `Logger` impls will typically call this from `acquire()`.
52    ///
53    /// You may only call `start_frame` when no frame is currently being encoded.
54    /// Failure to do so may result in corrupted data on the wire.
55    ///
56    /// The `write` closure will be called with the encoded data that must
57    /// be sent on the wire. It may be called zero, one, or multiple times.
58    pub fn start_frame(&mut self, write: impl FnMut(&[u8])) {
59        self.inner.start_frame(write)
60    }
61
62    /// Finish encoding a log frame.
63    ///
64    /// `Logger` impls will typically call this from `release()`.
65    ///
66    /// You may only call `end_frame` when a frame is currently being encoded.
67    /// Failure to do so may result in corrupted data on the wire.
68    ///
69    /// The `write` closure will be called with the encoded data that must
70    /// be sent on the wire. It may be called zero, one, or multiple times.
71    pub fn end_frame(&mut self, write: impl FnMut(&[u8])) {
72        self.inner.end_frame(write)
73    }
74
75    /// Write part of data for a log frame.
76    ///
77    /// `Logger` impls will typically call this from `write()`.
78    ///
79    /// You may only call `write` when a frame is currently being encoded.
80    /// Failure to do so may result in corrupted data on the wire.
81    ///
82    /// The `write` closure will be called with the encoded data that must
83    /// be sent on the wire. It may be called zero, one, or multiple times.
84    pub fn write(&mut self, data: &[u8], write: impl FnMut(&[u8])) {
85        self.inner.write(data, write)
86    }
87}