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