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")
}