use super::put::*;
use core::mem::MaybeUninit;
type Mu8 = MaybeUninit<u8>;
pub struct UncheckedBufWriter<'a> {
buf: &'a mut [Mu8],
written: usize,
}
impl<'a> UncheckedBufWriter<'a> {
pub fn new(buf: &'a mut [Mu8]) -> Self {
Self { buf, written: 0 }
}
pub fn written(&self) -> usize {
self.written
}
#[inline]
unsafe fn reserve<'s>(&'s mut self, len: usize) -> &'s mut [Mu8]
where
'a: 's,
{
let extent = self.written + len;
debug_assert!(
extent <= self.buf.len(),
"UncheckedBufWriter: buffer overflow"
);
let start = self.written;
self.written = extent;
unsafe { self.buf.get_unchecked_mut(start..extent) }
}
}
impl PutUnchecked for UncheckedBufWriter<'_> {
#[inline]
unsafe fn put_byte(&mut self, b: u8) {
unsafe {
let p = self.reserve(1);
p.get_unchecked_mut(0).write(b);
}
}
#[inline]
unsafe fn put_bytes(&mut self, bytes: &[u8]) {
let buf = unsafe { self.reserve(bytes.len()) };
buf.write_copy_of_slice(bytes);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::serialize::writer_unchecked::WriterUnchecked;
fn check<T: crate::WriteXDR>(v: &T, write_unchecked: impl FnOnce(&mut UncheckedBufWriter)) {
let mut cbuf = [MaybeUninit::uninit(); 64];
let clen = crate::cxs::encode_into(v, &mut cbuf).unwrap();
let mut ubuf = [MaybeUninit::uninit(); 64];
let mut w = UncheckedBufWriter::new(&mut ubuf);
write_unchecked(&mut w);
let ulen = w.written();
assert_eq!(clen, ulen);
let (c, u) = unsafe {
(
cbuf[..clen].assume_init_ref(),
ubuf[..ulen].assume_init_ref(),
)
};
assert_eq!(c, u);
}
#[test]
fn u32_all_widths() {
for n in [0u32, 62, 63, 255, 256, 65535, 65536, u32::MAX] {
check(&n, |w| unsafe { WriterUnchecked::<CXS>::write_u32(w, n) });
}
}
#[test]
fn i32_all_widths() {
for n in [
0i32,
31,
-31,
32,
-32,
127,
-128,
128,
-129,
i32::MAX,
i32::MIN,
] {
check(&n, |w| unsafe { WriterUnchecked::<CXS>::write_i32(w, n) });
}
}
#[test]
fn i64_u64_and_16bit() {
for n in [0i64, i32::MAX as i64, i32::MAX as i64 + 1, i64::MIN] {
check(&n, |w| unsafe { WriterUnchecked::<CXS>::write_i64(w, n) });
}
for n in [0u64, u32::MAX as u64, u32::MAX as u64 + 1, u64::MAX] {
check(&n, |w| unsafe { WriterUnchecked::<CXS>::write_u64(w, n) });
}
for n in [0u16, 62, 63, 255, 256, u16::MAX] {
check(&n, |w| unsafe { WriterUnchecked::<CXS>::write_u16(w, n) });
}
for n in [0i16, 31, -31, 32, i16::MAX, i16::MIN] {
check(&n, |w| unsafe { WriterUnchecked::<CXS>::write_i16(w, n) });
}
}
#[test]
fn bool_floats_opaque() {
check(&true, |w| unsafe {
WriterUnchecked::<CXS>::write_bool(w, true)
});
check(&1.5f32, |w| unsafe {
WriterUnchecked::<CXS>::write_f32(w, 1.5)
});
check(&1.5f64, |w| unsafe {
WriterUnchecked::<CXS>::write_f64(w, 1.5)
});
let bytes: &[u8] = b"hello";
check(&bytes, |w| unsafe {
WriterUnchecked::<CXS>::write_opaque_variable(w, b"hello")
});
}
#[cfg(debug_assertions)]
#[test]
#[should_panic(expected = "UncheckedBufWriter: buffer overflow")]
fn overflow_debug_asserts() {
let mut buf: [Mu8; 0] = [];
let mut w = UncheckedBufWriter::new(&mut buf);
unsafe { WriterUnchecked::<CXS>::write_u32(&mut w, 1) };
}
}