1use crate::error::{MqttError, Result};
7use bebytes::BeBytes;
8use bytes::{Buf, BufMut};
9use std::fmt;
10
11pub const VARIABLE_INT_MAX: u32 = 268_435_455;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub struct VariableInt {
23 value: u32,
24}
25
26impl VariableInt {
27 pub fn new(value: u32) -> Result<Self> {
33 if value > VARIABLE_INT_MAX {
34 return Err(MqttError::ProtocolError(format!(
35 "Variable integer value {value} exceeds maximum {VARIABLE_INT_MAX}"
36 )));
37 }
38 Ok(Self { value })
39 }
40
41 #[must_use]
47 pub fn new_unchecked(value: u32) -> Self {
48 debug_assert!(value <= VARIABLE_INT_MAX);
49 Self { value }
50 }
51
52 #[must_use]
54 pub fn value(&self) -> u32 {
55 self.value
56 }
57
58 #[must_use]
60 pub fn encoded_size(&self) -> u32 {
61 match self.value {
62 0..=127 => 1,
63 128..=16_383 => 2,
64 16_384..=2_097_151 => 3,
65 2_097_152..=VARIABLE_INT_MAX => 4,
66 _ => unreachable!("Invalid variable int value"),
67 }
68 }
69
70 pub fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
76 let mut val = self.value;
77 loop {
78 let mut byte = (val % 128) as u8;
79 val /= 128;
80 if val > 0 {
81 byte |= 0x80; }
83 buf.put_u8(byte);
84 if val == 0 {
85 break;
86 }
87 }
88 Ok(())
89 }
90
91 pub fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
100 let mut value = 0u32;
101 let mut multiplier = 1u32;
102 let mut byte_count = 0;
103
104 loop {
105 if !buf.has_remaining() {
106 return Err(MqttError::MalformedPacket(
107 "Insufficient bytes for variable integer".to_string(),
108 ));
109 }
110
111 byte_count += 1;
112 if byte_count > 4 {
113 return Err(MqttError::MalformedPacket(
114 "Variable integer exceeds 4 bytes".to_string(),
115 ));
116 }
117
118 let byte = buf.get_u8();
119 value += u32::from(byte & 0x7F) * multiplier;
120
121 if (byte & 0x80) == 0 {
122 break;
123 }
124
125 multiplier *= 128;
126 if multiplier > 128 * 128 * 128 {
127 return Err(MqttError::MalformedPacket(
128 "Variable integer overflow".to_string(),
129 ));
130 }
131 }
132
133 if value > VARIABLE_INT_MAX {
134 return Err(MqttError::MalformedPacket(format!(
135 "Variable integer value {value} exceeds maximum"
136 )));
137 }
138
139 Ok(Self { value })
140 }
141}
142
143impl fmt::Display for VariableInt {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 write!(f, "{}", self.value)
146 }
147}
148
149impl From<VariableInt> for u32 {
150 fn from(v: VariableInt) -> Self {
151 v.value
152 }
153}
154
155impl TryFrom<u32> for VariableInt {
156 type Error = MqttError;
157
158 fn try_from(value: u32) -> Result<Self> {
159 Self::new(value)
160 }
161}
162
163impl TryFrom<usize> for VariableInt {
164 type Error = MqttError;
165
166 fn try_from(value: usize) -> Result<Self> {
167 let value = u32::try_from(value).map_err(|_| {
168 MqttError::ProtocolError("Value too large for variable integer".to_string())
169 })?;
170 Self::new(value)
171 }
172}
173
174impl BeBytes for VariableInt {
176 fn field_size() -> usize {
177 0
179 }
180
181 fn to_be_bytes(&self) -> Vec<u8> {
182 let mut buf = Vec::new();
183 let _ = self.encode(&mut buf); buf
185 }
186
187 fn try_from_be_bytes(
188 bytes: &[u8],
189 ) -> std::result::Result<(Self, usize), bebytes::BeBytesError> {
190 use bytes::Bytes;
191 let mut buf = Bytes::copy_from_slice(bytes);
192 let start_len = buf.len();
193
194 match Self::decode(&mut buf) {
195 Ok(var_int) => {
196 let consumed = start_len - buf.len();
197 Ok((var_int, consumed))
198 }
199 Err(_) => Err(bebytes::BeBytesError::InsufficientData {
200 expected: 1, actual: bytes.len(),
202 }),
203 }
204 }
205
206 fn to_le_bytes(&self) -> Vec<u8> {
207 self.to_be_bytes()
209 }
210
211 fn try_from_le_bytes(
212 bytes: &[u8],
213 ) -> std::result::Result<(Self, usize), bebytes::BeBytesError> {
214 Self::try_from_be_bytes(bytes)
216 }
217}
218
219pub fn encode_variable_int<B: BufMut>(buf: &mut B, value: u32) -> Result<()> {
228 VariableInt::new(value)?.encode(buf)
229}
230
231pub fn decode_variable_int<B: Buf>(buf: &mut B) -> Result<u32> {
240 Ok(VariableInt::decode(buf)?.value())
241}
242
243#[must_use]
248pub fn variable_int_len(value: u32) -> usize {
249 VariableInt::new_unchecked(value.min(VARIABLE_INT_MAX)).encoded_size() as usize
250}
251
252#[must_use]
254pub fn encoded_variable_int_len(value: u32) -> usize {
255 variable_int_len(value)
256}
257
258pub const VARIABLE_BYTE_INT_MAX: u32 = VARIABLE_INT_MAX;
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264 use bytes::BytesMut;
265
266 #[test]
267 fn test_new_valid_values() {
268 assert!(VariableInt::new(0).is_ok());
269 assert!(VariableInt::new(127).is_ok());
270 assert!(VariableInt::new(128).is_ok());
271 assert!(VariableInt::new(16_383).is_ok());
272 assert!(VariableInt::new(16_384).is_ok());
273 assert!(VariableInt::new(2_097_151).is_ok());
274 assert!(VariableInt::new(2_097_152).is_ok());
275 assert!(VariableInt::new(VARIABLE_INT_MAX).is_ok());
276 }
277
278 #[test]
279 fn test_new_invalid_values() {
280 assert!(VariableInt::new(VARIABLE_INT_MAX + 1).is_err());
281 assert!(VariableInt::new(u32::MAX).is_err());
282 }
283
284 #[test]
285 fn test_encoded_size() {
286 assert_eq!(VariableInt::new_unchecked(0).encoded_size(), 1);
287 assert_eq!(VariableInt::new_unchecked(127).encoded_size(), 1);
288 assert_eq!(VariableInt::new_unchecked(128).encoded_size(), 2);
289 assert_eq!(VariableInt::new_unchecked(16_383).encoded_size(), 2);
290 assert_eq!(VariableInt::new_unchecked(16_384).encoded_size(), 3);
291 assert_eq!(VariableInt::new_unchecked(2_097_151).encoded_size(), 3);
292 assert_eq!(VariableInt::new_unchecked(2_097_152).encoded_size(), 4);
293 assert_eq!(
294 VariableInt::new_unchecked(VARIABLE_INT_MAX).encoded_size(),
295 4
296 );
297 }
298
299 #[test]
300 fn test_encode_decode_single_byte() {
301 let mut buf = BytesMut::new();
302
303 for value in [0, 1, 64, 127] {
304 buf.clear();
305 let var_int = VariableInt::new(value).unwrap();
306 var_int.encode(&mut buf).unwrap();
307 assert_eq!(buf.len(), 1);
308
309 let decoded = VariableInt::decode(&mut buf).unwrap();
310 assert_eq!(decoded.value(), value);
311 }
312 }
313
314 #[test]
315 fn test_encode_decode_two_bytes() {
316 let mut buf = BytesMut::new();
317
318 for value in [128, 129, 321, 16_383] {
319 buf.clear();
320 let var_int = VariableInt::new(value).unwrap();
321 var_int.encode(&mut buf).unwrap();
322 assert_eq!(buf.len(), 2);
323
324 let decoded = VariableInt::decode(&mut buf).unwrap();
325 assert_eq!(decoded.value(), value);
326 }
327 }
328
329 #[test]
330 fn test_encode_decode_three_bytes() {
331 let mut buf = BytesMut::new();
332
333 for value in [16_384, 65_535, 2_097_151] {
334 buf.clear();
335 let var_int = VariableInt::new(value).unwrap();
336 var_int.encode(&mut buf).unwrap();
337 assert_eq!(buf.len(), 3);
338
339 let decoded = VariableInt::decode(&mut buf).unwrap();
340 assert_eq!(decoded.value(), value);
341 }
342 }
343
344 #[test]
345 fn test_encode_decode_four_bytes() {
346 let mut buf = BytesMut::new();
347
348 for value in [2_097_152, 10_000_000, VARIABLE_INT_MAX] {
349 buf.clear();
350 let var_int = VariableInt::new(value).unwrap();
351 var_int.encode(&mut buf).unwrap();
352 assert_eq!(buf.len(), 4);
353
354 let decoded = VariableInt::decode(&mut buf).unwrap();
355 assert_eq!(decoded.value(), value);
356 }
357 }
358
359 #[test]
360 fn test_mqtt_spec_examples() {
361 let mut buf = BytesMut::new();
362
363 let var_int = VariableInt::new(64).unwrap();
365 var_int.encode(&mut buf).unwrap();
366 assert_eq!(buf[0], 0x40);
367
368 buf.clear();
370 let var_int = VariableInt::new(321).unwrap();
371 var_int.encode(&mut buf).unwrap();
372 assert_eq!(buf[0], 0xC1);
373 assert_eq!(buf[1], 0x02);
374 }
375
376 #[test]
377 fn test_bebytes_integration() {
378 use bebytes::BeBytes;
379
380 let var_int = VariableInt::new(321).unwrap();
382 let bytes = var_int.to_be_bytes();
383 assert_eq!(bytes.len(), 2);
384 assert_eq!(bytes[0], 0xC1);
385 assert_eq!(bytes[1], 0x02);
386
387 let (decoded, consumed) = VariableInt::try_from_be_bytes(&bytes).unwrap();
389 assert_eq!(decoded.value(), 321);
390 assert_eq!(consumed, 2);
391
392 assert_eq!(VariableInt::field_size(), 0); }
395
396 #[test]
397 fn test_decode_insufficient_bytes() {
398 let mut buf = BytesMut::new();
399 buf.put_u8(0x80); let result = VariableInt::decode(&mut buf);
402 assert!(result.is_err());
403 }
404
405 #[test]
406 fn test_decode_too_many_bytes() {
407 let mut buf = BytesMut::new();
408 buf.put_u8(0x80);
410 buf.put_u8(0x80);
411 buf.put_u8(0x80);
412 buf.put_u8(0x80);
413 buf.put_u8(0x01);
414
415 let result = VariableInt::decode(&mut buf);
416 assert!(result.is_err());
417 }
418
419 #[test]
420 fn test_conversions() {
421 let var_int = VariableInt::new(123).unwrap();
422
423 let value: u32 = var_int.into();
425 assert_eq!(value, 123);
426
427 let var_int2 = VariableInt::try_from(456u32).unwrap();
429 assert_eq!(var_int2.value(), 456);
430
431 let var_int3 = VariableInt::try_from(789usize).unwrap();
433 assert_eq!(var_int3.value(), 789);
434
435 assert!(VariableInt::try_from(VARIABLE_INT_MAX + 1).is_err());
437 }
438
439 #[test]
440 fn test_display() {
441 let var_int = VariableInt::new(12345).unwrap();
442 assert_eq!(format!("{var_int}"), "12345");
443 }
444
445 #[cfg(test)]
446 mod property_tests {
447 use super::*;
448 use proptest::prelude::*;
449
450 proptest! {
451 #[test]
452 fn prop_round_trip(value in 0u32..=VARIABLE_INT_MAX) {
453 let mut buf = BytesMut::new();
454
455 let var_int = VariableInt::new(value).unwrap();
456 var_int.encode(&mut buf).unwrap();
457 let decoded = VariableInt::decode(&mut buf).unwrap();
458
459 prop_assert_eq!(decoded.value(), value);
460 }
461
462 #[test]
463 fn prop_encoded_size_matches_actual(value in 0u32..=VARIABLE_INT_MAX) {
464 let mut buf = BytesMut::new();
465
466 let var_int = VariableInt::new(value).unwrap();
467 let predicted_size = var_int.encoded_size();
468 var_int.encode(&mut buf).unwrap();
469 let actual_size = u32::try_from(buf.len()).expect("buffer size should fit in u32");
470
471 prop_assert_eq!(predicted_size, actual_size);
472 }
473
474 #[test]
475 fn prop_bebytes_round_trip(value in 0u32..=VARIABLE_INT_MAX) {
476 use bebytes::BeBytes;
477
478 let var_int = VariableInt::new(value).unwrap();
479 let bytes = var_int.to_be_bytes();
480 prop_assert_eq!(bytes.len(), var_int.encoded_size() as usize);
481
482 let (decoded, consumed) = VariableInt::try_from_be_bytes(&bytes).unwrap();
483 prop_assert_eq!(decoded.value(), value);
484 prop_assert_eq!(consumed, bytes.len());
485 }
486
487 #[test]
488 fn prop_invalid_values_rejected(value in (VARIABLE_INT_MAX + 1)..=u32::MAX) {
489 let result = VariableInt::new(value);
490 prop_assert!(result.is_err());
491 }
492
493 #[test]
494 fn prop_size_boundaries(value in 0u32..=VARIABLE_INT_MAX) {
495 let var_int = VariableInt::new(value).unwrap();
496 let size = var_int.encoded_size();
497
498 match value {
499 0..=127 => prop_assert_eq!(size, 1),
500 128..=16_383 => prop_assert_eq!(size, 2),
501 16_384..=2_097_151 => prop_assert_eq!(size, 3),
502 2_097_152..=VARIABLE_INT_MAX => prop_assert_eq!(size, 4),
503 _ => unreachable!(),
504 }
505 }
506 }
507 }
508}