feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17624 files changed
+4564928
-38
No files matched your search
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"files":{".cargo_vcs_info.json":"650ac788af80141750b38ff765da4283bda3ff2b00c8b5d5bc2a52e88940866b","Cargo.lock":"accf550bf9bee84808fa74cdbaa3ddaa53054845b7c246582de4bc2e9c2f7cfd","Cargo.toml":"6a9ebd66fcc1f4d9da18ed2ece85156b7f43853cd993ab00d5a70583d43f6114","Cargo.toml.orig":"1dcb8e638119e957e50be2f88b364aa5b0597733e52c59fa0b97828026cf3231","README.md":"5e700d30bb71220ef88579ff9e0fec6831fe63e2d8e427365a63d6520fb80180","build.rs":"74328346bd1c202eeaac556f1c3efec14728bee128fd80295fb91cfec2bda473","defmt.x.in":"59268a679b5d7c530b2583ebe11c6bf2503447c3b3d80acc02bff2aa4f0a94b7","src/encoding/mod.rs":"5b6ce83be33b48931007dc6eb85f22ace4a0fa75b7711f707372ad51289e5ef2","src/encoding/raw.rs":"af6d8c0595839bbaf320597ef21b9902bdc7c57554a3fe0f3040819cc6d32ecc","src/encoding/rzcobs.rs":"92672511227f594a9aab87d59484ec999060b1cfe5adb04584ea9e4e20cfa90d","src/export/integers.rs":"c2e6f88a5a479daf5b70ec2dbc3a393b92d98412ab0928e9eb4fe6bed7ba8e0d","src/export/mod.rs":"d8202149e82727c4f63e60fecddc07e87b99d8d579321a74af64d31117f3deab","src/export/traits.rs":"2ea5bfed4ccea5456e4f8c85e71c059d0d61f6d9c566f58dc6dd72c2d9d5c18f","src/formatter.rs":"4db3f2387ab0755ca3c6b88925c5ad937c5c372fad8bba567a967400ef3b2442","src/impls/adapter.rs":"3ec42ba59b1a3c0c0791e7835dafbf1d4949a4cc395cd6d7b1c854afac8c9dc6","src/impls/alloc_.rs":"10b0e2912a11cea4b7dcb5669390652e4f3efc53935229f12323d9dc0b1becdc","src/impls/arrays.rs":"b51a2cd29175ab358b455456cb2438c3c79d593826a584ca2102815ee8e4f50f","src/impls/core_/alloc_.rs":"1878549b456b536f7fad14ae310bc692c740aab3562415daca0c81b881a5d065","src/impls/core_/array.rs":"fd2d973588c3a5a765a03de8184283018f6892e6ca371c7b5251853f3ab682dd","src/impls/core_/cell.rs":"1a462f04149e94baefe60d9df4667868e2775948594dc9f47840a756788821f7","src/impls/core_/mod.rs":"936431095f5a146f53e7e70a0cae50c429ab1d12e7a165d6b7d6f791e01088d4","src/impls/core_/net.rs":"9dbc9b4ba6e6f3396e4f77a3680ee5b23e971430ee5cfb974f794d02f2a53c7a","src/impls/core_/num.rs":"62fefb5f6f886be1a3567ec3635627e7d13e4f0075a68bbe3bd7126f0d8138f5","src/impls/core_/ops.rs":"faf79e49c2a77d2e680d86c5488f5e6f5a1ca772ad02d74bd6903abd466d48f4","src/impls/core_/panic.rs":"fce9ee191efbd0490ba79b156bbc5f52e02903b33821cedf3f99efd684c846cd","src/impls/core_/ptr.rs":"63c2ba3d36f0aacd3e904874e755a6e37c86b1821ef76399558cee996d65f451","src/impls/core_/slice.rs":"46b9e426b10c402cbff5f9b1b0adeec9300edd71f4c0156573692d023dcd363b","src/impls/mod.rs":"1c7e568a6fdf1d2691d892d7da0de5bf7b9309f5d3a438da092eb8df1414c394","src/impls/primitives.rs":"7a471a31aa7cb2fbf4eedda1bb355ef0dbc75f973f5b90457022275b80afac14","src/impls/tuples.rs":"dc4bf3f672aa00caccf4d92a6509ade3c4d3ef5c54d1f5cdce307d0b5f2ec0f5","src/lib.rs":"ffd5ab8179b2de36db56546ab65b219fcafa432c39f24ab9bd9f1e01d4a6a2c8","src/tests.rs":"751bf13525e9b530d79167a84fce198442397057119bd24da4fed9901f320962","src/traits.rs":"c28f959132d0517c37a2afb30ccce07ad060e6a0ca35aeed6a99d89cb0ff2235","tests/basic_usage.rs":"c96a309945a59f2ca0bb4f71492708d43157efbb66524f6ba761d6ff6a05868e","tests/derive-bounds.rs":"eb310054cc19d820d7b19487e207d6b9f9bb5607e5022124b79297a7d724e907","tests/encode.rs":"cd1057cd5e790877860af1a18adda1e813b903c4faea738e02c236774cfb1070","tests/ui.rs":"70863ba9ec109df44d0f02fdfcb6ac5f7936444bf18a2552ac2fad1709e573d1","tests/ui/derive-empty-attr.rs":"bb115212d334bbfd5972945e327c9a64563b14322308ccb9ccbb99a32b2e0288","tests/ui/derive-empty-attr.stderr":"8329a8f375be7825a7a7b5e53ca65d142b185dda78c4e13fc91b1a8c56de2bc2","tests/ui/derive-invalid-attr-arg-item.rs":"69a6fe539146127838070a0ebb05dcc69e57fd28bf125a723ecf79636e1a3187","tests/ui/derive-invalid-attr-arg-item.stderr":"a4ea6069967cd8c98ef6426a4414f7f772fea07b58a76e6cd80235ce1794d8ad","tests/ui/derive-invalid-attr-arg.rs":"2cefb1357aae0cbe510df64097969008884891095a359a69b2b889940f21f8bc","tests/ui/derive-invalid-attr-arg.stderr":"e5e739500a7a8a06e498a9b32c5ea10fdc814ddfbf37de4b88759e1dcedcda21","tests/ui/derive-invalid-crate-overwrite.rs":"839f3de8e03b050e59a8ace778f838fb42b1a8f5e6b8f080b45b3db338b1a327","tests/ui/derive-invalid-crate-overwrite.stderr":"291862d7082bd9e70ac83ade94df310fed737a7821a5d6905f20d60c23a16893","tests/ui/derive-multi-attr.rs":"7573cacc2a3aa659bd72525d9cc4b32b70e391a7a1be8bc98c052bc00685e4cd","tests/ui/derive-multi-attr.stderr":"3685b4bc7abe951184f221a1e27853d276924966261efc6d5a730edd843f802a","tests/ui/log-invalid-hint.rs":"0212228d6f934c00c9f8dd0dd7e08018812e1180e9ef6f9834a63691bf66f1de","tests/ui/log-invalid-hint.stderr":"2b8d7e9e9830afd53fcb1b901fbbc48def6c9bcd1e8515e80e03c6f47cabdc43","tests/ui/panic-handler-argument.rs":"bef9a9adfcd4589cde42791f4b167efd6ba4e9aa4ea9c32011a5088908a173a9","tests/ui/panic-handler-argument.stderr":"c15bdaca6a10c8e71a17675551ddf4d924ab4f01364972759203a479045ee2c5","tests/ui/panic-handler-empty.rs":"ed7dd8d42a1957043eb0c06f4a3d12cc27dd12ed914dd43a230da1889b6b3b39","tests/ui/panic-handler-empty.stderr":"b40a56abfb99fe1ef208bad363ead3ca7a3fbdca8cb153ae6eba76028b2fcb51","tests/ui/panic-handler-export-name.rs":"565cLine truncated
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "8459657ef6df5e6f3386512744110caef5f0612a",
|
||||
"dirty": true
|
||||
},
|
||||
"path_in_vcs": "defmt"
|
||||
}
|
||||
+375
@@ -0,0 +1,375 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "defmt"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"defmt-macros",
|
||||
"rustc_version",
|
||||
"trybuild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-macros"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
|
||||
dependencies = [
|
||||
"defmt-parser",
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-parser"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-triple"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790"
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trybuild"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ae08be68c056db96f0e6c6dd820727cca756ced9e1f4cc7fdd20e2a55e23898"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"target-triple",
|
||||
"termcolor",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
# 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 = "1.0.1"
|
||||
authors = ["The Knurling-rs developers"]
|
||||
build = "build.rs"
|
||||
links = "defmt"
|
||||
autolib = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
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"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["alloc"]
|
||||
rustdoc-args = ["--cfg=docsrs"]
|
||||
targets = [
|
||||
"thumbv6m-none-eabi",
|
||||
"thumbv7em-none-eabihf",
|
||||
]
|
||||
|
||||
[features]
|
||||
alloc = []
|
||||
avoid-default-panic = []
|
||||
encoding-raw = []
|
||||
encoding-rzcobs = []
|
||||
ip_in_core = []
|
||||
unstable-test = ["defmt-macros/unstable-test"]
|
||||
|
||||
[lib]
|
||||
name = "defmt"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[test]]
|
||||
name = "basic_usage"
|
||||
path = "tests/basic_usage.rs"
|
||||
|
||||
[[test]]
|
||||
name = "derive-bounds"
|
||||
path = "tests/derive-bounds.rs"
|
||||
|
||||
[[test]]
|
||||
name = "encode"
|
||||
path = "tests/encode.rs"
|
||||
|
||||
[[test]]
|
||||
name = "ui"
|
||||
path = "tests/ui.rs"
|
||||
|
||||
[dependencies.bitflags]
|
||||
version = "1"
|
||||
|
||||
[dependencies.defmt-macros]
|
||||
version = "=1.0.1"
|
||||
|
||||
[dev-dependencies.rustc_version]
|
||||
version = "0.4"
|
||||
|
||||
[dev-dependencies.trybuild]
|
||||
version = "1"
|
||||
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
# `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 <https://defmt.ferrous-systems.com>.
|
||||
|
||||
## 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
|
||||
|
||||
The minimum supported Rust version is 1.76 (or Ferrocene 24.05). `defmt` is tested against the latest stable Rust version and the MSRV.
|
||||
|
||||
## 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
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
use std::{env, error::Error, fs, path::PathBuf};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// Read the linker script
|
||||
let mut linker_script = fs::read_to_string("defmt.x.in")?;
|
||||
|
||||
// Optionally exclude default panic handler
|
||||
if cfg!(feature = "avoid-default-panic") {
|
||||
linker_script = avoid_default_panic(linker_script);
|
||||
}
|
||||
|
||||
// Put the linker script somewhere the linker can find it
|
||||
let out = &PathBuf::from(env::var("OUT_DIR")?);
|
||||
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");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// allow #[cfg(cfg_name)]
|
||||
for cfg_name in ["c_variadic", "no_cas"] {
|
||||
println!("cargo:rustc-check-cfg=cfg({cfg_name})");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn avoid_default_panic(linker_script: String) -> String {
|
||||
linker_script.replacen("PROVIDE(_defmt_panic = __defmt_default_panic);", "", 1)
|
||||
}
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
/* 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.*);
|
||||
|
||||
/* We order the ids of the log messages by severity and put markers in between, so that we can filter logs at runtime by severity */
|
||||
__DEFMT_MARKER_TRACE_START = .;
|
||||
*(.defmt.trace.*);
|
||||
__DEFMT_MARKER_TRACE_END = .;
|
||||
__DEFMT_MARKER_DEBUG_START = .;
|
||||
*(.defmt.debug.*);
|
||||
__DEFMT_MARKER_DEBUG_END = .;
|
||||
__DEFMT_MARKER_INFO_START = .;
|
||||
*(.defmt.info.*);
|
||||
__DEFMT_MARKER_INFO_END = .;
|
||||
__DEFMT_MARKER_WARN_START = .;
|
||||
*(.defmt.warn.*);
|
||||
__DEFMT_MARKER_WARN_END = .;
|
||||
__DEFMT_MARKER_ERROR_START = .;
|
||||
*(.defmt.error.*);
|
||||
__DEFMT_MARKER_ERROR_END = .;
|
||||
|
||||
/* 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");
|
||||
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
#[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`.
|
||||
#[allow(clippy::new_without_default)]
|
||||
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)
|
||||
}
|
||||
}
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
pub(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)
|
||||
}
|
||||
}
|
||||
Vendored
+267
@@ -0,0 +1,267 @@
|
||||
// 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<u8> = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
use 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())
|
||||
}
|
||||
Vendored
+235
@@ -0,0 +1,235 @@
|
||||
mod 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 = const { core::sync::atomic::AtomicU16::new(0) };
|
||||
static BYTES: core::cell::RefCell<Vec<u8>> = const { 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<u8> {
|
||||
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<T>(x: impl traits::Truncate<T>) -> T {
|
||||
x.truncate()
|
||||
}
|
||||
|
||||
pub fn into_result<T: traits::IntoResult>(x: T) -> Result<T::Ok, T::Error> {
|
||||
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<T: Format + ?Sized>(f: &T) {
|
||||
istr(&T::_format_tag());
|
||||
f._format_data();
|
||||
}
|
||||
|
||||
/// Implementation detail
|
||||
pub fn fmt_slice<T: Format>(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<T: Format>(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 unsafe fn acquire_and_header(s: &Str) {
|
||||
acquire();
|
||||
istr(s);
|
||||
timestamp(make_formatter());
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn acquire_header_and_release(s: &Str) {
|
||||
// safety: will be released a few lines further down
|
||||
unsafe { acquire() };
|
||||
istr(s);
|
||||
timestamp(make_formatter());
|
||||
// safety: acquire() was called a few lines above
|
||||
unsafe { release() };
|
||||
}
|
||||
|
||||
struct FmtWrite;
|
||||
|
||||
impl core::fmt::Write for FmtWrite {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
write(s.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Vendored
+82
@@ -0,0 +1,82 @@
|
||||
#[allow(unused_imports)]
|
||||
use crate as defmt;
|
||||
use crate::{Format, Formatter, Str};
|
||||
|
||||
pub trait Truncate<U> {
|
||||
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<X> 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<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T> IntoResult for Option<T> {
|
||||
type Ok = T;
|
||||
type Error = NoneError;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Result<T, NoneError> {
|
||||
self.ok_or(NoneError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> IntoResult for Result<T, E> {
|
||||
type Ok = T;
|
||||
type Error = E;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
use 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,
|
||||
}
|
||||
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
use 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<T: fmt::Debug + ?Sized> fmt::Debug for Debug2Format<'_, T> {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||
self.0.fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug + ?Sized> 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<T: fmt::Display + ?Sized> fmt::Display for Display2Format<'_, T> {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||
self.0.fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display + ?Sized> Format for Display2Format<'_, T> {
|
||||
default_format!();
|
||||
|
||||
fn _format_tag() -> Str {
|
||||
defmt_macros::internp!("{=__internal_Display}")
|
||||
}
|
||||
|
||||
fn _format_data(&self) {
|
||||
export::display(&self.0);
|
||||
}
|
||||
}
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
use super::*;
|
||||
|
||||
impl<T> Format for alloc::boxed::Box<T>
|
||||
where
|
||||
T: ?Sized + Format,
|
||||
{
|
||||
delegate_format!(T, self, &*self);
|
||||
}
|
||||
|
||||
impl<T> Format for alloc::rc::Rc<T>
|
||||
where
|
||||
T: ?Sized + Format,
|
||||
{
|
||||
delegate_format!(T, self, &*self);
|
||||
}
|
||||
|
||||
#[cfg(not(no_cas))]
|
||||
impl<T> Format for alloc::sync::Arc<T>
|
||||
where
|
||||
T: ?Sized + Format,
|
||||
{
|
||||
delegate_format!(T, self, &*self);
|
||||
}
|
||||
|
||||
impl<T> Format for alloc::vec::Vec<T>
|
||||
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<Owned = alloc::vec::Vec<T>>,
|
||||
{
|
||||
delegate_format!([T], self, self.as_ref());
|
||||
}
|
||||
|
||||
impl<'a> Format for alloc::borrow::Cow<'a, str> {
|
||||
delegate_format!(str, self, self.as_ref());
|
||||
}
|
||||
Vendored
+100
@@ -0,0 +1,100 @@
|
||||
use super::*;
|
||||
use crate::export;
|
||||
|
||||
macro_rules! arrays {
|
||||
( $($len:literal $fmt:literal,)+ ) => {
|
||||
impl<T, const N: usize> 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]}",
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
use core::alloc;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl Format for alloc::Layout {
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(
|
||||
fmt,
|
||||
"Layout {{ size: {}, align: {} }}",
|
||||
self.size(),
|
||||
self.align()
|
||||
);
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
use core::array;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl Format for array::TryFromSliceError {
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "TryFromSliceError(())");
|
||||
}
|
||||
}
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
use super::*;
|
||||
|
||||
impl<T> Format for core::cell::Cell<T>
|
||||
where
|
||||
T: Format + Copy,
|
||||
{
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "Cell {{ value: {=?} }})", self.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Format for core::cell::RefCell<T>
|
||||
where
|
||||
T: Format,
|
||||
{
|
||||
default_format!();
|
||||
|
||||
#[inline]
|
||||
fn _format_tag() -> Str {
|
||||
internp!("RefCell {{ value: <borrowed> }}|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")
|
||||
}
|
||||
}
|
||||
Vendored
+120
@@ -0,0 +1,120 @@
|
||||
//! 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 panic;
|
||||
mod ptr;
|
||||
mod slice;
|
||||
|
||||
use super::*;
|
||||
use crate::export;
|
||||
|
||||
impl<T> Format for Option<T>
|
||||
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<T, E> Format for Result<T, E>
|
||||
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<T> Format for core::marker::PhantomData<T> {
|
||||
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<A, B> Format for core::iter::Zip<A, B>
|
||||
where
|
||||
A: Format,
|
||||
B: Format,
|
||||
{
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "Zip(..)")
|
||||
}
|
||||
}
|
||||
Vendored
+72
@@ -0,0 +1,72 @@
|
||||
use 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
use 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(())");
|
||||
}
|
||||
}
|
||||
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
use super::*;
|
||||
|
||||
impl<Idx> Format for core::ops::Range<Idx>
|
||||
where
|
||||
Idx: Format,
|
||||
{
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "{}..{}", self.start, self.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx> Format for core::ops::RangeFrom<Idx>
|
||||
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<Idx> Format for core::ops::RangeInclusive<Idx>
|
||||
where
|
||||
Idx: Format,
|
||||
{
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "{}..={}", self.start(), self.end())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx> Format for core::ops::RangeTo<Idx>
|
||||
where
|
||||
Idx: Format,
|
||||
{
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "..{}", self.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Idx> Format for core::ops::RangeToInclusive<Idx>
|
||||
where
|
||||
Idx: Format,
|
||||
{
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "..={}", self.end)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
use core::panic;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl Format for panic::PanicInfo<'_> {
|
||||
fn format(&self, f: Formatter) {
|
||||
if let Some(location) = self.location() {
|
||||
crate::write!(f, "panicked at {}", location);
|
||||
} else {
|
||||
crate::write!(f, "panicked");
|
||||
}
|
||||
// TODO: consider supporting self.message() once stabilized, or add a crate feature for
|
||||
// conditional support
|
||||
}
|
||||
}
|
||||
|
||||
impl Format for panic::Location<'_> {
|
||||
fn format(&self, f: Formatter) {
|
||||
crate::write!(
|
||||
f,
|
||||
"{=str}:{=u32}:{=u32}",
|
||||
self.file(),
|
||||
self.line(),
|
||||
self.column()
|
||||
);
|
||||
}
|
||||
}
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
use super::*;
|
||||
|
||||
impl<T> Format for core::ptr::NonNull<T> {
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "{}", self.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(c_variadic)]
|
||||
macro_rules! fnptr_format_cvariadic {
|
||||
($($Arg:ident),+) => {
|
||||
impl<Ret, $($Arg),*> Format for extern "C" fn($($Arg),* , ...) -> Ret {
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "{}", (*self as usize) as *const ())
|
||||
}
|
||||
}
|
||||
impl<Ret, $($Arg),*> 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<Ret, $($Arg),*> Format for extern "Rust" fn($($Arg),*) -> Ret {
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "{}", (*self as usize) as *const ())
|
||||
}
|
||||
}
|
||||
impl<Ret, $($Arg),*> Format for extern "C" fn($($Arg),*) -> Ret {
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "{}", (*self as usize) as *const ())
|
||||
}
|
||||
}
|
||||
impl<Ret, $($Arg),*> Format for unsafe extern "Rust" fn($($Arg),*) -> Ret {
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "{}", (*self as usize) as *const ())
|
||||
}
|
||||
}
|
||||
impl<Ret, $($Arg),*> 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 }
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
use 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(..)")
|
||||
}
|
||||
}
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
macro_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};
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
use 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<T> Format for [T]
|
||||
where
|
||||
T: Format,
|
||||
{
|
||||
default_format!();
|
||||
|
||||
#[inline]
|
||||
fn _format_tag() -> Str {
|
||||
internp!("{=[?]}")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _format_data(&self) {
|
||||
export::fmt_slice(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Format for &'_ T
|
||||
where
|
||||
T: Format + ?Sized,
|
||||
{
|
||||
delegate_format!(T, self, self);
|
||||
}
|
||||
|
||||
impl<T> 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<T> Format for *const T
|
||||
where
|
||||
T: ?Sized,
|
||||
{
|
||||
fn format(&self, fmt: Formatter) {
|
||||
crate::write!(fmt, "0x{:x}", *self as *const () as usize);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Format for *mut T
|
||||
where
|
||||
T: ?Sized,
|
||||
{
|
||||
fn format(&self, fmt: Formatter) {
|
||||
Format::format(&(*self as *const T), fmt)
|
||||
}
|
||||
}
|
||||
Vendored
+55
@@ -0,0 +1,55 @@
|
||||
use 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) }
|
||||
Vendored
+467
@@ -0,0 +1,467 @@
|
||||
//! A highly efficient logging framework that targets resource-constrained
|
||||
//! devices, like microcontrollers.
|
||||
//!
|
||||
//! Check out the defmt book at <https://defmt.ferrous-systems.com> for more
|
||||
//! information about how to use it.
|
||||
//!
|
||||
//! # Compatibility
|
||||
//!
|
||||
//! The `defmt` wire format might change between minor versions. Attempting to
|
||||
//! read a defmt stream with an incompatible version will result in an error,
|
||||
//! and any tool used to process that stream should first check for a symbol
|
||||
//! named like `_defmt_version_ = X`, where X indicates the wire format version
|
||||
//! in use.
|
||||
//!
|
||||
//! Updating your version of defmt might mean you also have to update your
|
||||
//! version of `defmt-print` or `defmt-decoder`.
|
||||
|
||||
#![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(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<T, E>` 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 x = result.expect("text");
|
||||
/// let x = unwrap!(result, "text");
|
||||
///
|
||||
/// # let arg = ();
|
||||
/// let x = result.expect(&format!("text {:?}", arg));
|
||||
/// let x = unwrap!(result, "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;
|
||||
|
||||
/// This is an alias for defmt's [`unwrap`] macro which supports messages like std's except.
|
||||
/// ```
|
||||
/// use defmt::expect;
|
||||
///
|
||||
/// # let result = Ok::<(), ()>(());
|
||||
/// # let arg = ();
|
||||
/// let x = result.expect(&format!("text {:?}", arg));
|
||||
/// let x = expect!(result, "text {:?}", arg); // arg must be implement `Format`
|
||||
/// ```
|
||||
///
|
||||
/// For the complete documentation see that of defmt's *unwrap* macro.
|
||||
// note: Linking to unwrap is broken as of 2024-10-09, it links back to expect
|
||||
pub use defmt_macros::unwrap as expect;
|
||||
|
||||
/// 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unstable-test"))]
|
||||
#[doc(hidden)]
|
||||
pub struct IdRanges {
|
||||
pub trace: core::ops::Range<u16>,
|
||||
pub debug: core::ops::Range<u16>,
|
||||
pub info: core::ops::Range<u16>,
|
||||
pub warn: core::ops::Range<u16>,
|
||||
pub error: core::ops::Range<u16>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unstable-test"))]
|
||||
impl IdRanges {
|
||||
pub fn get() -> Self {
|
||||
extern "C" {
|
||||
static __DEFMT_MARKER_TRACE_START: u8;
|
||||
static __DEFMT_MARKER_TRACE_END: u8;
|
||||
static __DEFMT_MARKER_DEBUG_START: u8;
|
||||
static __DEFMT_MARKER_DEBUG_END: u8;
|
||||
static __DEFMT_MARKER_INFO_START: u8;
|
||||
static __DEFMT_MARKER_INFO_END: u8;
|
||||
static __DEFMT_MARKER_WARN_START: u8;
|
||||
static __DEFMT_MARKER_WARN_END: u8;
|
||||
static __DEFMT_MARKER_ERROR_START: u8;
|
||||
static __DEFMT_MARKER_ERROR_END: u8;
|
||||
}
|
||||
|
||||
let trace_start = unsafe { &__DEFMT_MARKER_TRACE_START as *const u8 as u16 };
|
||||
let trace_end = unsafe { &__DEFMT_MARKER_TRACE_END as *const u8 as u16 };
|
||||
let debug_start = unsafe { &__DEFMT_MARKER_DEBUG_START as *const u8 as u16 };
|
||||
let debug_end = unsafe { &__DEFMT_MARKER_DEBUG_END as *const u8 as u16 };
|
||||
let info_start = unsafe { &__DEFMT_MARKER_INFO_START as *const u8 as u16 };
|
||||
let info_end = unsafe { &__DEFMT_MARKER_INFO_END as *const u8 as u16 };
|
||||
let warn_start = unsafe { &__DEFMT_MARKER_WARN_START as *const u8 as u16 };
|
||||
let warn_end = unsafe { &__DEFMT_MARKER_WARN_END as *const u8 as u16 };
|
||||
let error_start = unsafe { &__DEFMT_MARKER_ERROR_START as *const u8 as u16 };
|
||||
let error_end = unsafe { &__DEFMT_MARKER_ERROR_END as *const u8 as u16 };
|
||||
Self {
|
||||
trace: trace_start..trace_end,
|
||||
debug: debug_start..debug_end,
|
||||
info: info_start..info_end,
|
||||
warn: warn_start..warn_end,
|
||||
error: error_start..error_end,
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
use 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,);
|
||||
}
|
||||
Vendored
+131
@@ -0,0 +1,131 @@
|
||||
use 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);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// **Note** Some implementations of standard types like `Vec<T>` are hidden behind the `alloc` feature flag.
|
||||
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]);
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
fn 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);
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
extern crate defmt as defmt2;
|
||||
|
||||
fn main() {
|
||||
let baz: Baz<Qux> = Default::default();
|
||||
defmt::info!("{}", baz);
|
||||
}
|
||||
|
||||
trait Foo {
|
||||
type Bar;
|
||||
}
|
||||
#[derive(defmt::Format, Default)]
|
||||
struct Baz<T: Foo> {
|
||||
field: T::Bar,
|
||||
field2: Quux<T>,
|
||||
}
|
||||
#[derive(defmt::Format, Default)]
|
||||
struct Qux;
|
||||
impl Foo for Qux {
|
||||
type Bar = Qux;
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(defmt::Format, Default)]
|
||||
enum Quux<T: Foo> {
|
||||
#[default]
|
||||
None,
|
||||
Variant1(T),
|
||||
Variant2 {
|
||||
f: T::Bar,
|
||||
},
|
||||
Variant3(T::Bar),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(defmt::Format)]
|
||||
#[defmt(crate = defmt2)]
|
||||
struct Quz;
|
||||
Vendored
+1011
File diff suppressed because it is too large.
Load diff
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
#[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)
|
||||
&& std::env::var_os("SKIP_UI_TESTS").is_none()
|
||||
{
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/ui/*.rs");
|
||||
|
||||
t.pass("tests/basic_usage.rs");
|
||||
t.pass("tests/derive-bounds.rs");
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
#[derive(defmt::Format)]
|
||||
struct S {
|
||||
#[defmt()]
|
||||
f: bool,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: expected 1 attribute argument
|
||||
--> $DIR/derive-empty-attr.rs:3:7
|
||||
|
|
||||
3 | #[defmt()]
|
||||
| ^^^^^^^
|
||||
@@ -0,0 +1,7 @@
|
||||
#[derive(defmt::Format)]
|
||||
#[defmt(FooBar)]
|
||||
struct S {
|
||||
f: bool,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: unknown defmt attribute `FooBar`
|
||||
--> tests/ui/derive-invalid-attr-arg-item.rs:2:9
|
||||
|
|
||||
2 | #[defmt(FooBar)]
|
||||
| ^^^^^^
|
||||
@@ -0,0 +1,7 @@
|
||||
#[derive(defmt::Format)]
|
||||
struct S {
|
||||
#[defmt(FooBar)]
|
||||
f: bool,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: expected `Debug2Format` or `Display2Format`
|
||||
--> $DIR/derive-invalid-attr-arg.rs:3:13
|
||||
|
|
||||
3 | #[defmt(FooBar)]
|
||||
| ^^^^^^
|
||||
@@ -0,0 +1,13 @@
|
||||
#[derive(defmt::Format)]
|
||||
#[defmt(crate = unresolved)]
|
||||
struct S {}
|
||||
|
||||
#[derive(defmt::Format)]
|
||||
#[defmt(crate = "not a path")]
|
||||
struct S2 {}
|
||||
|
||||
#[derive(defmt::Format)]
|
||||
#[defmt(crate(defmt))]
|
||||
struct S3 {}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,25 @@
|
||||
error: expected identifier
|
||||
--> tests/ui/derive-invalid-crate-overwrite.rs:6:17
|
||||
|
|
||||
6 | #[defmt(crate = "not a path")]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: expected `=`
|
||||
--> tests/ui/derive-invalid-crate-overwrite.rs:10:14
|
||||
|
|
||||
10 | #[defmt(crate(defmt))]
|
||||
| ^
|
||||
|
||||
error[E0432]: unresolved import `unresolved`
|
||||
--> tests/ui/derive-invalid-crate-overwrite.rs:1:10
|
||||
|
|
||||
1 | #[derive(defmt::Format)]
|
||||
| ^^^^^^^^^^^^^ no external crate `unresolved`
|
||||
|
|
||||
= note: this error originates in the derive macro `defmt::Format` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0433]: failed to resolve: use of undeclared crate or module `unresolved`
|
||||
--> tests/ui/derive-invalid-crate-overwrite.rs:2:17
|
||||
|
|
||||
2 | #[defmt(crate = unresolved)]
|
||||
| ^^^^^^^^^^ use of undeclared crate or module `unresolved`
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#[derive(defmt::Format)]
|
||||
struct S {
|
||||
#[defmt(Debug2Format)]
|
||||
#[defmt()]
|
||||
f: bool,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,7 @@
|
||||
error: multiple `defmt` attributes not supported
|
||||
--> $DIR/derive-multi-attr.rs:3:5
|
||||
|
|
||||
3 | / #[defmt(Debug2Format)]
|
||||
4 | | #[defmt()]
|
||||
5 | | f: bool,
|
||||
| |___________^
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
defmt::info!("{=u8:dunno}", 42)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: unknown display hint: "dunno"
|
||||
--> $DIR/log-invalid-hint.rs:2:18
|
||||
|
|
||||
2 | defmt::info!("{=u8:dunno}", 42)
|
||||
| ^^^^^^^^^^^^^
|
||||
@@ -0,0 +1,5 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[defmt::panic_handler]
|
||||
fn foo(x: bool) -> ! { info!("{:?}", x); loop {} }
|
||||
@@ -0,0 +1,5 @@
|
||||
error: function must have signature `fn() -> !`
|
||||
--> $DIR/panic-handler-argument.rs:5:4
|
||||
|
|
||||
5 | fn foo(x: bool) -> ! { info!("{:?}", x); loop {} }
|
||||
| ^^^
|
||||
@@ -0,0 +1,5 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[defmt::panic_handler]
|
||||
fn foo() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: function must have signature `fn() -> !`
|
||||
--> $DIR/panic-handler-empty.rs:5:4
|
||||
|
|
||||
5 | fn foo() {}
|
||||
| ^^^
|
||||
@@ -0,0 +1,8 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[defmt::panic_handler]
|
||||
#[export_name = "hello"]
|
||||
fn foo() -> ! {
|
||||
loop {}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: `#[panic_handler]` attribute cannot be used together with `#[export_name]`
|
||||
--> $DIR/panic-handler-export-name.rs:5:1
|
||||
|
|
||||
5 | #[export_name = "hello"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -0,0 +1,8 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[defmt::panic_handler]
|
||||
#[no_mangle]
|
||||
fn panic() -> ! {
|
||||
loop {}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: `#[panic_handler]` attribute cannot be used together with `#[no_mangle]`
|
||||
--> $DIR/panic-handler-no-mangle.rs:5:1
|
||||
|
|
||||
5 | #[no_mangle]
|
||||
| ^^^^^^^^^^^^
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
struct S;
|
||||
|
||||
impl defmt::Format for S {
|
||||
fn format(&self, f: defmt::Formatter) {
|
||||
defmt::write!(f, "{=u8:dunno}", 42)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: unknown display hint: "dunno"
|
||||
--> $DIR/write-invalid-hint.rs:5:26
|
||||
|
|
||||
5 | defmt::write!(f, "{=u8:dunno}", 42)
|
||||
| ^^^^^^^^^^^^^
|
||||
Reference in new issue
Block a user