#![allow(unsafe_code)]
use crate::backend::fd::{AsFd, AsRawFd};
use crate::ffi::CStr;
use core::mem::{self, MaybeUninit};
use itoa::{Buffer, Integer};
#[cfg(all(feature = "std", unix))]
use std::os::unix::ffi::OsStrExt;
#[cfg(all(feature = "std", target_os = "wasi"))]
use std::os::wasi::ffi::OsStrExt;
#[cfg(feature = "std")]
use {core::fmt, std::ffi::OsStr, std::path::Path};
#[derive(Clone)]
pub struct DecInt {
buf: [MaybeUninit<u8>; u64::MAX_STR_LEN + 1],
len: usize,
}
const _: () = assert!(u64::MAX_STR_LEN == i64::MAX_STR_LEN);
impl DecInt {
#[inline]
pub fn new<Int: Integer>(i: Int) -> Self {
let mut buf = [MaybeUninit::uninit(); 21];
let mut str_buf = Buffer::new();
let str_buf = str_buf.format(i);
assert!(
str_buf.len() < buf.len(),
"{str_buf}{} unsupported.",
core::any::type_name::<Int>()
);
buf[..str_buf.len()].copy_from_slice(unsafe {
mem::transmute::<&[u8], &[MaybeUninit<u8>]>(str_buf.as_bytes())
});
buf[str_buf.len()] = MaybeUninit::new(0);
Self {
buf,
len: str_buf.len(),
}
}
#[inline]
pub fn from_fd<Fd: AsFd>(fd: Fd) -> Self {
Self::new(fd.as_fd().as_raw_fd())
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
}
#[inline]
pub fn as_c_str(&self) -> &CStr {
let bytes_with_nul = self.as_bytes_with_nul();
debug_assert!(CStr::from_bytes_with_nul(bytes_with_nul).is_ok());
unsafe { CStr::from_bytes_with_nul_unchecked(bytes_with_nul) }
}
#[inline]
pub fn as_bytes_with_nul(&self) -> &[u8] {
let init = &self.buf[..=self.len];
unsafe { mem::transmute::<&[MaybeUninit<u8>], &[u8]>(init) }
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
let bytes = self.as_bytes_with_nul();
&bytes[..bytes.len() - 1]
}
}
#[cfg(feature = "std")]
impl AsRef<Path> for DecInt {
#[inline]
fn as_ref(&self) -> &Path {
let as_os_str: &OsStr = OsStrExt::from_bytes(self.as_bytes());
Path::new(as_os_str)
}
}
#[cfg(feature = "std")]
impl fmt::Debug for DecInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}