zero_mysql/protocol/
primitive.rs1use crate::nightly::{cold_path, unlikely};
2
3use crate::error::{Error, Result, eyre};
4use zerocopy::FromBytes;
5use zerocopy::byteorder::little_endian::{U16 as U16LE, U32 as U32LE, U64 as U64LE};
6
7pub fn read_int_1(data: &[u8]) -> Result<(u8, &[u8])> {
9 if unlikely(data.is_empty()) {
10 return Err(Error::LibraryBug(eyre!("read_int_1: empty buffer")));
11 }
12 Ok((data[0], &data[1..]))
13}
14
15pub fn read_int_2(data: &[u8]) -> Result<(u16, &[u8])> {
17 if unlikely(data.len() < 2) {
18 return Err(Error::LibraryBug(eyre!(
19 "read_int_2: buffer too short: {} < 2",
20 data.len()
21 )));
22 }
23 let value = U16LE::ref_from_bytes(&data[..2])?.get();
24 Ok((value, &data[2..]))
25}
26
27pub fn read_int_3(data: &[u8]) -> Result<(u32, &[u8])> {
29 if unlikely(data.len() < 3) {
30 return Err(Error::LibraryBug(eyre!(
31 "read_int_3: buffer too short: {} < 3",
32 data.len()
33 )));
34 }
35 let value = u32::from_le_bytes([data[0], data[1], data[2], 0]);
36 Ok((value, &data[3..]))
37}
38
39pub fn read_int_4(data: &[u8]) -> Result<(u32, &[u8])> {
41 if unlikely(data.len() < 4) {
42 return Err(Error::LibraryBug(eyre!(
43 "read_int_4: buffer too short: {} < 4",
44 data.len()
45 )));
46 }
47 let value = U32LE::ref_from_bytes(&data[..4])?.get();
48 Ok((value, &data[4..]))
49}
50
51pub fn read_int_6(data: &[u8]) -> Result<(u64, &[u8])> {
53 if unlikely(data.len() < 6) {
54 return Err(Error::LibraryBug(eyre!(
55 "read_int_6: buffer too short: {} < 6",
56 data.len()
57 )));
58 }
59 let value = u64::from_le_bytes([data[0], data[1], data[2], data[3], data[4], data[5], 0, 0]);
60 Ok((value, &data[6..]))
61}
62
63pub fn read_int_8(data: &[u8]) -> Result<(u64, &[u8])> {
65 if unlikely(data.len() < 8) {
66 return Err(Error::LibraryBug(eyre!(
67 "read_int_8: buffer too short: {} < 8",
68 data.len()
69 )));
70 }
71 let value = U64LE::ref_from_bytes(&data[..8])?.get();
72 Ok((value, &data[8..]))
73}
74
75pub fn read_int_lenenc(data: &[u8]) -> Result<(u64, &[u8])> {
77 match data.first() {
78 Some(0xFC) => {
79 let (val, rest) = read_int_2(&data[1..])?;
80 Ok((val as u64, rest))
81 }
82 Some(0xFD) => {
83 let (val, rest) = read_int_3(&data[1..])?;
84 Ok((val as u64, rest))
85 }
86 Some(0xFE) => {
87 let (val, rest) = read_int_8(&data[1..])?;
88 Ok((val, rest))
89 }
90 Some(val) => Ok((*val as u64, &data[1..])),
91 None => {
92 cold_path();
93 Err(Error::LibraryBug(eyre!("read_int_lenenc: empty buffer")))
94 }
95 }
96}
97
98pub fn read_string_fix(data: &[u8], len: usize) -> Result<(&[u8], &[u8])> {
100 if unlikely(data.len() < len) {
101 return Err(Error::LibraryBug(eyre!(
102 "read_string_fix: buffer too short: {} < {}",
103 data.len(),
104 len
105 )));
106 }
107 Ok((&data[..len], &data[len..]))
108}
109
110pub fn read_string_null(data: &[u8]) -> Result<(&[u8], &[u8])> {
113 for (i, &byte) in data.iter().enumerate() {
114 if byte == 0 {
115 return Ok((&data[..i], &data[i + 1..]));
116 }
117 }
118 Err(Error::LibraryBug(eyre!(
119 "read_string_null: no null terminator found"
120 )))
121}
122
123pub fn read_string_lenenc(data: &[u8]) -> Result<(&[u8], &[u8])> {
125 let (len, rest) = read_int_lenenc(data)?;
126 read_string_fix(rest, len as usize)
127}
128
129#[inline]
131pub fn write_int_1(out: &mut Vec<u8>, value: u8) {
132 out.push(value);
133}
134
135#[inline]
137pub fn write_int_2(out: &mut Vec<u8>, value: u16) {
138 out.extend_from_slice(&value.to_le_bytes());
139}
140
141#[inline]
143pub fn write_int_3(out: &mut Vec<u8>, value: u32) {
144 out.extend_from_slice(&value.to_le_bytes()[..3]);
145}
146
147#[inline]
149pub fn write_int_4(out: &mut Vec<u8>, value: u32) {
150 out.extend_from_slice(&value.to_le_bytes());
151}
152
153#[inline]
155pub fn write_int_8(out: &mut Vec<u8>, value: u64) {
156 out.extend_from_slice(&value.to_le_bytes());
157}
158
159pub fn write_int_lenenc(out: &mut Vec<u8>, value: u64) {
161 if value < 251 {
162 out.push(value as u8);
163 } else if value < (1 << 16) {
164 out.push(0xfc);
165 write_int_2(out, value as u16);
166 } else if value < (1 << 24) {
167 out.push(0xfd);
168 write_int_3(out, value as u32);
169 } else {
170 out.push(0xfe);
171 write_int_8(out, value);
172 }
173}
174
175#[inline]
177pub fn write_bytes_fix(out: &mut Vec<u8>, data: &[u8]) {
178 out.extend_from_slice(data);
179}
180
181#[inline]
183pub fn write_string_null(out: &mut Vec<u8>, bytes: &[u8]) {
184 out.extend_from_slice(bytes);
185 out.push(0);
186}
187
188#[inline]
190pub fn write_string_lenenc(out: &mut Vec<u8>, s: &str) {
191 write_int_lenenc(out, s.len() as u64);
192 out.extend_from_slice(s.as_bytes());
193}
194
195#[inline]
197pub fn write_bytes_lenenc(out: &mut Vec<u8>, data: &[u8]) {
198 write_int_lenenc(out, data.len() as u64);
199 out.extend_from_slice(data);
200}