use core::fmt;
pub type Result<T = ()> = core::result::Result<T, bun_core::Error>;
pub use bun_core::write::{IntBe, IntLe, Write};
#[derive(Default)]
pub struct DiscardingWriter {
pub count: usize,
}
impl DiscardingWriter {
#[inline]
pub const fn new() -> Self {
Self { count: 0 }
}
}
impl Write for DiscardingWriter {
#[inline]
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
self.count += buf.len();
Ok(())
}
#[inline]
fn splat_byte_all(&mut self, _byte: u8, n: usize) -> Result<()> {
self.count += n;
Ok(())
}
#[inline]
fn written_len(&self) -> usize {
self.count
}
}
pub struct FixedBufferStream<B> {
pub buffer: B,
pub pos: usize,
}
impl<B> FixedBufferStream<B> {
#[inline]
pub fn new(buffer: B) -> Self {
Self { buffer, pos: 0 }
}
#[inline]
pub fn seek_to(&mut self, p: usize) {
self.pos = p;
}
#[inline]
pub fn reset(&mut self) {
self.pos = 0;
}
}
impl<'a> FixedBufferStream<&'a mut [u8]> {
#[inline]
pub fn new_mut(buffer: &'a mut [u8]) -> Self {
Self { buffer, pos: 0 }
}
}
impl<B: AsRef<[u8]>> FixedBufferStream<B> {
#[inline]
pub fn get_written(&self) -> &[u8] {
&self.buffer.as_ref()[..self.pos]
}
#[inline]
pub fn get_pos(&self) -> Result<usize> {
Ok(self.pos)
}
#[inline]
pub fn reader(&mut self) -> &mut Self {
self
}
pub fn read_all(&mut self, out: &mut [u8]) -> Result<usize> {
let buf = self.buffer.as_ref();
let avail = buf.len().saturating_sub(self.pos);
let n = avail.min(out.len());
out[..n].copy_from_slice(&buf[self.pos..self.pos + n]);
self.pos += n;
Ok(n)
}
pub fn read_exact(&mut self, out: &mut [u8]) -> Result<()> {
let buf = self.buffer.as_ref();
let end = self
.pos
.checked_add(out.len())
.ok_or_else(|| bun_core::err!("EndOfStream"))?;
if end > buf.len() {
return Err(bun_core::err!("EndOfStream"));
}
out.copy_from_slice(&buf[self.pos..end]);
self.pos = end;
Ok(())
}
#[inline]
pub fn read_int_le<I: IntLe>(&mut self) -> Result<I> {
let mut bytes = I::Bytes::default();
self.read_exact(bytes.as_mut())?;
Ok(I::from_le_bytes(bytes))
}
#[inline]
pub fn read_int_be<I: IntBe>(&mut self) -> Result<I> {
let mut bytes = I::Bytes::default();
self.read_exact(bytes.as_mut())?;
Ok(I::from_be_bytes(bytes))
}
pub fn read_struct<T: Copy>(&mut self) -> Result<T> {
let buf = self.buffer.as_ref();
let n = core::mem::size_of::<T>();
let end = self
.pos
.checked_add(n)
.ok_or_else(|| bun_core::err!("EndOfStream"))?;
if end > buf.len() {
return Err(bun_core::err!("EndOfStream"));
}
let out = unsafe { core::ptr::read_unaligned(buf[self.pos..end].as_ptr().cast::<T>()) };
self.pos = end;
Ok(out)
}
}
impl<B: AsMut<[u8]>> Write for FixedBufferStream<B> {
fn write_all(&mut self, src: &[u8]) -> Result<()> {
let buf = self.buffer.as_mut();
let end = self
.pos
.checked_add(src.len())
.ok_or_else(|| bun_core::err!("NoSpaceLeft"))?;
if end > buf.len() {
return Err(bun_core::err!("NoSpaceLeft"));
}
buf[self.pos..end].copy_from_slice(src);
self.pos = end;
Ok(())
}
#[inline]
fn written_len(&self) -> usize {
self.pos
}
}
pub struct BufWriter<'a, W: Write> {
buf: &'a mut [u8],
pos: usize,
inner: W,
}
impl<'a, W: Write> BufWriter<'a, W> {
#[inline]
pub fn with_buffer(buf: &'a mut [u8], inner: W) -> Self {
Self { buf, pos: 0, inner }
}
#[inline]
pub fn buffered(&self) -> &[u8] {
&self.buf[..self.pos]
}
#[inline]
pub fn into_inner(self) -> W {
self.inner
}
#[inline]
pub fn inner(&mut self) -> &mut W {
&mut self.inner
}
#[inline]
fn flush_buf(&mut self) -> Result<()> {
if self.pos > 0 {
self.inner.write_all(&self.buf[..self.pos])?;
self.pos = 0;
}
Ok(())
}
}
impl<'a, W: Write> Write for BufWriter<'a, W> {
fn write_all(&mut self, mut src: &[u8]) -> Result<()> {
if self.buf.is_empty() {
return self.inner.write_all(src);
}
if src.len() >= self.buf.len() {
self.flush_buf()?;
return self.inner.write_all(src);
}
let avail = self.buf.len() - self.pos;
if src.len() > avail {
self.buf[self.pos..].copy_from_slice(&src[..avail]);
self.pos = self.buf.len();
self.flush_buf()?;
src = &src[avail..];
}
self.buf[self.pos..self.pos + src.len()].copy_from_slice(src);
self.pos += src.len();
Ok(())
}
#[inline]
fn flush(&mut self) -> Result<()> {
self.flush_buf()?;
self.inner.flush()
}
}
pub struct FmtAdapter<'a, W: ?Sized = fmt::Formatter<'a>> {
inner: &'a mut W,
}
impl<'a, W: fmt::Write + ?Sized> FmtAdapter<'a, W> {
#[inline]
pub fn new(inner: &'a mut W) -> Self {
Self { inner }
}
#[inline]
pub fn inner(&mut self) -> &mut W {
self.inner
}
}
impl<W: fmt::Write + ?Sized> fmt::Write for FmtAdapter<'_, W> {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
self.inner.write_str(s)
}
}
impl<W: fmt::Write> Write for FmtAdapter<'_, W> {
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
let r = match bun_core::str_utf8(buf) {
Some(s) => self.inner.write_str(s),
None => self.inner.write_str(&String::from_utf8_lossy(buf)),
};
r.map_err(|_| bun_core::err!("FmtError"))
}
#[inline]
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> {
self.inner
.write_fmt(args)
.map_err(|_| bun_core::err!("FmtError"))
}
}
pub struct AsFmt<'a> {
sink: &'a mut dyn Write,
pub err: Option<bun_core::Error>,
}
impl<'a> AsFmt<'a> {
#[inline]
pub fn new(sink: &'a mut dyn Write) -> Self {
Self { sink, err: None }
}
}
impl fmt::Write for AsFmt<'_> {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.sink.write_all(s.as_bytes()) {
Ok(()) => Ok(()),
Err(e) => {
self.err = Some(e);
Err(fmt::Error)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vec_sink() {
let mut v = Vec::new();
v.write_all(b"hello").unwrap();
v.write_byte(b' ').unwrap();
v.splat_byte_all(b'!', 3).unwrap();
v.write_int_le::<u16>(0x0201).unwrap();
assert_eq!(v, b"hello !!!\x01\x02");
}
#[test]
fn buf_writer_basic() {
let mut sink = Vec::new();
let mut scratch = [0u8; 4];
{
let mut w = BufWriter::with_buffer(&mut scratch, &mut sink);
w.write_all(b"ab").unwrap();
w.write_all(b"cd").unwrap(); w.write_all(b"e").unwrap(); w.flush().unwrap();
}
assert_eq!(sink, b"abcde");
}
#[test]
fn buf_writer_large_bypass() {
let mut sink = Vec::new();
let mut scratch = [0u8; 4];
let mut w = BufWriter::with_buffer(&mut scratch, &mut sink);
w.write_all(b"x").unwrap();
w.write_all(b"0123456789").unwrap(); w.flush().unwrap();
assert_eq!(sink, b"x0123456789");
}
#[test]
fn fmt_adapter() {
let mut s = String::new();
{
let mut a = FmtAdapter::new(&mut s);
a.write_all(b"hi ").unwrap();
write!(a, "{}", 42).expect("infallible: in-memory write");
}
assert_eq!(s, "hi 42");
}
}