Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ':cbor' hint for CBOR Diagnostic Notation (EDN) #916

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ Initial release
### [defmt-decoder-next]

* [#902] Minor change to `impl StreamDecoder` for `Raw` and `Rzcobs`, eliding a lifetime specifier to satisfy Clippy 1.83. No observable change.
* [#916] Support the ":cbor" display hint, adding new dependency `cbor-edn`.

### [defmt-decoder-v0.4.0] (2024-11-27)

Expand Down Expand Up @@ -609,6 +610,9 @@ Initial release

### [defmt-parser-next]

* [#916] Mark `DisplayHint` as `non_exhaustive`. This is a breaking change.
* [#916] Add display hint ":cbor", indicating RFC8949 encoded data to be displayed in diagnostic notation.

### [defmt-parser-v0.4.1] (2024-11-27)

* [#897] Added its own README
Expand Down
43 changes: 30 additions & 13 deletions book/src/hints.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ The hint follows the syntax `:Display` and must come after the type within the b

The following display hints are currently supported:

| hint | name |
| :----- | :------------------------------------------------------- |
| `:x` | lowercase hexadecimal |
| `:X` | uppercase hexadecimal |
| `:?` | `core::fmt::Debug`-like |
| `:b` | binary |
| `:o` | octal |
| `:a` | ASCII |
| `:ms` | timestamp in seconds (input in milliseconds) |
| `:us` | timestamp in seconds (input in microseconds) |
| `:ts` | timestamp in human-readable time (input in seconds) |
| `:tms` | timestamp in human-readable time (input in milliseconds) |
| `:tus` | timestamp in human-readable time (input in microseconds) |
| hint | name |
| :------ | :------------------------------------------------------- |
| `:x` | lowercase hexadecimal |
| `:X` | uppercase hexadecimal |
| `:?` | `core::fmt::Debug`-like |
| `:b` | binary |
| `:o` | octal |
| `:a` | ASCII |
| `:ms` | timestamp in seconds (input in milliseconds) |
| `:us` | timestamp in seconds (input in microseconds) |
| `:ts` | timestamp in human-readable time (input in seconds) |
| `:tms` | timestamp in human-readable time (input in milliseconds) |
| `:tus` | timestamp in human-readable time (input in microseconds) |
| `:cbor` | CBOR encoded items rendered in Diagnostic Notation (EDN) |

The first 4 display hints resemble what's supported in `core::fmt`, for example:

Expand All @@ -44,6 +45,22 @@ let bytes = [104, 101, 255, 108, 108, 111];
defmt::info!("{=[u8]:a}", bytes); // -> INFO b"he\xffllo"
```

The CBOR display hint is useful when CBOR data is in memory, especially before further processing:

``` rust
# extern crate defmt;
# fn parse(slice: &[u8]) -> Result<(), ()> {
# Ok(())
# }
# fn main() -> Result<(), ()> {
let id_cred = &[0xa1, 0x04, 0x44, 0x6b, 0x69, 0x64, 0x31];

defmt::info!("Peer ID: {=[u8]:cbor}", id_cred); // -> INFO Peer ID: {4: 'kid1'}
let parsed = parse(id_cred)?;
# Ok(())
# }
```

## Alternate printing

Adding `#` in front of a binary, octal, and hexadecimal display hints, precedes these numbers with a base indicator.
Expand Down
1 change: 1 addition & 0 deletions decoder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["arbitrary_precision"] }
regex = "1"
alterable_logger = "1"
cbor-edn = { version = "0.0.6", default-features = false }

[features]
# DEPRECATED: noop, will be removed in 1.0
Expand Down
10 changes: 10 additions & 0 deletions decoder/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,16 @@ impl<'t> Frame<'t> {
}
buf.push(']');
}
Some(DisplayHint::Cbor) => {
use core::fmt::Write;
let parsed = cbor_edn::Sequence::from_cbor(bytes);
match parsed {
Ok(parsed) => buf.write_str(&parsed.serialize())?,
Err(err) => {
write!(buf, "invalid CBOR (error: {}, bytes: {:02x?})", err, bytes)?
}
}
}
_ => write!(buf, "{bytes:?}")?,
}
Ok(())
Expand Down
13 changes: 13 additions & 0 deletions parser/src/display_hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::str::FromStr;

/// All display hints
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum DisplayHint {
NoHint {
zero_pad: usize,
Expand Down Expand Up @@ -40,6 +41,17 @@ pub enum DisplayHint {
disambiguator: String,
crate_name: Option<String>,
},
/// `:cbor`: There is CBOR data encoded in those bytes, to be shown in diagnostic notation.
///
/// Technically, the byte string interpreted as a CBOR sequence, and shown in the diagnostic
/// notation of a sequence. That is identical to processing a single CBOR item if there is just
/// one present, but also allows reporting multiple items from consecutive memory; diagnostic
/// notation turns those into comma separated items.
// Should we have a flag to say "do a more display style stringification" (like, if you
// recognize `54([64,h'20010db8'])`, don't show "IP'2001:db8::/64'" but just "2001:db8::64")?
// Should we allow additional params that give a CDDL that further guides processing (like,
// when data is not tagged but the shape is known for processing anyway)?
Cbor,
/// Display hints currently not supported / understood
Unknown(String),
}
Expand Down Expand Up @@ -108,6 +120,7 @@ impl DisplayHint {
},
"iso8601ms" => DisplayHint::ISO8601(TimePrecision::Millis),
"iso8601s" => DisplayHint::ISO8601(TimePrecision::Seconds),
"cbor" => DisplayHint::Cbor,
"?" => DisplayHint::Debug,
_ => return None,
})
Expand Down
Loading