use super::WireError;
use prost::alloc::vec::Vec;
#[inline]
pub fn encode_fixed32(value: u32, buf: &mut Vec<u8>) {
buf.extend_from_slice(&value.to_le_bytes());
}
#[inline]
pub fn decode_fixed32(buf: &[u8]) -> Result<(u32, usize), WireError> {
if buf.len() < 4 {
return Err(WireError::UnexpectedEof);
}
let bytes: [u8; 4] = [buf[0], buf[1], buf[2], buf[3]];
Ok((u32::from_le_bytes(bytes), 4))
}
#[inline]
pub fn encode_fixed64(value: u64, buf: &mut Vec<u8>) {
buf.extend_from_slice(&value.to_le_bytes());
}
#[inline]
pub fn decode_fixed64(buf: &[u8]) -> Result<(u64, usize), WireError> {
if buf.len() < 8 {
return Err(WireError::UnexpectedEof);
}
let bytes: [u8; 8] = [
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
];
Ok((u64::from_le_bytes(bytes), 8))
}
#[inline]
pub fn encode_float(value: f32, buf: &mut Vec<u8>) {
encode_fixed32(value.to_bits(), buf);
}
#[inline]
pub fn decode_float(buf: &[u8]) -> Result<(f32, usize), WireError> {
let (bits, consumed) = decode_fixed32(buf)?;
Ok((f32::from_bits(bits), consumed))
}
#[inline]
pub fn encode_double(value: f64, buf: &mut Vec<u8>) {
encode_fixed64(value.to_bits(), buf);
}
#[inline]
pub fn decode_double(buf: &[u8]) -> Result<(f64, usize), WireError> {
let (bits, consumed) = decode_fixed64(buf)?;
Ok((f64::from_bits(bits), consumed))
}
#[inline]
pub fn encode_sfixed32(value: i32, buf: &mut Vec<u8>) {
encode_fixed32(value as u32, buf);
}
#[inline]
pub fn decode_sfixed32(buf: &[u8]) -> Result<(i32, usize), WireError> {
let (bits, consumed) = decode_fixed32(buf)?;
Ok((bits as i32, consumed))
}
#[inline]
pub fn encode_sfixed64(value: i64, buf: &mut Vec<u8>) {
encode_fixed64(value as u64, buf);
}
#[inline]
pub fn decode_sfixed64(buf: &[u8]) -> Result<(i64, usize), WireError> {
let (bits, consumed) = decode_fixed64(buf)?;
Ok((bits as i64, consumed))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fixed32_round_trip() {
let values = [0u32, 1, 255, 256, u32::MAX, 0xDEAD_BEEF];
for &v in &values {
let mut buf = Vec::new();
encode_fixed32(v, &mut buf);
assert_eq!(buf.len(), 4);
let (decoded, consumed) = decode_fixed32(&buf).expect("decode");
assert_eq!(decoded, v);
assert_eq!(consumed, 4);
}
}
#[test]
fn fixed64_round_trip() {
let values = [0u64, 1, u32::MAX as u64, u64::MAX, 0xDEAD_BEEF_CAFE_BABEu64];
for &v in &values {
let mut buf = Vec::new();
encode_fixed64(v, &mut buf);
assert_eq!(buf.len(), 8);
let (decoded, consumed) = decode_fixed64(&buf).expect("decode");
assert_eq!(decoded, v);
assert_eq!(consumed, 8);
}
}
#[test]
fn float_round_trip() {
let values = [0.0f32, 1.0, -1.0, f32::MIN, f32::MAX, f32::EPSILON];
for &v in &values {
let mut buf = Vec::new();
encode_float(v, &mut buf);
let (decoded, _) = decode_float(&buf).expect("decode");
assert_eq!(decoded, v);
}
}
#[test]
fn float_nan_preserved() {
let mut buf = Vec::new();
encode_float(f32::NAN, &mut buf);
let (decoded, _) = decode_float(&buf).expect("decode");
assert!(decoded.is_nan());
}
#[test]
fn double_round_trip() {
let values = [
0.0f64,
1.0,
-1.0,
f64::MIN,
f64::MAX,
f64::EPSILON,
core::f64::consts::PI,
];
for &v in &values {
let mut buf = Vec::new();
encode_double(v, &mut buf);
let (decoded, _) = decode_double(&buf).expect("decode");
assert_eq!(decoded, v);
}
}
#[test]
fn sfixed32_round_trip() {
let values = [0i32, 1, -1, i32::MIN, i32::MAX];
for &v in &values {
let mut buf = Vec::new();
encode_sfixed32(v, &mut buf);
let (decoded, consumed) = decode_sfixed32(&buf).expect("decode");
assert_eq!(decoded, v);
assert_eq!(consumed, 4);
}
}
#[test]
fn sfixed64_round_trip() {
let values = [0i64, 1, -1, i64::MIN, i64::MAX];
for &v in &values {
let mut buf = Vec::new();
encode_sfixed64(v, &mut buf);
let (decoded, consumed) = decode_sfixed64(&buf).expect("decode");
assert_eq!(decoded, v);
assert_eq!(consumed, 8);
}
}
#[test]
fn decode_fixed32_eof() {
assert!(matches!(
decode_fixed32(&[0x01, 0x02]),
Err(WireError::UnexpectedEof)
));
}
#[test]
fn decode_fixed64_eof() {
assert!(matches!(
decode_fixed64(&[0x01, 0x02, 0x03, 0x04]),
Err(WireError::UnexpectedEof)
));
}
#[test]
fn little_endian_order() {
let mut buf = Vec::new();
encode_fixed32(0x01020304, &mut buf);
assert_eq!(buf, &[0x04, 0x03, 0x02, 0x01]);
}
}