defmt-0.3.5/.cargo_vcs_info.json0000644000000001430000000000100121360ustar { "git": { "sha1": "e1413dafb86f3bbe7377d44bee52f97abaaedcfd" }, "path_in_vcs": "defmt" }defmt-0.3.5/Cargo.toml0000644000000027670000000000100101520ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "defmt" version = "0.3.5" authors = ["The Knurling-rs developers"] links = "defmt" description = "A highly efficient logging framework that targets resource-constrained devices, like microcontrollers" homepage = "https://knurling.ferrous-systems.com/" readme = "README.md" keywords = [ "knurling", "logging", "logger", "formatting", "formatter", ] categories = [ "embedded", "no-std", "development-tools::debugging", "value-formatting", ] license = "MIT OR Apache-2.0" repository = "https://github.com/knurling-rs/defmt" resolver = "1" [package.metadata.docs.rs] features = ["alloc"] rustdoc-args = ["--cfg=docsrs"] targets = [ "thumbv6m-none-eabi", "thumbv7em-none-eabihf", ] [dependencies.bitflags] version = "1" [dependencies.defmt-macros] version = "0.3.2" [dev-dependencies.rustc_version] version = "0.4" [dev-dependencies.trybuild] version = "1" [features] alloc = [] encoding-raw = [] encoding-rzcobs = [] ip_in_core = [] unstable-test = ["defmt-macros/unstable-test"] defmt-0.3.5/Cargo.toml.orig000064400000000000000000000040731046102023000136230ustar 00000000000000[package] authors = [ "The Knurling-rs developers" ] categories = [ "embedded", "no-std", "development-tools::debugging", "value-formatting", ] description = "A highly efficient logging framework that targets resource-constrained devices, like microcontrollers" edition = "2021" keywords = [ "knurling", "logging", "logger", "formatting", "formatter" ] license = "MIT OR Apache-2.0" links = "defmt" # Prevent multiple versions of defmt being linked name = "defmt" readme = "../README.md" repository = "https://github.com/knurling-rs/defmt" homepage = "https://knurling.ferrous-systems.com/" version = "0.3.5" [features] alloc = [] ip_in_core = [] # Encoding feature flags. These should only be set by end-user crates, not by library crates. # # If no encoding is selected, `defmt` will assume the encoding is "don't care" and # will pick a default one. The current default is `encoding-rzcobs`. The default may change # in minor releases, changing it is not considered a breaking change since all encodings # are guaranteed to be supported by the corresponding `defmt-decoder` version. # Raw encoding: All log frames are concatenated and sent over the wire with no framing or compression. # This is the fastest CPU-wise, but may end up being slower if the limiting factor is wire speed. encoding-raw = [] # rzCOBS encoding: Performs framing on the log frames using reverse-COBS, additionally applying a # light compression for data known to contain many zero bytes, like defmt streams. # The framing allows the decoder to recover from missing or corrupted data, and start decoding # in the middle of a stream, for example when attaching to an already-running device. encoding-rzcobs = [] # WARNING: for internal use only, not covered by semver guarantees unstable-test = [ "defmt-macros/unstable-test" ] [dependencies] defmt-macros = { path = "../macros", version = "0.3.2" } bitflags = "1" [dev-dependencies] rustc_version = "0.4" trybuild = "1" [package.metadata.docs.rs] features = [ "alloc" ] rustdoc-args = [ "--cfg=docsrs" ] targets = [ "thumbv6m-none-eabi", "thumbv7em-none-eabihf" ] defmt-0.3.5/README.md000064400000000000000000000047471046102023000122230ustar 00000000000000# `defmt` `defmt` ("de format", short for "deferred formatting") is a highly efficient logging framework that targets resource-constrained devices, like microcontrollers. For more details about the framework check the book at . The git version of the defmt book can be viewed at . ## Setup ### New project The fastest way to get started with `defmt` is to use our [app-template] to set up a new Cortex-M embedded project. [app-template]: https://github.com/knurling-rs/app-template ### Existing project To include `defmt` in your existing project, follow our [Application Setup guide]. [Application Setup guide]: https://defmt.ferrous-systems.com/setup.html ## MSRV `defmt` always compiles on the [latest `stable` rust release](https://github.com/rust-lang/rust/releases/latest). This is enforced by our CI building and testing against this version. It still might work on older rust versions, but this isn't ensured. ## defmt ecosystem The following diagram illustrates the user-facing and internal crates of the defmt framework. ![defmt crates structure](assets/defmt.png) ## Developer Information ### Running Tests Tests are run using `cargo xtask` -- although this is simply an alias (defined in `.cargo/config.toml`) for `cargo run --package xtask --`. To see a list of options, see [`xtask/src/main.rs`](xtask/src/main.rs), or run: ```console $ cargo xtask help ``` For example, to run all the tests, run: ```console $ cargo xtask test-all ``` You will need `qemu-system-arm` installed and in your `$PATH` for some of the tests (e.g. `test-snapshot`). ## Support `defmt` is part of the [Knurling] project, [Ferrous Systems]' effort at improving tooling used to develop for embedded systems. If you think that our work is useful, consider sponsoring it via [GitHub Sponsors]. ## License Licensed under either of - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions. [Knurling]: https://knurling.ferrous-systems.com/ [Ferrous Systems]: https://ferrous-systems.com/ [GitHub Sponsors]: https://github.com/sponsors/knurling-rs defmt-0.3.5/build.rs000064400000000000000000000014641046102023000124020ustar 00000000000000use std::{env, error::Error, fs, path::PathBuf}; fn main() -> Result<(), Box> { // Put the linker script somewhere the linker can find it let out = &PathBuf::from(env::var("OUT_DIR")?); let linker_script = fs::read_to_string("defmt.x.in")?; fs::write(out.join("defmt.x"), linker_script)?; println!("cargo:rustc-link-search={}", out.display()); let target = env::var("TARGET")?; // `"atomic-cas": false` in `--print target-spec-json` // last updated: rust 1.48.0 match &target[..] { "avr-gnu-base" | "msp430-none-elf" | "riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" | "thumbv4t-none-eabi" | "thumbv6m-none-eabi" => { println!("cargo:rustc-cfg=no_cas"); } _ => {} } Ok(()) } defmt-0.3.5/defmt.x.in000064400000000000000000000017211046102023000126260ustar 00000000000000/* exhaustively search for these symbols */ EXTERN(_defmt_acquire); EXTERN(_defmt_release); EXTERN(__defmt_default_timestamp); EXTERN(__DEFMT_MARKER_TIMESTAMP_WAS_DEFINED); PROVIDE(_defmt_timestamp = __defmt_default_timestamp); PROVIDE(_defmt_panic = __defmt_default_panic); SECTIONS { /* `1` specifies the start address of this virtual (`(INFO)`) section */ /* Tag number 0 is reserved for special uses, like as a format sequence terminator. */ .defmt 1 (INFO) : { /* For some reason the `1` above has no effect, but this does */ . = 1; /* Format implementations for primitives like u8 */ *(.defmt.prim.*); /* Everything user-defined */ *(.defmt.*); __DEFMT_MARKER_END = .; /* Symbols that aren't referenced by the program and */ /* should be placed at the end of the section */ KEEP(*(.defmt.end .defmt.end.*)); } } ASSERT(__DEFMT_MARKER_END < 65534, ".defmt section cannot contain more than 65534 interned strings"); defmt-0.3.5/src/encoding/mod.rs000064400000000000000000000071271046102023000144410ustar 00000000000000#[cfg(all(feature = "encoding-raw", feature = "encoding-rzcobs"))] compile_error!("Multiple `encoding-*` features are enabled. You may only enable one."); #[cfg_attr(feature = "encoding-raw", path = "raw.rs")] #[cfg_attr(not(feature = "encoding-raw"), path = "rzcobs.rs")] mod inner; // This wrapper struct is to avoid copypasting the public docs in all the impls. /// Encode raw defmt frames for sending over the wire. /// /// defmt emits "log frames", which are sequences of bytes. The raw log frame data /// is then *encoded* prior to sending over the wire. /// /// `Encoder` will encode the frames according to the currently selected /// `encoding-*` Cargo feature. See `Cargo.toml` for the supported encodings /// and their tradeoffs. /// /// Encodings may perform two functions: /// /// - Framing: Adds extra data to allow the encoder to know when each frame starts /// and ends in the stream. Unframed log frames already contain enough information for /// the decoder to know when they end, so framing is optional. However, without framing /// the decoder must receive all bytes intact or it may "lose sync". With framing, it can /// recover from missing/corrupted data, and can start decoding from the "middle" of an /// already-running stream. /// - Compression: The frame data has rather low entropy (for example, it contains many /// zero bytes due to encoding all integers in fixed with, and will likely contain many /// repetitions). Compression can decrease the on-the-wire required bandwidth. /// /// defmt provides the `Encoder` separately instead of feeding already-encoded bytes /// to the `Logger` because `Logger` implementations may decide to allow /// concurrent logging from multiple "contexts" such as threads or interrupt /// priority levels. In this case, the Logger implementation needs to create one /// Encoder for each such context. pub struct Encoder { inner: inner::Encoder, } impl Encoder { /// Create a new `Encoder`. pub const fn new() -> Self { Self { inner: inner::Encoder::new(), } } /// Start encoding a log frame. /// /// `Logger` impls will typically call this from `acquire()`. /// /// You may only call `start_frame` when no frame is currently being encoded. /// Failure to do so may result in corrupted data on the wire. /// /// The `write` closure will be called with the encoded data that must /// be sent on the wire. It may be called zero, one, or multiple times. pub fn start_frame(&mut self, write: impl FnMut(&[u8])) { self.inner.start_frame(write) } /// Finish encoding a log frame. /// /// `Logger` impls will typically call this from `release()`. /// /// You may only call `end_frame` when a frame is currently being encoded. /// Failure to do so may result in corrupted data on the wire. /// /// The `write` closure will be called with the encoded data that must /// be sent on the wire. It may be called zero, one, or multiple times. pub fn end_frame(&mut self, write: impl FnMut(&[u8])) { self.inner.end_frame(write) } /// Write part of data for a log frame. /// /// `Logger` impls will typically call this from `write()`. /// /// You may only call `write` when a frame is currently being encoded. /// Failure to do so may result in corrupted data on the wire. /// /// The `write` closure will be called with the encoded data that must /// be sent on the wire. It may be called zero, one, or multiple times. pub fn write(&mut self, data: &[u8], write: impl FnMut(&[u8])) { self.inner.write(data, write) } } defmt-0.3.5/src/encoding/raw.rs000064400000000000000000000006071046102023000144470ustar 00000000000000pub(crate) struct Encoder { _private: (), } impl Encoder { pub(crate) const fn new() -> Self { Self { _private: () } } pub(crate) fn start_frame(&mut self, _write: impl FnMut(&[u8])) {} pub(crate) fn end_frame(&mut self, _write: impl FnMut(&[u8])) {} pub(crate) fn write(&mut self, data: &[u8], mut write: impl FnMut(&[u8])) { write(data) } } defmt-0.3.5/src/encoding/rzcobs.rs000064400000000000000000000321601046102023000151570ustar 00000000000000// Standard COBS/rCOBS: // 00000000 => end of frame // nnnnnnnn => output n-1 bytes from stream, output 0x00 // 11111111 => output 254 bytes from stream // // zCOBS/rzCOBS: // 00000000 => end of frame // 0xxxxxxx => foreach x from LSB to MSB: if x=0 output 1 byte from stream, if x=1 output 0x00 // 1nnnnnnn => output n+7 bytes from stream, output 0x00 // 11111111 => output 134 bytes from stream pub(crate) struct Encoder { run: u8, zeros: u8, started: bool, } impl Encoder { pub const fn new() -> Self { Self { run: 0, zeros: 0, started: false, } } pub fn start_frame(&mut self, mut write: impl FnMut(&[u8])) { let mut write_byte = move |b: u8| write(&[b]); if !self.started { self.started = true; // Write a frame-separator at the very beginning. This allows the // decoder to correctly decode the first frame if a previous boot had left a // partly-written frame. write_byte(0x00); } } pub fn end_frame(&mut self, mut write: impl FnMut(&[u8])) { let mut write_byte = move |b: u8| write(&[b]); // Finish writing the previous symbol if needed. match self.run { 0 => {} 1..=6 => write_byte((self.zeros | (0xFF << self.run)) & 0x7F), _ => write_byte((self.run - 7) | 0x80), } // Write frame-separator. write_byte(0x00); self.run = 0; self.zeros = 0; } pub fn write(&mut self, data: &[u8], mut write: impl FnMut(&[u8])) { let mut write_byte = move |b: u8| write(&[b]); for &byte in data { if self.run < 7 { if byte == 0 { self.zeros |= 1 << self.run; } else { write_byte(byte); } self.run += 1; if self.run == 7 && self.zeros != 0x00 { write_byte(self.zeros); self.run = 0; self.zeros = 0; } } else if byte == 0 { write_byte((self.run - 7) | 0x80); self.run = 0; self.zeros = 0; } else { write_byte(byte); self.run += 1; if self.run == 134 { write_byte(0xFF); self.run = 0; self.zeros = 0; } } } } } #[cfg(feature = "unstable-test")] #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { let tests: &[(&[u8], &[u8])] = &[ (&[], &[0x00]), (&[0x00], &[0x7f, 0x00]), (&[0x00, 0x00], &[0x7f, 0x00]), (&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], &[0x7f, 0x00]), ( &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], &[0x7f, 0x7f, 0x00], ), (&[0x01], &[0x01, 0x7e, 0x00]), (&[0x01, 0x00], &[0x01, 0x7e, 0x00]), (&[0x00, 0x01], &[0x01, 0x7d, 0x00]), (&[0x01, 0x02], &[0x01, 0x02, 0x7c, 0x00]), ( &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00], &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x40, 0x00], ), ( &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77], &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x80, 0x00], ), ( &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00], &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x80, 0x00], ), ( &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88], &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x81, 0x00], ), ( &[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, ], &[0x7f, 0xff, 0x3f, 0x00], ), ( &[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, ], &[0x44, 0x5f, 0xff, 0x3f, 0x00], ), ( &[ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ], &[ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0xfe, 0x00, ], ), ( &[ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x00, ], &[ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0xfe, 0x00, ], ), ( &[ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, ], &[ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xff, 0x00, ], ), ( &[ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x00, ], &[ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xff, 0x7f, 0x00, ], ), ]; for (dec, enc) in tests { let mut res: Vec = Vec::new(); let mut e = Encoder::new(); e.started = true; // simulate that this is not the first frame. e.start_frame(|data| res.extend(data)); e.write(dec, |data| res.extend(data)); e.end_frame(|data| res.extend(data)); assert_eq!(enc, &res); } } } defmt-0.3.5/src/export/integers.rs000064400000000000000000000007031046102023000152260ustar 00000000000000use super::*; macro_rules! write_to_le_bytes { ($($s:ident),*) => { $(/// Implementation detail pub fn $s(b: &$s) { write(&b.to_le_bytes()) })* }; } write_to_le_bytes!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128); /// Implementation detail pub fn usize(b: &usize) { write(&(*b as u32).to_le_bytes()) } /// Implementation detail pub fn isize(b: &isize) { write(&(*b as i32).to_le_bytes()) } defmt-0.3.5/src/export/mod.rs000064400000000000000000000114731046102023000141730ustar 00000000000000mod integers; mod traits; use core::fmt::Write as _; use crate::{Format, Formatter, Str}; pub use self::integers::*; pub use bitflags::bitflags; pub trait UnsignedInt {} impl UnsignedInt for u8 {} impl UnsignedInt for u16 {} impl UnsignedInt for u32 {} impl UnsignedInt for u64 {} impl UnsignedInt for u128 {} #[cfg(feature = "unstable-test")] thread_local! { static I: core::sync::atomic::AtomicU16 = core::sync::atomic::AtomicU16::new(0); static BYTES: core::cell::RefCell> = core::cell::RefCell::new(Vec::new()); } /// For testing purposes #[cfg(feature = "unstable-test")] pub fn fetch_string_index() -> u16 { I.with(|i| i.load(core::sync::atomic::Ordering::Relaxed)) } /// For testing purposes #[cfg(feature = "unstable-test")] pub fn fetch_add_string_index() -> u16 { I.with(|i| i.fetch_add(1, core::sync::atomic::Ordering::Relaxed)) } /// Get and clear the logged bytes #[cfg(feature = "unstable-test")] pub fn fetch_bytes() -> Vec { BYTES.with(|b| core::mem::take(&mut *b.borrow_mut())) } /// Only to be used by the defmt macros /// Safety: must be paired with a later call to release() #[cfg(feature = "unstable-test")] pub unsafe fn acquire() {} /// Only to be used by the defmt macros /// Safety: must be paired with a later call to release() #[cfg(not(feature = "unstable-test"))] #[inline(always)] pub unsafe fn acquire() { extern "Rust" { fn _defmt_acquire(); } _defmt_acquire() } /// Only to be used by the defmt macros /// Safety: must follow an earlier call to acquire() #[cfg(feature = "unstable-test")] pub unsafe fn release() {} /// Only to be used by the defmt macros /// Safety: must follow an earlier call to acquire() #[cfg(not(feature = "unstable-test"))] #[inline(always)] pub unsafe fn release() { extern "Rust" { fn _defmt_release(); } _defmt_release() } #[cfg(feature = "unstable-test")] pub fn write(bytes: &[u8]) { BYTES.with(|b| b.borrow_mut().extend(bytes)) } #[cfg(not(feature = "unstable-test"))] #[inline(always)] pub fn write(bytes: &[u8]) { extern "Rust" { fn _defmt_write(bytes: &[u8]); } unsafe { _defmt_write(bytes) } } /// For testing purposes #[cfg(feature = "unstable-test")] pub fn timestamp(_fmt: crate::Formatter<'_>) {} #[cfg(not(feature = "unstable-test"))] #[inline(always)] pub fn timestamp(fmt: crate::Formatter<'_>) { extern "Rust" { fn _defmt_timestamp(_: crate::Formatter<'_>); } unsafe { _defmt_timestamp(fmt) } } /// Returns the interned string at `address`. pub fn make_istr(address: u16) -> Str { Str { address } } /// Create a Formatter. pub fn make_formatter<'a>() -> Formatter<'a> { Formatter { _phantom: core::marker::PhantomData, } } pub fn truncate(x: impl traits::Truncate) -> T { x.truncate() } pub fn into_result(x: T) -> Result { x.into_result() } /// For testing purposes #[cfg(feature = "unstable-test")] pub fn panic() -> ! { panic!() } #[cfg(not(feature = "unstable-test"))] #[inline(always)] pub fn panic() -> ! { extern "Rust" { fn _defmt_panic() -> !; } unsafe { _defmt_panic() } } /// Implementation detail pub fn fmt(f: &T) { istr(&T::_format_tag()); f._format_data(); } /// Implementation detail pub fn fmt_slice(values: &[T]) { usize(&values.len()); istr(&T::_format_tag()); for value in values { value._format_data(); } } /// Implementation detail pub fn f32(b: &f32) { write(&f32::to_bits(*b).to_le_bytes()) } /// Implementation detail pub fn f64(b: &f64) { write(&f64::to_bits(*b).to_le_bytes()) } /// Implementation detail pub fn char(b: &char) { write(&(*b as u32).to_le_bytes()) } pub fn str(s: &str) { usize(&s.len()); write(s.as_bytes()); } pub fn slice(s: &[u8]) { usize(&s.len()); write(s); } // NOTE: This is passed `&[u8; N]` – it's just coerced to a slice. pub fn u8_array(a: &[u8]) { write(a); } // NOTE: This is passed `&[u8; N]` – it's just coerced to a slice. pub fn fmt_array(a: &[T]) { istr(&T::_format_tag()); for value in a { value._format_data(); } } /// Implementation detail pub fn istr(s: &Str) { write(&s.address.to_le_bytes()) } /// Implementation detail pub fn bool(b: &bool) { u8(&(*b as u8)); } /// Implementation detail pub fn debug(val: &dyn core::fmt::Debug) { core::write!(FmtWrite, "{val:?}").ok(); write(&[0xff]); } /// Implementation detail pub fn display(val: &dyn core::fmt::Display) { core::write!(FmtWrite, "{val}").ok(); write(&[0xff]); } #[inline(never)] pub fn header(s: &Str) { istr(s); timestamp(make_formatter()); } struct FmtWrite; impl core::fmt::Write for FmtWrite { fn write_str(&mut self, s: &str) -> core::fmt::Result { write(s.as_bytes()); Ok(()) } } defmt-0.3.5/src/export/traits.rs000064400000000000000000000030511046102023000147130ustar 00000000000000#[allow(unused_imports)] use crate as defmt; use crate::{Format, Formatter, Str}; pub trait Truncate { fn truncate(self) -> U; } macro_rules! impl_truncate { ($($from:ty => $into:ty),*) => { $(impl Truncate<$into> for $from { fn truncate(self) -> $into { self as $into } })* }; } // We implement `Truncate for X` so that the macro can unconditionally use it, // even if no truncation is performed. impl_truncate!( u8 => u8, u16 => u8, u32 => u8, u64 => u8, u128 => u8, u16 => u16, u32 => u16, u64 => u16, u128 => u16, u32 => u32, u64 => u32, u128 => u32, u64 => u64, u128 => u64, u128 => u128 ); #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct NoneError; impl Format for NoneError { fn format(&self, _fmt: Formatter) { unreachable!(); } fn _format_tag() -> Str { defmt_macros::internp!("Unwrap of a None option value") } fn _format_data(&self) {} } /// Transform `self` into a `Result` /// /// # Call sites /// * [`defmt::unwrap!`] pub trait IntoResult { type Ok; type Error; fn into_result(self) -> Result; } impl IntoResult for Option { type Ok = T; type Error = NoneError; #[inline] fn into_result(self) -> Result { self.ok_or(NoneError) } } impl IntoResult for Result { type Ok = T; type Error = E; #[inline] fn into_result(self) -> Self { self } } defmt-0.3.5/src/formatter.rs000064400000000000000000000005261046102023000140730ustar 00000000000000use core::marker::PhantomData; /// Handle to a defmt logger. #[derive(Copy, Clone)] pub struct Formatter<'a> { pub(crate) _phantom: PhantomData<&'a ()>, } /// An interned string created via [`intern!`]. /// /// [`intern!`]: macro.intern.html #[derive(Clone, Copy)] pub struct Str { /// 16-bit address pub(crate) address: u16, } defmt-0.3.5/src/impls/adapter.rs000064400000000000000000000045361046102023000146410ustar 00000000000000use core::fmt; use crate as defmt; use crate::{export, Format, Formatter, Str}; /// An "adapter" type to feed `Debug` values into defmt macros, which expect `defmt::Format` values. /// /// This adapter disables compression and uses the `core::fmt` code on-device! You should prefer /// `defmt::Format` over `Debug` whenever possible. /// /// # Examples /// /// ```rust /// # #[derive(Debug)] /// # struct ExpensiveThing(); /// # let expensive_thing = ExpensiveThing(); /// # /// defmt::info!("{:?}", defmt::Debug2Format(&expensive_thing)); /// // ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ /// // must `#[derive(Debug)]` /// ``` /// /// Note that any provided defmt display hints will be ignored /// because this always uses `{:?}` to format the contained value. pub struct Debug2Format<'a, T: fmt::Debug + ?Sized>(pub &'a T); impl Format for Debug2Format<'_, T> { default_format!(); fn _format_tag() -> Str { defmt_macros::internp!("{=__internal_Debug}") } fn _format_data(&self) { export::debug(&self.0); } } /// An "adapter" type to feed `Display` values into defmt macros, which expect `defmt::Format` values. /// /// This adapter disables compression and uses the `core::fmt` code on-device! You should prefer /// `defmt::Format` over `Display` whenever possible. /// /// # Examples /// /// ```rust /// # struct ExpensiveThing(); /// # /// # impl core::fmt::Display for ExpensiveThing { /// # fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { /// # write!(f, "{}", "expensive") /// # } /// # } /// # let expensive_thing = ExpensiveThing(); /// # /// defmt::info!("{}", defmt::Display2Format(&expensive_thing)); /// // ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ /// // must implement `fmt::Display` /// ``` /// /// Note that any provided defmt display hints will be ignored /// because this always uses `{}` to format the contained value. pub struct Display2Format<'a, T: fmt::Display + ?Sized>(pub &'a T); impl Format for Display2Format<'_, T> { default_format!(); fn _format_tag() -> Str { defmt_macros::internp!("{=__internal_Display}") } fn _format_data(&self) { export::display(&self.0); } } defmt-0.3.5/src/impls/alloc_.rs000064400000000000000000000015441046102023000144460ustar 00000000000000use super::*; impl Format for alloc::boxed::Box where T: ?Sized + Format, { delegate_format!(T, self, &*self); } impl Format for alloc::rc::Rc where T: ?Sized + Format, { delegate_format!(T, self, &*self); } #[cfg(not(no_cas))] impl Format for alloc::sync::Arc where T: ?Sized + Format, { delegate_format!(T, self, &*self); } impl Format for alloc::vec::Vec where T: Format, { delegate_format!([T], self, self.as_slice()); } impl Format for alloc::string::String { delegate_format!(str, self, self.as_str()); } impl<'a, T> Format for alloc::borrow::Cow<'a, [T]> where T: 'a + Format, [T]: alloc::borrow::ToOwned>, { delegate_format!([T], self, self.as_ref()); } impl<'a> Format for alloc::borrow::Cow<'a, str> { delegate_format!(str, self, self.as_ref()); } defmt-0.3.5/src/impls/arrays.rs000064400000000000000000000044131046102023000145140ustar 00000000000000use super::*; use crate::export; macro_rules! arrays { ( $($len:literal $fmt:literal,)+ ) => { impl Format for [T; N] where T: Format { default_format!(); #[inline] fn _format_tag() -> Str { match N { $( $len => internp!($fmt), )+ _ => internp!("{=[?]}"), } } #[inline] fn _format_data(&self) { match N { $( $len )|+ => export::fmt_array(self), _ => export::fmt_slice(self), } } } }; } arrays! { 0 "{=[?;0]}", 1 "{=[?;1]}", 2 "{=[?;2]}", 3 "{=[?;3]}", 4 "{=[?;4]}", 5 "{=[?;5]}", 6 "{=[?;6]}", 7 "{=[?;7]}", 8 "{=[?;8]}", 9 "{=[?;9]}", 10 "{=[?;10]}", 11 "{=[?;11]}", 12 "{=[?;12]}", 13 "{=[?;13]}", 14 "{=[?;14]}", 15 "{=[?;15]}", 16 "{=[?;16]}", 17 "{=[?;17]}", 18 "{=[?;18]}", 19 "{=[?;19]}", 20 "{=[?;20]}", 21 "{=[?;21]}", 22 "{=[?;22]}", 23 "{=[?;23]}", 24 "{=[?;24]}", 25 "{=[?;25]}", 26 "{=[?;26]}", 27 "{=[?;27]}", 28 "{=[?;28]}", 29 "{=[?;29]}", 30 "{=[?;30]}", 31 "{=[?;31]}", 32 "{=[?;32]}", 64 "{=[?;64]}", 128 "{=[?;128]}", 256 "{=[?;256]}", 512 "{=[?;512]}", 1024 "{=[?;1024]}", 2048 "{=[?;2048]}", 4096 "{=[?;4096]}", 8192 "{=[?;8192]}", 16384 "{=[?;16384]}", 32768 "{=[?;32768]}", 65536 "{=[?;65536]}", 131072 "{=[?;131072]}", 262144 "{=[?;262144]}", 524288 "{=[?;524288]}", 1048576 "{=[?;1048576]}", 2097152 "{=[?;2097152]}", 4194304 "{=[?;4194304]}", 8388608 "{=[?;8388608]}", 16777216 "{=[?;16777216]}", 33554432 "{=[?;33554432]}", 67108864 "{=[?;67108864]}", 134217728 "{=[?;134217728]}", 268435456 "{=[?;268435456]}", 536870912 "{=[?;536870912]}", 1073741824 "{=[?;1073741824]}", 100 "{=[?;100]}", 1000 "{=[?;1000]}", 10000 "{=[?;10000]}", 100000 "{=[?;100000]}", 1000000 "{=[?;1000000]}", 10000000 "{=[?;10000000]}", 100000000 "{=[?;100000000]}", 1000000000 "{=[?;1000000000]}", } defmt-0.3.5/src/impls/core_/alloc_.rs000064400000000000000000000004051046102023000155300ustar 00000000000000use core::alloc; use super::*; impl Format for alloc::Layout { fn format(&self, fmt: Formatter) { crate::write!( fmt, "Layout {{ size: {}, align: {} }}", self.size(), self.align() ); } } defmt-0.3.5/src/impls/core_/array.rs000064400000000000000000000002601046102023000154140ustar 00000000000000use core::array; use super::*; impl Format for array::TryFromSliceError { fn format(&self, fmt: Formatter) { crate::write!(fmt, "TryFromSliceError(())"); } } defmt-0.3.5/src/impls/core_/cell.rs000064400000000000000000000017121046102023000152200ustar 00000000000000use super::*; impl Format for core::cell::Cell where T: Format + Copy, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "Cell {{ value: {=?} }})", self.get()) } } impl Format for core::cell::RefCell where T: Format, { default_format!(); #[inline] fn _format_tag() -> Str { internp!("RefCell {{ value: }}|RefCell {{ value: {=?} }}") } #[inline] fn _format_data(&self) { match self.try_borrow() { Err(_) => export::u8(&0), Ok(x) => { export::u8(&1); export::istr(&T::_format_tag()); x._format_data() } } } } impl Format for core::cell::BorrowError { fn format(&self, fmt: Formatter) { crate::write!(fmt, "BorrowError") } } impl Format for core::cell::BorrowMutError { fn format(&self, fmt: Formatter) { crate::write!(fmt, "BorrowMutError") } } defmt-0.3.5/src/impls/core_/mod.rs000064400000000000000000000046201046102023000150610ustar 00000000000000//! Some of these objects don't expose enough to accurately report their debug state. In this case //! we show as much state as we can. Users can always use `Debug2Format` to get more information, //! at the cost of bringing core::fmt into the firmware and doing the layout work on device. //! //! We generally keep the type parameter trait bounds in case it becomes possible to use this //! later, without making a backwards-incompatible change. mod alloc_; mod array; mod cell; #[cfg(feature = "ip_in_core")] mod net; mod num; mod ops; mod ptr; mod slice; use super::*; use crate::export; impl Format for Option where T: Format, { default_format!(); #[inline] fn _format_tag() -> Str { internp!("None|Some({=?})") } #[inline] fn _format_data(&self) { match self { None => export::u8(&0), Some(x) => { export::u8(&1); export::istr(&T::_format_tag()); x._format_data() } } } } impl Format for Result where T: Format, E: Format, { default_format!(); #[inline] fn _format_tag() -> Str { internp!("Err({=?})|Ok({=?})") } #[inline] fn _format_data(&self) { match self { Err(e) => { export::u8(&0); export::istr(&E::_format_tag()); e._format_data() } Ok(x) => { export::u8(&1); export::istr(&T::_format_tag()); x._format_data() } } } } impl Format for core::marker::PhantomData { default_format!(); #[inline] fn _format_tag() -> Str { internp!("PhantomData") } #[inline] fn _format_data(&self) {} } impl Format for core::convert::Infallible { default_format!(); #[inline] fn _format_tag() -> Str { unreachable!(); } #[inline] fn _format_data(&self) { unreachable!(); } } impl Format for core::time::Duration { fn format(&self, fmt: Formatter) { crate::write!( fmt, "Duration {{ secs: {=u64}, nanos: {=u32} }}", self.as_secs(), self.subsec_nanos(), ) } } impl Format for core::iter::Zip where A: Format, B: Format, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "Zip(..)") } } defmt-0.3.5/src/impls/core_/net.rs000064400000000000000000000033711046102023000150720ustar 00000000000000use core::net; use super::*; impl Format for net::AddrParseError { fn format(&self, fmt: Formatter) { crate::write!(fmt, "AddrParseError(_)"); } } impl Format for net::Ipv4Addr { fn format(&self, fmt: Formatter) { let [a, b, c, d] = self.octets(); crate::write!(fmt, "{}.{}.{}.{}", a, b, c, d); } } impl Format for net::SocketAddrV4 { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}:{}", self.ip(), self.port()); } } impl Format for net::Ipv6Addr { fn format(&self, fmt: Formatter) { let octets: [u8; 16] = self.octets(); crate::write!( fmt, "{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}", octets[0], octets[1], octets[2], octets[3], octets[4], octets[5], octets[6], octets[7], octets[8], octets[9], octets[10], octets[11], octets[12], octets[13], octets[14], octets[15] ); } } impl Format for net::SocketAddrV6 { fn format(&self, fmt: Formatter) { crate::write!(fmt, "[{}]:{}", self.ip(), self.port()); } } impl Format for net::IpAddr { fn format(&self, fmt: Formatter) { match self { net::IpAddr::V4(a) => crate::write!(fmt, "{}", a), net::IpAddr::V6(a) => crate::write!(fmt, "{}", a), } } } impl Format for net::SocketAddr { fn format(&self, fmt: Formatter) { match self { net::SocketAddr::V4(a) => crate::write!(fmt, "{}", a), net::SocketAddr::V6(a) => crate::write!(fmt, "{}", a), } } } defmt-0.3.5/src/impls/core_/num.rs000064400000000000000000000015341046102023000151020ustar 00000000000000use core::num; use super::*; macro_rules! non_zero { ($type:ty, $hint:literal) => { impl Format for $type { fn format(&self, fmt: Formatter) { crate::write!(fmt, $hint, self.get()); } } }; } non_zero! {num::NonZeroI8, "{=i8}"} non_zero! {num::NonZeroI16, "{=i16}"} non_zero! {num::NonZeroI32, "{=i32}"} non_zero! {num::NonZeroI64, "{=i64}"} non_zero! {num::NonZeroI128, "{=i128}"} non_zero! {num::NonZeroIsize, "{=isize}"} non_zero! {num::NonZeroU8, "{=u8}"} non_zero! {num::NonZeroU16, "{=u16}"} non_zero! {num::NonZeroU32, "{=u32}"} non_zero! {num::NonZeroU64, "{=u64}"} non_zero! {num::NonZeroU128, "{=u128}"} non_zero! {num::NonZeroUsize, "{=usize}"} impl Format for num::TryFromIntError { fn format(&self, fmt: Formatter) { crate::write!(fmt, "TryFromIntError(())"); } } defmt-0.3.5/src/impls/core_/ops.rs000064400000000000000000000017521046102023000151060ustar 00000000000000use super::*; impl Format for core::ops::Range where Idx: Format, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}..{}", self.start, self.end) } } impl Format for core::ops::RangeFrom where Idx: Format, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}..", self.start) } } impl Format for core::ops::RangeFull { fn format(&self, fmt: Formatter) { crate::write!(fmt, "..",) } } impl Format for core::ops::RangeInclusive where Idx: Format, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}..={}", self.start(), self.end()) } } impl Format for core::ops::RangeTo where Idx: Format, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "..{}", self.end) } } impl Format for core::ops::RangeToInclusive where Idx: Format, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "..={}", self.end) } } defmt-0.3.5/src/impls/core_/ptr.rs000064400000000000000000000046041046102023000151110ustar 00000000000000use super::*; impl Format for core::ptr::NonNull { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}", self.as_ptr()) } } #[cfg(c_variadic)] macro_rules! fnptr_format_cvariadic { ($($Arg:ident),+) => { impl Format for extern "C" fn($($Arg),* , ...) -> Ret { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}", (*self as usize) as *const ()) } } impl Format for unsafe extern "C" fn($($Arg),* , ...) -> Ret { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}", (*self as usize) as *const ()) } } }; () => { // C variadics require at least one other argument }; } macro_rules! fnptr_format_args { ($($Arg:ident),*) => { impl Format for extern "Rust" fn($($Arg),*) -> Ret { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}", (*self as usize) as *const ()) } } impl Format for extern "C" fn($($Arg),*) -> Ret { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}", (*self as usize) as *const ()) } } impl Format for unsafe extern "Rust" fn($($Arg),*) -> Ret { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}", (*self as usize) as *const ()) } } impl Format for unsafe extern "C" fn($($Arg),*) -> Ret { fn format(&self, fmt: Formatter) { crate::write!(fmt, "{}", (*self as usize) as *const ()) } } #[cfg(c_variadic)] fnptr_format_cvariadic!{ $($Arg),* } }; } // core::ptr has fnptr impls up to 12 arguments // https://doc.rust-lang.org/src/core/ptr/mod.rs.html#1994 fnptr_format_args! {} fnptr_format_args! { A } fnptr_format_args! { A, B } fnptr_format_args! { A, B, C } fnptr_format_args! { A, B, C, D } fnptr_format_args! { A, B, C, D, E } fnptr_format_args! { A, B, C, D, E, F } fnptr_format_args! { A, B, C, D, E, F, G } fnptr_format_args! { A, B, C, D, E, F, G, H } fnptr_format_args! { A, B, C, D, E, F, G, H, I } fnptr_format_args! { A, B, C, D, E, F, G, H, I, J } fnptr_format_args! { A, B, C, D, E, F, G, H, I, J, K } fnptr_format_args! { A, B, C, D, E, F, G, H, I, J, K, L } defmt-0.3.5/src/impls/core_/slice.rs000064400000000000000000000011441046102023000153770ustar 00000000000000use super::*; impl<'a, T: 'a> Format for core::slice::ChunksExact<'a, T> where T: Format, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "ChunksExact(..)") } } impl<'a, T: 'a> Format for core::slice::Iter<'a, T> where T: Format, { fn format(&self, fmt: Formatter) { crate::write!( fmt, "Iter {{ slice: {=[?]}, position: ? }}", self.as_slice() ) } } impl<'a, T: 'a> Format for core::slice::Windows<'a, T> where T: Format, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "Windows(..)") } } defmt-0.3.5/src/impls/mod.rs000064400000000000000000000014651046102023000137760ustar 00000000000000macro_rules! default_format { () => { #[inline] fn format(&self, _fmt: Formatter) { crate::export::istr(&Self::_format_tag()); self._format_data(); } }; } macro_rules! delegate_format { ($ty:ty, $self_:ident, $val:expr) => { #[inline] fn format(&$self_, fmt: Formatter) { <$ty as Format>::format($val, fmt) } #[inline] fn _format_tag() -> Str { <$ty as Format>::_format_tag() } #[inline] fn _format_data(&$self_) { <$ty as Format>::_format_data($val) } }; } pub mod adapter; #[cfg(feature = "alloc")] mod alloc_; mod arrays; mod core_; mod primitives; mod tuples; use defmt_macros::internp; use crate::{self as defmt, Format, Formatter, Str}; defmt-0.3.5/src/impls/primitives.rs000064400000000000000000000041371046102023000154110ustar 00000000000000use crate::export; use super::*; macro_rules! prim { ($ty:ty, $fmt: literal, $self_:ident, $write:expr) => { impl Format for $ty { default_format!(); #[inline] fn _format_tag() -> Str { internp!($fmt) } #[inline] fn _format_data(&$self_) { $write } } }; } prim!(i8, "{=i8}", self, export::i8(self)); prim!(i16, "{=i16}", self, export::i16(self)); prim!(i32, "{=i32}", self, export::i32(self)); prim!(i64, "{=i64}", self, export::i64(self)); prim!(i128, "{=i128}", self, export::i128(self)); prim!(isize, "{=isize}", self, export::isize(self)); prim!(u8, "{=u8}", self, export::u8(self)); prim!(u16, "{=u16}", self, export::u16(self)); prim!(u32, "{=u32}", self, export::u32(self)); prim!(u64, "{=u64}", self, export::u64(self)); prim!(u128, "{=u128}", self, export::u128(self)); prim!(usize, "{=usize}", self, export::usize(self)); prim!(f32, "{=f32}", self, export::f32(self)); prim!(f64, "{=f64}", self, export::f64(self)); prim!(str, "{=str}", self, export::str(self)); prim!(bool, "{=bool}", self, export::bool(self)); prim!(Str, "{=istr}", self, export::istr(self)); prim!(char, "{=char}", self, export::char(self)); impl Format for [T] where T: Format, { default_format!(); #[inline] fn _format_tag() -> Str { internp!("{=[?]}") } #[inline] fn _format_data(&self) { export::fmt_slice(self); } } impl Format for &'_ T where T: Format + ?Sized, { delegate_format!(T, self, self); } impl Format for &'_ mut T where T: Format + ?Sized, { delegate_format!(T, self, self); } // Format raw pointer as hexadecimal // // First cast raw pointer to thin pointer, then to usize and finally format as hexadecimal. impl Format for *const T where T: ?Sized, { fn format(&self, fmt: Formatter) { crate::write!(fmt, "0x{:x}", *self as *const () as usize); } } impl Format for *mut T where T: ?Sized, { fn format(&self, fmt: Formatter) { Format::format(&(*self as *const T), fmt) } } defmt-0.3.5/src/impls/tuples.rs000064400000000000000000000036151046102023000145320ustar 00000000000000use super::*; use crate::export; impl Format for () { default_format!(); #[inline] fn _format_tag() -> Str { internp!("()") } #[inline] fn _format_data(&self) {} } macro_rules! tuple { ( $format:expr, ($($name:ident),+) ) => ( impl<$($name:Format),+> Format for ($($name,)+) where last_type!($($name,)+): ?Sized { default_format!(); #[inline] fn _format_tag() -> Str { internp!($format) } #[inline] #[allow(non_snake_case, unused_assignments)] fn _format_data(&self) { let ($(ref $name,)+) = *self; $( export::istr(&$name::_format_tag()); $name._format_data(); )+ } } ) } macro_rules! last_type { ($a:ident,) => { $a }; ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) }; } tuple! { "({=?})", (T0) } tuple! { "({=?}, {=?})", (T0, T1) } tuple! { "({=?}, {=?}, {=?})", (T0, T1, T2) } tuple! { "({=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3) } tuple! { "({=?}, {=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3, T4) } tuple! { "({=?}, {=?}, {=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3, T4, T5) } tuple! { "({=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3, T4, T5, T6) } tuple! { "({=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3, T4, T5, T6, T7) } tuple! { "({=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3, T4, T5, T6, T7, T8) } tuple! { "({=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) } tuple! { "({=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) } tuple! { "({=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?}, {=?})", (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) } defmt-0.3.5/src/lib.rs000064400000000000000000000332641046102023000126430ustar 00000000000000//! A highly efficient logging framework that targets resource-constrained devices, like //! microcontrollers. //! //! Check out the defmt book at for more information about how //! to use it. //! //! # Compatibility //! //! The `defmt` wire format might change between major versions. Attempting to read a defmt stream //! with an incompatible version will result in an error. This means that you have to update both //! the host and target side if a breaking change in defmt is released. #![cfg_attr(not(feature = "unstable-test"), no_std)] // NOTE if you change this URL you'll also need to update all other crates in this repo #![doc(html_logo_url = "https://knurling.ferrous-systems.com/knurling_logo_light_text.svg")] #![warn(missing_docs)] #![cfg_attr(feature = "ip_in_core", feature(ip_in_core))] #[cfg(feature = "alloc")] extern crate alloc; // This must be in the root lib.rs, otherwise it doesn't appear in the final binary. /// The defmt ABI and wire format version. /// /// This number has to be updated every time there is a backwards-incompatible change to /// - the symbol naming scheme /// - the symbol and section layout /// - the data encoding / wire format #[used] #[cfg_attr(target_os = "macos", link_section = ".defmt,end.VERSION")] #[cfg_attr(not(target_os = "macos"), link_section = ".defmt.end")] #[export_name = "_defmt_version_ = 4"] static DEFMT_VERSION: u8 = 0; #[used] #[cfg_attr(target_os = "macos", link_section = ".defmt,end.ENCODING")] #[cfg_attr(not(target_os = "macos"), link_section = ".defmt.end")] #[cfg_attr(feature = "encoding-raw", export_name = "_defmt_encoding_ = raw")] #[cfg_attr( not(feature = "encoding-raw"), export_name = "_defmt_encoding_ = rzcobs" )] #[allow(missing_docs)] #[doc(hidden)] pub static DEFMT_ENCODING: u8 = 0; mod encoding; #[doc(hidden)] pub mod export; mod formatter; mod impls; #[cfg(all(test, feature = "unstable-test"))] mod tests; mod traits; pub use crate::{ encoding::Encoder, formatter::{Formatter, Str}, impls::adapter::{Debug2Format, Display2Format}, traits::{Format, Logger}, }; #[cfg(all(test, not(feature = "unstable-test")))] compile_error!( "to run unit tests enable the `unstable-test` feature, e.g. `cargo t --features unstable-test`" ); /// Just like the [`core::assert!`] macro but `defmt` is used to log the panic message /// /// [`core::assert!`]: https://doc.rust-lang.org/core/macro.assert.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::assert_ as assert; /// Just like the [`core::assert_eq!`] macro but `defmt` is used to log the panic message /// /// [`core::assert_eq!`]: https://doc.rust-lang.org/core/macro.assert_eq.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::assert_eq_ as assert_eq; /// Just like the [`core::assert_ne!`] macro but `defmt` is used to log the panic message /// /// [`core::assert_ne!`]: https://doc.rust-lang.org/core/macro.assert_ne.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::assert_ne_ as assert_ne; /// Just like the [`core::debug_assert!`] macro but `defmt` is used to log the panic message /// /// [`core::debug_assert!`]: https://doc.rust-lang.org/core/macro.debug_assert.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::debug_assert_ as debug_assert; /// Just like the [`core::debug_assert_eq!`] macro but `defmt` is used to log the panic message /// /// [`core::debug_assert_eq!`]: https://doc.rust-lang.org/core/macro.debug_assert_eq.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::debug_assert_eq_ as debug_assert_eq; /// Just like the [`core::debug_assert_ne!`] macro but `defmt` is used to log the panic message /// /// [`core::debug_assert_ne!`]: https://doc.rust-lang.org/core/macro.debug_assert_ne.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::debug_assert_ne_ as debug_assert_ne; /// Just like the [`core::unreachable!`] macro but `defmt` is used to log the panic message /// /// [`core::unreachable!`]: https://doc.rust-lang.org/core/macro.unreachable.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::unreachable_ as unreachable; /// Just like the [`core::todo!`] macro but `defmt` is used to log the panic message /// /// [`core::todo!`]: https://doc.rust-lang.org/core/macro.todo.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::todo_ as todo; /// Just like the [`core::unimplemented!`] macro but `defmt` is used to log the panic message /// /// [`core::unimplemented!`]: https://doc.rust-lang.org/core/macro.unimplemented.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::todo_ as unimplemented; /// Just like the [`core::panic!`] macro but `defmt` is used to log the panic message /// /// [`core::panic!`]: https://doc.rust-lang.org/core/macro.panic.html /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::panic_ as panic; /// Unwraps an `Option` or `Result`, panicking if it is `None` or `Err`. /// /// This macro is roughly equivalent to `{Option,Result}::{expect,unwrap}` but invocation looks /// a bit different because this is a macro and not a method. The other difference is that /// `unwrap!`-ing a `Result` value requires that the error type `E` implements the `Format` /// trait /// /// The following snippet shows the differences between core's unwrap method and defmt's unwrap /// macro: /// /// ``` /// use defmt::unwrap; /// /// # let option = Some(()); /// let x = option.unwrap(); /// let x = unwrap!(option); /// /// # let result = Ok::<(), ()>(()); /// let x = result.unwrap(); /// let x = unwrap!(result); /// /// # let value = result; /// let x = value.expect("text"); /// let x = unwrap!(value, "text"); /// /// # let arg = (); /// let x = value.expect(&format!("text {:?}", arg)); /// let x = unwrap!(value, "text {:?}", arg); // arg must be implement `Format` /// ``` /// /// If used, the format string must follow the defmt syntax (documented in [the manual]) /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::unwrap; /// Overrides the panicking behavior of `defmt::panic!` /// /// By default, `defmt::panic!` calls `core::panic!` after logging the panic message using `defmt`. /// This can result in the panic message being printed twice in some cases. To avoid that issue use /// this macro. See [the manual] for details. /// /// [the manual]: https://defmt.ferrous-systems.com/panic.html /// /// # Inter-operation with built-in attributes /// /// This attribute cannot be used together with the `export_name` or `no_mangle` attributes pub use defmt_macros::panic_handler; /// Creates an interned string ([`Str`]) from a string literal. /// /// This must be called on a string literal, and will allocate the literal in the object file. At /// runtime, only a small string index is required to refer to the string, represented as the /// [`Str`] type. /// /// # Example /// /// ``` /// let interned = defmt::intern!("long string literal taking up little space"); /// ``` /// /// [`Str`]: struct.Str.html pub use defmt_macros::intern; /// Always logs data irrespective of log level. /// /// Please refer to [the manual] for documentation on the syntax. /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::println; /// Logs data at *debug* level. /// /// Please refer to [the manual] for documentation on the syntax. /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::debug; /// Logs data at *error* level. /// /// Please refer to [the manual] for documentation on the syntax. /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::error; /// Logs data at *info* level. /// /// Please refer to [the manual] for documentation on the syntax. /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::info; /// Logs data at *trace* level. /// /// Please refer to [the manual] for documentation on the syntax. /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::trace; /// Logs data at *warn* level. /// /// Please refer to [the manual] for documentation on the syntax. /// /// [the manual]: https://defmt.ferrous-systems.com/macros.html pub use defmt_macros::warn; /// Just like the [`std::dbg!`] macro but `defmt` is used to log the message at `TRACE` level. /// /// [`std::dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html pub use defmt_macros::dbg; /// Writes formatted data to a [`Formatter`]. /// /// [`Formatter`]: struct.Formatter.html pub use defmt_macros::write; /// Defines the global defmt logger. /// /// `#[global_logger]` needs to be put on a unit struct type declaration. This struct has to /// implement the [`Logger`] trait. /// /// # Example /// /// ``` /// use defmt::{Logger, global_logger}; /// /// #[global_logger] /// struct MyLogger; /// /// unsafe impl Logger for MyLogger { /// fn acquire() { /// # todo!() /// // ... /// } /// unsafe fn flush() { /// # todo!() /// // ... /// } /// unsafe fn release() { /// # todo!() /// // ... /// } /// unsafe fn write(bytes: &[u8]) { /// # todo!() /// // ... /// } /// } /// ``` /// /// [`Logger`]: trait.Logger.html pub use defmt_macros::global_logger; /// Defines the global timestamp provider for defmt. /// /// This macro can be used to attach a timestamp or other data to every defmt message. Its syntax /// works exactly like the logging macros, except that no local variables can be accessed and the /// macro should be placed in a module instead of a function. /// /// `timestamp!` must only be used once across the crate graph. /// /// If no crate defines a timestamp, no timestamp will be included in the logged messages. /// /// # Examples /// /// ``` /// # use core::sync::atomic::{AtomicU32, Ordering}; /// /// static COUNT: AtomicU32 = AtomicU32::new(0); /// defmt::timestamp!("{=u32:us}", COUNT.fetch_add(1, Ordering::Relaxed)); /// ``` pub use defmt_macros::timestamp; /// Generates a bitflags structure that can be formatted with defmt. /// /// This macro is a wrapper around the [`bitflags!`] crate, and provides an (almost) identical /// interface. Refer to [its documentation] for an explanation of the syntax. /// /// [its documentation]: https://docs.rs/bitflags/1/bitflags/ /// /// # Limitations /// /// This macro only supports bitflags structs represented as one of Rust's built-in unsigned integer /// types (`u8`, `u16`, `u32`, `u64`, or `u128`). Custom types are not supported. This restriction /// is necessary to support defmt's efficient encoding. /// /// # Examples /// /// The example from the bitflags crate works as-is: /// /// ``` /// defmt::bitflags! { /// struct Flags: u32 { /// const A = 0b00000001; /// const B = 0b00000010; /// const C = 0b00000100; /// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; /// } /// } /// /// defmt::info!("Flags::ABC: {}", Flags::ABC); /// defmt::info!("Flags::empty(): {}", Flags::empty()); /// ``` pub use defmt_macros::bitflags; #[doc(hidden)] // documented as the `Format` trait instead pub use defmt_macros::Format; // There is no default timestamp format. Instead, the decoder looks for a matching ELF symbol. If // absent, timestamps are turned off. #[export_name = "__defmt_default_timestamp"] fn default_timestamp(_f: Formatter<'_>) {} #[export_name = "__defmt_default_panic"] fn default_panic() -> ! { core::panic!() } /// Block until host has read all pending data. /// /// The flush operation will not fail, but might not succeed in flushing _all_ pending data. It is /// implemented as a "best effort" operation. /// /// This calls the method `flush` of the used "global [`Logger`]". The logger is likely provided by /// [`defmt-rtt`](https://crates.io/crates/defmt-rtt) or [`defmt-itm`](https://crates.io/crates/defmt-itm). pub fn flush() { match () { #[cfg(feature = "unstable-test")] () => { // no-op when run on host } #[cfg(not(feature = "unstable-test"))] () => { extern "Rust" { fn _defmt_acquire(); fn _defmt_flush(); fn _defmt_release(); } // SAFETY: // * we call these function in the correct order: first acquire the lock, then flush and // finally release the lock // * these function should be provided by the macro `#[global_logger]` and therefore // trustworthy to call through FFI-bounds unsafe { _defmt_acquire(); _defmt_flush(); _defmt_release() } } } } defmt-0.3.5/src/tests.rs000064400000000000000000000014531046102023000132320ustar 00000000000000use crate as defmt; #[test] fn log_levels() { // just make sure they build OK for now defmt::trace!("test trace"); defmt::debug!("test debug"); defmt::info!("test info"); defmt::warn!("test warn"); defmt::error!("test error"); } #[test] fn str() { defmt::info!("Hello, {=str}", "world"); let world = defmt::intern!("world"); defmt::info!("Hello, {=istr}", world); } #[test] fn trailing_comma() { defmt::trace!("test trace",); defmt::debug!("test debug",); defmt::info!("test info",); defmt::warn!("test warn",); defmt::error!("test error",); defmt::trace!("test trace {=?}", 0,); defmt::debug!("test debug {=?}", 0,); defmt::info!("test info {=?}", 0,); defmt::warn!("test warn {=?}", 0,); defmt::error!("test error {=?}", 0,); } defmt-0.3.5/src/traits.rs000064400000000000000000000112621046102023000133750ustar 00000000000000use defmt_macros::internp; #[allow(unused_imports)] use crate as defmt; use crate::{export, Formatter, Str}; /// Trait for types that can be formatted via defmt. /// /// This trait is used by the `{:?}` format specifier and can format a wide range of types. /// User-defined types can `#[derive(Format)]` to get an auto-generated implementation of this /// trait. /// /// **Note**: The implementation of `#[derive(Format)]` assumes that no builtin types are shadowed /// (for example by defining a `struct u8;`). This allows it to represent them more compactly. /// /// # Example /// /// Usually, an implementation of this trait can be `#[derive]`d automatically: /// /// ``` /// use defmt::Format; /// /// #[derive(Format)] /// struct Header { /// source: u8, /// destination: u8, /// sequence: u16, /// } /// ``` /// /// Manual implementations can make use of the [`write!`] macro: /// /// ``` /// use defmt::{Format, Formatter, write}; /// /// struct Id(u32); /// /// impl Format for Id { /// fn format(&self, fmt: Formatter) { /// // Format as hexadecimal. /// write!(fmt, "Id({:x})", self.0); /// } /// } /// ``` pub trait Format { /// Writes the defmt representation of `self` to `fmt`. fn format(&self, fmt: Formatter); #[doc(hidden)] fn _format_tag() -> Str { internp!("{=__internal_FormatSequence}") } #[doc(hidden)] fn _format_data(&self) { self.format(export::make_formatter()); export::u16(&0); // terminator } } /// Global logger acquire-release mechanism /// /// This trait's methods will be called by the defmt logging macros to transmit the /// encoded log data over the wire. The call order is: /// - One `acquire()` call to start the log frame. /// - Multiple `write()` calls, with fragments of the log frame data each. /// - One `release()` call. /// /// The data passed to `write()` is *unencoded*. Implementations MUST encode it with `Encoder` /// prior to sending it over the wire. The simplest way is for `acquire()` to call `Encoder::start_frame()`, /// `write()` to call `Encoder::write()`, and `release()` to call `Encoder::end_frame()`. /// /// The global logger can be acquired once for each "execution context". The definition /// of execution context is up to the implementation. For example, it can be: /// /// - the entire process. /// - one thread in std environments. /// - one interrupt priority level in embedded devices. /// /// # Safety /// /// - `acquire` logically acquires the global logger in the current execution context. /// The acquiring is tracked internally, no Rust object is returned representing ownership. /// - `acquire` is a safe function, therefore it must be thread-safe and interrupt-safe /// /// And, not safety related, the methods should never be invoked from user code. The easiest way to /// ensure this is to implement `Logger` on a *private* `struct` and mark that `struct` as the /// `#[global_logger]`. pub unsafe trait Logger { /// Acquire the global logger in the current execution context. /// /// This will be called by the defmt logging macros before writing each log frame. /// /// Panics if already acquired in the current execution context. Otherwise it must never fail. fn acquire(); /// Block until host has read all pending data. /// /// The flush operation must not fail. This is a "best effort" operation, I/O errors should be discarded. /// /// # Safety /// Must only be called when the global logger is acquired in the current execution context. /// (i.e. between `acquire()` and `release()`). unsafe fn flush(); /// Releases the global logger in the current execution context. /// /// This will be called by the defmt logging macros after writing each log frame. /// /// # Safety /// Must be called exactly once for each acquire(), in the same execution context. unsafe fn release(); /// Writes `bytes` to the destination. /// /// This will be called by the defmt logging macros to transmit frame data. One log frame may cause multiple `write` calls. /// /// The write operation must not fail. This is a "best effort" operation, I/O errors should be discarded. /// /// The `bytes` are unencoded log frame data, they MUST be encoded with `Encoder` prior to /// sending over the wire. /// /// Note that a call to `write` does *not* correspond to a defmt logging macro invocation. A /// single `defmt::info!` call can result in an arbitrary number of `write` calls. /// /// # Safety /// Must only be called when the global logger is acquired in the current execution context. /// (i.e. between `acquire()` and `release()`). unsafe fn write(bytes: &[u8]); } defmt-0.3.5/tests/basic_usage.rs000064400000000000000000000004121046102023000147020ustar 00000000000000fn main() { defmt::info!("hello"); } #[defmt::global_logger] struct Logger; unsafe impl defmt::Logger for Logger { fn acquire() {} unsafe fn flush() {} unsafe fn release() {} unsafe fn write(_bytes: &[u8]) {} } defmt::timestamp!("{=u32}", 0); defmt-0.3.5/tests/encode.rs000064400000000000000000000571031046102023000137030ustar 00000000000000// NOTE these tests should live in `defmt-macros` but the expansion of the macros defined there // depend on `defmt` and `defmt` depends on `defmt-macros` -- the circular dependency may get in // the way of `cargo test` // NOTE string interning is mocked when testing so that it does not do real interning. Instead // the "interner" always returns a **7-bit** `u8` value that's bumped on every interning operation. // // In practice, this means that the following operation: // ``` // fn foo(f: &mut Formatter) { // write!(f, "Hello") // } // ``` // writes a *different* index on each call. With real interning this operation always writes the // same index. // // `fetch_string_index` returns the current index of the mocked interner. Use this // when writing the expected output of a unit test. // // ``` // let mut f = Internalexport::make_formatter(); // let index = defmt::export::fetch_string_index(); // foo(&mut f); // NOTE increases the interner index // assert_eq!(fetch_bytes(), [index]); // // let mut f = Internalexport::make_formatter(); // foo(&mut f); // assert_eq!(fetch_bytes(), [index.wrapping_add(1)]); // ^^^^^^^^^^^^^^^ account for the previous `foo` call // ``` // // The mocked string index is thread local so you can run unit tests in parallel. // `fetch_string_index` returns the thread-local interner index. // // Additional notes: // // - the mocked index is 7 bits so its LEB128 encoding is the input byte use defmt::{export::fetch_string_index, write, Debug2Format, Display2Format, Format, Formatter}; // Increase the 7-bit mocked interned index fn inc(index: u16, n: u16) -> u16 { index.wrapping_add(n) } fn write_format(val: &T) { defmt::export::istr(&T::_format_tag()); val._format_data(); } macro_rules! check { ([$($x:expr),* $(,)?]) => { { let mut v = Vec::::new(); $( v.extend(&($x).to_le_bytes()); )* assert_eq!(defmt::export::fetch_bytes(), v); } }; } macro_rules! check_format { ($format:expr, [$($x:expr),* $(,)?] $(,)?) => { { let mut v = Vec::::new(); $( v.extend(&($x).to_le_bytes()); )* write_format($format); assert_eq!(defmt::export::fetch_bytes(), v); } } } #[test] fn write() { let index = fetch_string_index(); let g = defmt::export::make_formatter(); write!(g, "The answer is {=u8}", 42); check!([ index, // "The answer is {=u8}", 42u8, // u8 value ]); let g = defmt::export::make_formatter(); write!(g, "The answer is {=?}", 42u8); check!([ inc(index, 1), // "The answer is {=?}" inc(index, 2), // "{=u8}" / impl Format for u8 42u8, // u8 value ]); } #[test] fn bitfields_mixed() { let index = fetch_string_index(); let g = defmt::export::make_formatter(); write!( g, "bitfields {0=7..12}, {1=0..5}", 0b1110_0101_1111_0000u16, 0b1111_0000u8 ); check!([ index, // bitfields {0=7..12}, {1=0..5}", 0b1111_0000u8, 0b1110_0101u8, // u16 0b1111_0000u8, // u8 ]); } #[test] fn bitfields_across_octets() { let index = fetch_string_index(); let g = defmt::export::make_formatter(); write!(g, "bitfields {0=0..7} {0=9..14}", 0b0110_0011_1101_0010u16); check!([ index, // bitfields {0=0..7} {0=9..14}", 0b1101_0010u8, 0b0110_0011u8, // u16 ]); } #[test] fn bitfields_truncate_lower() { let index = fetch_string_index(); let g = defmt::export::make_formatter(); write!( g, "bitfields {0=9..14}", 0b0000_0000_0000_1111_0110_0011_1101_0010u32 ); check!([ index, // bitfields {0=9..14}", 0b0110_0011u8, // the first octet should have been truncated away ]); } #[test] fn bitfields_assert_range_exclusive() { let index = fetch_string_index(); let g = defmt::export::make_formatter(); write!(g, "bitfields {0=6..8}", 0b1010_0101u8,); check!([ index, // "bitfields {0=6..8}" 0b1010_0101u8 ]); } #[test] fn debug_attr_struct() { #[derive(Debug)] struct DebugOnly { _a: i32, } #[derive(Format)] struct X { y: bool, #[defmt(Debug2Format)] d: DebugOnly, } let index = fetch_string_index(); check_format!( &X { y: false, d: DebugOnly { _a: 3 } }, [ index, // "X {{ y: {=bool}, d: {=?} }}" 0b0u8, // y inc(index, 1), // DebugOnly's format string b'D', // Text of the Debug output b'e', b'b', b'u', b'g', b'O', b'n', b'l', b'y', b' ', b'{', b' ', b'_', b'a', b':', b' ', b'3', b' ', b'}', 0xffu8 ], ) } #[test] fn display_attr_enum() { use std::fmt; struct DisplayOnly {} impl fmt::Display for DisplayOnly { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Display") } } #[derive(Format)] enum X { #[allow(dead_code)] Bool(bool), Display(#[defmt(Display2Format)] DisplayOnly), } let index = fetch_string_index(); check_format!( &X::Display(DisplayOnly {}), [ index, // "Bool({=bool})|Display({=?})" 0b1u8, // Variant: Display inc(index, 1), // DisplayOnly's format string b'D', // Text of the Display output b'i', b's', b'p', b'l', b'a', b'y', 0xffu8 ], ) } #[test] fn boolean_struct() { #[derive(Format)] struct X { y: bool, z: bool, } let index = fetch_string_index(); check_format!( &X { y: false, z: true }, [ index, // "X {{ y: {=bool}, z: {=bool} }}" 0b0u8, // y 0b1u8, // z ], ) } #[test] fn single_struct() { #[derive(Format)] struct X { y: u8, z: u16, } let index = fetch_string_index(); check_format!( &X { y: 1, z: 2 }, [ index, // "X {{ y: {=u8}, z: {=u16} }}" 1u8, // x 2u8, // y.low 0u8, // y.high ], ) } #[test] fn single_struct_manual() { // Above `#[derive]`d impl should be equivalent to this: struct X { y: u8, z: u16, } impl Format for X { fn format(&self, f: Formatter) { defmt::write!(f, "X {{ y: {=u8}, z: {=u16} }}", self.y, self.z) } } let index = fetch_string_index(); check_format!( &X { y: 1, z: 2 }, [ index, // "{=__internal_FormatSequence}" inc(index, 1), // "X {{ y: {=u8}, z: {=u16} }}" 1u8, // y 2u16, // z 0u16, // terminator ], ) } #[test] fn single_struct_manual_multiwrite() { // Above `#[derive]`d impl should be equivalent to this: struct X { y: u8, z: u16, } impl Format for X { fn format(&self, f: Formatter) { defmt::write!(f, "y={=u8}", self.y); defmt::write!(f, "z={=u16}", self.z); } } let index = fetch_string_index(); check_format!( &X { y: 1, z: 2 }, [ index, // "{=__internal_FormatSequence}" inc(index, 1), // "y={=u8}" 1u8, // y inc(index, 2), // "z={=u16}" 2u16, // z 0u16, // terminator ], ) } #[test] fn slice_struct_manual_multiwrite() { // Above `#[derive]`d impl should be equivalent to this: struct X { y: u8, z: u16, } impl Format for X { fn format(&self, f: Formatter) { defmt::write!(f, "y={=u8}", self.y); defmt::write!(f, "z={=u16}", self.z); } } let index = fetch_string_index(); check_format!( &[X { y: 1, z: 2 }, X { y: 3, z: 4 }][..], [ index, // "{=[?]}" 2u32, // len inc(index, 1), // "{=__internal_FormatSequence}" // first element inc(index, 2), // "y={=u8}" 1u8, // y inc(index, 3), // "z={=u16}" 2u16, // z 0u16, // terminator // second element inc(index, 4), // "y={=u8}" 3u8, // y inc(index, 5), // "z={=u16}" 4u16, // z 0u16, // terminator ], ) } #[test] fn nested_struct() { #[derive(Format)] struct X { y: Y, } #[derive(Format)] struct Y { z: u8, } let val = 42u8; let index = fetch_string_index(); check_format!( &X { y: Y { z: val } }, [ index, // "X {{ y: {=?} }}" inc(index, 1), // "Y {{ z: {=u8} }}" val, ], ); } #[test] fn tuple_struct() { #[derive(Format)] struct Struct(u8, u16); let index = fetch_string_index(); check_format!( &Struct(0x1f, 0xaaaa), [ index, // "Struct({=u8}, {=u16})" 0x1fu8, // u8 0xaaaau16, // u16 ], ); } #[test] fn c_like_enum() { #[derive(Format)] #[allow(dead_code)] enum Enum { A, B, C, } let index = fetch_string_index(); check_format!( &Enum::A, [ index, // 0u8, // `Enum::A` ], ); let index = fetch_string_index(); check_format!( &Enum::B, [ index, // 1u8, // `Enum::B` ], ); } #[test] fn uninhabited_enum() { #[derive(Format)] enum Void {} } /// Tests that univariant enums do not encode the discriminant (since the variant in use is always /// the same). #[test] fn univariant_enum() { #[derive(Format)] enum NoData { Variant, } let index = fetch_string_index(); check_format!( &NoData::Variant, [ index, // ], ); #[derive(Format)] enum Data { Variant(u8, u16), } let index = fetch_string_index(); check_format!( &Data::Variant(0x1f, 0xaaaa), [ index, // 0x1fu8, // u8 0xaaaau16, // u16 ], ); } #[test] fn nested_enum() { #[derive(Format)] #[allow(dead_code)] enum CLike { A, B, C, } #[derive(Format)] enum Inner { A(CLike, u8), _B, } #[derive(Format)] enum Outer { Variant1 { pre: u8, inner: Inner, post: u8 }, Variant2, Variant3(Inner), } let index = fetch_string_index(); check_format!( &Outer::Variant1 { pre: 0xEE, inner: Inner::A(CLike::B, 0x07), post: 0xAB, }, [ index, // 0u8, // `Outer::Variant1` 0xEEu8, // u8 pre inc(index, 1), // `Inner`'s formatting string 0u8, // `Inner::A` inc(index, 2), // `CLike`'s formatting string 1u8, // `CLike::B` 0x07u8, // u8 0xABu8, // u8 post ], ); let index = fetch_string_index(); check_format!( &Outer::Variant2, [ index, // 1u8, // `Outer::Variant2` ], ); let index = fetch_string_index(); check_format!( &Outer::Variant3(Inner::A(CLike::B, 0x07)), [ index, // 2u8, // `Outer::Variant3` inc(index, 1), // `Inner`'s formatting string 0u8, // `Inner::A` inc(index, 2), // `CLike`'s formatting string 1u8, // `CLike::B` 0x07u8, // u8 ], ); } #[test] fn slice() { let index = fetch_string_index(); let val: &[u8] = &[23u8, 42u8]; check_format!( val, [ index, // "{=[?]}" val.len() as u32, // length inc(index, 1), // "{=u8}" 23u8, // val[0] 42u8, // val[1] ], ) } #[test] fn slice_of_usize() { let index = fetch_string_index(); let val: &[usize] = &[23usize, 42]; check_format!( val, [ index, // "{=[?]}" val.len() as u32, // length inc(index, 1), // "{=usize}" 23u32, // val[0] 42u32, // val[1] ], ) } #[test] fn slice_of_bools() { let index = fetch_string_index(); let val: &[bool] = &[true, true, false]; check_format!( val, [ index, // "{=[?]}" val.len() as u32, // length inc(index, 1), // "{=bool}" 0b1u8, 0b1u8, 0b0u8, ], ) } #[test] fn format_primitives() { let index = fetch_string_index(); check_format!( &42u8, [ index, // "{=u8}" 42u8, ], ); check_format!( &42u16, [ inc(index, 1), // "{=u16}" 42u16, ], ); check_format!( &513u16, [ inc(index, 2), // "{=u16}" 513u16, ], ); check_format!( &42u32, [ inc(index, 3), // "{=u32}" 42u32, ], ); check_format!( &513u32, [ inc(index, 4), // "{=u32}" 513u32, ], ); check_format!( &5.13f32, [ inc(index, 5), // "{=f32}" 246u8, 40u8, 164u8, 64u8, ], ); check_format!( &42i8, [ inc(index, 6), // "{=i8}" 42u8, ], ); check_format!( &-42i8, [ inc(index, 7), // "{=i8}" -42i8 as u8, ], ); check_format!( &None::, [ inc(index, 8), // "" 0u8, // None discriminant ], ); check_format!( &Some(42u8), [ inc(index, 9), // "" 1u8, // Some discriminant inc(index, 10), // "{=u8}" 42u8, // Some.0 field ], ); check_format!(&-1isize, [inc(index, 11), -1i32]); check_format!(&-128isize, [inc(index, 12), -128i32]); check_format!( &true, [ inc(index, 13), // "{=bool}" 0b1u8, ], ); check_format!( &513u64, [ inc(index, 14), // "{=u64}" 513u64, ], ); check_format!( &-2i64, [ inc(index, 15), // "{=i64}" -2i64, ], ); check_format!( &'a', [ inc(index, 16), // "{=char}" 0x61u8, 0x00u8, 0x00u8, 0x00u8, ], ); } #[test] fn istr() { let index = fetch_string_index(); let interned = defmt::intern!("interned string contents"); check_format!( &interned, [ inc(index, 1), // "{=istr}" index, ], ); } #[test] fn format_arrays() { let index = fetch_string_index(); let array: [u16; 0] = []; check_format!( &array, [ index, // "{=[?;0]}" inc(index, 1), // "{=u16}" ] ); let index = fetch_string_index(); let array: [u16; 3] = [1, 256, 257]; check_format!( &array, [ index, // "{=[?;3]}" inc(index, 1), // "{=u16}" 1u16, // [0] 256u16, // [1] 257u16, // [2] ], ); } #[test] fn format_slice_of_primitives() { let index = fetch_string_index(); let slice: &[u16] = &[1, 256, 257]; check_format!( slice, [ index, // "{=[?]}" slice.len() as u32, // inc(index, 1), // "{=u16}" 1u16, // [0] 256u16, // [1] 257u16, // [2] ], ); } #[test] fn format_slice_of_structs() { #[derive(Format)] struct X { y: Y, } #[derive(Format)] struct Y { z: u8, } let index = fetch_string_index(); let slice: &[_] = &[X { y: Y { z: 42 } }, X { y: Y { z: 24 } }]; check_format!( slice, [ index, // "{=[?]}" slice.len() as u32, // // first element inc(index, 1), // "X {{ y: {=?} }}" inc(index, 2), // "Y {{ z: {=u8} }}" 42u8, // [0].y.z // second element: no outer tag inc(index, 3), // "Y {{ z: {=u8} }}" 24u8, // [1].y.z ], ); } #[test] fn format_slice_of_slices() { let index = fetch_string_index(); let slice: &[&[u16]] = &[&[256, 257], &[258, 259, 260]]; check_format!( slice, [ index, // "{=[?]}" slice.len() as u32, // inc(index, 1), // "{=[?]}" // first slice slice[0].len() as u32, inc(index, 2), // "{=u16}" 256u16, // [0][0] 257u16, // [0][1] // second slice slice[1].len() as u32, inc(index, 3), // "{=u16}" 258u16, // [1][0] 259u16, // [1][1] 260u16, // [1][2] ], ); } #[test] fn format_slice_enum_slice() { let index = fetch_string_index(); let slice: &[Option<&[u8]>] = &[None, Some(&[42, 43])]; check_format!( slice, [ index, // "{=[?]}" slice.len() as u32, // // first optional slice inc(index, 1), // "None|Some({=?})" 0u8, // discriminant // second optional slice // omitted: "None|Some({=?})" index 1u8, // discriminant inc(index, 2), // "{=[?]}" (the ? behind "Some({=?})") 2u32, // length of second optional slice inc(index, 3), // "{=u8}" (the ? behind "{=[?]}") 42u8, // omitted: "{=u8}" index 43u8, ], ); } #[test] fn format_slice_enum_generic_struct() { #[derive(Format)] struct S { x: u8, y: T, } let index = fetch_string_index(); let slice: &[Option>] = &[None, Some(S { x: 42, y: 43 })]; check_format!( slice, [ index, // "{=[?]}" slice.len() as u32, // // first optional element inc(index, 1), // "None|Some({=?})" 0u8, // discriminant // second optional element // omitted: "None|Some({=?})" index 1u8, // discriminant inc(index, 2), // "S {{ x: {=u8}, y: {=?} }}" (the ? behind "Some({=?})") 42u8, // S.x inc(index, 3), // "{=u8}" (the ? behind S.y) 43u8, // S. y ], ); } #[test] fn derive_with_bounds() { #[derive(Format)] struct S { val: T, } #[derive(Format)] struct S2<'a: 'b, 'b> { a: &'a u8, b: &'b u8, } let index = fetch_string_index(); check_format!( &S { val: 0 }, [ index, // "S {{ val: {=?} }}" inc(index, 1), // "{=i32}" 0u32, ], ); let index = fetch_string_index(); check_format!( &S2 { a: &1, b: &2 }, [ index, // "S2 { a: {=u8}, b: {=u8} }}" 1u8, 2u8, ], ); } #[test] fn format_bools() { #[derive(Format)] struct A(bool); #[derive(Format)] struct B(bool); let index = fetch_string_index(); check_format!( &(A(true), B(true)), [ index, // "({=?}, {=?})" inc(index, 1), // "A({=bool})" 0b1u8, // A inc(index, 2), // "B({=bool})" 0b1u8, // B ], ); } #[test] fn enum_variants() { #[allow(dead_code)] #[derive(Format)] enum EnumSmall { A0, A1, A2, } #[rustfmt::skip] #[allow(dead_code)] #[derive(Format)] enum EnumLarge { A000, A001, A002, A003, A004, A005, A006, A007, A008, A009, A010, A011, A012, A013, A014, A015, A016, A017, A018, A019, A020, A021, A022, A023, A024, A025, A026, A027, A028, A029, A030, A031, A032, A033, A034, A035, A036, A037, A038, A039, A040, A041, A042, A043, A044, A045, A046, A047, A048, A049, A050, A051, A052, A053, A054, A055, A056, A057, A058, A059, A060, A061, A062, A063, A064, A065, A066, A067, A068, A069, A070, A071, A072, A073, A074, A075, A076, A077, A078, A079, A080, A081, A082, A083, A084, A085, A086, A087, A088, A089, A090, A091, A092, A093, A094, A095, A096, A097, A098, A099, A100, A101, A102, A103, A104, A105, A106, A107, A108, A109, A110, A111, A112, A113, A114, A115, A116, A117, A118, A119, A120, A121, A122, A123, A124, A125, A126, A127, A128, A129, A130, A131, A132, A133, A134, A135, A136, A137, A138, A139, A140, A141, A142, A143, A144, A145, A146, A147, A148, A149, A150, A151, A152, A153, A154, A155, A156, A157, A158, A159, A160, A161, A162, A163, A164, A165, A166, A167, A168, A169, A170, A171, A172, A173, A174, A175, A176, A177, A178, A179, A180, A181, A182, A183, A184, A185, A186, A187, A188, A189, A190, A191, A192, A193, A194, A195, A196, A197, A198, A199, A200, A201, A202, A203, A204, A205, A206, A207, A208, A209, A210, A211, A212, A213, A214, A215, A216, A217, A218, A219, A220, A221, A222, A223, A224, A225, A226, A227, A228, A229, A230, A231, A232, A233, A234, A235, A236, A237, A238, A239, A240, A241, A242, A243, A244, A245, A246, A247, A248, A249, A250, A251, A252, A253, A254, A255, A256, A257, A258, A259, A260, A261, A262, A263, A264, A265, A266, A267, A268, A269, } let e = EnumSmall::A2; let index = fetch_string_index(); check_format!(&e, [index, 2u8]); let e = EnumLarge::A002; let index = fetch_string_index(); check_format!(&e, [index, 2u16]); let e = EnumLarge::A269; let index = fetch_string_index(); check_format!(&e, [index, 269u16]); } #[test] fn derive_str() { #[derive(Format)] struct S { x: &'static str, } let s = S { x: "hi" }; let index = fetch_string_index(); check_format!( &s, [ index, // "S {{ s: {:str} }}" (NOTE: `s` field is not {:?}) // so no extra format string index here 2u32, // s.x.len() 104u8, // b'h' 105u8, // b'i' ], ); } #[test] fn core_fmt_adapters() { let index = fetch_string_index(); check_format!(&Debug2Format(&123u8), [index, b'1', b'2', b'3', 0xffu8]); let index = fetch_string_index(); check_format!(&Display2Format(&123u8), [index, b'1', b'2', b'3', 0xffu8]); } defmt-0.3.5/tests/ui/derive-empty-attr.rs000064400000000000000000000001201046102023000164300ustar 00000000000000#[derive(defmt::Format)] struct S { #[defmt()] f: bool, } fn main() {} defmt-0.3.5/tests/ui/derive-empty-attr.stderr000064400000000000000000000001611046102023000173140ustar 00000000000000error: expected 1 attribute argument --> $DIR/derive-empty-attr.rs:3:7 | 3 | #[defmt()] | ^^^^^^^ defmt-0.3.5/tests/ui/derive-invalid-attr-arg.rs000064400000000000000000000001261046102023000174750ustar 00000000000000#[derive(defmt::Format)] struct S { #[defmt(FooBar)] f: bool, } fn main() {} defmt-0.3.5/tests/ui/derive-invalid-attr-arg.stderr000064400000000000000000000002211046102023000203500ustar 00000000000000error: expected `Debug2Format` or `Display2Format` --> $DIR/derive-invalid-attr-arg.rs:3:13 | 3 | #[defmt(FooBar)] | ^^^^^^ defmt-0.3.5/tests/ui/derive-multi-attr.rs000064400000000000000000000001531046102023000164320ustar 00000000000000#[derive(defmt::Format)] struct S { #[defmt(Debug2Format)] #[defmt()] f: bool, } fn main() {} defmt-0.3.5/tests/ui/derive-multi-attr.stderr000064400000000000000000000002631046102023000173130ustar 00000000000000error: multiple `defmt` attributes not supported --> $DIR/derive-multi-attr.rs:3:5 | 3 | / #[defmt(Debug2Format)] 4 | | #[defmt()] 5 | | f: bool, | |___________^ defmt-0.3.5/tests/ui/log-invalid-hint.rs000064400000000000000000000000621046102023000162200ustar 00000000000000fn main() { defmt::info!("{=u8:dunno}", 42) } defmt-0.3.5/tests/ui/log-invalid-hint.stderr000064400000000000000000000002271046102023000171020ustar 00000000000000error: unknown display hint: "dunno" --> $DIR/log-invalid-hint.rs:2:18 | 2 | defmt::info!("{=u8:dunno}", 42) | ^^^^^^^^^^^^^ defmt-0.3.5/tests/ui/panic-handler-argument.rs000064400000000000000000000001431046102023000174000ustar 00000000000000#![no_main] #![no_std] #[defmt::panic_handler] fn foo(x: bool) -> ! { info!("{:?}", x); loop {} } defmt-0.3.5/tests/ui/panic-handler-argument.stderr000064400000000000000000000002361046102023000202620ustar 00000000000000error: function must have signature `fn() -> !` --> $DIR/panic-handler-argument.rs:5:4 | 5 | fn foo(x: bool) -> ! { info!("{:?}", x); loop {} } | ^^^ defmt-0.3.5/tests/ui/panic-handler-empty.rs000064400000000000000000000000741046102023000167170ustar 00000000000000#![no_main] #![no_std] #[defmt::panic_handler] fn foo() {} defmt-0.3.5/tests/ui/panic-handler-empty.stderr000064400000000000000000000001641046102023000175760ustar 00000000000000error: function must have signature `fn() -> !` --> $DIR/panic-handler-empty.rs:5:4 | 5 | fn foo() {} | ^^^ defmt-0.3.5/tests/ui/panic-handler-export-name.rs000064400000000000000000000001471046102023000200210ustar 00000000000000#![no_main] #![no_std] #[defmt::panic_handler] #[export_name = "hello"] fn foo() -> ! { loop {} } defmt-0.3.5/tests/ui/panic-handler-export-name.stderr000064400000000000000000000002731046102023000207000ustar 00000000000000error: `#[panic_handler]` attribute cannot be used together with `#[export_name]` --> $DIR/panic-handler-export-name.rs:5:1 | 5 | #[export_name = "hello"] | ^^^^^^^^^^^^^^^^^^^^^^^^ defmt-0.3.5/tests/ui/panic-handler-no-mangle.rs000064400000000000000000000001351046102023000174340ustar 00000000000000#![no_main] #![no_std] #[defmt::panic_handler] #[no_mangle] fn panic() -> ! { loop {} } defmt-0.3.5/tests/ui/panic-handler-no-mangle.stderr000064400000000000000000000002371046102023000203160ustar 00000000000000error: `#[panic_handler]` attribute cannot be used together with `#[no_mangle]` --> $DIR/panic-handler-no-mangle.rs:5:1 | 5 | #[no_mangle] | ^^^^^^^^^^^^ defmt-0.3.5/tests/ui/write-invalid-hint.rs000064400000000000000000000002241046102023000165710ustar 00000000000000struct S; impl defmt::Format for S { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "{=u8:dunno}", 42) } } fn main() {} defmt-0.3.5/tests/ui/write-invalid-hint.stderr000064400000000000000000000002511046102023000174500ustar 00000000000000error: unknown display hint: "dunno" --> $DIR/write-invalid-hint.rs:5:26 | 5 | defmt::write!(f, "{=u8:dunno}", 42) | ^^^^^^^^^^^^^ defmt-0.3.5/tests/ui.rs000064400000000000000000000005661046102023000130640ustar 00000000000000#[test] fn ui() { // only test error messages on the stable channel (nightly may change too often) if rustc_version::version_meta() .map(|meta| meta.channel == rustc_version::Channel::Stable) .unwrap_or(false) { let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); t.pass("tests/basic_usage.rs"); } }