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