Skip to main content

bsql_driver_postgres/
codec.rs

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