use core::mem::MaybeUninit;
use crate::{fmt::Write, Error};
const MAX_CAPACITY: usize = u16::MAX as usize;
const MAX_INTEGER_LEN: u8 = 20;
const MAX_PRECISION: usize = 9;
const BROAD_MINIMUM_BUFFER_LEN: usize = 20;
const RADIX_100_ZERO: [u8; 200] = *b"00010203040506070809\
10111213141516171819\
20212223242526272829\
30313233343536373839\
40414243444546474849\
50515253545556575859\
60616263646566676869\
70717273747576777879\
80818283848586878889\
90919293949596979899";
const RADIX_100_SPACE: [u8; 200] = *b" 0 1 2 3 4 5 6 7 8 9\
10111213141516171819\
20212223242526272829\
30313233343536373839\
40414243444546474849\
50515253545556575859\
60616263646566676869\
70717273747576777879\
80818283848586878889\
90919293949596979899";
#[derive(Clone, Copy)]
pub(crate) struct ArrayBuffer<const N: usize> {
data: [MaybeUninit<u8>; N],
}
impl<const N: usize> ArrayBuffer<N> {
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn as_borrowed<'data>(&mut self) -> BorrowedBuffer<'_> {
BorrowedBuffer::from(&mut self.data)
}
unsafe fn assume_init(self) -> [u8; N] {
unsafe {
*(&self.data as *const [MaybeUninit<u8>; N] as *const [u8; N])
}
}
}
impl<const N: usize> Default for ArrayBuffer<N> {
#[cfg_attr(feature = "perf-inline", inline(always))]
fn default() -> ArrayBuffer<N> {
ArrayBuffer { data: [MaybeUninit::uninit(); N] }
}
}
#[derive(Debug)]
pub(crate) struct BorrowedBuffer<'data> {
data: &'data mut [MaybeUninit<u8>],
filled: u16,
}
impl<'data> BorrowedBuffer<'data> {
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn with_writer<const N: usize>(
wtr: &mut dyn Write,
_runtime_allocation: usize,
mut with: impl FnMut(&mut BorrowedBuffer<'_>) -> Result<(), Error>,
) -> Result<(), Error> {
#[cfg(feature = "alloc")]
if let Some(buf) = unsafe { wtr.as_mut_vec() } {
buf.reserve(_runtime_allocation);
return BorrowedBuffer::with_vec_spare_capacity(buf, with);
}
let mut buf = ArrayBuffer::<N>::default();
let mut bbuf = buf.as_borrowed();
with(&mut bbuf)?;
wtr.write_str(bbuf.filled())?;
Ok(())
}
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn with_vec_spare_capacity<T>(
buf: &'data mut alloc::vec::Vec<u8>,
mut with: impl FnMut(&mut BorrowedBuffer<'_>) -> T,
) -> T {
let mut bbuf = BorrowedBuffer::from_vec_spare_capacity(buf);
let returned = with(&mut bbuf);
let new_len = bbuf.len();
unsafe {
buf.set_len(new_len);
}
returned
}
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn from_vec_spare_capacity(
vec: &'data mut alloc::vec::Vec<u8>,
) -> BorrowedBuffer<'data> {
let data = vec.spare_capacity_mut();
let len = data.len().min(MAX_CAPACITY);
BorrowedBuffer::from(&mut data[..len])
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_str(&mut self, string: &str) {
let data: &[MaybeUninit<u8>] = unsafe {
core::slice::from_raw_parts(
string.as_ptr().cast::<MaybeUninit<u8>>(),
string.len(),
)
};
self.available()
.get_mut(..string.len())
.expect("string data exceeds available buffer space")
.copy_from_slice(data);
self.filled += string.len() as u16;
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_char(&mut self, ch: char) {
self.write_str(ch.encode_utf8(&mut [0; 4]));
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_ascii_char(&mut self, byte: u8) {
assert!(byte.is_ascii());
self.available()
.get_mut(0)
.expect("insufficient buffer space to write one byte")
.write(byte);
self.filled += 1;
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int(&mut self, n: impl Into<u64>) {
let mut n = n.into();
let digits = digits(n);
let mut remaining_digits = usize::from(digits);
let available = self
.available()
.get_mut(..remaining_digits)
.expect("u8 integer digits exceeds available buffer space");
while remaining_digits > 0 {
remaining_digits -= 1;
unsafe {
available
.get_unchecked_mut(remaining_digits)
.write(b'0' + ((n % 10) as u8));
}
n /= 10;
}
self.filled += u16::from(digits);
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad0(&mut self, n: impl Into<u64>, pad_len: u8) {
let mut n = n.into();
let pad_len = pad_len.min(MAX_INTEGER_LEN);
let digits = pad_len.max(digits(n));
let mut remaining_digits = usize::from(digits);
let available = self
.available()
.get_mut(..remaining_digits)
.expect("u8 integer digits exceeds available buffer space");
while remaining_digits > 0 {
remaining_digits -= 1;
unsafe {
available
.get_unchecked_mut(remaining_digits)
.write(b'0' + ((n % 10) as u8));
}
n /= 10;
}
self.filled += u16::from(digits);
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad(
&mut self,
n: impl Into<u64>,
pad_byte: u8,
pad_len: u8,
) {
assert!(pad_byte.is_ascii(), "padding byte must be ASCII");
let mut n = n.into();
let pad_len = pad_len.min(MAX_INTEGER_LEN);
let digits = pad_len.max(digits(n));
let mut remaining_digits = usize::from(digits);
let available = self
.available()
.get_mut(..remaining_digits)
.expect("u8 integer digits exceeds available buffer space");
while remaining_digits > 0 {
remaining_digits -= 1;
unsafe {
available
.get_unchecked_mut(remaining_digits)
.write(b'0' + ((n % 10) as u8));
}
n /= 10;
if n == 0 {
break;
}
}
while remaining_digits > 0 {
remaining_digits -= 1;
unsafe {
available.get_unchecked_mut(remaining_digits).write(pad_byte);
}
}
self.filled += u16::from(digits);
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int1(&mut self, n: impl Into<u64>) {
let n = n.into();
assert!(n <= 9);
self.write_ascii_char(b'0' + (n as u8));
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad2(&mut self, n: impl Into<u64>) {
let n = n.into();
assert!(n <= 99);
let dst = self
.available()
.get_mut(..2)
.expect("padded 2 digit integer exceeds available buffer space");
let radix_offset = ((n % 100) * 2) as usize;
unsafe {
dst.get_unchecked_mut(0)
.write(*RADIX_100_ZERO.get_unchecked(radix_offset));
dst.get_unchecked_mut(1)
.write(*RADIX_100_ZERO.get_unchecked(radix_offset + 1));
}
self.filled += 2;
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad2_space(&mut self, n: impl Into<u64>) {
let n = n.into();
assert!(n <= 99);
let dst = self
.available()
.get_mut(..2)
.expect("padded 2 digit integer exceeds available buffer space");
let radix_offset = ((n % 100) * 2) as usize;
unsafe {
dst.get_unchecked_mut(0)
.write(*RADIX_100_SPACE.get_unchecked(radix_offset));
dst.get_unchecked_mut(1)
.write(*RADIX_100_SPACE.get_unchecked(radix_offset + 1));
}
self.filled += 2;
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad4(&mut self, n: impl Into<u64>) {
let mut n = n.into();
assert!(n <= 9999);
let dst = self
.available()
.get_mut(..4)
.expect("padded 4 digit integer exceeds available buffer space");
let radix_offset = ((n % 100) * 2) as usize;
unsafe {
dst.get_unchecked_mut(2)
.write(*RADIX_100_ZERO.get_unchecked(radix_offset));
dst.get_unchecked_mut(3)
.write(*RADIX_100_ZERO.get_unchecked(radix_offset + 1));
}
n /= 100;
let radix_offset = ((n % 100) * 2) as usize;
unsafe {
dst.get_unchecked_mut(0)
.write(*RADIX_100_ZERO.get_unchecked(radix_offset));
dst.get_unchecked_mut(1)
.write(*RADIX_100_ZERO.get_unchecked(radix_offset + 1));
}
self.filled += 4;
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_fraction(
&mut self,
precision: Option<u8>,
mut n: u32,
) {
assert!(n <= 999_999_999);
let mut buf = ArrayBuffer::<MAX_PRECISION>::default();
for i in (0..MAX_PRECISION).rev() {
unsafe {
buf.data.get_unchecked_mut(i).write(b'0' + ((n % 10) as u8));
}
n /= 10;
}
let end = precision
.map(|p| p.min(MAX_PRECISION as u8))
.unwrap_or_else(|| {
let buf = unsafe { buf.assume_init() };
let mut end = MAX_PRECISION as u8;
while end > 0 && buf[usize::from(end) - 1] == b'0' {
end -= 1;
}
end
});
let buf = &buf.data[..usize::from(end)];
self.available()
.get_mut(..buf.len())
.expect("fraction exceeds available buffer space")
.copy_from_slice(buf);
self.filled += u16::from(end);
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn clear(&mut self) {
self.filled = 0;
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn filled(&self) -> &str {
let filled = unsafe { self.data.get_unchecked(..self.len()) };
unsafe {
core::str::from_utf8_unchecked(core::slice::from_raw_parts(
filled.as_ptr().cast::<u8>(),
self.len(),
))
}
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn available(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe { self.data.get_unchecked_mut(self.len()..) }
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn len(&self) -> usize {
usize::from(self.filled)
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn available_capacity(&self) -> usize {
self.capacity() - self.len()
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn capacity(&self) -> usize {
self.data.len()
}
}
impl<'data> From<&'data mut [u8]> for BorrowedBuffer<'data> {
#[cfg_attr(feature = "perf-inline", inline(always))]
fn from(data: &'data mut [u8]) -> BorrowedBuffer<'data> {
assert!(
data.len() <= MAX_CAPACITY,
"borrowed buffer only supports {MAX_CAPACITY} bytes"
);
let len = data.len();
let data: *mut MaybeUninit<u8> = data.as_mut_ptr().cast();
let data = unsafe { core::slice::from_raw_parts_mut(data, len) };
BorrowedBuffer { data, filled: 0 }
}
}
impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuffer<'data> {
#[cfg_attr(feature = "perf-inline", inline(always))]
fn from(data: &'data mut [MaybeUninit<u8>]) -> BorrowedBuffer<'data> {
assert!(
data.len() <= MAX_CAPACITY,
"borrowed buffer only supports {MAX_CAPACITY} bytes"
);
BorrowedBuffer { data, filled: 0 }
}
}
impl<'data, const N: usize> From<&'data mut [MaybeUninit<u8>; N]>
for BorrowedBuffer<'data>
{
#[cfg_attr(feature = "perf-inline", inline(always))]
fn from(data: &'data mut [MaybeUninit<u8>; N]) -> BorrowedBuffer<'data> {
BorrowedBuffer::from(&mut data[..])
}
}
pub(crate) struct BorrowedWriter<'buffer, 'data, 'write> {
bbuf: &'buffer mut BorrowedBuffer<'data>,
wtr: &'write mut dyn Write,
}
impl<'buffer, 'data, 'write> BorrowedWriter<'buffer, 'data, 'write> {
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn new(
bbuf: &'buffer mut BorrowedBuffer<'data>,
wtr: &'write mut dyn Write,
) -> BorrowedWriter<'buffer, 'data, 'write> {
assert!(bbuf.capacity() >= BROAD_MINIMUM_BUFFER_LEN);
BorrowedWriter { bbuf, wtr }
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn finish(self) -> Result<(), Error> {
self.wtr.write_str(self.bbuf.filled())?;
self.bbuf.clear();
Ok(())
}
#[cold]
#[inline(never)]
pub(crate) fn flush(&mut self) -> Result<(), Error> {
self.wtr.write_str(self.bbuf.filled())?;
self.bbuf.clear();
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn if_will_fill_then_flush(
&mut self,
additional: impl Into<usize>,
) -> Result<(), Error> {
let n = additional.into();
if self.bbuf.len().saturating_add(n) > self.bbuf.capacity() {
self.flush()?;
}
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_str(&mut self, string: &str) -> Result<(), Error> {
if string.len() > self.bbuf.available_capacity() {
self.flush()?;
if string.len() > self.bbuf.available_capacity() {
return self.wtr.write_str(string);
}
}
self.bbuf.write_str(string);
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_char(&mut self, ch: char) -> Result<(), Error> {
self.if_will_fill_then_flush(ch.len_utf8())?;
self.bbuf.write_char(ch);
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_ascii_char(&mut self, byte: u8) -> Result<(), Error> {
if self.bbuf.available_capacity() == 0 {
self.flush()?;
}
self.bbuf.write_ascii_char(byte);
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad(
&mut self,
n: impl Into<u64>,
pad_byte: u8,
pad_len: u8,
) -> Result<(), Error> {
let n = n.into();
let pad_len = pad_len.min(MAX_INTEGER_LEN);
let digits = pad_len.max(digits(n));
self.if_will_fill_then_flush(digits)?;
self.bbuf.write_int_pad(n, pad_byte, pad_len);
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad2(
&mut self,
n: impl Into<u64>,
) -> Result<(), Error> {
self.if_will_fill_then_flush(2usize)?;
self.bbuf.write_int_pad2(n);
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad2_space(
&mut self,
n: impl Into<u64>,
) -> Result<(), Error> {
self.if_will_fill_then_flush(2usize)?;
self.bbuf.write_int_pad2_space(n);
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_int_pad4(
&mut self,
n: impl Into<u64>,
) -> Result<(), Error> {
self.if_will_fill_then_flush(4usize)?;
self.bbuf.write_int_pad4(n);
Ok(())
}
#[cfg_attr(feature = "perf-inline", inline(always))]
pub(crate) fn write_fraction(
&mut self,
precision: Option<u8>,
n: u32,
) -> Result<(), Error> {
self.if_will_fill_then_flush(9usize)?;
self.bbuf.write_fraction(precision, n);
Ok(())
}
}
impl<'buffer, 'data, 'write> Write for BorrowedWriter<'buffer, 'data, 'write> {
fn write_str(&mut self, string: &str) -> Result<(), Error> {
BorrowedWriter::write_str(self, string)
}
}
#[cfg_attr(feature = "perf-inline", inline(always))]
fn digits(n: u64) -> u8 {
match n {
0..=9 => 1,
10..=99 => 2,
100..=999 => 3,
1000..=9999 => 4,
_ => n.ilog10() as u8 + 1,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn write_str_array() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_str("Hello, world!");
assert_eq!(bbuf.filled(), "Hello, world!");
let buf = bbuf.filled();
assert_eq!(buf, "Hello, world!");
}
#[test]
fn write_int_array() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int(0u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "0");
}
bbuf.clear();
bbuf.write_int(1u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "1");
}
bbuf.clear();
bbuf.write_int(10u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "10");
}
bbuf.clear();
bbuf.write_int(100u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "100");
}
bbuf.clear();
bbuf.write_int(u64::MAX);
{
let buf = bbuf.filled();
assert_eq!(buf, "18446744073709551615");
}
}
#[test]
fn write_int_pad2() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad2(0u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "00");
}
bbuf.clear();
bbuf.write_int_pad2(1u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "01");
}
bbuf.clear();
bbuf.write_int_pad2(10u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "10");
}
bbuf.clear();
bbuf.write_int_pad2(99u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "99");
}
}
#[test]
#[should_panic]
fn write_int_pad2_panic() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad2(u64::MAX);
}
#[test]
fn write_int_pad4() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad4(0u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "0000");
}
bbuf.clear();
bbuf.write_int_pad4(1u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "0001");
}
bbuf.clear();
bbuf.write_int_pad4(10u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "0010");
}
bbuf.clear();
bbuf.write_int_pad4(99u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "0099");
}
bbuf.clear();
bbuf.write_int_pad4(999u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "0999");
}
bbuf.clear();
bbuf.write_int_pad4(9999u64);
{
let buf = bbuf.filled();
assert_eq!(buf, "9999");
}
}
#[test]
#[should_panic]
fn write_int_pad4_panic() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad4(u64::MAX);
}
#[test]
fn write_int_pad_zero() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad(0u64, b'0', 0);
{
let buf = bbuf.filled();
assert_eq!(buf, "0");
}
bbuf.clear();
bbuf.write_int_pad(0u64, b'0', 1);
{
let buf = bbuf.filled();
assert_eq!(buf, "0");
}
bbuf.clear();
bbuf.write_int_pad(0u64, b'0', 2);
{
let buf = bbuf.filled();
assert_eq!(buf, "00");
}
bbuf.clear();
bbuf.write_int_pad(0u64, b'0', 20);
{
let buf = bbuf.filled();
assert_eq!(buf, "00000000000000000000");
}
bbuf.clear();
bbuf.write_int_pad(0u64, b'0', 21);
{
let buf = bbuf.filled();
assert_eq!(buf, "00000000000000000000");
}
bbuf.clear();
bbuf.write_int_pad(0u64, b' ', 2);
{
let buf = bbuf.filled();
assert_eq!(buf, " 0");
}
}
#[test]
fn write_int_pad_one() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad(1u64, b'0', 0);
{
let buf = bbuf.filled();
assert_eq!(buf, "1");
}
bbuf.clear();
bbuf.write_int_pad(1u64, b'0', 1);
{
let buf = bbuf.filled();
assert_eq!(buf, "1");
}
bbuf.clear();
bbuf.write_int_pad(1u64, b'0', 2);
{
let buf = bbuf.filled();
assert_eq!(buf, "01");
}
bbuf.clear();
bbuf.write_int_pad(1u64, b'0', 20);
{
let buf = bbuf.filled();
assert_eq!(buf, "00000000000000000001");
}
bbuf.clear();
bbuf.write_int_pad(1u64, b'0', 21);
{
let buf = bbuf.filled();
assert_eq!(buf, "00000000000000000001");
}
bbuf.clear();
bbuf.write_int_pad(1u64, b' ', 2);
{
let buf = bbuf.filled();
assert_eq!(buf, " 1");
}
}
#[test]
fn write_int_pad_max() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad(u64::MAX, b'0', 0);
{
let buf = bbuf.filled();
assert_eq!(buf, "18446744073709551615");
}
bbuf.clear();
bbuf.write_int_pad(u64::MAX, b'0', 1);
{
let buf = bbuf.filled();
assert_eq!(buf, "18446744073709551615");
}
bbuf.clear();
bbuf.write_int_pad(u64::MAX, b'0', 2);
{
let buf = bbuf.filled();
assert_eq!(buf, "18446744073709551615");
}
bbuf.clear();
bbuf.write_int_pad(u64::MAX, b'0', 20);
{
let buf = bbuf.filled();
assert_eq!(buf, "18446744073709551615");
}
bbuf.clear();
bbuf.write_int_pad(u64::MAX, b'0', 21);
{
let buf = bbuf.filled();
assert_eq!(buf, "18446744073709551615");
}
bbuf.clear();
bbuf.write_int_pad(u64::MAX, b' ', 2);
{
let buf = bbuf.filled();
assert_eq!(buf, "18446744073709551615");
}
}
#[test]
#[should_panic]
fn write_int_pad_non_ascii_panic() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad(0u64, 0xFF, 0);
}
#[test]
#[should_panic]
fn write_int_pad_insufficient_capacity_panic() {
let mut buf = ArrayBuffer::<19>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_int_pad(0u64, b'0', 20);
}
#[test]
fn write_fraction_no_precision() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_fraction(None, 0);
{
let buf = bbuf.filled();
assert_eq!(buf, "");
}
bbuf.clear();
bbuf.write_fraction(None, 1);
{
let buf = bbuf.filled();
assert_eq!(buf, "000000001");
}
bbuf.clear();
bbuf.write_fraction(None, 123_000_000);
{
let buf = bbuf.filled();
assert_eq!(buf, "123");
}
bbuf.clear();
bbuf.write_fraction(None, 999_999_999);
{
let buf = bbuf.filled();
assert_eq!(buf, "999999999");
}
}
#[test]
fn write_fraction_precision() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_fraction(Some(0), 0);
{
let buf = bbuf.filled();
assert_eq!(buf, "");
}
bbuf.clear();
bbuf.write_fraction(Some(1), 0);
{
let buf = bbuf.filled();
assert_eq!(buf, "0");
}
bbuf.clear();
bbuf.write_fraction(Some(9), 0);
{
let buf = bbuf.filled();
assert_eq!(buf, "000000000");
}
bbuf.clear();
bbuf.write_fraction(Some(0), 1);
{
let buf = bbuf.filled();
assert_eq!(buf, "");
}
bbuf.clear();
bbuf.write_fraction(Some(9), 1);
{
let buf = bbuf.filled();
assert_eq!(buf, "000000001");
}
bbuf.clear();
bbuf.write_fraction(Some(0), 123_000_000);
{
let buf = bbuf.filled();
assert_eq!(buf, "");
}
bbuf.clear();
bbuf.write_fraction(Some(1), 123_000_000);
{
let buf = bbuf.filled();
assert_eq!(buf, "1");
}
bbuf.clear();
bbuf.write_fraction(Some(2), 123_000_000);
{
let buf = bbuf.filled();
assert_eq!(buf, "12");
}
bbuf.clear();
bbuf.write_fraction(Some(3), 123_000_000);
{
let buf = bbuf.filled();
assert_eq!(buf, "123");
}
bbuf.clear();
bbuf.write_fraction(Some(6), 123_000_000);
{
let buf = bbuf.filled();
assert_eq!(buf, "123000");
}
bbuf.clear();
bbuf.write_fraction(Some(9), 123_000_000);
{
let buf = bbuf.filled();
assert_eq!(buf, "123000000");
}
bbuf.clear();
bbuf.write_fraction(Some(10), 123_000_000);
{
let buf = bbuf.filled();
assert_eq!(buf, "123000000");
}
bbuf.clear();
bbuf.write_fraction(Some(0), 999_999_999);
{
let buf = bbuf.filled();
assert_eq!(buf, "");
}
bbuf.clear();
bbuf.write_fraction(Some(1), 999_999_999);
{
let buf = bbuf.filled();
assert_eq!(buf, "9");
}
bbuf.clear();
bbuf.write_fraction(Some(3), 999_999_999);
{
let buf = bbuf.filled();
assert_eq!(buf, "999");
}
bbuf.clear();
bbuf.write_fraction(Some(6), 999_999_999);
{
let buf = bbuf.filled();
assert_eq!(buf, "999999");
}
bbuf.clear();
bbuf.write_fraction(Some(9), 999_999_999);
{
let buf = bbuf.filled();
assert_eq!(buf, "999999999");
}
}
#[test]
#[should_panic]
fn write_fraction_too_big_panic() {
let mut buf = ArrayBuffer::<100>::default();
let mut bbuf = buf.as_borrowed();
bbuf.write_fraction(None, 1_000_000_000);
}
}