use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::{io, mem};
use crate::constants::Wrap;
use crate::endian::{Endian, U16, U32, U64};
use crate::pod::{Pod, bytes_of, bytes_of_slice};
pub trait WritableBuffer {
fn reserve(&mut self, size: u64) -> Result<(), ()>;
fn write_bytes(&mut self, val: &[u8]);
fn write_zeros(&mut self, mut additional: u64) {
while additional > 0 {
let write_amt = additional.min(1024) as usize;
self.write_bytes(&[0; 1024][..write_amt]);
additional -= write_amt as u64;
}
}
}
pub trait WritableBufferExt: WritableBuffer {
fn write_pod<T: Pod>(&mut self, val: &T) {
self.write_bytes(bytes_of(val))
}
fn write_pod_slice<T: Pod>(&mut self, val: &[T]) {
self.write_bytes(bytes_of_slice(val))
}
fn write_u16<E, T>(&mut self, endian: E, val: T)
where
E: Endian,
T: Wrap<Inner = u16> + Copy + 'static,
{
self.write_bytes(bytes_of(&U16::new(endian, val)))
}
fn write_u32<E, T>(&mut self, endian: E, val: T)
where
E: Endian,
T: Wrap<Inner = u32> + Copy + 'static,
{
self.write_bytes(bytes_of(&U32::new(endian, val)))
}
fn write_u64<E, T>(&mut self, endian: E, val: T)
where
E: Endian,
T: Wrap<Inner = u64> + Copy + 'static,
{
self.write_bytes(bytes_of(&U64::new(endian, val)))
}
}
impl<W: WritableBuffer + ?Sized> WritableBufferExt for W {}
impl<W: WritableBuffer + ?Sized> WritableBuffer for &mut W {
#[inline]
fn reserve(&mut self, size: u64) -> Result<(), ()> {
(**self).reserve(size)
}
#[inline]
fn write_bytes(&mut self, val: &[u8]) {
(**self).write_bytes(val)
}
#[inline]
fn write_zeros(&mut self, additional: u64) {
(**self).write_zeros(additional)
}
}
pub trait GrowableBuffer: WritableBuffer {
fn as_writable(&mut self) -> &mut dyn WritableBuffer;
}
pub struct CountingBuffer<W> {
buffer: W,
count: u64,
}
impl<W> core::fmt::Debug for CountingBuffer<W> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("CountingBuffer")
.field("count", &self.count)
.finish_non_exhaustive()
}
}
impl<W> CountingBuffer<W> {
pub fn new(buffer: W) -> Self {
CountingBuffer { buffer, count: 0 }
}
pub fn into_inner(self) -> W {
self.buffer
}
pub fn count(&self) -> u64 {
self.count
}
}
impl<W: WritableBuffer> CountingBuffer<W> {
pub fn resize(&mut self, new_len: u64) {
debug_assert!(new_len >= self.count);
self.write_zeros(new_len.saturating_sub(self.count));
}
pub fn write_align(&mut self, size: u64) {
self.resize(align(self.count, size));
}
}
impl<W: WritableBuffer> WritableBuffer for CountingBuffer<W> {
#[inline]
fn reserve(&mut self, size: u64) -> Result<(), ()> {
self.buffer.reserve(size)
}
#[inline]
fn write_bytes(&mut self, val: &[u8]) {
self.buffer.write_bytes(val);
self.count += val.len() as u64;
}
#[inline]
fn write_zeros(&mut self, additional: u64) {
self.buffer.write_zeros(additional);
self.count += additional;
}
}
impl GrowableBuffer for Vec<u8> {
fn as_writable(&mut self) -> &mut dyn WritableBuffer {
self
}
}
impl WritableBuffer for Vec<u8> {
#[inline]
fn reserve(&mut self, size: u64) -> Result<(), ()> {
debug_assert!(self.is_empty());
let size = usize::try_from(size).map_err(|_| ())?;
self.reserve(size);
Ok(())
}
#[inline]
fn write_bytes(&mut self, val: &[u8]) {
self.extend_from_slice(val)
}
#[inline]
fn write_zeros(&mut self, additional: u64) {
let new_len = self.len() + additional as usize;
self.resize(new_len, 0);
}
}
impl WritableBuffer for &mut [u8] {
#[inline]
fn reserve(&mut self, size: u64) -> Result<(), ()> {
if size > self.len() as u64 {
return Err(());
}
Ok(())
}
#[inline]
fn write_bytes(&mut self, val: &[u8]) {
let (head, tail) = core::mem::take(self).split_at_mut(val.len());
head.copy_from_slice(val);
*self = tail;
}
#[inline]
fn write_zeros(&mut self, additional: u64) {
let (head, tail) = core::mem::take(self).split_at_mut(additional as usize);
head.fill(0);
*self = tail;
}
}
#[cfg(feature = "std")]
#[derive(Debug)]
pub struct StreamingBuffer<W> {
writer: W,
result: Result<(), io::Error>,
}
#[cfg(feature = "std")]
impl<W> StreamingBuffer<W> {
pub fn new(writer: W) -> Self {
StreamingBuffer {
writer,
result: Ok(()),
}
}
pub fn into_inner(self) -> W {
self.writer
}
pub fn result(&mut self) -> Result<(), io::Error> {
mem::replace(&mut self.result, Ok(()))
}
}
#[cfg(feature = "std")]
impl<W: io::Write> StreamingBuffer<W> {
pub fn flush(&mut self) -> Result<(), io::Error> {
self.result()?;
self.writer.flush()
}
}
#[cfg(feature = "std")]
impl<W: io::Write> GrowableBuffer for StreamingBuffer<W> {
fn as_writable(&mut self) -> &mut dyn WritableBuffer {
self
}
}
#[cfg(feature = "std")]
impl<W: io::Write> WritableBuffer for StreamingBuffer<W> {
#[inline]
fn reserve(&mut self, _size: u64) -> Result<(), ()> {
Ok(())
}
#[inline]
fn write_bytes(&mut self, val: &[u8]) {
if self.result.is_ok() {
self.result = self.writer.write_all(val);
}
}
}
#[allow(dead_code)]
pub(crate) fn write_uleb128(buf: &mut Vec<u8>, mut val: u64) -> usize {
let mut len = 0;
loop {
let mut byte = (val & 0x7f) as u8;
val >>= 7;
let done = val == 0;
if !done {
byte |= 0x80;
}
buf.push(byte);
len += 1;
if done {
return len;
}
}
}
#[allow(dead_code)]
pub(crate) fn write_sleb128(buf: &mut Vec<u8>, mut val: i64) -> usize {
let mut len = 0;
loop {
let mut byte = val as u8;
val >>= 6;
let done = val == 0 || val == -1;
if done {
byte &= !0x80;
} else {
val >>= 1;
byte |= 0x80;
}
buf.push(byte);
len += 1;
if done {
return len;
}
}
}
#[allow(dead_code)]
pub(crate) fn align_u32(offset: u32, size: u32) -> u32 {
(offset + (size - 1)) & !(size - 1)
}
#[allow(dead_code)]
pub(crate) fn align(offset: u64, size: u64) -> u64 {
(offset + (size - 1)) & !(size - 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slice_buffer() {
let mut data = [0u8; 4];
assert_eq!((&mut data[..]).reserve(5), Err(()));
assert_eq!((&mut data[..]).reserve(4), Ok(()));
assert_eq!((&mut data[..]).reserve(3), Ok(()));
let mut data = [0xffu8; 9];
let mut slice = &mut data[..];
let mut buffer = CountingBuffer::new(&mut slice);
buffer.write_bytes(&[1, 2, 3]);
assert_eq!(buffer.count(), 3);
buffer.write_zeros(2);
assert_eq!(buffer.count(), 5);
buffer.write_align(4);
assert_eq!(buffer.count(), 8);
assert_eq!(data, [1, 2, 3, 0, 0, 0, 0, 0, 0xff]);
}
}