Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Format/FormatWith use Cell #608

Merged
merged 2 commits into from Jun 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
95 changes: 75 additions & 20 deletions src/format.rs
@@ -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,
}
}
}