1use rupg_common::SqlState;
8
9use crate::error::TypeError;
10use crate::scalar::NAME_MAX_BYTES;
11
12#[derive(Debug, Clone)]
14pub struct Recv<'a> {
15 data: &'a [u8],
16 at: usize,
17}
18
19impl<'a> Recv<'a> {
20 pub fn new(data: &'a [u8]) -> Recv<'a> {
21 Recv { data, at: 0 }
22 }
23
24 pub fn bytes(&mut self, len: usize) -> Result<&'a [u8], TypeError> {
26 let Some(bytes) = self.data.get(self.at..self.at.saturating_add(len)) else {
27 return Err(TypeError::new(
28 SqlState::PROTOCOL_VIOLATION,
29 "insufficient data left in message".to_string(),
30 ));
31 };
32 self.at += len;
33 Ok(bytes)
34 }
35
36 fn array<const N: usize>(&mut self) -> Result<[u8; N], TypeError> {
37 let mut out = [0; N];
38 out.copy_from_slice(self.bytes(N)?);
39 Ok(out)
40 }
41
42 pub fn remaining(&self) -> usize {
44 self.data.len() - self.at
45 }
46
47 pub fn byte(&mut self) -> Result<u8, TypeError> {
49 let Some(&byte) = self.data.get(self.at) else {
50 return Err(TypeError::new(
51 SqlState::PROTOCOL_VIOLATION,
52 "no data left in message".to_string(),
53 ));
54 };
55 self.at += 1;
56 Ok(byte)
57 }
58
59 pub fn rest(&mut self) -> &'a [u8] {
61 let rest = &self.data[self.at..];
62 self.at = self.data.len();
63 rest
64 }
65
66 pub fn text(&mut self) -> Result<&'a str, TypeError> {
68 utf8(self.rest())
69 }
70
71 pub fn cstring(&mut self) -> Result<&'a str, TypeError> {
73 let rest = &self.data[self.at..];
74 let Some(len) = rest.iter().position(|&b| b == 0) else {
75 return Err(TypeError::new(
76 SqlState::PROTOCOL_VIOLATION,
77 "invalid string in message".to_string(),
78 ));
79 };
80 self.at += len + 1;
81 utf8(&rest[..len])
82 }
83
84 pub fn bool(&mut self) -> Result<bool, TypeError> {
86 Ok(self.byte()? != 0)
87 }
88
89 pub fn i16(&mut self) -> Result<i16, TypeError> {
90 self.array().map(i16::from_be_bytes)
91 }
92
93 pub fn i32(&mut self) -> Result<i32, TypeError> {
94 self.array().map(i32::from_be_bytes)
95 }
96
97 pub fn i64(&mut self) -> Result<i64, TypeError> {
98 self.array().map(i64::from_be_bytes)
99 }
100
101 pub fn u32(&mut self) -> Result<u32, TypeError> {
103 self.array().map(u32::from_be_bytes)
104 }
105
106 pub fn f32(&mut self) -> Result<f32, TypeError> {
107 self.array().map(f32::from_be_bytes)
108 }
109
110 pub fn f64(&mut self) -> Result<f64, TypeError> {
111 self.array().map(f64::from_be_bytes)
112 }
113
114 pub fn uuid(&mut self) -> Result<[u8; 16], TypeError> {
115 self.array()
116 }
117
118 pub fn finish(self, number: usize) -> Result<(), TypeError> {
120 if self.at == self.data.len() {
121 return Ok(());
122 }
123 let message = if number == 0 {
125 "incorrect binary data format".to_string()
126 } else {
127 format!("incorrect binary data format in bind parameter {number}")
128 };
129 Err(TypeError::new(SqlState::INVALID_BINARY_REPRESENTATION, message))
130 }
131}
132
133fn utf8(rest: &[u8]) -> Result<&str, TypeError> {
135 let valid = match std::str::from_utf8(rest) {
136 Ok(text) if !text.contains('\0') => return Ok(text),
137 Ok(text) => text.len(),
138 Err(error) => error.valid_up_to(),
139 };
140 let bad = rest[..valid].iter().position(|&b| b == 0).unwrap_or(valid);
141 let len = match rest[bad] {
143 b if b & 0x80 == 0 => 1,
144 b if b & 0xe0 == 0xc0 => 2,
145 b if b & 0xf0 == 0xe0 => 3,
146 b if b & 0xf8 == 0xf0 => 4,
147 _ => 1,
148 };
149 let bytes: Vec<String> = rest[bad..].iter().take(len).map(|b| format!("0x{b:02x}")).collect();
150 Err(TypeError::new(
151 SqlState::CHARACTER_NOT_IN_REPERTOIRE,
152 format!("invalid byte sequence for encoding \"UTF8\": {}", bytes.join(" ")),
153 ))
154}
155
156pub fn name_recv(text: &str) -> Result<&str, TypeError> {
158 if text.len() <= NAME_MAX_BYTES {
159 return Ok(text);
160 }
161 let mut error = TypeError::new(SqlState::NAME_TOO_LONG, "identifier too long".to_string());
162 error.detail = Some(format!("Identifier must be less than {} characters.", NAME_MAX_BYTES + 1));
163 Err(error)
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn a_value_must_have_the_size_of_its_type() {
172 let mut recv = Recv::new(&[0, 0, 0, 42]);
173 assert_eq!(recv.i32(), Ok(42));
174 assert_eq!(recv.finish(1), Ok(()));
175
176 let mut recv = Recv::new(&[0, 0, 42]);
177 let short = recv.i32().unwrap_err();
178 assert_eq!(
179 (short.sqlstate.as_str(), short.message.as_str()),
180 ("08P01", "insufficient data left in message")
181 );
182
183 let mut recv = Recv::new(&[0, 0, 0, 0, 42]);
184 assert_eq!(recv.i32(), Ok(0));
185 let long = recv.finish(3).unwrap_err();
186 assert_eq!(
187 (long.sqlstate.as_str(), long.message.as_str()),
188 ("22P03", "incorrect binary data format in bind parameter 3")
189 );
190
191 assert_eq!(Recv::new(&[]).bool().unwrap_err().message, "no data left in message");
192 assert_eq!(Recv::new(&[7]).bool(), Ok(true));
193 assert_eq!(Recv::new(&1.5f64.to_be_bytes()).f64(), Ok(1.5));
194 assert_eq!(Recv::new(&[0xff; 4]).u32(), Ok(u32::MAX));
195 let mut recv = Recv::new(b"abc");
196 assert_eq!((recv.rest(), recv.finish(1)), (&b"abc"[..], Ok(())));
197 }
198
199 #[test]
200 fn a_string_must_be_utf8_with_no_zero_byte() {
201 assert_eq!(Recv::new("aé".as_bytes()).text(), Ok("aé"));
202 let message = |bytes: &[u8]| Recv::new(bytes).text().unwrap_err().message;
203 assert_eq!(message(b"a\0b"), "invalid byte sequence for encoding \"UTF8\": 0x00");
204 assert_eq!(message(b"a\xc3("), "invalid byte sequence for encoding \"UTF8\": 0xc3 0x28");
205 assert_eq!(message(b"\xe2\x82"), "invalid byte sequence for encoding \"UTF8\": 0xe2 0x82");
206 assert_eq!(message(b"\xff"), "invalid byte sequence for encoding \"UTF8\": 0xff");
207 assert_eq!(Recv::new(b"\xed\xa0\x80").text().unwrap_err().sqlstate.as_str(), "22021");
208 }
209
210 #[test]
211 fn a_long_name_is_an_error_in_binary() {
212 assert_eq!(name_recv(&"n".repeat(63)).map(str::len), Ok(63));
213 let error = name_recv(&"n".repeat(64)).unwrap_err();
214 assert_eq!(
215 (error.sqlstate.as_str(), error.message.as_str()),
216 ("42622", "identifier too long")
217 );
218 assert_eq!(error.detail.as_deref(), Some("Identifier must be less than 64 characters."));
219 }
220}