Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
rust source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
mrustc (master)
rustc 1.0.0
rustc 1.1.0
rustc 1.10.0
rustc 1.11.0
rustc 1.12.0
rustc 1.13.0
rustc 1.14.0
rustc 1.15.1
rustc 1.16.0
rustc 1.17.0
rustc 1.18.0
rustc 1.19.0
rustc 1.2.0
rustc 1.20.0
rustc 1.21.0
rustc 1.22.0
rustc 1.23.0
rustc 1.24.0
rustc 1.25.0
rustc 1.26.0
rustc 1.27.0
rustc 1.27.1
rustc 1.28.0
rustc 1.29.0
rustc 1.3.0
rustc 1.30.0
rustc 1.31.0
rustc 1.32.0
rustc 1.33.0
rustc 1.34.0
rustc 1.35.0
rustc 1.36.0
rustc 1.37.0
rustc 1.38.0
rustc 1.39.0
rustc 1.4.0
rustc 1.40.0
rustc 1.41.0
rustc 1.42.0
rustc 1.43.0
rustc 1.44.0
rustc 1.45.0
rustc 1.45.2
rustc 1.46.0
rustc 1.47.0
rustc 1.48.0
rustc 1.49.0
rustc 1.5.0
rustc 1.50.0
rustc 1.51.0
rustc 1.52.0
rustc 1.53.0
rustc 1.54.0
rustc 1.55.0
rustc 1.56.0
rustc 1.57.0
rustc 1.58.0
rustc 1.59.0
rustc 1.6.0
rustc 1.60.0
rustc 1.61.0
rustc 1.62.0
rustc 1.63.0
rustc 1.64.0
rustc 1.65.0
rustc 1.66.0
rustc 1.67.0
rustc 1.68.0
rustc 1.69.0
rustc 1.7.0
rustc 1.70.0
rustc 1.71.0
rustc 1.72.0
rustc 1.73.0
rustc 1.74.0
rustc 1.75.0
rustc 1.76.0
rustc 1.77.0
rustc 1.78.0
rustc 1.79.0
rustc 1.8.0
rustc 1.80.0
rustc 1.81.0
rustc 1.82.0
rustc 1.83.0
rustc 1.84.0
rustc 1.85.0
rustc 1.86.0
rustc 1.87.0
rustc 1.88.0
rustc 1.89.0
rustc 1.9.0
rustc beta
rustc nightly
rustc-cg-gcc (master)
x86-64 GCCRS (GCC master)
x86-64 GCCRS (GCCRS master)
x86-64 GCCRS 14.1 (GCC assertions)
x86-64 GCCRS 14.1 (GCC)
x86-64 GCCRS 14.2 (GCC assertions)
x86-64 GCCRS 14.2 (GCC)
x86-64 GCCRS 14.3 (GCC assertions)
x86-64 GCCRS 14.3 (GCC)
x86-64 GCCRS 15.1 (GCC assertions)
x86-64 GCCRS 15.1 (GCC)
x86-64 GCCRS 15.2 (GCC assertions)
x86-64 GCCRS 15.2 (GCC)
Options
Source code
//! Efficient decimal integer formatting. //! //! # Safety //! //! This uses `CStr::from_bytes_with_nul_unchecked` and //! `str::from_utf8_unchecked`on the buffer that it filled itself. #![allow(unsafe_code)] use std::os::fd::{AsFd, AsRawFd}; use std::ffi::CStr; use std::hint::unreachable_unchecked; use std::mem::{self, MaybeUninit}; use std::num::NonZeroU8; pub fn foo(i: i32) -> DecInt { DecInt::new(i) } /// Format an integer into a decimal `Path` component, without constructing a /// temporary `PathBuf` or `String`. /// /// This is used for opening paths such as `/proc/self/fd/<fd>` on Linux. /// /// # Examples /// /// ``` /// # #[cfg(any(feature = "fs", feature = "net"))] /// use rustix::path::DecInt; /// /// # #[cfg(any(feature = "fs", feature = "net"))] /// assert_eq!( /// format!("hello {}", DecInt::new(9876).as_ref().display()), /// "hello 9876" /// ); /// ``` #[derive(Clone)] pub struct DecInt { buf: [MaybeUninit<u8>; BUF_LEN], len: NonZeroU8, } /// Enough to hold an {u,i}64 and NUL terminator. const BUF_LEN: usize = U64_MAX_STR_LEN + 1; /// Maximum length of a formatted [`u64`]. const U64_MAX_STR_LEN: usize = "18446744073709551615".len(); /// Maximum length of a formatted [`i64`]. #[allow(dead_code)] const I64_MAX_STR_LEN: usize = "-9223372036854775808".len(); const _: () = assert!(U64_MAX_STR_LEN == I64_MAX_STR_LEN); mod private { pub trait Sealed: Copy { type Unsigned: super::Integer; fn as_unsigned(self) -> (bool, Self::Unsigned); fn eq_zero(self) -> bool; fn div_mod_10(&mut self) -> u8; } macro_rules! impl_unsigned { ($($ty:ty)+) => { $( impl Sealed for $ty { type Unsigned = $ty; #[inline] fn as_unsigned(self) -> (bool, $ty) { (false, self) } #[inline] fn eq_zero(self) -> bool { self == 0 } #[inline] fn div_mod_10(&mut self) -> u8 { let result = (*self % 10) as u8; *self /= 10; result } } )+ } } macro_rules! impl_signed { ($($signed:ty : $unsigned:ty)+) => { $( impl Sealed for $signed { type Unsigned = $unsigned; #[inline] fn as_unsigned(self) -> (bool, $unsigned) { if self >= 0 { (false, self as $unsigned) } else { (true, !(self as $unsigned) + 1) } } #[inline] fn eq_zero(self) -> bool { unimplemented!() } #[inline] fn div_mod_10(&mut self) -> u8 { unimplemented!() } } )+ } } impl_unsigned!(u8 u16 u32 u64); impl_signed!(i8:u8 i16:u16 i32:u32 i64:u64); #[cfg(any( target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64" ))] const _: () = { impl_unsigned!(usize); impl_signed!(isize:usize); }; } /// An integer that can be used by [`DecInt::new`]. pub trait Integer: private::Sealed {} impl Integer for i8 {} impl Integer for i16 {} impl Integer for i32 {} impl Integer for i64 {} impl Integer for u8 {} impl Integer for u16 {} impl Integer for u32 {} impl Integer for u64 {} #[cfg(any( target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64" ))] const _: () = { impl Integer for isize {} impl Integer for usize {} }; impl DecInt { /// Construct a new path component from an integer. pub fn new<Int: Integer>(i: Int) -> Self { use private::Sealed; let (is_neg, mut i) = i.as_unsigned(); let mut len = 1; let mut buf = [MaybeUninit::uninit(); BUF_LEN]; buf[BUF_LEN - 1] = MaybeUninit::new(b'\0'); // We use `loop { …; if cond { break } }` instead of `while !cond { … }` so the loop is // entered at least once. This way `0` does not need a special handling. loop { len += 1; if len > BUF_LEN { // SAFETY: a stringified i64/u64 cannot be longer than `U64_MAX_STR_LEN` bytes unsafe { unreachable_unchecked() }; } buf[BUF_LEN - len] = MaybeUninit::new(b'0' + i.div_mod_10()); if i.eq_zero() { break; } } if is_neg { len += 1; if len > BUF_LEN { // SAFETY: a stringified i64/u64 cannot be longer than `U64_MAX_STR_LEN` bytes unsafe { unreachable_unchecked() }; } buf[BUF_LEN - len] = MaybeUninit::new(b'-'); } DecInt { buf, // SAFETY: cannot be less that 2 (initialized with 1 + at least one loop) len: unsafe { NonZeroU8::new_unchecked(len as u8) }, } } /// Construct a new path component from a file descriptor. #[inline] pub fn from_fd<Fd: AsFd>(fd: Fd) -> Self { Self::new(fd.as_fd().as_raw_fd()) } /// Return the raw byte buffer as a `&str`. #[inline] pub fn as_str(&self) -> &str { // SAFETY: `DecInt` always holds a formatted decimal number, so it's // always valid UTF-8. unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } } /// Return the raw byte buffer as a `&CStr`. #[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()); // SAFETY: `self.buf` holds a single decimal ASCII representation and // at least one extra NUL byte. unsafe { CStr::from_bytes_with_nul_unchecked(bytes_with_nul) } } /// Return the raw byte buffer including the NUL byte. #[inline] pub fn as_bytes_with_nul(&self) -> &[u8] { let len = self.len.get() as usize; if len > BUF_LEN { // SAFETY: a stringified i64/u64 cannot be longer than `U64_MAX_STR_LEN` bytes unsafe { unreachable_unchecked() }; } let init = &self.buf[(self.buf.len() - len)..]; // SAFETY: we're guaranteed to have initialized len+1 bytes. unsafe { mem::transmute::<&[MaybeUninit<u8>], &[u8]>(init) } } /// Return the raw byte buffer. #[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) } }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree