#![cfg_attr(not(any(test, feature = "std")), no_std)]
#![feature(c_variadic)]
use core::{ffi::*, fmt};
pub mod output;
mod parser;
use argument::*;
pub use parser::format;
pub mod argument {
use super::*;
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Flags: u8 {
const LEFT_ALIGN = 0b00000001;
const PREPEND_PLUS = 0b00000010;
const PREPEND_SPACE = 0b00000100;
const PREPEND_ZERO = 0b00001000;
const THOUSANDS_GROUPING = 0b00010000;
const ALTERNATE_FORM = 0b00100000;
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum DoubleFormat {
Normal,
UpperNormal,
Scientific,
UpperScientific,
Auto,
UpperAuto,
Hex,
UpperHex,
}
impl DoubleFormat {
pub fn is_upper(self) -> bool {
use DoubleFormat::*;
matches!(self, UpperNormal | UpperScientific | UpperAuto | UpperHex)
}
pub fn set_upper(self, upper: bool) -> Self {
use DoubleFormat::*;
match self {
Normal | UpperNormal => {
if upper {
UpperNormal
} else {
Normal
}
}
Scientific | UpperScientific => {
if upper {
UpperScientific
} else {
Scientific
}
}
Auto | UpperAuto => {
if upper {
UpperAuto
} else {
Auto
}
}
Hex | UpperHex => {
if upper {
UpperHex
} else {
Hex
}
}
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub enum SignedInt {
Int(c_int),
Char(c_schar),
Short(c_short),
Long(c_long),
LongLong(c_longlong),
Isize(isize),
}
impl From<SignedInt> for i64 {
fn from(num: SignedInt) -> Self {
#[allow(clippy::unnecessary_cast)]
match num {
SignedInt::Int(x) => x as i64,
SignedInt::Char(x) => x as i64,
SignedInt::Short(x) => x as i64,
SignedInt::Long(x) => x as i64,
SignedInt::LongLong(x) => x as i64,
SignedInt::Isize(x) => x as i64,
}
}
}
impl SignedInt {
pub fn is_sign_negative(self) -> bool {
match self {
SignedInt::Int(x) => x < 0,
SignedInt::Char(x) => x < 0,
SignedInt::Short(x) => x < 0,
SignedInt::Long(x) => x < 0,
SignedInt::LongLong(x) => x < 0,
SignedInt::Isize(x) => x < 0,
}
}
}
impl fmt::Display for SignedInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SignedInt::Int(x) => fmt::Display::fmt(x, f),
SignedInt::Char(x) => fmt::Display::fmt(x, f),
SignedInt::Short(x) => fmt::Display::fmt(x, f),
SignedInt::Long(x) => fmt::Display::fmt(x, f),
SignedInt::LongLong(x) => fmt::Display::fmt(x, f),
SignedInt::Isize(x) => fmt::Display::fmt(x, f),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub enum UnsignedInt {
Int(c_uint),
Char(c_uchar),
Short(c_ushort),
Long(c_ulong),
LongLong(c_ulonglong),
Isize(usize),
}
impl From<UnsignedInt> for u64 {
fn from(num: UnsignedInt) -> Self {
#[allow(clippy::unnecessary_cast)]
match num {
UnsignedInt::Int(x) => x as u64,
UnsignedInt::Char(x) => x as u64,
UnsignedInt::Short(x) => x as u64,
UnsignedInt::Long(x) => x as u64,
UnsignedInt::LongLong(x) => x as u64,
UnsignedInt::Isize(x) => x as u64,
}
}
}
impl fmt::Display for UnsignedInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnsignedInt::Int(x) => fmt::Display::fmt(x, f),
UnsignedInt::Char(x) => fmt::Display::fmt(x, f),
UnsignedInt::Short(x) => fmt::Display::fmt(x, f),
UnsignedInt::Long(x) => fmt::Display::fmt(x, f),
UnsignedInt::LongLong(x) => fmt::Display::fmt(x, f),
UnsignedInt::Isize(x) => fmt::Display::fmt(x, f),
}
}
}
impl fmt::LowerHex for UnsignedInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnsignedInt::Int(x) => fmt::LowerHex::fmt(x, f),
UnsignedInt::Char(x) => fmt::LowerHex::fmt(x, f),
UnsignedInt::Short(x) => fmt::LowerHex::fmt(x, f),
UnsignedInt::Long(x) => fmt::LowerHex::fmt(x, f),
UnsignedInt::LongLong(x) => fmt::LowerHex::fmt(x, f),
UnsignedInt::Isize(x) => fmt::LowerHex::fmt(x, f),
}
}
}
impl fmt::UpperHex for UnsignedInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnsignedInt::Int(x) => fmt::UpperHex::fmt(x, f),
UnsignedInt::Char(x) => fmt::UpperHex::fmt(x, f),
UnsignedInt::Short(x) => fmt::UpperHex::fmt(x, f),
UnsignedInt::Long(x) => fmt::UpperHex::fmt(x, f),
UnsignedInt::LongLong(x) => fmt::UpperHex::fmt(x, f),
UnsignedInt::Isize(x) => fmt::UpperHex::fmt(x, f),
}
}
}
impl fmt::Octal for UnsignedInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnsignedInt::Int(x) => fmt::Octal::fmt(x, f),
UnsignedInt::Char(x) => fmt::Octal::fmt(x, f),
UnsignedInt::Short(x) => fmt::Octal::fmt(x, f),
UnsignedInt::Long(x) => fmt::Octal::fmt(x, f),
UnsignedInt::LongLong(x) => fmt::Octal::fmt(x, f),
UnsignedInt::Isize(x) => fmt::Octal::fmt(x, f),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Argument<'a> {
pub flags: Flags,
pub width: c_int,
pub precision: Option<c_int>,
pub specifier: Specifier<'a>,
}
impl<'a> From<Specifier<'a>> for Argument<'a> {
fn from(specifier: Specifier<'a>) -> Self {
Self {
flags: Flags::empty(),
width: 0,
precision: None,
specifier,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[non_exhaustive]
pub enum Specifier<'a> {
Percent,
Int(SignedInt),
Uint(UnsignedInt),
Octal(UnsignedInt),
Double { value: f64, format: DoubleFormat },
Bytes(&'a [u8]),
String(&'a CStr),
Char(c_char),
Hex(UnsignedInt),
UpperHex(UnsignedInt),
Pointer(*const ()),
WriteBytesWritten(c_int, *const c_int),
}
}