mirror of
https://github.com/Noratrieb/mono-fmt.git
synced 2026-01-17 08:45:05 +01:00
std
This commit is contained in:
parent
d7844568ca
commit
bfd86b1338
8 changed files with 795 additions and 51 deletions
|
|
@ -65,6 +65,14 @@ macro_rules! traits {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
|
pub mod macro_exports {
|
||||||
|
pub use super::{$($name, $trait),*};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod pub_exports {
|
||||||
|
pub use super::{$($name, $trait),*};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,4 +85,5 @@ traits!(
|
||||||
struct UpperHexArg: trait UpperHex;
|
struct UpperHexArg: trait UpperHex;
|
||||||
struct UpperExpArg: trait UpperExp;
|
struct UpperExpArg: trait UpperExp;
|
||||||
struct LowerExpArg: trait LowerExp;
|
struct LowerExpArg: trait LowerExp;
|
||||||
|
struct PointerArg: trait Pointer;
|
||||||
);
|
);
|
||||||
|
|
|
||||||
503
src/formatter.rs
Normal file
503
src/formatter.rs
Normal file
|
|
@ -0,0 +1,503 @@
|
||||||
|
use crate::{Debug, FmtOpts, Result, Write};
|
||||||
|
|
||||||
|
pub struct Formatter<W, O> {
|
||||||
|
pub(crate) buf: W,
|
||||||
|
pub(crate) opts: O,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write, O: FmtOpts> core::fmt::Write for Formatter<W, O> {
|
||||||
|
fn write_char(&mut self, c: char) -> std::fmt::Result {
|
||||||
|
self.buf.write_char(c).map_err(|_| std::fmt::Error)
|
||||||
|
}
|
||||||
|
fn write_str(&mut self, s: &str) -> std::fmt::Result {
|
||||||
|
self.buf.write_str(s).map_err(|_| std::fmt::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W> Formatter<W, ()> {
|
||||||
|
pub fn new(buf: W) -> Self {
|
||||||
|
Self { buf, opts: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write, O: FmtOpts> Formatter<W, O> {
|
||||||
|
pub fn write_char(&mut self, char: char) -> Result {
|
||||||
|
self.buf.write_char(char)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_str(&mut self, str: &str) -> Result {
|
||||||
|
self.buf.write_str(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug_list<'b>(&'b mut self) -> DebugList<'b, W, O> {
|
||||||
|
debug_list_new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug_set<'b>(&'b mut self) -> DebugSet<'b, W, O> {
|
||||||
|
debug_set_new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug_map<'b>(&'b mut self) -> DebugMap<'b, W, O> {
|
||||||
|
debug_map_new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_buf<'buf, F, Wrap>(&'buf mut self, wrap: F) -> Formatter<Wrap, O>
|
||||||
|
where
|
||||||
|
F: FnOnce(&'buf mut W) -> Wrap,
|
||||||
|
{
|
||||||
|
Formatter {
|
||||||
|
buf: wrap(&mut self.buf),
|
||||||
|
opts: self.opts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W, O: FmtOpts> Formatter<W, O> {
|
||||||
|
pub(crate) fn wrap_with<ONew: FmtOpts>(
|
||||||
|
&mut self,
|
||||||
|
opts: &ONew,
|
||||||
|
) -> Formatter<&mut W, ONew::ReplaceInnermost<O>> {
|
||||||
|
Formatter {
|
||||||
|
buf: &mut self.buf,
|
||||||
|
opts: opts.override_other(self.opts),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BUILDERS
|
||||||
|
// adapted from `core`
|
||||||
|
use crate as fmt;
|
||||||
|
|
||||||
|
struct PadAdapter<'state, 'buf, W> {
|
||||||
|
buf: &'buf mut W,
|
||||||
|
state: &'state mut PadAdapterState,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PadAdapterState {
|
||||||
|
on_newline: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PadAdapterState {
|
||||||
|
fn default() -> Self {
|
||||||
|
PadAdapterState { on_newline: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'state, 'buf, W> PadAdapter<'state, 'buf, W>
|
||||||
|
where
|
||||||
|
W: Write + 'buf,
|
||||||
|
{
|
||||||
|
fn wrap<'slot, 'fmt, O: FmtOpts>(
|
||||||
|
fmt: &'fmt mut Formatter<W, O>,
|
||||||
|
slot: &'slot mut Option<Self>,
|
||||||
|
state: &'state mut PadAdapterState,
|
||||||
|
) -> fmt::Formatter<&'slot mut PadAdapter<'state, 'buf, W>, O>
|
||||||
|
where
|
||||||
|
'fmt: 'buf + 'slot,
|
||||||
|
{
|
||||||
|
fmt.wrap_buf(move |buf| slot.insert(PadAdapter { buf, state }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> fmt::Write for PadAdapter<'_, '_, W> {
|
||||||
|
fn write_str(&mut self, mut s: &str) -> fmt::Result {
|
||||||
|
while !s.is_empty() {
|
||||||
|
if self.state.on_newline {
|
||||||
|
self.buf.write_str(" ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let split = match s.find('\n') {
|
||||||
|
Some(pos) => {
|
||||||
|
self.state.on_newline = true;
|
||||||
|
pos + 1
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.state.on_newline = false;
|
||||||
|
s.len()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.buf.write_str(&s[..split])?;
|
||||||
|
s = &s[split..];
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "must eventually call `finish()` on Debug builders"]
|
||||||
|
pub struct DebugStruct<'a, W, O> {
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
result: fmt::Result,
|
||||||
|
has_fields: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn debug_struct_new<'a, W: Write, O: FmtOpts>(
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
name: &str,
|
||||||
|
) -> DebugStruct<'a, W, O> {
|
||||||
|
let result = fmt.write_str(name);
|
||||||
|
DebugStruct {
|
||||||
|
fmt,
|
||||||
|
result,
|
||||||
|
has_fields: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, W: Write, O: FmtOpts> DebugStruct<'a, W, O> {
|
||||||
|
pub fn field(&mut self, name: &str, value: &impl Debug) -> &mut Self {
|
||||||
|
self.result = self.result.and_then(|_| {
|
||||||
|
if self.is_pretty() {
|
||||||
|
if !self.has_fields {
|
||||||
|
self.fmt.write_str(" {\n")?;
|
||||||
|
}
|
||||||
|
let mut slot = None;
|
||||||
|
let mut state = Default::default();
|
||||||
|
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
|
||||||
|
writer.write_str(name)?;
|
||||||
|
writer.write_str(": ")?;
|
||||||
|
value.fmt(&mut writer)?;
|
||||||
|
writer.write_str(",\n")
|
||||||
|
} else {
|
||||||
|
let prefix = if self.has_fields { ", " } else { " { " };
|
||||||
|
self.fmt.write_str(prefix)?;
|
||||||
|
self.fmt.write_str(name)?;
|
||||||
|
self.fmt.write_str(": ")?;
|
||||||
|
value.fmt(self.fmt)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.has_fields = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish_non_exhaustive(&mut self) -> fmt::Result {
|
||||||
|
self.result = self.result.and_then(|_| {
|
||||||
|
if self.has_fields {
|
||||||
|
if self.is_pretty() {
|
||||||
|
let mut slot = None;
|
||||||
|
let mut state = Default::default();
|
||||||
|
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
|
||||||
|
writer.write_str("..\n")?;
|
||||||
|
self.fmt.write_str("}")
|
||||||
|
} else {
|
||||||
|
self.fmt.write_str(", .. }")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.fmt.write_str(" { .. }")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(&mut self) -> fmt::Result {
|
||||||
|
if self.has_fields {
|
||||||
|
self.result = self.result.and_then(|_| {
|
||||||
|
if self.is_pretty() {
|
||||||
|
self.fmt.write_str("}")
|
||||||
|
} else {
|
||||||
|
self.fmt.write_str(" }")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_pretty(&self) -> bool {
|
||||||
|
self.fmt.alternate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "must eventually call `finish()` on Debug builders"]
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct DebugTuple<'a, W, O> {
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
result: fmt::Result,
|
||||||
|
fields: usize,
|
||||||
|
empty_name: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn debug_tuple_new<'a, W: Write, O: FmtOpts>(
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
name: &str,
|
||||||
|
) -> DebugTuple<'a, W, O> {
|
||||||
|
let result = fmt.write_str(name);
|
||||||
|
DebugTuple {
|
||||||
|
fmt,
|
||||||
|
result,
|
||||||
|
fields: 0,
|
||||||
|
empty_name: name.is_empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, W: Write, O: FmtOpts> DebugTuple<'a, W, O> {
|
||||||
|
pub fn field(&mut self, value: &impl Debug) -> &mut Self {
|
||||||
|
self.result = self.result.and_then(|_| {
|
||||||
|
if self.is_pretty() {
|
||||||
|
if self.fields == 0 {
|
||||||
|
self.fmt.write_str("(\n")?;
|
||||||
|
}
|
||||||
|
let mut slot = None;
|
||||||
|
let mut state = Default::default();
|
||||||
|
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
|
||||||
|
value.fmt(&mut writer)?;
|
||||||
|
writer.write_str(",\n")
|
||||||
|
} else {
|
||||||
|
let prefix = if self.fields == 0 { "(" } else { ", " };
|
||||||
|
self.fmt.write_str(prefix)?;
|
||||||
|
value.fmt(self.fmt)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.fields += 1;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(&mut self) -> fmt::Result {
|
||||||
|
if self.fields > 0 {
|
||||||
|
self.result = self.result.and_then(|_| {
|
||||||
|
if self.fields == 1 && self.empty_name && !self.is_pretty() {
|
||||||
|
self.fmt.write_str(",")?;
|
||||||
|
}
|
||||||
|
self.fmt.write_str(")")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_pretty(&self) -> bool {
|
||||||
|
self.fmt.alternate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DebugInner<'a, W, O> {
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
result: fmt::Result,
|
||||||
|
has_fields: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, W: Write, O: FmtOpts> DebugInner<'a, W, O> {
|
||||||
|
fn entry(&mut self, entry: &impl Debug) {
|
||||||
|
self.result = self.result.and_then(|_| {
|
||||||
|
if self.is_pretty() {
|
||||||
|
if !self.has_fields {
|
||||||
|
self.fmt.write_str("\n")?;
|
||||||
|
}
|
||||||
|
let mut slot = None;
|
||||||
|
let mut state = Default::default();
|
||||||
|
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
|
||||||
|
entry.fmt(&mut writer)?;
|
||||||
|
writer.write_str(",\n")
|
||||||
|
} else {
|
||||||
|
if self.has_fields {
|
||||||
|
self.fmt.write_str(", ")?
|
||||||
|
}
|
||||||
|
entry.fmt(self.fmt)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.has_fields = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_pretty(&self) -> bool {
|
||||||
|
self.fmt.alternate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "must eventually call `finish()` on Debug builders"]
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct DebugSet<'a, W, O> {
|
||||||
|
inner: DebugInner<'a, W, O>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn debug_set_new<'a, W: Write, O: FmtOpts>(
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
) -> DebugSet<'a, W, O> {
|
||||||
|
let result = fmt.write_str("{");
|
||||||
|
DebugSet {
|
||||||
|
inner: DebugInner {
|
||||||
|
fmt,
|
||||||
|
result,
|
||||||
|
has_fields: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, W: Write, O: FmtOpts> DebugSet<'a, W, O> {
|
||||||
|
pub fn entry(&mut self, entry: &impl Debug) -> &mut Self {
|
||||||
|
self.inner.entry(entry);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entries<D, I>(&mut self, entries: I) -> &mut Self
|
||||||
|
where
|
||||||
|
D: fmt::Debug,
|
||||||
|
I: IntoIterator<Item = D>,
|
||||||
|
{
|
||||||
|
for entry in entries {
|
||||||
|
self.entry(&entry);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(&mut self) -> fmt::Result {
|
||||||
|
self.inner
|
||||||
|
.result
|
||||||
|
.and_then(|_| self.inner.fmt.write_str("}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "must eventually call `finish()` on Debug builders"]
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct DebugList<'a, W, O> {
|
||||||
|
inner: DebugInner<'a, W, O>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn debug_list_new<'a, W: Write, O: FmtOpts>(
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
) -> DebugList<'a, W, O> {
|
||||||
|
let result = fmt.write_str("[");
|
||||||
|
DebugList {
|
||||||
|
inner: DebugInner {
|
||||||
|
fmt,
|
||||||
|
result,
|
||||||
|
has_fields: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, W: Write, O: FmtOpts> DebugList<'a, W, O> {
|
||||||
|
pub fn entry(&mut self, entry: &impl Debug) -> &mut Self {
|
||||||
|
self.inner.entry(entry);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entries<D, I>(&mut self, entries: I) -> &mut Self
|
||||||
|
where
|
||||||
|
D: fmt::Debug,
|
||||||
|
I: IntoIterator<Item = D>,
|
||||||
|
{
|
||||||
|
for entry in entries {
|
||||||
|
self.entry(&entry);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(&mut self) -> fmt::Result {
|
||||||
|
self.inner
|
||||||
|
.result
|
||||||
|
.and_then(|_| self.inner.fmt.write_str("]"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "must eventually call `finish()` on Debug builders"]
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct DebugMap<'a, W, O> {
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
result: fmt::Result,
|
||||||
|
has_fields: bool,
|
||||||
|
has_key: bool,
|
||||||
|
// The state of newlines is tracked between keys and values
|
||||||
|
state: PadAdapterState,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn debug_map_new<'a, 'b, W: Write, O: FmtOpts>(
|
||||||
|
fmt: &'a mut fmt::Formatter<W, O>,
|
||||||
|
) -> DebugMap<'a, W, O> {
|
||||||
|
let result = fmt.write_str("{");
|
||||||
|
DebugMap {
|
||||||
|
fmt,
|
||||||
|
result,
|
||||||
|
has_fields: false,
|
||||||
|
has_key: false,
|
||||||
|
state: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, W: Write, O: FmtOpts> DebugMap<'a, W, O> {
|
||||||
|
pub fn entry(&mut self, key: &impl Debug, value: &impl Debug) -> &mut Self {
|
||||||
|
self.key(key).value(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn key(&mut self, key: &impl Debug) -> &mut Self {
|
||||||
|
self.result = self.result.and_then(|_| {
|
||||||
|
assert!(
|
||||||
|
!self.has_key,
|
||||||
|
"attempted to begin a new map entry \
|
||||||
|
without completing the previous one"
|
||||||
|
);
|
||||||
|
|
||||||
|
if self.is_pretty() {
|
||||||
|
if !self.has_fields {
|
||||||
|
self.fmt.write_str("\n")?;
|
||||||
|
}
|
||||||
|
let mut slot = None;
|
||||||
|
self.state = Default::default();
|
||||||
|
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut self.state);
|
||||||
|
key.fmt(&mut writer)?;
|
||||||
|
writer.write_str(": ")?;
|
||||||
|
} else {
|
||||||
|
if self.has_fields {
|
||||||
|
self.fmt.write_str(", ")?
|
||||||
|
}
|
||||||
|
key.fmt(self.fmt)?;
|
||||||
|
self.fmt.write_str(": ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.has_key = true;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&mut self, value: impl Debug) -> &mut Self {
|
||||||
|
self.result = self.result.and_then(|_| {
|
||||||
|
assert!(
|
||||||
|
self.has_key,
|
||||||
|
"attempted to format a map value before its key"
|
||||||
|
);
|
||||||
|
|
||||||
|
if self.is_pretty() {
|
||||||
|
let mut slot = None;
|
||||||
|
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut self.state);
|
||||||
|
value.fmt(&mut writer)?;
|
||||||
|
writer.write_str(",\n")?;
|
||||||
|
} else {
|
||||||
|
value.fmt(self.fmt)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.has_key = false;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
self.has_fields = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entries<K, V, I>(&mut self, entries: I) -> &mut Self
|
||||||
|
where
|
||||||
|
K: fmt::Debug,
|
||||||
|
V: fmt::Debug,
|
||||||
|
I: IntoIterator<Item = (K, V)>,
|
||||||
|
{
|
||||||
|
for (k, v) in entries {
|
||||||
|
self.entry(&k, &v);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(&mut self) -> fmt::Result {
|
||||||
|
self.result.and_then(|_| {
|
||||||
|
assert!(
|
||||||
|
!self.has_key,
|
||||||
|
"attempted to finish a map with a partial entry"
|
||||||
|
);
|
||||||
|
|
||||||
|
self.fmt.write_str("}")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_pretty(&self) -> bool {
|
||||||
|
self.fmt.alternate()
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/lib.rs
63
src/lib.rs
|
|
@ -1,6 +1,7 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
|
mod formatter;
|
||||||
mod opts;
|
mod opts;
|
||||||
mod rust_core_impl;
|
mod rust_core_impl;
|
||||||
mod write;
|
mod write;
|
||||||
|
|
@ -13,18 +14,23 @@ macro_rules! format_args {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
args::{Arguments, Binary, Debug, Display, LowerExp, LowerHex, Octal, UpperExp, UpperHex},
|
args::{pub_exports::*, Arguments},
|
||||||
|
formatter::Formatter,
|
||||||
opts::FmtOpts,
|
opts::FmtOpts,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type Result = std::result::Result<(), Error>;
|
pub type Result = std::result::Result<(), Error>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Error;
|
pub struct Error;
|
||||||
|
|
||||||
pub trait Write {
|
pub trait Write {
|
||||||
fn write_str(&mut self, str: &str) -> Result;
|
fn write_str(&mut self, str: &str) -> Result;
|
||||||
fn write_char(&mut self, char: char) -> Result;
|
|
||||||
|
fn write_char(&mut self, char: char) -> Result {
|
||||||
|
let mut buf = [0; 4];
|
||||||
|
self.write_str(char.encode_utf8(&mut buf))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Write for String {
|
impl Write for String {
|
||||||
|
|
@ -49,48 +55,6 @@ impl<W: Write> Write for &mut W {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Formatter<W, O> {
|
|
||||||
buf: W,
|
|
||||||
opts: O,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write, O: FmtOpts> core::fmt::Write for Formatter<W, O> {
|
|
||||||
fn write_char(&mut self, c: char) -> std::fmt::Result {
|
|
||||||
self.buf.write_char(c).map_err(|_| std::fmt::Error)
|
|
||||||
}
|
|
||||||
fn write_str(&mut self, s: &str) -> std::fmt::Result {
|
|
||||||
self.buf.write_str(s).map_err(|_| std::fmt::Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W> Formatter<W, ()> {
|
|
||||||
fn new(buf: W) -> Self {
|
|
||||||
Self { buf, opts: () }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write, O: FmtOpts> Formatter<W, O> {
|
|
||||||
pub fn write_char(&mut self, char: char) -> Result {
|
|
||||||
self.buf.write_char(char)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_str(&mut self, str: &str) -> Result {
|
|
||||||
self.buf.write_str(str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W, O: FmtOpts> Formatter<W, O> {
|
|
||||||
fn wrap_with<'opt, ONew: FmtOpts>(
|
|
||||||
&mut self,
|
|
||||||
opts: &ONew,
|
|
||||||
) -> Formatter<&mut W, ONew::ReplaceInnermost<O>> {
|
|
||||||
Formatter {
|
|
||||||
buf: &mut self.buf,
|
|
||||||
opts: opts.override_other(self.opts),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod helpers {
|
pub mod helpers {
|
||||||
use crate::{Arguments, Formatter, Result, Write};
|
use crate::{Arguments, Formatter, Result, Write};
|
||||||
|
|
||||||
|
|
@ -108,15 +72,12 @@ pub mod helpers {
|
||||||
|
|
||||||
/// Not part of the public API.
|
/// Not part of the public API.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
mod _private {
|
pub mod _private {
|
||||||
pub use mono_fmt_macro::__format_args;
|
pub use mono_fmt_macro::__format_args;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
args::{
|
args::{macro_exports::*, Str},
|
||||||
BinaryArg, DebugArg, DisplayArg, LowerExpArg, LowerHexArg, OctalArg, Str, UpperExpArg,
|
opts::exports::*,
|
||||||
UpperHexArg,
|
|
||||||
},
|
|
||||||
opts::{WithAlign, WithAlternate, WithFill, WithWidth},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,10 @@ macro_rules! options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
||||||
|
pub mod exports {
|
||||||
|
pub use super::{$($with_name),*};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
21
src/rust_core_impl/aggregated.rs
Normal file
21
src/rust_core_impl/aggregated.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
//! A bunch of impls copied from all over the place
|
||||||
|
|
||||||
|
use crate::{Debug, FmtOpts, Formatter, Result, Write};
|
||||||
|
|
||||||
|
impl<T: Debug + ?Sized> Debug for &T {
|
||||||
|
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
|
||||||
|
<T as Debug>::fmt(&self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug, const N: usize> Debug for [T; N] {
|
||||||
|
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
|
||||||
|
<[T] as Debug>::fmt(&&self[..], f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug> Debug for [T] {
|
||||||
|
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result {
|
||||||
|
f.debug_list().entries(self.iter()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
//! Copied modified stuff from core
|
//! Copied modified stuff from core
|
||||||
|
|
||||||
|
mod aggregated;
|
||||||
mod num;
|
mod num;
|
||||||
|
|
||||||
use crate::{opts::Alignment, Error, FmtOpts, Formatter, Result, Write};
|
use crate::{opts::Alignment, Error, FmtOpts, Formatter, Result, Write};
|
||||||
|
|
|
||||||
21
tests/base.rs
Normal file
21
tests/base.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
use mono_fmt::{FmtOpts, Write};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate mono_fmt;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_flags() {
|
||||||
|
// No residual flags left by pointer formatting
|
||||||
|
let p = "".as_ptr();
|
||||||
|
assert_eq!(format!("{:p} {:x}", p, 16), format!("{p:p} 10"));
|
||||||
|
|
||||||
|
assert_eq!(format!("{: >3}", 'a'), " a");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pointer_formats_data_pointer() {
|
||||||
|
let b: &[u8] = b"";
|
||||||
|
let s: &str = "";
|
||||||
|
assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
|
||||||
|
assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
|
||||||
|
}
|
||||||
224
tests/num.rs
Normal file
224
tests/num.rs
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate mono_fmt;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_int() {
|
||||||
|
// Formatting integers should select the right implementation based off
|
||||||
|
// the type of the argument. Also, hex/octal/binary should be defined
|
||||||
|
// for integers, but they shouldn't emit the negative sign.
|
||||||
|
assert_eq!(format!("{}", 1isize), "1");
|
||||||
|
assert_eq!(format!("{}", 1i8), "1");
|
||||||
|
assert_eq!(format!("{}", 1i16), "1");
|
||||||
|
assert_eq!(format!("{}", 1i32), "1");
|
||||||
|
assert_eq!(format!("{}", 1i64), "1");
|
||||||
|
assert_eq!(format!("{}", -1isize), "-1");
|
||||||
|
assert_eq!(format!("{}", -1i8), "-1");
|
||||||
|
assert_eq!(format!("{}", -1i16), "-1");
|
||||||
|
assert_eq!(format!("{}", -1i32), "-1");
|
||||||
|
assert_eq!(format!("{}", -1i64), "-1");
|
||||||
|
assert_eq!(format!("{:?}", 1isize), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1i8), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1i16), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1i32), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1i64), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1isize), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1i8), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1i16), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1i32), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1i64), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1isize), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1i8), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1i16), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1i32), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1i64), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1isize), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1i8), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1i16), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1i32), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1i64), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1isize), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1i8), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1i16), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1i32), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1i64), "1");
|
||||||
|
assert_eq!(format!("{:e}", 1isize), "1e0");
|
||||||
|
assert_eq!(format!("{:e}", 1i8), "1e0");
|
||||||
|
assert_eq!(format!("{:e}", 1i16), "1e0");
|
||||||
|
assert_eq!(format!("{:e}", 1i32), "1e0");
|
||||||
|
assert_eq!(format!("{:e}", 1i64), "1e0");
|
||||||
|
assert_eq!(format!("{:E}", 1isize), "1E0");
|
||||||
|
assert_eq!(format!("{:E}", 1i8), "1E0");
|
||||||
|
assert_eq!(format!("{:E}", 1i16), "1E0");
|
||||||
|
assert_eq!(format!("{:E}", 1i32), "1E0");
|
||||||
|
assert_eq!(format!("{:E}", 1i64), "1E0");
|
||||||
|
|
||||||
|
assert_eq!(format!("{}", 1usize), "1");
|
||||||
|
assert_eq!(format!("{}", 1u8), "1");
|
||||||
|
assert_eq!(format!("{}", 1u16), "1");
|
||||||
|
assert_eq!(format!("{}", 1u32), "1");
|
||||||
|
assert_eq!(format!("{}", 1u64), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1usize), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1u8), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1u16), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1u32), "1");
|
||||||
|
assert_eq!(format!("{:?}", 1u64), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1usize), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1u8), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1u16), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1u32), "1");
|
||||||
|
assert_eq!(format!("{:b}", 1u64), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1usize), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1u8), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1u16), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1u32), "1");
|
||||||
|
assert_eq!(format!("{:x}", 1u64), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1usize), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1u8), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1u16), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1u32), "1");
|
||||||
|
assert_eq!(format!("{:X}", 1u64), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1usize), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1u8), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1u16), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1u32), "1");
|
||||||
|
assert_eq!(format!("{:o}", 1u64), "1");
|
||||||
|
assert_eq!(format!("{:e}", 1u8), "1e0");
|
||||||
|
assert_eq!(format!("{:e}", 1u16), "1e0");
|
||||||
|
assert_eq!(format!("{:e}", 1u32), "1e0");
|
||||||
|
assert_eq!(format!("{:e}", 1u64), "1e0");
|
||||||
|
assert_eq!(format!("{:E}", 1u8), "1E0");
|
||||||
|
assert_eq!(format!("{:E}", 1u16), "1E0");
|
||||||
|
assert_eq!(format!("{:E}", 1u32), "1E0");
|
||||||
|
assert_eq!(format!("{:E}", 1u64), "1E0");
|
||||||
|
|
||||||
|
// Test a larger number
|
||||||
|
assert_eq!(format!("{:b}", 55), "110111");
|
||||||
|
assert_eq!(format!("{:o}", 55), "67");
|
||||||
|
assert_eq!(format!("{}", 55), "55");
|
||||||
|
assert_eq!(format!("{:x}", 55), "37");
|
||||||
|
assert_eq!(format!("{:X}", 55), "37");
|
||||||
|
assert_eq!(format!("{:e}", 55), "5.5e1");
|
||||||
|
assert_eq!(format!("{:E}", 55), "5.5E1");
|
||||||
|
assert_eq!(format!("{:e}", 10000000000u64), "1e10");
|
||||||
|
assert_eq!(format!("{:E}", 10000000000u64), "1E10");
|
||||||
|
assert_eq!(format!("{:e}", 10000000001u64), "1.0000000001e10");
|
||||||
|
assert_eq!(format!("{:E}", 10000000001u64), "1.0000000001E10");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_int_exp_limits() {
|
||||||
|
assert_eq!(format!("{:e}", i8::MIN), "-1.28e2");
|
||||||
|
assert_eq!(format!("{:e}", i8::MAX), "1.27e2");
|
||||||
|
assert_eq!(format!("{:e}", i16::MIN), "-3.2768e4");
|
||||||
|
assert_eq!(format!("{:e}", i16::MAX), "3.2767e4");
|
||||||
|
assert_eq!(format!("{:e}", i32::MIN), "-2.147483648e9");
|
||||||
|
assert_eq!(format!("{:e}", i32::MAX), "2.147483647e9");
|
||||||
|
assert_eq!(format!("{:e}", i64::MIN), "-9.223372036854775808e18");
|
||||||
|
assert_eq!(format!("{:e}", i64::MAX), "9.223372036854775807e18");
|
||||||
|
assert_eq!(format!("{:e}", i128::MIN), "-1.70141183460469231731687303715884105728e38");
|
||||||
|
assert_eq!(format!("{:e}", i128::MAX), "1.70141183460469231731687303715884105727e38");
|
||||||
|
|
||||||
|
assert_eq!(format!("{:e}", u8::MAX), "2.55e2");
|
||||||
|
assert_eq!(format!("{:e}", u16::MAX), "6.5535e4");
|
||||||
|
assert_eq!(format!("{:e}", u32::MAX), "4.294967295e9");
|
||||||
|
assert_eq!(format!("{:e}", u64::MAX), "1.8446744073709551615e19");
|
||||||
|
assert_eq!(format!("{:e}", u128::MAX), "3.40282366920938463463374607431768211455e38");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_int_exp_precision() {
|
||||||
|
//test adding precision
|
||||||
|
assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2");
|
||||||
|
assert_eq!(format!("{:.10e}", i16::MIN), "-3.2768000000e4");
|
||||||
|
assert_eq!(format!("{:.10e}", i32::MIN), "-2.1474836480e9");
|
||||||
|
assert_eq!(format!("{:.20e}", i64::MIN), "-9.22337203685477580800e18");
|
||||||
|
assert_eq!(format!("{:.40e}", i128::MIN), "-1.7014118346046923173168730371588410572800e38");
|
||||||
|
|
||||||
|
//test rounding
|
||||||
|
assert_eq!(format!("{:.1e}", i8::MIN), "-1.3e2");
|
||||||
|
assert_eq!(format!("{:.1e}", i16::MIN), "-3.3e4");
|
||||||
|
assert_eq!(format!("{:.1e}", i32::MIN), "-2.1e9");
|
||||||
|
assert_eq!(format!("{:.1e}", i64::MIN), "-9.2e18");
|
||||||
|
assert_eq!(format!("{:.1e}", i128::MIN), "-1.7e38");
|
||||||
|
|
||||||
|
//test huge precision
|
||||||
|
assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000)));
|
||||||
|
//test zero precision
|
||||||
|
assert_eq!(format!("{:.0e}", 1), format!("1e0",));
|
||||||
|
assert_eq!(format!("{:.0e}", 35), format!("4e1",));
|
||||||
|
|
||||||
|
//test padding with precision (and sign)
|
||||||
|
assert_eq!(format!("{:+10.3e}", 1), " +1.000e0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_int_zero() {
|
||||||
|
assert_eq!(format!("{}", 0), "0");
|
||||||
|
assert_eq!(format!("{:?}", 0), "0");
|
||||||
|
assert_eq!(format!("{:b}", 0), "0");
|
||||||
|
assert_eq!(format!("{:o}", 0), "0");
|
||||||
|
assert_eq!(format!("{:x}", 0), "0");
|
||||||
|
assert_eq!(format!("{:X}", 0), "0");
|
||||||
|
assert_eq!(format!("{:e}", 0), "0e0");
|
||||||
|
assert_eq!(format!("{:E}", 0), "0E0");
|
||||||
|
|
||||||
|
assert_eq!(format!("{}", 0u32), "0");
|
||||||
|
assert_eq!(format!("{:?}", 0u32), "0");
|
||||||
|
assert_eq!(format!("{:b}", 0u32), "0");
|
||||||
|
assert_eq!(format!("{:o}", 0u32), "0");
|
||||||
|
assert_eq!(format!("{:x}", 0u32), "0");
|
||||||
|
assert_eq!(format!("{:X}", 0u32), "0");
|
||||||
|
assert_eq!(format!("{:e}", 0u32), "0e0");
|
||||||
|
assert_eq!(format!("{:E}", 0u32), "0E0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_int_flags() {
|
||||||
|
assert_eq!(format!("{:3}", 1), " 1");
|
||||||
|
assert_eq!(format!("{:>3}", 1), " 1");
|
||||||
|
assert_eq!(format!("{:>+3}", 1), " +1");
|
||||||
|
assert_eq!(format!("{:<3}", 1), "1 ");
|
||||||
|
assert_eq!(format!("{:#}", 1), "1");
|
||||||
|
assert_eq!(format!("{:#x}", 10), "0xa");
|
||||||
|
assert_eq!(format!("{:#X}", 10), "0xA");
|
||||||
|
assert_eq!(format!("{:#5x}", 10), " 0xa");
|
||||||
|
assert_eq!(format!("{:#o}", 10), "0o12");
|
||||||
|
assert_eq!(format!("{:08x}", 10), "0000000a");
|
||||||
|
assert_eq!(format!("{:8x}", 10), " a");
|
||||||
|
assert_eq!(format!("{:<8x}", 10), "a ");
|
||||||
|
assert_eq!(format!("{:>8x}", 10), " a");
|
||||||
|
assert_eq!(format!("{:#08x}", 10), "0x00000a");
|
||||||
|
assert_eq!(format!("{:08}", -10), "-0000010");
|
||||||
|
assert_eq!(format!("{:x}", !0u8), "ff");
|
||||||
|
assert_eq!(format!("{:X}", !0u8), "FF");
|
||||||
|
assert_eq!(format!("{:b}", !0u8), "11111111");
|
||||||
|
assert_eq!(format!("{:o}", !0u8), "377");
|
||||||
|
assert_eq!(format!("{:#x}", !0u8), "0xff");
|
||||||
|
assert_eq!(format!("{:#X}", !0u8), "0xFF");
|
||||||
|
assert_eq!(format!("{:#b}", !0u8), "0b11111111");
|
||||||
|
assert_eq!(format!("{:#o}", !0u8), "0o377");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_int_sign_padding() {
|
||||||
|
assert_eq!(format!("{:+5}", 1), " +1");
|
||||||
|
assert_eq!(format!("{:+5}", -1), " -1");
|
||||||
|
assert_eq!(format!("{:05}", 1), "00001");
|
||||||
|
assert_eq!(format!("{:05}", -1), "-0001");
|
||||||
|
assert_eq!(format!("{:+05}", 1), "+0001");
|
||||||
|
assert_eq!(format!("{:+05}", -1), "-0001");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_int_twos_complement() {
|
||||||
|
assert_eq!(format!("{}", i8::MIN), "-128");
|
||||||
|
assert_eq!(format!("{}", i16::MIN), "-32768");
|
||||||
|
assert_eq!(format!("{}", i32::MIN), "-2147483648");
|
||||||
|
assert_eq!(format!("{}", i64::MIN), "-9223372036854775808");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_debug_hex() {
|
||||||
|
assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]");
|
||||||
|
assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]");
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue