lnmp_codec/binary/
types.rs

1//! Binary type system for LNMP v0.4 protocol.
2
3use super::error::BinaryError;
4use lnmp_core::LnmpValue;
5
6/// Type tag for binary values (LNMP v0.4/v0.5)
7#[repr(u8)]
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum TypeTag {
10    /// Integer type (VarInt encoded)
11    Int = 0x01,
12    /// Float type (8-byte IEEE754 LE)
13    Float = 0x02,
14    /// Boolean type (1 byte: 0x00 or 0x01)
15    Bool = 0x03,
16    /// String type (length VarInt + UTF-8 bytes)
17    String = 0x04,
18    /// String array type (count VarInt + repeated length+UTF-8)
19    StringArray = 0x05,
20    /// Nested record type (v0.5) - TAG + FIELD_COUNT + FID/VALUE pairs
21    NestedRecord = 0x06,
22    /// Nested array type (v0.5) - TAG + ELEMENT_COUNT + RECORD entries
23    NestedArray = 0x07,
24    /// Reserved for future use (v0.5+)
25    Reserved08 = 0x08,
26    /// Reserved for future use (v0.5+)
27    Reserved09 = 0x09,
28    /// Reserved for future use (v0.5+)
29    Reserved0A = 0x0A,
30    /// Reserved for future use (v0.5+)
31    Reserved0B = 0x0B,
32    /// Reserved for future use (v0.5+)
33    Reserved0C = 0x0C,
34    /// Reserved for future use (v0.5+)
35    Reserved0D = 0x0D,
36    /// Reserved for future use (v0.5+)
37    Reserved0E = 0x0E,
38    /// Reserved for future use (v0.5+)
39    Reserved0F = 0x0F,
40}
41
42impl TypeTag {
43    /// Converts a byte to a TypeTag
44    pub fn from_u8(byte: u8) -> Result<Self, BinaryError> {
45        match byte {
46            0x01 => Ok(TypeTag::Int),
47            0x02 => Ok(TypeTag::Float),
48            0x03 => Ok(TypeTag::Bool),
49            0x04 => Ok(TypeTag::String),
50            0x05 => Ok(TypeTag::StringArray),
51            0x06 => Ok(TypeTag::NestedRecord),
52            0x07 => Ok(TypeTag::NestedArray),
53            0x08 => Ok(TypeTag::Reserved08),
54            0x09 => Ok(TypeTag::Reserved09),
55            0x0A => Ok(TypeTag::Reserved0A),
56            0x0B => Ok(TypeTag::Reserved0B),
57            0x0C => Ok(TypeTag::Reserved0C),
58            0x0D => Ok(TypeTag::Reserved0D),
59            0x0E => Ok(TypeTag::Reserved0E),
60            0x0F => Ok(TypeTag::Reserved0F),
61            _ => Err(BinaryError::InvalidTypeTag { tag: byte }),
62        }
63    }
64
65    /// Converts the TypeTag to a byte
66    pub fn to_u8(self) -> u8 {
67        self as u8
68    }
69
70    /// Returns true if this is a v0.5+ type tag (nested or reserved)
71    pub fn is_v0_5_type(&self) -> bool {
72        matches!(
73            self,
74            TypeTag::NestedRecord
75                | TypeTag::NestedArray
76                | TypeTag::Reserved08
77                | TypeTag::Reserved09
78                | TypeTag::Reserved0A
79                | TypeTag::Reserved0B
80                | TypeTag::Reserved0C
81                | TypeTag::Reserved0D
82                | TypeTag::Reserved0E
83                | TypeTag::Reserved0F
84        )
85    }
86
87    /// Returns true if this is a reserved type tag
88    pub fn is_reserved(&self) -> bool {
89        matches!(
90            self,
91            TypeTag::Reserved08
92                | TypeTag::Reserved09
93                | TypeTag::Reserved0A
94                | TypeTag::Reserved0B
95                | TypeTag::Reserved0C
96                | TypeTag::Reserved0D
97                | TypeTag::Reserved0E
98                | TypeTag::Reserved0F
99        )
100    }
101}
102
103/// Binary value representation for LNMP v0.4/v0.5
104#[derive(Debug, Clone, PartialEq)]
105pub enum BinaryValue {
106    /// Integer value (i64)
107    Int(i64),
108    /// Floating-point value (f64)
109    Float(f64),
110    /// Boolean value
111    Bool(bool),
112    /// String value
113    String(String),
114    /// Array of strings
115    StringArray(Vec<String>),
116    /// Nested record (v0.5)
117    NestedRecord(Box<lnmp_core::LnmpRecord>),
118    /// Array of nested records (v0.5)
119    NestedArray(Vec<lnmp_core::LnmpRecord>),
120}
121
122impl BinaryValue {
123    /// Converts from LnmpValue to BinaryValue
124    ///
125    /// In v0.5, nested structures are supported. Use `from_lnmp_value_v0_4` for v0.4 compatibility.
126    pub fn from_lnmp_value(value: &LnmpValue) -> Result<Self, BinaryError> {
127        match value {
128            LnmpValue::Int(i) => Ok(BinaryValue::Int(*i)),
129            LnmpValue::Float(f) => Ok(BinaryValue::Float(*f)),
130            LnmpValue::Bool(b) => Ok(BinaryValue::Bool(*b)),
131            LnmpValue::String(s) => Ok(BinaryValue::String(s.clone())),
132            LnmpValue::StringArray(arr) => Ok(BinaryValue::StringArray(arr.clone())),
133            LnmpValue::NestedRecord(rec) => Ok(BinaryValue::NestedRecord(rec.clone())),
134            LnmpValue::NestedArray(arr) => Ok(BinaryValue::NestedArray(arr.clone())),
135        }
136    }
137
138    /// Converts from LnmpValue to BinaryValue (v0.4 compatibility mode)
139    ///
140    /// Returns an error if the value contains nested structures (not supported in v0.4)
141    pub fn from_lnmp_value_v0_4(value: &LnmpValue) -> Result<Self, BinaryError> {
142        match value {
143            LnmpValue::Int(i) => Ok(BinaryValue::Int(*i)),
144            LnmpValue::Float(f) => Ok(BinaryValue::Float(*f)),
145            LnmpValue::Bool(b) => Ok(BinaryValue::Bool(*b)),
146            LnmpValue::String(s) => Ok(BinaryValue::String(s.clone())),
147            LnmpValue::StringArray(arr) => Ok(BinaryValue::StringArray(arr.clone())),
148            LnmpValue::NestedRecord(_) => Err(BinaryError::InvalidValue {
149                field_id: 0,
150                type_tag: 0x06,
151                reason: "Nested records not supported in v0.4 binary format".to_string(),
152            }),
153            LnmpValue::NestedArray(_) => Err(BinaryError::InvalidValue {
154                field_id: 0,
155                type_tag: 0x07,
156                reason: "Nested arrays not supported in v0.4 binary format".to_string(),
157            }),
158        }
159    }
160
161    /// Converts to LnmpValue
162    pub fn to_lnmp_value(&self) -> LnmpValue {
163        match self {
164            BinaryValue::Int(i) => LnmpValue::Int(*i),
165            BinaryValue::Float(f) => LnmpValue::Float(*f),
166            BinaryValue::Bool(b) => LnmpValue::Bool(*b),
167            BinaryValue::String(s) => LnmpValue::String(s.clone()),
168            BinaryValue::StringArray(arr) => LnmpValue::StringArray(arr.clone()),
169            BinaryValue::NestedRecord(rec) => LnmpValue::NestedRecord(rec.clone()),
170            BinaryValue::NestedArray(arr) => LnmpValue::NestedArray(arr.clone()),
171        }
172    }
173
174    /// Returns the type tag for this value
175    pub fn type_tag(&self) -> TypeTag {
176        match self {
177            BinaryValue::Int(_) => TypeTag::Int,
178            BinaryValue::Float(_) => TypeTag::Float,
179            BinaryValue::Bool(_) => TypeTag::Bool,
180            BinaryValue::String(_) => TypeTag::String,
181            BinaryValue::StringArray(_) => TypeTag::StringArray,
182            BinaryValue::NestedRecord(_) => TypeTag::NestedRecord,
183            BinaryValue::NestedArray(_) => TypeTag::NestedArray,
184        }
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    #![allow(clippy::approx_constant)]
191
192    use super::*;
193    use lnmp_core::LnmpRecord;
194
195    #[test]
196    fn test_type_tag_from_u8() {
197        assert_eq!(TypeTag::from_u8(0x01).unwrap(), TypeTag::Int);
198        assert_eq!(TypeTag::from_u8(0x02).unwrap(), TypeTag::Float);
199        assert_eq!(TypeTag::from_u8(0x03).unwrap(), TypeTag::Bool);
200        assert_eq!(TypeTag::from_u8(0x04).unwrap(), TypeTag::String);
201        assert_eq!(TypeTag::from_u8(0x05).unwrap(), TypeTag::StringArray);
202    }
203
204    #[test]
205    fn test_type_tag_from_u8_invalid() {
206        assert!(TypeTag::from_u8(0x00).is_err());
207        assert!(TypeTag::from_u8(0xFF).is_err());
208    }
209
210    #[test]
211    fn test_type_tag_from_u8_v0_5_types() {
212        // v0.5 types should now be valid
213        assert_eq!(TypeTag::from_u8(0x06).unwrap(), TypeTag::NestedRecord);
214        assert_eq!(TypeTag::from_u8(0x07).unwrap(), TypeTag::NestedArray);
215    }
216
217    #[test]
218    fn test_type_tag_from_u8_reserved() {
219        // Reserved types should be valid but marked as reserved
220        assert_eq!(TypeTag::from_u8(0x08).unwrap(), TypeTag::Reserved08);
221        assert_eq!(TypeTag::from_u8(0x09).unwrap(), TypeTag::Reserved09);
222        assert_eq!(TypeTag::from_u8(0x0A).unwrap(), TypeTag::Reserved0A);
223        assert_eq!(TypeTag::from_u8(0x0B).unwrap(), TypeTag::Reserved0B);
224        assert_eq!(TypeTag::from_u8(0x0C).unwrap(), TypeTag::Reserved0C);
225        assert_eq!(TypeTag::from_u8(0x0D).unwrap(), TypeTag::Reserved0D);
226        assert_eq!(TypeTag::from_u8(0x0E).unwrap(), TypeTag::Reserved0E);
227        assert_eq!(TypeTag::from_u8(0x0F).unwrap(), TypeTag::Reserved0F);
228    }
229
230    #[test]
231    fn test_type_tag_to_u8() {
232        assert_eq!(TypeTag::Int.to_u8(), 0x01);
233        assert_eq!(TypeTag::Float.to_u8(), 0x02);
234        assert_eq!(TypeTag::Bool.to_u8(), 0x03);
235        assert_eq!(TypeTag::String.to_u8(), 0x04);
236        assert_eq!(TypeTag::StringArray.to_u8(), 0x05);
237    }
238
239    #[test]
240    fn test_type_tag_round_trip() {
241        let tags = vec![
242            TypeTag::Int,
243            TypeTag::Float,
244            TypeTag::Bool,
245            TypeTag::String,
246            TypeTag::StringArray,
247            TypeTag::NestedRecord,
248            TypeTag::NestedArray,
249            TypeTag::Reserved08,
250            TypeTag::Reserved09,
251            TypeTag::Reserved0A,
252            TypeTag::Reserved0B,
253            TypeTag::Reserved0C,
254            TypeTag::Reserved0D,
255            TypeTag::Reserved0E,
256            TypeTag::Reserved0F,
257        ];
258
259        for tag in tags {
260            let byte = tag.to_u8();
261            let parsed = TypeTag::from_u8(byte).unwrap();
262            assert_eq!(parsed, tag);
263        }
264    }
265
266    #[test]
267    fn test_type_tag_is_v0_5_type() {
268        // v0.4 types should return false
269        assert!(!TypeTag::Int.is_v0_5_type());
270        assert!(!TypeTag::Float.is_v0_5_type());
271        assert!(!TypeTag::Bool.is_v0_5_type());
272        assert!(!TypeTag::String.is_v0_5_type());
273        assert!(!TypeTag::StringArray.is_v0_5_type());
274
275        // v0.5 types should return true
276        assert!(TypeTag::NestedRecord.is_v0_5_type());
277        assert!(TypeTag::NestedArray.is_v0_5_type());
278        assert!(TypeTag::Reserved08.is_v0_5_type());
279        assert!(TypeTag::Reserved09.is_v0_5_type());
280        assert!(TypeTag::Reserved0A.is_v0_5_type());
281        assert!(TypeTag::Reserved0B.is_v0_5_type());
282        assert!(TypeTag::Reserved0C.is_v0_5_type());
283        assert!(TypeTag::Reserved0D.is_v0_5_type());
284        assert!(TypeTag::Reserved0E.is_v0_5_type());
285        assert!(TypeTag::Reserved0F.is_v0_5_type());
286    }
287
288    #[test]
289    fn test_type_tag_is_reserved() {
290        // Non-reserved types should return false
291        assert!(!TypeTag::Int.is_reserved());
292        assert!(!TypeTag::Float.is_reserved());
293        assert!(!TypeTag::Bool.is_reserved());
294        assert!(!TypeTag::String.is_reserved());
295        assert!(!TypeTag::StringArray.is_reserved());
296        assert!(!TypeTag::NestedRecord.is_reserved());
297        assert!(!TypeTag::NestedArray.is_reserved());
298
299        // Reserved types should return true
300        assert!(TypeTag::Reserved08.is_reserved());
301        assert!(TypeTag::Reserved09.is_reserved());
302        assert!(TypeTag::Reserved0A.is_reserved());
303        assert!(TypeTag::Reserved0B.is_reserved());
304        assert!(TypeTag::Reserved0C.is_reserved());
305        assert!(TypeTag::Reserved0D.is_reserved());
306        assert!(TypeTag::Reserved0E.is_reserved());
307        assert!(TypeTag::Reserved0F.is_reserved());
308    }
309
310    #[test]
311    fn test_binary_value_from_lnmp_int() {
312        let lnmp_val = LnmpValue::Int(42);
313        let binary_val = BinaryValue::from_lnmp_value(&lnmp_val).unwrap();
314        assert_eq!(binary_val, BinaryValue::Int(42));
315    }
316
317    #[test]
318    fn test_binary_value_from_lnmp_float() {
319        let lnmp_val = LnmpValue::Float(3.14);
320        let binary_val = BinaryValue::from_lnmp_value(&lnmp_val).unwrap();
321        assert_eq!(binary_val, BinaryValue::Float(3.14));
322    }
323
324    #[test]
325    fn test_binary_value_from_lnmp_bool() {
326        let lnmp_val = LnmpValue::Bool(true);
327        let binary_val = BinaryValue::from_lnmp_value(&lnmp_val).unwrap();
328        assert_eq!(binary_val, BinaryValue::Bool(true));
329    }
330
331    #[test]
332    fn test_binary_value_from_lnmp_string() {
333        let lnmp_val = LnmpValue::String("hello".to_string());
334        let binary_val = BinaryValue::from_lnmp_value(&lnmp_val).unwrap();
335        assert_eq!(binary_val, BinaryValue::String("hello".to_string()));
336    }
337
338    #[test]
339    fn test_binary_value_from_lnmp_string_array() {
340        let lnmp_val = LnmpValue::StringArray(vec!["a".to_string(), "b".to_string()]);
341        let binary_val = BinaryValue::from_lnmp_value(&lnmp_val).unwrap();
342        assert_eq!(
343            binary_val,
344            BinaryValue::StringArray(vec!["a".to_string(), "b".to_string()])
345        );
346    }
347
348    #[test]
349    fn test_binary_value_from_lnmp_nested_record() {
350        // v0.5 now supports nested records
351        let nested = LnmpValue::NestedRecord(Box::new(LnmpRecord::new()));
352        let result = BinaryValue::from_lnmp_value(&nested);
353        assert!(result.is_ok());
354        match result.unwrap() {
355            BinaryValue::NestedRecord(_) => {}
356            _ => panic!("Expected NestedRecord variant"),
357        }
358    }
359
360    #[test]
361    fn test_binary_value_from_lnmp_nested_array() {
362        // v0.5 now supports nested arrays
363        let nested = LnmpValue::NestedArray(vec![]);
364        let result = BinaryValue::from_lnmp_value(&nested);
365        assert!(result.is_ok());
366        match result.unwrap() {
367            BinaryValue::NestedArray(_) => {}
368            _ => panic!("Expected NestedArray variant"),
369        }
370    }
371
372    #[test]
373    fn test_binary_value_from_lnmp_nested_record_error_v0_4() {
374        // v0.4 compatibility mode should still reject nested records
375        let nested = LnmpValue::NestedRecord(Box::new(LnmpRecord::new()));
376        let result = BinaryValue::from_lnmp_value_v0_4(&nested);
377        assert!(result.is_err());
378        match result {
379            Err(BinaryError::InvalidValue { reason, .. }) => {
380                assert!(reason.contains("not supported in v0.4"));
381            }
382            _ => panic!("Expected InvalidValue error"),
383        }
384    }
385
386    #[test]
387    fn test_binary_value_from_lnmp_nested_array_error_v0_4() {
388        // v0.4 compatibility mode should still reject nested arrays
389        let nested = LnmpValue::NestedArray(vec![]);
390        let result = BinaryValue::from_lnmp_value_v0_4(&nested);
391        assert!(result.is_err());
392        match result {
393            Err(BinaryError::InvalidValue { reason, .. }) => {
394                assert!(reason.contains("not supported in v0.4"));
395            }
396            _ => panic!("Expected InvalidValue error"),
397        }
398    }
399
400    #[test]
401    fn test_binary_value_to_lnmp_int() {
402        let binary_val = BinaryValue::Int(-42);
403        let lnmp_val = binary_val.to_lnmp_value();
404        assert_eq!(lnmp_val, LnmpValue::Int(-42));
405    }
406
407    #[test]
408    fn test_binary_value_to_lnmp_float() {
409        let binary_val = BinaryValue::Float(2.718);
410        let lnmp_val = binary_val.to_lnmp_value();
411        assert_eq!(lnmp_val, LnmpValue::Float(2.718));
412    }
413
414    #[test]
415    fn test_binary_value_to_lnmp_bool() {
416        let binary_val = BinaryValue::Bool(false);
417        let lnmp_val = binary_val.to_lnmp_value();
418        assert_eq!(lnmp_val, LnmpValue::Bool(false));
419    }
420
421    #[test]
422    fn test_binary_value_to_lnmp_string() {
423        let binary_val = BinaryValue::String("world".to_string());
424        let lnmp_val = binary_val.to_lnmp_value();
425        assert_eq!(lnmp_val, LnmpValue::String("world".to_string()));
426    }
427
428    #[test]
429    fn test_binary_value_to_lnmp_string_array() {
430        let binary_val = BinaryValue::StringArray(vec!["x".to_string(), "y".to_string()]);
431        let lnmp_val = binary_val.to_lnmp_value();
432        assert_eq!(
433            lnmp_val,
434            LnmpValue::StringArray(vec!["x".to_string(), "y".to_string()])
435        );
436    }
437
438    #[test]
439    fn test_binary_value_round_trip_int() {
440        let original = LnmpValue::Int(12345);
441        let binary = BinaryValue::from_lnmp_value(&original).unwrap();
442        let back = binary.to_lnmp_value();
443        assert_eq!(original, back);
444    }
445
446    #[test]
447    fn test_binary_value_round_trip_float() {
448        let original = LnmpValue::Float(1.414);
449        let binary = BinaryValue::from_lnmp_value(&original).unwrap();
450        let back = binary.to_lnmp_value();
451        assert_eq!(original, back);
452    }
453
454    #[test]
455    fn test_binary_value_round_trip_bool() {
456        let original = LnmpValue::Bool(true);
457        let binary = BinaryValue::from_lnmp_value(&original).unwrap();
458        let back = binary.to_lnmp_value();
459        assert_eq!(original, back);
460    }
461
462    #[test]
463    fn test_binary_value_round_trip_string() {
464        let original = LnmpValue::String("test".to_string());
465        let binary = BinaryValue::from_lnmp_value(&original).unwrap();
466        let back = binary.to_lnmp_value();
467        assert_eq!(original, back);
468    }
469
470    #[test]
471    fn test_binary_value_round_trip_string_array() {
472        let original = LnmpValue::StringArray(vec!["admin".to_string(), "dev".to_string()]);
473        let binary = BinaryValue::from_lnmp_value(&original).unwrap();
474        let back = binary.to_lnmp_value();
475        assert_eq!(original, back);
476    }
477
478    #[test]
479    fn test_binary_value_type_tag_int() {
480        let val = BinaryValue::Int(100);
481        assert_eq!(val.type_tag(), TypeTag::Int);
482    }
483
484    #[test]
485    fn test_binary_value_type_tag_float() {
486        let val = BinaryValue::Float(3.14);
487        assert_eq!(val.type_tag(), TypeTag::Float);
488    }
489
490    #[test]
491    fn test_binary_value_type_tag_bool() {
492        let val = BinaryValue::Bool(true);
493        assert_eq!(val.type_tag(), TypeTag::Bool);
494    }
495
496    #[test]
497    fn test_binary_value_type_tag_string() {
498        let val = BinaryValue::String("test".to_string());
499        assert_eq!(val.type_tag(), TypeTag::String);
500    }
501
502    #[test]
503    fn test_binary_value_type_tag_string_array() {
504        let val = BinaryValue::StringArray(vec!["a".to_string()]);
505        assert_eq!(val.type_tag(), TypeTag::StringArray);
506    }
507
508    #[test]
509    fn test_binary_value_type_tag_nested_record() {
510        let val = BinaryValue::NestedRecord(Box::new(LnmpRecord::new()));
511        assert_eq!(val.type_tag(), TypeTag::NestedRecord);
512    }
513
514    #[test]
515    fn test_binary_value_type_tag_nested_array() {
516        let val = BinaryValue::NestedArray(vec![]);
517        assert_eq!(val.type_tag(), TypeTag::NestedArray);
518    }
519
520    #[test]
521    fn test_binary_value_round_trip_nested_record() {
522        let mut record = LnmpRecord::new();
523        record.add_field(lnmp_core::LnmpField {
524            fid: 1,
525            value: LnmpValue::Int(42),
526        });
527        let original = LnmpValue::NestedRecord(Box::new(record));
528        let binary = BinaryValue::from_lnmp_value(&original).unwrap();
529        let back = binary.to_lnmp_value();
530        assert_eq!(original, back);
531    }
532
533    #[test]
534    fn test_binary_value_round_trip_nested_array() {
535        let mut record = LnmpRecord::new();
536        record.add_field(lnmp_core::LnmpField {
537            fid: 1,
538            value: LnmpValue::String("test".to_string()),
539        });
540        let original = LnmpValue::NestedArray(vec![record]);
541        let binary = BinaryValue::from_lnmp_value(&original).unwrap();
542        let back = binary.to_lnmp_value();
543        assert_eq!(original, back);
544    }
545
546    #[test]
547    fn test_binary_value_empty_string() {
548        let lnmp_val = LnmpValue::String("".to_string());
549        let binary_val = BinaryValue::from_lnmp_value(&lnmp_val).unwrap();
550        assert_eq!(binary_val, BinaryValue::String("".to_string()));
551        let back = binary_val.to_lnmp_value();
552        assert_eq!(back, lnmp_val);
553    }
554
555    #[test]
556    fn test_binary_value_empty_string_array() {
557        let lnmp_val = LnmpValue::StringArray(vec![]);
558        let binary_val = BinaryValue::from_lnmp_value(&lnmp_val).unwrap();
559        assert_eq!(binary_val, BinaryValue::StringArray(vec![]));
560        let back = binary_val.to_lnmp_value();
561        assert_eq!(back, lnmp_val);
562    }
563
564    #[test]
565    fn test_binary_value_negative_int() {
566        let lnmp_val = LnmpValue::Int(-9999);
567        let binary_val = BinaryValue::from_lnmp_value(&lnmp_val).unwrap();
568        assert_eq!(binary_val, BinaryValue::Int(-9999));
569        let back = binary_val.to_lnmp_value();
570        assert_eq!(back, lnmp_val);
571    }
572
573    #[test]
574    fn test_binary_value_special_floats() {
575        // Test NaN
576        let nan_val = LnmpValue::Float(f64::NAN);
577        let binary_nan = BinaryValue::from_lnmp_value(&nan_val).unwrap();
578        match binary_nan {
579            BinaryValue::Float(f) => assert!(f.is_nan()),
580            _ => panic!("Expected Float variant"),
581        }
582
583        // Test Infinity
584        let inf_val = LnmpValue::Float(f64::INFINITY);
585        let binary_inf = BinaryValue::from_lnmp_value(&inf_val).unwrap();
586        assert_eq!(binary_inf, BinaryValue::Float(f64::INFINITY));
587
588        // Test Negative Infinity
589        let neg_inf_val = LnmpValue::Float(f64::NEG_INFINITY);
590        let binary_neg_inf = BinaryValue::from_lnmp_value(&neg_inf_val).unwrap();
591        assert_eq!(binary_neg_inf, BinaryValue::Float(f64::NEG_INFINITY));
592    }
593}