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