1pub mod decode;
19pub mod encode;
20pub mod oid;
21
22use std::collections::HashMap;
23
24pub use decode::{BinaryDecode, Decode, TextDecode, decode_value};
25pub use encode::{BinaryEncode, Encode, Format, TextEncode, encode_value};
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum TypeCategory {
30 Boolean,
32 Numeric,
34 String,
36 DateTime,
38 Binary,
40 Json,
42 Uuid,
44 Array,
46 Range,
48 Composite,
50 Network,
52 Geometric,
54 Unknown,
56}
57
58#[derive(Debug, Clone)]
60pub struct TypeInfo {
61 pub oid: u32,
63 pub name: &'static str,
65 pub array_oid: Option<u32>,
67 pub element_oid: Option<u32>,
69 pub category: TypeCategory,
71 pub size: i16,
73 pub binary_format: bool,
75}
76
77impl TypeInfo {
78 const fn new(
80 oid: u32,
81 name: &'static str,
82 category: TypeCategory,
83 size: i16,
84 array_oid: Option<u32>,
85 ) -> Self {
86 Self {
87 oid,
88 name,
89 array_oid,
90 element_oid: None,
91 category,
92 size,
93 binary_format: true,
94 }
95 }
96
97 const fn array(oid: u32, name: &'static str, element_oid: u32) -> Self {
99 Self {
100 oid,
101 name,
102 array_oid: None,
103 element_oid: Some(element_oid),
104 category: TypeCategory::Array,
105 size: -1,
106 binary_format: true,
107 }
108 }
109}
110
111pub struct TypeRegistry {
115 by_oid: HashMap<u32, TypeInfo>,
116 by_name: HashMap<&'static str, u32>,
117}
118
119impl Default for TypeRegistry {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125impl TypeRegistry {
126 #[must_use]
128 pub fn new() -> Self {
129 let mut registry = Self {
130 by_oid: HashMap::new(),
131 by_name: HashMap::new(),
132 };
133
134 registry.register_builtins();
136
137 registry
138 }
139
140 #[must_use]
142 pub fn get(&self, oid: u32) -> Option<&TypeInfo> {
143 self.by_oid.get(&oid)
144 }
145
146 #[must_use]
148 pub fn by_name(&self, name: &str) -> Option<&TypeInfo> {
149 self.by_name.get(name).and_then(|oid| self.by_oid.get(oid))
150 }
151
152 #[must_use]
154 pub fn category(&self, oid: u32) -> TypeCategory {
155 self.get(oid).map_or(TypeCategory::Unknown, |t| t.category)
156 }
157
158 #[must_use]
160 pub fn supports_binary(&self, oid: u32) -> bool {
161 self.get(oid).is_some_and(|t| t.binary_format)
162 }
163
164 pub fn register(&mut self, info: TypeInfo) {
166 self.by_name.insert(info.name, info.oid);
167 self.by_oid.insert(info.oid, info);
168 }
169
170 fn register_builtins(&mut self) {
171 self.register(TypeInfo::new(
173 oid::BOOL,
174 "bool",
175 TypeCategory::Boolean,
176 1,
177 Some(oid::BOOL_ARRAY),
178 ));
179
180 self.register(TypeInfo::new(
182 oid::INT2,
183 "int2",
184 TypeCategory::Numeric,
185 2,
186 Some(oid::INT2_ARRAY),
187 ));
188 self.register(TypeInfo::new(
189 oid::INT4,
190 "int4",
191 TypeCategory::Numeric,
192 4,
193 Some(oid::INT4_ARRAY),
194 ));
195 self.register(TypeInfo::new(
196 oid::INT8,
197 "int8",
198 TypeCategory::Numeric,
199 8,
200 Some(oid::INT8_ARRAY),
201 ));
202
203 self.register(TypeInfo::new(
205 oid::FLOAT4,
206 "float4",
207 TypeCategory::Numeric,
208 4,
209 Some(oid::FLOAT4_ARRAY),
210 ));
211 self.register(TypeInfo::new(
212 oid::FLOAT8,
213 "float8",
214 TypeCategory::Numeric,
215 8,
216 Some(oid::FLOAT8_ARRAY),
217 ));
218 self.register(TypeInfo::new(
219 oid::NUMERIC,
220 "numeric",
221 TypeCategory::Numeric,
222 -1,
223 Some(oid::NUMERIC_ARRAY),
224 ));
225
226 self.register(TypeInfo::new(
228 oid::TEXT,
229 "text",
230 TypeCategory::String,
231 -1,
232 Some(oid::TEXT_ARRAY),
233 ));
234 self.register(TypeInfo::new(
235 oid::VARCHAR,
236 "varchar",
237 TypeCategory::String,
238 -1,
239 Some(oid::VARCHAR_ARRAY),
240 ));
241 self.register(TypeInfo::new(
242 oid::BPCHAR,
243 "bpchar",
244 TypeCategory::String,
245 -1,
246 None,
247 ));
248 self.register(TypeInfo::new(
249 oid::CHAR,
250 "char",
251 TypeCategory::String,
252 1,
253 Some(oid::CHAR_ARRAY),
254 ));
255 self.register(TypeInfo::new(
256 oid::NAME,
257 "name",
258 TypeCategory::String,
259 64,
260 Some(oid::NAME_ARRAY),
261 ));
262
263 self.register(TypeInfo::new(
265 oid::BYTEA,
266 "bytea",
267 TypeCategory::Binary,
268 -1,
269 Some(oid::BYTEA_ARRAY),
270 ));
271
272 self.register(TypeInfo::new(
274 oid::DATE,
275 "date",
276 TypeCategory::DateTime,
277 4,
278 Some(oid::DATE_ARRAY),
279 ));
280 self.register(TypeInfo::new(
281 oid::TIME,
282 "time",
283 TypeCategory::DateTime,
284 8,
285 Some(oid::TIME_ARRAY),
286 ));
287 self.register(TypeInfo::new(
288 oid::TIMETZ,
289 "timetz",
290 TypeCategory::DateTime,
291 12,
292 None,
293 ));
294 self.register(TypeInfo::new(
295 oid::TIMESTAMP,
296 "timestamp",
297 TypeCategory::DateTime,
298 8,
299 Some(oid::TIMESTAMP_ARRAY),
300 ));
301 self.register(TypeInfo::new(
302 oid::TIMESTAMPTZ,
303 "timestamptz",
304 TypeCategory::DateTime,
305 8,
306 Some(oid::TIMESTAMPTZ_ARRAY),
307 ));
308 self.register(TypeInfo::new(
309 oid::INTERVAL,
310 "interval",
311 TypeCategory::DateTime,
312 16,
313 Some(oid::INTERVAL_ARRAY),
314 ));
315
316 self.register(TypeInfo::new(
318 oid::UUID,
319 "uuid",
320 TypeCategory::Uuid,
321 16,
322 Some(oid::UUID_ARRAY),
323 ));
324
325 self.register(TypeInfo::new(
327 oid::JSON,
328 "json",
329 TypeCategory::Json,
330 -1,
331 Some(oid::JSON_ARRAY),
332 ));
333 self.register(TypeInfo::new(
334 oid::JSONB,
335 "jsonb",
336 TypeCategory::Json,
337 -1,
338 Some(oid::JSONB_ARRAY),
339 ));
340
341 self.register(TypeInfo::new(
343 oid::OID,
344 "oid",
345 TypeCategory::Numeric,
346 4,
347 Some(oid::OID_ARRAY),
348 ));
349 self.register(TypeInfo::new(
350 oid::XID,
351 "xid",
352 TypeCategory::Numeric,
353 4,
354 None,
355 ));
356 self.register(TypeInfo::new(
357 oid::CID,
358 "cid",
359 TypeCategory::Numeric,
360 4,
361 None,
362 ));
363
364 self.register(TypeInfo::new(
366 oid::INET,
367 "inet",
368 TypeCategory::Network,
369 -1,
370 None,
371 ));
372 self.register(TypeInfo::new(
373 oid::CIDR,
374 "cidr",
375 TypeCategory::Network,
376 -1,
377 None,
378 ));
379 self.register(TypeInfo::new(
380 oid::MACADDR,
381 "macaddr",
382 TypeCategory::Network,
383 6,
384 None,
385 ));
386
387 self.register(TypeInfo::new(
389 oid::INT4RANGE,
390 "int4range",
391 TypeCategory::Range,
392 -1,
393 None,
394 ));
395 self.register(TypeInfo::new(
396 oid::INT8RANGE,
397 "int8range",
398 TypeCategory::Range,
399 -1,
400 None,
401 ));
402 self.register(TypeInfo::new(
403 oid::NUMRANGE,
404 "numrange",
405 TypeCategory::Range,
406 -1,
407 None,
408 ));
409 self.register(TypeInfo::new(
410 oid::TSRANGE,
411 "tsrange",
412 TypeCategory::Range,
413 -1,
414 None,
415 ));
416 self.register(TypeInfo::new(
417 oid::TSTZRANGE,
418 "tstzrange",
419 TypeCategory::Range,
420 -1,
421 None,
422 ));
423 self.register(TypeInfo::new(
424 oid::DATERANGE,
425 "daterange",
426 TypeCategory::Range,
427 -1,
428 None,
429 ));
430
431 self.register(TypeInfo::array(oid::BOOL_ARRAY, "bool[]", oid::BOOL));
433 self.register(TypeInfo::array(oid::INT2_ARRAY, "int2[]", oid::INT2));
434 self.register(TypeInfo::array(oid::INT4_ARRAY, "int4[]", oid::INT4));
435 self.register(TypeInfo::array(oid::INT8_ARRAY, "int8[]", oid::INT8));
436 self.register(TypeInfo::array(oid::FLOAT4_ARRAY, "float4[]", oid::FLOAT4));
437 self.register(TypeInfo::array(oid::FLOAT8_ARRAY, "float8[]", oid::FLOAT8));
438 self.register(TypeInfo::array(oid::TEXT_ARRAY, "text[]", oid::TEXT));
439 self.register(TypeInfo::array(
440 oid::VARCHAR_ARRAY,
441 "varchar[]",
442 oid::VARCHAR,
443 ));
444 self.register(TypeInfo::array(oid::BYTEA_ARRAY, "bytea[]", oid::BYTEA));
445 self.register(TypeInfo::array(oid::DATE_ARRAY, "date[]", oid::DATE));
446 self.register(TypeInfo::array(oid::TIME_ARRAY, "time[]", oid::TIME));
447 self.register(TypeInfo::array(
448 oid::TIMESTAMP_ARRAY,
449 "timestamp[]",
450 oid::TIMESTAMP,
451 ));
452 self.register(TypeInfo::array(
453 oid::TIMESTAMPTZ_ARRAY,
454 "timestamptz[]",
455 oid::TIMESTAMPTZ,
456 ));
457 self.register(TypeInfo::array(
458 oid::INTERVAL_ARRAY,
459 "interval[]",
460 oid::INTERVAL,
461 ));
462 self.register(TypeInfo::array(
463 oid::NUMERIC_ARRAY,
464 "numeric[]",
465 oid::NUMERIC,
466 ));
467 self.register(TypeInfo::array(oid::UUID_ARRAY, "uuid[]", oid::UUID));
468 self.register(TypeInfo::array(oid::JSON_ARRAY, "json[]", oid::JSON));
469 self.register(TypeInfo::array(oid::JSONB_ARRAY, "jsonb[]", oid::JSONB));
470 self.register(TypeInfo::array(oid::OID_ARRAY, "oid[]", oid::OID));
471 self.register(TypeInfo::array(oid::CHAR_ARRAY, "char[]", oid::CHAR));
472 self.register(TypeInfo::array(oid::NAME_ARRAY, "name[]", oid::NAME));
473
474 self.register(TypeInfo::new(
476 oid::UNKNOWN,
477 "unknown",
478 TypeCategory::Unknown,
479 -2,
480 None,
481 ));
482 self.register(TypeInfo::new(
483 oid::VOID,
484 "void",
485 TypeCategory::Unknown,
486 4,
487 None,
488 ));
489 }
490}
491
492#[cfg(test)]
493mod tests {
494 use super::*;
495
496 #[test]
497 fn test_type_registry_creation() {
498 let registry = TypeRegistry::new();
499
500 assert!(registry.get(oid::BOOL).is_some());
502 assert!(registry.get(oid::INT4).is_some());
503 assert!(registry.get(oid::TEXT).is_some());
504
505 assert!(registry.by_name("int4").is_some());
507 assert!(registry.by_name("text").is_some());
508 }
509
510 #[test]
511 fn test_type_categories() {
512 let registry = TypeRegistry::new();
513
514 assert_eq!(registry.category(oid::BOOL), TypeCategory::Boolean);
515 assert_eq!(registry.category(oid::INT4), TypeCategory::Numeric);
516 assert_eq!(registry.category(oid::TEXT), TypeCategory::String);
517 assert_eq!(registry.category(oid::DATE), TypeCategory::DateTime);
518 assert_eq!(registry.category(oid::BYTEA), TypeCategory::Binary);
519 assert_eq!(registry.category(oid::JSON), TypeCategory::Json);
520 assert_eq!(registry.category(oid::UUID), TypeCategory::Uuid);
521 assert_eq!(registry.category(oid::INT4_ARRAY), TypeCategory::Array);
522 }
523
524 #[test]
525 fn test_array_types() {
526 let registry = TypeRegistry::new();
527
528 let int4 = registry.get(oid::INT4).unwrap();
529 assert_eq!(int4.array_oid, Some(oid::INT4_ARRAY));
530
531 let int4_array = registry.get(oid::INT4_ARRAY).unwrap();
532 assert_eq!(int4_array.element_oid, Some(oid::INT4));
533 }
534
535 #[test]
536 fn test_binary_format_support() {
537 let registry = TypeRegistry::new();
538
539 assert!(registry.supports_binary(oid::INT4));
540 assert!(registry.supports_binary(oid::TEXT));
541 assert!(registry.supports_binary(oid::BOOL));
542 }
543
544 #[test]
545 fn test_unknown_type() {
546 let registry = TypeRegistry::new();
547
548 assert_eq!(registry.category(999_999), TypeCategory::Unknown);
549 assert!(!registry.supports_binary(999_999));
550 }
551}