Skip to main content

bsql_driver_postgres/
codec.rs

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