1use crate::{EncodeError, ParseError};
2
3#[derive(Debug)]
8pub struct OptionEncoder<'a> {
9 buf: &'a mut [u8],
10 pos: usize,
11 last_number: u16,
12 wrote_any: bool,
13}
14
15impl<'a> OptionEncoder<'a> {
16 pub fn new(buf: &'a mut [u8]) -> Self {
18 Self {
19 buf,
20 pos: 0,
21 last_number: 0,
22 wrote_any: false,
23 }
24 }
25
26 pub fn with_last_number(buf: &'a mut [u8], last_number: u16) -> Self {
28 Self {
29 buf,
30 pos: 0,
31 last_number,
32 wrote_any: true,
33 }
34 }
35
36 pub fn put(&mut self, number: u16, value: &[u8]) -> Result<(), EncodeError> {
38 if self.wrote_any && number < self.last_number {
39 return Err(EncodeError::OptionOutOfOrder);
40 }
41 let delta = if self.wrote_any {
42 number - self.last_number
43 } else {
44 number
45 };
46 let delta_len = encoded_len(delta);
47 let value_len = encoded_len(value.len() as u16);
48 let required = 1 + delta_len + value_len + value.len();
49 if self.pos + required > self.buf.len() {
50 return Err(EncodeError::BufferTooSmall);
51 }
52
53 let header_pos = self.pos;
54 self.pos += 1;
55 let delta_nibble = write_extended(&mut self.buf[self.pos..], delta)?;
56 self.pos += delta_len;
57 let len_nibble = write_extended(&mut self.buf[self.pos..], value.len() as u16)?;
58 self.pos += value_len;
59 self.buf[header_pos] = (delta_nibble << 4) | len_nibble;
60 self.buf[self.pos..self.pos + value.len()].copy_from_slice(value);
61 self.pos += value.len();
62 self.last_number = number;
63 self.wrote_any = true;
64 Ok(())
65 }
66
67 pub fn end_marker(&mut self) -> Result<(), EncodeError> {
69 if self.pos >= self.buf.len() {
70 return Err(EncodeError::BufferTooSmall);
71 }
72 self.buf[self.pos] = 0xFF;
73 self.pos += 1;
74 Ok(())
75 }
76
77 pub fn finish(self) -> usize {
79 self.pos
80 }
81}
82
83#[derive(Clone, Debug)]
88pub struct OptionDecoder<'a> {
89 data: &'a [u8],
90 pos: usize,
91 last_number: u16,
92 finished: bool,
93 errored: bool,
94}
95
96impl<'a> OptionDecoder<'a> {
97 pub fn new(data: &'a [u8]) -> Self {
99 Self {
100 data,
101 pos: 0,
102 last_number: 0,
103 finished: false,
104 errored: false,
105 }
106 }
107
108 pub fn remainder(&self) -> &'a [u8] {
113 if self.finished {
114 &self.data[self.pos..]
115 } else {
116 &[]
117 }
118 }
119}
120
121impl<'a> Iterator for OptionDecoder<'a> {
122 type Item = Result<(u16, &'a [u8]), ParseError>;
123
124 fn next(&mut self) -> Option<Self::Item> {
125 if self.finished || self.errored {
126 return None;
127 }
128 if self.pos >= self.data.len() {
129 self.errored = true;
130 return Some(Err(ParseError::MissingOptionTerminator));
131 }
132
133 let first = self.data[self.pos];
134 if first == 0xFF {
135 self.pos += 1;
136 self.finished = true;
137 return None;
138 }
139
140 self.pos += 1;
141 let delta_nibble = first >> 4;
142 let len_nibble = first & 0x0F;
143 let (delta, delta_len) = match read_extended(&self.data[self.pos..], delta_nibble) {
144 Ok(value) => value,
145 Err(err) => {
146 self.errored = true;
147 return Some(Err(err));
148 }
149 };
150 self.pos += delta_len;
151 let (len, len_len) = match read_extended(&self.data[self.pos..], len_nibble) {
152 Ok(value) => value,
153 Err(err) => {
154 self.errored = true;
155 return Some(Err(err));
156 }
157 };
158 self.pos += len_len;
159
160 if self.pos + len as usize > self.data.len() {
161 self.errored = true;
162 return Some(Err(ParseError::Truncated));
163 }
164
165 let number = self
166 .last_number
167 .checked_add(delta)
168 .ok_or(ParseError::MalformedOption);
169 let number = match number {
170 Ok(value) => value,
171 Err(err) => {
172 self.errored = true;
173 return Some(Err(err));
174 }
175 };
176 let value = &self.data[self.pos..self.pos + len as usize];
177 self.pos += len as usize;
178 self.last_number = number;
179 Some(Ok((number, value)))
180 }
181}
182
183fn encoded_len(value: u16) -> usize {
184 match value {
185 0..=12 => 0,
186 13..=268 => 1,
187 _ => 2,
188 }
189}
190
191fn write_extended(buf: &mut [u8], value: u16) -> Result<u8, EncodeError> {
192 match value {
193 0..=12 => Ok(value as u8),
194 13..=268 => {
195 if buf.is_empty() {
196 return Err(EncodeError::BufferTooSmall);
197 }
198 buf[0] = (value - 13) as u8;
199 Ok(13)
200 }
201 _ => {
202 if buf.len() < 2 {
203 return Err(EncodeError::BufferTooSmall);
204 }
205 let extended = value - 269;
206 buf[..2].copy_from_slice(&extended.to_be_bytes());
207 Ok(14)
208 }
209 }
210}
211
212fn read_extended(data: &[u8], nibble: u8) -> Result<(u16, usize), ParseError> {
213 match nibble {
214 0..=12 => Ok((nibble as u16, 0)),
215 13 => {
216 if data.is_empty() {
217 return Err(ParseError::Truncated);
218 }
219 Ok((data[0] as u16 + 13, 1))
220 }
221 14 => {
222 if data.len() < 2 {
223 return Err(ParseError::Truncated);
224 }
225 Ok((u16::from_be_bytes([data[0], data[1]]) + 269, 2))
226 }
227 _ => Err(ParseError::InvalidOptionNibble),
228 }
229}