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