use std::fmt;
use std::fmt::Display;
use std::fmt::Write;
use crate::indenter;
const INDENT: &str = " ";
fn subwriter<T: Display>(indent: &'static str, f: &mut fmt::Formatter, v: T) -> fmt::Result {
if f.alternate() {
write!(indenter::indented(f, indent), "{:#}", &v)
} else {
Display::fmt(&v, f)
}
}
enum Len {
Zero,
One,
Many, }
pub fn display_pair<'a, K: Display + 'a, V: Display + 'a>(
key: K,
separator: &'a str,
value: V,
) -> impl Display + 'a {
DisplayPair(key, separator, value)
}
struct DisplayPair<'a, K: Display, V: Display>(pub K, pub &'a str, pub V);
impl<'a, K: Display, V: Display> Display for DisplayPair<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)?;
f.write_str(self.1)?;
Display::fmt(&self.2, f)
}
}
struct ContainerDisplayHelper<'a, 'b> {
f: &'a mut fmt::Formatter<'b>,
separator: &'static str,
outer: &'static str,
indent: &'static str,
seen_items: usize,
}
impl<'a, 'b> ContainerDisplayHelper<'a, 'b> {
fn begin_inner(
f: &'a mut fmt::Formatter<'b>,
prefix: &str,
num_items: Len,
) -> Result<Self, fmt::Error> {
let (separator, outer, indent) = match (f.alternate(), num_items) {
(false, _) => (", ", "", ""),
(true, Len::Zero) => ("", "", ""),
(true, Len::One) => ("", " ", ""),
_ => (",\n", "\n", INDENT),
};
f.write_str(prefix)?;
f.write_str(outer)?;
Ok(Self {
f,
separator,
outer,
indent,
seen_items: 0,
})
}
pub fn item<T: Display>(&mut self, v: T) -> fmt::Result {
if self.seen_items != 0 {
self.f.write_str(self.separator)?;
}
self.seen_items += 1;
subwriter(self.indent, self.f, &v)
}
pub fn end(self, suffix: &str) -> fmt::Result {
self.f.write_str(self.outer)?;
self.f.write_str(suffix)
}
}
pub fn display_container<T: Display, Iter: IntoIterator<Item = T>>(
f: &mut fmt::Formatter,
prefix: &str,
suffix: &str,
items: Iter,
) -> fmt::Result {
let mut items = items.into_iter();
let helper = match items.next() {
None => ContainerDisplayHelper::begin_inner(f, prefix, Len::Zero)?,
Some(first) => match items.next() {
None => {
let mut helper = ContainerDisplayHelper::begin_inner(f, prefix, Len::One)?;
helper.item(first)?;
helper
}
Some(second) => {
let mut helper = ContainerDisplayHelper::begin_inner(f, prefix, Len::Many)?;
helper.item(first)?;
helper.item(second)?;
for v in items {
helper.item(v)?;
}
helper
}
},
};
helper.end(suffix)
}
pub fn display_keyed_container<K: Display, V: Display, Iter: IntoIterator<Item = (K, V)>>(
f: &mut fmt::Formatter,
prefix: &str,
suffix: &str,
separator: &str,
items: Iter,
) -> fmt::Result {
display_container(
f,
prefix,
suffix,
items
.into_iter()
.map(|(k, v)| display_pair(k, separator, v)),
)
}
enum Either<A, B> {
Left(A),
Right(B),
}
impl<A: Display, B: Display> Display for Either<A, B> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Either::Left(a) => Display::fmt(a, f),
Either::Right(b) => Display::fmt(b, f),
}
}
}
struct EitherIter<A: Iterator, B: Iterator> {
pub(crate) a: Option<A>,
pub(crate) b: B,
}
impl<A: Iterator, B: Iterator> Iterator for EitherIter<A, B> {
type Item = Either<A::Item, B::Item>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(a) = &mut self.a {
if let Some(v) = a.next() {
return Some(Either::Left(v));
}
self.a = None;
}
self.b.next().map(Either::Right)
}
}
pub fn display_chain<A, B>(first: A, second: B) -> impl Iterator<Item = impl Display>
where
A: IntoIterator,
A::Item: Display,
B: IntoIterator,
B::Item: Display,
{
EitherIter {
a: Some(first.into_iter()),
b: second.into_iter(),
}
}
#[cfg(test)]
mod tests {
use std::fmt;
use super::*;
#[test]
fn test_container() {
struct Wrapped(Vec<u32>);
impl fmt::Display for Wrapped {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
display_container(f, "prefix[", "]", self.0.iter())
}
}
assert_eq!("prefix[]", format!("{:}", Wrapped(vec![])));
assert_eq!("prefix[1]", format!("{:}", Wrapped(vec![1])));
assert_eq!("prefix[1, 2]", format!("{:}", Wrapped(vec![1, 2])));
assert_eq!("prefix[1, 2, 3]", format!("{:}", Wrapped(vec![1, 2, 3])));
assert_eq!("prefix[]", format!("{:#}", Wrapped(vec![])));
assert_eq!("prefix[ 1 ]", format!("{:#}", Wrapped(vec![1])));
assert_eq!(
"prefix[\n 1,\n 2\n]",
format!("{:#}", Wrapped(vec![1, 2])),
);
assert_eq!(
"prefix[\n 1,\n 2,\n 3\n]",
format!("{:#}", Wrapped(vec![1, 2, 3])),
);
}
#[test]
fn test_keyed_container() {
struct Wrapped(Vec<(u32, &'static str)>);
impl fmt::Display for Wrapped {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
display_keyed_container(
f,
"prefix[",
"]",
": ",
self.0.iter().map(|(k, v)| (k, format!("\"{}\"", v))),
)
}
}
assert_eq!("prefix[]", format!("{:}", Wrapped(vec![])));
assert_eq!("prefix[1: \"1\"]", format!("{:}", Wrapped(vec![(1, "1")])));
assert_eq!(
"prefix[1: \"1\", 2: \"2\"]",
format!("{:}", Wrapped(vec![(1, "1"), (2, "2")])),
);
assert_eq!(
"prefix[1: \"1\", 2: \"2\", 3: \"3\"]",
format!("{:}", Wrapped(vec![(1, "1"), (2, "2"), (3, "3")])),
);
assert_eq!("prefix[]", format!("{:#}", Wrapped(vec![])));
assert_eq!(
"prefix[ 1: \"1\" ]",
format!("{:#}", Wrapped(vec![(1, "1")]))
);
assert_eq!(
"prefix[\n 1: \"1\",\n 2: \"2\"\n]",
format!("{:#}", Wrapped(vec![(1, "1"), (2, "2")])),
);
assert_eq!(
"prefix[\n 1: \"1\",\n 2: \"2\",\n 3: \"3\"\n]",
format!("{:#}", Wrapped(vec![(1, "1"), (2, "2"), (3, "3")])),
);
}
#[test]
fn test_combinators() {
struct MyItems(Vec<(String, i32)>);
impl fmt::Display for MyItems {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
display_container(
f,
"{",
"}",
display_chain(
&["magic"],
self.0.iter().map(|(k, v)| display_pair(k, "=", v)),
),
)
}
}
assert_eq!(
MyItems(vec![("hello".to_owned(), 1), ("world".to_owned(), 2)]).to_string(),
"{magic, hello=1, world=2}"
);
}
}