Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 447d72c

Browse files
committedMar 24, 2025·
Added functionality for int_format_into
1 parent ae8ab87 commit 447d72c

File tree

3 files changed

+372
-68
lines changed

3 files changed

+372
-68
lines changed
 

‎library/core/src/fmt/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod float;
1515
#[cfg(no_fp_fmt_parse)]
1616
mod nofloat;
1717
mod num;
18+
mod num_buffer;
1819
mod rt;
1920

2021
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
@@ -33,6 +34,9 @@ pub enum Alignment {
3334
Center,
3435
}
3536

37+
#[unstable(feature = "int_format_into", issue = "138215")]
38+
pub use num_buffer::NumBuffer;
39+
3640
#[stable(feature = "debug_builders", since = "1.2.0")]
3741
pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
3842
#[unstable(feature = "debug_closure_helpers", issue = "117729")]

‎library/core/src/fmt/num.rs

Lines changed: 303 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Integer and floating-point number formatting
22
3+
use crate::fmt::num_buffer::NumBuffer;
34
use crate::mem::MaybeUninit;
45
use crate::num::fmt as numfmt;
56
use crate::ops::{Div, Rem, Sub};
@@ -199,44 +200,60 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"\
199200
6061626364656667686970717273747576777879\
200201
8081828384858687888990919293949596979899";
201202

202-
macro_rules! impl_Display {
203-
($($signed:ident, $unsigned:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => {
203+
static NEGATIVE_SIGN: &[u8; 1] = b"-";
204+
205+
// SAFETY: safety is ensured by the caller about:
206+
// 1. The contents of `buf` containing only ASCII characters.
207+
// 2. `offset` being bound checked.
208+
// 3. The contents of `buf` being initialized from `offset` onwards till the end.
209+
unsafe fn extract_str_from_buf(buf: &NumBuffer, offset: usize) -> &str {
210+
// SAFETY: safety is ensured by the caller about:
211+
// 1. `offset` being bound checked
212+
// 2. The contents of `buf` being initialized from `offset` onwards till the end.
213+
let written = unsafe { buf.extract(offset..) };
214+
215+
// SAFETY: safety is ensured by the caller about:
216+
// 1. The contents of `buf` containing only ASCII characters.
217+
let as_str = unsafe {
218+
str::from_utf8_unchecked(slice::from_raw_parts(
219+
MaybeUninit::slice_as_ptr(written),
220+
written.len(),
221+
))
222+
};
204223

205-
$(
206-
#[stable(feature = "rust1", since = "1.0.0")]
207-
impl fmt::Display for $unsigned {
208-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209-
#[cfg(not(feature = "optimize_for_size"))]
210-
{
211-
self._fmt(true, f)
212-
}
213-
#[cfg(feature = "optimize_for_size")]
214-
{
215-
$gen_name(self.$conv_fn(), true, f)
216-
}
217-
}
218-
}
224+
as_str
225+
}
219226

220-
#[stable(feature = "rust1", since = "1.0.0")]
221-
impl fmt::Display for $signed {
222-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223-
#[cfg(not(feature = "optimize_for_size"))]
224-
{
225-
return self.unsigned_abs()._fmt(*self >= 0, f);
226-
}
227-
#[cfg(feature = "optimize_for_size")]
228-
{
229-
return $gen_name(self.unsigned_abs().$conv_fn(), *self >= 0, f);
230-
}
231-
}
232-
}
227+
// SAFETY: safety is ensured by the caller about:
228+
// 1. `start_offset` being bound checked
229+
unsafe fn add_negative_sign(
230+
is_nonnegative: bool,
231+
buf: &mut NumBuffer,
232+
start_offset: usize,
233+
) -> usize {
234+
if is_nonnegative {
235+
return start_offset;
236+
}
237+
238+
let offset = start_offset - 1;
239+
240+
// Setting sign for the negative number
241+
// SAFETY: `start_offset` being bound checked is ensured by
242+
// the caller.
243+
unsafe { buf.write(offset, NEGATIVE_SIGN[0]) };
233244

245+
offset
246+
}
247+
248+
// Basic functionality that is relied upon by functionality within
249+
// `impl_Display` and `impl_FormatInto`
250+
macro_rules! impl_NumBuffer {
251+
($($unsigned:ident,)* ; as $u:ident named $gen_name:ident) => {
252+
253+
$(
234254
#[cfg(not(feature = "optimize_for_size"))]
235255
impl $unsigned {
236-
fn _fmt(self, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237-
const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1;
238-
// Buffer decimals for $unsigned with right alignment.
239-
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
256+
fn _write_into_buf(self, buf: &mut NumBuffer) -> usize {
240257
// Count the number of bytes in buf that are not initialized.
241258
let mut offset = buf.len();
242259
// Consume the least-significant decimals from a working copy.
@@ -245,10 +262,11 @@ macro_rules! impl_Display {
245262
// Format per four digits from the lookup table.
246263
// Four digits need a 16-bit $unsigned or wider.
247264
while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
248-
// SAFETY: All of the decimals fit in buf due to MAX_DEC_N
265+
// SAFETY: All of the decimals fit in `buf` since `buf` is large enough to
266+
// accommodate the largest representation of a number possible (that of i128::MIN)
249267
// and the while condition ensures at least 4 more decimals.
250268
unsafe { core::hint::assert_unchecked(offset >= 4) }
251-
// SAFETY: The offset counts down from its initial buf.len()
269+
// SAFETY: The offset counts down from its initial size
252270
// without underflow due to the previous precondition.
253271
unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
254272
offset -= 4;
@@ -259,69 +277,82 @@ macro_rules! impl_Display {
259277
remain /= scale;
260278
let pair1 = (quad / 100) as usize;
261279
let pair2 = (quad % 100) as usize;
262-
buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
263-
buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
264-
buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
265-
buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
280+
281+
// SAFETY: The offset is bounds-checked in the asserts above.
282+
unsafe {
283+
buf.write(offset + 0, DEC_DIGITS_LUT[pair1 * 2 + 0]);
284+
buf.write(offset + 1, DEC_DIGITS_LUT[pair1 * 2 + 1]);
285+
buf.write(offset + 2, DEC_DIGITS_LUT[pair2 * 2 + 0]);
286+
buf.write(offset + 3, DEC_DIGITS_LUT[pair2 * 2 + 1]);
287+
}
266288
}
267289

268290
// Format per two digits from the lookup table.
269291
if remain > 9 {
270-
// SAFETY: All of the decimals fit in buf due to MAX_DEC_N
292+
// SAFETY: All of the decimals fit in `buf` since `buf` is large enough to
293+
// accommodate the largest representation of a number possible (that of i128::MIN)
271294
// and the while condition ensures at least 2 more decimals.
272295
unsafe { core::hint::assert_unchecked(offset >= 2) }
273-
// SAFETY: The offset counts down from its initial buf.len()
296+
// SAFETY: The offset counts down from its initial size
274297
// without underflow due to the previous precondition.
275298
unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
276299
offset -= 2;
277300

278301
let pair = (remain % 100) as usize;
279302
remain /= 100;
280-
buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
281-
buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
303+
304+
// SAFETY: The offset is bounds-checked in the asserts above.
305+
unsafe {
306+
buf.write(offset + 0, DEC_DIGITS_LUT[pair * 2 + 0]);
307+
buf.write(offset + 1, DEC_DIGITS_LUT[pair * 2 + 1]);
308+
};
282309
}
283310

284311
// Format the last remaining digit, if any.
285312
if remain != 0 || self == 0 {
286-
// SAFETY: All of the decimals fit in buf due to MAX_DEC_N
313+
// SAFETY: All of the decimals fit in `buf` since `buf` is large enough to
314+
// accommodate the largest representation of a number possible (that of i128::MIN)
287315
// and the if condition ensures (at least) 1 more decimals.
288316
unsafe { core::hint::assert_unchecked(offset >= 1) }
289-
// SAFETY: The offset counts down from its initial buf.len()
317+
// SAFETY: The offset counts down from its initial size
290318
// without underflow due to the previous precondition.
291319
unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
292320
offset -= 1;
293321

294322
// Either the compiler sees that remain < 10, or it prevents
295323
// a boundary check up next.
296324
let last = (remain & 15) as usize;
297-
buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
325+
326+
// SAFETY: The offset is bounds-checked in the asserts above.
327+
unsafe { buf.write(offset, DEC_DIGITS_LUT[last * 2 + 1]) };
298328
// not used: remain = 0;
299329
}
300330

301-
// SAFETY: All buf content since offset is set.
302-
let written = unsafe { buf.get_unchecked(offset..) };
303-
// SAFETY: Writes use ASCII from the lookup table exclusively.
304-
let as_str = unsafe {
305-
str::from_utf8_unchecked(slice::from_raw_parts(
306-
MaybeUninit::slice_as_ptr(written),
307-
written.len(),
308-
))
309-
};
331+
offset
332+
}
333+
334+
fn _fmt(self, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335+
// Buffer decimals for $unsigned with right alignment.
336+
let mut buf = NumBuffer::new();
337+
let offset = self._write_into_buf(&mut buf);
338+
339+
// SAFETY: All contents of `buf` since offset is set, and
340+
// writes use ASCII from the lookup table exclusively.
341+
let as_str = unsafe { extract_str_from_buf(&buf, offset) };
342+
310343
f.pad_integral(is_nonnegative, "", as_str)
311344
}
312345
})*
313346

314347
#[cfg(feature = "optimize_for_size")]
315-
fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316-
const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1;
317-
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
318-
let mut curr = MAX_DEC_N;
319-
let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
348+
fn $gen_name(mut n: $u, is_nonnegative: bool, buf: &mut NumBuffer) -> &str {
349+
let mut curr = buf.len();
350+
let buf_ptr = NumBuffer::extract_start_mut_ptr(buf);
320351

321352
// SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
322-
// `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
353+
// `curr == buf.len() == 40 > log(n)` since `n < 2^128 < 10^39 < 10^40`, and at
323354
// each step this is kept the same as `n` is divided. Since `n` is always
324-
// non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
355+
// non-negative, this means that `curr >= (40 - 39) == 1 > 0` so `buf_ptr[curr..curr + 1]`
325356
// is safe to access.
326357
unsafe {
327358
loop {
@@ -335,16 +366,187 @@ macro_rules! impl_Display {
335366
}
336367
}
337368

338-
// SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid UTF-8
369+
// SAFETY: `curr >= 1` (unchanged if `is_nonnegative` is true) and
370+
// `curr >= 0` (incase `is_nonnegative` is false) so `buf_ptr[curr..curr + 1]`
371+
// is safe to access.
372+
unsafe { add_negative_sign(is_nonnegative, buf, curr) };
373+
374+
// SAFETY: `curr >= 0` (since we made `buf` large enough), and all the chars are valid UTF-8
339375
let buf_slice = unsafe {
340376
str::from_utf8_unchecked(
341377
slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
342378
};
343-
f.pad_integral(is_nonnegative, "", buf_slice)
379+
380+
buf_slice
344381
}
345382
};
346383
}
347384

385+
// Must invoke `impl_NumBuffer` before invoking this macro.
386+
macro_rules! impl_Display {
387+
($($signed:ident, $unsigned:ident,)* ; via $conv_fn:ident named $gen_name:ident) => {
388+
389+
$(
390+
#[stable(feature = "rust1", since = "1.0.0")]
391+
impl fmt::Display for $unsigned {
392+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393+
#[cfg(not(feature = "optimize_for_size"))]
394+
{
395+
self._fmt(true, f)
396+
}
397+
#[cfg(feature = "optimize_for_size")]
398+
{
399+
let mut buf = NumBuffer::new();
400+
401+
// not setting the sign here, hence sending `is_nonnegative` as `true`
402+
let as_str = $gen_name(self.$conv_fn(), true, &mut buf);
403+
f.pad_integral(true, "", as_str)
404+
}
405+
}
406+
}
407+
408+
#[stable(feature = "rust1", since = "1.0.0")]
409+
impl fmt::Display for $signed {
410+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411+
#[cfg(not(feature = "optimize_for_size"))]
412+
{
413+
return self.unsigned_abs()._fmt(*self >= 0, f);
414+
}
415+
#[cfg(feature = "optimize_for_size")]
416+
{
417+
let mut buf = NumBuffer::new();
418+
419+
// not setting the sign here, hence sending `is_nonnegative` as `true`
420+
let as_str = $gen_name(self.unsigned_abs().$conv_fn(), true, &mut buf);
421+
f.pad_integral(*self >= 0, "", as_str)
422+
}
423+
}
424+
}
425+
)*
426+
};
427+
}
428+
429+
// Must invoke `impl_NumBuffer` before invoking this macro.
430+
macro_rules! impl_FormatInto {
431+
($($signed:ident, $unsigned:ident,)* ; via $conv_fn:ident named $gen_name:ident) => {
432+
$(
433+
#[unstable(feature = "int_format_into", issue = "138215")]
434+
impl $signed {
435+
/// Allows users to write an integer (in signed decimal format) into a variable `buf` of
436+
/// type [`NumBuffer`] that is passed by the caller by mutable reference.
437+
///
438+
/// # Examples
439+
/// ```
440+
/// #![feature(int_format_into)]
441+
/// use core::fmt::NumBuffer;
442+
///
443+
#[doc = concat!("let n = 0", stringify!($signed), ";")]
444+
/// let mut buf = NumBuffer::new();
445+
/// assert_eq!(n.format_into(&mut buf), "0");
446+
///
447+
#[doc = concat!("let n1 = -32", stringify!($signed), ";")]
448+
/// let mut buf1 = NumBuffer::new();
449+
/// assert_eq!(n1.format_into(&mut buf1), "-32");
450+
///
451+
#[doc = concat!("let n2 = ", stringify!($signed::MIN), ";")]
452+
/// let mut buf2 = NumBuffer::new();
453+
#[doc = concat!("assert_eq!(n2.format_into(&mut buf2), ", stringify!($signed::MIN), ".to_string());")]
454+
///
455+
#[doc = concat!("let n3 = ", stringify!($signed::MAX), ";")]
456+
/// let mut buf3 = NumBuffer::new();
457+
#[doc = concat!("assert_eq!(n3.format_into(&mut buf3), ", stringify!($signed::MAX), ".to_string());")]
458+
/// ```
459+
///
460+
pub fn format_into(self, buf: &mut NumBuffer) -> &str {
461+
#[cfg(not(feature = "optimize_for_size"))]
462+
{
463+
let is_nonnegative = self >= 0;
464+
let mut offset = self.unsigned_abs()._write_into_buf(buf);
465+
466+
// SAFETY: `offset >= 1` since only a maximum of 39 digits
467+
// would have been written into the buffer (of size 40 bytes).
468+
// The negative sign is not written yet.
469+
unsafe { core::hint::assert_unchecked(offset >= 1) }
470+
471+
// SAFETY: The offset counts down from its initial size
472+
// without underflow due to the previous precondition.
473+
unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
474+
475+
// SAFETY: `offset >= 1` (unchanged if `is_nonnegative` is true) and
476+
// `offset >= 0` (incase `is_nonnegative` is false) so
477+
// `buf_ptr[offset..offset + 1]` is safe to access.
478+
offset = unsafe { add_negative_sign(is_nonnegative, buf, offset) };
479+
480+
// SAFETY: All buf content since offset is set, and
481+
// writes use ASCII from the lookup table exclusively.
482+
let as_str = unsafe { extract_str_from_buf(buf, offset) };
483+
484+
as_str
485+
}
486+
487+
#[cfg(feature = "optimize_for_size")]
488+
{
489+
let is_nonnegative = self >= 0;
490+
$gen_name(self.unsigned_abs().$conv_fn(), is_nonnegative, buf)
491+
}
492+
493+
}
494+
}
495+
496+
#[unstable(feature = "int_format_into", issue = "138215")]
497+
impl $unsigned {
498+
/// Allows users to write an integer (in signed decimal format) into a variable `buf` of
499+
/// type [`NumBuffer`] that is passed by the caller by mutable reference.
500+
///
501+
/// # Examples
502+
/// ```
503+
/// #![feature(int_format_into)]
504+
/// use core::fmt::NumBuffer;
505+
///
506+
#[doc = concat!("let n = 0", stringify!($signed), ";")]
507+
/// let mut buf = NumBuffer::new();
508+
/// assert_eq!(n.format_into(&mut buf), "0");
509+
///
510+
#[doc = concat!("let n1 = 32", stringify!($unsigned), ";")]
511+
/// let mut buf1 = NumBuffer::new();
512+
/// assert_eq!(n1.format_into(&mut buf1), "32");
513+
///
514+
#[doc = concat!("let n2 = ", stringify!($unsigned::MAX), ";")]
515+
/// let mut buf2 = NumBuffer::new();
516+
#[doc = concat!("assert_eq!(n2.format_into(&mut buf2), ", stringify!($unsigned::MAX), ".to_string());")]
517+
/// ```
518+
///
519+
pub fn format_into(self, buf: &mut NumBuffer) -> &str {
520+
#[cfg(not(feature = "optimize_for_size"))]
521+
{
522+
let offset = self._write_into_buf(buf);
523+
524+
// SAFETY: `offset >= 1` since only a maximum of 39 digits
525+
// would have been written into the buffer (of size 40 bytes).
526+
unsafe { core::hint::assert_unchecked(offset >= 1) }
527+
528+
// SAFETY: The offset counts down from its initial size
529+
// without underflow due to the previous precondition.
530+
unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
531+
532+
// SAFETY: All contents in `buf` since offset is set, and
533+
// writes use ASCII from the lookup table exclusively.
534+
let as_str = unsafe { extract_str_from_buf(buf, offset) };
535+
536+
as_str
537+
}
538+
539+
#[cfg(feature = "optimize_for_size")]
540+
{
541+
$gen_name(self.$conv_fn(), true, buf)
542+
}
543+
544+
}
545+
}
546+
)*
547+
}
548+
}
549+
348550
macro_rules! impl_Exp {
349551
($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
350552
fn $name(
@@ -523,14 +725,24 @@ impl_Debug! {
523725
#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
524726
mod imp {
525727
use super::*;
728+
impl_NumBuffer!(
729+
u8, u16, u32, u64, usize,
730+
; as u64 named stringify_u64);
526731
impl_Display!(
527732
i8, u8,
528733
i16, u16,
529734
i32, u32,
530735
i64, u64,
531736
isize, usize,
532-
; as u64 via to_u64 named fmt_u64
533-
);
737+
; via to_u64 named stringify_u64);
738+
impl_FormatInto!(
739+
i8, u8,
740+
i16, u16,
741+
i32, u32,
742+
i64, u64,
743+
isize, usize,
744+
; via to_u64 named stringify_u64);
745+
534746
impl_Exp!(
535747
i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
536748
as u64 via to_u64 named exp_u64
@@ -540,19 +752,42 @@ mod imp {
540752
#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
541753
mod imp {
542754
use super::*;
755+
impl_NumBuffer!(
756+
u8, u16, u32, usize,
757+
; as u32 named stringify_u32);
543758
impl_Display!(
544759
i8, u8,
545760
i16, u16,
546761
i32, u32,
547762
isize, usize,
548-
; as u32 via to_u32 named fmt_u32);
763+
; via to_u32 named stringify_u32);
764+
impl_FormatInto!(
765+
i8, u8,
766+
i16, u16,
767+
i32, u32,
768+
isize, usize,
769+
; via to_u32 named stringify_u32);
770+
771+
impl_NumBuffer!(
772+
u64,
773+
; as u64 named stringify_u64);
549774
impl_Display!(
550775
i64, u64,
551-
; as u64 via to_u64 named fmt_u64);
776+
; via to_u64 named stringify_u64);
777+
impl_FormatInto!(
778+
i64, u64,
779+
; via to_u64 named stringify_u64);
552780

553781
impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
554782
impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
555783
}
784+
impl_NumBuffer!(
785+
u128,
786+
; as u128 named stringify_u128);
787+
impl_FormatInto!(
788+
i128, u128,
789+
; via to_u128 named stringify_u128);
790+
556791
impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
557792

558793
/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.

‎library/core/src/fmt/num_buffer.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use crate::mem::MaybeUninit;
2+
use crate::slice::SliceIndex;
3+
4+
/// 40 is chosen as the buffer length, as it is equal
5+
/// to that required to accommodate i128::MIN, which has the largest
6+
/// decimal string representation
7+
/// (39 decimal digits + 1 for negative sign).
8+
const BUF_SIZE: usize = 40;
9+
10+
/// A minimal buffer implementation containing elements of type
11+
/// `MaybeUninit<u8>`.
12+
#[unstable(feature = "int_format_into", issue = "138215")]
13+
#[derive(Debug)]
14+
pub struct NumBuffer {
15+
/// An array of elements of type `MaybeUninit<u8>`.
16+
contents: [MaybeUninit<u8>; BUF_SIZE],
17+
}
18+
19+
#[unstable(feature = "int_format_into", issue = "138215")]
20+
impl NumBuffer {
21+
/// Initializes `contents` as an uninitialized array of `MaybeUninit<u8>`.
22+
#[unstable(feature = "int_format_into", issue = "138215")]
23+
pub fn new() -> Self {
24+
NumBuffer { contents: [MaybeUninit::<u8>::uninit(); BUF_SIZE] }
25+
}
26+
27+
/// Returns the length of the buffer.
28+
#[unstable(feature = "int_format_into", issue = "138215")]
29+
pub fn len(&self) -> usize {
30+
BUF_SIZE
31+
}
32+
33+
/// Extracts a slice of the contents of the buffer.
34+
/// This function is unsafe, since it does not itself
35+
/// bounds-check `index`.
36+
///
37+
/// SAFETY: `index` is bounds-checked by the caller.
38+
#[unstable(feature = "int_format_into", issue = "138215")]
39+
pub(crate) unsafe fn extract<I>(&self, index: I) -> &I::Output
40+
where
41+
I: SliceIndex<[MaybeUninit<u8>]>,
42+
{
43+
// SAFETY: `index` is bound-checked by the caller.
44+
unsafe { self.contents.get_unchecked(index) }
45+
}
46+
47+
/// Returns a mutable pointer pointing to the start of the buffer.
48+
#[unstable(feature = "int_format_into", issue = "138215")]
49+
#[cfg(feature = "optimize_for_size")]
50+
pub(crate) fn extract_start_mut_ptr(buf: &mut Self) -> *mut u8 {
51+
MaybeUninit::slice_as_mut_ptr(&mut buf.contents)
52+
}
53+
54+
/// Writes data at index `offset` of the buffer.
55+
/// This function is unsafe, since it does not itself perform
56+
/// the safety checks below.
57+
///
58+
/// SAFETY: The caller ensures the following:
59+
/// 1. `offset` is bounds-checked.
60+
/// 2. `data` is a valid ASCII character.
61+
#[unstable(feature = "int_format_into", issue = "138215")]
62+
pub(crate) unsafe fn write(&mut self, offset: usize, data: u8) {
63+
self.contents[offset].write(data);
64+
}
65+
}

0 commit comments

Comments
 (0)
Please sign in to comment.