LCOV - code coverage report
Current view: top level - libs/proxy/postgres-protocol2/src/message - backend.rs (source / functions) Coverage Total Hit
Test: 07bee600374ccd486c69370d0972d9035964fe68.info Lines: 39.1 % 379 148
Test Date: 2025-02-20 13:11:02 Functions: 43.8 % 48 21

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

Generated by: LCOV version 2.1-beta