179 lines
4.8 KiB
Rust
179 lines
4.8 KiB
Rust
use std::cell::Cell;
|
|
use std::fmt;
|
|
|
|
/// Format all iterator elements lazily, separated by `sep`.
|
|
///
|
|
/// The format value can only be formatted once, after that the iterator is
|
|
/// exhausted.
|
|
///
|
|
/// See [`.format_with()`](crate::Itertools::format_with) for more information.
|
|
pub struct FormatWith<'a, I, F> {
|
|
sep: &'a str,
|
|
/// `FormatWith` uses interior mutability because `Display::fmt` takes `&self`.
|
|
inner: Cell<Option<(I, F)>>,
|
|
}
|
|
|
|
/// Format all iterator elements lazily, separated by `sep`.
|
|
///
|
|
/// The format value can only be formatted once, after that the iterator is
|
|
/// exhausted.
|
|
///
|
|
/// See [`.format()`](crate::Itertools::format)
|
|
/// for more information.
|
|
pub struct Format<'a, I> {
|
|
sep: &'a str,
|
|
/// `Format` uses interior mutability because `Display::fmt` takes `&self`.
|
|
inner: Cell<Option<I>>,
|
|
}
|
|
|
|
pub fn new_format<I, F>(iter: I, separator: &str, f: F) -> FormatWith<'_, I, F>
|
|
where
|
|
I: Iterator,
|
|
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
|
|
{
|
|
FormatWith {
|
|
sep: separator,
|
|
inner: Cell::new(Some((iter, f))),
|
|
}
|
|
}
|
|
|
|
pub fn new_format_default<I>(iter: I, separator: &str) -> Format<'_, I>
|
|
where
|
|
I: Iterator,
|
|
{
|
|
Format {
|
|
sep: separator,
|
|
inner: Cell::new(Some(iter)),
|
|
}
|
|
}
|
|
|
|
impl<'a, I, F> fmt::Display for FormatWith<'a, I, F>
|
|
where
|
|
I: Iterator,
|
|
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let (mut iter, mut format) = match self.inner.take() {
|
|
Some(t) => t,
|
|
None => panic!("FormatWith: was already formatted once"),
|
|
};
|
|
|
|
if let Some(fst) = iter.next() {
|
|
format(fst, &mut |disp: &dyn fmt::Display| disp.fmt(f))?;
|
|
iter.try_for_each(|elt| {
|
|
if !self.sep.is_empty() {
|
|
f.write_str(self.sep)?;
|
|
}
|
|
format(elt, &mut |disp: &dyn fmt::Display| disp.fmt(f))
|
|
})?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<'a, I, F> fmt::Debug for FormatWith<'a, I, F>
|
|
where
|
|
I: Iterator,
|
|
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
fmt::Display::fmt(self, f)
|
|
}
|
|
}
|
|
|
|
impl<'a, I> Format<'a, I>
|
|
where
|
|
I: Iterator,
|
|
{
|
|
fn format(
|
|
&self,
|
|
f: &mut fmt::Formatter,
|
|
cb: fn(&I::Item, &mut fmt::Formatter) -> fmt::Result,
|
|
) -> fmt::Result {
|
|
let mut iter = match self.inner.take() {
|
|
Some(t) => t,
|
|
None => panic!("Format: was already formatted once"),
|
|
};
|
|
|
|
if let Some(fst) = iter.next() {
|
|
cb(&fst, f)?;
|
|
iter.try_for_each(|elt| {
|
|
if !self.sep.is_empty() {
|
|
f.write_str(self.sep)?;
|
|
}
|
|
cb(&elt, f)
|
|
})?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
macro_rules! impl_format {
|
|
($($fmt_trait:ident)*) => {
|
|
$(
|
|
impl<'a, I> fmt::$fmt_trait for Format<'a, I>
|
|
where I: Iterator,
|
|
I::Item: fmt::$fmt_trait,
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
self.format(f, fmt::$fmt_trait::fmt)
|
|
}
|
|
}
|
|
)*
|
|
}
|
|
}
|
|
|
|
impl_format! {Display Debug UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer}
|
|
|
|
impl<'a, I, F> Clone for FormatWith<'a, I, F>
|
|
where
|
|
(I, F): Clone,
|
|
{
|
|
fn clone(&self) -> Self {
|
|
struct PutBackOnDrop<'r, 'a, I, F> {
|
|
into: &'r FormatWith<'a, I, F>,
|
|
inner: Option<(I, F)>,
|
|
}
|
|
// This ensures we preserve the state of the original `FormatWith` if `Clone` panics
|
|
impl<'r, 'a, I, F> Drop for PutBackOnDrop<'r, 'a, I, F> {
|
|
fn drop(&mut self) {
|
|
self.into.inner.set(self.inner.take())
|
|
}
|
|
}
|
|
let pbod = PutBackOnDrop {
|
|
inner: self.inner.take(),
|
|
into: self,
|
|
};
|
|
Self {
|
|
inner: Cell::new(pbod.inner.clone()),
|
|
sep: self.sep,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, I> Clone for Format<'a, I>
|
|
where
|
|
I: Clone,
|
|
{
|
|
fn clone(&self) -> Self {
|
|
struct PutBackOnDrop<'r, 'a, I> {
|
|
into: &'r Format<'a, I>,
|
|
inner: Option<I>,
|
|
}
|
|
// This ensures we preserve the state of the original `FormatWith` if `Clone` panics
|
|
impl<'r, 'a, I> Drop for PutBackOnDrop<'r, 'a, I> {
|
|
fn drop(&mut self) {
|
|
self.into.inner.set(self.inner.take())
|
|
}
|
|
}
|
|
let pbod = PutBackOnDrop {
|
|
inner: self.inner.take(),
|
|
into: self,
|
|
};
|
|
Self {
|
|
inner: Cell::new(pbod.inner.clone()),
|
|
sep: self.sep,
|
|
}
|
|
}
|
|
}
|