Skip to main content

zero_mysql/protocol/
primitive.rs

1use 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
7/// Read 1-byte integer
8pub 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
15/// Read 2-byte little-endian integer
16pub 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
27/// Read 3-byte little-endian integer
28pub 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
36/// Read 4-byte little-endian integer
37pub 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
48/// Read 6-byte little-endian integer
49pub 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
59/// Read 8-byte little-endian integer
60pub 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
71/// Read length-encoded integer
72pub 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
94/// Read fixed-length string
95pub 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
106/// Read null-terminated string
107/// TODO: use memchr
108pub 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
119/// Read length-encoded string
120pub 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/// Write 1-byte integer
126#[inline]
127pub fn write_int_1(out: &mut Vec<u8>, value: u8) {
128    out.push(value);
129}
130
131/// Write 2-byte little-endian integer
132#[inline]
133pub fn write_int_2(out: &mut Vec<u8>, value: u16) {
134    out.extend_from_slice(&value.to_le_bytes());
135}
136
137/// Write 3-byte little-endian integer
138#[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/// Write 4-byte little-endian integer
144#[inline]
145pub fn write_int_4(out: &mut Vec<u8>, value: u32) {
146    out.extend_from_slice(&value.to_le_bytes());
147}
148
149/// Write 8-byte little-endian integer
150#[inline]
151pub fn write_int_8(out: &mut Vec<u8>, value: u64) {
152    out.extend_from_slice(&value.to_le_bytes());
153}
154
155/// Write length-encoded integer
156pub 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/// Write fixed-length bytes
172#[inline]
173pub fn write_bytes_fix(out: &mut Vec<u8>, data: &[u8]) {
174    out.extend_from_slice(data);
175}
176
177/// Write null-terminated string
178#[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/// Write length-encoded string
185#[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/// Write length-encoded bytes
192#[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}