From 22fa6f0fb80a01bdf1be14c97899b121f242bf14 Mon Sep 17 00:00:00 2001 From: Thomas BESSOU Date: Fri, 25 Mar 2022 15:21:29 +0100 Subject: [PATCH 1/2] Make Format/FormatWith use Cell Resolves #607 --- src/format.rs | 90 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/src/format.rs b/src/format.rs index d87cee950..2927af706 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,5 +1,5 @@ +use std::cell::Cell; use std::fmt; -use std::cell::RefCell; /// Format all iterator elements lazily, separated by `sep`. /// @@ -7,11 +7,10 @@ use std::cell::RefCell; /// 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>, + inner: Cell>, } /// Format all iterator elements lazily, separated by `sep`. @@ -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>, + inner: Cell>, } pub fn new_format(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(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"), }; @@ -71,12 +72,14 @@ 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(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result - where F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result, + where + F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result, { - let mut iter = match self.inner.borrow_mut().take() { + let mut iter = match self.inner.take() { Some(t) => t, None => panic!("Format: was already formatted once"), }; @@ -109,5 +112,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, + } + // 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, + } + } +} From dce737881142787cb17cc5d8a06ff6ac006d630d Mon Sep 17 00:00:00 2001 From: Thomas BESSOU Date: Fri, 25 Mar 2022 16:00:33 +0100 Subject: [PATCH 2/2] remove unnecessary genericity --- src/format.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/format.rs b/src/format.rs index 2927af706..c4cb65dcb 100644 --- a/src/format.rs +++ b/src/format.rs @@ -75,10 +75,11 @@ impl<'a, I> Format<'a, I> where I: Iterator, { - fn format(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result - where - F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result, - { + 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"),