1pub mod numeric;
6pub mod temporal;
7
8pub use numeric::Numeric;
9pub use temporal::{Date, Time, Timestamp};
10
11use crate::protocol::types::{decode_json, decode_jsonb, decode_text_array, decode_uuid, oid};
12
13#[derive(Debug, Clone)]
15pub enum TypeError {
16 UnexpectedOid {
18 expected: &'static str,
20 got: u32,
22 },
23 InvalidData(String),
25 UnexpectedNull,
27}
28
29impl std::fmt::Display for TypeError {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match self {
32 TypeError::UnexpectedOid { expected, got } => {
33 write!(f, "Expected {} type, got OID {}", expected, got)
34 }
35 TypeError::InvalidData(msg) => write!(f, "Invalid data: {}", msg),
36 TypeError::UnexpectedNull => write!(f, "Unexpected NULL value"),
37 }
38 }
39}
40
41impl std::error::Error for TypeError {}
42
43pub trait FromPg: Sized {
45 fn from_pg(bytes: &[u8], oid: u32, format: i16) -> Result<Self, TypeError>;
51}
52
53pub trait ToPg {
55 fn to_pg(&self) -> (Vec<u8>, u32, i16);
58}
59
60impl FromPg for String {
63 fn from_pg(bytes: &[u8], _oid: u32, _format: i16) -> Result<Self, TypeError> {
64 String::from_utf8(bytes.to_vec())
65 .map_err(|e| TypeError::InvalidData(format!("Invalid UTF-8: {}", e)))
66 }
67}
68
69impl ToPg for String {
70 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
71 (self.as_bytes().to_vec(), oid::TEXT, 0)
72 }
73}
74
75impl ToPg for &str {
76 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
77 (self.as_bytes().to_vec(), oid::TEXT, 0)
78 }
79}
80
81impl FromPg for i32 {
84 fn from_pg(bytes: &[u8], _oid: u32, format: i16) -> Result<Self, TypeError> {
85 if format == 1 {
86 if bytes.len() != 4 {
88 return Err(TypeError::InvalidData(
89 "Expected 4 bytes for i32".to_string(),
90 ));
91 }
92 Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
93 } else {
94 std::str::from_utf8(bytes)
96 .map_err(|e| TypeError::InvalidData(e.to_string()))?
97 .parse()
98 .map_err(|e| TypeError::InvalidData(format!("Invalid i32: {}", e)))
99 }
100 }
101}
102
103impl ToPg for i32 {
104 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
105 (self.to_be_bytes().to_vec(), oid::INT4, 1)
106 }
107}
108
109impl FromPg for i64 {
110 fn from_pg(bytes: &[u8], _oid: u32, format: i16) -> Result<Self, TypeError> {
111 if format == 1 {
112 if bytes.len() != 8 {
114 return Err(TypeError::InvalidData(
115 "Expected 8 bytes for i64".to_string(),
116 ));
117 }
118 Ok(i64::from_be_bytes([
119 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
120 ]))
121 } else {
122 std::str::from_utf8(bytes)
124 .map_err(|e| TypeError::InvalidData(e.to_string()))?
125 .parse()
126 .map_err(|e| TypeError::InvalidData(format!("Invalid i64: {}", e)))
127 }
128 }
129}
130
131impl ToPg for i64 {
132 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
133 (self.to_be_bytes().to_vec(), oid::INT8, 1)
134 }
135}
136
137impl FromPg for f64 {
140 fn from_pg(bytes: &[u8], _oid: u32, format: i16) -> Result<Self, TypeError> {
141 if format == 1 {
142 if bytes.len() != 8 {
144 return Err(TypeError::InvalidData(
145 "Expected 8 bytes for f64".to_string(),
146 ));
147 }
148 Ok(f64::from_be_bytes([
149 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
150 ]))
151 } else {
152 std::str::from_utf8(bytes)
154 .map_err(|e| TypeError::InvalidData(e.to_string()))?
155 .parse()
156 .map_err(|e| TypeError::InvalidData(format!("Invalid f64: {}", e)))
157 }
158 }
159}
160
161impl ToPg for f64 {
162 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
163 (self.to_be_bytes().to_vec(), oid::FLOAT8, 1)
164 }
165}
166
167impl FromPg for bool {
170 fn from_pg(bytes: &[u8], _oid: u32, format: i16) -> Result<Self, TypeError> {
171 if format == 1 {
172 Ok(bytes.first().map(|b| *b != 0).unwrap_or(false))
174 } else {
175 match bytes.first() {
177 Some(b't') | Some(b'T') | Some(b'1') => Ok(true),
178 Some(b'f') | Some(b'F') | Some(b'0') => Ok(false),
179 _ => Err(TypeError::InvalidData("Invalid boolean".to_string())),
180 }
181 }
182 }
183}
184
185impl ToPg for bool {
186 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
187 (vec![if *self { 1 } else { 0 }], oid::BOOL, 1)
188 }
189}
190
191#[derive(Debug, Clone, PartialEq)]
195pub struct Uuid(pub String);
196
197impl FromPg for Uuid {
198 fn from_pg(bytes: &[u8], oid_val: u32, format: i16) -> Result<Self, TypeError> {
199 if oid_val != oid::UUID {
200 return Err(TypeError::UnexpectedOid {
201 expected: "uuid",
202 got: oid_val,
203 });
204 }
205
206 if format == 1 && bytes.len() == 16 {
207 decode_uuid(bytes).map(Uuid).map_err(TypeError::InvalidData)
209 } else {
210 String::from_utf8(bytes.to_vec())
212 .map(Uuid)
213 .map_err(|e| TypeError::InvalidData(e.to_string()))
214 }
215 }
216}
217
218impl ToPg for Uuid {
219 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
220 (self.0.as_bytes().to_vec(), oid::UUID, 0)
222 }
223}
224
225fn from_utf8_string(bytes: &[u8]) -> Result<String, TypeError> {
228 std::str::from_utf8(bytes)
229 .map(|s| s.to_string())
230 .map_err(|e| TypeError::InvalidData(e.to_string()))
231}
232
233fn decode_inet_like_binary(bytes: &[u8], force_prefix: bool) -> Result<String, TypeError> {
234 if bytes.len() < 4 {
241 return Err(TypeError::InvalidData(
242 "inet/cidr binary payload too short".to_string(),
243 ));
244 }
245
246 let family = bytes[0];
247 let bits = bytes[1];
248 let is_cidr = bytes[2];
249 let addr_len = bytes[3] as usize;
250
251 if bytes.len() != 4 + addr_len {
252 return Err(TypeError::InvalidData(
253 "inet/cidr binary payload length mismatch".to_string(),
254 ));
255 }
256
257 let addr = &bytes[4..];
258 match family {
259 2 => {
260 if addr_len > 4 {
261 return Err(TypeError::InvalidData(
262 "invalid IPv4 inet/cidr address length".to_string(),
263 ));
264 }
265 let mut full = [0u8; 4];
266 full[..addr_len].copy_from_slice(addr);
267 let ip = std::net::Ipv4Addr::from(full);
268 let include_prefix = force_prefix || is_cidr != 0 || bits != 32;
269 if include_prefix {
270 Ok(format!("{}/{}", ip, bits))
271 } else {
272 Ok(ip.to_string())
273 }
274 }
275 3 => {
276 if addr_len > 16 {
277 return Err(TypeError::InvalidData(
278 "invalid IPv6 inet/cidr address length".to_string(),
279 ));
280 }
281 let mut full = [0u8; 16];
282 full[..addr_len].copy_from_slice(addr);
283 let ip = std::net::Ipv6Addr::from(full);
284 let include_prefix = force_prefix || is_cidr != 0 || bits != 128;
285 if include_prefix {
286 Ok(format!("{}/{}", ip, bits))
287 } else {
288 Ok(ip.to_string())
289 }
290 }
291 _ => Err(TypeError::InvalidData(format!(
292 "unsupported inet/cidr address family: {}",
293 family
294 ))),
295 }
296}
297
298#[derive(Debug, Clone, PartialEq, Eq)]
300pub struct Inet(pub String);
301
302impl Inet {
303 pub fn new(s: impl Into<String>) -> Self {
305 Self(s.into())
306 }
307
308 pub fn as_str(&self) -> &str {
310 &self.0
311 }
312}
313
314impl FromPg for Inet {
315 fn from_pg(bytes: &[u8], oid_val: u32, format: i16) -> Result<Self, TypeError> {
316 if oid_val != oid::INET {
317 return Err(TypeError::UnexpectedOid {
318 expected: "inet",
319 got: oid_val,
320 });
321 }
322
323 let s = if format == 1 {
324 decode_inet_like_binary(bytes, false)?
325 } else {
326 from_utf8_string(bytes)?
327 };
328 Ok(Inet(s))
329 }
330}
331
332impl ToPg for Inet {
333 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
334 (self.0.as_bytes().to_vec(), oid::INET, 0)
335 }
336}
337
338#[derive(Debug, Clone, PartialEq, Eq)]
340pub struct Cidr(pub String);
341
342impl Cidr {
343 pub fn new(s: impl Into<String>) -> Self {
345 Self(s.into())
346 }
347
348 pub fn as_str(&self) -> &str {
350 &self.0
351 }
352}
353
354impl FromPg for Cidr {
355 fn from_pg(bytes: &[u8], oid_val: u32, format: i16) -> Result<Self, TypeError> {
356 if oid_val != oid::CIDR {
357 return Err(TypeError::UnexpectedOid {
358 expected: "cidr",
359 got: oid_val,
360 });
361 }
362
363 let s = if format == 1 {
364 decode_inet_like_binary(bytes, true)?
365 } else {
366 from_utf8_string(bytes)?
367 };
368 Ok(Cidr(s))
369 }
370}
371
372impl ToPg for Cidr {
373 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
374 (self.0.as_bytes().to_vec(), oid::CIDR, 0)
375 }
376}
377
378#[derive(Debug, Clone, PartialEq, Eq)]
380pub struct MacAddr(pub String);
381
382impl MacAddr {
383 pub fn new(s: impl Into<String>) -> Self {
385 Self(s.into())
386 }
387
388 pub fn as_str(&self) -> &str {
390 &self.0
391 }
392}
393
394impl FromPg for MacAddr {
395 fn from_pg(bytes: &[u8], oid_val: u32, format: i16) -> Result<Self, TypeError> {
396 if oid_val != oid::MACADDR {
397 return Err(TypeError::UnexpectedOid {
398 expected: "macaddr",
399 got: oid_val,
400 });
401 }
402
403 let s = if format == 1 {
404 if bytes.len() != 6 {
405 return Err(TypeError::InvalidData(
406 "Expected 6 bytes for macaddr".to_string(),
407 ));
408 }
409 format!(
410 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
411 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]
412 )
413 } else {
414 from_utf8_string(bytes)?
415 };
416
417 Ok(MacAddr(s))
418 }
419}
420
421impl ToPg for MacAddr {
422 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
423 (self.0.as_bytes().to_vec(), oid::MACADDR, 0)
424 }
425}
426
427#[derive(Debug, Clone, PartialEq)]
431pub struct Json(pub String);
432
433impl FromPg for Json {
434 fn from_pg(bytes: &[u8], oid_val: u32, _format: i16) -> Result<Self, TypeError> {
435 let json_str = if oid_val == oid::JSONB {
436 decode_jsonb(bytes).map_err(TypeError::InvalidData)?
437 } else {
438 decode_json(bytes).map_err(TypeError::InvalidData)?
439 };
440 Ok(Json(json_str))
441 }
442}
443
444impl ToPg for Json {
445 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
446 let mut buf = Vec::with_capacity(1 + self.0.len());
448 buf.push(1); buf.extend_from_slice(self.0.as_bytes());
450 (buf, oid::JSONB, 1)
451 }
452}
453
454impl FromPg for Vec<String> {
457 fn from_pg(bytes: &[u8], _oid: u32, _format: i16) -> Result<Self, TypeError> {
458 let s = std::str::from_utf8(bytes).map_err(|e| TypeError::InvalidData(e.to_string()))?;
459 Ok(decode_text_array(s))
460 }
461}
462
463impl FromPg for Vec<i64> {
464 fn from_pg(bytes: &[u8], _oid: u32, _format: i16) -> Result<Self, TypeError> {
465 let s = std::str::from_utf8(bytes).map_err(|e| TypeError::InvalidData(e.to_string()))?;
466 crate::protocol::types::decode_int_array(s).map_err(TypeError::InvalidData)
467 }
468}
469
470impl<T: FromPg> FromPg for Option<T> {
473 fn from_pg(bytes: &[u8], oid_val: u32, format: i16) -> Result<Self, TypeError> {
474 Ok(Some(T::from_pg(bytes, oid_val, format)?))
476 }
477}
478
479impl FromPg for Vec<u8> {
482 fn from_pg(bytes: &[u8], _oid: u32, _format: i16) -> Result<Self, TypeError> {
483 Ok(bytes.to_vec())
484 }
485}
486
487impl ToPg for Vec<u8> {
488 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
489 (self.clone(), oid::BYTEA, 1)
490 }
491}
492
493impl ToPg for &[u8] {
494 fn to_pg(&self) -> (Vec<u8>, u32, i16) {
495 (self.to_vec(), oid::BYTEA, 1)
496 }
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502
503 #[test]
504 fn test_string_from_pg() {
505 let result = String::from_pg(b"hello", oid::TEXT, 0).unwrap();
506 assert_eq!(result, "hello");
507 }
508
509 #[test]
510 fn test_i32_from_pg_text() {
511 let result = i32::from_pg(b"42", oid::INT4, 0).unwrap();
512 assert_eq!(result, 42);
513 }
514
515 #[test]
516 fn test_i32_from_pg_binary() {
517 let bytes = 42i32.to_be_bytes();
518 let result = i32::from_pg(&bytes, oid::INT4, 1).unwrap();
519 assert_eq!(result, 42);
520 }
521
522 #[test]
523 fn test_bool_from_pg() {
524 assert!(bool::from_pg(b"t", oid::BOOL, 0).unwrap());
525 assert!(!bool::from_pg(b"f", oid::BOOL, 0).unwrap());
526 assert!(bool::from_pg(&[1], oid::BOOL, 1).unwrap());
527 assert!(!bool::from_pg(&[0], oid::BOOL, 1).unwrap());
528 }
529
530 #[test]
531 fn test_uuid_from_pg_binary() {
532 let uuid_bytes: [u8; 16] = [
533 0x55, 0x0e, 0x84, 0x00, 0xe2, 0x9b, 0x41, 0xd4, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44,
534 0x00, 0x00,
535 ];
536 let result = Uuid::from_pg(&uuid_bytes, oid::UUID, 1).unwrap();
537 assert_eq!(result.0, "550e8400-e29b-41d4-a716-446655440000");
538 }
539
540 #[test]
541 fn test_inet_from_pg_text() {
542 let inet = Inet::from_pg(b"10.0.0.1", oid::INET, 0).unwrap();
543 assert_eq!(inet.0, "10.0.0.1");
544 }
545
546 #[test]
547 fn test_inet_from_pg_binary_ipv4() {
548 let bytes = [2u8, 32, 0, 4, 10, 1, 2, 3];
550 let inet = Inet::from_pg(&bytes, oid::INET, 1).unwrap();
551 assert_eq!(inet.0, "10.1.2.3");
552 }
553
554 #[test]
555 fn test_cidr_from_pg_binary_ipv4() {
556 let bytes = [2u8, 24, 1, 4, 192, 168, 1, 0];
558 let cidr = Cidr::from_pg(&bytes, oid::CIDR, 1).unwrap();
559 assert_eq!(cidr.0, "192.168.1.0/24");
560 }
561
562 #[test]
563 fn test_macaddr_from_pg_binary() {
564 let bytes = [0x08u8, 0x00, 0x2b, 0x01, 0x02, 0x03];
565 let mac = MacAddr::from_pg(&bytes, oid::MACADDR, 1).unwrap();
566 assert_eq!(mac.0, "08:00:2b:01:02:03");
567 }
568
569 #[test]
570 fn test_network_types_to_pg_oids() {
571 let inet = Inet::new("10.0.0.0/8");
572 let (_, inet_oid, inet_format) = inet.to_pg();
573 assert_eq!(inet_oid, oid::INET);
574 assert_eq!(inet_format, 0);
575
576 let cidr = Cidr::new("10.0.0.0/8");
577 let (_, cidr_oid, cidr_format) = cidr.to_pg();
578 assert_eq!(cidr_oid, oid::CIDR);
579 assert_eq!(cidr_format, 0);
580
581 let mac = MacAddr::new("08:00:2b:01:02:03");
582 let (_, mac_oid, mac_format) = mac.to_pg();
583 assert_eq!(mac_oid, oid::MACADDR);
584 assert_eq!(mac_format, 0);
585 }
586}