use super::{AllHeaderTy, Packet, PacketCodec, ALL_HEADERS_LEN_TX};
use asynchronous_codec::Encoder;
use bytes::{BufMut, BytesMut};
pub(crate) trait Encode<B: BufMut> {
fn encode(self, dst: &mut B) -> crate::Result<()>;
}
pub(crate) fn encode_b_varchar(dst: &mut BytesMut, s: &str) -> crate::Result<()> {
let units: Vec<u16> = s.encode_utf16().collect();
if units.len() > u8::MAX as usize {
return Err(crate::Error::Protocol(
format!(
"string is too long for a B_VARCHAR ({} UTF-16 code units, max 255)",
units.len()
)
.into(),
));
}
dst.put_u8(units.len() as u8);
for unit in units {
dst.put_u16_le(unit);
}
Ok(())
}
pub(crate) fn encode_all_headers_tx(dst: &mut BytesMut, transaction_desc: [u8; 8]) {
dst.put_u32_le(ALL_HEADERS_LEN_TX as u32);
dst.put_u32_le(ALL_HEADERS_LEN_TX as u32 - 4);
dst.put_u16_le(AllHeaderTy::TransactionDescriptor as u16);
dst.put_slice(&transaction_desc);
dst.put_u32_le(1);
}
impl Encoder for PacketCodec {
type Item<'a> = Packet;
type Error = crate::Error;
fn encode(&mut self, item: Packet, dst: &mut BytesMut) -> Result<(), Self::Error> {
item.encode(dst)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tds::codec::{PacketHeader, PacketType};
#[test]
fn encode_writes_header_and_payload_to_dst() {
let payload = BytesMut::from(&b"abcd"[..]);
let packet = Packet::new(PacketHeader::batch(1), payload);
let mut dst = BytesMut::new();
let mut codec = PacketCodec;
codec.encode(packet, &mut dst).expect("encode must succeed");
assert_eq!(dst.len(), 12);
assert_eq!(dst[0], PacketType::SQLBatch as u8);
assert_eq!(&dst[2..4], &12u16.to_be_bytes());
assert_eq!(&dst[8..], b"abcd");
}
#[test]
fn encode_b_varchar_is_byte_exact() {
let mut dst = BytesMut::new();
encode_b_varchar(&mut dst, "Hi").unwrap();
let mut expected = Vec::new();
expected.push(2u8); expected.extend_from_slice(&('H' as u16).to_le_bytes());
expected.extend_from_slice(&('i' as u16).to_le_bytes());
assert_eq!(&dst[..], &expected[..]);
}
#[test]
fn encode_b_varchar_empty_writes_zero_length() {
let mut dst = BytesMut::new();
encode_b_varchar(&mut dst, "").unwrap();
assert_eq!(&dst[..], &[0u8]);
}
#[test]
fn encode_b_varchar_accepts_255_units() {
let name = "a".repeat(255);
let mut dst = BytesMut::new();
encode_b_varchar(&mut dst, &name).expect("255-unit string must encode");
assert_eq!(dst[0], 255);
assert_eq!(dst.len(), 1 + 255 * 2);
}
#[test]
fn encode_b_varchar_rejects_256_units() {
let name = "a".repeat(256);
let mut dst = BytesMut::new();
let err = encode_b_varchar(&mut dst, &name).unwrap_err();
assert!(matches!(err, crate::Error::Protocol(_)), "got {err:?}");
}
#[test]
fn encode_all_headers_tx_is_byte_exact() {
let td = [1u8, 2, 3, 4, 5, 6, 7, 8];
let mut dst = BytesMut::new();
encode_all_headers_tx(&mut dst, td);
let mut expected = Vec::new();
expected.extend_from_slice(&22u32.to_le_bytes()); expected.extend_from_slice(&18u32.to_le_bytes()); expected.extend_from_slice(&2u16.to_le_bytes()); expected.extend_from_slice(&td); expected.extend_from_slice(&1u32.to_le_bytes());
assert_eq!(&dst[..], &expected[..]);
}
}