use core::fmt::{self, Write};
use core::mem::MaybeUninit;
pub(crate) trait Output {
fn write(&mut self, bytes: &[u8]);
#[inline]
fn write_byte(&mut self, byte: u8) {
self.write(&[byte])
}
#[inline]
fn remaining(&self) -> Option<usize> {
None
}
}
impl Output for &mut [u8] {
#[inline]
fn write(&mut self, bytes: &[u8]) {
let this = crate::impl_core::slice_as_uninit_mut(self);
unsafe {
let count = write_bytes_output_slice(this, bytes);
advance_slice(self, count);
}
}
#[inline]
fn remaining(&self) -> Option<usize> {
Some(self.len())
}
}
impl Output for &mut [MaybeUninit<u8>] {
#[inline]
fn write(&mut self, bytes: &[u8]) {
unsafe {
let count = write_bytes_output_slice(self, bytes);
advance_slice(self, count);
}
}
#[inline]
fn remaining(&self) -> Option<usize> {
Some(self.len())
}
}
pub(crate) struct FormatterOutput<'a, 'b> {
f: &'a mut fmt::Formatter<'b>,
result: fmt::Result,
}
impl<'a, 'b> FormatterOutput<'a, 'b> {
#[inline]
pub(crate) fn new(f: &'a mut fmt::Formatter<'b>) -> Self {
Self { f, result: Ok(()) }
}
#[inline]
pub(crate) const fn finish(&self) -> fmt::Result {
self.result
}
}
impl Output for &mut FormatterOutput<'_, '_> {
#[inline]
fn write(&mut self, bytes: &[u8]) {
if self.result.is_err() {
return;
}
if cfg!(debug_assertions) {
core::str::from_utf8(bytes).unwrap();
}
self.result = self
.f
.write_str(unsafe { core::str::from_utf8_unchecked(bytes) });
}
#[inline]
fn write_byte(&mut self, byte: u8) {
if self.result.is_err() {
return;
}
self.result = self.f.write_char(byte as char);
}
}
#[inline(always)]
unsafe fn write_bytes_output_slice(output: &mut [MaybeUninit<u8>], bytes: &[u8]) -> usize {
let src = bytes.as_ptr().cast::<MaybeUninit<u8>>();
let dst = output.as_mut_ptr();
let count = bytes.len();
debug_assert!(output.len() >= count);
unsafe { dst.copy_from_nonoverlapping(src, count) };
count
}
#[inline(always)]
unsafe fn advance_slice<T>(slice: &mut &mut [T], count: usize) {
debug_assert!(slice.len() >= count);
let len = slice.len();
let ptr = slice.as_mut_ptr();
*slice = core::slice::from_raw_parts_mut(ptr.add(count), len - count);
}