This commit is contained in:
nora 2022-09-25 13:27:49 +02:00
parent a90c1bf054
commit 6fc05446fb
7 changed files with 143 additions and 30 deletions

View file

@ -13,3 +13,8 @@ edition = "2021"
[dependencies] [dependencies]
mono-fmt-macro = { path = "./mono-fmt-macro" } mono-fmt-macro = { path = "./mono-fmt-macro" }
[features]
alloc = []
std = ["alloc"]
default = ["std"]

View file

@ -6,11 +6,11 @@ pub struct Formatter<W, O> {
} }
impl<W: Write, O: FmtOpts> core::fmt::Write for Formatter<W, O> { impl<W: Write, O: FmtOpts> core::fmt::Write for Formatter<W, O> {
fn write_char(&mut self, c: char) -> std::fmt::Result { fn write_char(&mut self, c: char) -> core::fmt::Result {
self.buf.write_char(c).map_err(|_| std::fmt::Error) self.buf.write_char(c).map_err(|_| core::fmt::Error)
} }
fn write_str(&mut self, s: &str) -> std::fmt::Result { fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.buf.write_str(s).map_err(|_| std::fmt::Error) self.buf.write_str(s).map_err(|_| core::fmt::Error)
} }
} }

View file

@ -1,5 +1,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(dead_code)] #![allow(dead_code)]
extern crate alloc;
mod args; mod args;
mod formatter; mod formatter;
mod opts; mod opts;
@ -19,7 +22,7 @@ pub use crate::{
opts::FmtOpts, opts::FmtOpts,
}; };
pub type Result = std::result::Result<(), Error>; pub type Result = core::result::Result<(), Error>;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Error; pub struct Error;
@ -34,6 +37,9 @@ pub trait Write {
} }
pub mod helpers { pub mod helpers {
#[cfg(feature = "alloc")]
use alloc::string::String;
use crate::{Arguments, Formatter, Result, Write}; use crate::{Arguments, Formatter, Result, Write};
pub fn write<W: Write, A: Arguments>(buffer: W, args: A) -> Result { pub fn write<W: Write, A: Arguments>(buffer: W, args: A) -> Result {
@ -41,6 +47,7 @@ pub mod helpers {
args.fmt(&mut fmt) args.fmt(&mut fmt)
} }
#[cfg(feature = "alloc")]
pub fn format<A: Arguments>(args: A) -> String { pub fn format<A: Arguments>(args: A) -> String {
let mut string = String::new(); let mut string = String::new();
write(&mut string, args).unwrap(); write(&mut string, args).unwrap();
@ -59,6 +66,7 @@ pub mod _private {
}; };
} }
#[cfg(feature = "alloc")]
#[macro_export] #[macro_export]
macro_rules! format { macro_rules! format {
($($tt:tt)*) => { ($($tt:tt)*) => {

View file

@ -92,8 +92,21 @@ mod char {
} }
mod strings { mod strings {
#[cfg(feature = "alloc")]
use alloc::string::String;
use super::impl_prelude::*; use super::impl_prelude::*;
#[cfg(feature = "alloc")]
impl Debug for String {
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
f.write_char('"')?;
f.write_str(self)?;
f.write_char('"')
}
}
#[cfg(feature = "alloc")]
impl Display for String { impl Display for String {
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result { fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
f.write_str(self) f.write_str(self)
@ -113,12 +126,4 @@ mod strings {
f.write_char('"') f.write_char('"')
} }
} }
impl Debug for String {
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
f.write_char('"')?;
f.write_str(self)?;
f.write_char('"')
}
}
} }

View file

@ -249,7 +249,7 @@ impl<W: Write, O: FmtOpts> Formatter<W, O> {
default: Alignment, default: Alignment,
self_fill: char, self_fill: char,
self_align: Alignment, self_align: Alignment,
) -> std::result::Result<PostPadding, Error> { ) -> core::result::Result<PostPadding, Error> {
// WARN: We might have `self` in an invalid state, don't touch `self` opts // WARN: We might have `self` in an invalid state, don't touch `self` opts
let align = match self_align { let align = match self_align {
Alignment::Unknown => default, Alignment::Unknown => default,
@ -279,7 +279,7 @@ impl<W: Write, O: FmtOpts> Formatter<W, O> {
// in a bad value for `buf` into `numfmt::to_shortest_str` since it is a // in a bad value for `buf` into `numfmt::to_shortest_str` since it is a
// public function. // public function.
// FIXME: Determine whether this could result in UB. // FIXME: Determine whether this could result in UB.
buf.write_str(unsafe { std::str::from_utf8_unchecked(s) }) buf.write_str(unsafe { core::str::from_utf8_unchecked(s) })
} }
if !formatted.sign.is_empty() { if !formatted.sign.is_empty() {

View file

@ -1,6 +1,6 @@
//! Integer and floating-point number formatting //! Integer and floating-point number formatting
use std::{ use core::{
mem::MaybeUninit, mem::MaybeUninit,
ops::{Div, Rem, Sub}, ops::{Div, Rem, Sub},
ptr, slice, str, ptr, slice, str,
@ -223,7 +223,7 @@ macro_rules! impl_Display {
// is safe to access. // is safe to access.
unsafe { unsafe {
// need at least 16 bits for the 4-characters-at-a-time to work. // need at least 16 bits for the 4-characters-at-a-time to work.
assert!(std::mem::size_of::<$u>() >= 2); assert!(core::mem::size_of::<$u>() >= 2);
// eagerly decode 4 characters at a time // eagerly decode 4 characters at a time
while n >= 10000 { while n >= 10000 {

View file

@ -1,17 +1,5 @@
use crate::{Result, Write}; use crate::{Result, Write};
impl Write for String {
fn write_str(&mut self, str: &str) -> Result {
self.push_str(str);
Ok(())
}
fn write_char(&mut self, char: char) -> Result {
self.push(char);
Ok(())
}
}
impl<W: Write> Write for &mut W { impl<W: Write> Write for &mut W {
fn write_str(&mut self, str: &str) -> Result { fn write_str(&mut self, str: &str) -> Result {
<W as Write>::write_str(self, str) <W as Write>::write_str(self, str)
@ -21,3 +9,110 @@ impl<W: Write> Write for &mut W {
<W as Write>::write_char(self, char) <W as Write>::write_char(self, char)
} }
} }
impl Write for &'_ mut [u8] {
fn write_str(&mut self, str: &str) -> Result {
let data = str.as_bytes();
let amt = core::cmp::min(str.len(), self.len());
let (a, b) = core::mem::replace(self, &mut []).split_at_mut(amt);
a.copy_from_slice(&data[..amt]);
*self = b;
Ok(())
}
}
#[cfg(feature = "alloc")]
mod alloc_impls {
use alloc::{boxed::Box, collections::VecDeque, string::String, vec::Vec};
use crate::{Result, Write};
impl Write for String {
fn write_str(&mut self, str: &str) -> Result {
self.push_str(str);
Ok(())
}
fn write_char(&mut self, char: char) -> Result {
self.push(char);
Ok(())
}
}
impl<W: Write> Write for Box<W> {
fn write_str(&mut self, str: &str) -> Result {
<W as Write>::write_str(self, str)
}
fn write_char(&mut self, char: char) -> Result {
<W as Write>::write_char(self, char)
}
}
impl Write for Vec<u8> {
fn write_str(&mut self, str: &str) -> Result {
self.extend(str.as_bytes());
Ok(())
}
}
impl Write for VecDeque<u8> {
fn write_str(&mut self, str: &str) -> Result {
self.extend(str.as_bytes());
Ok(())
}
}
}
#[cfg(feature = "std")]
mod std_impls {
use std::{
fs,
io::{self, Write as IoWrite},
net, process,
};
use crate::Result;
trait IoWriteForwad: IoWrite {
fn write_str(&mut self, str: &str) -> Result {
<Self as IoWrite>::write_all(self, str.as_bytes()).map_err(|_| crate::Error)
}
fn write_char(&mut self, char: char) -> Result {
let mut buf = [0; 4];
<Self as IoWrite>::write_all(self, char.encode_utf8(&mut buf).as_bytes())
.map_err(|_| crate::Error)
}
}
macro_rules! impl_io_forward {
($($name:ty),* $(,)?) => {
$(
impl IoWriteForwad for $name {}
)*
};
}
impl_io_forward!(
fs::File,
net::TcpStream,
process::ChildStdin,
io::Cursor<&'_ mut [u8]>,
io::Sink,
io::Stderr,
io::StderrLock<'_>,
io::Stdout,
io::StdoutLock<'_>,
io::Cursor<&'_ mut Vec<u8>>,
io::Cursor<Box<[u8]>>,
io::Cursor<Vec<u8>>,
&fs::File,
&net::TcpStream,
&process::ChildStdin,
&io::Sink,
&io::Stderr,
&io::Stdout,
);
}