use std::fmt::Write;
use std::string::String;
use formatter::Formatter;
use types::*;
fn write_char(f: &mut Formatter, c: char, n: usize) {
for _ in 0..n {
f.write_char(c).unwrap();
}
}
#[test]
fn test_write_char() {
let mut s = String::new();
s.write_str("h ").unwrap();
{
let mut f = Formatter::from_str("{}", &mut s).unwrap();
write_char(&mut f, 'f', 3);
}
assert!(s == "h fff");
}
fn write_from<I>(fmt: &mut Formatter, f: I, n: usize) -> usize
where
I: Iterator<Item = char>,
{
if n == 0 {
return 0;
}
let mut n_written: usize = 0;
for c in f {
fmt.write_char(c).unwrap();
n_written += 1;
if n_written == n {
return n_written;
}
}
n_written
}
#[test]
fn test_write_from() {
let mut s = String::new();
s.write_str("h ").unwrap();
{
let mut f = Formatter::from_str("{}", &mut s).unwrap();
write_from(&mut f, "fff".chars(), 5);
}
assert!(s == "h fff");
{
let mut f = Formatter::from_str("{}", &mut s).unwrap();
write_from(&mut f, "xxxx".chars(), 2);
}
assert!(s == "h fffxx");
{
let mut f = Formatter::from_str("{}", &mut s).unwrap();
write_from(&mut f, "333".chars(), 3);
}
assert!(s == "h fffxx333");
s.clear();
{
let mut f = Formatter::from_str("{}", &mut s).unwrap();
write!(f, "hello").unwrap();
}
assert!(s == "hello");
}
impl<'a, 'b> Formatter<'a, 'b> {
pub fn str(&mut self, s: &str) -> Result<()> {
self.set_default_align(Alignment::Left);
if !(self.ty() == None || self.ty() == Some('s')) {
let mut msg = String::new();
write!(
msg,
"Unknown format code {:?} for object of type 'str'",
self.ty()
)
.unwrap();
return Err(FmtError::TypeError(msg));
} else if self.alternate() {
return Err(FmtError::TypeError(
"Alternate form (#) not allowed in string \
format specifier"
.to_string(),
));
} else if self.thousands() {
return Err(FmtError::TypeError(
"Cannot specify ',' with 's'".to_string(),
));
} else if self.sign().is_unspecified() {
return Err(FmtError::TypeError(
"Sign not allowed in string format specifier".to_string(),
));
}
self.str_unchecked(s)
}
pub fn str_unchecked(&mut self, s: &str) -> Result<()> {
let fill = self.fill();
let width = self.width();
let precision = self.precision();
let chars_count = s.chars().count();
let len = match precision {
Some(p) => {
if p < chars_count {
p
} else {
chars_count
}
}
None => chars_count,
};
let mut chars = s.chars();
let mut pad: usize = 0;
if let Some(mut width) = width {
if width > len {
let align = self.align();
match align {
Alignment::Left => pad = width - len,
Alignment::Center => {
width -= len;
pad = width / 2;
write_char(self, fill, pad);
pad += width % 2;
}
Alignment::Right => {
write_char(self, fill, width - len);
}
Alignment::Equal => {
return Err(FmtError::Invalid(
"sign aware zero padding and Align '=' not yet supported".to_string(),
))
}
Alignment::Unspecified => unreachable!(),
}
}
}
write_from(self, &mut chars, len);
write_char(self, fill, pad);
Ok(())
}
}
pub fn strfmt_map<F>(fmtstr: &str, f: F) -> Result<String>
where
F: FnMut(Formatter) -> Result<()>,
{
let mut f = f;
let mut out = String::with_capacity(fmtstr.len() * 2);
let mut bytes_read: usize = 0;
let mut opening_brace: usize = 0;
let mut closing_brace: bool = false;
let mut reading_fmt = false;
let mut remaining = fmtstr;
for c in fmtstr.chars() {
bytes_read += c.len_utf8();
if c == '{' {
if reading_fmt && opening_brace == bytes_read - 2 {
out.push(c);
reading_fmt = false;
} else if !reading_fmt {
reading_fmt = true;
opening_brace = bytes_read - 1;
} else {
out.clear();
out.write_str("extra { found").unwrap();
return Err(FmtError::Invalid(out));
}
} else if c == '}' {
if !reading_fmt && !closing_brace {
closing_brace = true;
} else if closing_brace {
out.push(c);
closing_brace = false;
} else {
let (_, r) = remaining.split_at(opening_brace);
let (fmt_pattern, r) = r.split_at(bytes_read - opening_brace);
remaining = r;
let (_, fmt_pattern) = fmt_pattern.split_at(1);
let (fmt_pattern, _) = fmt_pattern.split_at(fmt_pattern.len() - 1);
let fmt = Formatter::from_str(fmt_pattern, &mut out)?;
f(fmt)?;
reading_fmt = false;
bytes_read = 0;
}
} else if closing_brace {
return Err(FmtError::Invalid(
"Single '}' encountered in format string".to_string(),
));
} else if !reading_fmt {
out.push(c)
} }
if closing_brace {
return Err(FmtError::Invalid(
"Single '}' encountered in format string".to_string(),
));
} else if reading_fmt {
return Err(FmtError::Invalid(
"Expected '}' before end of string".to_string(),
));
}
out.shrink_to_fit();
Ok(out)
}