Skip to main content

libmagic_rs/evaluator/
types.rs

1// Copyright (c) 2025-2026 the libmagic-rs contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Type interpretation for reading and converting bytes from file buffers
5//!
6//! This module provides functions for safely reading different data types from byte buffers
7//! with proper bounds checking and error handling.
8
9use crate::parser::ast::{Endianness, TypeKind, Value};
10use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian};
11use thiserror::Error;
12
13/// Errors that can occur during type reading operations
14#[derive(Debug, Error, PartialEq, Eq)]
15pub enum TypeReadError {
16    /// Buffer access beyond available data
17    #[error(
18        "Buffer overrun: attempted to read at offset {offset} but buffer length is {buffer_len}"
19    )]
20    BufferOverrun {
21        /// The offset that was attempted to be accessed
22        offset: usize,
23        /// The actual length of the buffer
24        buffer_len: usize,
25    },
26    /// Unsupported type variant
27    #[error("Unsupported type: {type_name}")]
28    UnsupportedType {
29        /// The name of the unsupported type
30        type_name: String,
31    },
32}
33
34/// Safely reads a single byte from the buffer at the specified offset
35///
36/// This function provides secure byte reading with comprehensive bounds checking
37/// to prevent buffer overruns and potential security vulnerabilities.
38///
39/// # Arguments
40///
41/// * `buffer` - The byte buffer to read from
42/// * `offset` - The offset position to read the byte from
43///
44/// # Returns
45///
46/// Returns `Ok(Value::Uint(byte_value))` if the read is successful, or
47/// `Err(TypeReadError::BufferOverrun)` if the offset is beyond the buffer bounds.
48///
49/// # Security
50///
51/// This function performs strict bounds checking to prevent:
52/// - Buffer overruns that could lead to memory safety issues
53/// - Reading uninitialized or out-of-bounds memory
54/// - Integer overflow in offset calculations
55///
56/// # Examples
57///
58/// ```
59/// use libmagic_rs::evaluator::types::read_byte;
60/// use libmagic_rs::parser::ast::Value;
61///
62/// let buffer = &[0x7f, 0x45, 0x4c, 0x46]; // ELF magic bytes
63///
64/// // Read first byte (0x7f)
65/// let result = read_byte(buffer, 0).unwrap();
66/// assert_eq!(result, Value::Uint(0x7f));
67///
68/// // Read last byte (0x46)
69/// let result = read_byte(buffer, 3).unwrap();
70/// assert_eq!(result, Value::Uint(0x46));
71/// ```
72///
73/// # Errors
74///
75/// Returns `TypeReadError::BufferOverrun` if the offset is greater than or equal to
76/// the buffer length.
77pub fn read_byte(buffer: &[u8], offset: usize) -> Result<Value, TypeReadError> {
78    buffer
79        .get(offset)
80        .map(|&byte| Value::Uint(u64::from(byte)))
81        .ok_or(TypeReadError::BufferOverrun {
82            offset,
83            buffer_len: buffer.len(),
84        })
85}
86
87/// Safely reads a 16-bit integer from the buffer at the specified offset
88///
89/// # Arguments
90///
91/// * `buffer` - The byte buffer to read from
92/// * `offset` - The offset position to read the 16-bit value from
93/// * `endian` - The byte order to use for interpretation
94/// * `signed` - Whether to interpret the value as signed or unsigned
95///
96/// # Returns
97///
98/// Returns `Ok(Value::Uint(value))` for unsigned values or `Ok(Value::Int(value))` for signed values
99/// if the read is successful, or `Err(TypeReadError::BufferOverrun)` if there are insufficient bytes.
100///
101/// # Examples
102///
103/// ```
104/// use libmagic_rs::evaluator::types::read_short;
105/// use libmagic_rs::parser::ast::{Endianness, Value};
106///
107/// let buffer = &[0x34, 0x12, 0xff, 0x7f]; // Little-endian data
108///
109/// // Read unsigned little-endian short (0x1234)
110/// let result = read_short(buffer, 0, Endianness::Little, false).unwrap();
111/// assert_eq!(result, Value::Uint(0x1234));
112///
113/// // Read signed little-endian short (0x7fff = 32767)
114/// let result = read_short(buffer, 2, Endianness::Little, true).unwrap();
115/// assert_eq!(result, Value::Int(32767));
116/// ```
117///
118/// # Errors
119///
120/// Returns `TypeReadError::BufferOverrun` if there are fewer than 2 bytes available
121/// starting at the specified offset.
122pub fn read_short(
123    buffer: &[u8],
124    offset: usize,
125    endian: Endianness,
126    signed: bool,
127) -> Result<Value, TypeReadError> {
128    let bytes = buffer
129        .get(offset..offset + 2)
130        .ok_or(TypeReadError::BufferOverrun {
131            offset,
132            buffer_len: buffer.len(),
133        })?;
134
135    let value = match endian {
136        Endianness::Little => LittleEndian::read_u16(bytes),
137        Endianness::Big => BigEndian::read_u16(bytes),
138        Endianness::Native => NativeEndian::read_u16(bytes),
139    };
140
141    if signed {
142        #[allow(clippy::cast_possible_wrap)]
143        Ok(Value::Int(i64::from(value as i16)))
144    } else {
145        Ok(Value::Uint(u64::from(value)))
146    }
147}
148
149/// Safely reads a 32-bit integer from the buffer at the specified offset
150///
151/// # Arguments
152///
153/// * `buffer` - The byte buffer to read from
154/// * `offset` - The offset position to read the 32-bit value from
155/// * `endian` - The byte order to use for interpretation
156/// * `signed` - Whether to interpret the value as signed or unsigned
157///
158/// # Returns
159///
160/// Returns `Ok(Value::Uint(value))` for unsigned values or `Ok(Value::Int(value))` for signed values
161/// if the read is successful, or `Err(TypeReadError::BufferOverrun)` if there are insufficient bytes.
162///
163/// # Examples
164///
165/// ```
166/// use libmagic_rs::evaluator::types::read_long;
167/// use libmagic_rs::parser::ast::{Endianness, Value};
168///
169/// let buffer = &[0x78, 0x56, 0x34, 0x12, 0xff, 0xff, 0xff, 0x7f];
170///
171/// // Read unsigned little-endian long (0x12345678)
172/// let result = read_long(buffer, 0, Endianness::Little, false).unwrap();
173/// assert_eq!(result, Value::Uint(0x12345678));
174///
175/// // Read signed little-endian long (0x7fffffff = 2147483647)
176/// let result = read_long(buffer, 4, Endianness::Little, true).unwrap();
177/// assert_eq!(result, Value::Int(2147483647));
178/// ```
179///
180/// # Errors
181///
182/// Returns `TypeReadError::BufferOverrun` if there are fewer than 4 bytes available
183/// starting at the specified offset.
184pub fn read_long(
185    buffer: &[u8],
186    offset: usize,
187    endian: Endianness,
188    signed: bool,
189) -> Result<Value, TypeReadError> {
190    let bytes = buffer
191        .get(offset..offset + 4)
192        .ok_or(TypeReadError::BufferOverrun {
193            offset,
194            buffer_len: buffer.len(),
195        })?;
196
197    let value = match endian {
198        Endianness::Little => LittleEndian::read_u32(bytes),
199        Endianness::Big => BigEndian::read_u32(bytes),
200        Endianness::Native => NativeEndian::read_u32(bytes),
201    };
202
203    if signed {
204        #[allow(clippy::cast_possible_wrap)]
205        Ok(Value::Int(i64::from(value as i32)))
206    } else {
207        Ok(Value::Uint(u64::from(value)))
208    }
209}
210
211/// Safely reads a null-terminated string from the buffer at the specified offset
212///
213/// This function reads bytes from the buffer starting at the given offset until it encounters
214/// a null byte (0x00) or reaches the maximum length limit. The resulting bytes are converted
215/// to a UTF-8 string with proper error handling for invalid sequences.
216///
217/// # Arguments
218///
219/// * `buffer` - The byte buffer to read from
220/// * `offset` - The offset position to start reading the string from
221/// * `max_length` - Optional maximum number of bytes to read excluding the null terminator.
222///   If a NUL is found within `max_length` bytes, it is not counted in the result length.
223///   If no NUL is found, up to `max_length` bytes are returned with no trailing NUL.
224///   When `None`, reads until the first NUL or end of buffer.
225///
226/// # Returns
227///
228/// Returns `Ok(Value::String(string))` if the read is successful, or an appropriate error
229/// if the read fails due to buffer overrun or invalid UTF-8 sequences.
230///
231/// # Security
232///
233/// This function provides several security guarantees:
234/// - Bounds checking prevents reading beyond buffer limits
235/// - Length limits prevent excessive memory allocation
236/// - UTF-8 validation ensures string safety
237/// - Null termination handling prevents runaway reads
238///
239/// # Examples
240///
241/// ```
242/// use libmagic_rs::evaluator::types::read_string;
243/// use libmagic_rs::parser::ast::Value;
244///
245/// // Null-terminated string
246/// let buffer = b"Hello\x00World";
247/// let result = read_string(buffer, 0, None).unwrap();
248/// assert_eq!(result, Value::String("Hello".to_string()));
249///
250/// // String with length limit
251/// let buffer = b"VeryLongString\x00";
252/// let result = read_string(buffer, 0, Some(4)).unwrap();
253/// assert_eq!(result, Value::String("Very".to_string()));
254///
255/// // String without null terminator (reads to max_length)
256/// let buffer = b"NoNull";
257/// let result = read_string(buffer, 0, Some(6)).unwrap();
258/// assert_eq!(result, Value::String("NoNull".to_string()));
259///
260/// // NUL found within max_length (NUL not counted in result)
261/// let buffer = b"Hello\x00World";
262/// let result = read_string(buffer, 0, Some(10)).unwrap();
263/// assert_eq!(result, Value::String("Hello".to_string()));
264///
265/// // No NUL found, returns exactly max_length bytes
266/// let buffer = b"ABCDEF";
267/// let result = read_string(buffer, 0, Some(4)).unwrap();
268/// assert_eq!(result, Value::String("ABCD".to_string()));
269/// ```
270///
271/// # Errors
272///
273/// Returns `TypeReadError::BufferOverrun` if the offset is beyond the buffer bounds,
274/// or if no null terminator is found within the available buffer space when no `max_length` is specified.
275pub fn read_string(
276    buffer: &[u8],
277    offset: usize,
278    max_length: Option<usize>,
279) -> Result<Value, TypeReadError> {
280    // Check if offset is within buffer bounds
281    if offset >= buffer.len() {
282        return Err(TypeReadError::BufferOverrun {
283            offset,
284            buffer_len: buffer.len(),
285        });
286    }
287
288    // Get the slice starting from offset
289    let remaining_buffer = &buffer[offset..];
290
291    // Determine the actual length to read (uses SIMD-accelerated memchr for null scan)
292    let read_length = if let Some(max_len) = max_length {
293        // Find null terminator within max_length, or use max_length if no null found
294        let search_len = std::cmp::min(max_len, remaining_buffer.len());
295        memchr::memchr(0, &remaining_buffer[..search_len]).unwrap_or(search_len)
296    } else {
297        // Find null terminator in entire remaining buffer
298        memchr::memchr(0, remaining_buffer).unwrap_or(remaining_buffer.len())
299    };
300
301    // Extract the string bytes (excluding null terminator)
302    let string_bytes = &remaining_buffer[..read_length];
303
304    // Convert to UTF-8 string, replacing invalid sequences with replacement character
305    let string_value = String::from_utf8_lossy(string_bytes).into_owned();
306
307    Ok(Value::String(string_value))
308}
309
310/// Reads and interprets bytes according to the specified `TypeKind`
311///
312/// This is the main interface for type interpretation that dispatches to the appropriate
313/// reading function based on the `TypeKind` variant.
314///
315/// # Arguments
316///
317/// * `buffer` - The byte buffer to read from
318/// * `offset` - The offset position to read from
319/// * `type_kind` - The type specification that determines how to interpret the bytes
320///
321/// # Returns
322///
323/// Returns the interpreted value as a `Value` enum variant, or an error if the read fails.
324///
325/// # Examples
326///
327/// ```
328/// use libmagic_rs::evaluator::types::read_typed_value;
329/// use libmagic_rs::parser::ast::{TypeKind, Endianness, Value};
330///
331/// let buffer = &[0x7f, 0x45, 0x4c, 0x46, 0x34, 0x12];
332///
333/// // Read a byte
334/// let byte_result = read_typed_value(buffer, 0, &TypeKind::Byte).unwrap();
335/// assert_eq!(byte_result, Value::Uint(0x7f));
336///
337/// // Read a little-endian short
338/// let short_type = TypeKind::Short {
339///     endian: Endianness::Little,
340///     signed: false,
341/// };
342/// let short_result = read_typed_value(buffer, 4, &short_type).unwrap();
343/// assert_eq!(short_result, Value::Uint(0x1234));
344/// ```
345///
346/// # Errors
347///
348/// Returns `TypeReadError::BufferOverrun` if there are insufficient bytes for the requested type,
349/// or `TypeReadError::UnsupportedType` for type variants that are not yet implemented.
350pub fn read_typed_value(
351    buffer: &[u8],
352    offset: usize,
353    type_kind: &TypeKind,
354) -> Result<Value, TypeReadError> {
355    match type_kind {
356        TypeKind::Byte => read_byte(buffer, offset),
357        TypeKind::Short { endian, signed } => read_short(buffer, offset, *endian, *signed),
358        TypeKind::Long { endian, signed } => read_long(buffer, offset, *endian, *signed),
359        TypeKind::String { max_length } => read_string(buffer, offset, *max_length),
360    }
361}
362
363#[cfg(test)]
364mod tests {
365    use super::*;
366
367    #[test]
368    fn test_read_byte_success() {
369        let buffer = &[0x7f, 0x45, 0x4c, 0x46];
370
371        // Test reading each byte
372        assert_eq!(read_byte(buffer, 0).unwrap(), Value::Uint(0x7f));
373        assert_eq!(read_byte(buffer, 1).unwrap(), Value::Uint(0x45));
374        assert_eq!(read_byte(buffer, 2).unwrap(), Value::Uint(0x4c));
375        assert_eq!(read_byte(buffer, 3).unwrap(), Value::Uint(0x46));
376    }
377
378    #[test]
379    fn test_read_byte_zero_value() {
380        let buffer = &[0x00, 0xff];
381
382        // Test reading zero byte
383        assert_eq!(read_byte(buffer, 0).unwrap(), Value::Uint(0));
384        // Test reading max byte value
385        assert_eq!(read_byte(buffer, 1).unwrap(), Value::Uint(255));
386    }
387
388    #[test]
389    fn test_read_byte_single_byte_buffer() {
390        let buffer = &[0x42];
391
392        // Should succeed for offset 0
393        assert_eq!(read_byte(buffer, 0).unwrap(), Value::Uint(0x42));
394
395        // Should fail for offset 1
396        let result = read_byte(buffer, 1);
397        assert!(result.is_err());
398        assert_eq!(
399            result.unwrap_err(),
400            TypeReadError::BufferOverrun {
401                offset: 1,
402                buffer_len: 1
403            }
404        );
405    }
406
407    #[test]
408    fn test_read_byte_empty_buffer() {
409        let buffer = &[];
410
411        // Should fail for any offset
412        let result = read_byte(buffer, 0);
413        assert!(result.is_err());
414        assert_eq!(
415            result.unwrap_err(),
416            TypeReadError::BufferOverrun {
417                offset: 0,
418                buffer_len: 0
419            }
420        );
421    }
422
423    #[test]
424    fn test_read_byte_out_of_bounds() {
425        let buffer = &[0x01, 0x02, 0x03];
426
427        // Test various out-of-bounds offsets
428        let test_cases = [3, 4, 10, 100, usize::MAX];
429
430        for offset in test_cases {
431            let result = read_byte(buffer, offset);
432            assert!(result.is_err());
433            assert_eq!(
434                result.unwrap_err(),
435                TypeReadError::BufferOverrun {
436                    offset,
437                    buffer_len: 3
438                }
439            );
440        }
441    }
442
443    #[test]
444    fn test_read_byte_large_buffer() {
445        // Test with a larger buffer to ensure no performance issues
446        let buffer: Vec<u8> = (0..=255).collect();
447
448        // Test reading from various positions
449        assert_eq!(read_byte(&buffer, 0).unwrap(), Value::Uint(0));
450        assert_eq!(read_byte(&buffer, 127).unwrap(), Value::Uint(127));
451        assert_eq!(read_byte(&buffer, 255).unwrap(), Value::Uint(255));
452
453        // Test out of bounds
454        let result = read_byte(&buffer, 256);
455        assert!(result.is_err());
456        assert_eq!(
457            result.unwrap_err(),
458            TypeReadError::BufferOverrun {
459                offset: 256,
460                buffer_len: 256
461            }
462        );
463    }
464
465    #[test]
466    fn test_read_byte_all_byte_values() {
467        // Test that all possible byte values are correctly converted to u64
468        let buffer: Vec<u8> = (0..=255).collect();
469
470        for (i, &expected_byte) in buffer.iter().enumerate() {
471            let result = read_byte(&buffer, i).unwrap();
472            assert_eq!(result, Value::Uint(u64::from(expected_byte)));
473        }
474    }
475
476    #[test]
477    fn test_type_read_error_display() {
478        let error = TypeReadError::BufferOverrun {
479            offset: 10,
480            buffer_len: 5,
481        };
482
483        let error_string = format!("{error}");
484        assert!(error_string.contains("Buffer overrun"));
485        assert!(error_string.contains("offset 10"));
486        assert!(error_string.contains("buffer length is 5"));
487    }
488
489    #[test]
490    fn test_type_read_error_debug() {
491        let error = TypeReadError::BufferOverrun {
492            offset: 42,
493            buffer_len: 20,
494        };
495
496        let debug_string = format!("{error:?}");
497        assert!(debug_string.contains("BufferOverrun"));
498        assert!(debug_string.contains("offset: 42"));
499        assert!(debug_string.contains("buffer_len: 20"));
500    }
501
502    #[test]
503    fn test_type_read_error_equality() {
504        let error1 = TypeReadError::BufferOverrun {
505            offset: 5,
506            buffer_len: 3,
507        };
508        let error2 = TypeReadError::BufferOverrun {
509            offset: 5,
510            buffer_len: 3,
511        };
512        let error3 = TypeReadError::BufferOverrun {
513            offset: 6,
514            buffer_len: 3,
515        };
516
517        assert_eq!(error1, error2);
518        assert_ne!(error1, error3);
519    }
520
521    #[test]
522    fn test_read_byte_boundary_conditions() {
523        let buffer = &[0xaa, 0xbb, 0xcc];
524
525        // Test reading at exact boundary (last valid index)
526        assert_eq!(read_byte(buffer, 2).unwrap(), Value::Uint(0xcc));
527
528        // Test reading just past boundary
529        let result = read_byte(buffer, 3);
530        assert!(result.is_err());
531    }
532
533    #[test]
534    fn test_read_byte_return_type() {
535        let buffer = &[0x80]; // Test with high bit set
536
537        let result = read_byte(buffer, 0).unwrap();
538
539        // Verify it returns Value::Uint, not Value::Int
540        match result {
541            Value::Uint(val) => assert_eq!(val, 0x80),
542            _ => panic!("Expected Value::Uint variant"),
543        }
544    }
545
546    // Tests for read_short function
547    #[test]
548    fn test_read_short_little_endian_unsigned() {
549        let buffer = &[0x34, 0x12, 0x78, 0x56]; // 0x1234, 0x5678 in little-endian
550
551        // Read first short (0x1234)
552        let result = read_short(buffer, 0, Endianness::Little, false).unwrap();
553        assert_eq!(result, Value::Uint(0x1234));
554
555        // Read second short (0x5678)
556        let result = read_short(buffer, 2, Endianness::Little, false).unwrap();
557        assert_eq!(result, Value::Uint(0x5678));
558    }
559
560    #[test]
561    fn test_read_short_big_endian_unsigned() {
562        let buffer = &[0x12, 0x34, 0x56, 0x78]; // 0x1234, 0x5678 in big-endian
563
564        // Read first short (0x1234)
565        let result = read_short(buffer, 0, Endianness::Big, false).unwrap();
566        assert_eq!(result, Value::Uint(0x1234));
567
568        // Read second short (0x5678)
569        let result = read_short(buffer, 2, Endianness::Big, false).unwrap();
570        assert_eq!(result, Value::Uint(0x5678));
571    }
572
573    #[test]
574    fn test_read_short_native_endian_unsigned() {
575        let buffer = &[0x34, 0x12, 0x78, 0x56];
576
577        // Read using native endianness
578        let result = read_short(buffer, 0, Endianness::Native, false).unwrap();
579
580        // The exact value depends on the system's endianness, but it should be valid
581        match result {
582            Value::Uint(val) => {
583                // Should be either 0x1234 (little-endian) or 0x3412 (big-endian)
584                assert!(val == 0x1234 || val == 0x3412);
585            }
586            _ => panic!("Expected Value::Uint variant"),
587        }
588    }
589
590    #[test]
591    fn test_read_short_signed_positive() {
592        let buffer = &[0xff, 0x7f]; // 0x7fff = 32767 in little-endian
593
594        let result = read_short(buffer, 0, Endianness::Little, true).unwrap();
595        assert_eq!(result, Value::Int(32767));
596    }
597
598    #[test]
599    fn test_read_short_signed_negative() {
600        let buffer = &[0x00, 0x80]; // 0x8000 = -32768 in little-endian (signed)
601
602        let result = read_short(buffer, 0, Endianness::Little, true).unwrap();
603        assert_eq!(result, Value::Int(-32768));
604    }
605
606    #[test]
607    fn test_read_short_signed_vs_unsigned() {
608        let buffer = &[0xff, 0xff]; // 0xffff
609
610        // Unsigned interpretation
611        let unsigned_result = read_short(buffer, 0, Endianness::Little, false).unwrap();
612        assert_eq!(unsigned_result, Value::Uint(65535));
613
614        // Signed interpretation
615        let signed_result = read_short(buffer, 0, Endianness::Little, true).unwrap();
616        assert_eq!(signed_result, Value::Int(-1));
617    }
618
619    #[test]
620    fn test_read_short_buffer_overrun() {
621        let buffer = &[0x12]; // Only 1 byte available
622
623        // Should fail when trying to read 2 bytes
624        let result = read_short(buffer, 0, Endianness::Little, false);
625        assert!(result.is_err());
626        assert_eq!(
627            result.unwrap_err(),
628            TypeReadError::BufferOverrun {
629                offset: 0,
630                buffer_len: 1
631            }
632        );
633    }
634
635    #[test]
636    fn test_read_short_offset_out_of_bounds() {
637        let buffer = &[0x12, 0x34, 0x56];
638
639        // Should fail when trying to read 2 bytes starting at offset 2 (only 1 byte left)
640        let result = read_short(buffer, 2, Endianness::Little, false);
641        assert!(result.is_err());
642        assert_eq!(
643            result.unwrap_err(),
644            TypeReadError::BufferOverrun {
645                offset: 2,
646                buffer_len: 3
647            }
648        );
649    }
650
651    #[test]
652    fn test_read_short_empty_buffer() {
653        let buffer = &[];
654
655        let result = read_short(buffer, 0, Endianness::Little, false);
656        assert!(result.is_err());
657        assert_eq!(
658            result.unwrap_err(),
659            TypeReadError::BufferOverrun {
660                offset: 0,
661                buffer_len: 0
662            }
663        );
664    }
665
666    #[test]
667    fn test_read_short_all_endianness_variants() {
668        let buffer = &[0x12, 0x34];
669
670        // Test all endianness variants
671        let little = read_short(buffer, 0, Endianness::Little, false).unwrap();
672        let big = read_short(buffer, 0, Endianness::Big, false).unwrap();
673        let native = read_short(buffer, 0, Endianness::Native, false).unwrap();
674
675        // Little-endian: 0x3412, Big-endian: 0x1234
676        assert_eq!(little, Value::Uint(0x3412));
677        assert_eq!(big, Value::Uint(0x1234));
678
679        // Native should match one of them
680        match native {
681            Value::Uint(val) => assert!(val == 0x1234 || val == 0x3412),
682            _ => panic!("Expected Value::Uint variant"),
683        }
684    }
685
686    // Tests for read_long function
687    #[test]
688    fn test_read_long_little_endian_unsigned() {
689        let buffer = &[0x78, 0x56, 0x34, 0x12, 0xbc, 0x9a, 0x78, 0x56]; // 0x12345678, 0x56789abc
690
691        // Read first long (0x12345678)
692        let result = read_long(buffer, 0, Endianness::Little, false).unwrap();
693        assert_eq!(result, Value::Uint(0x1234_5678));
694
695        // Read second long (0x56789abc)
696        let result = read_long(buffer, 4, Endianness::Little, false).unwrap();
697        assert_eq!(result, Value::Uint(0x5678_9abc));
698    }
699
700    #[test]
701    fn test_read_long_big_endian_unsigned() {
702        let buffer = &[0x12, 0x34, 0x56, 0x78, 0x56, 0x78, 0x9a, 0xbc]; // 0x12345678, 0x56789abc
703
704        // Read first long (0x12345678)
705        let result = read_long(buffer, 0, Endianness::Big, false).unwrap();
706        assert_eq!(result, Value::Uint(0x1234_5678));
707
708        // Read second long (0x56789abc)
709        let result = read_long(buffer, 4, Endianness::Big, false).unwrap();
710        assert_eq!(result, Value::Uint(0x5678_9abc));
711    }
712
713    #[test]
714    fn test_read_long_native_endian_unsigned() {
715        let buffer = &[0x78, 0x56, 0x34, 0x12];
716
717        // Read using native endianness
718        let result = read_long(buffer, 0, Endianness::Native, false).unwrap();
719
720        // The exact value depends on the system's endianness, but it should be valid
721        match result {
722            Value::Uint(val) => {
723                // Should be either 0x12345678 (little-endian) or 0x78563412 (big-endian)
724                assert!(val == 0x1234_5678 || val == 0x7856_3412);
725            }
726            _ => panic!("Expected Value::Uint variant"),
727        }
728    }
729
730    #[test]
731    fn test_read_long_signed_positive() {
732        let buffer = &[0xff, 0xff, 0xff, 0x7f]; // 0x7fffffff = 2147483647 in little-endian
733
734        let result = read_long(buffer, 0, Endianness::Little, true).unwrap();
735        assert_eq!(result, Value::Int(2_147_483_647));
736    }
737
738    #[test]
739    fn test_read_long_signed_negative() {
740        let buffer = &[0x00, 0x00, 0x00, 0x80]; // 0x80000000 = -2147483648 in little-endian (signed)
741
742        let result = read_long(buffer, 0, Endianness::Little, true).unwrap();
743        assert_eq!(result, Value::Int(-2_147_483_648));
744    }
745
746    #[test]
747    fn test_read_long_signed_vs_unsigned() {
748        let buffer = &[0xff, 0xff, 0xff, 0xff]; // 0xffffffff
749
750        // Unsigned interpretation
751        let unsigned_result = read_long(buffer, 0, Endianness::Little, false).unwrap();
752        assert_eq!(unsigned_result, Value::Uint(4_294_967_295));
753
754        // Signed interpretation
755        let signed_result = read_long(buffer, 0, Endianness::Little, true).unwrap();
756        assert_eq!(signed_result, Value::Int(-1));
757    }
758
759    #[test]
760    fn test_read_long_buffer_overrun() {
761        let buffer = &[0x12, 0x34, 0x56]; // Only 3 bytes available
762
763        // Should fail when trying to read 4 bytes
764        let result = read_long(buffer, 0, Endianness::Little, false);
765        assert!(result.is_err());
766        assert_eq!(
767            result.unwrap_err(),
768            TypeReadError::BufferOverrun {
769                offset: 0,
770                buffer_len: 3
771            }
772        );
773    }
774
775    #[test]
776    fn test_read_long_offset_out_of_bounds() {
777        let buffer = &[0x12, 0x34, 0x56, 0x78, 0x9a];
778
779        // Should fail when trying to read 4 bytes starting at offset 2 (only 3 bytes left)
780        let result = read_long(buffer, 2, Endianness::Little, false);
781        assert!(result.is_err());
782        assert_eq!(
783            result.unwrap_err(),
784            TypeReadError::BufferOverrun {
785                offset: 2,
786                buffer_len: 5
787            }
788        );
789    }
790
791    #[test]
792    fn test_read_long_empty_buffer() {
793        let buffer = &[];
794
795        let result = read_long(buffer, 0, Endianness::Little, false);
796        assert!(result.is_err());
797        assert_eq!(
798            result.unwrap_err(),
799            TypeReadError::BufferOverrun {
800                offset: 0,
801                buffer_len: 0
802            }
803        );
804    }
805
806    #[test]
807    fn test_read_long_all_endianness_variants() {
808        let buffer = &[0x12, 0x34, 0x56, 0x78];
809
810        // Test all endianness variants
811        let little = read_long(buffer, 0, Endianness::Little, false).unwrap();
812        let big = read_long(buffer, 0, Endianness::Big, false).unwrap();
813        let native = read_long(buffer, 0, Endianness::Native, false).unwrap();
814
815        // Little-endian: 0x78563412, Big-endian: 0x12345678
816        assert_eq!(little, Value::Uint(0x7856_3412));
817        assert_eq!(big, Value::Uint(0x1234_5678));
818
819        // Native should match one of them
820        match native {
821            Value::Uint(val) => assert!(val == 0x1234_5678 || val == 0x7856_3412),
822            _ => panic!("Expected Value::Uint variant"),
823        }
824    }
825
826    #[test]
827    fn test_read_long_extreme_values() {
828        // Test maximum unsigned 32-bit value
829        let max_buffer = &[0xff, 0xff, 0xff, 0xff];
830        let max_result = read_long(max_buffer, 0, Endianness::Little, false).unwrap();
831        assert_eq!(max_result, Value::Uint(u64::from(u32::MAX)));
832
833        // Test zero value
834        let zero_buffer = &[0x00, 0x00, 0x00, 0x00];
835        let zero_result = read_long(zero_buffer, 0, Endianness::Little, false).unwrap();
836        assert_eq!(zero_result, Value::Uint(0));
837    }
838
839    #[test]
840    fn test_read_short_extreme_values() {
841        // Test maximum unsigned 16-bit value
842        let max_buffer = &[0xff, 0xff];
843        let max_result = read_short(max_buffer, 0, Endianness::Little, false).unwrap();
844        assert_eq!(max_result, Value::Uint(u64::from(u16::MAX)));
845
846        // Test zero value
847        let zero_buffer = &[0x00, 0x00];
848        let zero_result = read_short(zero_buffer, 0, Endianness::Little, false).unwrap();
849        assert_eq!(zero_result, Value::Uint(0));
850    }
851
852    #[test]
853    fn test_multi_byte_reading_consistency() {
854        // Test that reading the same bytes with different functions gives consistent results
855        let buffer = &[0x34, 0x12, 0x78, 0x56, 0xbc, 0x9a, 0xde, 0xf0];
856
857        // Read as individual bytes
858        let byte0 = read_byte(buffer, 0).unwrap();
859        let byte1 = read_byte(buffer, 1).unwrap();
860
861        // Read as short
862        let short = read_short(buffer, 0, Endianness::Little, false).unwrap();
863
864        // Verify consistency
865        match (byte0, byte1, short) {
866            (Value::Uint(b0), Value::Uint(b1), Value::Uint(s)) => {
867                assert_eq!(s, b0 + (b1 << 8)); // Little-endian composition
868            }
869            _ => panic!("Expected all Uint values"),
870        }
871    }
872
873    // Tests for UnsupportedType error
874    #[test]
875    fn test_unsupported_type_error() {
876        let error = TypeReadError::UnsupportedType {
877            type_name: "CustomType".to_string(),
878        };
879
880        let error_string = format!("{error}");
881        assert!(error_string.contains("Unsupported type"));
882        assert!(error_string.contains("CustomType"));
883    }
884
885    #[test]
886    fn test_unsupported_type_error_debug() {
887        let error = TypeReadError::UnsupportedType {
888            type_name: "TestType".to_string(),
889        };
890
891        let debug_string = format!("{error:?}");
892        assert!(debug_string.contains("UnsupportedType"));
893        assert!(debug_string.contains("TestType"));
894    }
895
896    #[test]
897    fn test_unsupported_type_error_equality() {
898        let error1 = TypeReadError::UnsupportedType {
899            type_name: "Type1".to_string(),
900        };
901        let error2 = TypeReadError::UnsupportedType {
902            type_name: "Type1".to_string(),
903        };
904        let error3 = TypeReadError::UnsupportedType {
905            type_name: "Type2".to_string(),
906        };
907
908        assert_eq!(error1, error2);
909        assert_ne!(error1, error3);
910    }
911
912    // Tests for read_typed_value function
913    #[test]
914    fn test_read_typed_value_byte() {
915        let buffer = &[0x7f, 0x45, 0x4c, 0x46];
916        let type_kind = TypeKind::Byte;
917
918        let result = read_typed_value(buffer, 0, &type_kind).unwrap();
919        assert_eq!(result, Value::Uint(0x7f));
920
921        let result = read_typed_value(buffer, 3, &type_kind).unwrap();
922        assert_eq!(result, Value::Uint(0x46));
923    }
924
925    #[test]
926    fn test_read_typed_value_short_unsigned_little_endian() {
927        let buffer = &[0x34, 0x12, 0x78, 0x56];
928        let type_kind = TypeKind::Short {
929            endian: Endianness::Little,
930            signed: false,
931        };
932
933        let result = read_typed_value(buffer, 0, &type_kind).unwrap();
934        assert_eq!(result, Value::Uint(0x1234));
935
936        let result = read_typed_value(buffer, 2, &type_kind).unwrap();
937        assert_eq!(result, Value::Uint(0x5678));
938    }
939
940    #[test]
941    fn test_read_typed_value_short_signed_big_endian() {
942        let buffer = &[0x80, 0x00, 0x7f, 0xff];
943        let type_kind = TypeKind::Short {
944            endian: Endianness::Big,
945            signed: true,
946        };
947
948        // 0x8000 = -32768 in signed 16-bit
949        let result = read_typed_value(buffer, 0, &type_kind).unwrap();
950        assert_eq!(result, Value::Int(-32768));
951
952        // 0x7fff = 32767 in signed 16-bit
953        let result = read_typed_value(buffer, 2, &type_kind).unwrap();
954        assert_eq!(result, Value::Int(32767));
955    }
956
957    #[test]
958    fn test_read_typed_value_long_unsigned_little_endian() {
959        let buffer = &[0x78, 0x56, 0x34, 0x12, 0xbc, 0x9a, 0x78, 0x56];
960        let type_kind = TypeKind::Long {
961            endian: Endianness::Little,
962            signed: false,
963        };
964
965        let result = read_typed_value(buffer, 0, &type_kind).unwrap();
966        assert_eq!(result, Value::Uint(0x1234_5678));
967
968        let result = read_typed_value(buffer, 4, &type_kind).unwrap();
969        assert_eq!(result, Value::Uint(0x5678_9abc));
970    }
971
972    #[test]
973    fn test_read_typed_value_long_signed_big_endian() {
974        let buffer = &[0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff];
975        let type_kind = TypeKind::Long {
976            endian: Endianness::Big,
977            signed: true,
978        };
979
980        // 0x80000000 = -2147483648 in signed 32-bit
981        let result = read_typed_value(buffer, 0, &type_kind).unwrap();
982        assert_eq!(result, Value::Int(-2_147_483_648));
983
984        // 0x7fffffff = 2147483647 in signed 32-bit
985        let result = read_typed_value(buffer, 4, &type_kind).unwrap();
986        assert_eq!(result, Value::Int(2_147_483_647));
987    }
988
989    #[test]
990    fn test_read_typed_value_native_endian() {
991        let buffer = &[0x34, 0x12, 0x78, 0x56, 0xbc, 0x9a, 0xde, 0xf0];
992
993        // Test short with native endianness
994        let short_type = TypeKind::Short {
995            endian: Endianness::Native,
996            signed: false,
997        };
998
999        let result = read_typed_value(buffer, 0, &short_type).unwrap();
1000        match result {
1001            Value::Uint(val) => {
1002                // Should be either 0x1234 (little-endian) or 0x3412 (big-endian)
1003                assert!(val == 0x1234 || val == 0x3412);
1004            }
1005            _ => panic!("Expected Value::Uint variant"),
1006        }
1007    }
1008
1009    #[test]
1010    fn test_read_typed_value_string() {
1011        let buffer = b"Hello\x00World\x00";
1012        let type_kind = TypeKind::String { max_length: None };
1013
1014        let result = read_typed_value(buffer, 0, &type_kind).unwrap();
1015        assert_eq!(result, Value::String("Hello".to_string()));
1016
1017        let result = read_typed_value(buffer, 6, &type_kind).unwrap();
1018        assert_eq!(result, Value::String("World".to_string()));
1019    }
1020
1021    #[test]
1022    fn test_read_typed_value_string_with_max_length() {
1023        let buffer = b"VeryLongString\x00";
1024        let type_kind = TypeKind::String {
1025            max_length: Some(4),
1026        };
1027
1028        let result = read_typed_value(buffer, 0, &type_kind).unwrap();
1029        assert_eq!(result, Value::String("Very".to_string()));
1030    }
1031
1032    #[test]
1033    fn test_read_typed_value_buffer_overrun() {
1034        let buffer = &[0x12];
1035        let type_kind = TypeKind::Short {
1036            endian: Endianness::Little,
1037            signed: false,
1038        };
1039
1040        let result = read_typed_value(buffer, 0, &type_kind);
1041        assert!(result.is_err());
1042        assert_eq!(
1043            result.unwrap_err(),
1044            TypeReadError::BufferOverrun {
1045                offset: 0,
1046                buffer_len: 1
1047            }
1048        );
1049    }
1050
1051    // Tests for read_string function
1052    #[test]
1053    fn test_read_string_null_terminated() {
1054        let buffer = b"Hello\x00World";
1055
1056        let result = read_string(buffer, 0, None).unwrap();
1057        assert_eq!(result, Value::String("Hello".to_string()));
1058    }
1059
1060    #[test]
1061    fn test_read_string_null_terminated_at_offset() {
1062        let buffer = b"Prefix\x00Hello\x00Suffix";
1063
1064        let result = read_string(buffer, 7, None).unwrap();
1065        assert_eq!(result, Value::String("Hello".to_string()));
1066    }
1067
1068    #[test]
1069    fn test_read_string_with_max_length_shorter_than_null() {
1070        let buffer = b"VeryLongString\x00";
1071
1072        // Max length is shorter than the null terminator position
1073        let result = read_string(buffer, 0, Some(4)).unwrap();
1074        assert_eq!(result, Value::String("Very".to_string()));
1075    }
1076
1077    #[test]
1078    fn test_read_string_with_max_length_longer_than_null() {
1079        let buffer = b"Short\x00LongerSuffix";
1080
1081        // Max length is longer than the null terminator position
1082        let result = read_string(buffer, 0, Some(10)).unwrap();
1083        assert_eq!(result, Value::String("Short".to_string()));
1084    }
1085
1086    #[test]
1087    fn test_read_string_no_null_terminator_with_max_length() {
1088        let buffer = b"NoNullTerminator";
1089
1090        // Should read up to max_length when no null terminator is found
1091        let result = read_string(buffer, 0, Some(6)).unwrap();
1092        assert_eq!(result, Value::String("NoNull".to_string()));
1093    }
1094
1095    #[test]
1096    fn test_read_string_no_null_terminator_no_max_length() {
1097        let buffer = b"NoNullTerminator";
1098
1099        // Should read entire remaining buffer when no null terminator and no max_length
1100        let result = read_string(buffer, 0, None).unwrap();
1101        assert_eq!(result, Value::String("NoNullTerminator".to_string()));
1102    }
1103
1104    #[test]
1105    fn test_read_string_empty_string() {
1106        let buffer = b"\x00Hello";
1107
1108        // Should return empty string when null terminator is at offset
1109        let result = read_string(buffer, 0, None).unwrap();
1110        assert_eq!(result, Value::String(String::new()));
1111    }
1112
1113    #[test]
1114    fn test_read_string_empty_buffer() {
1115        let buffer = b"";
1116
1117        // Should fail with buffer overrun for empty buffer
1118        let result = read_string(buffer, 0, None);
1119        assert!(result.is_err());
1120        assert_eq!(
1121            result.unwrap_err(),
1122            TypeReadError::BufferOverrun {
1123                offset: 0,
1124                buffer_len: 0
1125            }
1126        );
1127    }
1128
1129    #[test]
1130    fn test_read_string_offset_out_of_bounds() {
1131        let buffer = b"Hello";
1132
1133        // Should fail when offset is beyond buffer length
1134        let result = read_string(buffer, 10, None);
1135        assert!(result.is_err());
1136        assert_eq!(
1137            result.unwrap_err(),
1138            TypeReadError::BufferOverrun {
1139                offset: 10,
1140                buffer_len: 5
1141            }
1142        );
1143    }
1144
1145    #[test]
1146    fn test_read_string_offset_at_buffer_end() {
1147        let buffer = b"Hello";
1148
1149        // Should fail when offset equals buffer length
1150        let result = read_string(buffer, 5, None);
1151        assert!(result.is_err());
1152        assert_eq!(
1153            result.unwrap_err(),
1154            TypeReadError::BufferOverrun {
1155                offset: 5,
1156                buffer_len: 5
1157            }
1158        );
1159    }
1160
1161    #[test]
1162    fn test_read_string_max_length_zero() {
1163        let buffer = b"Hello\x00World";
1164
1165        // Should return empty string when max_length is 0
1166        let result = read_string(buffer, 0, Some(0)).unwrap();
1167        assert_eq!(result, Value::String(String::new()));
1168    }
1169
1170    #[test]
1171    fn test_read_string_max_length_larger_than_buffer() {
1172        let buffer = b"Short";
1173
1174        // Should read entire buffer when max_length exceeds buffer size
1175        let result = read_string(buffer, 0, Some(100)).unwrap();
1176        assert_eq!(result, Value::String("Short".to_string()));
1177    }
1178
1179    #[test]
1180    fn test_read_string_utf8_valid() {
1181        let buffer = b"Caf\xc3\xa9\x00"; // "Café" in UTF-8
1182
1183        let result = read_string(buffer, 0, None).unwrap();
1184        assert_eq!(result, Value::String("Café".to_string()));
1185    }
1186
1187    #[test]
1188    fn test_read_string_utf8_invalid() {
1189        let buffer = b"Invalid\xff\xfe\x00"; // Invalid UTF-8 sequence
1190
1191        let result = read_string(buffer, 0, None).unwrap();
1192        // Should use replacement characters for invalid UTF-8
1193        assert!(matches!(result, Value::String(_)));
1194        if let Value::String(s) = result {
1195            assert!(s.starts_with("Invalid"));
1196            assert!(s.contains('\u{FFFD}')); // UTF-8 replacement character
1197        }
1198    }
1199
1200    #[test]
1201    fn test_read_string_binary_data() {
1202        let buffer = &[0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x80, 0x90]; // "Hello" + binary
1203
1204        let result = read_string(buffer, 0, None).unwrap();
1205        assert_eq!(result, Value::String("Hello".to_string()));
1206    }
1207
1208    #[test]
1209    fn test_read_string_multiple_nulls() {
1210        let buffer = b"First\x00\x00Second\x00";
1211
1212        // Should stop at first null terminator
1213        let result = read_string(buffer, 0, None).unwrap();
1214        assert_eq!(result, Value::String("First".to_string()));
1215
1216        // Reading from second null should return empty string
1217        let result = read_string(buffer, 6, None).unwrap();
1218        assert_eq!(result, Value::String(String::new()));
1219    }
1220
1221    #[test]
1222    fn test_read_string_ascii_control_characters() {
1223        let buffer = b"Hello\x09World\x00"; // Tab character in string
1224
1225        let result = read_string(buffer, 0, None).unwrap();
1226        assert_eq!(result, Value::String("Hello\tWorld".to_string()));
1227    }
1228
1229    #[test]
1230    fn test_read_string_single_character() {
1231        let buffer = b"A\x00";
1232
1233        let result = read_string(buffer, 0, None).unwrap();
1234        assert_eq!(result, Value::String("A".to_string()));
1235    }
1236
1237    #[test]
1238    fn test_read_string_max_length_exact_match() {
1239        let buffer = b"Exact\x00";
1240
1241        // Max length exactly matches string length (excluding null)
1242        let result = read_string(buffer, 0, Some(5)).unwrap();
1243        assert_eq!(result, Value::String("Exact".to_string()));
1244    }
1245
1246    #[test]
1247    fn test_read_string_at_buffer_boundary() {
1248        let buffer = b"Hello";
1249
1250        // Reading from last character position
1251        let result = read_string(buffer, 4, Some(1)).unwrap();
1252        assert_eq!(result, Value::String("o".to_string()));
1253    }
1254
1255    #[test]
1256    fn test_read_string_whitespace_handling() {
1257        let buffer = b"  Spaces  \x00";
1258
1259        // Should preserve whitespace in strings
1260        let result = read_string(buffer, 0, None).unwrap();
1261        assert_eq!(result, Value::String("  Spaces  ".to_string()));
1262    }
1263
1264    #[test]
1265    fn test_read_string_newline_characters() {
1266        let buffer = b"Line1\nLine2\r\n\x00";
1267
1268        let result = read_string(buffer, 0, None).unwrap();
1269        assert_eq!(result, Value::String("Line1\nLine2\r\n".to_string()));
1270    }
1271
1272    #[test]
1273    fn test_read_string_consistency_with_typed_value() {
1274        let buffer = b"Test\x00String";
1275
1276        // Test that read_string and read_typed_value produce same results
1277        let direct_result = read_string(buffer, 0, None).unwrap();
1278
1279        let type_kind = TypeKind::String { max_length: None };
1280        let typed_result = read_typed_value(buffer, 0, &type_kind).unwrap();
1281
1282        assert_eq!(direct_result, typed_result);
1283        assert_eq!(typed_result, Value::String("Test".to_string()));
1284    }
1285
1286    #[test]
1287    fn test_read_string_consistency_with_max_length() {
1288        let buffer = b"LongString\x00";
1289
1290        // Test consistency between direct call and typed_value call with max_length
1291        let direct_result = read_string(buffer, 0, Some(4)).unwrap();
1292
1293        let type_kind = TypeKind::String {
1294            max_length: Some(4),
1295        };
1296        let typed_result = read_typed_value(buffer, 0, &type_kind).unwrap();
1297
1298        assert_eq!(direct_result, typed_result);
1299        assert_eq!(typed_result, Value::String("Long".to_string()));
1300    }
1301
1302    #[test]
1303    fn test_read_string_edge_case_combinations() {
1304        // Test various edge case combinations
1305        let test_cases = [
1306            (b"" as &[u8], 0, None, true), // Empty buffer should fail
1307            (b"\x00", 0, None, false),     // Just null terminator
1308            (b"A", 0, Some(0), false),     // Zero max length
1309            (b"AB", 1, Some(1), false),    // Single char at offset
1310        ];
1311
1312        for (buffer, offset, max_length, should_fail) in test_cases {
1313            let result = read_string(buffer, offset, max_length);
1314
1315            if should_fail {
1316                assert!(
1317                    result.is_err(),
1318                    "Expected failure for buffer {buffer:?}, offset {offset}, max_length {max_length:?}"
1319                );
1320            } else {
1321                assert!(
1322                    result.is_ok(),
1323                    "Expected success for buffer {buffer:?}, offset {offset}, max_length {max_length:?}"
1324                );
1325            }
1326        }
1327    }
1328}
1329
1330#[test]
1331fn test_read_typed_value_buffer_overrun() {
1332    let buffer = &[0x12, 0x34];
1333
1334    // Try to read a long (4 bytes) from a 2-byte buffer
1335    let long_type = TypeKind::Long {
1336        endian: Endianness::Little,
1337        signed: false,
1338    };
1339    let result = read_typed_value(buffer, 0, &long_type);
1340    assert!(result.is_err());
1341    assert_eq!(
1342        result.unwrap_err(),
1343        TypeReadError::BufferOverrun {
1344            offset: 0,
1345            buffer_len: 2
1346        }
1347    );
1348
1349    // Try to read a short (2 bytes) at offset 1 from a 2-byte buffer
1350    let short_type = TypeKind::Short {
1351        endian: Endianness::Little,
1352        signed: false,
1353    };
1354    let result = read_typed_value(buffer, 1, &short_type);
1355    assert!(result.is_err());
1356    assert_eq!(
1357        result.unwrap_err(),
1358        TypeReadError::BufferOverrun {
1359            offset: 1,
1360            buffer_len: 2
1361        }
1362    );
1363}
1364
1365#[test]
1366fn test_read_typed_value_all_supported_types() {
1367    let buffer = &[0x7f, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0xbc, 0x9a];
1368
1369    // Test all supported TypeKind variants
1370    let test_cases = vec![
1371        (TypeKind::Byte, 0, Value::Uint(0x7f)),
1372        (
1373            TypeKind::Short {
1374                endian: Endianness::Little,
1375                signed: false,
1376            },
1377            1,
1378            Value::Uint(0x1234), // bytes [0x34, 0x12] -> 0x1234 little-endian
1379        ),
1380        (
1381            TypeKind::Short {
1382                endian: Endianness::Big,
1383                signed: false,
1384            },
1385            1,
1386            Value::Uint(0x3412), // bytes [0x34, 0x12] -> 0x3412 big-endian
1387        ),
1388        (
1389            TypeKind::Long {
1390                endian: Endianness::Little,
1391                signed: false,
1392            },
1393            1,
1394            Value::Uint(0x5678_1234), // bytes [0x34, 0x12, 0x78, 0x56] -> 0x56781234 little-endian
1395        ),
1396        (
1397            TypeKind::Long {
1398                endian: Endianness::Big,
1399                signed: false,
1400            },
1401            1,
1402            Value::Uint(0x3412_7856), // bytes [0x34, 0x12, 0x78, 0x56] -> 0x34127856 big-endian
1403        ),
1404    ];
1405
1406    for (type_kind, offset, expected) in test_cases {
1407        let result = read_typed_value(buffer, offset, &type_kind).unwrap();
1408        assert_eq!(result, expected, "Failed for type: {type_kind:?}");
1409    }
1410}
1411
1412#[test]
1413fn test_read_typed_value_signed_vs_unsigned() {
1414    let buffer = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
1415
1416    // Test signed vs unsigned interpretation for shorts
1417    let unsigned_short = TypeKind::Short {
1418        endian: Endianness::Little,
1419        signed: false,
1420    };
1421    let signed_short = TypeKind::Short {
1422        endian: Endianness::Little,
1423        signed: true,
1424    };
1425
1426    let unsigned_result = read_typed_value(buffer, 0, &unsigned_short).unwrap();
1427    let signed_result = read_typed_value(buffer, 0, &signed_short).unwrap();
1428
1429    assert_eq!(unsigned_result, Value::Uint(65535));
1430    assert_eq!(signed_result, Value::Int(-1));
1431
1432    // Test signed vs unsigned interpretation for longs
1433    let unsigned_long = TypeKind::Long {
1434        endian: Endianness::Little,
1435        signed: false,
1436    };
1437    let signed_long = TypeKind::Long {
1438        endian: Endianness::Little,
1439        signed: true,
1440    };
1441
1442    let unsigned_result = read_typed_value(buffer, 0, &unsigned_long).unwrap();
1443    let signed_result = read_typed_value(buffer, 0, &signed_long).unwrap();
1444
1445    assert_eq!(unsigned_result, Value::Uint(4_294_967_295));
1446    assert_eq!(signed_result, Value::Int(-1));
1447}
1448
1449#[test]
1450fn test_read_typed_value_consistency_with_direct_calls() {
1451    let buffer = &[0x34, 0x12, 0x78, 0x56, 0xbc, 0x9a, 0xde, 0xf0];
1452
1453    // Test that read_typed_value gives same results as direct function calls
1454    let byte_type = TypeKind::Byte;
1455    let direct_byte = read_byte(buffer, 0).unwrap();
1456    let typed_byte = read_typed_value(buffer, 0, &byte_type).unwrap();
1457    assert_eq!(direct_byte, typed_byte);
1458
1459    let short_type = TypeKind::Short {
1460        endian: Endianness::Little,
1461        signed: false,
1462    };
1463    let direct_short = read_short(buffer, 0, Endianness::Little, false).unwrap();
1464    let typed_short = read_typed_value(buffer, 0, &short_type).unwrap();
1465    assert_eq!(direct_short, typed_short);
1466
1467    let long_type = TypeKind::Long {
1468        endian: Endianness::Big,
1469        signed: true,
1470    };
1471    let direct_long = read_long(buffer, 0, Endianness::Big, true).unwrap();
1472    let typed_long = read_typed_value(buffer, 0, &long_type).unwrap();
1473    assert_eq!(direct_long, typed_long);
1474}
1475
1476#[test]
1477fn test_read_typed_value_empty_buffer() {
1478    let buffer = &[];
1479
1480    // All types should fail on empty buffer
1481    let types = vec![
1482        TypeKind::Byte,
1483        TypeKind::Short {
1484            endian: Endianness::Little,
1485            signed: false,
1486        },
1487        TypeKind::Long {
1488            endian: Endianness::Little,
1489            signed: false,
1490        },
1491    ];
1492
1493    for type_kind in types {
1494        let result = read_typed_value(buffer, 0, &type_kind);
1495        assert!(result.is_err());
1496        match result.unwrap_err() {
1497            TypeReadError::BufferOverrun { offset, buffer_len } => {
1498                assert_eq!(offset, 0);
1499                assert_eq!(buffer_len, 0);
1500            }
1501            TypeReadError::UnsupportedType { .. } => panic!("Expected BufferOverrun error"),
1502        }
1503    }
1504}