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