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 let (&byte, rest) = data
10 .split_first()
11 .ok_or_else(|| Error::LibraryBug(eyre!("read_int_1: empty buffer")))?;
12 Ok((byte, rest))
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 let (chunk, rest) = data.split_first_chunk::<3>().ok_or_else(|| {
30 Error::LibraryBug(eyre!("read_int_3: buffer too short: {} < 3", data.len()))
31 })?;
32 let value = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], 0]);
33 Ok((value, rest))
34}
35
36pub fn read_int_4(data: &[u8]) -> Result<(u32, &[u8])> {
38 if unlikely(data.len() < 4) {
39 return Err(Error::LibraryBug(eyre!(
40 "read_int_4: buffer too short: {} < 4",
41 data.len()
42 )));
43 }
44 let value = U32LE::ref_from_bytes(&data[..4])?.get();
45 Ok((value, &data[4..]))
46}
47
48pub fn read_int_6(data: &[u8]) -> Result<(u64, &[u8])> {
50 let (chunk, rest) = data.split_first_chunk::<6>().ok_or_else(|| {
51 Error::LibraryBug(eyre!("read_int_6: buffer too short: {} < 6", data.len()))
52 })?;
53 let value = u64::from_le_bytes([
54 chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], chunk[5], 0, 0,
55 ]);
56 Ok((value, rest))
57}
58
59pub fn read_int_8(data: &[u8]) -> Result<(u64, &[u8])> {
61 if unlikely(data.len() < 8) {
62 return Err(Error::LibraryBug(eyre!(
63 "read_int_8: buffer too short: {} < 8",
64 data.len()
65 )));
66 }
67 let value = U64LE::ref_from_bytes(&data[..8])?.get();
68 Ok((value, &data[8..]))
69}
70
71pub fn read_int_lenenc(data: &[u8]) -> Result<(u64, &[u8])> {
73 match data.first() {
74 Some(0xFC) => {
75 let (val, rest) = read_int_2(&data[1..])?;
76 Ok((val as u64, rest))
77 }
78 Some(0xFD) => {
79 let (val, rest) = read_int_3(&data[1..])?;
80 Ok((val as u64, rest))
81 }
82 Some(0xFE) => {
83 let (val, rest) = read_int_8(&data[1..])?;
84 Ok((val, rest))
85 }
86 Some(val) => Ok((*val as u64, &data[1..])),
87 None => {
88 cold_path();
89 Err(Error::LibraryBug(eyre!("read_int_lenenc: empty buffer")))
90 }
91 }
92}
93
94pub fn read_string_fix(data: &[u8], len: usize) -> Result<(&[u8], &[u8])> {
96 if unlikely(data.len() < len) {
97 return Err(Error::LibraryBug(eyre!(
98 "read_string_fix: buffer too short: {} < {}",
99 data.len(),
100 len
101 )));
102 }
103 Ok((&data[..len], &data[len..]))
104}
105
106pub fn read_string_null(data: &[u8]) -> Result<(&[u8], &[u8])> {
109 for (i, &byte) in data.iter().enumerate() {
110 if byte == 0 {
111 return Ok((&data[..i], &data[i + 1..]));
112 }
113 }
114 Err(Error::LibraryBug(eyre!(
115 "read_string_null: no null terminator found"
116 )))
117}
118
119pub fn read_string_lenenc(data: &[u8]) -> Result<(&[u8], &[u8])> {
121 let (len, rest) = read_int_lenenc(data)?;
122 read_string_fix(rest, len as usize)
123}
124
125#[inline]
127pub fn write_int_1(out: &mut Vec<u8>, value: u8) {
128 out.push(value);
129}
130
131#[inline]
133pub fn write_int_2(out: &mut Vec<u8>, value: u16) {
134 out.extend_from_slice(&value.to_le_bytes());
135}
136
137#[inline]
139pub fn write_int_3(out: &mut Vec<u8>, value: u32) {
140 out.extend_from_slice(&value.to_le_bytes()[..3]);
141}
142
143#[inline]
145pub fn write_int_4(out: &mut Vec<u8>, value: u32) {
146 out.extend_from_slice(&value.to_le_bytes());
147}
148
149#[inline]
151pub fn write_int_8(out: &mut Vec<u8>, value: u64) {
152 out.extend_from_slice(&value.to_le_bytes());
153}
154
155pub fn write_int_lenenc(out: &mut Vec<u8>, value: u64) {
157 if value < 251 {
158 out.push(value as u8);
159 } else if value < (1 << 16) {
160 out.push(0xfc);
161 write_int_2(out, value as u16);
162 } else if value < (1 << 24) {
163 out.push(0xfd);
164 write_int_3(out, value as u32);
165 } else {
166 out.push(0xfe);
167 write_int_8(out, value);
168 }
169}
170
171#[inline]
173pub fn write_bytes_fix(out: &mut Vec<u8>, data: &[u8]) {
174 out.extend_from_slice(data);
175}
176
177#[inline]
179pub fn write_string_null(out: &mut Vec<u8>, bytes: &[u8]) {
180 out.extend_from_slice(bytes);
181 out.push(0);
182}
183
184#[inline]
186pub fn write_string_lenenc(out: &mut Vec<u8>, s: &str) {
187 write_int_lenenc(out, s.len() as u64);
188 out.extend_from_slice(s.as_bytes());
189}
190
191#[inline]
193pub fn write_bytes_lenenc(out: &mut Vec<u8>, data: &[u8]) {
194 write_int_lenenc(out, data.len() as u64);
195 out.extend_from_slice(data);
196}