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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Tools for handling the extension encoding of CoAP options
use TryInto;
/// Nibble value for "1 byte extension"
pub const VALUE_1B: u8 = 13u8;
/// Nibble value for "2 byte extension"
pub const VALUE_2B: u8 = 14u8;
/// Nibble value reserved for the payload marker
pub const VALUE_RESERVED: u8 = 15u8;
/// The offset added to a 1-byte extended value
pub const OFFSET_1B: u16 = 13u16;
/// The offset added to a 2-byte extended value
pub const OFFSET_2B: u16 = 269u16;
/// All the ways decoding an extension value can go wrong
/// Decode an extended value.
///
/// Given a value that was initially extracted from an Option Delta or Option Length nibble of an
/// option, read up to 2 extended bytes from the slice that contains the remaining data, and
/// advance the slice by that amount.
///
/// This returns `Some(())` on success, or None to indicate any error condition (which may be
/// exhaustion of the slice, the presence of the value 15, or an overflow induced by an
/// almost-maximum value in the 2-byte extension
///
/// Typical use
/// -----------
///
/// ```
/// # use coap_message_implementations::option_extension::take_extension;
/// let data = b"\xbd\x01long-path-name\xff";
///
/// let nibble = data[0];
/// let mut delta = (nibble >> 4).into();
/// let mut length = (nibble & 0x0f).into();
///
/// let mut view = &data[1..];
/// // Delta is 11; this does not modify anything
/// take_extension(&mut delta, &mut view).unwrap();
/// // Length is 13 + 1; this takes one byte off view
/// take_extension(&mut length, &mut view).unwrap();
///
/// assert!(delta == 11);
/// assert!(length == 14);
/// assert!(&view[..14] == b"long-path-name");
/// ```
/// Write an extended option delta or length value into a vector.
///
/// The resulting nibble then needs to be shifted and stored in the respective half the previously
/// pushed value.
///
/// While this can be used to push the extension data into a
/// [`heapless::Vec`](https://docs.rs/heapless/latest/heapless/struct.Vec.html), beware that
/// heapless indicates its error condition by panicking. Before calling push_extensions on such a
/// target, the caller may want to check whether 2 more bytes (the maximum this function appends)
/// are still free.
/// Encode delta and length into a small returned buffer
///
/// This function performs all of the option encoding steps except handling the actual data value.
///
/// Typical use
/// -----------
///
/// ```
/// # use std::convert::TryInto;
/// # use coap_message_implementations::option_extension::encode_extensions;
///
/// let mut last_option = 11u16;
/// let mut buffer = heapless::Vec::<u8, 20>::new();
///
/// let option = 11u16;
/// let delta = option - last_option;
/// let last_option = option;
/// let data = b"core";
///
/// buffer.extend_from_slice(encode_extensions(
/// delta,
/// data.len().try_into().expect("Too long to express"),
/// ).as_ref()).expect("Buffer too short");
/// buffer.extend_from_slice(data).expect("Buffer too short");
///
/// assert!(buffer == b"\x04core");
///
/// ```