1#![allow(missing_docs)]
2
3use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
4use bytes::{Bytes, BytesMut};
5use fallible_iterator::FallibleIterator;
6use memchr::memchr;
7use std::cmp;
8use std::io::{self, Read};
9use std::ops::Range;
10use std::str;
11
12use crate::Oid;
13
14pub const PARSE_COMPLETE_TAG: u8 = b'1';
15pub const BIND_COMPLETE_TAG: u8 = b'2';
16pub const CLOSE_COMPLETE_TAG: u8 = b'3';
17pub const NOTIFICATION_RESPONSE_TAG: u8 = b'A';
18pub const COPY_DONE_TAG: u8 = b'c';
19pub const COMMAND_COMPLETE_TAG: u8 = b'C';
20pub const COPY_DATA_TAG: u8 = b'd';
21pub const DATA_ROW_TAG: u8 = b'D';
22pub const ERROR_RESPONSE_TAG: u8 = b'E';
23pub const COPY_IN_RESPONSE_TAG: u8 = b'G';
24pub const COPY_OUT_RESPONSE_TAG: u8 = b'H';
25pub const COPY_BOTH_RESPONSE_TAG: u8 = b'W';
26pub const EMPTY_QUERY_RESPONSE_TAG: u8 = b'I';
27pub const BACKEND_KEY_DATA_TAG: u8 = b'K';
28pub const NO_DATA_TAG: u8 = b'n';
29pub const NOTICE_RESPONSE_TAG: u8 = b'N';
30pub const AUTHENTICATION_TAG: u8 = b'R';
31pub const PORTAL_SUSPENDED_TAG: u8 = b's';
32pub const PARAMETER_STATUS_TAG: u8 = b'S';
33pub const PARAMETER_DESCRIPTION_TAG: u8 = b't';
34pub const ROW_DESCRIPTION_TAG: u8 = b'T';
35pub const READY_FOR_QUERY_TAG: u8 = b'Z';
36
37#[derive(Debug, Copy, Clone)]
38pub struct Header {
39 tag: u8,
40 len: i32,
41}
42
43#[allow(clippy::len_without_is_empty)]
44impl Header {
45 #[inline]
46 pub fn parse(buf: &[u8]) -> io::Result<Option<Header>> {
47 if buf.len() < 5 {
48 return Ok(None);
49 }
50
51 let tag = buf[0];
52 let len = BigEndian::read_i32(&buf[1..]);
53
54 if len < 4 {
55 return Err(io::Error::new(
56 io::ErrorKind::InvalidData,
57 "invalid message length: header length < 4",
58 ));
59 }
60
61 Ok(Some(Header { tag, len }))
62 }
63
64 #[inline]
65 pub fn tag(self) -> u8 {
66 self.tag
67 }
68
69 #[inline]
70 pub fn len(self) -> i32 {
71 self.len
72 }
73}
74
75#[non_exhaustive]
77pub enum Message {
78 AuthenticationCleartextPassword,
79 AuthenticationGss,
80 AuthenticationKerberosV5,
81 AuthenticationMd5Password(AuthenticationMd5PasswordBody),
82 AuthenticationOk,
83 AuthenticationScmCredential,
84 AuthenticationSspi,
85 AuthenticationGssContinue(AuthenticationGssContinueBody),
86 AuthenticationSasl(AuthenticationSaslBody),
87 AuthenticationSaslContinue(AuthenticationSaslContinueBody),
88 AuthenticationSaslFinal(AuthenticationSaslFinalBody),
89 BackendKeyData(BackendKeyDataBody),
90 BindComplete,
91 CloseComplete,
92 CommandComplete(CommandCompleteBody),
93 CopyData(CopyDataBody),
94 CopyDone,
95 CopyInResponse(CopyInResponseBody),
96 CopyOutResponse(CopyOutResponseBody),
97 CopyBothResponse(CopyBothResponseBody),
98 DataRow(DataRowBody),
99 EmptyQueryResponse,
100 ErrorResponse(ErrorResponseBody),
101 NoData,
102 NoticeResponse(NoticeResponseBody),
103 NotificationResponse(NotificationResponseBody),
104 ParameterDescription(ParameterDescriptionBody),
105 ParameterStatus(ParameterStatusBody),
106 ParseComplete,
107 PortalSuspended,
108 ReadyForQuery(ReadyForQueryBody),
109 RowDescription(RowDescriptionBody),
110}
111
112impl Message {
113 #[inline]
114 pub fn parse(buf: &mut BytesMut) -> io::Result<Option<Message>> {
115 if buf.len() < 5 {
116 let to_read = 5 - buf.len();
117 buf.reserve(to_read);
118 return Ok(None);
119 }
120
121 let tag = buf[0];
122 let len = (&buf[1..5]).read_u32::<BigEndian>().unwrap();
123
124 if len < 4 {
125 return Err(io::Error::new(
126 io::ErrorKind::InvalidInput,
127 "invalid message length: parsing u32",
128 ));
129 }
130
131 let total_len = len as usize + 1;
132 if buf.len() < total_len {
133 let to_read = total_len - buf.len();
134 buf.reserve(to_read);
135 return Ok(None);
136 }
137
138 let mut buf = Buffer {
139 bytes: buf.split_to(total_len).freeze(),
140 idx: 5,
141 };
142
143 let message = match tag {
144 PARSE_COMPLETE_TAG => Message::ParseComplete,
145 BIND_COMPLETE_TAG => Message::BindComplete,
146 CLOSE_COMPLETE_TAG => Message::CloseComplete,
147 NOTIFICATION_RESPONSE_TAG => {
148 let process_id = buf.read_i32::<BigEndian>()?;
149 let channel = buf.read_cstr()?;
150 let message = buf.read_cstr()?;
151 Message::NotificationResponse(NotificationResponseBody {
152 process_id,
153 channel,
154 message,
155 })
156 }
157 COPY_DONE_TAG => Message::CopyDone,
158 COMMAND_COMPLETE_TAG => {
159 let tag = buf.read_cstr()?;
160 Message::CommandComplete(CommandCompleteBody { tag })
161 }
162 COPY_DATA_TAG => {
163 let storage = buf.read_all();
164 Message::CopyData(CopyDataBody { storage })
165 }
166 DATA_ROW_TAG => {
167 let len = buf.read_u16::<BigEndian>()?;
168 let storage = buf.read_all();
169 Message::DataRow(DataRowBody { storage, len })
170 }
171 ERROR_RESPONSE_TAG => {
172 let storage = buf.read_all();
173 Message::ErrorResponse(ErrorResponseBody { storage })
174 }
175 COPY_IN_RESPONSE_TAG => {
176 let format = buf.read_u8()?;
177 let len = buf.read_u16::<BigEndian>()?;
178 let storage = buf.read_all();
179 Message::CopyInResponse(CopyInResponseBody {
180 format,
181 len,
182 storage,
183 })
184 }
185 COPY_OUT_RESPONSE_TAG => {
186 let format = buf.read_u8()?;
187 let len = buf.read_u16::<BigEndian>()?;
188 let storage = buf.read_all();
189 Message::CopyOutResponse(CopyOutResponseBody {
190 format,
191 len,
192 storage,
193 })
194 }
195 COPY_BOTH_RESPONSE_TAG => {
196 let format = buf.read_u8()?;
197 let len = buf.read_u16::<BigEndian>()?;
198 let storage = buf.read_all();
199 Message::CopyBothResponse(CopyBothResponseBody {
200 format,
201 len,
202 storage,
203 })
204 }
205 EMPTY_QUERY_RESPONSE_TAG => Message::EmptyQueryResponse,
206 BACKEND_KEY_DATA_TAG => {
207 let process_id = buf.read_i32::<BigEndian>()?;
208 let secret_key = buf.read_i32::<BigEndian>()?;
209 Message::BackendKeyData(BackendKeyDataBody {
210 process_id,
211 secret_key,
212 })
213 }
214 NO_DATA_TAG => Message::NoData,
215 NOTICE_RESPONSE_TAG => {
216 let storage = buf.read_all();
217 Message::NoticeResponse(NoticeResponseBody { storage })
218 }
219 AUTHENTICATION_TAG => match buf.read_i32::<BigEndian>()? {
220 0 => Message::AuthenticationOk,
221 2 => Message::AuthenticationKerberosV5,
222 3 => Message::AuthenticationCleartextPassword,
223 5 => {
224 let mut salt = [0; 4];
225 buf.read_exact(&mut salt)?;
226 Message::AuthenticationMd5Password(AuthenticationMd5PasswordBody { salt })
227 }
228 6 => Message::AuthenticationScmCredential,
229 7 => Message::AuthenticationGss,
230 8 => {
231 let storage = buf.read_all();
232 Message::AuthenticationGssContinue(AuthenticationGssContinueBody(storage))
233 }
234 9 => Message::AuthenticationSspi,
235 10 => {
236 let storage = buf.read_all();
237 Message::AuthenticationSasl(AuthenticationSaslBody(storage))
238 }
239 11 => {
240 let storage = buf.read_all();
241 Message::AuthenticationSaslContinue(AuthenticationSaslContinueBody(storage))
242 }
243 12 => {
244 let storage = buf.read_all();
245 Message::AuthenticationSaslFinal(AuthenticationSaslFinalBody(storage))
246 }
247 tag => {
248 return Err(io::Error::new(
249 io::ErrorKind::InvalidInput,
250 format!("unknown authentication tag `{}`", tag),
251 ));
252 }
253 },
254 PORTAL_SUSPENDED_TAG => Message::PortalSuspended,
255 PARAMETER_STATUS_TAG => {
256 let name = buf.read_cstr()?;
257 let value = buf.read_cstr()?;
258 Message::ParameterStatus(ParameterStatusBody { name, value })
259 }
260 PARAMETER_DESCRIPTION_TAG => {
261 let len = buf.read_u16::<BigEndian>()?;
262 let storage = buf.read_all();
263 Message::ParameterDescription(ParameterDescriptionBody { storage, len })
264 }
265 ROW_DESCRIPTION_TAG => {
266 let len = buf.read_u16::<BigEndian>()?;
267 let storage = buf.read_all();
268 Message::RowDescription(RowDescriptionBody { storage, len })
269 }
270 READY_FOR_QUERY_TAG => {
271 let status = buf.read_u8()?;
272 Message::ReadyForQuery(ReadyForQueryBody { status })
273 }
274 tag => {
275 return Err(io::Error::new(
276 io::ErrorKind::InvalidInput,
277 format!("unknown message tag `{}`", tag),
278 ));
279 }
280 };
281
282 if !buf.is_empty() {
283 return Err(io::Error::new(
284 io::ErrorKind::InvalidInput,
285 "invalid message length: expected buffer to be empty",
286 ));
287 }
288
289 Ok(Some(message))
290 }
291}
292
293struct Buffer {
294 bytes: Bytes,
295 idx: usize,
296}
297
298impl Buffer {
299 #[inline]
300 fn slice(&self) -> &[u8] {
301 &self.bytes[self.idx..]
302 }
303
304 #[inline]
305 fn is_empty(&self) -> bool {
306 self.slice().is_empty()
307 }
308
309 #[inline]
310 fn read_cstr(&mut self) -> io::Result<Bytes> {
311 match memchr(0, self.slice()) {
312 Some(pos) => {
313 let start = self.idx;
314 let end = start + pos;
315 let cstr = self.bytes.slice(start..end);
316 self.idx = end + 1;
317 Ok(cstr)
318 }
319 None => Err(io::Error::new(
320 io::ErrorKind::UnexpectedEof,
321 "unexpected EOF",
322 )),
323 }
324 }
325
326 #[inline]
327 fn read_all(&mut self) -> Bytes {
328 let buf = self.bytes.slice(self.idx..);
329 self.idx = self.bytes.len();
330 buf
331 }
332}
333
334impl Read for Buffer {
335 #[inline]
336 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
337 let len = {
338 let slice = self.slice();
339 let len = cmp::min(slice.len(), buf.len());
340 buf[..len].copy_from_slice(&slice[..len]);
341 len
342 };
343 self.idx += len;
344 Ok(len)
345 }
346}
347
348pub struct AuthenticationMd5PasswordBody {
349 salt: [u8; 4],
350}
351
352impl AuthenticationMd5PasswordBody {
353 #[inline]
354 pub fn salt(&self) -> [u8; 4] {
355 self.salt
356 }
357}
358
359pub struct AuthenticationGssContinueBody(Bytes);
360
361impl AuthenticationGssContinueBody {
362 #[inline]
363 pub fn data(&self) -> &[u8] {
364 &self.0
365 }
366}
367
368pub struct AuthenticationSaslBody(Bytes);
369
370impl AuthenticationSaslBody {
371 #[inline]
372 pub fn mechanisms(&self) -> SaslMechanisms<'_> {
373 SaslMechanisms(&self.0)
374 }
375}
376
377pub struct SaslMechanisms<'a>(&'a [u8]);
378
379impl<'a> FallibleIterator for SaslMechanisms<'a> {
380 type Item = &'a str;
381 type Error = io::Error;
382
383 #[inline]
384 fn next(&mut self) -> io::Result<Option<&'a str>> {
385 let value_end = find_null(self.0, 0)?;
386 if value_end == 0 {
387 if self.0.len() != 1 {
388 return Err(io::Error::new(
389 io::ErrorKind::InvalidData,
390 "invalid message length: expected to be at end of iterator for sasl",
391 ));
392 }
393 Ok(None)
394 } else {
395 let value = get_str(&self.0[..value_end])?;
396 self.0 = &self.0[value_end + 1..];
397 Ok(Some(value))
398 }
399 }
400}
401
402pub struct AuthenticationSaslContinueBody(Bytes);
403
404impl AuthenticationSaslContinueBody {
405 #[inline]
406 pub fn data(&self) -> &[u8] {
407 &self.0
408 }
409}
410
411pub struct AuthenticationSaslFinalBody(Bytes);
412
413impl AuthenticationSaslFinalBody {
414 #[inline]
415 pub fn data(&self) -> &[u8] {
416 &self.0
417 }
418}
419
420pub struct BackendKeyDataBody {
421 process_id: i32,
422 secret_key: i32,
423}
424
425impl BackendKeyDataBody {
426 #[inline]
427 pub fn process_id(&self) -> i32 {
428 self.process_id
429 }
430
431 #[inline]
432 pub fn secret_key(&self) -> i32 {
433 self.secret_key
434 }
435}
436
437pub struct CommandCompleteBody {
438 tag: Bytes,
439}
440
441impl CommandCompleteBody {
442 #[inline]
443 pub fn tag(&self) -> io::Result<&str> {
444 get_str(&self.tag)
445 }
446}
447
448pub struct CopyDataBody {
449 storage: Bytes,
450}
451
452impl CopyDataBody {
453 #[inline]
454 pub fn data(&self) -> &[u8] {
455 &self.storage
456 }
457
458 #[inline]
459 pub fn into_bytes(self) -> Bytes {
460 self.storage
461 }
462}
463
464pub struct CopyInResponseBody {
465 format: u8,
466 len: u16,
467 storage: Bytes,
468}
469
470impl CopyInResponseBody {
471 #[inline]
472 pub fn format(&self) -> u8 {
473 self.format
474 }
475
476 #[inline]
477 pub fn column_formats(&self) -> ColumnFormats<'_> {
478 ColumnFormats {
479 remaining: self.len,
480 buf: &self.storage,
481 }
482 }
483}
484
485pub struct ColumnFormats<'a> {
486 buf: &'a [u8],
487 remaining: u16,
488}
489
490impl<'a> FallibleIterator for ColumnFormats<'a> {
491 type Item = u16;
492 type Error = io::Error;
493
494 #[inline]
495 fn next(&mut self) -> io::Result<Option<u16>> {
496 if self.remaining == 0 {
497 if self.buf.is_empty() {
498 return Ok(None);
499 } else {
500 return Err(io::Error::new(
501 io::ErrorKind::InvalidInput,
502 "invalid message length: wrong column formats",
503 ));
504 }
505 }
506
507 self.remaining -= 1;
508 self.buf.read_u16::<BigEndian>().map(Some)
509 }
510
511 #[inline]
512 fn size_hint(&self) -> (usize, Option<usize>) {
513 let len = self.remaining as usize;
514 (len, Some(len))
515 }
516}
517
518pub struct CopyOutResponseBody {
519 format: u8,
520 len: u16,
521 storage: Bytes,
522}
523
524impl CopyOutResponseBody {
525 #[inline]
526 pub fn format(&self) -> u8 {
527 self.format
528 }
529
530 #[inline]
531 pub fn column_formats(&self) -> ColumnFormats<'_> {
532 ColumnFormats {
533 remaining: self.len,
534 buf: &self.storage,
535 }
536 }
537}
538
539#[derive(Debug, Clone)]
540pub struct CopyBothResponseBody {
541 format: u8,
542 len: u16,
543 storage: Bytes,
544}
545
546impl CopyBothResponseBody {
547 #[inline]
548 pub fn format(&self) -> u8 {
549 self.format
550 }
551
552 #[inline]
553 pub fn column_formats(&self) -> ColumnFormats<'_> {
554 ColumnFormats {
555 remaining: self.len,
556 buf: &self.storage,
557 }
558 }
559}
560
561#[derive(Debug, Clone)]
562pub struct DataRowBody {
563 storage: Bytes,
564 len: u16,
565}
566
567impl DataRowBody {
568 #[inline]
569 pub fn ranges(&self) -> DataRowRanges<'_> {
570 DataRowRanges {
571 buf: &self.storage,
572 len: self.storage.len(),
573 remaining: self.len,
574 }
575 }
576
577 #[inline]
578 pub fn buffer(&self) -> &[u8] {
579 &self.storage
580 }
581
582 #[inline]
583 pub fn buffer_bytes(&self) -> &Bytes {
584 &self.storage
585 }
586}
587
588pub struct DataRowRanges<'a> {
589 buf: &'a [u8],
590 len: usize,
591 remaining: u16,
592}
593
594impl<'a> FallibleIterator for DataRowRanges<'a> {
595 type Item = Option<Range<usize>>;
596 type Error = io::Error;
597
598 #[inline]
599 fn next(&mut self) -> io::Result<Option<Option<Range<usize>>>> {
600 if self.remaining == 0 {
601 if self.buf.is_empty() {
602 return Ok(None);
603 } else {
604 return Err(io::Error::new(
605 io::ErrorKind::InvalidInput,
606 "invalid message length: datarowrange is not empty",
607 ));
608 }
609 }
610
611 self.remaining -= 1;
612 let len = self.buf.read_i32::<BigEndian>()?;
613 if len < 0 {
614 Ok(Some(None))
615 } else {
616 let len = len as usize;
617 if self.buf.len() < len {
618 return Err(io::Error::new(
619 io::ErrorKind::UnexpectedEof,
620 "unexpected EOF",
621 ));
622 }
623 let base = self.len - self.buf.len();
624 self.buf = &self.buf[len..];
625 Ok(Some(Some(base..base + len)))
626 }
627 }
628
629 #[inline]
630 fn size_hint(&self) -> (usize, Option<usize>) {
631 let len = self.remaining as usize;
632 (len, Some(len))
633 }
634}
635
636pub struct ErrorResponseBody {
637 storage: Bytes,
638}
639
640impl ErrorResponseBody {
641 #[inline]
642 pub fn fields(&self) -> ErrorFields<'_> {
643 ErrorFields { buf: &self.storage }
644 }
645}
646
647pub struct ErrorFields<'a> {
648 buf: &'a [u8],
649}
650
651impl<'a> FallibleIterator for ErrorFields<'a> {
652 type Item = ErrorField<'a>;
653 type Error = io::Error;
654
655 #[inline]
656 fn next(&mut self) -> io::Result<Option<ErrorField<'a>>> {
657 let type_ = self.buf.read_u8()?;
658 if type_ == 0 {
659 if self.buf.is_empty() {
660 return Ok(None);
661 } else {
662 return Err(io::Error::new(
663 io::ErrorKind::InvalidInput,
664 "invalid message length: error fields is not drained",
665 ));
666 }
667 }
668
669 let value_end = find_null(self.buf, 0)?;
670 let value = &self.buf[..value_end];
671 self.buf = &self.buf[value_end + 1..];
672
673 Ok(Some(ErrorField { type_, value }))
674 }
675}
676
677pub struct ErrorField<'a> {
678 type_: u8,
679 value: &'a [u8],
680}
681
682impl<'a> ErrorField<'a> {
683 #[inline]
684 pub fn type_(&self) -> u8 {
685 self.type_
686 }
687
688 #[inline]
689 #[deprecated(note = "use value_bytes instead", since = "0.6.7")]
690 pub fn value(&self) -> &str {
691 str::from_utf8(self.value).expect("error field value contained non-UTF8 bytes")
692 }
693
694 #[inline]
695 pub fn value_bytes(&self) -> &[u8] {
696 self.value
697 }
698}
699
700pub struct NoticeResponseBody {
701 storage: Bytes,
702}
703
704impl NoticeResponseBody {
705 #[inline]
706 pub fn fields(&self) -> ErrorFields<'_> {
707 ErrorFields { buf: &self.storage }
708 }
709}
710
711pub struct NotificationResponseBody {
712 process_id: i32,
713 channel: Bytes,
714 message: Bytes,
715}
716
717impl NotificationResponseBody {
718 #[inline]
719 pub fn process_id(&self) -> i32 {
720 self.process_id
721 }
722
723 #[inline]
724 pub fn channel(&self) -> io::Result<&str> {
725 get_str(&self.channel)
726 }
727
728 #[inline]
729 pub fn message(&self) -> io::Result<&str> {
730 get_str(&self.message)
731 }
732}
733
734pub struct ParameterDescriptionBody {
735 storage: Bytes,
736 len: u16,
737}
738
739impl ParameterDescriptionBody {
740 #[inline]
741 pub fn parameters(&self) -> Parameters<'_> {
742 Parameters {
743 buf: &self.storage,
744 remaining: self.len,
745 }
746 }
747}
748
749pub struct Parameters<'a> {
750 buf: &'a [u8],
751 remaining: u16,
752}
753
754impl<'a> FallibleIterator for Parameters<'a> {
755 type Item = Oid;
756 type Error = io::Error;
757
758 #[inline]
759 fn next(&mut self) -> io::Result<Option<Oid>> {
760 if self.remaining == 0 {
761 if self.buf.is_empty() {
762 return Ok(None);
763 } else {
764 return Err(io::Error::new(
765 io::ErrorKind::InvalidInput,
766 "invalid message length: parameters is not drained",
767 ));
768 }
769 }
770
771 self.remaining -= 1;
772 self.buf.read_u32::<BigEndian>().map(Some)
773 }
774
775 #[inline]
776 fn size_hint(&self) -> (usize, Option<usize>) {
777 let len = self.remaining as usize;
778 (len, Some(len))
779 }
780}
781
782pub struct ParameterStatusBody {
783 name: Bytes,
784 value: Bytes,
785}
786
787impl ParameterStatusBody {
788 #[inline]
789 pub fn name(&self) -> io::Result<&str> {
790 get_str(&self.name)
791 }
792
793 #[inline]
794 pub fn value(&self) -> io::Result<&str> {
795 get_str(&self.value)
796 }
797}
798
799pub struct ReadyForQueryBody {
800 status: u8,
801}
802
803impl ReadyForQueryBody {
804 #[inline]
805 pub fn status(&self) -> u8 {
806 self.status
807 }
808}
809
810pub struct RowDescriptionBody {
811 storage: Bytes,
812 len: u16,
813}
814
815impl RowDescriptionBody {
816 #[inline]
817 pub fn fields(&self) -> Fields<'_> {
818 Fields {
819 buf: &self.storage,
820 remaining: self.len,
821 }
822 }
823}
824
825pub struct Fields<'a> {
826 buf: &'a [u8],
827 remaining: u16,
828}
829
830impl<'a> FallibleIterator for Fields<'a> {
831 type Item = Field<'a>;
832 type Error = io::Error;
833
834 #[inline]
835 fn next(&mut self) -> io::Result<Option<Field<'a>>> {
836 if self.remaining == 0 {
837 if self.buf.is_empty() {
838 return Ok(None);
839 } else {
840 return Err(io::Error::new(
841 io::ErrorKind::InvalidInput,
842 "invalid message length: field is not drained",
843 ));
844 }
845 }
846
847 self.remaining -= 1;
848 let name_end = find_null(self.buf, 0)?;
849 let name = get_str(&self.buf[..name_end])?;
850 self.buf = &self.buf[name_end + 1..];
851 let table_oid = self.buf.read_u32::<BigEndian>()?;
852 let column_id = self.buf.read_i16::<BigEndian>()?;
853 let type_oid = self.buf.read_u32::<BigEndian>()?;
854 let type_size = self.buf.read_i16::<BigEndian>()?;
855 let type_modifier = self.buf.read_i32::<BigEndian>()?;
856 let format = self.buf.read_i16::<BigEndian>()?;
857
858 Ok(Some(Field {
859 name,
860 table_oid,
861 column_id,
862 type_oid,
863 type_size,
864 type_modifier,
865 format,
866 }))
867 }
868}
869
870pub struct Field<'a> {
871 name: &'a str,
872 table_oid: Oid,
873 column_id: i16,
874 type_oid: Oid,
875 type_size: i16,
876 type_modifier: i32,
877 format: i16,
878}
879
880impl<'a> Field<'a> {
881 #[inline]
882 pub fn name(&self) -> &'a str {
883 self.name
884 }
885
886 #[inline]
887 pub fn table_oid(&self) -> Oid {
888 self.table_oid
889 }
890
891 #[inline]
892 pub fn column_id(&self) -> i16 {
893 self.column_id
894 }
895
896 #[inline]
897 pub fn type_oid(&self) -> Oid {
898 self.type_oid
899 }
900
901 #[inline]
902 pub fn type_size(&self) -> i16 {
903 self.type_size
904 }
905
906 #[inline]
907 pub fn type_modifier(&self) -> i32 {
908 self.type_modifier
909 }
910
911 #[inline]
912 pub fn format(&self) -> i16 {
913 self.format
914 }
915}
916
917#[inline]
918fn find_null(buf: &[u8], start: usize) -> io::Result<usize> {
919 match memchr(0, &buf[start..]) {
920 Some(pos) => Ok(pos + start),
921 None => Err(io::Error::new(
922 io::ErrorKind::UnexpectedEof,
923 "unexpected EOF",
924 )),
925 }
926}
927
928#[inline]
929fn get_str(buf: &[u8]) -> io::Result<&str> {
930 str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
931}