#![feature(fmt_internals)]
#![feature(unicode_internals)]
#![feature(specialization)]
#![feature(print_internals)]
#![feature(rustc_private)]
#[doc(hidden)]
#[inline]
pub fn _print(args: Arguments) {
std::io::_print(args)
}
pub mod codegen;
mod erase;
mod macros;
mod fmt_macros;
use std::io;
use std::fmt::{self, Arguments, ArgumentV1};
use std::fmt::rt::v1;
use std::borrow::Cow;
use std::marker::PhantomData;
pub use codegen::FormatArgs;
#[derive(Debug)]
pub enum Error<'a> {
BadSyntax(Vec<(String, Option<String>)>),
BadIndex(usize),
BadName(&'a str),
NoSuchFormat(&'a str),
UnsatisfiedFormat {
idx: usize,
must_implement: &'static str,
},
BadCount(usize),
Io(std::io::Error),
Fmt(std::fmt::Error),
}
impl<'a> From<std::io::Error> for Error<'a> {
fn from(e: std::io::Error) -> Self {
Error::Io(e)
}
}
impl<'a> From<std::fmt::Error> for Error<'a> {
fn from(e: std::fmt::Error) -> Self {
Error::Fmt(e)
}
}
impl<'a> std::error::Error for Error<'a> {
fn description(&self) -> &str {
match *self {
Error::BadSyntax(_) => "bad syntax",
Error::BadIndex(_) => "out-of-range index",
Error::BadName(_) => "unknown name",
Error::NoSuchFormat(_) => "bad formatting specifier",
Error::UnsatisfiedFormat{..} => "formatting trait not satisfied",
Error::BadCount(_) => "non-integer used as count",
Error::Io(ref e) => e.description(),
Error::Fmt(ref f) => f.description(),
}
}
fn cause(&self) -> Option<&dyn std::error::Error> {
match *self {
Error::Io(ref e) => Some(e),
Error::Fmt(ref e) => Some(e),
_ => None,
}
}
}
impl<'a> fmt::Display for Error<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::BadIndex(i) => write!(fmt, "index {} out of range", i),
Error::BadName(n) => write!(fmt, "unknown name {:?}", n),
Error::NoSuchFormat(c) => write!(fmt, "bad formatting specifier {:?}", c),
Error::UnsatisfiedFormat { idx, must_implement } =>
write!(fmt, "argument {} does not implement {}", idx, must_implement),
Error::BadCount(i) => write!(fmt, "argument {} cannot be used as a count", i),
Error::Io(ref e) => e.fmt(fmt),
Error::Fmt(ref e) => e.fmt(fmt),
Error::BadSyntax(ref errors) => {
for (i, err) in errors.iter().enumerate() {
if i > 0 {
fmt.write_str("; ")?;
}
fmt.write_str(&err.0)?;
if let Some(ref more) = err.1 {
write!(fmt, " ({})", more)?;
}
}
Ok(())
}
}
}
}
pub struct Param<'a> {
name: Option<&'static str>,
value: &'a dyn erase::Format,
as_usize: Option<usize>,
}
impl<'a> Param<'a> {
pub fn normal<T>(t: &'a T) -> Param<'a> {
use erase::Format;
Param {
name: None,
as_usize: t.as_usize(),
value: t,
}
}
pub fn named<T>(name: &'static str, t: &'a T) -> Param<'a> {
use erase::Format;
Param {
name: Some(name),
as_usize: t.as_usize(),
value: t,
}
}
}
enum PreparedArgument<T> {
Normal(fn(&T, &mut fmt::Formatter) -> fmt::Result),
Usize(fn(&T) -> &usize),
}
impl<T> Copy for PreparedArgument<T> {}
impl<T> Clone for PreparedArgument<T> {
fn clone(&self) -> Self { *self }
}
pub struct PreparedFormat<'s, T: FormatArgs> {
inner: Parsed<'s, DelayedParse<T>>,
}
impl<'s, T: FormatArgs> PreparedFormat<'s, T> {
#[inline]
pub fn prepare(spec: &'s str) -> Result<Self, Error> {
parse(spec, &mut DelayedParse::<T>(PhantomData))
.map(|result| PreparedFormat { inner: result })
}
#[inline]
pub fn newln(&mut self) -> &mut Self {
self.inner.newln();
self
}
pub fn with<F: FnOnce(Arguments) -> R, R>(&self, t: &T, f: F) -> R {
let pieces = self.inner.pieces();
let args: Vec<ArgumentV1> = self.inner.args.iter().map(|f| match *f {
PreparedArgument::Normal(func) => ArgumentV1::new(t, func),
PreparedArgument::Usize(func) => ArgumentV1::from_usize(func(t)),
}).collect();
f(match self.inner.fmt {
Some(ref fmt) => Arguments::new_v1_formatted(&pieces, &args, fmt),
None => Arguments::new_v1(&pieces, &args),
})
}
#[inline]
pub fn format(&self, t: &T) -> String {
self.with(t, ::std::fmt::format)
}
#[inline]
pub fn print(&self, t: &T) {
self.with(t, _print)
}
#[inline]
pub fn write_io<W: io::Write + ?Sized>(&self, t: &T, dest: &mut W) -> io::Result<()> {
self.with(t, |args| dest.write_fmt(args))
}
#[inline]
pub fn write_fmt<W: fmt::Write + ?Sized>(&self, t: &T, dest: &mut W) -> fmt::Result {
self.with(t, |args| dest.write_fmt(args))
}
}
impl<'s, T: FormatArgs> Clone for PreparedFormat<'s, T> {
fn clone(&self) -> Self {
PreparedFormat { inner: self.inner.clone() }
}
fn clone_from(&mut self, source: &Self) {
self.inner.clone_from(&source.inner)
}
}
#[derive(Clone)]
pub struct FormatBuf<'s> {
inner: Parsed<'s, ImmediateParse<'s>>,
}
impl<'s> FormatBuf<'s> {
#[inline]
pub fn new(spec: &'s str, params: &'s [Param<'s>]) -> Result<Self, Error<'s>> {
parse(spec, &mut ImmediateParse(params))
.map(|result| FormatBuf { inner: result })
}
#[inline]
pub fn newln(&mut self) -> &mut Self {
self.inner.newln();
self
}
pub fn with<F: FnOnce(Arguments) -> R, R>(&self, f: F) -> R {
let pieces = self.inner.pieces();
f(match self.inner.fmt {
Some(ref fmt) => Arguments::new_v1_formatted(&pieces, &self.inner.args, fmt),
None => Arguments::new_v1(&pieces, &self.inner.args),
})
}
#[inline]
pub fn format(&self) -> String {
self.with(::std::fmt::format)
}
#[inline]
pub fn print(&self) {
self.with(_print)
}
#[inline]
pub fn write_io<W: io::Write + ?Sized>(&self, dest: &mut W) -> io::Result<()> {
self.with(|args| dest.write_fmt(args))
}
#[inline]
pub fn write_fmt<W: fmt::Write + ?Sized>(&self, dest: &mut W) -> fmt::Result {
self.with(|args| dest.write_fmt(args))
}
}
impl<'a> fmt::Display for FormatBuf<'a> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.with(|args| fmt.write_fmt(args))
}
}
impl<'a> fmt::Debug for FormatBuf<'a> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, fmt)
}
}
trait ParseTarget<'p> {
type Argument;
fn validate_name(&mut self, name: &str) -> Option<usize>;
fn validate_index(&mut self, index: usize) -> bool;
fn format<'s>(&mut self, spec: &'s str, idx: usize) -> Result<Self::Argument, Error<'s>>;
fn format_usize(&mut self, idx: usize) -> Option<Self::Argument>;
}
struct ImmediateParse<'p>(&'p [Param<'p>]);
impl<'p> ParseTarget<'p> for ImmediateParse<'p> {
type Argument = ArgumentV1<'p>;
fn validate_name(&mut self, name: &str) -> Option<usize> {
self.0.iter().position(|p| p.name.map_or(false, |n| n == name))
}
fn validate_index(&mut self, index: usize) -> bool {
index < self.0.len()
}
fn format<'s>(&mut self, spec: &'s str, idx: usize) -> Result<Self::Argument, Error<'s>> {
self.0[idx].value.by_name(spec, idx)
}
fn format_usize(&mut self, idx: usize) -> Option<Self::Argument> {
self.0[idx].as_usize.as_ref().map(ArgumentV1::from_usize)
}
}
struct DelayedParse<T>(PhantomData<fn(&T)>);
impl<'p, T: FormatArgs> ParseTarget<'p> for DelayedParse<T> {
type Argument = PreparedArgument<T>;
fn validate_name(&mut self, name: &str) -> Option<usize> {
T::validate_name(name)
}
fn validate_index(&mut self, index: usize) -> bool {
T::validate_index(index)
}
fn format<'s>(&mut self, spec: &'s str, idx: usize) -> Result<Self::Argument, Error<'s>> {
erase::codegen_get_child::<T>(spec, idx).map(PreparedArgument::Normal)
}
fn format_usize(&mut self, idx: usize) -> Option<Self::Argument> {
T::as_usize(idx).map(PreparedArgument::Usize)
}
}
struct Parsed<'s, P: ParseTarget<'s>> {
pieces: Vec<Cow<'s, str>>,
args: Vec<P::Argument>,
fmt: Option<Vec<v1::Argument>>,
}
impl<'s, P: ParseTarget<'s>> Clone for Parsed<'s, P>
where P::Argument: Clone
{
fn clone(&self) -> Self {
Parsed {
pieces: self.pieces.clone(),
args: self.args.clone(),
fmt: self.fmt.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.pieces.clone_from(&source.pieces);
self.args.clone_from(&source.args);
self.fmt.clone_from(&source.fmt);
}
}
impl<'s, P: ParseTarget<'s>> Parsed<'s, P> {
fn newln(&mut self) {
let len = self.fmt.as_ref().map_or(self.args.len(), |fmt| fmt.len());
if self.pieces.len() > len {
self.pieces.last_mut().unwrap().to_mut().push_str("\n")
} else {
self.pieces.push("\n".into())
}
}
#[inline]
fn pieces(&self) -> Vec<&str> {
self.pieces.iter().map(|r| &**r).collect()
}
}
fn parse<'s, P: ParseTarget<'s>>(spec: &'s str, target: &mut P)
-> Result<Parsed<'s, P>, Error<'s>>
{
let mut parser = fmt_macros::Parser::new(spec);
let result = inner_parse(&mut parser, target);
if parser.errors.is_empty() {
result
} else {
Err(Error::BadSyntax(parser.errors))
}
}
fn inner_parse<'s, P>(parser: &mut fmt_macros::Parser<'s>, target: &mut P)
-> Result<Parsed<'s, P>, Error<'s>>
where P: ParseTarget<'s>
{
use fmt_macros as p;
const DEFAULT_FILL: char = ' ';
const DEFAULT_KEY: p::FormatSpec = p::FormatSpec {
fill: None,
align: p::AlignUnknown,
flags: 0,
precision: p::CountImplied,
width: p::CountImplied,
ty: "",
};
const DEFAULT_VALUE: v1::FormatSpec = v1::FormatSpec {
fill: DEFAULT_FILL,
align: v1::Alignment::Unknown,
flags: 0,
precision: v1::Count::Implied,
width: v1::Count::Implied,
};
let mut pieces = Vec::new();
let mut args = Vec::new();
let mut fmt = None;
let mut fmt_len = 0;
let mut str_accum: Cow<str> = "".into();
while let Some(piece) = parser.next() {
match piece {
p::Piece::String(text) => {
if str_accum.is_empty() {
str_accum = text.into();
} else if !text.is_empty() {
str_accum.to_mut().push_str(text);
}
}
p::Piece::NextArgument(arg) => {
let mut push_arg = |arg| {
let len = args.len();
args.push(arg);
len
};
pieces.push(std::mem::replace(&mut str_accum, "".into()));
let idx = match arg.position {
p::Position::ArgumentIs(idx) => {
if !target.validate_index(idx) {
return Err(Error::BadIndex(idx))
}
idx
}
p::Position::ArgumentNamed(name) => {
match target.validate_name(name) {
Some(idx) => idx,
None => return Err(Error::BadName(name))
}
}
};
let argument_pos = push_arg(target.format(arg.format.ty, idx)?);
let mut convert_count = |c| -> Result<v1::Count, Error<'s>> {
Ok(match c {
p::CountIs(val) => v1::Count::Is(val),
p::CountIsName(name) => {
let idx = match target.validate_name(name) {
Some(idx) => idx,
None => return Err(Error::BadName(name))
};
v1::Count::Param(push_arg(match target.format_usize(idx) {
Some(arg) => arg,
None => return Err(Error::BadCount(idx))
}))
}
p::CountIsParam(idx) => {
if !target.validate_index(idx) {
return Err(Error::BadIndex(idx))
}
v1::Count::Param(push_arg(match target.format_usize(idx) {
Some(arg) => arg,
None => return Err(Error::BadCount(idx))
}))
},
p::CountImplied => v1::Count::Implied,
})
};
if fmt.is_none() && (arg.format != DEFAULT_KEY || argument_pos != fmt_len) {
fmt = Some((0..fmt_len).map(|i| v1::Argument {
position: v1::Position::At(i),
format: DEFAULT_VALUE,
}).collect::<Vec<_>>());
}
if let Some(fmt) = fmt.as_mut() {
let spec = v1::FormatSpec {
fill: arg.format.fill.unwrap_or(DEFAULT_FILL),
flags: arg.format.flags,
align: match arg.format.align {
p::AlignLeft => v1::Alignment::Left,
p::AlignRight => v1::Alignment::Right,
p::AlignCenter => v1::Alignment::Center,
p::AlignUnknown => v1::Alignment::Unknown,
},
precision: convert_count(arg.format.precision)?,
width: convert_count(arg.format.width)?,
};
fmt.push(v1::Argument {
position: v1::Position::At(argument_pos),
format: spec,
})
}
fmt_len += 1;
}
}
}
if !str_accum.is_empty() {
pieces.push(str_accum);
}
Ok(Parsed {
pieces: pieces,
args: args,
fmt: fmt,
})
}