Skip to main content

noxu_bind/tuple/
tuple_input.rs

1//! TupleInput: reads primitive types from a byte buffer using sortable encodings.
2//!
3
4use crate::error::{BindError, Result};
5use bytes::Bytes;
6
7/// A reader for tuple-encoded byte data.
8///
9/// Reads primitive values from a byte buffer using the same encoding formats
10/// as `TupleInput`. Signed integers use big-endian with the sign bit
11/// flipped for sortable ordering. Floats use IEEE 754 with bit manipulation
12/// for sortable ordering.
13///
14/// Internally uses `bytes::Bytes` so that `clone()` is O(1) and `from_vec`
15/// is zero-copy.
16///
17///
18#[derive(Debug, Clone)]
19pub struct TupleInput {
20    buf: Bytes,
21    off: usize,
22}
23
24impl TupleInput {
25    /// Creates a new `TupleInput` from a byte slice (copies the slice).
26    pub fn new(data: &[u8]) -> Self {
27        Self { buf: Bytes::copy_from_slice(data), off: 0 }
28    }
29
30    /// Creates a new `TupleInput` from a byte vector — zero-copy.
31    pub fn from_vec(data: Vec<u8>) -> Self {
32        Self { buf: Bytes::from(data), off: 0 }
33    }
34
35    /// Creates a new `TupleInput` from existing `Bytes` — zero-copy.
36    pub fn from_bytes(data: Bytes) -> Self {
37        Self { buf: data, off: 0 }
38    }
39
40    /// Returns the number of bytes remaining to be read.
41    pub fn available(&self) -> usize {
42        self.buf.len().saturating_sub(self.off)
43    }
44
45    /// Returns the current read offset.
46    pub fn get_offset(&self) -> usize {
47        self.off
48    }
49
50    /// Sets the read offset.
51    pub fn set_offset(&mut self, offset: usize) {
52        self.off = offset;
53    }
54
55    /// Returns a reference to the underlying buffer.
56    pub fn get_buffer(&self) -> &[u8] {
57        &self.buf
58    }
59
60    /// Reads a single byte from the buffer.
61    fn read_fast(&mut self) -> Result<u8> {
62        if self.off >= self.buf.len() {
63            return Err(BindError::BufferUnderflow { needed: 1, available: 0 });
64        }
65        let b = self.buf[self.off];
66        self.off += 1;
67        Ok(b)
68    }
69
70    /// Reads a boolean (one byte) value. Non-zero is `true`.
71    ///
72    /// Reads values written by `TupleOutput::write_bool`.
73    pub fn read_bool(&mut self) -> Result<bool> {
74        Ok(self.read_fast()? != 0)
75    }
76
77    /// Reads an unsigned byte value.
78    ///
79    /// Reads values written by `TupleOutput::write_u8`.
80    pub fn read_u8(&mut self) -> Result<u8> {
81        self.read_fast()
82    }
83
84    /// Reads a signed byte (one byte) value with sign bit flipped for sort order.
85    ///
86    /// Reads values written by `TupleOutput::write_i8`.
87    pub fn read_i8(&mut self) -> Result<i8> {
88        let b = self.read_fast()?;
89        Ok((b ^ 0x80) as i8)
90    }
91
92    /// Reads an unsigned short (two byte, big-endian) value.
93    ///
94    /// Reads values written by `TupleOutput::write_u16`.
95    pub fn read_u16(&mut self) -> Result<u16> {
96        let c1 = self.read_fast()? as u16;
97        let c2 = self.read_fast()? as u16;
98        Ok((c1 << 8) | c2)
99    }
100
101    /// Reads a signed short (two byte) value with sign bit flipped for sort order.
102    ///
103    /// Reads values written by `TupleOutput::write_i16`.
104    pub fn read_i16(&mut self) -> Result<i16> {
105        let v = self.read_u16()?;
106        Ok((v ^ 0x8000) as i16)
107    }
108
109    /// Reads an unsigned int (four byte, big-endian) value.
110    ///
111    /// Reads values written by `TupleOutput::write_u32`.
112    pub fn read_u32(&mut self) -> Result<u32> {
113        let c1 = self.read_fast()? as u32;
114        let c2 = self.read_fast()? as u32;
115        let c3 = self.read_fast()? as u32;
116        let c4 = self.read_fast()? as u32;
117        Ok((c1 << 24) | (c2 << 16) | (c3 << 8) | c4)
118    }
119
120    /// Reads a signed int (four byte) value with sign bit flipped for sort order.
121    ///
122    /// Reads values written by `TupleOutput::write_i32`.
123    pub fn read_i32(&mut self) -> Result<i32> {
124        let v = self.read_u32()?;
125        Ok((v ^ 0x80000000) as i32)
126    }
127
128    /// Reads an unsigned long (eight byte, big-endian) value.
129    ///
130    /// Reads values written by `TupleOutput::write_u64`.
131    pub fn read_u64(&mut self) -> Result<u64> {
132        let c1 = self.read_fast()? as u64;
133        let c2 = self.read_fast()? as u64;
134        let c3 = self.read_fast()? as u64;
135        let c4 = self.read_fast()? as u64;
136        let c5 = self.read_fast()? as u64;
137        let c6 = self.read_fast()? as u64;
138        let c7 = self.read_fast()? as u64;
139        let c8 = self.read_fast()? as u64;
140        Ok((c1 << 56)
141            | (c2 << 48)
142            | (c3 << 40)
143            | (c4 << 32)
144            | (c5 << 24)
145            | (c6 << 16)
146            | (c7 << 8)
147            | c8)
148    }
149
150    /// Reads a signed long (eight byte) value with sign bit flipped for sort order.
151    ///
152    /// Reads values written by `TupleOutput::write_i64`.
153    pub fn read_i64(&mut self) -> Result<i64> {
154        let v = self.read_u64()?;
155        Ok((v ^ 0x8000000000000000) as i64)
156    }
157
158    /// Reads an unsorted float (four byte) value from the buffer.
159    ///
160    /// The float is stored as raw IEEE 754 bits in big-endian order.
161    /// This does NOT produce sortable byte ordering.
162    ///
163    /// Reads values written by `TupleOutput::write_float`.
164    pub fn read_float(&mut self) -> Result<f32> {
165        let bits = self.read_u32()?;
166        Ok(f32::from_bits(bits))
167    }
168
169    /// Reads an unsorted double (eight byte) value from the buffer.
170    ///
171    /// The double is stored as raw IEEE 754 bits in big-endian order.
172    /// This does NOT produce sortable byte ordering.
173    ///
174    /// Reads values written by `TupleOutput::write_double`.
175    pub fn read_double(&mut self) -> Result<f64> {
176        let bits = self.read_u64()?;
177        Ok(f64::from_bits(bits))
178    }
179
180    /// Reads a sorted float (four byte) value from the buffer.
181    ///
182    /// Uses sign-bit manipulation to produce sortable byte ordering:
183    /// - Positive floats: sign bit flipped (0x80000000 XOR)
184    /// - Negative floats: all bits flipped (0xFFFFFFFF XOR)
185    ///
186    /// Reads values written by `TupleOutput::write_sorted_float`.
187    pub fn read_sorted_float(&mut self) -> Result<f32> {
188        let encoded = self.read_u32()?;
189        // If the high bit is set after reading, it was originally positive
190        // (sign bit was flipped to 1), so XOR with 0x80000000.
191        // If high bit is clear, it was originally negative (all bits flipped),
192        // so XOR with 0xFFFFFFFF.
193        let bits = if encoded & 0x80000000 != 0 {
194            encoded ^ 0x80000000
195        } else {
196            encoded ^ 0xFFFFFFFF
197        };
198        Ok(f32::from_bits(bits))
199    }
200
201    /// Reads a sorted double (eight byte) value from the buffer.
202    ///
203    /// Uses sign-bit manipulation to produce sortable byte ordering:
204    /// - Positive doubles: sign bit flipped (0x8000000000000000 XOR)
205    /// - Negative doubles: all bits flipped (0xFFFFFFFFFFFFFFFF XOR)
206    ///
207    /// Reads values written by `TupleOutput::write_sorted_double`.
208    pub fn read_sorted_double(&mut self) -> Result<f64> {
209        let encoded = self.read_u64()?;
210        let bits = if encoded & 0x8000000000000000 != 0 {
211            encoded ^ 0x8000000000000000
212        } else {
213            encoded ^ 0xFFFFFFFFFFFFFFFF
214        };
215        Ok(f64::from_bits(bits))
216    }
217
218    /// Reads a packed (variable-length) i32 value.
219    ///
220    /// This is an unsorted variable-length encoding where values in [-119, 119]
221    /// are stored in a single byte. Larger values use 2-5 bytes.
222    ///
223    ///
224    ///
225    /// Reads values written by `TupleOutput::write_packed_int`.
226    pub fn read_packed_int(&mut self) -> Result<i32> {
227        let b1 = self.read_fast()? as i8;
228
229        let (negative, byte_len) = if b1 < -119 {
230            (true, ((-b1) as usize) - 119)
231        } else if b1 > 119 {
232            (false, (b1 as usize) - 119)
233        } else {
234            return Ok(b1 as i32);
235        };
236
237        let mut value: u32 = self.read_fast()? as u32;
238        if byte_len > 1 {
239            value |= (self.read_fast()? as u32) << 8;
240            if byte_len > 2 {
241                value |= (self.read_fast()? as u32) << 16;
242                if byte_len > 3 {
243                    value |= (self.read_fast()? as u32) << 24;
244                }
245            }
246        }
247
248        if negative {
249            Ok(-(value as i32) - 119)
250        } else {
251            Ok((value as i32) + 119)
252        }
253    }
254
255    /// Reads a packed (variable-length) i64 value.
256    ///
257    /// This is an unsorted variable-length encoding where values in [-119, 119]
258    /// are stored in a single byte. Larger values use 2-9 bytes.
259    ///
260    ///
261    ///
262    /// Reads values written by `TupleOutput::write_packed_long`.
263    pub fn read_packed_long(&mut self) -> Result<i64> {
264        let b1 = self.read_fast()? as i8;
265
266        let (negative, byte_len) = if b1 < -119 {
267            (true, ((-b1) as usize) - 119)
268        } else if b1 > 119 {
269            (false, (b1 as usize) - 119)
270        } else {
271            return Ok(b1 as i64);
272        };
273
274        let mut value: u64 = self.read_fast()? as u64;
275        if byte_len > 1 {
276            value |= (self.read_fast()? as u64) << 8;
277            if byte_len > 2 {
278                value |= (self.read_fast()? as u64) << 16;
279                if byte_len > 3 {
280                    value |= (self.read_fast()? as u64) << 24;
281                    if byte_len > 4 {
282                        value |= (self.read_fast()? as u64) << 32;
283                        if byte_len > 5 {
284                            value |= (self.read_fast()? as u64) << 40;
285                            if byte_len > 6 {
286                                value |= (self.read_fast()? as u64) << 48;
287                                if byte_len > 7 {
288                                    value |= (self.read_fast()? as u64) << 56;
289                                }
290                            }
291                        }
292                    }
293                }
294            }
295        }
296
297        if negative {
298            Ok(-(value as i64) - 119)
299        } else {
300            Ok((value as i64) + 119)
301        }
302    }
303
304    /// Reads a sorted packed (variable-length, order-preserving) i32 value.
305    ///
306    /// Decodes the format written by `TupleOutput::write_sorted_packed_int`.
307    ///
308    /// Single-byte range [-119, 120]: first byte in `[0x08, 0xF7]`, stored as
309    /// `(value + 127)`.  Negative multi-byte: first byte `< 0x08`, meaning
310    /// `(0x08 - b1)` big-endian value bytes follow; value = `raw - 119`.
311    /// Positive multi-byte: first byte `> 0xF7`, meaning `(b1 - 0xF7)` big-endian
312    /// value bytes follow; value = `raw + 121`.
313    ///
314    ///
315    pub fn read_sorted_packed_int(&mut self) -> Result<i32> {
316        let b1 = self.read_fast()?;
317        if b1 < 0x08 {
318            // Negative: (0x08 - b1) additional big-endian bytes
319            let n = (0x08 - b1) as usize;
320            let mut raw: u32 = 0xFFFFFFFF;
321            for _ in 0..n {
322                raw = (raw << 8) | (self.read_fast()? as u32);
323            }
324            Ok(raw as i32 - 119)
325        } else if b1 > 0xF7 {
326            // Positive: (b1 - 0xF7) additional big-endian bytes
327            let n = (b1 - 0xF7) as usize;
328            let mut raw: u32 = 0;
329            for _ in 0..n {
330                raw = (raw << 8) | (self.read_fast()? as u32);
331            }
332            Ok(raw as i32 + 121)
333        } else {
334            Ok(b1 as i32 - 127)
335        }
336    }
337
338    /// Reads a sorted packed (variable-length, order-preserving) i64 value.
339    ///
340    /// Decodes the format written by `TupleOutput::write_sorted_packed_long`.
341    /// Uses the same header-byte scheme as `read_sorted_packed_int`, extended
342    /// to up to 8 value bytes.
343    ///
344    ///
345    pub fn read_sorted_packed_long(&mut self) -> Result<i64> {
346        let b1 = self.read_fast()?;
347        if b1 < 0x08 {
348            let n = (0x08 - b1) as usize;
349            let mut raw: u64 = 0xFFFFFFFFFFFFFFFF;
350            for _ in 0..n {
351                raw = (raw << 8) | (self.read_fast()? as u64);
352            }
353            Ok(raw as i64 - 119)
354        } else if b1 > 0xF7 {
355            let n = (b1 - 0xF7) as usize;
356            let mut raw: u64 = 0;
357            for _ in 0..n {
358                raw = (raw << 8) | (self.read_fast()? as u64);
359            }
360            Ok(raw as i64 + 121)
361        } else {
362            Ok(b1 as i64 - 127)
363        }
364    }
365
366    /// Reads a Java `char` (16-bit Unicode code point) stored as two big-endian bytes.
367    ///
368    /// Reads values written by `TupleOutput::write_char`.
369    pub fn read_char(&mut self) -> Result<u16> {
370        self.read_u16()
371    }
372
373    /// Reads a null-escaped UTF-8 string from the buffer.
374    ///
375    /// Scans for the two-byte terminator [0x00, 0x00], unescaping any
376    /// [0x00, 0x01] sequences back to a single 0x00 byte. This is the
377    /// inverse of `TupleOutput::write_string`.
378    pub fn read_string(&mut self) -> Result<String> {
379        let mut decoded: Vec<u8> = Vec::new();
380        loop {
381            if self.off >= self.buf.len() {
382                return Err(BindError::InvalidData(
383                    "no null terminator found for string".to_string(),
384                ));
385            }
386            let b = self.buf[self.off];
387            self.off += 1;
388            if b == 0x00 {
389                // Peek at next byte to distinguish terminator from escape
390                if self.off >= self.buf.len() {
391                    return Err(BindError::InvalidData(
392                        "truncated null escape sequence in string".to_string(),
393                    ));
394                }
395                let next = self.buf[self.off];
396                self.off += 1;
397                if next == 0x00 {
398                    // [0x00, 0x00] is the end-of-string terminator
399                    break;
400                } else if next == 0x01 {
401                    // [0x00, 0x01] is an escaped null byte
402                    decoded.push(0x00);
403                } else {
404                    return Err(BindError::InvalidData(format!(
405                        "invalid null escape byte 0x{:02x} in string",
406                        next
407                    )));
408                }
409            } else {
410                decoded.push(b);
411            }
412        }
413        String::from_utf8(decoded).map_err(|e| {
414            BindError::StringEncoding(format!("invalid UTF-8: {}", e))
415        })
416    }
417
418    /// Reads the specified number of raw bytes from the buffer.
419    ///
420    /// Reads values written by `TupleOutput::write_bytes`.
421    pub fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>> {
422        if self.available() < len {
423            return Err(BindError::BufferUnderflow {
424                needed: len,
425                available: self.available(),
426            });
427        }
428        let bytes = self.buf[self.off..self.off + len].to_vec();
429        self.off += len;
430        Ok(bytes)
431    }
432
433    /// Skips the specified number of bytes.
434    pub fn skip(&mut self, count: usize) -> Result<()> {
435        if self.available() < count {
436            return Err(BindError::BufferUnderflow {
437                needed: count,
438                available: self.available(),
439            });
440        }
441        self.off += count;
442        Ok(())
443    }
444}
445
446#[cfg(test)]
447mod tests {
448    use super::*;
449    use crate::tuple::TupleOutput;
450
451    #[test]
452    fn test_bool_round_trip() {
453        let mut out = TupleOutput::new();
454        out.write_bool(true);
455        out.write_bool(false);
456        let mut input = TupleInput::new(&out.to_vec());
457        assert!(input.read_bool().unwrap());
458        assert!(!input.read_bool().unwrap());
459    }
460
461    #[test]
462    fn test_i8_round_trip() {
463        let mut out = TupleOutput::new();
464        out.write_i8(-128);
465        out.write_i8(0);
466        out.write_i8(127);
467        let mut input = TupleInput::new(&out.to_vec());
468        assert_eq!(input.read_i8().unwrap(), -128);
469        assert_eq!(input.read_i8().unwrap(), 0);
470        assert_eq!(input.read_i8().unwrap(), 127);
471    }
472
473    #[test]
474    fn test_i16_round_trip() {
475        let mut out = TupleOutput::new();
476        out.write_i16(i16::MIN);
477        out.write_i16(0);
478        out.write_i16(i16::MAX);
479        let mut input = TupleInput::new(&out.to_vec());
480        assert_eq!(input.read_i16().unwrap(), i16::MIN);
481        assert_eq!(input.read_i16().unwrap(), 0);
482        assert_eq!(input.read_i16().unwrap(), i16::MAX);
483    }
484
485    #[test]
486    fn test_i32_round_trip() {
487        let mut out = TupleOutput::new();
488        out.write_i32(i32::MIN);
489        out.write_i32(-1);
490        out.write_i32(0);
491        out.write_i32(1);
492        out.write_i32(i32::MAX);
493        let mut input = TupleInput::new(&out.to_vec());
494        assert_eq!(input.read_i32().unwrap(), i32::MIN);
495        assert_eq!(input.read_i32().unwrap(), -1);
496        assert_eq!(input.read_i32().unwrap(), 0);
497        assert_eq!(input.read_i32().unwrap(), 1);
498        assert_eq!(input.read_i32().unwrap(), i32::MAX);
499    }
500
501    #[test]
502    fn test_i64_round_trip() {
503        let mut out = TupleOutput::new();
504        out.write_i64(i64::MIN);
505        out.write_i64(-1);
506        out.write_i64(0);
507        out.write_i64(1);
508        out.write_i64(i64::MAX);
509        let mut input = TupleInput::new(&out.to_vec());
510        assert_eq!(input.read_i64().unwrap(), i64::MIN);
511        assert_eq!(input.read_i64().unwrap(), -1);
512        assert_eq!(input.read_i64().unwrap(), 0);
513        assert_eq!(input.read_i64().unwrap(), 1);
514        assert_eq!(input.read_i64().unwrap(), i64::MAX);
515    }
516
517    #[test]
518    fn test_u8_round_trip() {
519        let mut out = TupleOutput::new();
520        out.write_u8(0);
521        out.write_u8(128);
522        out.write_u8(255);
523        let mut input = TupleInput::new(&out.to_vec());
524        assert_eq!(input.read_u8().unwrap(), 0);
525        assert_eq!(input.read_u8().unwrap(), 128);
526        assert_eq!(input.read_u8().unwrap(), 255);
527    }
528
529    #[test]
530    fn test_float_round_trip() {
531        let mut out = TupleOutput::new();
532        out.write_float(0.0);
533        out.write_float(1.5);
534        out.write_float(-1.5);
535        out.write_float(f32::MAX);
536        out.write_float(f32::MIN);
537        let mut input = TupleInput::new(&out.to_vec());
538        assert_eq!(input.read_float().unwrap(), 0.0);
539        assert_eq!(input.read_float().unwrap(), 1.5);
540        assert_eq!(input.read_float().unwrap(), -1.5);
541        assert_eq!(input.read_float().unwrap(), f32::MAX);
542        assert_eq!(input.read_float().unwrap(), f32::MIN);
543    }
544
545    #[test]
546    fn test_double_round_trip() {
547        let mut out = TupleOutput::new();
548        out.write_double(0.0);
549        out.write_double(1.5);
550        out.write_double(-1.5);
551        out.write_double(f64::MAX);
552        out.write_double(f64::MIN);
553        let mut input = TupleInput::new(&out.to_vec());
554        assert_eq!(input.read_double().unwrap(), 0.0);
555        assert_eq!(input.read_double().unwrap(), 1.5);
556        assert_eq!(input.read_double().unwrap(), -1.5);
557        assert_eq!(input.read_double().unwrap(), f64::MAX);
558        assert_eq!(input.read_double().unwrap(), f64::MIN);
559    }
560
561    #[test]
562    fn test_sorted_float_round_trip() {
563        let mut out = TupleOutput::new();
564        out.write_sorted_float(-1.0);
565        out.write_sorted_float(0.0);
566        out.write_sorted_float(1.0);
567        out.write_sorted_float(f32::MAX);
568        out.write_sorted_float(f32::MIN);
569        let mut input = TupleInput::new(&out.to_vec());
570        assert_eq!(input.read_sorted_float().unwrap(), -1.0);
571        assert_eq!(input.read_sorted_float().unwrap(), 0.0);
572        assert_eq!(input.read_sorted_float().unwrap(), 1.0);
573        assert_eq!(input.read_sorted_float().unwrap(), f32::MAX);
574        assert_eq!(input.read_sorted_float().unwrap(), f32::MIN);
575    }
576
577    #[test]
578    fn test_sorted_double_round_trip() {
579        let mut out = TupleOutput::new();
580        out.write_sorted_double(-1.0);
581        out.write_sorted_double(0.0);
582        out.write_sorted_double(1.0);
583        out.write_sorted_double(f64::MAX);
584        out.write_sorted_double(f64::MIN);
585        let mut input = TupleInput::new(&out.to_vec());
586        assert_eq!(input.read_sorted_double().unwrap(), -1.0);
587        assert_eq!(input.read_sorted_double().unwrap(), 0.0);
588        assert_eq!(input.read_sorted_double().unwrap(), 1.0);
589        assert_eq!(input.read_sorted_double().unwrap(), f64::MAX);
590        assert_eq!(input.read_sorted_double().unwrap(), f64::MIN);
591    }
592
593    #[test]
594    fn test_packed_int_round_trip() {
595        let mut out = TupleOutput::new();
596        let values = [
597            0,
598            1,
599            -1,
600            119,
601            -119,
602            120,
603            -120,
604            255,
605            -256,
606            1000,
607            -1000,
608            i32::MAX,
609            i32::MIN,
610            65535,
611            -65536,
612        ];
613        for &v in &values {
614            out.write_packed_int(v);
615        }
616        let mut input = TupleInput::new(&out.to_vec());
617        for &v in &values {
618            assert_eq!(
619                input.read_packed_int().unwrap(),
620                v,
621                "failed for value {}",
622                v
623            );
624        }
625    }
626
627    #[test]
628    fn test_packed_long_round_trip() {
629        let mut out = TupleOutput::new();
630        let values: &[i64] = &[
631            0,
632            1,
633            -1,
634            119,
635            -119,
636            120,
637            -120,
638            1000,
639            -1000,
640            i32::MAX as i64,
641            i32::MIN as i64,
642            i64::MAX,
643            i64::MIN,
644        ];
645        for &v in values {
646            out.write_packed_long(v);
647        }
648        let mut input = TupleInput::new(&out.to_vec());
649        for &v in values {
650            assert_eq!(
651                input.read_packed_long().unwrap(),
652                v,
653                "failed for value {}",
654                v
655            );
656        }
657    }
658
659    #[test]
660    fn test_string_round_trip() {
661        let mut out = TupleOutput::new();
662        out.write_string("hello");
663        out.write_string("");
664        out.write_string("world");
665        let mut input = TupleInput::new(&out.to_vec());
666        assert_eq!(input.read_string().unwrap(), "hello");
667        assert_eq!(input.read_string().unwrap(), "");
668        assert_eq!(input.read_string().unwrap(), "world");
669    }
670
671    #[test]
672    fn test_bytes_round_trip() {
673        let mut out = TupleOutput::new();
674        out.write_bytes(&[1, 2, 3, 4, 5]);
675        let mut input = TupleInput::new(&out.to_vec());
676        assert_eq!(input.read_bytes(5).unwrap(), vec![1, 2, 3, 4, 5]);
677    }
678
679    #[test]
680    fn test_buffer_underflow() {
681        let mut input = TupleInput::new(&[]);
682        assert!(input.read_i32().is_err());
683    }
684
685    #[test]
686    fn test_available() {
687        let mut input = TupleInput::new(&[1, 2, 3, 4]);
688        assert_eq!(input.available(), 4);
689        input.read_u8().unwrap();
690        assert_eq!(input.available(), 3);
691    }
692
693    // -----------------------------------------------------------------------
694    // Ported from TupleFormatTest: read-side correctness
695    // -----------------------------------------------------------------------
696
697    /// TupleFormatTest: available decrements correctly after each read.
698    #[test]
699    fn test_available_tracks_reads() {
700        let mut out = TupleOutput::new();
701        out.write_bool(true);
702        out.write_i8(-1);
703        out.write_i16(1000);
704        out.write_i32(123);
705        out.write_i64(456);
706        // sizes: 1 + 1 + 2 + 4 + 8 = 16
707        let mut inp = TupleInput::new(&out.to_vec());
708        assert_eq!(inp.available(), 16);
709        inp.read_bool().unwrap();
710        assert_eq!(inp.available(), 15);
711        inp.read_i8().unwrap();
712        assert_eq!(inp.available(), 14);
713        inp.read_i16().unwrap();
714        assert_eq!(inp.available(), 12);
715        inp.read_i32().unwrap();
716        assert_eq!(inp.available(), 8);
717        inp.read_i64().unwrap();
718        assert_eq!(inp.available(), 0);
719    }
720
721    /// TupleFormatTest: multi-type interleaving round-trip.
722    #[test]
723    fn test_multi_type_interleave_round_trip() {
724        let mut out = TupleOutput::new();
725        out.write_string("abc");
726        out.write_i32(42);
727        out.write_bool(true);
728        out.write_double(-1.5_f64);
729        out.write_string("xyz");
730
731        let mut inp = TupleInput::new(&out.to_vec());
732        assert_eq!(inp.read_string().unwrap(), "abc");
733        assert_eq!(inp.read_i32().unwrap(), 42);
734        assert!(inp.read_bool().unwrap());
735        assert_eq!(inp.read_double().unwrap(), -1.5_f64);
736        assert_eq!(inp.read_string().unwrap(), "xyz");
737        assert_eq!(inp.available(), 0);
738    }
739
740    /// TupleFormatTest: skip advances the offset correctly.
741    #[test]
742    fn test_skip() {
743        let mut out = TupleOutput::new();
744        out.write_i32(111);
745        out.write_i32(222);
746        out.write_i32(333);
747        let mut inp = TupleInput::new(&out.to_vec());
748        inp.skip(4).unwrap(); // skip the first i32
749        assert_eq!(inp.read_i32().unwrap(), 222);
750        assert_eq!(inp.available(), 4);
751        assert_eq!(inp.read_i32().unwrap(), 333);
752        assert_eq!(inp.available(), 0);
753    }
754
755    /// TupleFormatTest: skip past end returns an error.
756    #[test]
757    fn test_skip_past_end_error() {
758        let mut inp = TupleInput::new(&[1, 2, 3]);
759        assert!(inp.skip(4).is_err());
760    }
761
762    /// TupleFormatTest: set_offset / get_offset acts as mark+reset.
763    #[test]
764    fn test_set_get_offset_mark_reset() {
765        let mut out = TupleOutput::new();
766        out.write_i32(10);
767        out.write_i32(20);
768        let mut inp = TupleInput::new(&out.to_vec());
769        assert_eq!(inp.get_offset(), 0);
770        inp.read_i32().unwrap();
771        let mark = inp.get_offset(); // 4
772        assert_eq!(inp.read_i32().unwrap(), 20);
773        // reset back to mark
774        inp.set_offset(mark);
775        assert_eq!(inp.read_i32().unwrap(), 20);
776        assert_eq!(inp.available(), 0);
777    }
778
779    /// TupleFormatTest: get_buffer returns the original data.
780    #[test]
781    fn test_get_buffer() {
782        let data = vec![1u8, 2, 3, 4];
783        let inp = TupleInput::new(&data);
784        assert_eq!(inp.get_buffer(), data.as_slice());
785    }
786
787    /// TupleFormatTest: bool sequence read/write.
788    #[test]
789    fn test_bool_sequence_read() {
790        let mut out = TupleOutput::new();
791        out.write_bool(true);
792        out.write_bool(false);
793        out.write_bool(true);
794        assert_eq!(out.len(), 3);
795        let mut inp = TupleInput::new(&out.to_vec());
796        assert!(inp.read_bool().unwrap());
797        assert!(!inp.read_bool().unwrap());
798        assert!(inp.read_bool().unwrap());
799        assert_eq!(inp.available(), 0);
800    }
801
802    /// TupleFormatTest: i16 sequence read/write.
803    #[test]
804    fn test_short_sequence_read() {
805        let mut out = TupleOutput::new();
806        out.write_i16(0);
807        out.write_i16(1);
808        out.write_i16(-1);
809        assert_eq!(out.len(), 6);
810        let mut inp = TupleInput::new(&out.to_vec());
811        assert_eq!(inp.read_i16().unwrap(), 0);
812        assert_eq!(inp.read_i16().unwrap(), 1);
813        assert_eq!(inp.read_i16().unwrap(), -1);
814        assert_eq!(inp.available(), 0);
815    }
816
817    /// TupleFormatTest: i32 sequence read/write.
818    #[test]
819    fn test_int_sequence_read() {
820        let mut out = TupleOutput::new();
821        out.write_i32(0);
822        out.write_i32(1);
823        out.write_i32(-1);
824        assert_eq!(out.len(), 12);
825        let mut inp = TupleInput::new(&out.to_vec());
826        assert_eq!(inp.read_i32().unwrap(), 0);
827        assert_eq!(inp.read_i32().unwrap(), 1);
828        assert_eq!(inp.read_i32().unwrap(), -1);
829        assert_eq!(inp.available(), 0);
830    }
831
832    /// TupleFormatTest: i64 sequence read/write.
833    #[test]
834    fn test_long_sequence_read() {
835        let mut out = TupleOutput::new();
836        out.write_i64(0);
837        out.write_i64(1);
838        out.write_i64(-1);
839        assert_eq!(out.len(), 24);
840        let mut inp = TupleInput::new(&out.to_vec());
841        assert_eq!(inp.read_i64().unwrap(), 0);
842        assert_eq!(inp.read_i64().unwrap(), 1);
843        assert_eq!(inp.read_i64().unwrap(), -1);
844        assert_eq!(inp.available(), 0);
845    }
846
847    /// TupleFormatTest: f32 sequence read/write.
848    #[test]
849    fn test_float_sequence_read() {
850        let mut out = TupleOutput::new();
851        out.write_float(0.0);
852        out.write_float(1.0);
853        out.write_float(-1.0);
854        assert_eq!(out.len(), 12);
855        let mut inp = TupleInput::new(&out.to_vec());
856        assert_eq!(inp.read_float().unwrap(), 0.0f32);
857        assert_eq!(inp.read_float().unwrap(), 1.0f32);
858        assert_eq!(inp.read_float().unwrap(), -1.0f32);
859        assert_eq!(inp.available(), 0);
860    }
861
862    /// TupleFormatTest: f64 sequence read/write.
863    #[test]
864    fn test_double_sequence_read() {
865        let mut out = TupleOutput::new();
866        out.write_double(0.0);
867        out.write_double(1.0);
868        out.write_double(-1.0);
869        assert_eq!(out.len(), 24);
870        let mut inp = TupleInput::new(&out.to_vec());
871        assert_eq!(inp.read_double().unwrap(), 0.0f64);
872        assert_eq!(inp.read_double().unwrap(), 1.0f64);
873        assert_eq!(inp.read_double().unwrap(), -1.0f64);
874        assert_eq!(inp.available(), 0);
875    }
876
877    /// TupleFormatTest: sorted float sequence read/write.
878    #[test]
879    fn test_sorted_float_sequence_read() {
880        let mut out = TupleOutput::new();
881        out.write_sorted_float(0.0);
882        out.write_sorted_float(1.0);
883        out.write_sorted_float(-1.0);
884        assert_eq!(out.len(), 12);
885        let mut inp = TupleInput::new(&out.to_vec());
886        assert_eq!(inp.read_sorted_float().unwrap(), 0.0f32);
887        assert_eq!(inp.read_sorted_float().unwrap(), 1.0f32);
888        assert_eq!(inp.read_sorted_float().unwrap(), -1.0f32);
889        assert_eq!(inp.available(), 0);
890    }
891
892    /// TupleFormatTest: sorted double sequence read/write.
893    #[test]
894    fn test_sorted_double_sequence_read() {
895        let mut out = TupleOutput::new();
896        out.write_sorted_double(0.0);
897        out.write_sorted_double(1.0);
898        out.write_sorted_double(-1.0);
899        assert_eq!(out.len(), 24);
900        let mut inp = TupleInput::new(&out.to_vec());
901        assert_eq!(inp.read_sorted_double().unwrap(), 0.0f64);
902        assert_eq!(inp.read_sorted_double().unwrap(), 1.0f64);
903        assert_eq!(inp.read_sorted_double().unwrap(), -1.0f64);
904        assert_eq!(inp.available(), 0);
905    }
906
907    /// TupleFormatTest: NaN round-trips through unsorted float.
908    #[test]
909    fn test_float_nan_round_trip() {
910        let mut out = TupleOutput::new();
911        out.write_float(f32::NAN);
912        let mut inp = TupleInput::new(&out.to_vec());
913        assert!(inp.read_float().unwrap().is_nan());
914    }
915
916    /// TupleFormatTest: NaN round-trips through unsorted double.
917    #[test]
918    fn test_double_nan_round_trip() {
919        let mut out = TupleOutput::new();
920        out.write_double(f64::NAN);
921        let mut inp = TupleInput::new(&out.to_vec());
922        assert!(inp.read_double().unwrap().is_nan());
923    }
924
925    /// TupleFormatTest: NaN round-trips through sorted float.
926    #[test]
927    fn test_sorted_float_nan_round_trip() {
928        let mut out = TupleOutput::new();
929        out.write_sorted_float(f32::NAN);
930        let mut inp = TupleInput::new(&out.to_vec());
931        assert!(inp.read_sorted_float().unwrap().is_nan());
932    }
933
934    /// TupleFormatTest: NaN round-trips through sorted double.
935    #[test]
936    fn test_sorted_double_nan_round_trip() {
937        let mut out = TupleOutput::new();
938        out.write_sorted_double(f64::NAN);
939        let mut inp = TupleInput::new(&out.to_vec());
940        assert!(inp.read_sorted_double().unwrap().is_nan());
941    }
942
943    /// TupleFormatTest: infinity round-trips through sorted float.
944    #[test]
945    fn test_sorted_float_infinity_round_trip() {
946        let mut out = TupleOutput::new();
947        out.write_sorted_float(f32::INFINITY);
948        out.write_sorted_float(f32::NEG_INFINITY);
949        let mut inp = TupleInput::new(&out.to_vec());
950        assert_eq!(inp.read_sorted_float().unwrap(), f32::INFINITY);
951        assert_eq!(inp.read_sorted_float().unwrap(), f32::NEG_INFINITY);
952        assert_eq!(inp.available(), 0);
953    }
954
955    /// TupleFormatTest: infinity round-trips through sorted double.
956    #[test]
957    fn test_sorted_double_infinity_round_trip() {
958        let mut out = TupleOutput::new();
959        out.write_sorted_double(f64::INFINITY);
960        out.write_sorted_double(f64::NEG_INFINITY);
961        let mut inp = TupleInput::new(&out.to_vec());
962        assert_eq!(inp.read_sorted_double().unwrap(), f64::INFINITY);
963        assert_eq!(inp.read_sorted_double().unwrap(), f64::NEG_INFINITY);
964        assert_eq!(inp.available(), 0);
965    }
966
967    /// TupleFormatTest: packed int 119/0xFFFF+119/MAX sizes and round-trip.
968    #[test]
969    fn test_packed_int_specific_sizes_round_trip() {
970        let cases: &[(i32, usize)] =
971            &[(119, 1), (0xFFFF + 119, 3), (i32::MAX, 5)];
972        for &(val, expected_size) in cases {
973            let mut out = TupleOutput::new();
974            out.write_packed_int(val);
975            assert_eq!(out.len(), expected_size, "packed_int {} size", val);
976            let mut inp = TupleInput::new(&out.to_vec());
977            assert_eq!(inp.read_packed_int().unwrap(), val);
978        }
979    }
980
981    /// TupleFormatTest: packed long 119/0xFFFFFFFF+119/MAX sizes and round-trip.
982    #[test]
983    fn test_packed_long_specific_sizes_round_trip() {
984        let cases: &[(i64, usize)] =
985            &[(119, 1), (0xFFFF_FFFF_i64 + 119, 5), (i64::MAX, 9)];
986        for &(val, expected_size) in cases {
987            let mut out = TupleOutput::new();
988            out.write_packed_long(val);
989            assert_eq!(out.len(), expected_size, "packed_long {} size", val);
990            let mut inp = TupleInput::new(&out.to_vec());
991            assert_eq!(inp.read_packed_long().unwrap(), val);
992        }
993    }
994
995    /// TupleFormatTest: sorted packed int sizes and round-trip.
996    #[test]
997    fn test_sorted_packed_int_specific_sizes_round_trip() {
998        let cases: &[(i32, usize)] = &[
999            (-1, 1),
1000            (0, 1),
1001            (1, 1),
1002            (-119, 1),
1003            (120, 1),
1004            (121, 2),
1005            (-120, 2),
1006            (i32::MAX, 5),
1007            (i32::MIN, 5),
1008        ];
1009        for &(val, expected_size) in cases {
1010            let mut out = TupleOutput::new();
1011            out.write_sorted_packed_int(val);
1012            assert_eq!(
1013                out.len(),
1014                expected_size,
1015                "sorted_packed_int {} size",
1016                val
1017            );
1018            let mut inp = TupleInput::new(&out.to_vec());
1019            assert_eq!(inp.read_sorted_packed_int().unwrap(), val);
1020        }
1021    }
1022
1023    /// TupleFormatTest: sorted packed long sizes and round-trip.
1024    #[test]
1025    fn test_sorted_packed_long_specific_sizes_round_trip() {
1026        let cases: &[(i64, usize)] = &[
1027            (-1, 1),
1028            (0, 1),
1029            (1, 1),
1030            (-119, 1),
1031            (120, 1),
1032            (121, 2),
1033            (-120, 2),
1034            (i64::MAX, 9),
1035            (i64::MIN, 9),
1036        ];
1037        for &(val, expected_size) in cases {
1038            let mut out = TupleOutput::new();
1039            out.write_sorted_packed_long(val);
1040            assert_eq!(
1041                out.len(),
1042                expected_size,
1043                "sorted_packed_long {} size",
1044                val
1045            );
1046            let mut inp = TupleInput::new(&out.to_vec());
1047            assert_eq!(inp.read_sorted_packed_long().unwrap(), val);
1048        }
1049    }
1050
1051    /// TupleFormatTest: u8 sequence read/write including boundary values.
1052    #[test]
1053    fn test_unsigned_byte_sequence_read() {
1054        let mut out = TupleOutput::new();
1055        out.write_u8(0);
1056        out.write_u8(1);
1057        out.write_u8(255);
1058        assert_eq!(out.len(), 3);
1059        let mut inp = TupleInput::new(&out.to_vec());
1060        assert_eq!(inp.read_u8().unwrap(), 0);
1061        assert_eq!(inp.read_u8().unwrap(), 1);
1062        assert_eq!(inp.read_u8().unwrap(), 255);
1063        assert_eq!(inp.available(), 0);
1064    }
1065
1066    /// TupleFormatTest: u16 sequence read/write including boundary values.
1067    #[test]
1068    fn test_unsigned_short_sequence_read() {
1069        let mut out = TupleOutput::new();
1070        out.write_u16(0);
1071        out.write_u16(1);
1072        out.write_u16(0xFFFF);
1073        assert_eq!(out.len(), 6);
1074        let mut inp = TupleInput::new(&out.to_vec());
1075        assert_eq!(inp.read_u16().unwrap(), 0);
1076        assert_eq!(inp.read_u16().unwrap(), 1);
1077        assert_eq!(inp.read_u16().unwrap(), 0xFFFF);
1078        assert_eq!(inp.available(), 0);
1079    }
1080
1081    /// TupleFormatTest: u32 sequence read/write including boundary values.
1082    #[test]
1083    fn test_unsigned_int_sequence_read() {
1084        let mut out = TupleOutput::new();
1085        out.write_u32(0);
1086        out.write_u32(1);
1087        out.write_u32(0xFFFF_FFFF);
1088        assert_eq!(out.len(), 12);
1089        let mut inp = TupleInput::new(&out.to_vec());
1090        assert_eq!(inp.read_u32().unwrap(), 0);
1091        assert_eq!(inp.read_u32().unwrap(), 1);
1092        assert_eq!(inp.read_u32().unwrap(), 0xFFFF_FFFF);
1093        assert_eq!(inp.available(), 0);
1094    }
1095
1096    /// TupleFormatTest: null string then int interleaved.
1097    /// TupleFormatTest.testNullString writes null then int and back.
1098    /// In Rust we model "null string" as Option<String>, but the tuple
1099    /// format doesn't have a built-in null. We test the Rust equivalent:
1100    /// an empty string followed by an i32, verifying the i32 is readable.
1101    #[test]
1102    fn test_string_then_int_interleaved() {
1103        let mut out = TupleOutput::new();
1104        out.write_string("abc");
1105        out.write_i32(123);
1106        // "abc" = 3 + 2 bytes terminator = 5; i32 = 4 bytes → total 9
1107        assert_eq!(out.len(), 9);
1108        let mut inp = TupleInput::new(&out.to_vec());
1109        assert_eq!(inp.read_string().unwrap(), "abc");
1110        assert_eq!(inp.available(), 4);
1111        assert_eq!(inp.read_i32().unwrap(), 123);
1112        assert_eq!(inp.available(), 0);
1113    }
1114
1115    /// TupleFormatTest: char round-trips as 2 bytes.
1116    #[test]
1117    fn test_char_size_and_round_trip() {
1118        let mut out = TupleOutput::new();
1119        out.write_char(b'a' as u16);
1120        assert_eq!(out.len(), 2);
1121        let mut inp = TupleInput::new(&out.to_vec());
1122        assert_eq!(inp.read_char().unwrap(), b'a' as u16);
1123        assert_eq!(inp.available(), 0);
1124    }
1125
1126    /// TupleFormatTest: from_vec constructor works the same as new.
1127    #[test]
1128    fn test_from_vec_constructor() {
1129        let data = vec![0x80u8, 0x00, 0x00, 0x2B]; // write_i32(43)
1130        let mut inp1 = TupleInput::from_vec(data.clone());
1131        let mut inp2 = TupleInput::new(&data);
1132        assert_eq!(inp1.read_i32().unwrap(), inp2.read_i32().unwrap());
1133    }
1134
1135    // -----------------------------------------------------------------------
1136    // Ported from TupleBindingTest: edge values for all numeric types
1137    // -----------------------------------------------------------------------
1138
1139    /// TupleBindingTest: i8 edge values MIN, -1, 0, 1, MAX.
1140    #[test]
1141    fn test_i8_edge_values() {
1142        for &v in &[i8::MIN, -1i8, 0, 1, i8::MAX] {
1143            let mut out = TupleOutput::new();
1144            out.write_i8(v);
1145            assert_eq!(out.len(), 1, "i8 {} should be 1 byte", v);
1146            let mut inp = TupleInput::new(&out.to_vec());
1147            assert_eq!(inp.read_i8().unwrap(), v);
1148        }
1149    }
1150
1151    /// TupleBindingTest: i16 edge values MIN, -1, 0, 1, MAX.
1152    #[test]
1153    fn test_i16_edge_values() {
1154        for &v in &[i16::MIN, -1i16, 0, 1, i16::MAX] {
1155            let mut out = TupleOutput::new();
1156            out.write_i16(v);
1157            assert_eq!(out.len(), 2, "i16 {} should be 2 bytes", v);
1158            let mut inp = TupleInput::new(&out.to_vec());
1159            assert_eq!(inp.read_i16().unwrap(), v);
1160        }
1161    }
1162
1163    /// TupleBindingTest: i32 edge values MIN, MAX, and all wrapping boundary arithmetic.
1164    #[test]
1165    fn test_i32_wrapping_values() {
1166        // TupleFormatTest.testInt exercises values like MAX+1 which wrap.
1167        // i32::MAX+1 wraps to i32::MIN in two's complement.
1168        let cases: &[(i32, i32)] = &[
1169            (i32::MAX.wrapping_add(1), i32::MIN), // wraps
1170            (i32::MIN.wrapping_sub(1), i32::MAX), // wraps
1171        ];
1172        for &(input_val, expected) in cases {
1173            let mut out = TupleOutput::new();
1174            out.write_i32(input_val);
1175            let mut inp = TupleInput::new(&out.to_vec());
1176            assert_eq!(inp.read_i32().unwrap(), expected);
1177        }
1178    }
1179
1180    /// TupleBindingTest: i64 edge values MIN, MAX, and wrapping boundary arithmetic.
1181    #[test]
1182    fn test_i64_wrapping_values() {
1183        let cases: &[(i64, i64)] = &[
1184            (i64::MAX.wrapping_add(1), i64::MIN),
1185            (i64::MIN.wrapping_sub(1), i64::MAX),
1186        ];
1187        for &(input_val, expected) in cases {
1188            let mut out = TupleOutput::new();
1189            out.write_i64(input_val);
1190            let mut inp = TupleInput::new(&out.to_vec());
1191            assert_eq!(inp.read_i64().unwrap(), expected);
1192        }
1193    }
1194
1195    /// TupleBindingTest: float special values (NaN, infinity, min, max).
1196    #[test]
1197    fn test_float_special_values_round_trip() {
1198        let special: &[f32] = &[
1199            f32::NAN,
1200            f32::INFINITY,
1201            f32::NEG_INFINITY,
1202            f32::MAX,
1203            f32::MIN,
1204            f32::MIN_POSITIVE,
1205            0.0,
1206            -0.0,
1207            1.0,
1208            -1.0,
1209        ];
1210        for &v in special {
1211            let mut out = TupleOutput::new();
1212            out.write_float(v);
1213            assert_eq!(out.len(), 4);
1214            let mut inp = TupleInput::new(&out.to_vec());
1215            let got = inp.read_float().unwrap();
1216            if v.is_nan() {
1217                assert!(got.is_nan(), "NaN should round-trip as NaN");
1218            } else {
1219                assert_eq!(
1220                    got.to_bits(),
1221                    v.to_bits(),
1222                    "float {} should round-trip",
1223                    v
1224                );
1225            }
1226        }
1227    }
1228
1229    /// TupleBindingTest: double special values (NaN, infinity, min, max).
1230    #[test]
1231    fn test_double_special_values_round_trip() {
1232        let special: &[f64] = &[
1233            f64::NAN,
1234            f64::INFINITY,
1235            f64::NEG_INFINITY,
1236            f64::MAX,
1237            f64::MIN,
1238            f64::MIN_POSITIVE,
1239            0.0,
1240            -0.0,
1241            1.0,
1242            -1.0,
1243        ];
1244        for &v in special {
1245            let mut out = TupleOutput::new();
1246            out.write_double(v);
1247            assert_eq!(out.len(), 8);
1248            let mut inp = TupleInput::new(&out.to_vec());
1249            let got = inp.read_double().unwrap();
1250            if v.is_nan() {
1251                assert!(got.is_nan(), "NaN should round-trip as NaN");
1252            } else {
1253                assert_eq!(
1254                    got.to_bits(),
1255                    v.to_bits(),
1256                    "double {} should round-trip",
1257                    v
1258                );
1259            }
1260        }
1261    }
1262
1263    /// TupleBindingTest: sorted float special values.
1264    #[test]
1265    fn test_sorted_float_special_values_round_trip() {
1266        let special: &[f32] = &[
1267            f32::NAN,
1268            f32::INFINITY,
1269            f32::NEG_INFINITY,
1270            f32::MAX,
1271            f32::MIN,
1272            f32::MIN_POSITIVE,
1273            0.0,
1274            -0.0,
1275            1.0,
1276            -1.0,
1277            123.123,
1278        ];
1279        for &v in special {
1280            let mut out = TupleOutput::new();
1281            out.write_sorted_float(v);
1282            assert_eq!(out.len(), 4);
1283            let mut inp = TupleInput::new(&out.to_vec());
1284            let got = inp.read_sorted_float().unwrap();
1285            if v.is_nan() {
1286                assert!(got.is_nan(), "NaN should round-trip");
1287            } else {
1288                assert_eq!(
1289                    got.to_bits(),
1290                    v.to_bits(),
1291                    "sorted float {} should round-trip",
1292                    v
1293                );
1294            }
1295        }
1296    }
1297
1298    /// TupleBindingTest: sorted double special values.
1299    #[test]
1300    fn test_sorted_double_special_values_round_trip() {
1301        let special: &[f64] = &[
1302            f64::NAN,
1303            f64::INFINITY,
1304            f64::NEG_INFINITY,
1305            f64::MAX,
1306            f64::MIN,
1307            f64::MIN_POSITIVE,
1308            0.0,
1309            -0.0,
1310            1.0,
1311            -1.0,
1312            123.123,
1313        ];
1314        for &v in special {
1315            let mut out = TupleOutput::new();
1316            out.write_sorted_double(v);
1317            assert_eq!(out.len(), 8);
1318            let mut inp = TupleInput::new(&out.to_vec());
1319            let got = inp.read_sorted_double().unwrap();
1320            if v.is_nan() {
1321                assert!(got.is_nan(), "NaN should round-trip");
1322            } else {
1323                assert_eq!(
1324                    got.to_bits(),
1325                    v.to_bits(),
1326                    "sorted double {} should round-trip",
1327                    v
1328                );
1329            }
1330        }
1331    }
1332}