Skip to main content

csv_eof/
lib.rs

1// Copyright (C) The Strand-Braid Authors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Allows silently swallowing `UnexpectedEof` errors when reading CSV files.
5use std::io::ErrorKind;
6
7/// Wrap an iterator in this to silently swallow `UnexpectedEof` errors.
8///
9/// Often when we are saving CSV files, they may be abruptly terminated when the
10/// program quits unexpectedly or the disk is full. While the problem should be
11/// solved elsewhere, the reality is that such corrupt CSV files exist and we
12/// want to parse them.
13pub struct TerminateEarlyOnUnexpectedEof<I, T>
14where
15    I: Iterator<Item = Result<T, csv::Error>>,
16{
17    inner: I,
18}
19
20impl<I, T> TerminateEarlyOnUnexpectedEof<I, T>
21where
22    I: Iterator<Item = Result<T, csv::Error>>,
23{
24    /// create a TerminateEarlyOnUnexpectedEof
25    pub fn new(inner: I) -> Self {
26        Self { inner }
27    }
28
29    /// unwrap a TerminateEarlyOnUnexpectedEof
30    pub fn into_inner(self) -> I {
31        self.inner
32    }
33}
34
35impl<I, T> Iterator for TerminateEarlyOnUnexpectedEof<I, T>
36where
37    I: Iterator<Item = Result<T, csv::Error>>,
38{
39    type Item = Result<T, csv::Error>;
40    fn next(&mut self) -> std::option::Option<<Self as Iterator>::Item> {
41        match self.inner.next() {
42            Some(Ok(item)) => Some(Ok(item)),
43            None => None,
44            Some(Err(e)) => match is_early_eof(&e) {
45                true => None,
46                false => Some(Err(e)),
47            },
48        }
49    }
50}
51
52/// check a `csv::Error` and return `true` iff it is an UnexpectedEof error
53fn is_early_eof(e: &csv::Error) -> bool {
54    if let csv::ErrorKind::Io(io_err) = e.kind()
55        && let ErrorKind::UnexpectedEof = io_err.kind()
56    {
57        return true;
58    }
59    false
60}
61
62/// A trait to wrap an Iterator and terminate without error on UnexpectedEof
63pub trait EarlyEofOk<I, T>
64where
65    I: Iterator<Item = Result<T, csv::Error>>,
66{
67    fn early_eof_ok(self) -> TerminateEarlyOnUnexpectedEof<I, T>;
68}
69
70impl<I, T> EarlyEofOk<I, T> for I
71where
72    I: Iterator<Item = Result<T, csv::Error>>,
73{
74    fn early_eof_ok(self) -> TerminateEarlyOnUnexpectedEof<I, T> {
75        TerminateEarlyOnUnexpectedEof::new(self)
76    }
77}