1#![allow(unsafe_code)]
8
9use crate::backend::fd::{AsFd, AsRawFd};
10use crate::ffi::CStr;
11use core::mem::{self, MaybeUninit};
12use itoa::{Buffer, Integer};
13#[cfg(all(feature = "std", unix))]
14use std::os::unix::ffi::OsStrExt;
15#[cfg(all(feature = "std", target_os = "wasi"))]
16use std::os::wasi::ffi::OsStrExt;
17#[cfg(feature = "std")]
18use {core::fmt, std::ffi::OsStr, std::path::Path};
19
20#[derive(Clone)]
38pub struct DecInt {
39 buf: [MaybeUninit<u8>; u64::MAX_STR_LEN + 1],
41 len: usize,
42}
43const _: () = assert!(u64::MAX_STR_LEN == i64::MAX_STR_LEN);
44
45impl DecInt {
46 #[inline]
48 pub fn new<Int: Integer>(i: Int) -> Self {
49 let mut buf = [MaybeUninit::uninit(); 21];
50
51 let mut str_buf = Buffer::new();
52 let str_buf = str_buf.format(i);
53 assert!(
54 str_buf.len() < buf.len(),
55 "{str_buf}{} unsupported.",
56 core::any::type_name::<Int>()
57 );
58
59 buf[..str_buf.len()].copy_from_slice(unsafe {
60 mem::transmute::<&[u8], &[MaybeUninit<u8>]>(str_buf.as_bytes())
62 });
63 buf[str_buf.len()] = MaybeUninit::new(0);
64
65 Self {
66 buf,
67 len: str_buf.len(),
68 }
69 }
70
71 #[inline]
73 pub fn from_fd<Fd: AsFd>(fd: Fd) -> Self {
74 Self::new(fd.as_fd().as_raw_fd())
75 }
76
77 #[inline]
79 pub fn as_str(&self) -> &str {
80 unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
83 }
84
85 #[inline]
87 pub fn as_c_str(&self) -> &CStr {
88 let bytes_with_nul = self.as_bytes_with_nul();
89 debug_assert!(CStr::from_bytes_with_nul(bytes_with_nul).is_ok());
90
91 unsafe { CStr::from_bytes_with_nul_unchecked(bytes_with_nul) }
94 }
95
96 #[inline]
98 pub fn as_bytes_with_nul(&self) -> &[u8] {
99 let init = &self.buf[..=self.len];
100 unsafe { mem::transmute::<&[MaybeUninit<u8>], &[u8]>(init) }
102 }
103
104 #[inline]
106 pub fn as_bytes(&self) -> &[u8] {
107 let bytes = self.as_bytes_with_nul();
108 &bytes[..bytes.len() - 1]
109 }
110}
111
112#[cfg(feature = "std")]
113impl AsRef<Path> for DecInt {
114 #[inline]
115 fn as_ref(&self) -> &Path {
116 let as_os_str: &OsStr = OsStrExt::from_bytes(self.as_bytes());
117 Path::new(as_os_str)
118 }
119}
120
121#[cfg(feature = "std")]
122impl fmt::Debug for DecInt {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 self.as_str().fmt(f)
125 }
126}