std_io_iterators 1.0.0

An iterator for `STDIN` and a wrapper for `STDOUT`. Allows easy piping, and graceful closing of application if pipe breaks
Documentation
//! Iterator over recovered data being piped out

use crate::pipe_out::WriteLineResult;

/// Iterator over recovered data being piped out
///
/// The most anticipated error when piping out is a
/// [`std::io::ErrorKind::BrokenPipe`] i.e. the program being piped into completes
/// it's operation before the data being supplied to this program finishes
/// supplying. (See Warning in [`crate::prelude::PipeOut::pipe_out`])
///
/// Example (Dump Data)
/// ===================
///
/// When an error occurs while piping data out, the most likely desired
/// results is simply to return a `Result<(), std::io::Error>` to return to the
/// parent function
///
/// ```no_run
#[doc = include_str!("examples/pipe_out.rs")]
/// ```
///
/// Example (Recover Data)
/// ======================
///
/// In some scenarios, it may be desireable to recover the data being piped out
/// and re-direct it (eg: to a log file).  (See Warning in
/// [`crate::prelude::PipeOut::pipe_out`])
///
/// ```no_run
#[doc = include_str!("examples/example_handles_broken_pipe.rs")]
/// ```
pub struct PipeOutRecoveredIterator<D: std::fmt::Display, I: Iterator<Item = D>>
{
    /// The iterator being piped out
    pub iter: I,

    /// Datum being piped out when error occurred
    pub recovered_datum: Option<D>,

    /// Result of last [`pipe_out`][crate::pipe_out::PipeOut::pipe_out]
    pub result: WriteLineResult,
}

impl<D: std::fmt::Display, I: Iterator<Item = D>> Iterator
    for PipeOutRecoveredIterator<D, I>
{
    type Item = D;

    fn next(&mut self) -> Option<Self::Item> {
        self.recovered_datum.take().or_else(|| self.iter.next())
    }
}

impl<D: std::fmt::Display, I: Iterator<Item = D>>
    PipeOutRecoveredIterator<D, I>
{
    /// Return [`WriteLineResult`], Ignore recovered data
    ///
    /// # Example
    ///
    /// ```
    /// # use std_io_iterators::prelude::*;
    /// # const RESULT: WriteLineResult = WriteLineResult::PreviousError;
    /// # let iter = [""].into_iter();
    /// // GIVEN
    /// let recovered_iterator = PipeOutRecoveredIterator {
    ///     iter,
    ///     # recovered_datum: None,
    ///     result: RESULT,
    ///     // ...
    /// };
    ///
    /// // WHEN
    /// let actual = recovered_iterator.dump_data();
    ///
    /// // THEN
    /// assert!(actual.same_variant_as(&RESULT));
    /// ```
    pub fn dump_data(self) -> WriteLineResult {
        self.result
    }

    /// Return if error contained is broken pipe error
    pub fn is_broken_pipe(&self) -> bool {
        matches!(self.result, WriteLineResult::BrokenPipe(_))
    }

    /// Return if contains recovered datum
    ///
    /// # Example
    ///
    /// See [`PipeOutRecoveredIterator::take_recovered_datum`]
    pub fn has_recovered_datum(&self) -> bool {
        self.recovered_datum.is_some()
    }

    /// Return recovered datum (if present)
    ///
    /// Example
    /// =======
    ///
    /// ```
    /// # use std_io_iterators::prelude::*;
    /// # const DUMMY_RECOVERED_DATUM: &str = "Test1655350169";
    /// # let iter = [String::new()].into_iter();
    /// // GIVEN
    /// let mut result = PipeOutRecoveredIterator {
    ///     # iter,
    ///     recovered_datum: Some(DUMMY_RECOVERED_DATUM.to_owned()),
    ///     # result: WriteLineResult::Ok,
    ///     // ...
    /// };
    /// assert!(result.has_recovered_datum());
    ///
    /// // WHEN
    /// let actual = result.take_recovered_datum();
    ///
    /// // THEN
    /// assert_eq!(actual, Some(DUMMY_RECOVERED_DATUM.to_owned()));
    /// assert!(!result.has_recovered_datum());
    /// ```
    pub fn take_recovered_datum(&mut self) -> Option<D> {
        self.recovered_datum.take()
    }
}