Unified · Split
| @@ -1,6 +1,20 @@ | ||
| 1 | 1 | #![allow(missing_docs)] |
| 2 | 2 | use std::path::Path; |
| 3 | 3 | |
| 4 | +#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)] | |
| 5 | +pub struct Options { | |
| 6 | + /// How often to retry if an interrupt happens. | |
| 7 | + retries_on_interrupt: usize, | |
| 8 | +} | |
| 9 | + | |
| 10 | +impl Default for Options { | |
| 11 | + fn default() -> Self { | |
| 12 | + Options { | |
| 13 | + retries_on_interrupt: 10, | |
| 14 | + } | |
| 15 | + } | |
| 16 | +} | |
| 17 | + | |
| 4 | 18 | mod error { |
| 5 | 19 | use quick_error::quick_error; |
| 6 | 20 | use std::path::PathBuf; |
| @@ -37,20 +51,28 @@ pub use error::Error; · 30 unmodified lines | ||
| 37 | 51 | /// * `Some(Err(Error::Permanent))` is yielded exactly once on failure. |
| 38 | 52 | pub struct Iter<'a> { |
| 39 | 53 | cursors: Vec<&'a Path>, |
| 54 | + options: Options, | |
| 40 | 55 | } |
| 41 | 56 | |
| 42 | 57 | impl<'a> Iter<'a> { |
| 43 | 58 | pub fn new(target: &'a Path) -> Self { |
| 44 | − Iter { cursors: vec![target] } | |
| 59 | + Iter { | |
| 60 | + cursors: vec![target], | |
| 61 | + options: Default::default(), | |
| 62 | + } | |
| 45 | 63 | } |
| 46 | 64 | |
| 47 | − fn fail_permanently(&mut self, dir: &Path, err: impl Into<std::io::Error>) -> Option<Result<&'a Path, Error>> { | |
| 65 | + fn pernanent_failure(&mut self, dir: &Path, err: impl Into<std::io::Error>) -> Option<Result<&'a Path, Error>> { | |
| 48 | 66 | self.cursors.clear(); |
| 49 | 67 | Some(Err(Error::Permanent { |
| 50 | 68 | err: err.into(), |
| 51 | 69 | dir: dir.to_owned(), |
| 52 | 70 | })) |
| 53 | 71 | } |
| 72 | + | |
| 73 | + fn intermediate_failure(&self, err: std::io::Error) -> Option<Result<&'a Path, Error>> { | |
| 74 | + Some(Err(Error::Intermediate(err.kind()))) | |
| 75 | + } | |
| 54 | 76 | } |
| 55 | 77 | |
| 56 | 78 | impl<'a> Iterator for Iter<'a> { |
| @@ -59,17 +81,23 @@ impl<'a> Iterator for Iter<'a> { · 2 unmodified lines | ||
| 59 | 81 | fn next(&mut self) -> Option<Self::Item> { |
| 60 | 82 | use std::io::ErrorKind::*; |
| 61 | 83 | match self.cursors.pop() { |
| 62 | − Some(cursor) => match std::fs::create_dir(cursor) { | |
| 63 | − Ok(()) => Some(Ok(cursor)), | |
| 84 | + Some(dir) => match std::fs::create_dir(dir) { | |
| 85 | + Ok(()) => Some(Ok(dir)), | |
| 64 | 86 | Err(err) => match err.kind() { |
| 65 | − AlreadyExists => Some(Ok(cursor)), | |
| 87 | + AlreadyExists => Some(Ok(dir)), | |
| 66 | 88 | NotFound => { |
| 67 | − self.cursors.push(cursor); | |
| 68 | − self.cursors.push(match cursor.parent() { | |
| 69 | − None => return self.fail_permanently(cursor, InvalidInput), | |
| 89 | + self.cursors.push(dir); | |
| 90 | + self.cursors.push(match dir.parent() { | |
| 91 | + None => return self.pernanent_failure(dir, InvalidInput), | |
| 70 | 92 | Some(parent) => parent, |
| 71 | 93 | }); |
| 72 | − Some(Err(Error::Intermediate(err.kind()))) | |
| 94 | + self.intermediate_failure(err) | |
| 95 | + } | |
| 96 | + Interrupted if self.options.retries_on_interrupt == 0 => self.pernanent_failure(dir, Interrupted), | |
| 97 | + Interrupted => { | |
| 98 | + self.options.retries_on_interrupt -= 1; | |
| 99 | + self.cursors.push(dir); | |
| 100 | + self.intermediate_failure(err) | |
| 73 | 101 | } |
| 74 | 102 | kind => todo!("{:?}", kind), |
| 75 | 103 | }, |