LCOV - code coverage report
Current view: top level - libs/proxy/postgres-protocol2/src/message - backend.rs (source / functions) Coverage Total Hit
Test: 4be46b1c0003aa3bbac9ade362c676b419df4c20.info Lines: 31.7 % 350 111
Test Date: 2025-07-22 17:50:06 Functions: 46.7 % 45 21

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

Generated by: LCOV version 2.1-beta