Skip to content

Commit

Permalink
Merge #608
Browse files Browse the repository at this point in the history
608: Make Format/FormatWith use Cell r=jswrenn a=Ten0

Resolves #607

Co-authored-by: Thomas BESSOU <thomas.bessou@hotmail.fr>
  • Loading branch information
bors[bot] and Ten0 committed Jun 14, 2023
2 parents e2447dd + dce7378 commit cc5ae85
Showing 1 changed file with 75 additions and 20 deletions.
95 changes: 75 additions & 20 deletions src/format.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use std::cell::Cell;
use std::fmt;
use std::cell::RefCell;

/// 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.
#[derive(Clone)]
pub struct FormatWith<'a, I, F> {
sep: &'a str,
/// FormatWith uses interior mutability because Display::fmt takes &self.
inner: RefCell<Option<(I, F)>>,
inner: Cell<Option<(I, F)>>,
}

/// Format all iterator elements lazily, separated by `sep`.
Expand All @@ -21,38 +20,40 @@ pub struct FormatWith<'a, I, F> {
///
/// See [`.format()`](crate::Itertools::format)
/// for more information.
#[derive(Clone)]
pub struct Format<'a, I> {
sep: &'a str,
/// Format uses interior mutability because Display::fmt takes &self.
inner: RefCell<Option<I>>,
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
where
I: Iterator,
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
{
FormatWith {
sep: separator,
inner: RefCell::new(Some((iter, f))),
inner: Cell::new(Some((iter, f))),
}
}

pub fn new_format_default<I>(iter: I, separator: &str) -> Format<'_, I>
where I: Iterator,
where
I: Iterator,
{
Format {
sep: separator,
inner: RefCell::new(Some(iter)),
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
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.borrow_mut().take() {
let (mut iter, mut format) = match self.inner.take() {
Some(t) => t,
None => panic!("FormatWith: was already formatted once"),
};
Expand All @@ -71,12 +72,15 @@ impl<'a, I, F> fmt::Display for FormatWith<'a, I, F>
}

impl<'a, I> Format<'a, I>
where I: Iterator,
where
I: Iterator,
{
fn format<F>(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result
where F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result,
{
let mut iter = match self.inner.borrow_mut().take() {
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"),
};
Expand Down Expand Up @@ -109,5 +113,56 @@ macro_rules! impl_format {
}
}

impl_format!{Display Debug
UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer}
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,
}
}
}

0 comments on commit cc5ae85

Please sign in to comment.