coap_numbers/content_format.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
//! Functions for accessing CoAP Content Format numbers
//!
//! Unlike the other modules, these are not expressed as constants, for the plain reason that their
//! syntax is so far from Rust's that the names would become unwieldy (eg. `text/plain;
//! charset=utf-8` has several characters that'd all be coalesced into underscores by rules like
//! those applied for option numbers, and that's not even getting started with the ones that have
//! quotes in them).
//!
//! Instead, const functions are provided. The intention is to use them in such a way that the big
//! list of strings is only ever used at compile time.
//!
//! Maintenance note
//! ----------------
//!
//! This module's workhorse functions are sourced through files that are generated by a Python
//! script (`registry-content/build-content-formats.py`) triggered by a Makefile in the same
//! directory, and fed from IANA's published registry CSV.
//!
//! This process in intentionally only run manually, and its output is checked in to git. This
//! ensures that on every change, there is manual review (especially if new exotic characters show
//! up), that incompatible changes can be managed (although that's not that much of an issue as no
//! constants are exported from this module), and that the build process does not depend on online
//! infrastructure.
/// Workaround for lack of const comparison between strings, see
/// <https://github.com/rust-lang/rust/issues/92391>
const fn bytes_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut i = 0;
loop {
if i == a.len() {
return true;
}
if a[i] != b[i] {
return false;
}
i += 1;
}
}
/// Match a content format string representation against the list of known content formats.
///
/// The string `content_format` needs to match the value from the IANA registry verbatim; any
/// content codeing needs to be suffixed after an "@" character as described in RFC9193 for the
/// SenML Content-Format field. For the identity coding, that suffix must be omitted.
///
/// This function is not intended for embedded use, but as a tool for authors who can write
///
/// ```
/// # use coap_numbers::content_format;
/// let cf = content_format::from_str("application/cbor").unwrap();
/// ```
///
/// and thus don't need to copy around magic numbers.
pub const fn from_str(content_format: &str) -> Option<u16> {
let content_format = content_format.as_bytes();
include!("content_format_atoi.rs");
None
}
/// Turn a content format number into a content format string
///
/// See [from_str] for the string format.
///
/// This function is mainly intended for debugging.
///
/// ```
/// # use coap_numbers::content_format;
/// let cf = content_format::to_str(0).unwrap();
/// ```
pub const fn to_str(content_format: u16) -> Option<&'static str> {
include!("content_format_itoa.rs")
}