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