Skip to main content

bsql_driver_postgres/
codec.rs

1//! Binary encode/decode for PostgreSQL types.
2//!
3//! All decoding operates on raw byte slices (from the arena or wire buffer).
4//! Encoding appends big-endian bytes to a `Vec<u8>`.
5//!
6//! PostgreSQL binary format is big-endian for all numeric types.
7
8use crate::DriverError;
9
10// --- Encode trait ---
11
12/// Encode a Rust value into PostgreSQL binary format.
13///
14/// Implementations append the binary representation to `buf`. The length prefix
15/// is handled by the caller (wire protocol layer), not the encoder.
16///
17/// # Example
18///
19/// ```
20/// use bsql_driver_postgres::Encode;
21///
22/// let mut buf = Vec::new();
23/// 42i32.encode_binary(&mut buf);
24/// assert_eq!(buf, &[0, 0, 0, 42]);
25/// ```
26pub trait Encode {
27    /// Append the binary-encoded value to `buf`.
28    fn encode_binary(&self, buf: &mut Vec<u8>);
29
30    /// The PostgreSQL OID for this type.
31    fn type_oid(&self) -> u32;
32
33    /// Whether this value represents SQL NULL.
34    ///
35    /// When true, the wire protocol sends length -1 with no data bytes.
36    /// Default is false. Implementations for `Option<T>` override this.
37    fn is_null(&self) -> bool {
38        false
39    }
40
41    /// Encode the binary value directly into `dst` at position 0.
42    ///
43    /// Returns `true` if the encoded length matches `dst.len()` (i.e., same size
44    /// as the template slot). Returns `false` if the size differs, signaling the
45    /// caller to fall back to a full rebuild.
46    ///
47    /// The default implementation uses a small inline buffer and copies. Fixed-size
48    /// types (i32, i64, etc.) override this to write directly — eliminating the
49    /// scratch buffer double-copy on the bind-template hot path.
50    fn encode_at(&self, dst: &mut [u8]) -> bool {
51        // Fallback: encode to a stack buffer, check size, copy.
52        let mut tmp = Vec::with_capacity(dst.len());
53        self.encode_binary(&mut tmp);
54        if tmp.len() == dst.len() {
55            dst.copy_from_slice(&tmp);
56            true
57        } else {
58            false
59        }
60    }
61}
62
63// --- Encode implementations ---
64
65impl Encode for bool {
66    #[inline]
67    fn encode_binary(&self, buf: &mut Vec<u8>) {
68        buf.push(if *self { 1 } else { 0 });
69    }
70
71    #[inline]
72    fn type_oid(&self) -> u32 {
73        16 // bool
74    }
75
76    #[inline]
77    fn encode_at(&self, dst: &mut [u8]) -> bool {
78        if dst.len() != 1 {
79            return false;
80        }
81        dst[0] = if *self { 1 } else { 0 };
82        true
83    }
84}
85
86impl Encode for i16 {
87    #[inline]
88    fn encode_binary(&self, buf: &mut Vec<u8>) {
89        buf.extend_from_slice(&self.to_be_bytes());
90    }
91
92    #[inline]
93    fn type_oid(&self) -> u32 {
94        21 // int2
95    }
96
97    #[inline]
98    fn encode_at(&self, dst: &mut [u8]) -> bool {
99        if dst.len() != 2 {
100            return false;
101        }
102        dst.copy_from_slice(&self.to_be_bytes());
103        true
104    }
105}
106
107impl Encode for i32 {
108    #[inline]
109    fn encode_binary(&self, buf: &mut Vec<u8>) {
110        buf.extend_from_slice(&self.to_be_bytes());
111    }
112
113    #[inline]
114    fn type_oid(&self) -> u32 {
115        23 // int4
116    }
117
118    #[inline]
119    fn encode_at(&self, dst: &mut [u8]) -> bool {
120        if dst.len() != 4 {
121            return false;
122        }
123        dst.copy_from_slice(&self.to_be_bytes());
124        true
125    }
126}
127
128impl Encode for i64 {
129    #[inline]
130    fn encode_binary(&self, buf: &mut Vec<u8>) {
131        buf.extend_from_slice(&self.to_be_bytes());
132    }
133
134    #[inline]
135    fn type_oid(&self) -> u32 {
136        20 // int8
137    }
138
139    #[inline]
140    fn encode_at(&self, dst: &mut [u8]) -> bool {
141        if dst.len() != 8 {
142            return false;
143        }
144        dst.copy_from_slice(&self.to_be_bytes());
145        true
146    }
147}
148
149impl Encode for f32 {
150    #[inline]
151    fn encode_binary(&self, buf: &mut Vec<u8>) {
152        buf.extend_from_slice(&self.to_be_bytes());
153    }
154
155    #[inline]
156    fn type_oid(&self) -> u32 {
157        700 // float4
158    }
159
160    #[inline]
161    fn encode_at(&self, dst: &mut [u8]) -> bool {
162        if dst.len() != 4 {
163            return false;
164        }
165        dst.copy_from_slice(&self.to_be_bytes());
166        true
167    }
168}
169
170impl Encode for f64 {
171    #[inline]
172    fn encode_binary(&self, buf: &mut Vec<u8>) {
173        buf.extend_from_slice(&self.to_be_bytes());
174    }
175
176    #[inline]
177    fn type_oid(&self) -> u32 {
178        701 // float8
179    }
180
181    #[inline]
182    fn encode_at(&self, dst: &mut [u8]) -> bool {
183        if dst.len() != 8 {
184            return false;
185        }
186        dst.copy_from_slice(&self.to_be_bytes());
187        true
188    }
189}
190
191impl Encode for &str {
192    #[inline]
193    fn encode_binary(&self, buf: &mut Vec<u8>) {
194        buf.extend_from_slice(self.as_bytes());
195    }
196
197    #[inline]
198    fn type_oid(&self) -> u32 {
199        25 // text
200    }
201}
202
203impl Encode for String {
204    #[inline]
205    fn encode_binary(&self, buf: &mut Vec<u8>) {
206        buf.extend_from_slice(self.as_bytes());
207    }
208
209    #[inline]
210    fn type_oid(&self) -> u32 {
211        25 // text
212    }
213}
214
215impl Encode for &[u8] {
216    #[inline]
217    fn encode_binary(&self, buf: &mut Vec<u8>) {
218        buf.extend_from_slice(self);
219    }
220
221    #[inline]
222    fn type_oid(&self) -> u32 {
223        17 // bytea
224    }
225}
226
227impl Encode for Vec<u8> {
228    #[inline]
229    fn encode_binary(&self, buf: &mut Vec<u8>) {
230        buf.extend_from_slice(self);
231    }
232
233    #[inline]
234    fn type_oid(&self) -> u32 {
235        17 // bytea
236    }
237}
238
239impl Encode for u32 {
240    #[inline]
241    fn encode_binary(&self, buf: &mut Vec<u8>) {
242        buf.extend_from_slice(&self.to_be_bytes());
243    }
244
245    #[inline]
246    fn type_oid(&self) -> u32 {
247        26 // oid
248    }
249
250    #[inline]
251    fn encode_at(&self, dst: &mut [u8]) -> bool {
252        if dst.len() != 4 {
253            return false;
254        }
255        dst.copy_from_slice(&self.to_be_bytes());
256        true
257    }
258}
259
260// --- Option<T> Encode — NULL parameter support ---
261
262impl<T: Encode> Encode for Option<T> {
263    #[inline]
264    fn encode_binary(&self, buf: &mut Vec<u8>) {
265        if let Some(val) = self {
266            val.encode_binary(buf);
267        }
268        // If None, encode_binary is a no-op — is_null() returns true,
269        // and the wire layer sends length -1 with no data bytes.
270    }
271
272    #[inline]
273    fn type_oid(&self) -> u32 {
274        // For NULL, we return 0 (unspecified). This is safe because the Parse
275        // message's param_oids array always gets explicit, concrete type OIDs
276        // from codegen — the Encode::type_oid for Option is only used in the
277        // fallback path and PG infers the type from context when it sees 0.
278        match self {
279            Some(val) => val.type_oid(),
280            None => 0,
281        }
282    }
283
284    #[inline]
285    fn is_null(&self) -> bool {
286        self.is_none()
287    }
288}
289
290// --- Feature-gated Encode implementations ---
291
292#[cfg(feature = "uuid")]
293impl Encode for uuid::Uuid {
294    #[inline]
295    fn encode_binary(&self, buf: &mut Vec<u8>) {
296        buf.extend_from_slice(self.as_bytes());
297    }
298
299    #[inline]
300    fn type_oid(&self) -> u32 {
301        2950 // uuid
302    }
303
304    #[inline]
305    fn encode_at(&self, dst: &mut [u8]) -> bool {
306        if dst.len() != 16 {
307            return false;
308        }
309        dst.copy_from_slice(self.as_bytes());
310        true
311    }
312}
313
314#[cfg(feature = "time")]
315impl Encode for time::OffsetDateTime {
316    #[inline]
317    fn encode_binary(&self, buf: &mut Vec<u8>) {
318        buf.extend_from_slice(&self.encode_pg_micros().to_be_bytes());
319    }
320
321    #[inline]
322    fn type_oid(&self) -> u32 {
323        1184 // timestamptz
324    }
325
326    #[inline]
327    fn encode_at(&self, dst: &mut [u8]) -> bool {
328        if dst.len() != 8 {
329            return false;
330        }
331        dst.copy_from_slice(&self.encode_pg_micros().to_be_bytes());
332        true
333    }
334}
335
336#[cfg(feature = "time")]
337trait OffsetDateTimeExt {
338    fn encode_pg_micros(&self) -> i64;
339}
340
341#[cfg(feature = "time")]
342impl OffsetDateTimeExt for time::OffsetDateTime {
343    #[inline]
344    fn encode_pg_micros(&self) -> i64 {
345        // PG epoch: 2000-01-01 00:00:00 UTC
346        // PG stores timestamptz as i64 microseconds since PG epoch
347        let pg_epoch =
348            time::OffsetDateTime::from_unix_timestamp(946_684_800).expect("PG epoch is valid");
349        let diff = *self - pg_epoch;
350        let micros_128 = diff.whole_microseconds();
351        if micros_128 >= i64::MIN as i128 && micros_128 <= i64::MAX as i128 {
352            micros_128 as i64
353        } else {
354            if micros_128 < 0 { i64::MIN } else { i64::MAX }
355        }
356    }
357}
358
359#[cfg(feature = "time")]
360impl Encode for time::Date {
361    #[inline]
362    fn encode_binary(&self, buf: &mut Vec<u8>) {
363        buf.extend_from_slice(&self.encode_pg_days().to_be_bytes());
364    }
365
366    #[inline]
367    fn type_oid(&self) -> u32 {
368        1082 // date
369    }
370
371    #[inline]
372    fn encode_at(&self, dst: &mut [u8]) -> bool {
373        if dst.len() != 4 {
374            return false;
375        }
376        dst.copy_from_slice(&self.encode_pg_days().to_be_bytes());
377        true
378    }
379}
380
381#[cfg(feature = "time")]
382trait DateExt {
383    fn encode_pg_days(&self) -> i32;
384}
385
386#[cfg(feature = "time")]
387impl DateExt for time::Date {
388    #[inline]
389    fn encode_pg_days(&self) -> i32 {
390        // PG stores date as i32 days since 2000-01-01
391        let pg_epoch = time::Date::from_calendar_date(2000, time::Month::January, 1)
392            .expect("PG epoch date is valid");
393        let days_i64 = (*self - pg_epoch).whole_days();
394        i32::try_from(days_i64).unwrap_or(if days_i64 < 0 { i32::MIN } else { i32::MAX })
395    }
396}
397
398#[cfg(feature = "time")]
399impl Encode for time::Time {
400    #[inline]
401    fn encode_binary(&self, buf: &mut Vec<u8>) {
402        buf.extend_from_slice(&self.encode_pg_micros().to_be_bytes());
403    }
404
405    #[inline]
406    fn type_oid(&self) -> u32 {
407        1083 // time
408    }
409
410    #[inline]
411    fn encode_at(&self, dst: &mut [u8]) -> bool {
412        if dst.len() != 8 {
413            return false;
414        }
415        dst.copy_from_slice(&self.encode_pg_micros().to_be_bytes());
416        true
417    }
418}
419
420#[cfg(feature = "time")]
421trait TimeExt {
422    fn encode_pg_micros(&self) -> i64;
423}
424
425#[cfg(feature = "time")]
426impl TimeExt for time::Time {
427    #[inline]
428    fn encode_pg_micros(&self) -> i64 {
429        // PG stores time as i64 microseconds since midnight
430        let midnight = time::Time::MIDNIGHT;
431        let diff = *self - midnight;
432        diff.whole_microseconds() as i64
433    }
434}
435
436#[cfg(feature = "time")]
437impl Encode for time::PrimitiveDateTime {
438    #[inline]
439    fn encode_binary(&self, buf: &mut Vec<u8>) {
440        buf.extend_from_slice(&self.encode_pg_micros().to_be_bytes());
441    }
442
443    #[inline]
444    fn type_oid(&self) -> u32 {
445        1114 // timestamp (without timezone)
446    }
447
448    #[inline]
449    fn encode_at(&self, dst: &mut [u8]) -> bool {
450        if dst.len() != 8 {
451            return false;
452        }
453        dst.copy_from_slice(&self.encode_pg_micros().to_be_bytes());
454        true
455    }
456}
457
458#[cfg(feature = "time")]
459trait PrimitiveDateTimeExt {
460    fn encode_pg_micros(&self) -> i64;
461}
462
463#[cfg(feature = "time")]
464impl PrimitiveDateTimeExt for time::PrimitiveDateTime {
465    #[inline]
466    fn encode_pg_micros(&self) -> i64 {
467        // TIMESTAMP (without tz) has the same binary format as TIMESTAMPTZ:
468        // i64 microseconds since PG epoch (2000-01-01 00:00:00)
469        let pg_epoch =
470            time::OffsetDateTime::from_unix_timestamp(946_684_800).expect("PG epoch is valid");
471        let as_utc = self.assume_utc();
472        let diff = as_utc - pg_epoch;
473        let micros_128 = diff.whole_microseconds();
474        if micros_128 >= i64::MIN as i128 && micros_128 <= i64::MAX as i128 {
475            micros_128 as i64
476        } else {
477            if micros_128 < 0 { i64::MIN } else { i64::MAX }
478        }
479    }
480}
481
482#[cfg(feature = "chrono")]
483impl Encode for chrono::NaiveDateTime {
484    #[inline]
485    fn encode_binary(&self, buf: &mut Vec<u8>) {
486        buf.extend_from_slice(&self.encode_pg_micros().to_be_bytes());
487    }
488
489    #[inline]
490    fn type_oid(&self) -> u32 {
491        1114 // timestamp (without timezone)
492    }
493
494    #[inline]
495    fn encode_at(&self, dst: &mut [u8]) -> bool {
496        if dst.len() != 8 {
497            return false;
498        }
499        dst.copy_from_slice(&self.encode_pg_micros().to_be_bytes());
500        true
501    }
502}
503
504#[cfg(feature = "chrono")]
505trait NaiveDateTimeExt {
506    fn encode_pg_micros(&self) -> i64;
507}
508
509#[cfg(feature = "chrono")]
510impl NaiveDateTimeExt for chrono::NaiveDateTime {
511    #[inline]
512    fn encode_pg_micros(&self) -> i64 {
513        // TIMESTAMP has same binary format: i64 microseconds since PG epoch
514        let pg_epoch_unix_micros: i64 = 946_684_800 * 1_000_000;
515        let unix_micros = self.and_utc().timestamp_micros();
516        unix_micros.saturating_sub(pg_epoch_unix_micros)
517    }
518}
519
520#[cfg(feature = "chrono")]
521impl Encode for chrono::DateTime<chrono::Utc> {
522    #[inline]
523    fn encode_binary(&self, buf: &mut Vec<u8>) {
524        buf.extend_from_slice(&self.encode_pg_micros().to_be_bytes());
525    }
526
527    #[inline]
528    fn type_oid(&self) -> u32 {
529        1184 // timestamptz
530    }
531
532    #[inline]
533    fn encode_at(&self, dst: &mut [u8]) -> bool {
534        if dst.len() != 8 {
535            return false;
536        }
537        dst.copy_from_slice(&self.encode_pg_micros().to_be_bytes());
538        true
539    }
540}
541
542#[cfg(feature = "chrono")]
543trait ChronoDateTimeUtcExt {
544    fn encode_pg_micros(&self) -> i64;
545}
546
547#[cfg(feature = "chrono")]
548impl ChronoDateTimeUtcExt for chrono::DateTime<chrono::Utc> {
549    #[inline]
550    fn encode_pg_micros(&self) -> i64 {
551        // PG epoch: 2000-01-01 00:00:00 UTC = Unix timestamp 946684800
552        let pg_epoch_unix_micros: i64 = 946_684_800 * 1_000_000;
553        let unix_micros = self.timestamp_micros();
554        unix_micros.saturating_sub(pg_epoch_unix_micros)
555    }
556}
557
558#[cfg(feature = "chrono")]
559impl Encode for chrono::NaiveDate {
560    #[inline]
561    fn encode_binary(&self, buf: &mut Vec<u8>) {
562        buf.extend_from_slice(&self.encode_pg_days().to_be_bytes());
563    }
564
565    #[inline]
566    fn type_oid(&self) -> u32 {
567        1082 // date
568    }
569
570    #[inline]
571    fn encode_at(&self, dst: &mut [u8]) -> bool {
572        if dst.len() != 4 {
573            return false;
574        }
575        dst.copy_from_slice(&self.encode_pg_days().to_be_bytes());
576        true
577    }
578}
579
580#[cfg(feature = "chrono")]
581trait ChronoNaiveDateExt {
582    fn encode_pg_days(&self) -> i32;
583}
584
585#[cfg(feature = "chrono")]
586impl ChronoNaiveDateExt for chrono::NaiveDate {
587    #[inline]
588    fn encode_pg_days(&self) -> i32 {
589        let pg_epoch = chrono::NaiveDate::from_ymd_opt(2000, 1, 1).expect("PG epoch date valid");
590        let days_i64 = (*self - pg_epoch).num_days();
591        i32::try_from(days_i64).unwrap_or(if days_i64 < 0 { i32::MIN } else { i32::MAX })
592    }
593}
594
595#[cfg(feature = "chrono")]
596impl Encode for chrono::NaiveTime {
597    #[inline]
598    fn encode_binary(&self, buf: &mut Vec<u8>) {
599        buf.extend_from_slice(&self.encode_pg_micros().to_be_bytes());
600    }
601
602    #[inline]
603    fn type_oid(&self) -> u32 {
604        1083 // time
605    }
606
607    #[inline]
608    fn encode_at(&self, dst: &mut [u8]) -> bool {
609        if dst.len() != 8 {
610            return false;
611        }
612        dst.copy_from_slice(&self.encode_pg_micros().to_be_bytes());
613        true
614    }
615}
616
617#[cfg(feature = "chrono")]
618trait ChronoNaiveTimeExt {
619    fn encode_pg_micros(&self) -> i64;
620}
621
622#[cfg(feature = "chrono")]
623impl ChronoNaiveTimeExt for chrono::NaiveTime {
624    #[inline]
625    fn encode_pg_micros(&self) -> i64 {
626        // Midnight (00:00:00) is infallibly valid -- this .expect() can never fail.
627        let midnight = chrono::NaiveTime::from_hms_opt(0, 0, 0).expect("midnight is always valid");
628        let diff = *self - midnight;
629        // Panic on None instead of silently encoding midnight (0).
630        diff.num_microseconds()
631            .expect("time-of-day difference always fits i64")
632    }
633}
634
635#[cfg(feature = "decimal")]
636impl Encode for rust_decimal::Decimal {
637    fn encode_binary(&self, buf: &mut Vec<u8>) {
638        // PG NUMERIC binary format:
639        //   i16 ndigits  — number of base-10000 digit groups
640        //   i16 weight   — exponent of first digit (units of 10^4)
641        //   i16 sign     — 0x0000 = positive, 0x4000 = negative
642        //   i16 dscale   — number of digits after decimal point
643        //   [i16; ndigits] — base-10000 digit values
644        //
645        // Special case: zero is encoded as ndigits=0, weight=0, sign=0, dscale=0.
646
647        if self.is_zero() {
648            // ndigits=0, weight=0, sign=+, dscale=scale
649            let dscale = i16::try_from(self.scale()).unwrap_or(i16::MAX);
650            buf.extend_from_slice(&0i16.to_be_bytes()); // ndigits
651            buf.extend_from_slice(&0i16.to_be_bytes()); // weight
652            buf.extend_from_slice(&0x0000i16.to_be_bytes()); // sign
653            buf.extend_from_slice(&dscale.to_be_bytes()); // dscale
654            return;
655        }
656
657        let sign: i16 = if self.is_sign_negative() {
658            0x4000
659        } else {
660            0x0000
661        };
662        let scale = self.scale();
663
664        // Get the absolute value as a u128 of unscaled digits
665        let abs = self.abs();
666        let mut mantissa = abs.mantissa().unsigned_abs();
667
668        // Collect decimal digits (max ~39 for u128, SmallVec caps at 32 inline)
669        let mut decimal_digits: smallvec::SmallVec<[i16; 32]> = smallvec::SmallVec::new();
670        while mantissa > 0 {
671            decimal_digits.push((mantissa % 10) as i16);
672            mantissa /= 10;
673        }
674        decimal_digits.reverse();
675
676        // decimal_digits now has the full unscaled number.
677        // The decimal point is `scale` digits from the right.
678        // Integer part length:
679        let total_digits = decimal_digits.len();
680        let int_len = total_digits.saturating_sub(scale as usize);
681
682        // Pad integer part on the left so its length is a multiple of 4
683        let int_pad = if int_len > 0 {
684            (4 - (int_len % 4)) % 4
685        } else {
686            0
687        };
688        // Pad fractional part on the right so total is a multiple of 4
689        let frac_len = total_digits - int_len;
690        let frac_pad = (4 - (frac_len % 4)) % 4;
691
692        let mut padded: smallvec::SmallVec<[i16; 32]> = smallvec::SmallVec::new();
693        padded.extend(std::iter::repeat_n(0i16, int_pad));
694        padded.extend_from_slice(&decimal_digits);
695        padded.extend(std::iter::repeat_n(0i16, frac_pad));
696
697        // Group into base-10000 digits
698        let mut pg_digits: smallvec::SmallVec<[i16; 12]> = smallvec::SmallVec::new();
699        for chunk in padded.chunks(4) {
700            let d = chunk[0] * 1000 + chunk[1] * 100 + chunk[2] * 10 + chunk[3];
701            pg_digits.push(d);
702        }
703
704        // Strip trailing zero groups from the fractional part
705        let int_groups = (int_len + int_pad) / 4;
706        while pg_digits.len() > int_groups && pg_digits.last().copied() == Some(0) {
707            pg_digits.pop();
708        }
709
710        let ndigits = pg_digits.len() as i16;
711
712        // for large scales, cast to i16 only at the end with saturation.
713        let weight: i16 = if int_len > 0 {
714            let w = (int_len + int_pad) / 4 - 1;
715            w as i16
716        } else {
717            // Pure fractional: weight is negative
718            // E.g., 0.0001 has weight -1 (first group is 10^-4)
719            let w = -((scale as usize - frac_len + frac_pad) as i32 / 4 + 1);
720            // Clamp to i16 range (PG weight is i16 on the wire)
721            w.clamp(i16::MIN as i32, i16::MAX as i32) as i16
722        };
723
724        let dscale = i16::try_from(scale).unwrap_or(i16::MAX);
725        buf.extend_from_slice(&ndigits.to_be_bytes());
726        buf.extend_from_slice(&weight.to_be_bytes());
727        buf.extend_from_slice(&sign.to_be_bytes());
728        buf.extend_from_slice(&dscale.to_be_bytes());
729        for d in &pg_digits {
730            buf.extend_from_slice(&d.to_be_bytes());
731        }
732    }
733
734    #[inline]
735    fn type_oid(&self) -> u32 {
736        1700 // numeric
737    }
738}
739
740// --- Decode functions ---
741
742/// Decode a boolean from binary format (1 byte: 0x00 = false, 0x01 = true).
743///
744/// # Errors
745///
746/// Returns `DriverError::Protocol` if the data is not exactly 1 byte.
747#[inline]
748pub fn decode_bool(data: &[u8]) -> Result<bool, DriverError> {
749    if data.len() != 1 {
750        return Err(DriverError::Protocol(format!(
751            "bool: expected 1 byte, got {}",
752            data.len()
753        )));
754    }
755    Ok(data[0] != 0)
756}
757
758/// Decode a 16-bit integer from binary format (2 bytes, big-endian).
759#[inline]
760pub fn decode_i16(data: &[u8]) -> Result<i16, DriverError> {
761    if data.len() != 2 {
762        return Err(DriverError::Protocol(format!(
763            "i16: expected 2 bytes, got {}",
764            data.len()
765        )));
766    }
767    Ok(i16::from_be_bytes([data[0], data[1]]))
768}
769
770/// Decode a 32-bit integer from binary format (4 bytes, big-endian).
771#[inline]
772pub fn decode_i32(data: &[u8]) -> Result<i32, DriverError> {
773    if data.len() != 4 {
774        return Err(DriverError::Protocol(format!(
775            "i32: expected 4 bytes, got {}",
776            data.len()
777        )));
778    }
779    Ok(i32::from_be_bytes([data[0], data[1], data[2], data[3]]))
780}
781
782/// Decode a 64-bit integer from binary format (8 bytes, big-endian).
783#[inline]
784pub fn decode_i64(data: &[u8]) -> Result<i64, DriverError> {
785    if data.len() != 8 {
786        return Err(DriverError::Protocol(format!(
787            "i64: expected 8 bytes, got {}",
788            data.len()
789        )));
790    }
791    Ok(i64::from_be_bytes([
792        data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
793    ]))
794}
795
796/// Decode a 32-bit float from binary format (4 bytes, big-endian IEEE 754).
797#[inline]
798pub fn decode_f32(data: &[u8]) -> Result<f32, DriverError> {
799    if data.len() != 4 {
800        return Err(DriverError::Protocol(format!(
801            "f32: expected 4 bytes, got {}",
802            data.len()
803        )));
804    }
805    Ok(f32::from_be_bytes([data[0], data[1], data[2], data[3]]))
806}
807
808/// Decode a 64-bit float from binary format (8 bytes, big-endian IEEE 754).
809#[inline]
810pub fn decode_f64(data: &[u8]) -> Result<f64, DriverError> {
811    if data.len() != 8 {
812        return Err(DriverError::Protocol(format!(
813            "f64: expected 8 bytes, got {}",
814            data.len()
815        )));
816    }
817    Ok(f64::from_be_bytes([
818        data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
819    ]))
820}
821
822/// Decode a UTF-8 string from binary format (variable length).
823///
824/// Returns the string slice directly — zero-copy when data lives in the arena.
825/// Uses SIMD-accelerated validation (SSE4.2/AVX2 on x86_64, NEON on aarch64)
826/// via `simdutf8`, falling back to scalar on unsupported targets.
827#[inline]
828pub fn decode_str(data: &[u8]) -> Result<&str, DriverError> {
829    simdutf8::basic::from_utf8(data)
830        .map_err(|e| DriverError::Protocol(format!("invalid UTF-8 in text column: {e}")))
831}
832
833/// Decode raw bytes (bytea) — identity function, zero-copy.
834#[inline]
835pub fn decode_bytes(data: &[u8]) -> &[u8] {
836    data
837}
838
839/// Decode a UUID from binary format (exactly 16 bytes).
840#[inline]
841pub fn decode_uuid(data: &[u8]) -> Result<[u8; 16], DriverError> {
842    if data.len() != 16 {
843        return Err(DriverError::Protocol(format!(
844            "uuid: expected 16 bytes, got {}",
845            data.len()
846        )));
847    }
848    let mut uuid = [0u8; 16];
849    uuid.copy_from_slice(data);
850    Ok(uuid)
851}
852
853/// Encode a parameter value into the wire buffer with its 4-byte length prefix.
854///
855/// NULL values get a length of -1 with no data.
856pub fn encode_param(buf: &mut Vec<u8>, param: &dyn Encode) {
857    let start = buf.len();
858    buf.extend_from_slice(&[0u8; 4]); // placeholder for length
859    param.encode_binary(buf);
860    let data_len = (buf.len() - start - 4) as i32;
861    buf[start..start + 4].copy_from_slice(&data_len.to_be_bytes());
862}
863
864// --- Array encode helper ---
865
866/// Write the PG binary array header for a 1-dimensional array.
867///
868/// For empty arrays (n_elements == 0), writes ndim=0 per PG convention.
869/// For non-empty arrays, writes a full 1-D header with lower_bound=1.
870fn encode_array_header(buf: &mut Vec<u8>, n_elements: usize, elem_oid: u32) {
871    if n_elements == 0 {
872        buf.extend_from_slice(&0i32.to_be_bytes()); // ndim = 0 (PG empty array convention)
873        buf.extend_from_slice(&0i32.to_be_bytes()); // has_null = 0
874        buf.extend_from_slice(&(elem_oid as i32).to_be_bytes()); // element OID
875        return;
876    }
877    buf.extend_from_slice(&1i32.to_be_bytes()); // ndim = 1
878    buf.extend_from_slice(&0i32.to_be_bytes()); // has_null = 0 (we don't support NULL elements in encode)
879    buf.extend_from_slice(&(elem_oid as i32).to_be_bytes()); // element OID
880    buf.extend_from_slice(&(n_elements as i32).to_be_bytes()); // length
881    buf.extend_from_slice(&1i32.to_be_bytes()); // lower_bound = 1
882}
883
884// --- Array Encode implementations ---
885
886impl Encode for [bool] {
887    fn encode_binary(&self, buf: &mut Vec<u8>) {
888        encode_array_header(buf, self.len(), 16);
889        for val in self {
890            buf.extend_from_slice(&1i32.to_be_bytes()); // elem_len = 1
891            buf.push(if *val { 1 } else { 0 });
892        }
893    }
894
895    #[inline]
896    fn type_oid(&self) -> u32 {
897        1000 // bool[]
898    }
899}
900
901impl Encode for &[bool] {
902    #[inline]
903    fn encode_binary(&self, buf: &mut Vec<u8>) {
904        (**self).encode_binary(buf);
905    }
906
907    #[inline]
908    fn type_oid(&self) -> u32 {
909        1000
910    }
911}
912
913impl Encode for Vec<bool> {
914    #[inline]
915    fn encode_binary(&self, buf: &mut Vec<u8>) {
916        self.as_slice().encode_binary(buf);
917    }
918
919    #[inline]
920    fn type_oid(&self) -> u32 {
921        1000
922    }
923}
924
925impl Encode for [i16] {
926    fn encode_binary(&self, buf: &mut Vec<u8>) {
927        encode_array_header(buf, self.len(), 21);
928        for val in self {
929            buf.extend_from_slice(&2i32.to_be_bytes()); // elem_len = 2
930            buf.extend_from_slice(&val.to_be_bytes());
931        }
932    }
933
934    #[inline]
935    fn type_oid(&self) -> u32 {
936        1005 // int2[]
937    }
938}
939
940impl Encode for &[i16] {
941    #[inline]
942    fn encode_binary(&self, buf: &mut Vec<u8>) {
943        (**self).encode_binary(buf);
944    }
945
946    #[inline]
947    fn type_oid(&self) -> u32 {
948        1005
949    }
950}
951
952impl Encode for Vec<i16> {
953    #[inline]
954    fn encode_binary(&self, buf: &mut Vec<u8>) {
955        self.as_slice().encode_binary(buf);
956    }
957
958    #[inline]
959    fn type_oid(&self) -> u32 {
960        1005
961    }
962}
963
964impl Encode for [i32] {
965    fn encode_binary(&self, buf: &mut Vec<u8>) {
966        encode_array_header(buf, self.len(), 23);
967        for val in self {
968            buf.extend_from_slice(&4i32.to_be_bytes()); // elem_len = 4
969            buf.extend_from_slice(&val.to_be_bytes());
970        }
971    }
972
973    #[inline]
974    fn type_oid(&self) -> u32 {
975        1007 // int4[]
976    }
977}
978
979impl Encode for &[i32] {
980    #[inline]
981    fn encode_binary(&self, buf: &mut Vec<u8>) {
982        (**self).encode_binary(buf);
983    }
984
985    #[inline]
986    fn type_oid(&self) -> u32 {
987        1007
988    }
989}
990
991impl Encode for Vec<i32> {
992    #[inline]
993    fn encode_binary(&self, buf: &mut Vec<u8>) {
994        self.as_slice().encode_binary(buf);
995    }
996
997    #[inline]
998    fn type_oid(&self) -> u32 {
999        1007
1000    }
1001}
1002
1003impl Encode for [i64] {
1004    fn encode_binary(&self, buf: &mut Vec<u8>) {
1005        encode_array_header(buf, self.len(), 20);
1006        for val in self {
1007            buf.extend_from_slice(&8i32.to_be_bytes()); // elem_len = 8
1008            buf.extend_from_slice(&val.to_be_bytes());
1009        }
1010    }
1011
1012    #[inline]
1013    fn type_oid(&self) -> u32 {
1014        1016 // int8[]
1015    }
1016}
1017
1018impl Encode for &[i64] {
1019    #[inline]
1020    fn encode_binary(&self, buf: &mut Vec<u8>) {
1021        (**self).encode_binary(buf);
1022    }
1023
1024    #[inline]
1025    fn type_oid(&self) -> u32 {
1026        1016
1027    }
1028}
1029
1030impl Encode for Vec<i64> {
1031    #[inline]
1032    fn encode_binary(&self, buf: &mut Vec<u8>) {
1033        self.as_slice().encode_binary(buf);
1034    }
1035
1036    #[inline]
1037    fn type_oid(&self) -> u32 {
1038        1016
1039    }
1040}
1041
1042impl Encode for [f32] {
1043    fn encode_binary(&self, buf: &mut Vec<u8>) {
1044        encode_array_header(buf, self.len(), 700);
1045        for val in self {
1046            buf.extend_from_slice(&4i32.to_be_bytes()); // elem_len = 4
1047            buf.extend_from_slice(&val.to_be_bytes());
1048        }
1049    }
1050
1051    #[inline]
1052    fn type_oid(&self) -> u32 {
1053        1021 // float4[]
1054    }
1055}
1056
1057impl Encode for &[f32] {
1058    #[inline]
1059    fn encode_binary(&self, buf: &mut Vec<u8>) {
1060        (**self).encode_binary(buf);
1061    }
1062
1063    #[inline]
1064    fn type_oid(&self) -> u32 {
1065        1021
1066    }
1067}
1068
1069impl Encode for Vec<f32> {
1070    #[inline]
1071    fn encode_binary(&self, buf: &mut Vec<u8>) {
1072        self.as_slice().encode_binary(buf);
1073    }
1074
1075    #[inline]
1076    fn type_oid(&self) -> u32 {
1077        1021
1078    }
1079}
1080
1081impl Encode for [f64] {
1082    fn encode_binary(&self, buf: &mut Vec<u8>) {
1083        encode_array_header(buf, self.len(), 701);
1084        for val in self {
1085            buf.extend_from_slice(&8i32.to_be_bytes()); // elem_len = 8
1086            buf.extend_from_slice(&val.to_be_bytes());
1087        }
1088    }
1089
1090    #[inline]
1091    fn type_oid(&self) -> u32 {
1092        1022 // float8[]
1093    }
1094}
1095
1096impl Encode for &[f64] {
1097    #[inline]
1098    fn encode_binary(&self, buf: &mut Vec<u8>) {
1099        (**self).encode_binary(buf);
1100    }
1101
1102    #[inline]
1103    fn type_oid(&self) -> u32 {
1104        1022
1105    }
1106}
1107
1108impl Encode for Vec<f64> {
1109    #[inline]
1110    fn encode_binary(&self, buf: &mut Vec<u8>) {
1111        self.as_slice().encode_binary(buf);
1112    }
1113
1114    #[inline]
1115    fn type_oid(&self) -> u32 {
1116        1022
1117    }
1118}
1119
1120impl Encode for [&str] {
1121    fn encode_binary(&self, buf: &mut Vec<u8>) {
1122        encode_array_header(buf, self.len(), 25);
1123        for val in self {
1124            let bytes = val.as_bytes();
1125            buf.extend_from_slice(&(bytes.len() as i32).to_be_bytes());
1126            buf.extend_from_slice(bytes);
1127        }
1128    }
1129
1130    #[inline]
1131    fn type_oid(&self) -> u32 {
1132        1009 // text[]
1133    }
1134}
1135
1136impl Encode for &[&str] {
1137    #[inline]
1138    fn encode_binary(&self, buf: &mut Vec<u8>) {
1139        (**self).encode_binary(buf);
1140    }
1141
1142    #[inline]
1143    fn type_oid(&self) -> u32 {
1144        1009
1145    }
1146}
1147
1148impl Encode for Vec<String> {
1149    fn encode_binary(&self, buf: &mut Vec<u8>) {
1150        encode_array_header(buf, self.len(), 25);
1151        for val in self {
1152            let bytes = val.as_bytes();
1153            buf.extend_from_slice(&(bytes.len() as i32).to_be_bytes());
1154            buf.extend_from_slice(bytes);
1155        }
1156    }
1157
1158    #[inline]
1159    fn type_oid(&self) -> u32 {
1160        1009 // text[]
1161    }
1162}
1163
1164impl Encode for [&[u8]] {
1165    fn encode_binary(&self, buf: &mut Vec<u8>) {
1166        encode_array_header(buf, self.len(), 17);
1167        for val in self {
1168            buf.extend_from_slice(&(val.len() as i32).to_be_bytes());
1169            buf.extend_from_slice(val);
1170        }
1171    }
1172
1173    #[inline]
1174    fn type_oid(&self) -> u32 {
1175        1001 // bytea[]
1176    }
1177}
1178
1179impl Encode for &[&[u8]] {
1180    #[inline]
1181    fn encode_binary(&self, buf: &mut Vec<u8>) {
1182        (**self).encode_binary(buf);
1183    }
1184
1185    #[inline]
1186    fn type_oid(&self) -> u32 {
1187        1001
1188    }
1189}
1190
1191impl Encode for [Vec<u8>] {
1192    fn encode_binary(&self, buf: &mut Vec<u8>) {
1193        encode_array_header(buf, self.len(), 17);
1194        for val in self {
1195            buf.extend_from_slice(&(val.len() as i32).to_be_bytes());
1196            buf.extend_from_slice(val);
1197        }
1198    }
1199
1200    #[inline]
1201    fn type_oid(&self) -> u32 {
1202        1001 // bytea[]
1203    }
1204}
1205
1206impl Encode for &[Vec<u8>] {
1207    #[inline]
1208    fn encode_binary(&self, buf: &mut Vec<u8>) {
1209        (**self).encode_binary(buf);
1210    }
1211
1212    #[inline]
1213    fn type_oid(&self) -> u32 {
1214        1001
1215    }
1216}
1217
1218impl Encode for Vec<Vec<u8>> {
1219    #[inline]
1220    fn encode_binary(&self, buf: &mut Vec<u8>) {
1221        self.as_slice().encode_binary(buf);
1222    }
1223
1224    #[inline]
1225    fn type_oid(&self) -> u32 {
1226        1001 // bytea[]
1227    }
1228}
1229
1230// --- Array decode functions ---
1231
1232/// Decode a PG binary array, returning the raw element byte slices.
1233///
1234/// PG binary array format:
1235/// - i32: ndim (number of dimensions, we only support 1)
1236/// - i32: has_null flag (0 = no NULLs, 1 = may have NULLs)
1237/// - i32: element type OID
1238/// - For each dimension: i32 length, i32 lower_bound
1239/// - For each element: i32 data_length (-1 = NULL), then data bytes
1240fn decode_array_elements(data: &[u8]) -> Result<Vec<&[u8]>, DriverError> {
1241    if data.len() < 12 {
1242        return Err(DriverError::Protocol(format!(
1243            "array: expected >= 12 bytes header, got {}",
1244            data.len()
1245        )));
1246    }
1247    let ndim = i32::from_be_bytes([data[0], data[1], data[2], data[3]]);
1248    if ndim == 0 {
1249        return Ok(Vec::new());
1250    }
1251    if ndim != 1 {
1252        return Err(DriverError::Protocol(format!(
1253            "array: only 1-dimensional arrays supported, got {ndim}"
1254        )));
1255    }
1256    // _has_null at [4..8], _elem_oid at [8..12]
1257    if data.len() < 20 {
1258        return Err(DriverError::Protocol(
1259            "array: truncated dimension header".into(),
1260        ));
1261    }
1262    let n_elements_raw = i32::from_be_bytes([data[12], data[13], data[14], data[15]]);
1263    if n_elements_raw < 0 {
1264        return Err(DriverError::Protocol(
1265            "array: negative element count".into(),
1266        ));
1267    }
1268    let n_elements = n_elements_raw as usize;
1269    // lower_bound at [16..20]
1270    let mut pos = 20;
1271    let mut elements = Vec::with_capacity(n_elements);
1272    for _ in 0..n_elements {
1273        if pos + 4 > data.len() {
1274            return Err(DriverError::Protocol("array: truncated element".into()));
1275        }
1276        let elem_len = i32::from_be_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]);
1277        pos += 4;
1278        if elem_len < 0 {
1279            // NULL element -- skip (arrays of non-nullable types shouldn't have this)
1280            continue;
1281        }
1282        let elem_len = elem_len as usize;
1283        if pos + elem_len > data.len() {
1284            return Err(DriverError::Protocol(
1285                "array: truncated element data".into(),
1286            ));
1287        }
1288        elements.push(&data[pos..pos + elem_len]);
1289        pos += elem_len;
1290    }
1291    Ok(elements)
1292}
1293
1294/// Decode a PG binary array of i32.
1295pub fn decode_array_i32(data: &[u8]) -> Result<Vec<i32>, DriverError> {
1296    decode_array_elements(data)?
1297        .into_iter()
1298        .map(decode_i32)
1299        .collect()
1300}
1301
1302/// Decode a PG binary array of i16.
1303pub fn decode_array_i16(data: &[u8]) -> Result<Vec<i16>, DriverError> {
1304    decode_array_elements(data)?
1305        .into_iter()
1306        .map(decode_i16)
1307        .collect()
1308}
1309
1310/// Decode a PG binary array of i64.
1311pub fn decode_array_i64(data: &[u8]) -> Result<Vec<i64>, DriverError> {
1312    decode_array_elements(data)?
1313        .into_iter()
1314        .map(decode_i64)
1315        .collect()
1316}
1317
1318/// Decode a PG binary array of f32.
1319pub fn decode_array_f32(data: &[u8]) -> Result<Vec<f32>, DriverError> {
1320    decode_array_elements(data)?
1321        .into_iter()
1322        .map(decode_f32)
1323        .collect()
1324}
1325
1326/// Decode a PG binary array of f64.
1327pub fn decode_array_f64(data: &[u8]) -> Result<Vec<f64>, DriverError> {
1328    decode_array_elements(data)?
1329        .into_iter()
1330        .map(decode_f64)
1331        .collect()
1332}
1333
1334/// Decode a PG binary array of booleans.
1335pub fn decode_array_bool(data: &[u8]) -> Result<Vec<bool>, DriverError> {
1336    decode_array_elements(data)?
1337        .into_iter()
1338        .map(decode_bool)
1339        .collect()
1340}
1341
1342/// Decode a PG binary array of text/varchar strings.
1343pub fn decode_array_str(data: &[u8]) -> Result<Vec<String>, DriverError> {
1344    decode_array_elements(data)?
1345        .into_iter()
1346        .map(|d| decode_str(d).map(|s| s.to_owned()))
1347        .collect()
1348}
1349
1350/// Decode a PG binary array of bytea values.
1351pub fn decode_array_bytea(data: &[u8]) -> Result<Vec<Vec<u8>>, DriverError> {
1352    Ok(decode_array_elements(data)?
1353        .into_iter()
1354        .map(|d| d.to_vec())
1355        .collect())
1356}
1357
1358// --- Feature-gated decode functions ---
1359
1360/// Decode a UUID from 16 raw bytes into `uuid::Uuid`.
1361#[cfg(feature = "uuid")]
1362#[inline]
1363pub fn decode_uuid_type(data: &[u8]) -> Result<uuid::Uuid, DriverError> {
1364    let bytes = decode_uuid(data)?;
1365    Ok(uuid::Uuid::from_bytes(bytes))
1366}
1367
1368/// Decode PG timestamptz (i64 microseconds since 2000-01-01) to `time::OffsetDateTime`.
1369#[cfg(feature = "time")]
1370#[inline]
1371pub fn decode_timestamptz_time(data: &[u8]) -> Result<time::OffsetDateTime, DriverError> {
1372    let micros = decode_i64(data)?;
1373    // PG epoch = Unix 946684800
1374    let unix_micros = micros + 946_684_800i64 * 1_000_000;
1375    let secs = unix_micros.div_euclid(1_000_000);
1376    let nanos = (unix_micros.rem_euclid(1_000_000) * 1000) as i128;
1377    time::OffsetDateTime::from_unix_timestamp_nanos(secs as i128 * 1_000_000_000 + nanos)
1378        .map_err(|e| DriverError::Protocol(format!("timestamptz decode: {e}")))
1379}
1380
1381/// Decode PG date (i32 days since 2000-01-01) to `time::Date`.
1382#[cfg(feature = "time")]
1383#[inline]
1384pub fn decode_date_time(data: &[u8]) -> Result<time::Date, DriverError> {
1385    let days = decode_i32(data)?;
1386    let pg_epoch = time::Date::from_calendar_date(2000, time::Month::January, 1)
1387        .expect("PG epoch date is valid");
1388    pg_epoch
1389        .checked_add(time::Duration::days(days as i64))
1390        .ok_or_else(|| DriverError::Protocol(format!("date out of range: {days} days")))
1391}
1392
1393/// Decode PG time (i64 microseconds since midnight) to `time::Time`.
1394#[cfg(feature = "time")]
1395#[inline]
1396pub fn decode_time_time(data: &[u8]) -> Result<time::Time, DriverError> {
1397    let micros = decode_i64(data)?;
1398
1399    // would cause `as u8` to wrap to wrong values.
1400    if !(0..86_400_000_000).contains(&micros) {
1401        return Err(DriverError::Protocol(format!(
1402            "time out of range: {micros}us (must be 0..86_400_000_000)"
1403        )));
1404    }
1405    let total_secs = micros / 1_000_000;
1406    let h = (total_secs / 3600) as u8;
1407    let m = ((total_secs % 3600) / 60) as u8;
1408    let s = (total_secs % 60) as u8;
1409    let micro = (micros % 1_000_000) as u32;
1410    time::Time::from_hms_micro(h, m, s, micro)
1411        .map_err(|e| DriverError::Protocol(format!("time decode: {e}")))
1412}
1413
1414/// Decode PG timestamptz to `chrono::DateTime<chrono::Utc>`.
1415#[cfg(feature = "chrono")]
1416#[inline]
1417pub fn decode_timestamptz_chrono(
1418    data: &[u8],
1419) -> Result<chrono::DateTime<chrono::Utc>, DriverError> {
1420    let micros = decode_i64(data)?;
1421    let pg_epoch_unix_micros: i64 = 946_684_800 * 1_000_000;
1422    let unix_micros = micros + pg_epoch_unix_micros;
1423    let secs = unix_micros.div_euclid(1_000_000);
1424    let nsecs = (unix_micros.rem_euclid(1_000_000) * 1000) as u32;
1425    chrono::DateTime::from_timestamp(secs, nsecs)
1426        .ok_or_else(|| DriverError::Protocol(format!("timestamptz out of range: {micros}us")))
1427}
1428
1429/// Decode PG date to `chrono::NaiveDate`.
1430#[cfg(feature = "chrono")]
1431#[inline]
1432pub fn decode_date_chrono(data: &[u8]) -> Result<chrono::NaiveDate, DriverError> {
1433    let days = decode_i32(data)?;
1434    let pg_epoch = chrono::NaiveDate::from_ymd_opt(2000, 1, 1).expect("PG epoch valid");
1435
1436    // silently mapped ALL dates before 2000-01-01 to epoch. Check sign first.
1437    let result = if days >= 0 {
1438        pg_epoch.checked_add_days(chrono::Days::new(days as u64))
1439    } else {
1440        pg_epoch.checked_sub_days(chrono::Days::new(days.unsigned_abs() as u64))
1441    };
1442    result.ok_or_else(|| DriverError::Protocol(format!("date out of range: {days} days")))
1443}
1444
1445/// Decode PG time to `chrono::NaiveTime`.
1446#[cfg(feature = "chrono")]
1447#[inline]
1448pub fn decode_time_chrono(data: &[u8]) -> Result<chrono::NaiveTime, DriverError> {
1449    let micros = decode_i64(data)?;
1450
1451    // when cast to u32, producing wrong time values.
1452    if !(0..86_400_000_000).contains(&micros) {
1453        return Err(DriverError::Protocol(format!(
1454            "time out of range: {micros}us (must be 0..86_400_000_000)"
1455        )));
1456    }
1457    let total_secs = (micros / 1_000_000) as u32;
1458    let micro = (micros % 1_000_000) as u32;
1459    chrono::NaiveTime::from_num_seconds_from_midnight_opt(total_secs, micro * 1000)
1460        .ok_or_else(|| DriverError::Protocol(format!("time out of range: {micros}us")))
1461}
1462
1463/// Decode PG numeric binary to `rust_decimal::Decimal`.
1464///
1465/// PG NUMERIC binary: i16 ndigits, i16 weight, i16 sign, i16 dscale,
1466/// followed by ndigits base-10000 digit values (i16 each).
1467///
1468/// The value is: sum(digit[i] * 10^(4 * (weight - i))) for i in 0..ndigits.
1469#[cfg(feature = "decimal")]
1470pub fn decode_numeric_decimal(data: &[u8]) -> Result<rust_decimal::Decimal, DriverError> {
1471    if data.len() < 8 {
1472        return Err(DriverError::Protocol(format!(
1473            "numeric: expected >= 8 bytes header, got {}",
1474            data.len()
1475        )));
1476    }
1477    let ndigits = i16::from_be_bytes([data[0], data[1]]) as usize;
1478    let weight = i16::from_be_bytes([data[2], data[3]]) as i32;
1479    let sign = i16::from_be_bytes([data[4], data[5]]);
1480    let _dscale = i16::from_be_bytes([data[6], data[7]]) as u32;
1481
1482    if data.len() != 8 + ndigits * 2 {
1483        return Err(DriverError::Protocol(format!(
1484            "numeric: expected {} bytes, got {}",
1485            8 + ndigits * 2,
1486            data.len()
1487        )));
1488    }
1489
1490    if ndigits == 0 {
1491        return Ok(rust_decimal::Decimal::ZERO);
1492    }
1493
1494    // Read digit values
1495    let mut digits: smallvec::SmallVec<[i64; 16]> = smallvec::SmallVec::with_capacity(ndigits);
1496    for i in 0..ndigits {
1497        let off = 8 + i * 2;
1498        digits.push(i16::from_be_bytes([data[off], data[off + 1]]) as i64);
1499    }
1500
1501    // Compute the value arithmetically: sum(digit[i] * 10^(4*(weight-i)))
1502    // Build a u128 mantissa and track the scale (fractional digits).
1503    let mut mantissa: u128 = 0;
1504    for &d in &digits {
1505        mantissa = mantissa
1506            .checked_mul(10_000)
1507            .and_then(|m| m.checked_add(d as u128))
1508            .ok_or_else(|| DriverError::Protocol("numeric value too large for Decimal".into()))?;
1509    }
1510
1511    // The value with all digits is: mantissa * 10^(4 * (weight - ndigits + 1))
1512    // If weight >= ndigits-1, we need to multiply by 10^(4*(weight - ndigits + 1))
1513    // If weight < ndigits-1, we have fractional digits
1514    let exponent = 4 * (weight - ndigits as i32 + 1);
1515    let result = if exponent >= 0 {
1516        // All integer: multiply mantissa by 10^exponent
1517        let factor = 10u128
1518            .checked_pow(exponent as u32)
1519            .ok_or_else(|| DriverError::Protocol("numeric exponent too large".into()))?;
1520        let m = mantissa
1521            .checked_mul(factor)
1522            .ok_or_else(|| DriverError::Protocol("numeric value too large for Decimal".into()))?;
1523        if m > u128::from(u64::MAX) {
1524            // Decimal max mantissa is 96 bits, fall back to string for huge values
1525            let s = m.to_string();
1526            s.parse::<rust_decimal::Decimal>()
1527                .map_err(|e| DriverError::Protocol(format!("numeric parse error: {e}")))?
1528        } else {
1529            rust_decimal::Decimal::from_i128_with_scale(m as i128, 0)
1530        }
1531    } else {
1532        // Has fractional part: scale = -exponent
1533        let scale = (-exponent) as u32;
1534        // rust_decimal stores mantissa as 96-bit integer with scale
1535        if mantissa <= u128::from(u64::MAX) {
1536            rust_decimal::Decimal::from_i128_with_scale(mantissa as i128, scale)
1537        } else {
1538            // Large mantissa — use string fallback
1539            let mut s = mantissa.to_string();
1540            if scale as usize >= s.len() {
1541                let zeros = scale as usize - s.len() + 1;
1542                s = format!("0.{}{s}", "0".repeat(zeros));
1543            } else {
1544                let dot_pos = s.len() - scale as usize;
1545                s.insert(dot_pos, '.');
1546            }
1547            s.parse::<rust_decimal::Decimal>()
1548                .map_err(|e| DriverError::Protocol(format!("numeric parse error: {e}")))?
1549        }
1550    };
1551
1552    if sign == 0x4000 {
1553        Ok(-result)
1554    } else {
1555        Ok(result)
1556    }
1557}
1558
1559#[cfg(test)]
1560#[allow(clippy::approx_constant)]
1561mod tests {
1562    use super::*;
1563
1564    // --- Encode round-trips ---
1565
1566    #[test]
1567    fn bool_roundtrip() {
1568        let mut buf = Vec::new();
1569        true.encode_binary(&mut buf);
1570        assert!(decode_bool(&buf).unwrap());
1571
1572        buf.clear();
1573        false.encode_binary(&mut buf);
1574        assert!(!decode_bool(&buf).unwrap());
1575    }
1576
1577    #[test]
1578    fn i16_roundtrip() {
1579        let mut buf = Vec::new();
1580        12345i16.encode_binary(&mut buf);
1581        assert_eq!(decode_i16(&buf).unwrap(), 12345);
1582
1583        buf.clear();
1584        (-1i16).encode_binary(&mut buf);
1585        assert_eq!(decode_i16(&buf).unwrap(), -1);
1586
1587        buf.clear();
1588        i16::MIN.encode_binary(&mut buf);
1589        assert_eq!(decode_i16(&buf).unwrap(), i16::MIN);
1590
1591        buf.clear();
1592        i16::MAX.encode_binary(&mut buf);
1593        assert_eq!(decode_i16(&buf).unwrap(), i16::MAX);
1594    }
1595
1596    #[test]
1597    fn i32_roundtrip() {
1598        let mut buf = Vec::new();
1599        42i32.encode_binary(&mut buf);
1600        assert_eq!(buf, &[0, 0, 0, 42]);
1601        assert_eq!(decode_i32(&buf).unwrap(), 42);
1602
1603        buf.clear();
1604        i32::MAX.encode_binary(&mut buf);
1605        assert_eq!(decode_i32(&buf).unwrap(), i32::MAX);
1606
1607        buf.clear();
1608        i32::MIN.encode_binary(&mut buf);
1609        assert_eq!(decode_i32(&buf).unwrap(), i32::MIN);
1610    }
1611
1612    #[test]
1613    fn i64_roundtrip() {
1614        let mut buf = Vec::new();
1615        1234567890123i64.encode_binary(&mut buf);
1616        assert_eq!(decode_i64(&buf).unwrap(), 1234567890123);
1617    }
1618
1619    #[test]
1620    fn f32_roundtrip() {
1621        let mut buf = Vec::new();
1622        3.14f32.encode_binary(&mut buf);
1623        let decoded = decode_f32(&buf).unwrap();
1624        assert!((decoded - 3.14).abs() < f32::EPSILON);
1625    }
1626
1627    #[test]
1628    fn f64_roundtrip() {
1629        let mut buf = Vec::new();
1630        std::f64::consts::PI.encode_binary(&mut buf);
1631        let decoded = decode_f64(&buf).unwrap();
1632        assert!((decoded - std::f64::consts::PI).abs() < f64::EPSILON);
1633    }
1634
1635    #[test]
1636    fn str_roundtrip() {
1637        let mut buf = Vec::new();
1638        "hello world".encode_binary(&mut buf);
1639        assert_eq!(decode_str(&buf).unwrap(), "hello world");
1640    }
1641
1642    #[test]
1643    fn string_roundtrip() {
1644        let mut buf = Vec::new();
1645        let s = String::from("test string");
1646        s.encode_binary(&mut buf);
1647        assert_eq!(decode_str(&buf).unwrap(), "test string");
1648    }
1649
1650    #[test]
1651    fn bytes_roundtrip() {
1652        let mut buf = Vec::new();
1653        let data: &[u8] = &[0xDE, 0xAD, 0xBE, 0xEF];
1654        data.encode_binary(&mut buf);
1655        assert_eq!(decode_bytes(&buf), data);
1656    }
1657
1658    #[test]
1659    fn vec_u8_roundtrip() {
1660        let mut buf = Vec::new();
1661        let data = vec![1u8, 2, 3, 4, 5];
1662        data.encode_binary(&mut buf);
1663        assert_eq!(decode_bytes(&buf), &[1, 2, 3, 4, 5]);
1664    }
1665
1666    #[test]
1667    fn u32_encode() {
1668        let mut buf = Vec::new();
1669        42u32.encode_binary(&mut buf);
1670        assert_eq!(buf, &[0, 0, 0, 42]);
1671    }
1672
1673    #[test]
1674    fn uuid_roundtrip() {
1675        let uuid_bytes: [u8; 16] = [
1676            0x55, 0x0e, 0x84, 0x00, 0xe2, 0x9b, 0x41, 0xd4, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44,
1677            0x00, 0x00,
1678        ];
1679        let decoded = decode_uuid(&uuid_bytes).unwrap();
1680        assert_eq!(decoded, uuid_bytes);
1681    }
1682
1683    // --- Error cases ---
1684
1685    #[test]
1686    fn decode_bool_wrong_length() {
1687        assert!(decode_bool(&[]).is_err());
1688        assert!(decode_bool(&[0, 0]).is_err());
1689    }
1690
1691    #[test]
1692    fn decode_i32_wrong_length() {
1693        assert!(decode_i32(&[0, 0, 0]).is_err());
1694        assert!(decode_i32(&[0, 0, 0, 0, 0]).is_err());
1695    }
1696
1697    #[test]
1698    fn decode_i64_wrong_length() {
1699        assert!(decode_i64(&[0; 7]).is_err());
1700        assert!(decode_i64(&[0; 9]).is_err());
1701    }
1702
1703    #[test]
1704    fn decode_f32_wrong_length() {
1705        assert!(decode_f32(&[0; 3]).is_err());
1706    }
1707
1708    #[test]
1709    fn decode_f64_wrong_length() {
1710        assert!(decode_f64(&[0; 7]).is_err());
1711    }
1712
1713    #[test]
1714    fn decode_str_invalid_utf8() {
1715        assert!(decode_str(&[0xFF, 0xFE]).is_err());
1716    }
1717
1718    #[test]
1719    fn decode_uuid_wrong_length() {
1720        assert!(decode_uuid(&[0; 15]).is_err());
1721        assert!(decode_uuid(&[0; 17]).is_err());
1722    }
1723
1724    #[test]
1725    fn empty_str_decode() {
1726        assert_eq!(decode_str(&[]).unwrap(), "");
1727    }
1728
1729    #[test]
1730    fn empty_bytes_decode() {
1731        assert_eq!(decode_bytes(&[]).len(), 0);
1732    }
1733
1734    // --- Type OIDs ---
1735
1736    #[test]
1737    fn type_oids_correct() {
1738        assert_eq!(true.type_oid(), 16);
1739        assert_eq!(0i16.type_oid(), 21);
1740        assert_eq!(0i32.type_oid(), 23);
1741        assert_eq!(0i64.type_oid(), 20);
1742        assert_eq!(0f32.type_oid(), 700);
1743        assert_eq!(0f64.type_oid(), 701);
1744        assert_eq!("".type_oid(), 25);
1745        assert_eq!(String::new().type_oid(), 25);
1746        let b: &[u8] = &[];
1747        assert_eq!(b.type_oid(), 17);
1748        assert_eq!(Vec::<u8>::new().type_oid(), 17);
1749        assert_eq!(0u32.type_oid(), 26);
1750    }
1751
1752    // --- Encode param with length prefix ---
1753
1754    #[test]
1755    fn encode_param_i32() {
1756        let mut buf = Vec::new();
1757        encode_param(&mut buf, &42i32);
1758        // 4 bytes length (=4) + 4 bytes data
1759        assert_eq!(buf.len(), 8);
1760        let len = i32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
1761        assert_eq!(len, 4);
1762        let val = i32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]);
1763        assert_eq!(val, 42);
1764    }
1765
1766    #[test]
1767    fn encode_param_str() {
1768        let mut buf = Vec::new();
1769        encode_param(&mut buf, &"hello");
1770        // 4 bytes length (=5) + 5 bytes data
1771        assert_eq!(buf.len(), 9);
1772        let len = i32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
1773        assert_eq!(len, 5);
1774        assert_eq!(&buf[4..], b"hello");
1775    }
1776
1777    #[test]
1778    fn option_none_is_null() {
1779        let val: Option<i32> = None;
1780        assert!(val.is_null());
1781        assert_eq!(val.type_oid(), 0);
1782    }
1783
1784    #[test]
1785    fn option_some_encodes() {
1786        let val: Option<i32> = Some(42);
1787        assert!(!val.is_null());
1788        assert_eq!(val.type_oid(), 23);
1789        let mut buf = Vec::new();
1790        val.encode_binary(&mut buf);
1791        assert_eq!(buf, &[0, 0, 0, 42]);
1792    }
1793
1794    #[test]
1795    fn option_none_encode_is_noop() {
1796        let val: Option<i32> = None;
1797        let mut buf = Vec::new();
1798        val.encode_binary(&mut buf);
1799        assert!(buf.is_empty(), "None encode should produce no bytes");
1800    }
1801
1802    // --- Audit gap tests ---
1803
1804    // #1: decode_i16 wrong length
1805    #[test]
1806    fn decode_i16_wrong_length() {
1807        assert!(decode_i16(&[]).is_err());
1808        assert!(decode_i16(&[0]).is_err());
1809        assert!(decode_i16(&[0, 0, 0]).is_err());
1810    }
1811
1812    // #2: f32 NaN roundtrip
1813    #[test]
1814    fn f32_nan_roundtrip() {
1815        let mut buf = Vec::new();
1816        f32::NAN.encode_binary(&mut buf);
1817        let decoded = decode_f32(&buf).unwrap();
1818        assert!(decoded.is_nan(), "NaN should survive roundtrip");
1819    }
1820
1821    // #2: f64 NaN roundtrip
1822    #[test]
1823    fn f64_nan_roundtrip() {
1824        let mut buf = Vec::new();
1825        f64::NAN.encode_binary(&mut buf);
1826        let decoded = decode_f64(&buf).unwrap();
1827        assert!(decoded.is_nan(), "NaN should survive roundtrip");
1828    }
1829
1830    // #3: f32 +Infinity/-Infinity roundtrip
1831    #[test]
1832    fn f32_infinity_roundtrip() {
1833        let mut buf = Vec::new();
1834        f32::INFINITY.encode_binary(&mut buf);
1835        assert_eq!(decode_f32(&buf).unwrap(), f32::INFINITY);
1836
1837        buf.clear();
1838        f32::NEG_INFINITY.encode_binary(&mut buf);
1839        assert_eq!(decode_f32(&buf).unwrap(), f32::NEG_INFINITY);
1840    }
1841
1842    // #3: f64 +Infinity/-Infinity roundtrip
1843    #[test]
1844    fn f64_infinity_roundtrip() {
1845        let mut buf = Vec::new();
1846        f64::INFINITY.encode_binary(&mut buf);
1847        assert_eq!(decode_f64(&buf).unwrap(), f64::INFINITY);
1848
1849        buf.clear();
1850        f64::NEG_INFINITY.encode_binary(&mut buf);
1851        assert_eq!(decode_f64(&buf).unwrap(), f64::NEG_INFINITY);
1852    }
1853
1854    // #4: f32 +0.0 vs -0.0 bit-pattern preservation
1855    #[test]
1856    fn f32_signed_zero_roundtrip() {
1857        let mut buf = Vec::new();
1858        0.0f32.encode_binary(&mut buf);
1859        let decoded = decode_f32(&buf).unwrap();
1860        assert_eq!(decoded.to_bits(), 0.0f32.to_bits(), "+0.0 bits must match");
1861
1862        buf.clear();
1863        (-0.0f32).encode_binary(&mut buf);
1864        let decoded = decode_f32(&buf).unwrap();
1865        assert_eq!(
1866            decoded.to_bits(),
1867            (-0.0f32).to_bits(),
1868            "-0.0 bits must match"
1869        );
1870    }
1871
1872    // #4: f64 +0.0 vs -0.0 bit-pattern preservation
1873    #[test]
1874    fn f64_signed_zero_roundtrip() {
1875        let mut buf = Vec::new();
1876        0.0f64.encode_binary(&mut buf);
1877        let decoded = decode_f64(&buf).unwrap();
1878        assert_eq!(decoded.to_bits(), 0.0f64.to_bits(), "+0.0 bits must match");
1879
1880        buf.clear();
1881        (-0.0f64).encode_binary(&mut buf);
1882        let decoded = decode_f64(&buf).unwrap();
1883        assert_eq!(
1884            decoded.to_bits(),
1885            (-0.0f64).to_bits(),
1886            "-0.0 bits must match"
1887        );
1888    }
1889
1890    // #5: i64 boundary values
1891    #[test]
1892    fn i64_boundary_roundtrip() {
1893        let mut buf = Vec::new();
1894        i64::MIN.encode_binary(&mut buf);
1895        assert_eq!(decode_i64(&buf).unwrap(), i64::MIN);
1896
1897        buf.clear();
1898        i64::MAX.encode_binary(&mut buf);
1899        assert_eq!(decode_i64(&buf).unwrap(), i64::MAX);
1900    }
1901
1902    // #6: i16 boundary values (already partially tested, ensuring completeness)
1903    #[test]
1904    fn i16_boundary_standalone() {
1905        let mut buf = Vec::new();
1906        i16::MIN.encode_binary(&mut buf);
1907        assert_eq!(decode_i16(&buf).unwrap(), i16::MIN);
1908
1909        buf.clear();
1910        i16::MAX.encode_binary(&mut buf);
1911        assert_eq!(decode_i16(&buf).unwrap(), i16::MAX);
1912    }
1913
1914    // #7: decode_date_chrono negative days (dates before 2000-01-01)
1915    #[cfg(feature = "chrono")]
1916    #[test]
1917    fn decode_date_chrono_negative_days() {
1918        // -365 days from PG epoch = 1999-01-01
1919        let data = (-365i32).to_be_bytes();
1920        let date = decode_date_chrono(&data).unwrap();
1921        assert_eq!(date, chrono::NaiveDate::from_ymd_opt(1999, 1, 1).unwrap());
1922    }
1923
1924    // #8: decode_date_chrono day=0 (exactly 2000-01-01)
1925    #[cfg(feature = "chrono")]
1926    #[test]
1927    fn decode_date_chrono_day_zero() {
1928        let data = 0i32.to_be_bytes();
1929        let date = decode_date_chrono(&data).unwrap();
1930        assert_eq!(date, chrono::NaiveDate::from_ymd_opt(2000, 1, 1).unwrap());
1931    }
1932
1933    // #9: decode_date_time negative days
1934    #[cfg(feature = "time")]
1935    #[test]
1936    fn decode_date_time_negative_days() {
1937        let data = (-1i32).to_be_bytes();
1938        let date = decode_date_time(&data).unwrap();
1939        let expected = time::Date::from_calendar_date(1999, time::Month::December, 31).unwrap();
1940        assert_eq!(date, expected);
1941    }
1942
1943    // #10: decode_time_time midnight (0 microseconds)
1944    #[cfg(feature = "time")]
1945    #[test]
1946    fn decode_time_time_midnight() {
1947        let data = 0i64.to_be_bytes();
1948        let t = decode_time_time(&data).unwrap();
1949        assert_eq!(t, time::Time::MIDNIGHT);
1950    }
1951
1952    // #11: decode_time_time max (23:59:59.999999)
1953    #[cfg(feature = "time")]
1954    #[test]
1955    fn decode_time_time_max_value() {
1956        let micros: i64 = 86_400_000_000 - 1; // 23:59:59.999999
1957        let data = micros.to_be_bytes();
1958        let t = decode_time_time(&data).unwrap();
1959        assert_eq!(t.hour(), 23);
1960        assert_eq!(t.minute(), 59);
1961        assert_eq!(t.second(), 59);
1962        assert_eq!(t.microsecond(), 999999);
1963    }
1964
1965    // #12: decode_time_time negative microseconds
1966    #[cfg(feature = "time")]
1967    #[test]
1968    fn decode_time_time_negative_micros_error() {
1969        let data = (-1i64).to_be_bytes();
1970        let result = decode_time_time(&data);
1971        assert!(result.is_err(), "negative microseconds should error");
1972    }
1973
1974    // #13: decode_time_time >= 86400000000
1975    #[cfg(feature = "time")]
1976    #[test]
1977    fn decode_time_time_overflow_error() {
1978        let data = 86_400_000_000i64.to_be_bytes();
1979        let result = decode_time_time(&data);
1980        assert!(result.is_err(), ">= 24h microseconds should error");
1981    }
1982
1983    // #14: decode_timestamptz_time PG epoch
1984    #[cfg(feature = "time")]
1985    #[test]
1986    fn decode_timestamptz_time_pg_epoch() {
1987        let data = 0i64.to_be_bytes();
1988        let dt = decode_timestamptz_time(&data).unwrap();
1989        // PG epoch is 2000-01-01 00:00:00 UTC
1990        assert_eq!(dt.year(), 2000);
1991        assert_eq!(dt.month(), time::Month::January);
1992        assert_eq!(dt.day(), 1);
1993        assert_eq!(dt.hour(), 0);
1994        assert_eq!(dt.minute(), 0);
1995        assert_eq!(dt.second(), 0);
1996    }
1997
1998    // #15: decode_numeric_decimal zero
1999    #[cfg(feature = "decimal")]
2000    #[test]
2001    fn decode_numeric_decimal_zero() {
2002        // PG numeric zero: ndigits=0, weight=0, sign=0, dscale=0
2003        let mut data = Vec::new();
2004        data.extend_from_slice(&0i16.to_be_bytes()); // ndigits
2005        data.extend_from_slice(&0i16.to_be_bytes()); // weight
2006        data.extend_from_slice(&0i16.to_be_bytes()); // sign
2007        data.extend_from_slice(&0i16.to_be_bytes()); // dscale
2008        let dec = decode_numeric_decimal(&data).unwrap();
2009        assert!(dec.is_zero());
2010    }
2011
2012    // #16: decode_numeric_decimal negative
2013    #[cfg(feature = "decimal")]
2014    #[test]
2015    fn decode_numeric_decimal_negative() {
2016        // -42: ndigits=1, weight=0, sign=0x4000, dscale=0, digit=42
2017        let mut data = Vec::new();
2018        data.extend_from_slice(&1i16.to_be_bytes()); // ndigits=1
2019        data.extend_from_slice(&0i16.to_be_bytes()); // weight=0
2020        data.extend_from_slice(&0x4000i16.to_be_bytes()); // sign=negative
2021        data.extend_from_slice(&0i16.to_be_bytes()); // dscale=0
2022        data.extend_from_slice(&42i16.to_be_bytes()); // digit=42
2023        let dec = decode_numeric_decimal(&data).unwrap();
2024        assert_eq!(dec, rust_decimal::Decimal::new(-42, 0));
2025    }
2026
2027    // #17: decode_numeric_decimal pure fractional (0.001)
2028    #[cfg(feature = "decimal")]
2029    #[test]
2030    fn decode_numeric_decimal_pure_fractional() {
2031        // 0.001: ndigits=1, weight=-1, sign=0, dscale=3, digit=1000
2032        // The digit 1000 at weight=-1 means 1000 * 10^(-4) = 0.1
2033        // Actually: 0.001 = 1 * 10^(-3). In PG format: weight=-1, digit=10
2034        // PG base-10000: weight=-1, digit=10 -> 10 * 10^(-4) = 0.001
2035        let mut data = Vec::new();
2036        data.extend_from_slice(&1i16.to_be_bytes()); // ndigits=1
2037        data.extend_from_slice(&(-1i16).to_be_bytes()); // weight=-1
2038        data.extend_from_slice(&0i16.to_be_bytes()); // sign=positive
2039        data.extend_from_slice(&3i16.to_be_bytes()); // dscale=3
2040        data.extend_from_slice(&10i16.to_be_bytes()); // digit=10 -> 10/10000 = 0.001
2041        let dec = decode_numeric_decimal(&data).unwrap();
2042        // rust_decimal preserves trailing zeros from dscale, normalize to compare value
2043        let dec_normalized = dec.normalize();
2044        assert_eq!(dec_normalized.to_string(), "0.001");
2045    }
2046
2047    // #18: decode_array_elements empty (ndim=0)
2048    #[test]
2049    fn decode_array_empty() {
2050        // ndim=0 means empty array
2051        let mut data = Vec::new();
2052        data.extend_from_slice(&0i32.to_be_bytes()); // ndim=0
2053        data.extend_from_slice(&0i32.to_be_bytes()); // has_null
2054        data.extend_from_slice(&23i32.to_be_bytes()); // element OID (int4)
2055        let elems = decode_array_i32(&data).unwrap();
2056        assert!(elems.is_empty());
2057    }
2058
2059    // #19: decode_array_elements multi-dimensional error
2060    #[test]
2061    fn decode_array_multidim_error() {
2062        let mut data = Vec::new();
2063        data.extend_from_slice(&2i32.to_be_bytes()); // ndim=2
2064        data.extend_from_slice(&0i32.to_be_bytes()); // has_null
2065        data.extend_from_slice(&23i32.to_be_bytes()); // element OID
2066        // Add enough fake dimension data
2067        data.extend_from_slice(&0i32.to_be_bytes());
2068        data.extend_from_slice(&0i32.to_be_bytes());
2069        data.extend_from_slice(&0i32.to_be_bytes());
2070        data.extend_from_slice(&0i32.to_be_bytes());
2071        let result = decode_array_i32(&data);
2072        assert!(result.is_err(), "multi-dimensional should error");
2073    }
2074
2075    // #20: decode_array_elements truncated data
2076    #[test]
2077    fn decode_array_truncated_error() {
2078        // Header says 1 element but data is cut short
2079        let mut data = Vec::new();
2080        data.extend_from_slice(&1i32.to_be_bytes()); // ndim=1
2081        data.extend_from_slice(&0i32.to_be_bytes()); // has_null
2082        data.extend_from_slice(&23i32.to_be_bytes()); // elem OID
2083        data.extend_from_slice(&1i32.to_be_bytes()); // n_elements=1
2084        data.extend_from_slice(&1i32.to_be_bytes()); // lower_bound
2085        // Missing element data
2086        let result = decode_array_i32(&data);
2087        assert!(result.is_err(), "truncated array should error");
2088    }
2089
2090    // #21: Option<T> encode: Some(42i32) -> non-null data
2091    #[test]
2092    fn option_some_i32_produces_data() {
2093        let val: Option<i32> = Some(42);
2094        assert!(!val.is_null());
2095        let mut buf = Vec::new();
2096        val.encode_binary(&mut buf);
2097        assert_eq!(decode_i32(&buf).unwrap(), 42);
2098    }
2099
2100    // #22: Option<T> encode: None::<i32> -> is_null()
2101    #[test]
2102    fn option_none_i32_is_null() {
2103        let val: Option<i32> = None;
2104        assert!(val.is_null());
2105        let mut buf = Vec::new();
2106        val.encode_binary(&mut buf);
2107        assert!(buf.is_empty());
2108    }
2109
2110    // #23: Empty string encode/decode
2111    #[test]
2112    fn empty_string_encode_decode() {
2113        let mut buf = Vec::new();
2114        "".encode_binary(&mut buf);
2115        assert!(buf.is_empty());
2116        assert_eq!(decode_str(&buf).unwrap(), "");
2117
2118        buf.clear();
2119        String::new().encode_binary(&mut buf);
2120        assert!(buf.is_empty());
2121        assert_eq!(decode_str(&buf).unwrap(), "");
2122    }
2123
2124    // #24: Empty bytes encode/decode
2125    #[test]
2126    fn empty_bytes_encode_decode() {
2127        let mut buf = Vec::new();
2128        let empty: &[u8] = &[];
2129        empty.encode_binary(&mut buf);
2130        assert!(buf.is_empty());
2131        assert_eq!(decode_bytes(&buf).len(), 0);
2132
2133        buf.clear();
2134        Vec::<u8>::new().encode_binary(&mut buf);
2135        assert!(buf.is_empty());
2136    }
2137
2138    // #25: Large string (1MB) encode/decode
2139    #[test]
2140    fn large_string_encode_decode() {
2141        let big = "x".repeat(1_000_000);
2142        let mut buf = Vec::new();
2143        big.as_str().encode_binary(&mut buf);
2144        assert_eq!(buf.len(), 1_000_000);
2145        assert_eq!(decode_str(&buf).unwrap(), big);
2146    }
2147
2148    // #26: UUID nil (all zeros)
2149    #[test]
2150    fn uuid_nil() {
2151        let nil = [0u8; 16];
2152        let decoded = decode_uuid(&nil).unwrap();
2153        assert_eq!(decoded, [0u8; 16]);
2154    }
2155
2156    // #27: UUID max (all 0xFF)
2157    #[test]
2158    fn uuid_max() {
2159        let max = [0xFF; 16];
2160        let decoded = decode_uuid(&max).unwrap();
2161        assert_eq!(decoded, [0xFF; 16]);
2162    }
2163
2164    // #26/#27 with uuid feature: uuid::Uuid nil and max
2165    #[cfg(feature = "uuid")]
2166    #[test]
2167    fn uuid_type_nil_and_max() {
2168        let nil = [0u8; 16];
2169        let uuid = decode_uuid_type(&nil).unwrap();
2170        assert_eq!(uuid, uuid::Uuid::nil());
2171
2172        let max = [0xFF; 16];
2173        let uuid = decode_uuid_type(&max).unwrap();
2174        assert_eq!(uuid, uuid::Uuid::max());
2175    }
2176
2177    // --- Array encode tests ---
2178
2179    // Array encode: bool
2180    #[test]
2181    fn encode_array_bool_empty() {
2182        let arr: &[bool] = &[];
2183        let mut buf = Vec::new();
2184        arr.encode_binary(&mut buf);
2185        let decoded = decode_array_bool(&buf).unwrap();
2186        assert!(decoded.is_empty());
2187    }
2188
2189    #[test]
2190    fn encode_array_bool_single() {
2191        let arr: &[bool] = &[true];
2192        let mut buf = Vec::new();
2193        arr.encode_binary(&mut buf);
2194        let decoded = decode_array_bool(&buf).unwrap();
2195        assert_eq!(decoded, vec![true]);
2196    }
2197
2198    #[test]
2199    fn encode_array_bool_multi() {
2200        let arr: &[bool] = &[true, false, true, false];
2201        let mut buf = Vec::new();
2202        arr.encode_binary(&mut buf);
2203        let decoded = decode_array_bool(&buf).unwrap();
2204        assert_eq!(decoded, vec![true, false, true, false]);
2205    }
2206
2207    #[test]
2208    fn encode_array_bool_vec_delegate() {
2209        let v = vec![false, true];
2210        let mut buf = Vec::new();
2211        v.encode_binary(&mut buf);
2212        let decoded = decode_array_bool(&buf).unwrap();
2213        assert_eq!(decoded, vec![false, true]);
2214        assert_eq!(v.type_oid(), 1000);
2215    }
2216
2217    // Array encode: i16
2218    #[test]
2219    fn encode_array_i16_empty() {
2220        let arr: &[i16] = &[];
2221        let mut buf = Vec::new();
2222        arr.encode_binary(&mut buf);
2223        let decoded = decode_array_i16(&buf).unwrap();
2224        assert!(decoded.is_empty());
2225    }
2226
2227    #[test]
2228    fn encode_array_i16_single() {
2229        let arr: &[i16] = &[42];
2230        let mut buf = Vec::new();
2231        arr.encode_binary(&mut buf);
2232        let decoded = decode_array_i16(&buf).unwrap();
2233        assert_eq!(decoded, vec![42i16]);
2234    }
2235
2236    #[test]
2237    fn encode_array_i16_multi_boundary() {
2238        let arr: &[i16] = &[i16::MIN, -1, 0, 1, i16::MAX];
2239        let mut buf = Vec::new();
2240        arr.encode_binary(&mut buf);
2241        let decoded = decode_array_i16(&buf).unwrap();
2242        assert_eq!(decoded, vec![i16::MIN, -1, 0, 1, i16::MAX]);
2243    }
2244
2245    #[test]
2246    fn encode_array_i16_vec_delegate() {
2247        let v = vec![100i16, 200];
2248        let mut buf = Vec::new();
2249        v.encode_binary(&mut buf);
2250        let decoded = decode_array_i16(&buf).unwrap();
2251        assert_eq!(decoded, vec![100i16, 200]);
2252        assert_eq!(v.type_oid(), 1005);
2253    }
2254
2255    // Array encode: i32
2256    #[test]
2257    fn encode_array_i32_empty() {
2258        let arr: &[i32] = &[];
2259        let mut buf = Vec::new();
2260        arr.encode_binary(&mut buf);
2261        let decoded = decode_array_i32(&buf).unwrap();
2262        assert!(decoded.is_empty());
2263    }
2264
2265    #[test]
2266    fn encode_array_i32_single() {
2267        let arr: &[i32] = &[42];
2268        let mut buf = Vec::new();
2269        arr.encode_binary(&mut buf);
2270        let decoded = decode_array_i32(&buf).unwrap();
2271        assert_eq!(decoded, vec![42]);
2272    }
2273
2274    #[test]
2275    fn encode_array_i32_multi_boundary() {
2276        let arr: &[i32] = &[i32::MIN, -1, 0, 1, i32::MAX];
2277        let mut buf = Vec::new();
2278        arr.encode_binary(&mut buf);
2279        let decoded = decode_array_i32(&buf).unwrap();
2280        assert_eq!(decoded, vec![i32::MIN, -1, 0, 1, i32::MAX]);
2281    }
2282
2283    #[test]
2284    fn encode_array_i32_vec_delegate() {
2285        let v = vec![10, 20, 30];
2286        let mut buf = Vec::new();
2287        v.encode_binary(&mut buf);
2288        let decoded = decode_array_i32(&buf).unwrap();
2289        assert_eq!(decoded, vec![10, 20, 30]);
2290        assert_eq!(v.type_oid(), 1007);
2291    }
2292
2293    // Array encode: i64
2294    #[test]
2295    fn encode_array_i64_empty() {
2296        let arr: &[i64] = &[];
2297        let mut buf = Vec::new();
2298        arr.encode_binary(&mut buf);
2299        let decoded = decode_array_i64(&buf).unwrap();
2300        assert!(decoded.is_empty());
2301    }
2302
2303    #[test]
2304    fn encode_array_i64_single() {
2305        let arr: &[i64] = &[9999999999i64];
2306        let mut buf = Vec::new();
2307        arr.encode_binary(&mut buf);
2308        let decoded = decode_array_i64(&buf).unwrap();
2309        assert_eq!(decoded, vec![9999999999i64]);
2310    }
2311
2312    #[test]
2313    fn encode_array_i64_multi_boundary() {
2314        let arr: &[i64] = &[i64::MIN, -1, 0, 1, i64::MAX];
2315        let mut buf = Vec::new();
2316        arr.encode_binary(&mut buf);
2317        let decoded = decode_array_i64(&buf).unwrap();
2318        assert_eq!(decoded, vec![i64::MIN, -1, 0, 1, i64::MAX]);
2319    }
2320
2321    #[test]
2322    fn encode_array_i64_vec_delegate() {
2323        let v = vec![1i64, 2, 3];
2324        let mut buf = Vec::new();
2325        v.encode_binary(&mut buf);
2326        let decoded = decode_array_i64(&buf).unwrap();
2327        assert_eq!(decoded, vec![1i64, 2, 3]);
2328        assert_eq!(v.type_oid(), 1016);
2329    }
2330
2331    // Array encode: f32
2332    #[test]
2333    fn encode_array_f32_empty() {
2334        let arr: &[f32] = &[];
2335        let mut buf = Vec::new();
2336        arr.encode_binary(&mut buf);
2337        let decoded = decode_array_f32(&buf).unwrap();
2338        assert!(decoded.is_empty());
2339    }
2340
2341    #[test]
2342    fn encode_array_f32_single() {
2343        let arr: &[f32] = &[3.14];
2344        let mut buf = Vec::new();
2345        arr.encode_binary(&mut buf);
2346        let decoded = decode_array_f32(&buf).unwrap();
2347        assert!((decoded[0] - 3.14).abs() < f32::EPSILON);
2348    }
2349
2350    #[test]
2351    fn encode_array_f32_multi_boundary() {
2352        let arr: &[f32] = &[
2353            f32::MIN,
2354            -0.0,
2355            0.0,
2356            f32::MAX,
2357            f32::INFINITY,
2358            f32::NEG_INFINITY,
2359        ];
2360        let mut buf = Vec::new();
2361        arr.encode_binary(&mut buf);
2362        let decoded = decode_array_f32(&buf).unwrap();
2363        assert_eq!(decoded[0], f32::MIN);
2364        assert_eq!(decoded[1].to_bits(), (-0.0f32).to_bits());
2365        assert_eq!(decoded[2].to_bits(), 0.0f32.to_bits());
2366        assert_eq!(decoded[3], f32::MAX);
2367        assert_eq!(decoded[4], f32::INFINITY);
2368        assert_eq!(decoded[5], f32::NEG_INFINITY);
2369    }
2370
2371    #[test]
2372    fn encode_array_f32_vec_delegate() {
2373        let v = vec![1.0f32, 2.0];
2374        let mut buf = Vec::new();
2375        v.encode_binary(&mut buf);
2376        let decoded = decode_array_f32(&buf).unwrap();
2377        assert_eq!(decoded, vec![1.0f32, 2.0]);
2378        assert_eq!(v.type_oid(), 1021);
2379    }
2380
2381    // Array encode: f64
2382    #[test]
2383    fn encode_array_f64_empty() {
2384        let arr: &[f64] = &[];
2385        let mut buf = Vec::new();
2386        arr.encode_binary(&mut buf);
2387        let decoded = decode_array_f64(&buf).unwrap();
2388        assert!(decoded.is_empty());
2389    }
2390
2391    #[test]
2392    fn encode_array_f64_single() {
2393        let arr: &[f64] = &[std::f64::consts::PI];
2394        let mut buf = Vec::new();
2395        arr.encode_binary(&mut buf);
2396        let decoded = decode_array_f64(&buf).unwrap();
2397        assert!((decoded[0] - std::f64::consts::PI).abs() < f64::EPSILON);
2398    }
2399
2400    #[test]
2401    fn encode_array_f64_multi_boundary() {
2402        let arr: &[f64] = &[
2403            f64::MIN,
2404            -0.0,
2405            0.0,
2406            f64::MAX,
2407            f64::INFINITY,
2408            f64::NEG_INFINITY,
2409        ];
2410        let mut buf = Vec::new();
2411        arr.encode_binary(&mut buf);
2412        let decoded = decode_array_f64(&buf).unwrap();
2413        assert_eq!(decoded[0], f64::MIN);
2414        assert_eq!(decoded[1].to_bits(), (-0.0f64).to_bits());
2415        assert_eq!(decoded[2].to_bits(), 0.0f64.to_bits());
2416        assert_eq!(decoded[3], f64::MAX);
2417        assert_eq!(decoded[4], f64::INFINITY);
2418        assert_eq!(decoded[5], f64::NEG_INFINITY);
2419    }
2420
2421    #[test]
2422    fn encode_array_f64_vec_delegate() {
2423        let v = vec![1.0f64, 2.0];
2424        let mut buf = Vec::new();
2425        v.encode_binary(&mut buf);
2426        let decoded = decode_array_f64(&buf).unwrap();
2427        assert_eq!(decoded, vec![1.0f64, 2.0]);
2428        assert_eq!(v.type_oid(), 1022);
2429    }
2430
2431    // Array encode: text (&[&str] and Vec<String>)
2432    #[test]
2433    fn encode_array_str_empty() {
2434        let arr: &[&str] = &[];
2435        let mut buf = Vec::new();
2436        arr.encode_binary(&mut buf);
2437        let decoded = decode_array_str(&buf).unwrap();
2438        assert!(decoded.is_empty());
2439    }
2440
2441    #[test]
2442    fn encode_array_str_single() {
2443        let arr: &[&str] = &["hello"];
2444        let mut buf = Vec::new();
2445        arr.encode_binary(&mut buf);
2446        let decoded = decode_array_str(&buf).unwrap();
2447        assert_eq!(decoded, vec!["hello".to_string()]);
2448    }
2449
2450    #[test]
2451    fn encode_array_str_multi() {
2452        let arr: &[&str] = &["hello", "", "world"];
2453        let mut buf = Vec::new();
2454        arr.encode_binary(&mut buf);
2455        let decoded = decode_array_str(&buf).unwrap();
2456        assert_eq!(
2457            decoded,
2458            vec!["hello".to_string(), "".to_string(), "world".to_string()]
2459        );
2460    }
2461
2462    #[test]
2463    fn encode_array_str_boundary_unicode() {
2464        let arr: &[&str] = &["\u{1F600}", "\u{00E9}"];
2465        let mut buf = Vec::new();
2466        arr.encode_binary(&mut buf);
2467        let decoded = decode_array_str(&buf).unwrap();
2468        assert_eq!(
2469            decoded,
2470            vec!["\u{1F600}".to_string(), "\u{00E9}".to_string()]
2471        );
2472    }
2473
2474    #[test]
2475    fn encode_array_vec_string() {
2476        let v = vec!["foo".to_string(), "bar".to_string()];
2477        let mut buf = Vec::new();
2478        v.encode_binary(&mut buf);
2479        let decoded = decode_array_str(&buf).unwrap();
2480        assert_eq!(decoded, vec!["foo".to_string(), "bar".to_string()]);
2481        assert_eq!(v.type_oid(), 1009);
2482    }
2483
2484    #[test]
2485    fn encode_array_vec_string_empty() {
2486        let v: Vec<String> = vec![];
2487        let mut buf = Vec::new();
2488        v.encode_binary(&mut buf);
2489        let decoded = decode_array_str(&buf).unwrap();
2490        assert!(decoded.is_empty());
2491    }
2492
2493    // Array encode: bytea (&[&[u8]] and Vec<Vec<u8>>)
2494    #[test]
2495    fn encode_array_bytea_empty() {
2496        let arr: &[&[u8]] = &[];
2497        let mut buf = Vec::new();
2498        arr.encode_binary(&mut buf);
2499        let decoded = decode_array_bytea(&buf).unwrap();
2500        assert!(decoded.is_empty());
2501    }
2502
2503    #[test]
2504    fn encode_array_bytea_single() {
2505        let data: &[u8] = &[0xDE, 0xAD];
2506        let arr: &[&[u8]] = &[data];
2507        let mut buf = Vec::new();
2508        arr.encode_binary(&mut buf);
2509        let decoded = decode_array_bytea(&buf).unwrap();
2510        assert_eq!(decoded, vec![vec![0xDE, 0xAD]]);
2511    }
2512
2513    #[test]
2514    fn encode_array_bytea_multi() {
2515        let a: &[u8] = &[1, 2, 3];
2516        let b: &[u8] = &[];
2517        let c: &[u8] = &[0xFF];
2518        let arr: &[&[u8]] = &[a, b, c];
2519        let mut buf = Vec::new();
2520        arr.encode_binary(&mut buf);
2521        let decoded = decode_array_bytea(&buf).unwrap();
2522        assert_eq!(decoded, vec![vec![1, 2, 3], vec![], vec![0xFF]]);
2523    }
2524
2525    #[test]
2526    fn encode_array_vec_vec_u8() {
2527        let v = vec![vec![10u8, 20], vec![30]];
2528        let mut buf = Vec::new();
2529        v.encode_binary(&mut buf);
2530        let decoded = decode_array_bytea(&buf).unwrap();
2531        assert_eq!(decoded, vec![vec![10u8, 20], vec![30]]);
2532        assert_eq!(v.type_oid(), 1001);
2533    }
2534
2535    #[test]
2536    fn encode_array_vec_vec_u8_empty() {
2537        let v: Vec<Vec<u8>> = vec![];
2538        let mut buf = Vec::new();
2539        v.encode_binary(&mut buf);
2540        let decoded = decode_array_bytea(&buf).unwrap();
2541        assert!(decoded.is_empty());
2542    }
2543
2544    // Array type OIDs
2545    #[test]
2546    fn array_type_oids_correct() {
2547        let b: &[bool] = &[];
2548        assert_eq!(b.type_oid(), 1000);
2549        let i2: &[i16] = &[];
2550        assert_eq!(i2.type_oid(), 1005);
2551        let i4: &[i32] = &[];
2552        assert_eq!(i4.type_oid(), 1007);
2553        let i8: &[i64] = &[];
2554        assert_eq!(i8.type_oid(), 1016);
2555        let f4: &[f32] = &[];
2556        assert_eq!(f4.type_oid(), 1021);
2557        let f8: &[f64] = &[];
2558        assert_eq!(f8.type_oid(), 1022);
2559        let t: &[&str] = &[];
2560        assert_eq!(t.type_oid(), 1009);
2561        let by: &[&[u8]] = &[];
2562        assert_eq!(by.type_oid(), 1001);
2563
2564        assert_eq!(Vec::<bool>::new().type_oid(), 1000);
2565        assert_eq!(Vec::<i16>::new().type_oid(), 1005);
2566        assert_eq!(Vec::<i32>::new().type_oid(), 1007);
2567        assert_eq!(Vec::<i64>::new().type_oid(), 1016);
2568        assert_eq!(Vec::<f32>::new().type_oid(), 1021);
2569        assert_eq!(Vec::<f64>::new().type_oid(), 1022);
2570        assert_eq!(Vec::<String>::new().type_oid(), 1009);
2571        assert_eq!(Vec::<Vec<u8>>::new().type_oid(), 1001);
2572    }
2573
2574    // Empty array header format: ndim=0
2575    #[test]
2576    fn encode_array_empty_ndim_zero() {
2577        let arr: &[i32] = &[];
2578        let mut buf = Vec::new();
2579        arr.encode_binary(&mut buf);
2580        // Empty array: ndim=0 (4 bytes), has_null=0 (4 bytes), elem_oid (4 bytes) = 12 bytes
2581        assert_eq!(buf.len(), 12);
2582        let ndim = i32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
2583        assert_eq!(ndim, 0, "empty array must have ndim=0");
2584        let elem_oid = i32::from_be_bytes([buf[8], buf[9], buf[10], buf[11]]);
2585        assert_eq!(
2586            elem_oid, 23,
2587            "element OID must be preserved for empty arrays"
2588        );
2589    }
2590
2591    // --- encode_at tests ---
2592
2593    #[test]
2594    fn encode_at_bool() {
2595        let mut dst = [0u8; 1];
2596        assert!(true.encode_at(&mut dst));
2597        assert_eq!(dst[0], 1);
2598        assert!(false.encode_at(&mut dst));
2599        assert_eq!(dst[0], 0);
2600        // Wrong size returns false.
2601        assert!(!true.encode_at(&mut [0u8; 2]));
2602    }
2603
2604    #[test]
2605    fn encode_at_i16() {
2606        let mut dst = [0u8; 2];
2607        assert!(0x1234i16.encode_at(&mut dst));
2608        assert_eq!(dst, [0x12, 0x34]);
2609        assert!(!42i16.encode_at(&mut [0u8; 4]));
2610    }
2611
2612    #[test]
2613    fn encode_at_i32() {
2614        let mut dst = [0u8; 4];
2615        assert!(42i32.encode_at(&mut dst));
2616        assert_eq!(dst, [0, 0, 0, 42]);
2617        assert!(!42i32.encode_at(&mut [0u8; 8]));
2618    }
2619
2620    #[test]
2621    fn encode_at_i64() {
2622        let mut dst = [0u8; 8];
2623        assert!(1234567890123i64.encode_at(&mut dst));
2624        assert_eq!(dst, 1234567890123i64.to_be_bytes());
2625        assert!(!42i64.encode_at(&mut [0u8; 4]));
2626    }
2627
2628    #[test]
2629    fn encode_at_f32() {
2630        let mut dst = [0u8; 4];
2631        assert!(3.14f32.encode_at(&mut dst));
2632        assert_eq!(dst, 3.14f32.to_be_bytes());
2633        assert!(!3.14f32.encode_at(&mut [0u8; 8]));
2634    }
2635
2636    #[test]
2637    fn encode_at_f64() {
2638        let mut dst = [0u8; 8];
2639        assert!(3.14f64.encode_at(&mut dst));
2640        assert_eq!(dst, 3.14f64.to_be_bytes());
2641        assert!(!3.14f64.encode_at(&mut [0u8; 4]));
2642    }
2643
2644    #[test]
2645    fn encode_at_u32() {
2646        let mut dst = [0u8; 4];
2647        assert!(42u32.encode_at(&mut dst));
2648        assert_eq!(dst, 42u32.to_be_bytes());
2649    }
2650
2651    #[test]
2652    fn encode_at_str_default_fallback() {
2653        // Variable-length types use the default encode_at fallback.
2654        let s: &str = "hello";
2655        let mut dst = [0u8; 5];
2656        assert!(s.encode_at(&mut dst));
2657        assert_eq!(&dst, b"hello");
2658        // Wrong size returns false.
2659        assert!(!s.encode_at(&mut [0u8; 3]));
2660    }
2661
2662    #[test]
2663    fn encode_at_matches_encode_binary() {
2664        // Verify encode_at produces identical bytes to encode_binary for all
2665        // fixed-size types.
2666        fn check<T: Encode>(val: T, expected_len: usize) {
2667            let mut buf = Vec::new();
2668            val.encode_binary(&mut buf);
2669            assert_eq!(buf.len(), expected_len);
2670            let mut dst = vec![0u8; expected_len];
2671            assert!(val.encode_at(&mut dst));
2672            assert_eq!(
2673                buf, dst,
2674                "encode_at must produce same bytes as encode_binary"
2675            );
2676        }
2677        check(true, 1);
2678        check(false, 1);
2679        check(42i16, 2);
2680        check(i16::MAX, 2);
2681        check(42i32, 4);
2682        check(i32::MIN, 4);
2683        check(42i64, 8);
2684        check(3.14f32, 4);
2685        check(3.14f64, 8);
2686        check(42u32, 4);
2687    }
2688
2689    // --- 10KB string encode/decode roundtrip ---
2690
2691    #[test]
2692    fn str_10kb_roundtrip() {
2693        let big = "A".repeat(10 * 1024);
2694        let mut buf = Vec::new();
2695        big.as_str().encode_binary(&mut buf);
2696        assert_eq!(buf.len(), 10 * 1024);
2697        assert_eq!(decode_str(&buf).unwrap(), big);
2698    }
2699
2700    // --- Empty Vec<u8> encode roundtrip ---
2701
2702    #[test]
2703    fn empty_vec_u8_encode_roundtrip() {
2704        let mut buf = Vec::new();
2705        Vec::<u8>::new().encode_binary(&mut buf);
2706        assert!(buf.is_empty(), "empty Vec<u8> should produce no bytes");
2707        assert_eq!(decode_bytes(&buf).len(), 0);
2708    }
2709
2710    // --- f32 MIN/MAX roundtrip ---
2711
2712    #[test]
2713    fn f32_min_max_roundtrip() {
2714        let mut buf = Vec::new();
2715        f32::MIN.encode_binary(&mut buf);
2716        assert_eq!(decode_f32(&buf).unwrap(), f32::MIN);
2717
2718        buf.clear();
2719        f32::MAX.encode_binary(&mut buf);
2720        assert_eq!(decode_f32(&buf).unwrap(), f32::MAX);
2721    }
2722
2723    // --- f64 MIN/MAX roundtrip ---
2724
2725    #[test]
2726    fn f64_min_max_roundtrip() {
2727        let mut buf = Vec::new();
2728        f64::MIN.encode_binary(&mut buf);
2729        assert_eq!(decode_f64(&buf).unwrap(), f64::MIN);
2730
2731        buf.clear();
2732        f64::MAX.encode_binary(&mut buf);
2733        assert_eq!(decode_f64(&buf).unwrap(), f64::MAX);
2734    }
2735
2736    // --- i32 zero roundtrip ---
2737
2738    #[test]
2739    fn i32_zero_roundtrip() {
2740        let mut buf = Vec::new();
2741        0i32.encode_binary(&mut buf);
2742        assert_eq!(decode_i32(&buf).unwrap(), 0);
2743    }
2744
2745    // --- i64 zero roundtrip ---
2746
2747    #[test]
2748    fn i64_zero_roundtrip() {
2749        let mut buf = Vec::new();
2750        0i64.encode_binary(&mut buf);
2751        assert_eq!(decode_i64(&buf).unwrap(), 0);
2752    }
2753
2754    // --- i16 zero roundtrip ---
2755
2756    #[test]
2757    fn i16_zero_roundtrip() {
2758        let mut buf = Vec::new();
2759        0i16.encode_binary(&mut buf);
2760        assert_eq!(decode_i16(&buf).unwrap(), 0);
2761    }
2762
2763    // --- f32 subnormal roundtrip ---
2764
2765    #[test]
2766    fn f32_subnormal_roundtrip() {
2767        let mut buf = Vec::new();
2768        f32::MIN_POSITIVE.encode_binary(&mut buf);
2769        assert_eq!(decode_f32(&buf).unwrap(), f32::MIN_POSITIVE);
2770    }
2771
2772    // --- f64 subnormal roundtrip ---
2773
2774    #[test]
2775    fn f64_subnormal_roundtrip() {
2776        let mut buf = Vec::new();
2777        f64::MIN_POSITIVE.encode_binary(&mut buf);
2778        assert_eq!(decode_f64(&buf).unwrap(), f64::MIN_POSITIVE);
2779    }
2780
2781    // --- f32 NaN bit-pattern preservation ---
2782
2783    #[test]
2784    fn f32_nan_bit_preservation() {
2785        let mut buf = Vec::new();
2786        f32::NAN.encode_binary(&mut buf);
2787        let decoded = decode_f32(&buf).unwrap();
2788        assert!(decoded.is_nan());
2789        // Bit-pattern should be preserved
2790        assert_eq!(decoded.to_bits(), f32::NAN.to_bits());
2791    }
2792
2793    // --- f64 NaN bit-pattern preservation ---
2794
2795    #[test]
2796    fn f64_nan_bit_preservation() {
2797        let mut buf = Vec::new();
2798        f64::NAN.encode_binary(&mut buf);
2799        let decoded = decode_f64(&buf).unwrap();
2800        assert!(decoded.is_nan());
2801        assert_eq!(decoded.to_bits(), f64::NAN.to_bits());
2802    }
2803}