#![cfg_attr(not(test), no_std)]
use core::marker::PhantomData;
mod teju;
pub use teju::float::Float;
use teju::format::{self, Format};
#[derive(Clone, Copy)]
pub struct Buffer<F: Float, Fmt: Format> {
float: PhantomData<F>,
bytes: Fmt::Buffer,
}
const POS_INF: &str = "inf";
const NEG_INF: &str = "-inf";
const NAN: &str = "NaN";
const POS_ZERO: &str = "0.0";
const NEG_ZERO: &str = "-0.0";
const POS_ZERO_EXP: &str = "0e0";
const NEG_ZERO_EXP: &str = "-0e0";
impl<F: Float, Fmt: Format> Buffer<F, Fmt> {
pub fn new() -> Self {
Buffer { float: PhantomData, bytes: Fmt::new_buffer() }
}
}
impl<F: Float, Fmt: Format> Default for Buffer<F, Fmt> {
fn default() -> Self {
Self::new()
}
}
impl<F: Float> Buffer<F, format::General> {
pub fn format(&mut self, num: F) -> &str {
match num.classify() {
teju::float::FloatType::Finite => self.format_finite(num),
teju::float::FloatType::PosInf => POS_INF,
teju::float::FloatType::NegInf => NEG_INF,
teju::float::FloatType::Nan => NAN,
}
}
pub fn format_finite(&mut self, num: F) -> &str {
match num.classify_finite() {
teju::float::FiniteFloatType::PosZero => return POS_ZERO,
teju::float::FiniteFloatType::NegZero => return NEG_ZERO,
teju::float::FiniteFloatType::Nonzero => (),
}
let ptr = <format::General as teju::format::Sealed>::buffer_as_ptr(&mut self.bytes);
let n = unsafe { num.format_general_finite_nonzero(ptr) };
let slice = unsafe { core::slice::from_raw_parts(ptr, n) };
debug_assert!(n <= self.bytes.len());
unsafe { core::str::from_utf8_unchecked(slice) }
}
}
impl<F: Float> Buffer<F, format::Scientific> {
pub fn format_exp(&mut self, num: F) -> &str {
match num.classify() {
teju::float::FloatType::Finite => self.format_exp_finite(num),
teju::float::FloatType::PosInf => POS_INF,
teju::float::FloatType::NegInf => NEG_INF,
teju::float::FloatType::Nan => NAN,
}
}
pub fn format_exp_finite(&mut self, num: F) -> &str {
match num.classify_finite() {
teju::float::FiniteFloatType::PosZero => return POS_ZERO_EXP,
teju::float::FiniteFloatType::NegZero => return NEG_ZERO_EXP,
teju::float::FiniteFloatType::Nonzero => (),
}
let ptr = <format::Scientific as teju::format::Sealed>::buffer_as_ptr(&mut self.bytes);
let n = unsafe { num.format_exp_finite_nonzero(ptr) };
let slice = unsafe { core::slice::from_raw_parts(ptr, n) };
debug_assert!(n <= self.bytes.len());
unsafe { core::str::from_utf8_unchecked(slice) }
}
}
impl<F: Float> Buffer<F, format::Decimal> {
pub fn format_dec(&mut self, num: F) -> &str {
match num.classify() {
teju::float::FloatType::Finite => self.format_dec_finite(num),
teju::float::FloatType::PosInf => POS_INF,
teju::float::FloatType::NegInf => NEG_INF,
teju::float::FloatType::Nan => NAN,
}
}
pub fn format_dec_finite(&mut self, num: F) -> &str {
match num.classify_finite() {
teju::float::FiniteFloatType::PosZero => return POS_ZERO,
teju::float::FiniteFloatType::NegZero => return NEG_ZERO,
teju::float::FiniteFloatType::Nonzero => (),
}
let ptr = <format::Decimal as teju::format::Sealed>::buffer_as_ptr(&mut self.bytes);
let n = unsafe { num.format_dec_finite_nonzero(ptr) };
let slice = unsafe { core::slice::from_raw_parts(ptr, n) };
debug_assert!(n <= self.bytes.len());
unsafe { core::str::from_utf8_unchecked(slice) }
}
}