1#[cfg(feature = "std")]
128use std::error::Error;
129
130#[cfg(not(feature = "std"))]
131use core::fmt;
132
133#[cfg(feature = "std")]
134use std::fmt;
135
136#[cfg(not(feature = "std"))]
137use alloc::{string::String, vec::Vec};
138
139use crate::object::ObjectIdentifier;
140
141#[cfg(feature = "std")]
143pub type Result<T> = std::result::Result<T, EncodingError>;
144
145#[cfg(not(feature = "std"))]
146pub type Result<T> = core::result::Result<T, EncodingError>;
147
148#[derive(Debug, Clone)]
150pub enum EncodingError {
151 BufferOverflow,
153 BufferUnderflow,
155 InvalidTag,
157 InvalidLength,
159 UnexpectedEndOfData,
161 InvalidFormat(String),
163 ValueOutOfRange,
165}
166
167impl fmt::Display for EncodingError {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 match self {
170 EncodingError::BufferOverflow => write!(f, "Buffer overflow during encoding"),
171 EncodingError::BufferUnderflow => write!(f, "Buffer underflow during decoding"),
172 EncodingError::InvalidTag => write!(f, "Invalid tag number encountered"),
173 EncodingError::InvalidLength => write!(f, "Invalid length value"),
174 EncodingError::UnexpectedEndOfData => write!(f, "Unexpected end of data"),
175 EncodingError::InvalidFormat(msg) => write!(f, "Invalid format: {}", msg),
176 EncodingError::ValueOutOfRange => write!(f, "Value out of valid range"),
177 }
178 }
179}
180
181#[cfg(feature = "std")]
182impl Error for EncodingError {}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
186#[repr(u8)]
187pub enum ApplicationTag {
188 Null = 0,
189 Boolean = 1,
190 UnsignedInt = 2,
191 SignedInt = 3,
192 Real = 4,
193 Double = 5,
194 OctetString = 6,
195 CharacterString = 7,
196 BitString = 8,
197 Enumerated = 9,
198 Date = 10,
199 Time = 11,
200 ObjectIdentifier = 12,
201 Reserved13 = 13,
202 Reserved14 = 14,
203 Reserved15 = 15,
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207pub enum BACnetTag {
208 Application(ApplicationTag),
209 Context(u8),
210}
211
212pub fn decode_tag(data: &[u8]) -> Result<(BACnetTag, usize, usize)> {
213 if data.is_empty() {
214 return Err(EncodingError::InvalidTag);
215 }
216
217 let tag_byte = data[0];
218 let tag_type = tag_byte & 0x08;
219 let mut length = (tag_byte & 0x07) as usize;
220 let mut consumed = 1;
221
222 let tag = if tag_type == 0 {
223 BACnetTag::Application(ApplicationTag::try_from(tag_byte >> 4)?)
224 } else {
225 BACnetTag::Context(tag_byte >> 4)
226 };
227
228 if length == 5 {
229 if data.len() < 2 {
230 return Err(EncodingError::BufferUnderflow);
231 }
232
233 let len_byte = data[1];
234 consumed += 1;
235
236 match len_byte {
237 0..=253 => {
238 length = len_byte as usize;
239 }
240 254 => {
241 if data.len() < 4 {
242 return Err(EncodingError::BufferUnderflow);
243 }
244 length = u16::from_be_bytes([data[2], data[3]]) as usize;
245 consumed += 2;
246 }
247 255 => {
248 if data.len() < 6 {
249 return Err(EncodingError::BufferUnderflow);
250 }
251 length = u32::from_be_bytes([data[2], data[3], data[4], data[5]]) as usize;
252 consumed += 4;
253 }
254 }
255 }
256
257 Ok((tag, length, consumed))
258}
259
260pub fn encode_application_tag(buffer: &mut Vec<u8>, tag: ApplicationTag, length: usize) {
262 let tag_byte = if length < 5 {
263 (tag as u8) << 4 | (length as u8)
264 } else {
265 (tag as u8) << 4 | 5
266 };
267
268 buffer.push(tag_byte);
269
270 if length >= 5 {
271 if length < 254 {
272 buffer.push(length as u8);
273 } else if length < 65536 {
274 buffer.push(254);
275 buffer.extend_from_slice(&(length as u16).to_be_bytes());
276 } else {
277 buffer.push(255);
278 buffer.extend_from_slice(&(length as u32).to_be_bytes());
279 }
280 }
281}
282
283pub fn decode_application_tag(data: &[u8]) -> Result<(ApplicationTag, usize, usize)> {
285 if data.is_empty() {
286 return Err(EncodingError::InvalidTag);
287 }
288
289 let tag_byte = data[0];
290 let tag = ApplicationTag::try_from(tag_byte >> 4)?;
291 let mut length = (tag_byte & 0x0F) as usize;
292 let mut consumed = 1;
293
294 if length == 5 {
295 if data.len() < 2 {
296 return Err(EncodingError::BufferUnderflow);
297 }
298
299 let len_byte = data[1];
300 consumed += 1;
301
302 match len_byte {
303 0..=253 => {
304 length = len_byte as usize;
305 }
306 254 => {
307 if data.len() < 4 {
308 return Err(EncodingError::BufferUnderflow);
309 }
310 length = u16::from_be_bytes([data[2], data[3]]) as usize;
311 consumed += 2;
312 }
313 255 => {
314 if data.len() < 6 {
315 return Err(EncodingError::BufferUnderflow);
316 }
317 length = u32::from_be_bytes([data[2], data[3], data[4], data[5]]) as usize;
318 consumed += 4;
319 }
320 }
321 }
322
323 Ok((tag, length, consumed))
324}
325
326pub fn encode_boolean(buffer: &mut Vec<u8>, value: bool) -> Result<()> {
328 encode_application_tag(buffer, ApplicationTag::Boolean, if value { 1 } else { 0 });
329 Ok(())
330}
331
332pub fn decode_boolean(data: &[u8]) -> Result<(bool, usize)> {
334 let (tag, length, consumed) = decode_application_tag(data)?;
335
336 if tag != ApplicationTag::Boolean {
337 return Err(EncodingError::InvalidTag);
338 }
339
340 let value = match length {
341 0 => false,
342 1 => true,
343 _ => return Err(EncodingError::InvalidLength),
344 };
345
346 Ok((value, consumed))
347}
348
349pub fn encode_unsigned(buffer: &mut Vec<u8>, value: u32) -> Result<()> {
351 let bytes = if value == 0 {
352 vec![0]
353 } else if value <= 0xFF {
354 vec![value as u8]
355 } else if value <= 0xFFFF {
356 (value as u16).to_be_bytes().to_vec()
357 } else if value <= 0xFFFFFF {
358 let bytes = value.to_be_bytes();
359 bytes[1..].to_vec()
360 } else {
361 value.to_be_bytes().to_vec()
362 };
363
364 encode_application_tag(buffer, ApplicationTag::UnsignedInt, bytes.len());
365 buffer.extend_from_slice(&bytes);
366 Ok(())
367}
368
369pub fn encode_unsigned64(buffer: &mut Vec<u8>, value: u64) {
370 let bytes = if value == 0 {
371 vec![0]
372 } else if value <= 0xFF {
373 vec![value as u8]
374 } else if value <= 0xFFFF {
375 (value as u16).to_be_bytes().to_vec()
376 } else if value <= 0xFFFFFF {
377 let bytes = value.to_be_bytes();
378 bytes[1..].to_vec()
379 } else if value <= 0xFFFFFFFF {
380 (value as u32).to_be_bytes().to_vec()
381 } else {
382 value.to_be_bytes().to_vec()
383 };
384
385 encode_application_tag(buffer, ApplicationTag::UnsignedInt, bytes.len());
386 buffer.extend_from_slice(&bytes);
387}
388
389pub fn decode_unsigned(data: &[u8]) -> Result<(u32, usize)> {
391 let (tag, length, mut consumed) = decode_application_tag(data)?;
392
393 if tag != ApplicationTag::UnsignedInt {
394 return Err(EncodingError::InvalidTag);
395 }
396
397 if data.len() < consumed + length {
398 return Err(EncodingError::BufferUnderflow);
399 }
400
401 let value = match length {
402 1 => data[consumed] as u32,
403 2 => u16::from_be_bytes([data[consumed], data[consumed + 1]]) as u32,
404 3 => {
405 let bytes = [0, data[consumed], data[consumed + 1], data[consumed + 2]];
406 u32::from_be_bytes(bytes)
407 }
408 4 => u32::from_be_bytes([
409 data[consumed],
410 data[consumed + 1],
411 data[consumed + 2],
412 data[consumed + 3],
413 ]),
414 _ => return Err(EncodingError::InvalidLength),
415 };
416
417 consumed += length;
418 Ok((value, consumed))
419}
420
421pub fn decode_unsigned64(data: &[u8]) -> Result<(u64, usize)> {
423 let (tag, length, mut consumed) = decode_application_tag(data)?;
424
425 if tag != ApplicationTag::UnsignedInt {
426 return Err(EncodingError::InvalidTag);
427 }
428
429 if data.len() < consumed + length {
430 return Err(EncodingError::BufferUnderflow);
431 }
432
433 let unused = 8 - length;
434 let mut value = [0; 8];
435 value[unused..].copy_from_slice(&data[consumed..consumed + length]);
436
437 let value = u64::from_be_bytes(value);
438
439 consumed += length;
440 Ok((value, consumed))
441}
442
443pub fn encode_signed(buffer: &mut Vec<u8>, value: i32) -> Result<()> {
445 let bytes = if (-128..=127).contains(&value) {
446 vec![value as u8]
447 } else if (-32768..=32767).contains(&value) {
448 (value as i16).to_be_bytes().to_vec()
449 } else if (-8388608..=8388607).contains(&value) {
450 let bytes = value.to_be_bytes();
451 bytes[1..].to_vec()
452 } else {
453 value.to_be_bytes().to_vec()
454 };
455
456 encode_application_tag(buffer, ApplicationTag::SignedInt, bytes.len());
457 buffer.extend_from_slice(&bytes);
458 Ok(())
459}
460
461pub fn encode_signed64(buffer: &mut Vec<u8>, value: i64) {
462 let bytes = if (-128..=127).contains(&value) {
463 vec![value as u8]
464 } else if (-32768..=32767).contains(&value) {
465 (value as i16).to_be_bytes().to_vec()
466 } else if (-8388608..=8388607).contains(&value) {
467 let bytes = value.to_be_bytes();
468 bytes[1..].to_vec()
469 } else if (i32::MIN as i64..=i32::MAX as i64).contains(&value) {
470 (value as i32).to_be_bytes().to_vec()
471 } else {
472 value.to_be_bytes().to_vec()
473 };
474
475 encode_application_tag(buffer, ApplicationTag::SignedInt, bytes.len());
476 buffer.extend_from_slice(&bytes);
477}
478
479pub fn decode_signed(data: &[u8]) -> Result<(i32, usize)> {
481 let (tag, length, mut consumed) = decode_application_tag(data)?;
482
483 if tag != ApplicationTag::SignedInt {
484 return Err(EncodingError::InvalidTag);
485 }
486
487 if data.len() < consumed + length {
488 return Err(EncodingError::BufferUnderflow);
489 }
490
491 let value = match length {
492 1 => data[consumed] as i8 as i32,
493 2 => i16::from_be_bytes([data[consumed], data[consumed + 1]]) as i32,
494 3 => {
495 let sign_extend = if data[consumed] & 0x80 != 0 {
496 0xFF
497 } else {
498 0x00
499 };
500 let bytes = [
501 sign_extend,
502 data[consumed],
503 data[consumed + 1],
504 data[consumed + 2],
505 ];
506 i32::from_be_bytes(bytes)
507 }
508 4 => i32::from_be_bytes([
509 data[consumed],
510 data[consumed + 1],
511 data[consumed + 2],
512 data[consumed + 3],
513 ]),
514 _ => return Err(EncodingError::InvalidLength),
515 };
516
517 consumed += length;
518 Ok((value, consumed))
519}
520
521pub fn decode_signed64(data: &[u8]) -> Result<(i64, usize)> {
523 let (tag, length, mut consumed) = decode_application_tag(data)?;
524
525 if tag != ApplicationTag::SignedInt {
526 return Err(EncodingError::InvalidTag);
527 }
528
529 if data.len() < consumed + length {
530 return Err(EncodingError::BufferUnderflow);
531 }
532
533 let unused = 8 - length;
534 let mut value = [0; 8];
535 value[unused..].copy_from_slice(&data[consumed..consumed + length]);
536
537 let value = match length {
538 1 => data[consumed] as i8 as i64,
539 2 => i16::from_be_bytes([data[consumed], data[consumed + 1]]) as i64,
540 v if (3..8).contains(&v) => {
541 let sign_extend = if data[consumed] & 0x80 != 0 {
542 0xFF
543 } else {
544 0x00
545 };
546
547 let mut value = [sign_extend; 8];
548 value[unused..].copy_from_slice(&data[consumed..consumed + length]);
549 i64::from_be_bytes(value)
550 }
551 8 => {
552 let mut value = [0; 8];
553 value.copy_from_slice(&data[consumed..consumed + length]);
554 i64::from_be_bytes(value)
555 }
556 _ => return Err(EncodingError::InvalidLength),
557 };
558
559 consumed += length;
560 Ok((value, consumed))
561}
562
563pub fn encode_real(buffer: &mut Vec<u8>, value: f32) -> Result<()> {
565 encode_application_tag(buffer, ApplicationTag::Real, 4);
566 buffer.extend_from_slice(&value.to_be_bytes());
567 Ok(())
568}
569
570pub fn decode_real(data: &[u8]) -> Result<(f32, usize)> {
572 let (tag, length, mut consumed) = decode_application_tag(data)?;
573
574 if tag != ApplicationTag::Real {
575 return Err(EncodingError::InvalidTag);
576 }
577
578 if length != 4 {
579 return Err(EncodingError::InvalidLength);
580 }
581
582 if data.len() < consumed + 4 {
583 return Err(EncodingError::BufferUnderflow);
584 }
585
586 let value = f32::from_be_bytes([
587 data[consumed],
588 data[consumed + 1],
589 data[consumed + 2],
590 data[consumed + 3],
591 ]);
592
593 consumed += 4;
594 Ok((value, consumed))
595}
596
597pub fn encode_octet_string(buffer: &mut Vec<u8>, value: &[u8]) -> Result<()> {
599 encode_application_tag(buffer, ApplicationTag::OctetString, value.len());
600 buffer.extend_from_slice(value);
601 Ok(())
602}
603
604pub fn decode_octet_string(data: &[u8]) -> Result<(Vec<u8>, usize)> {
606 let (tag, length, mut consumed) = decode_application_tag(data)?;
607
608 if tag != ApplicationTag::OctetString {
609 return Err(EncodingError::InvalidTag);
610 }
611
612 if data.len() < consumed + length {
613 return Err(EncodingError::BufferUnderflow);
614 }
615
616 let value = data[consumed..consumed + length].to_vec();
617 consumed += length;
618
619 Ok((value, consumed))
620}
621
622pub fn encode_character_string(buffer: &mut Vec<u8>, value: &str) -> Result<()> {
624 let string_bytes = value.as_bytes();
625 encode_application_tag(
626 buffer,
627 ApplicationTag::CharacterString,
628 string_bytes.len() + 1,
629 );
630 buffer.push(0); buffer.extend_from_slice(string_bytes);
632 Ok(())
633}
634
635pub fn decode_character_string(data: &[u8]) -> Result<(String, usize)> {
637 let (tag, length, mut consumed) = decode_application_tag(data)?;
638
639 if tag != ApplicationTag::CharacterString {
640 return Err(EncodingError::InvalidTag);
641 }
642
643 if data.len() < consumed + length || length == 0 {
644 return Err(EncodingError::BufferUnderflow);
645 }
646
647 let _encoding = data[consumed];
649 consumed += 1;
650
651 let string_data = &data[consumed..consumed + length - 1];
652 let value = String::from_utf8(string_data.to_vec())
653 .map_err(|_| EncodingError::InvalidFormat("Invalid UTF-8 string".to_string()))?;
654
655 consumed += length - 1;
656
657 Ok((value, consumed))
658}
659
660pub fn encode_enumerated(buffer: &mut Vec<u8>, value: u32) {
662 let bytes = if value <= 0xFF {
663 vec![value as u8]
664 } else if value <= 0xFFFF {
665 (value as u16).to_be_bytes().to_vec()
666 } else if value <= 0xFFFFFF {
667 let bytes = value.to_be_bytes();
668 bytes[1..].to_vec()
669 } else {
670 value.to_be_bytes().to_vec()
671 };
672
673 encode_application_tag(buffer, ApplicationTag::Enumerated, bytes.len());
674 buffer.extend_from_slice(&bytes);
675}
676
677pub fn decode_enumerated(data: &[u8]) -> Result<(u32, usize)> {
679 let (tag, length, mut consumed) = decode_application_tag(data)?;
680
681 if tag != ApplicationTag::Enumerated {
682 return Err(EncodingError::InvalidTag);
683 }
684
685 if data.len() < consumed + length {
686 return Err(EncodingError::BufferUnderflow);
687 }
688
689 let value = match length {
690 1 => data[consumed] as u32,
691 2 => u16::from_be_bytes([data[consumed], data[consumed + 1]]) as u32,
692 3 => {
693 let bytes = [0, data[consumed], data[consumed + 1], data[consumed + 2]];
694 u32::from_be_bytes(bytes)
695 }
696 4 => u32::from_be_bytes([
697 data[consumed],
698 data[consumed + 1],
699 data[consumed + 2],
700 data[consumed + 3],
701 ]),
702 _ => return Err(EncodingError::InvalidLength),
703 };
704
705 consumed += length;
706 Ok((value, consumed))
707}
708
709pub fn encode_date(buffer: &mut Vec<u8>, year: u16, month: u8, day: u8, weekday: u8) -> Result<()> {
711 encode_application_tag(buffer, ApplicationTag::Date, 4);
712 buffer.push(((year - 1900) % 256) as u8);
713 buffer.push(month);
714 buffer.push(day);
715 buffer.push(weekday);
716 Ok(())
717}
718
719pub fn decode_date(data: &[u8]) -> Result<((u16, u8, u8, u8), usize)> {
721 let (tag, length, mut consumed) = decode_application_tag(data)?;
722
723 if tag != ApplicationTag::Date {
724 return Err(EncodingError::InvalidTag);
725 }
726
727 if length != 4 || data.len() < consumed + 4 {
728 return Err(EncodingError::InvalidLength);
729 }
730
731 let year = if data[consumed] == 255 {
732 255
733 } else {
734 1900 + data[consumed] as u16
735 };
736 let month = data[consumed + 1];
737 let day = data[consumed + 2];
738 let weekday = data[consumed + 3];
739
740 consumed += 4;
741 Ok(((year, month, day, weekday), consumed))
742}
743
744pub fn encode_time(
746 buffer: &mut Vec<u8>,
747 hour: u8,
748 minute: u8,
749 second: u8,
750 hundredths: u8,
751) -> Result<()> {
752 encode_application_tag(buffer, ApplicationTag::Time, 4);
753 buffer.push(hour);
754 buffer.push(minute);
755 buffer.push(second);
756 buffer.push(hundredths);
757 Ok(())
758}
759
760pub fn decode_time(data: &[u8]) -> Result<((u8, u8, u8, u8), usize)> {
762 let (tag, length, mut consumed) = decode_application_tag(data)?;
763
764 if tag != ApplicationTag::Time {
765 return Err(EncodingError::InvalidTag);
766 }
767
768 if length != 4 || data.len() < consumed + 4 {
769 return Err(EncodingError::InvalidLength);
770 }
771
772 let hour = data[consumed];
773 let minute = data[consumed + 1];
774 let second = data[consumed + 2];
775 let hundredths = data[consumed + 3];
776
777 consumed += 4;
778 Ok(((hour, minute, second, hundredths), consumed))
779}
780
781pub fn encode_object_identifier(buffer: &mut Vec<u8>, object_id: ObjectIdentifier) -> Result<()> {
783 let object_id: u32 = object_id
784 .try_into()
785 .map_err(|_| EncodingError::ValueOutOfRange)?;
786 encode_application_tag(buffer, ApplicationTag::ObjectIdentifier, 4);
787 buffer.extend_from_slice(&object_id.to_be_bytes());
788 Ok(())
789}
790
791pub fn decode_object_identifier(data: &[u8]) -> Result<(ObjectIdentifier, usize)> {
793 let (tag, length, mut consumed) = decode_application_tag(data)?;
794
795 if tag != ApplicationTag::ObjectIdentifier {
796 return Err(EncodingError::InvalidTag);
797 }
798
799 if length != 4 || data.len() < consumed + 4 {
800 return Err(EncodingError::InvalidLength);
801 }
802
803 let object_id = u32::from_be_bytes([
804 data[consumed],
805 data[consumed + 1],
806 data[consumed + 2],
807 data[consumed + 3],
808 ]);
809
810 let object_type = object_id >> 22;
811 let instance = object_id & 0x3FFFFF;
812 let object_id = ObjectIdentifier::new(object_type.into(), instance);
813
814 consumed += 4;
815 Ok((object_id, consumed))
816}
817
818pub fn encode_double(buffer: &mut Vec<u8>, value: f64) -> Result<()> {
820 encode_application_tag(buffer, ApplicationTag::Double, 8);
821 buffer.extend_from_slice(&value.to_be_bytes());
822 Ok(())
823}
824
825pub fn decode_double(data: &[u8]) -> Result<(f64, usize)> {
827 let (tag, length, mut consumed) = decode_application_tag(data)?;
828
829 if tag != ApplicationTag::Double {
830 return Err(EncodingError::InvalidTag);
831 }
832
833 if length != 8 || data.len() < consumed + 8 {
834 return Err(EncodingError::InvalidLength);
835 }
836
837 let value = f64::from_be_bytes([
838 data[consumed],
839 data[consumed + 1],
840 data[consumed + 2],
841 data[consumed + 3],
842 data[consumed + 4],
843 data[consumed + 5],
844 data[consumed + 6],
845 data[consumed + 7],
846 ]);
847
848 consumed += 8;
849 Ok((value, consumed))
850}
851
852pub fn encode_context_tag(buffer: &mut Vec<u8>, tag_number: u8, length: usize) -> Result<()> {
854 if tag_number > 14 {
855 return Err(EncodingError::ValueOutOfRange);
856 }
857
858 let tag_byte = if length < 5 {
859 0x08 | (tag_number << 4) | (length as u8)
860 } else {
861 0x08 | (tag_number << 4) | 5
862 };
863
864 buffer.push(tag_byte);
865
866 if length >= 5 {
867 if length < 254 {
868 buffer.push(length as u8);
869 } else if length < 65536 {
870 buffer.push(254);
871 buffer.extend_from_slice(&(length as u16).to_be_bytes());
872 } else {
873 buffer.push(255);
874 buffer.extend_from_slice(&(length as u32).to_be_bytes());
875 }
876 }
877
878 Ok(())
879}
880
881pub fn encode_context_unsigned(value: u32, tag_number: u8) -> Result<Vec<u8>> {
883 let mut buffer = Vec::new();
884
885 let bytes = if value == 0 {
887 vec![0]
888 } else if value <= 0xFF {
889 vec![value as u8]
890 } else if value <= 0xFFFF {
891 (value as u16).to_be_bytes().to_vec()
892 } else if value <= 0xFFFFFF {
893 let bytes = value.to_be_bytes();
894 bytes[1..].to_vec()
895 } else {
896 value.to_be_bytes().to_vec()
897 };
898
899 encode_context_tag(&mut buffer, tag_number, bytes.len())?;
901
902 buffer.extend_from_slice(&bytes);
904
905 Ok(buffer)
906}
907
908pub fn decode_context_tag(data: &[u8]) -> Result<(u8, usize, usize)> {
910 if data.is_empty() {
911 return Err(EncodingError::InvalidTag);
912 }
913
914 let tag_byte = data[0];
915 if (tag_byte & 0x08) == 0 {
916 return Err(EncodingError::InvalidTag);
917 }
918
919 let tag_number = (tag_byte >> 4) & 0x0F;
920 let mut length = (tag_byte & 0x07) as usize;
921 let mut consumed = 1;
922
923 if length == 5 {
924 if data.len() < 2 {
925 return Err(EncodingError::BufferUnderflow);
926 }
927
928 let len_byte = data[1];
929 consumed += 1;
930
931 match len_byte {
932 0..=253 => {
933 length = len_byte as usize;
934 }
935 254 => {
936 if data.len() < 4 {
937 return Err(EncodingError::BufferUnderflow);
938 }
939 length = u16::from_be_bytes([data[2], data[3]]) as usize;
940 consumed += 2;
941 }
942 255 => {
943 if data.len() < 6 {
944 return Err(EncodingError::BufferUnderflow);
945 }
946 length = u32::from_be_bytes([data[2], data[3], data[4], data[5]]) as usize;
947 consumed += 4;
948 }
949 }
950 }
951
952 Ok((tag_number, length, consumed))
953}
954
955pub fn decode_context_unsigned(data: &[u8], expected_tag: u8) -> Result<(u32, usize)> {
957 let (tag_number, length, tag_consumed) = decode_context_tag(data)?;
958
959 if tag_number != expected_tag {
960 return Err(EncodingError::InvalidTag);
961 }
962
963 if data.len() < tag_consumed + length {
964 return Err(EncodingError::BufferUnderflow);
965 }
966
967 let value = match length {
968 0 => 0,
969 1 => data[tag_consumed] as u32,
970 2 => u16::from_be_bytes([data[tag_consumed], data[tag_consumed + 1]]) as u32,
971 3 => {
972 let bytes = [
973 0,
974 data[tag_consumed],
975 data[tag_consumed + 1],
976 data[tag_consumed + 2],
977 ];
978 u32::from_be_bytes(bytes)
979 }
980 4 => u32::from_be_bytes([
981 data[tag_consumed],
982 data[tag_consumed + 1],
983 data[tag_consumed + 2],
984 data[tag_consumed + 3],
985 ]),
986 _ => return Err(EncodingError::InvalidLength),
987 };
988
989 Ok((value, tag_consumed + length))
990}
991
992pub fn encode_context_enumerated(value: u32, tag_number: u8) -> Result<Vec<u8>> {
994 encode_context_unsigned(value, tag_number)
996}
997
998pub fn decode_context_enumerated(data: &[u8], expected_tag: u8) -> Result<(u32, usize)> {
1000 decode_context_unsigned(data, expected_tag)
1002}
1003
1004pub fn encode_context_object_id(object_id: ObjectIdentifier, tag_number: u8) -> Result<Vec<u8>> {
1006 let mut buffer = Vec::new();
1007
1008 let object_id: u32 = object_id.try_into()?;
1010
1011 encode_context_tag(&mut buffer, tag_number, 4)?;
1013
1014 buffer.extend_from_slice(&object_id.to_be_bytes());
1016
1017 Ok(buffer)
1018}
1019
1020pub fn decode_context_object_id(
1022 data: &[u8],
1023 expected_tag: u8,
1024) -> Result<(ObjectIdentifier, usize)> {
1025 let (tag_number, length, tag_consumed) = decode_context_tag(data)?;
1026
1027 if tag_number != expected_tag {
1028 return Err(EncodingError::InvalidTag);
1029 }
1030
1031 if length != 4 {
1032 return Err(EncodingError::InvalidLength);
1033 }
1034
1035 if data.len() < tag_consumed + 4 {
1036 return Err(EncodingError::BufferUnderflow);
1037 }
1038
1039 let object_id = u32::from_be_bytes([
1040 data[tag_consumed],
1041 data[tag_consumed + 1],
1042 data[tag_consumed + 2],
1043 data[tag_consumed + 3],
1044 ]);
1045
1046 Ok((object_id.into(), tag_consumed + 4))
1047}
1048
1049impl TryFrom<u8> for ApplicationTag {
1050 type Error = EncodingError;
1051
1052 fn try_from(value: u8) -> Result<Self> {
1053 match value {
1054 0 => Ok(ApplicationTag::Null),
1055 1 => Ok(ApplicationTag::Boolean),
1056 2 => Ok(ApplicationTag::UnsignedInt),
1057 3 => Ok(ApplicationTag::SignedInt),
1058 4 => Ok(ApplicationTag::Real),
1059 5 => Ok(ApplicationTag::Double),
1060 6 => Ok(ApplicationTag::OctetString),
1061 7 => Ok(ApplicationTag::CharacterString),
1062 8 => Ok(ApplicationTag::BitString),
1063 9 => Ok(ApplicationTag::Enumerated),
1064 10 => Ok(ApplicationTag::Date),
1065 11 => Ok(ApplicationTag::Time),
1066 12 => Ok(ApplicationTag::ObjectIdentifier),
1067 _ => Err(EncodingError::InvalidTag),
1068 }
1069 }
1070}
1071
1072pub mod advanced {
1074 use super::*;
1075 #[cfg(not(feature = "std"))]
1076 use alloc::{collections::BTreeMap, vec::Vec};
1077
1078 #[derive(Debug)]
1080 pub struct BufferManager {
1081 #[cfg(feature = "std")]
1083 encode_buffers: Vec<Vec<u8>>,
1084 #[cfg(not(feature = "std"))]
1085 encode_buffers: alloc::vec::Vec<alloc::vec::Vec<u8>>,
1086 max_buffer_size: usize,
1088 pub stats: BufferStats,
1090 }
1091
1092 #[derive(Debug, Default)]
1094 pub struct BufferStats {
1095 pub total_allocations: u64,
1096 pub buffer_reuses: u64,
1097 pub max_buffer_size_used: usize,
1098 pub total_bytes_encoded: u64,
1099 pub total_bytes_decoded: u64,
1100 }
1101
1102 impl BufferManager {
1103 pub fn new(max_buffer_size: usize) -> Self {
1105 Self {
1106 encode_buffers: Vec::with_capacity(8),
1107 max_buffer_size,
1108 stats: BufferStats::default(),
1109 }
1110 }
1111
1112 pub fn get_encode_buffer(&mut self) -> Vec<u8> {
1114 if let Some(mut buffer) = self.encode_buffers.pop() {
1115 buffer.clear();
1116 self.stats.buffer_reuses += 1;
1117 buffer
1118 } else {
1119 self.stats.total_allocations += 1;
1120 Vec::with_capacity(256)
1121 }
1122 }
1123
1124 pub fn return_buffer(&mut self, buffer: Vec<u8>) {
1126 self.stats.total_bytes_encoded += buffer.len() as u64;
1127 if buffer.capacity() <= self.max_buffer_size && self.encode_buffers.len() < 16 {
1128 self.encode_buffers.push(buffer);
1129 }
1130 }
1131
1132 pub fn update_decode_stats(&mut self, bytes_decoded: usize) {
1134 self.stats.total_bytes_decoded += bytes_decoded as u64;
1135 }
1136 }
1137
1138 pub mod context {
1140 use super::*;
1141
1142 pub fn encode_context_tag(
1144 buffer: &mut Vec<u8>,
1145 tag_number: u8,
1146 length: usize,
1147 ) -> Result<()> {
1148 if tag_number > 14 {
1149 return Err(EncodingError::ValueOutOfRange);
1150 }
1151
1152 let tag_byte = if length < 5 {
1153 0x08 | (tag_number << 4) | (length as u8)
1154 } else {
1155 0x08 | (tag_number << 4) | 5
1156 };
1157
1158 buffer.push(tag_byte);
1159
1160 if length >= 5 {
1161 if length < 254 {
1162 buffer.push(length as u8);
1163 } else if length < 65536 {
1164 buffer.push(254);
1165 buffer.extend_from_slice(&(length as u16).to_be_bytes());
1166 } else {
1167 buffer.push(255);
1168 buffer.extend_from_slice(&(length as u32).to_be_bytes());
1169 }
1170 }
1171
1172 Ok(())
1173 }
1174
1175 pub fn decode_context_tag(data: &[u8]) -> Result<(u8, usize, usize)> {
1177 if data.is_empty() {
1178 return Err(EncodingError::InvalidTag);
1179 }
1180
1181 let tag_byte = data[0];
1182 if (tag_byte & 0x08) == 0 {
1183 return Err(EncodingError::InvalidTag);
1184 }
1185
1186 let tag_number = (tag_byte >> 4) & 0x0F;
1187 let mut length = (tag_byte & 0x07) as usize;
1188 let mut consumed = 1;
1189
1190 if length == 5 {
1191 if data.len() < 2 {
1192 return Err(EncodingError::BufferUnderflow);
1193 }
1194
1195 let len_byte = data[1];
1196 consumed += 1;
1197
1198 match len_byte {
1199 0..=253 => {
1200 length = len_byte as usize;
1201 }
1202 254 => {
1203 if data.len() < 4 {
1204 return Err(EncodingError::BufferUnderflow);
1205 }
1206 length = u16::from_be_bytes([data[2], data[3]]) as usize;
1207 consumed += 2;
1208 }
1209 255 => {
1210 if data.len() < 6 {
1211 return Err(EncodingError::BufferUnderflow);
1212 }
1213 length = u32::from_be_bytes([data[2], data[3], data[4], data[5]]) as usize;
1214 consumed += 4;
1215 }
1216 }
1217 }
1218
1219 Ok((tag_number, length, consumed))
1220 }
1221
1222 pub fn encode_opening_tag(buffer: &mut Vec<u8>, tag_number: u8) -> Result<()> {
1224 if tag_number > 14 {
1225 return Err(EncodingError::ValueOutOfRange);
1226 }
1227 buffer.push(0x0E | (tag_number << 4));
1228 Ok(())
1229 }
1230
1231 pub fn encode_closing_tag(buffer: &mut Vec<u8>, tag_number: u8) -> Result<()> {
1233 if tag_number > 14 {
1234 return Err(EncodingError::ValueOutOfRange);
1235 }
1236 buffer.push(0x0F | (tag_number << 4));
1237 Ok(())
1238 }
1239 }
1240
1241 pub mod bitstring {
1243 use super::*;
1244
1245 #[allow(clippy::manual_is_multiple_of)]
1247 pub fn encode_bit_string(buffer: &mut Vec<u8>, bits: &[bool]) -> Result<()> {
1248 let byte_count = bits.len().div_ceil(8);
1249 let unused_bits = if bits.len() % 8 == 0 {
1250 0
1251 } else {
1252 8 - (bits.len() % 8)
1253 };
1254
1255 encode_application_tag(buffer, ApplicationTag::BitString, byte_count + 1);
1256 buffer.push(unused_bits as u8);
1257
1258 let mut current_byte = 0u8;
1259 let mut bit_pos = 0;
1260
1261 for &bit in bits {
1262 if bit {
1263 current_byte |= 1 << (7 - bit_pos);
1264 }
1265 bit_pos += 1;
1266
1267 if bit_pos == 8 {
1268 buffer.push(current_byte);
1269 current_byte = 0;
1270 bit_pos = 0;
1271 }
1272 }
1273
1274 if bit_pos > 0 {
1275 buffer.push(current_byte);
1276 }
1277
1278 Ok(())
1279 }
1280
1281 pub fn decode_bit_string(data: &[u8]) -> Result<(Vec<bool>, usize)> {
1283 let (tag, length, mut consumed) = decode_application_tag(data)?;
1284
1285 if tag != ApplicationTag::BitString {
1286 return Err(EncodingError::InvalidTag);
1287 }
1288
1289 if length == 0 || data.len() < consumed + length {
1290 return Err(EncodingError::BufferUnderflow);
1291 }
1292
1293 let unused_bits = data[consumed] as usize;
1294 consumed += 1;
1295
1296 if unused_bits > 7 {
1297 return Err(EncodingError::InvalidFormat(
1298 "Invalid unused bits count".to_string(),
1299 ));
1300 }
1301
1302 let mut bits = Vec::new();
1303 let byte_count = length - 1;
1304
1305 for i in 0..byte_count {
1306 let byte_val = data[consumed + i];
1307 let bits_in_byte = if i == byte_count - 1 {
1308 8 - unused_bits
1309 } else {
1310 8
1311 };
1312
1313 for bit_pos in 0..bits_in_byte {
1314 bits.push((byte_val & (1 << (7 - bit_pos))) != 0);
1315 }
1316 }
1317
1318 consumed += byte_count;
1319 Ok((bits, consumed))
1320 }
1321 }
1322
1323 pub mod perf {
1325 use super::*;
1326
1327 pub struct FastEncoder {
1329 buffer: Vec<u8>,
1330 }
1331
1332 impl FastEncoder {
1333 pub fn new(capacity: usize) -> Self {
1335 Self {
1336 buffer: Vec::with_capacity(capacity),
1337 }
1338 }
1339
1340 pub fn data(&self) -> &[u8] {
1342 &self.buffer
1343 }
1344
1345 pub fn clear(&mut self) {
1347 self.buffer.clear();
1348 }
1349
1350 pub fn encode_unsigned_fast(&mut self, value: u32) -> Result<()> {
1352 match value {
1353 0 => {
1354 self.buffer.extend_from_slice(&[0x21, 0x00]);
1355 }
1356 1..=255 => {
1357 self.buffer.extend_from_slice(&[0x21, value as u8]);
1358 }
1359 256..=65535 => {
1360 let bytes = (value as u16).to_be_bytes();
1361 self.buffer.extend_from_slice(&[0x22]);
1362 self.buffer.extend_from_slice(&bytes);
1363 }
1364 65536..=16777215 => {
1365 let bytes = value.to_be_bytes();
1366 self.buffer.extend_from_slice(&[0x23]);
1367 self.buffer.extend_from_slice(&bytes[1..]);
1368 }
1369 _ => {
1370 let bytes = value.to_be_bytes();
1371 self.buffer.extend_from_slice(&[0x24]);
1372 self.buffer.extend_from_slice(&bytes);
1373 }
1374 }
1375 Ok(())
1376 }
1377
1378 pub fn encode_boolean_fast(&mut self, value: bool) -> Result<()> {
1380 self.buffer.push(if value { 0x11 } else { 0x10 });
1381 Ok(())
1382 }
1383
1384 pub fn encode_real_fast(&mut self, value: f32) -> Result<()> {
1386 self.buffer.push(0x44);
1387 self.buffer.extend_from_slice(&value.to_be_bytes());
1388 Ok(())
1389 }
1390 }
1391 }
1392
1393 pub mod validation {
1395 use super::*;
1396
1397 pub struct DataValidator {
1399 max_tag_depth: usize,
1401 max_string_length: usize,
1403 }
1404
1405 impl DataValidator {
1406 pub fn new(max_tag_depth: usize, max_string_length: usize) -> Self {
1408 Self {
1409 max_tag_depth,
1410 max_string_length,
1411 }
1412 }
1413
1414 pub fn validate(&self, data: &[u8]) -> Result<()> {
1416 self.validate_recursive(data, 0)
1417 }
1418
1419 fn validate_recursive(&self, data: &[u8], depth: usize) -> Result<()> {
1420 if depth > self.max_tag_depth {
1421 return Err(EncodingError::InvalidFormat(
1422 "Maximum tag depth exceeded".to_string(),
1423 ));
1424 }
1425
1426 let mut pos = 0;
1427 while pos < data.len() {
1428 let (tag, length, consumed) = decode_application_tag(&data[pos..])?;
1429 pos += consumed;
1430
1431 match tag {
1432 ApplicationTag::CharacterString if length > self.max_string_length => {
1433 return Err(EncodingError::InvalidFormat(
1434 "String too long".to_string(),
1435 ));
1436 }
1437 ApplicationTag::OctetString if length > self.max_string_length * 2 => {
1438 return Err(EncodingError::InvalidFormat(
1439 "Octet string too long".to_string(),
1440 ));
1441 }
1442 _ => {}
1443 }
1444
1445 pos += length;
1446 }
1447
1448 Ok(())
1449 }
1450 }
1451 }
1452}
1453
1454pub struct EncodingStream {
1456 buffer: Vec<u8>,
1457 position: usize,
1458 max_size: usize,
1459}
1460
1461impl EncodingStream {
1462 pub fn new(max_size: usize) -> Self {
1464 Self {
1465 buffer: Vec::with_capacity(max_size),
1466 position: 0,
1467 max_size,
1468 }
1469 }
1470
1471 pub fn encode_tagged<T: EncodableValue>(
1473 &mut self,
1474 tag: ApplicationTag,
1475 value: T,
1476 ) -> Result<()> {
1477 if self.buffer.len() >= self.max_size {
1478 return Err(EncodingError::BufferOverflow);
1479 }
1480 value.encode_to(tag, &mut self.buffer)
1481 }
1482
1483 pub fn encode_context<T: EncodableValue>(&mut self, tag_number: u8, value: T) -> Result<()> {
1485 if self.buffer.len() >= self.max_size {
1486 return Err(EncodingError::BufferOverflow);
1487 }
1488 value.encode_context_to(tag_number, &mut self.buffer)
1489 }
1490
1491 pub fn data(&self) -> &[u8] {
1493 &self.buffer
1494 }
1495
1496 pub fn into_buffer(self) -> Vec<u8> {
1498 self.buffer
1499 }
1500
1501 pub fn clear(&mut self) {
1503 self.buffer.clear();
1504 self.position = 0;
1505 }
1506}
1507
1508pub trait EncodableValue {
1510 fn encode_to(&self, tag: ApplicationTag, buffer: &mut Vec<u8>) -> Result<()>;
1512
1513 fn encode_context_to(&self, tag_number: u8, buffer: &mut Vec<u8>) -> Result<()>;
1515}
1516
1517impl EncodableValue for bool {
1518 fn encode_to(&self, _tag: ApplicationTag, buffer: &mut Vec<u8>) -> Result<()> {
1519 encode_boolean(buffer, *self)
1520 }
1521
1522 fn encode_context_to(&self, tag_number: u8, buffer: &mut Vec<u8>) -> Result<()> {
1523 advanced::context::encode_context_tag(buffer, tag_number, if *self { 1 } else { 0 })
1524 }
1525}
1526
1527impl EncodableValue for u32 {
1528 fn encode_to(&self, _tag: ApplicationTag, buffer: &mut Vec<u8>) -> Result<()> {
1529 encode_unsigned(buffer, *self)
1530 }
1531
1532 fn encode_context_to(&self, tag_number: u8, buffer: &mut Vec<u8>) -> Result<()> {
1533 let temp_buffer = Vec::new();
1534 let mut temp = temp_buffer;
1535 encode_unsigned(&mut temp, *self)?;
1536 advanced::context::encode_context_tag(buffer, tag_number, temp.len() - 1)?;
1537 buffer.extend_from_slice(&temp[1..]);
1538 Ok(())
1539 }
1540}
1541
1542impl EncodableValue for i32 {
1543 fn encode_to(&self, _tag: ApplicationTag, buffer: &mut Vec<u8>) -> Result<()> {
1544 encode_signed(buffer, *self)
1545 }
1546
1547 fn encode_context_to(&self, tag_number: u8, buffer: &mut Vec<u8>) -> Result<()> {
1548 let temp_buffer = Vec::new();
1549 let mut temp = temp_buffer;
1550 encode_signed(&mut temp, *self)?;
1551 advanced::context::encode_context_tag(buffer, tag_number, temp.len() - 1)?;
1552 buffer.extend_from_slice(&temp[1..]);
1553 Ok(())
1554 }
1555}
1556
1557impl EncodableValue for f32 {
1558 fn encode_to(&self, _tag: ApplicationTag, buffer: &mut Vec<u8>) -> Result<()> {
1559 encode_real(buffer, *self)
1560 }
1561
1562 fn encode_context_to(&self, tag_number: u8, buffer: &mut Vec<u8>) -> Result<()> {
1563 advanced::context::encode_context_tag(buffer, tag_number, 4)?;
1564 buffer.extend_from_slice(&self.to_be_bytes());
1565 Ok(())
1566 }
1567}
1568
1569impl EncodableValue for f64 {
1570 fn encode_to(&self, _tag: ApplicationTag, buffer: &mut Vec<u8>) -> Result<()> {
1571 encode_double(buffer, *self)
1572 }
1573
1574 fn encode_context_to(&self, tag_number: u8, buffer: &mut Vec<u8>) -> Result<()> {
1575 advanced::context::encode_context_tag(buffer, tag_number, 8)?;
1576 buffer.extend_from_slice(&self.to_be_bytes());
1577 Ok(())
1578 }
1579}
1580
1581impl EncodableValue for &str {
1582 fn encode_to(&self, _tag: ApplicationTag, buffer: &mut Vec<u8>) -> Result<()> {
1583 encode_character_string(buffer, self)
1584 }
1585
1586 fn encode_context_to(&self, tag_number: u8, buffer: &mut Vec<u8>) -> Result<()> {
1587 advanced::context::encode_context_tag(buffer, tag_number, self.len() + 1)?;
1588 buffer.push(0); buffer.extend_from_slice(self.as_bytes());
1590 Ok(())
1591 }
1592}
1593
1594pub struct DecodingStream<'a> {
1596 data: &'a [u8],
1597 position: usize,
1598}
1599
1600impl<'a> DecodingStream<'a> {
1601 pub fn new(data: &'a [u8]) -> Self {
1603 Self { data, position: 0 }
1604 }
1605
1606 pub fn has_data(&self) -> bool {
1608 self.position < self.data.len()
1609 }
1610
1611 pub fn remaining(&self) -> usize {
1613 self.data.len().saturating_sub(self.position)
1614 }
1615
1616 pub fn peek_tag(&self) -> Result<ApplicationTag> {
1618 if self.position >= self.data.len() {
1619 return Err(EncodingError::UnexpectedEndOfData);
1620 }
1621
1622 let tag_byte = self.data[self.position];
1623 let tag = ApplicationTag::try_from(tag_byte >> 4)?;
1624 Ok(tag)
1625 }
1626
1627 pub fn decode_boolean(&mut self) -> Result<bool> {
1629 let (value, consumed) = decode_boolean(&self.data[self.position..])?;
1630 self.position += consumed;
1631 Ok(value)
1632 }
1633
1634 pub fn decode_unsigned(&mut self) -> Result<u32> {
1636 let (value, consumed) = decode_unsigned(&self.data[self.position..])?;
1637 self.position += consumed;
1638 Ok(value)
1639 }
1640
1641 pub fn decode_signed(&mut self) -> Result<i32> {
1643 let (value, consumed) = decode_signed(&self.data[self.position..])?;
1644 self.position += consumed;
1645 Ok(value)
1646 }
1647
1648 pub fn decode_real(&mut self) -> Result<f32> {
1650 let (value, consumed) = decode_real(&self.data[self.position..])?;
1651 self.position += consumed;
1652 Ok(value)
1653 }
1654
1655 pub fn decode_double(&mut self) -> Result<f64> {
1657 let (value, consumed) = decode_double(&self.data[self.position..])?;
1658 self.position += consumed;
1659 Ok(value)
1660 }
1661
1662 pub fn decode_character_string(&mut self) -> Result<String> {
1664 let (value, consumed) = decode_character_string(&self.data[self.position..])?;
1665 self.position += consumed;
1666 Ok(value)
1667 }
1668
1669 pub fn decode_octet_string(&mut self) -> Result<Vec<u8>> {
1671 let (value, consumed) = decode_octet_string(&self.data[self.position..])?;
1672 self.position += consumed;
1673 Ok(value)
1674 }
1675
1676 pub fn decode_enumerated(&mut self) -> Result<u32> {
1678 let (value, consumed) = decode_enumerated(&self.data[self.position..])?;
1679 self.position += consumed;
1680 Ok(value)
1681 }
1682
1683 pub fn decode_date(&mut self) -> Result<(u16, u8, u8, u8)> {
1685 let (value, consumed) = decode_date(&self.data[self.position..])?;
1686 self.position += consumed;
1687 Ok(value)
1688 }
1689
1690 pub fn decode_time(&mut self) -> Result<(u8, u8, u8, u8)> {
1692 let (value, consumed) = decode_time(&self.data[self.position..])?;
1693 self.position += consumed;
1694 Ok(value)
1695 }
1696
1697 pub fn decode_object_identifier(&mut self) -> Result<ObjectIdentifier> {
1699 let (identifier, consumed) = decode_object_identifier(&self.data[self.position..])?;
1700 self.position += consumed;
1701 Ok(identifier)
1702 }
1703
1704 pub fn skip_value(&mut self) -> Result<()> {
1706 let (_tag, length, consumed) = decode_application_tag(&self.data[self.position..])?;
1707 self.position += consumed + length;
1708 Ok(())
1709 }
1710
1711 pub fn position(&self) -> usize {
1713 self.position
1714 }
1715
1716 pub fn set_position(&mut self, position: usize) -> Result<()> {
1718 if position > self.data.len() {
1719 return Err(EncodingError::ValueOutOfRange);
1720 }
1721 self.position = position;
1722 Ok(())
1723 }
1724}
1725
1726#[derive(Default)]
1728pub struct PropertyArrayEncoder {
1729 buffer: Vec<u8>,
1730 count: usize,
1731}
1732
1733impl PropertyArrayEncoder {
1734 pub fn new() -> Self {
1736 Self::default()
1737 }
1738
1739 pub fn add_property<T: EncodableValue>(&mut self, property_id: u32, value: T) -> Result<()> {
1741 advanced::context::encode_context_tag(&mut self.buffer, 0, 4)?;
1743 self.buffer.extend_from_slice(&property_id.to_be_bytes());
1744
1745 advanced::context::encode_opening_tag(&mut self.buffer, 1)?;
1747
1748 value.encode_to(ApplicationTag::Null, &mut self.buffer)?;
1750
1751 advanced::context::encode_closing_tag(&mut self.buffer, 1)?;
1753
1754 self.count += 1;
1755 Ok(())
1756 }
1757
1758 pub fn data(&self) -> &[u8] {
1760 &self.buffer
1761 }
1762
1763 pub fn count(&self) -> usize {
1765 self.count
1766 }
1767
1768 pub fn clear(&mut self) {
1770 self.buffer.clear();
1771 self.count = 0;
1772 }
1773}
1774
1775#[derive(Default)]
1777pub struct ErrorEncoder {
1778 buffer: Vec<u8>,
1779}
1780
1781impl ErrorEncoder {
1782 pub fn new() -> Self {
1784 Self::default()
1785 }
1786
1787 pub fn encode_error(&mut self, error_class: u32, error_code: u32) -> Result<()> {
1789 advanced::context::encode_context_tag(
1791 &mut self.buffer,
1792 0,
1793 if error_class <= 0xFF {
1794 1
1795 } else if error_class <= 0xFFFF {
1796 2
1797 } else {
1798 4
1799 },
1800 )?;
1801 encode_enumerated(&mut self.buffer, error_class);
1802
1803 advanced::context::encode_context_tag(
1805 &mut self.buffer,
1806 1,
1807 if error_code <= 0xFF {
1808 1
1809 } else if error_code <= 0xFFFF {
1810 2
1811 } else {
1812 4
1813 },
1814 )?;
1815 encode_enumerated(&mut self.buffer, error_code);
1816
1817 Ok(())
1818 }
1819
1820 pub fn data(&self) -> &[u8] {
1822 &self.buffer
1823 }
1824
1825 pub fn clear(&mut self) {
1827 self.buffer.clear();
1828 }
1829}
1830
1831#[derive(Debug, Default)]
1833pub struct EncodingAnalyzer {
1834 pub stats: EncodingStatistics,
1836 benchmarks: Vec<EncodingBenchmark>,
1838 error_patterns: Vec<ErrorPattern>,
1840}
1841
1842#[derive(Debug, Default)]
1844pub struct EncodingStatistics {
1845 pub total_encodings: u64,
1847 pub total_decodings: u64,
1849 pub bytes_encoded: u64,
1851 pub bytes_decoded: u64,
1853 pub encoding_errors: u64,
1855 pub decoding_errors: u64,
1857 pub avg_encode_time_us: f64,
1859 pub avg_decode_time_us: f64,
1861}
1862
1863#[derive(Debug, Clone)]
1865struct EncodingBenchmark {
1866 _data_type: &'static str,
1868 _size: usize,
1870 _encode_time_us: u64,
1872 _decode_time_us: u64,
1874 #[cfg(feature = "std")]
1876 _timestamp: std::time::Instant,
1877}
1878
1879#[derive(Debug, Clone)]
1881struct ErrorPattern {
1882 error_type: EncodingError,
1884 count: u32,
1886 #[cfg(feature = "std")]
1888 last_seen: std::time::Instant,
1889}
1890
1891impl EncodingAnalyzer {
1892 pub fn new() -> Self {
1894 Self::default()
1895 }
1896
1897 pub fn record_encoding(&mut self, data_type: &'static str, bytes: usize, duration_us: u64) {
1899 self.stats.total_encodings += 1;
1900 self.stats.bytes_encoded += bytes as u64;
1901
1902 let total_time = self.stats.avg_encode_time_us * (self.stats.total_encodings - 1) as f64;
1904 self.stats.avg_encode_time_us =
1905 (total_time + duration_us as f64) / self.stats.total_encodings as f64;
1906
1907 self.benchmarks.push(EncodingBenchmark {
1909 _data_type: data_type,
1910 _size: bytes,
1911 _encode_time_us: duration_us,
1912 _decode_time_us: 0,
1913 #[cfg(feature = "std")]
1914 _timestamp: std::time::Instant::now(),
1915 });
1916
1917 if self.benchmarks.len() > 1000 {
1919 self.benchmarks.remove(0);
1920 }
1921 }
1922
1923 pub fn record_decoding(&mut self, _data_type: &'static str, bytes: usize, duration_us: u64) {
1925 self.stats.total_decodings += 1;
1926 self.stats.bytes_decoded += bytes as u64;
1927
1928 let total_time = self.stats.avg_decode_time_us * (self.stats.total_decodings - 1) as f64;
1930 self.stats.avg_decode_time_us =
1931 (total_time + duration_us as f64) / self.stats.total_decodings as f64;
1932 }
1933
1934 pub fn record_error(&mut self, error: EncodingError) {
1936 self.stats.encoding_errors += 1;
1937
1938 if let Some(pattern) = self
1940 .error_patterns
1941 .iter_mut()
1942 .find(|p| std::mem::discriminant(&p.error_type) == std::mem::discriminant(&error))
1943 {
1944 pattern.count += 1;
1945 #[cfg(feature = "std")]
1946 {
1947 pattern.last_seen = std::time::Instant::now();
1948 }
1949 } else {
1950 self.error_patterns.push(ErrorPattern {
1951 error_type: error,
1952 count: 1,
1953 #[cfg(feature = "std")]
1954 last_seen: std::time::Instant::now(),
1955 });
1956 }
1957 }
1958
1959 pub fn get_encoding_throughput(&self) -> f64 {
1961 if self.stats.avg_encode_time_us > 0.0 {
1962 (self.stats.bytes_encoded as f64 / self.stats.total_encodings as f64)
1963 / (self.stats.avg_encode_time_us / 1_000_000.0)
1964 } else {
1965 0.0
1966 }
1967 }
1968
1969 pub fn get_decoding_throughput(&self) -> f64 {
1971 if self.stats.avg_decode_time_us > 0.0 {
1972 (self.stats.bytes_decoded as f64 / self.stats.total_decodings as f64)
1973 / (self.stats.avg_decode_time_us / 1_000_000.0)
1974 } else {
1975 0.0
1976 }
1977 }
1978
1979 pub fn get_top_errors(&self, limit: usize) -> Vec<(&EncodingError, u32)> {
1981 let mut errors: Vec<_> = self
1982 .error_patterns
1983 .iter()
1984 .map(|p| (&p.error_type, p.count))
1985 .collect();
1986 errors.sort_by_key(|b| std::cmp::Reverse(b.1));
1987 errors.truncate(limit);
1988 errors
1989 }
1990
1991 pub fn reset(&mut self) {
1993 self.stats = EncodingStatistics::default();
1994 self.benchmarks.clear();
1995 self.error_patterns.clear();
1996 }
1997}
1998
1999#[derive(Debug)]
2001pub struct EncodingCache {
2002 cache: Vec<CacheEntry>,
2004 max_size: usize,
2006 pub hits: u64,
2008 pub misses: u64,
2010}
2011
2012#[derive(Debug, Clone)]
2014struct CacheEntry {
2015 hash: u64,
2017 encoded: Vec<u8>,
2019 access_count: u32,
2021 #[cfg(feature = "std")]
2023 last_access: std::time::Instant,
2024}
2025
2026impl EncodingCache {
2027 pub fn new(max_size: usize) -> Self {
2029 Self {
2030 cache: Vec::with_capacity(max_size),
2031 max_size,
2032 hits: 0,
2033 misses: 0,
2034 }
2035 }
2036
2037 pub fn get(&mut self, hash: u64) -> Option<Vec<u8>> {
2039 if let Some(entry) = self.cache.iter_mut().find(|e| e.hash == hash) {
2040 entry.access_count += 1;
2041 #[cfg(feature = "std")]
2042 {
2043 entry.last_access = std::time::Instant::now();
2044 }
2045 self.hits += 1;
2046 Some(entry.encoded.clone())
2047 } else {
2048 self.misses += 1;
2049 None
2050 }
2051 }
2052
2053 pub fn put(&mut self, hash: u64, encoded: Vec<u8>) {
2055 if self.cache.iter().any(|e| e.hash == hash) {
2057 return;
2058 }
2059
2060 if self.cache.len() >= self.max_size {
2062 self.cache.sort_by_key(|e| e.access_count);
2063 self.cache.remove(0);
2064 }
2065
2066 self.cache.push(CacheEntry {
2067 hash,
2068 encoded,
2069 access_count: 1,
2070 #[cfg(feature = "std")]
2071 last_access: std::time::Instant::now(),
2072 });
2073 }
2074
2075 pub fn clear(&mut self) {
2077 self.cache.clear();
2078 self.hits = 0;
2079 self.misses = 0;
2080 }
2081
2082 pub fn hit_ratio(&self) -> f64 {
2084 let total = self.hits + self.misses;
2085 if total > 0 {
2086 self.hits as f64 / total as f64
2087 } else {
2088 0.0
2089 }
2090 }
2091}
2092
2093#[derive(Debug, Clone)]
2095pub struct EncodingConfig {
2096 pub use_compression: bool,
2098 pub compression_threshold: usize,
2100 pub enable_caching: bool,
2102 pub cache_size: usize,
2104 pub enable_performance_tracking: bool,
2106 pub validation_level: ValidationLevel,
2108 pub max_string_length: usize,
2110 pub max_array_size: usize,
2112}
2113
2114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2116pub enum ValidationLevel {
2117 None,
2119 Basic,
2121 Strict,
2123 Paranoid,
2125}
2126
2127impl Default for EncodingConfig {
2128 fn default() -> Self {
2129 Self {
2130 use_compression: false,
2131 compression_threshold: 1024,
2132 enable_caching: true,
2133 cache_size: 1000,
2134 enable_performance_tracking: true,
2135 validation_level: ValidationLevel::Basic,
2136 max_string_length: 4096,
2137 max_array_size: 1000,
2138 }
2139 }
2140}
2141
2142#[derive(Debug)]
2144pub struct EncodingManager {
2145 _config: EncodingConfig,
2147 analyzer: Option<EncodingAnalyzer>,
2149 cache: Option<EncodingCache>,
2151 buffer_manager: advanced::BufferManager,
2153}
2154
2155impl EncodingManager {
2156 pub fn new(config: EncodingConfig) -> Self {
2158 let analyzer = if config.enable_performance_tracking {
2159 Some(EncodingAnalyzer::new())
2160 } else {
2161 None
2162 };
2163
2164 let cache = if config.enable_caching {
2165 Some(EncodingCache::new(config.cache_size))
2166 } else {
2167 None
2168 };
2169
2170 Self {
2171 _config: config,
2172 analyzer,
2173 cache,
2174 buffer_manager: advanced::BufferManager::new(8192),
2175 }
2176 }
2177
2178 pub fn encode<T: EncodableValue>(&mut self, value: T, tag: ApplicationTag) -> Result<Vec<u8>> {
2180 #[cfg(feature = "std")]
2181 let start_time = std::time::Instant::now();
2182
2183 let mut buffer = self.buffer_manager.get_encode_buffer();
2184 let result = value.encode_to(tag, &mut buffer);
2185
2186 #[cfg(feature = "std")]
2187 let duration = start_time.elapsed();
2188
2189 match result {
2190 Ok(_) => {
2191 if let Some(ref mut analyzer) = self.analyzer {
2192 #[cfg(feature = "std")]
2193 analyzer.record_encoding("generic", buffer.len(), duration.as_micros() as u64);
2194 #[cfg(not(feature = "std"))]
2195 analyzer.record_encoding("generic", buffer.len(), 0);
2196 }
2197
2198 let result_buffer = buffer.clone();
2199 self.buffer_manager.return_buffer(buffer);
2200 Ok(result_buffer)
2201 }
2202 Err(e) => {
2203 if let Some(ref mut analyzer) = self.analyzer {
2204 analyzer.record_error(e.clone());
2205 }
2206 self.buffer_manager.return_buffer(buffer);
2207 Err(e)
2208 }
2209 }
2210 }
2211
2212 pub fn decode<T>(
2214 &mut self,
2215 data: &[u8],
2216 decoder: impl Fn(&[u8]) -> Result<(T, usize)>,
2217 ) -> Result<T> {
2218 #[cfg(feature = "std")]
2219 let start_time = std::time::Instant::now();
2220
2221 let result = decoder(data);
2222
2223 #[cfg(feature = "std")]
2224 let duration = start_time.elapsed();
2225
2226 match result {
2227 Ok((value, consumed)) => {
2228 if let Some(ref mut analyzer) = self.analyzer {
2229 #[cfg(feature = "std")]
2230 analyzer.record_decoding("generic", consumed, duration.as_micros() as u64);
2231 #[cfg(not(feature = "std"))]
2232 analyzer.record_decoding("generic", consumed, 0);
2233 }
2234 Ok(value)
2235 }
2236 Err(e) => {
2237 if let Some(ref mut analyzer) = self.analyzer {
2238 analyzer.record_error(e.clone());
2239 }
2240 Err(e)
2241 }
2242 }
2243 }
2244
2245 pub fn get_stats(&self) -> Option<&EncodingStatistics> {
2247 self.analyzer.as_ref().map(|a| &a.stats)
2248 }
2249
2250 pub fn get_cache_stats(&self) -> Option<(u64, u64, f64)> {
2252 self.cache
2253 .as_ref()
2254 .map(|c| (c.hits, c.misses, c.hit_ratio()))
2255 }
2256
2257 pub fn reset_stats(&mut self) {
2259 if let Some(ref mut analyzer) = self.analyzer {
2260 analyzer.reset();
2261 }
2262 if let Some(ref mut cache) = self.cache {
2263 cache.clear();
2264 }
2265 }
2266}
2267
2268impl Default for EncodingManager {
2269 fn default() -> Self {
2270 Self::new(EncodingConfig::default())
2271 }
2272}
2273
2274#[cfg(test)]
2275mod tests {
2276 use crate::ObjectType;
2277
2278 use super::*;
2279
2280 #[test]
2281 fn test_encode_decode_boolean() {
2282 let mut buffer = Vec::new();
2283
2284 encode_boolean(&mut buffer, true).unwrap();
2286 let (value, consumed) = decode_boolean(&buffer).unwrap();
2287 assert!(value);
2288 assert_eq!(consumed, 1);
2289
2290 buffer.clear();
2292 encode_boolean(&mut buffer, false).unwrap();
2293 let (value, consumed) = decode_boolean(&buffer).unwrap();
2294 assert!(!value);
2295 assert_eq!(consumed, 1);
2296 }
2297
2298 #[test]
2299 fn test_encode_decode_unsigned() {
2300 let mut buffer = Vec::new();
2301 let test_values = [0, 255, 65535, 16777215, 4294967295];
2302
2303 for &test_value in &test_values {
2304 buffer.clear();
2305 encode_unsigned(&mut buffer, test_value).unwrap();
2306 let (value, _) = decode_unsigned(&buffer).unwrap();
2307 assert_eq!(value, test_value);
2308 }
2309 }
2310
2311 #[test]
2312 fn test_encode_decode_signed() {
2313 let mut buffer = Vec::new();
2314 let test_values = [-128, -1, 0, 1, 127, -32768, 32767, -8388608, 8388607];
2315
2316 for &test_value in &test_values {
2317 buffer.clear();
2318 encode_signed(&mut buffer, test_value).unwrap();
2319 let (value, _) = decode_signed(&buffer).unwrap();
2320 assert_eq!(value, test_value);
2321 }
2322 }
2323
2324 #[test]
2325 fn test_encode_decode_real() {
2326 let mut buffer = Vec::new();
2327 let test_values = [
2328 0.0,
2329 1.0,
2330 -1.0,
2331 std::f32::consts::PI,
2332 -273.15,
2333 f32::MAX,
2334 f32::MIN,
2335 ];
2336
2337 for &test_value in &test_values {
2338 buffer.clear();
2339 encode_real(&mut buffer, test_value).unwrap();
2340 let (value, _) = decode_real(&buffer).unwrap();
2341 assert_eq!(value, test_value);
2342 }
2343 }
2344
2345 #[test]
2346 fn test_encode_decode_character_string() {
2347 let mut buffer = Vec::new();
2348 let test_strings = ["Hello", "BACnet", "Temperature Sensor", ""];
2349
2350 for &test_string in &test_strings {
2351 buffer.clear();
2352 encode_character_string(&mut buffer, test_string).unwrap();
2353 let (value, _) = decode_character_string(&buffer).unwrap();
2354 assert_eq!(value, test_string);
2355 }
2356 }
2357
2358 #[test]
2359 fn test_encode_decode_octet_string() {
2360 let mut buffer = Vec::new();
2361 let test_data = vec![0x01, 0x02, 0x03, 0xFF, 0x00];
2362
2363 encode_octet_string(&mut buffer, &test_data).unwrap();
2364 let (decoded, _) = decode_octet_string(&buffer).unwrap();
2365 assert_eq!(decoded, test_data);
2366 }
2367
2368 #[test]
2369 fn test_encode_decode_enumerated() {
2370 let mut buffer = Vec::new();
2371 let test_values = [0, 1, 255, 256, 65535, 65536, 16777215];
2372
2373 for &test_value in &test_values {
2374 buffer.clear();
2375 encode_enumerated(&mut buffer, test_value);
2376 let (value, _) = decode_enumerated(&buffer).unwrap();
2377 assert_eq!(value, test_value);
2378 }
2379 }
2380
2381 #[test]
2382 fn test_encode_decode_date() {
2383 let mut buffer = Vec::new();
2384
2385 encode_date(&mut buffer, 2024, 3, 15, 5).unwrap(); let ((year, month, day, weekday), _) = decode_date(&buffer).unwrap();
2387 assert_eq!(year, 2024);
2388 assert_eq!(month, 3);
2389 assert_eq!(day, 15);
2390 assert_eq!(weekday, 5);
2391 }
2392
2393 #[test]
2394 fn test_encode_decode_time() {
2395 let mut buffer = Vec::new();
2396
2397 encode_time(&mut buffer, 14, 30, 45, 50).unwrap(); let ((hour, minute, second, hundredths), _) = decode_time(&buffer).unwrap();
2399 assert_eq!(hour, 14);
2400 assert_eq!(minute, 30);
2401 assert_eq!(second, 45);
2402 assert_eq!(hundredths, 50);
2403 }
2404
2405 #[test]
2406 fn test_encode_decode_object_identifier() {
2407 let mut buffer = Vec::new();
2408
2409 let object_id = ObjectIdentifier::new(ObjectType::AnalogValue, 12345);
2410 encode_object_identifier(&mut buffer, object_id).unwrap(); let (object_id, _) = decode_object_identifier(&buffer).unwrap();
2412 assert_eq!(object_id.object_type, ObjectType::AnalogValue);
2413 assert_eq!(object_id.instance, 12345);
2414 }
2415
2416 #[test]
2417 fn test_encode_decode_double() {
2418 let mut buffer = Vec::new();
2419 let test_values = [
2420 0.0,
2421 1.0,
2422 -1.0,
2423 std::f64::consts::PI,
2424 -273.15,
2425 f64::MAX,
2426 f64::MIN,
2427 ];
2428
2429 for &test_value in &test_values {
2430 buffer.clear();
2431 encode_double(&mut buffer, test_value).unwrap();
2432 let (value, _) = decode_double(&buffer).unwrap();
2433 assert_eq!(value, test_value);
2434 }
2435 }
2436
2437 #[test]
2438 fn test_buffer_manager() {
2439 use advanced::BufferManager;
2440
2441 let mut manager = BufferManager::new(1024);
2442
2443 let buffer1 = manager.get_encode_buffer();
2445 let buffer2 = manager.get_encode_buffer();
2446
2447 assert_eq!(manager.stats.total_allocations, 2);
2448 assert_eq!(manager.stats.buffer_reuses, 0);
2449
2450 manager.return_buffer(buffer1);
2451 let buffer3 = manager.get_encode_buffer();
2452
2453 assert_eq!(manager.stats.total_allocations, 2);
2454 assert_eq!(manager.stats.buffer_reuses, 1);
2455
2456 manager.return_buffer(buffer2);
2457 manager.return_buffer(buffer3);
2458 }
2459
2460 #[test]
2461 fn test_context_specific_encoding() {
2462 use advanced::context::*;
2463
2464 let mut buffer = Vec::new();
2465
2466 encode_context_tag(&mut buffer, 5, 10).unwrap();
2468 let (tag_number, length, consumed) = decode_context_tag(&buffer).unwrap();
2469
2470 assert_eq!(tag_number, 5);
2471 assert_eq!(length, 10);
2472 assert_eq!(consumed, 2);
2473 }
2474
2475 #[test]
2476 fn test_opening_closing_tags() {
2477 use advanced::context::*;
2478
2479 let mut buffer = Vec::new();
2480
2481 encode_opening_tag(&mut buffer, 3).unwrap();
2483 encode_closing_tag(&mut buffer, 3).unwrap();
2484
2485 assert_eq!(buffer, vec![0x3E, 0x3F]);
2486 }
2487
2488 #[test]
2489 fn test_bit_string_encoding() {
2490 use advanced::bitstring::*;
2491
2492 let mut buffer = Vec::new();
2493 let bits = vec![true, false, true, true, false, false, true, false, true];
2494
2495 encode_bit_string(&mut buffer, &bits).unwrap();
2496 let (decoded_bits, _) = decode_bit_string(&buffer).unwrap();
2497
2498 assert_eq!(decoded_bits, bits);
2499 }
2500
2501 #[test]
2502 fn test_fast_encoder() {
2503 use advanced::perf::FastEncoder;
2504
2505 let mut encoder = FastEncoder::new(256);
2506
2507 encoder.encode_unsigned_fast(42).unwrap();
2509 encoder.encode_boolean_fast(true).unwrap();
2510 encoder.encode_real_fast(std::f32::consts::PI).unwrap();
2511
2512 let data = encoder.data();
2513 assert!(!data.is_empty());
2514
2515 encoder.clear();
2516 assert_eq!(encoder.data().len(), 0);
2517 }
2518
2519 #[test]
2520 fn test_data_validator() {
2521 use advanced::validation::DataValidator;
2522
2523 let validator = DataValidator::new(10, 1000);
2524
2525 let mut buffer = Vec::new();
2527 encode_unsigned(&mut buffer, 42).unwrap();
2528 encode_character_string(&mut buffer, "Hello").unwrap();
2529
2530 assert!(validator.validate(&buffer).is_ok());
2531 }
2532
2533 #[test]
2534 fn test_encode_decode_performance() {
2535 let mut buffer = Vec::new();
2536 let iterations = 1000;
2537
2538 for i in 0..iterations {
2540 buffer.clear();
2541 encode_unsigned(&mut buffer, i).unwrap();
2542 let (value, _) = decode_unsigned(&buffer).unwrap();
2543 assert_eq!(value, i);
2544 }
2545 }
2546
2547 #[test]
2548 fn test_encode_decode_i64() {
2549 let mut buffer = Vec::new();
2550 let test_values = [
2551 0,
2552 1,
2553 -1,
2554 -330,
2555 i32::MAX as i64,
2556 i32::MIN as i64,
2557 i32::MAX as i64 + 10,
2558 i32::MIN as i64 - 10,
2559 i64::MAX,
2560 i64::MIN,
2561 i64::MAX as i32 as i64,
2562 i64::MIN as i32 as i64,
2563 ];
2564
2565 for &test_value in &test_values {
2566 buffer.clear();
2567 encode_signed64(&mut buffer, test_value);
2568 let (value, _) = decode_signed64(&buffer).unwrap();
2569 assert_eq!(value, test_value);
2570 }
2571 }
2572
2573 #[test]
2574 fn test_encode_decode_u64() {
2575 let mut buffer = Vec::new();
2576 let test_values = [
2577 0,
2578 1,
2579 255,
2580 330,
2581 u32::MAX as u64,
2582 u32::MIN as u64,
2583 u32::MAX as u64 + 10,
2584 u64::MAX,
2585 u64::MIN,
2586 u64::MAX as u32 as u64,
2587 u64::MIN as u32 as u64,
2588 ];
2589
2590 for &test_value in &test_values {
2591 buffer.clear();
2592 encode_unsigned64(&mut buffer, test_value);
2593 let (value, _) = decode_unsigned64(&buffer).unwrap();
2594 assert_eq!(value, test_value);
2595 }
2596 }
2597
2598 #[test]
2599 fn test_decode_bacnet_tag() {
2600 let data = [0x21];
2601 let (tag, length, consumed) = decode_tag(&data).unwrap();
2602 assert_eq!(tag, BACnetTag::Application(ApplicationTag::UnsignedInt));
2603 assert_eq!(length, 1);
2604 assert_eq!(consumed, 1);
2605
2606 let data = [0x1E];
2607 let (tag, length, consumed) = decode_tag(&data).unwrap();
2608 assert_eq!(tag, BACnetTag::Context(1));
2609 assert_eq!(length, 6);
2610 assert_eq!(consumed, 1);
2611
2612 let data = [0x0C];
2613 let (tag, length, consumed) = decode_tag(&data).unwrap();
2614 assert_eq!(tag, BACnetTag::Context(0));
2615 assert_eq!(length, 4);
2616 assert_eq!(consumed, 1);
2617
2618 let data = [0x35, 0x08];
2619 let (tag, length, consumed) = decode_tag(&data).unwrap();
2620 assert_eq!(tag, BACnetTag::Application(ApplicationTag::SignedInt));
2621 assert_eq!(length, 8);
2622 assert_eq!(consumed, 2);
2623 }
2624}