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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*!
# debug_iterator
This is a simple iterator adapter thats is applicable to iterators where the Iterator::Item is std::fmt::Debug

It prints to `stderr` by default, but using the feature 'logging' prints out to the `log` crate facade.

```rust
use debug_iterator::DebugIterator as _;

#[derive(Debug)]
struct Person {
    name: String,
    age: i32
}

let everyone_is_named_bob = "Bob".to_string();
let iter = (1..=3)
    .map(|k| k * 4)
    .map(|age| Person {
        name: everyone_is_named_bob.clone(),
        age,
    })
    .clone();

// debug ("{:?}")
iter.debug().for_each(|_| ());
// Person { name: "Bob", age: 4 }
// Person { name: "Bob", age: 8 }
// Person { name: "Bob", age: 12 }

// debug_pretty ("{:#?}")
iter.debug_pretty().for_each(|_| ());
// Person {
//     name: "Bob",
//     age: 4,
// }
// Person {
//     name: "Bob",
//     age: 8,
// }
// Person {
//     name: "Bob",
//     age: 12,
// }

// '{:?}' with a `&str` prefix:
iter.debug_prefix("This person is").for_each(|_| ());
// This person is: Person { name: "Bob", age: 4 }
// This person is: Person { name: "Bob", age: 8 }
// This person is: Person { name: "Bob", age: 12 }

// '{:#?}' with a `&str` prefix:
iter.debug_prefix_pretty("This person is").for_each(|_| ());
// This person is: Person {
//     name: "Bob",
//     age: 4,
// }
// This person is: Person {
//     name: "Bob",
//     age: 8,
// }
// This person is: Person {
//     name: "Bob",
//     age: 12,
// }

```
*/
use std::borrow::Cow;

/// [`DebugIterator`](./trait.DebugIterator.html) is an [`std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) adapter that simply prints out
/// the debug representation of the [`Iterator::Item`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#associatedtype.Item)
pub trait DebugIterator: Iterator {
    /// Create an adapter that prints out the [`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html) representation of the Item
    fn debug<'a>(self) -> DebugPrinter<'a, Self>
    where
        Self: Sized,
        Self::Item: std::fmt::Debug,
    {
        DebugPrinter::new(self, false, None)
    }

    /// Create an adapter that prints out the [`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html) alterntive representation of the Item
    fn debug_pretty<'a>(self) -> DebugPrinter<'a, Self>
    where
        Self: Sized,
        Self::Item: std::fmt::Debug,
    {
        DebugPrinter::new(self, true, None)
    }

    /// Create an adapter that prints out the [`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html) representation of the Item, with a Prefix
    fn debug_prefix<'a, S>(self, prefix: S) -> DebugPrinter<'a, Self>
    where
        Self: Sized + 'a,
        Self::Item: std::fmt::Debug,
        S: Into<Cow<'a, str>>,
    {
        DebugPrinter::new(self, false, Some(prefix.into()))
    }

    /// Create an adapter that prints out the [`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html) alterntive representation of the Item, with a Prefix
    fn debug_prefix_pretty<'a, S>(self, prefix: S) -> DebugPrinter<'a, Self>
    where
        Self: Sized + 'a,
        Self::Item: std::fmt::Debug,
        S: Into<Cow<'a, str>>,
    {
        DebugPrinter::new(self, true, Some(prefix.into()))
    }
}

/// [`DebugPrinter`](./struct.DebugPrinter.html) is the iterator for debug printing
pub struct DebugPrinter<'a, T>(T, bool, Option<Cow<'a, str>>);

impl<'a, T> DebugPrinter<'a, T>
where
    T: Iterator,
    T::Item: std::fmt::Debug,
{
    fn new(x: T, pretty: bool, msg: Option<Cow<'a, str>>) -> Self {
        Self(x, pretty, msg)
    }
}

impl<'a, T> Iterator for DebugPrinter<'a, T>
where
    T: Iterator,
    T::Item: std::fmt::Debug,
{
    type Item = T::Item;
    fn next(&mut self) -> Option<Self::Item> {
        let next = self.0.next()?;

        #[inline]
        macro_rules! _log_this {
            ($e:expr, $($xs:expr),* $(,)?) => {{
                #[cfg(feature = "logging")]
                ::log::debug!("{}", format_args!($e, $($xs),*));

                #[cfg(not(feature = "logging"))]
                eprintln!("{}", format_args!($e, $($xs),*));
            }};
        }

        match (self.1, &self.2) {
            (true, Some(prefix)) => _log_this!("{}: {:#?}", prefix, next),
            (false, Some(prefix)) => _log_this!("{}: {:?}", prefix, next),
            (true, None) => _log_this!("{:#?}", next),
            (false, None) => _log_this!("{:?}", next),
        }
        Some(next)
    }
}

impl<T: ?Sized> DebugIterator for T where T: Iterator {}