1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
use std::fmt::{Display, Formatter};
use crate::wrapper::{DisplayWithSep, PrintableWrapper};
/// Wraps iterators into [`PrintableWrapper`].
///
/// # Warning
///
/// Avoid creating [`PrintableWrapper`] from resource-owning iterators such as
/// [`std::vec::IntoIter`], since they would clone the owned data or perform
/// other heavy operations every time [`Display::fmt`] is called.
///
/// To statically ensure that you don't use resource-owning iterators in such a
/// context, enable the `unstable-assert-no-drop` feature. However, this
/// approach has serious drawbacks. See the description of this feature in the
/// documentation.
///
/// # Examples
///
/// ```rust
/// use printable::prelude::PrintableIter;
///
/// let v = vec![1, 2, 3];
/// assert_eq!(format!("{}", v.iter().printable()), "[1, 2, 3]");
///
/// let v: Vec<usize> = vec![1];
/// assert_eq!(format!("{}", v.iter().printable()), "[1]");
///
/// let v: Vec<usize> = vec![];
/// assert_eq!(format!("{}", v.iter().printable()), "[]");
/// ```
pub trait PrintableIter: Iterator + Clone
where
Self::Item: Display,
{
/// Compile-time assertion that `Self` doesn't own any resource.
///
/// # Warning
///
/// May violate backward compatibility and lead to compilation failure
/// even if the major semver versions of the underlying crates aren't
/// updated.
///
/// This may happen due to the following factors:
/// - The [`std::mem::needs_drop`] documentation does not guarantee its
/// stability.
/// - The fact that the `Self` type, which can be declared in a third-party
/// crate, started owning a resource doesn't require increasing the major
/// version of this crate.
#[cfg(feature = "unstable-assert-no-drop")]
const NO_DROP_CHECK: () = { assert!(!std::mem::needs_drop::<Self>()) };
/// Wraps custom iterator into [`PrintableWrapper`].
#[inline]
fn printable(
self,
) -> PrintableWrapper<&'static str, &'static str, &'static str, IterHandler<Self>> {
#[cfg(feature = "unstable-assert-no-drop")]
let () = Self::NO_DROP_CHECK;
PrintableWrapper {
inner: IterHandler(self),
sep: ", ",
left_bound: "[",
right_bound: "]",
}
}
}
impl<T> PrintableIter for T
where
T: Iterator + Clone,
T::Item: Display,
{
}
impl<T> From<T>
for PrintableWrapper<&'static str, &'static str, &'static str, IterHandler<T::IntoIter>>
where
T: IntoIterator,
T::Item: Display,
T::IntoIter: Clone,
{
#[inline]
fn from(value: T) -> Self {
value.into_iter().printable()
}
}
/// Handler for iterators used inside the [`PrintableWrapper`].
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct IterHandler<T>(T);
impl<T> DisplayWithSep for IterHandler<T>
where
T: Iterator + Clone,
T::Item: Display,
{
#[inline]
fn fmt(&self, f: &mut Formatter<'_>, sep: &impl Display) -> std::fmt::Result {
let mut iter = self.0.clone();
if let Some(v) = iter.next() {
v.fmt(f)?;
for v in iter {
sep.fmt(f)?;
v.fmt(f)?;
}
};
Ok(())
}
}