-
Notifications
You must be signed in to change notification settings - Fork 207
microcbor: derivable CBOR encoding with statically-known max length #2246
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
license-eye has totally checked 603 files.
Valid | Invalid | Ignored | Fixed |
---|---|---|---|
602 | 1 | 0 | 0 |
Click to see the invalid file list
- lib/ereport/examples/test-expanded.rs
Okay, so the current approach as of e2e5106 seems to be more or less functional. But, there's one big flaw: it turns out there isn't really a way to take something like the current trait: Lines 12 to 18 in 13de2cf
and write a function like pub fn encode_ereport<'buf, E: EreportData>(
ereport: &E,
buf: &'buf mut [u8; E::MAX_CBOR_LEN],
) -> &'buf [u8] {
let mut encoder = Encoder::new(buf);
todo!()
} because this runs afoul of
This feels pretty unfortunate, as a function like this is basically the UX I was hoping to be able to have. Currently, the user can get the type to tell it what the right length for the buffer is, and use it to construct a buffer, but we can't easily have an API that ensures you use the correct-length buffer when encoding, which is too bad. We could just enable the nightly-only Another option I'm thinking about is changing the trait to something like: pub trait EreportData: Encode<()> {
/// The maximum length of the CBOR-encoded representation of this value.
///
/// The value is free to encode fewer than this many bytes, but may not
/// encode more.
const MAX_CBOR_LEN: usize;
type NeededBuf: AsRef<[u8]> + AsMut<[u8]>;
} and having the derive macro generate a pub fn encode_ereport<'buf, E: EreportData>(
ereport: &E,
buf: &'buf mut E::NeededBuf,
) -> &'buf [u8] {
// ...
} and you wouldn't be able to call it with a too-short array. But, this might be overthinking it... |
Update: nope, the approach proposed in #2246 (comment) still ends up using a generic parameter in a const expression if the type is generic over another type implementing |
Co-authored-by: Matt Keeter <[email protected]>
since the generated code depends on `microcbor`, which we can't depend on because it reexports us :(
instead of having microcbor depend on fixedstr
and, add some compile-fail doctests
When encoding ereports in Hubris, the CBOR messages are generally
simple and consist of fixed-size data. However, if buffer sizes for
encoding those messages are just chosen arbitrarily by the programmer,
it is possible that subsequent changes to the ereport messages (such as
adding a new field...) will increase the encoded size beyond the chosen
buffer size, leading to encoding failures and data loss.
Therefore, this branch adds a new crate that provides traits and derive
macros for generating CBOR encoding implementations that determine the
maximum needed buffer size at compile time, using
minicbor
. Whilethis was primarily intended for use in the ereport system, it's fairly
general purpose, so I've named the new crate
microcbor
--- sinceit's implemented using
minicbor
, and is designed for use onmicrocontrollers.
I've also added a crate for representing strings as fixed-size arrays.
This is necessary since all field values in types deriving
microcbor::Encode
must have a known maximum length at compile time,which isn't the case for strings --- even
&'static str
constants.This looks superficially similar to
heapless::String
, but it'sactually quite different: the primary purpose of this thing is to be
able to be constructable from a
&'static str
in aconst fn
,failing if it's too long to fit in the max size buffer.
heapless::String
, on the other hand, is designed to behave more likethe
alloc::string::String
type and allow the string to bemutated/appended to at runtime. But, only empty
heapless::String
scan be
const fn
constructed. Also, my thing is backed by an array,so we could potentially use it elsewhere, such as in
hubpack
orzerocopy
-encoded messages. Since this seemed generally usefulishoutside of the CBOR stuff, I stuck it in its own
fixedstr
crate.The new libraries have a bunch of documentation explaining how they
work and how to use them, so I won't duplicate it all in the commit
message. Additionally, as a sort of trial balloon for the new stuff,
I've modified the ereports from
drv_gimlet_seq_server
to use it.I'll update other tasks subsequently, but I'd like to make a
follow-up change to have
build-i2c
just generateFixedStr
s forcomponent IDs instead, and I figured it was better to keep this diff
smaller for now.
Fixes #2241