Recursively walk a directory

Walk is not stable, so instead use read_dir() and construct the implementation manually.

use std::fs::read_dir;
use std::fs::ReadDir;
use std::path::Path;
use std::path::PathBuf;

pub struct Walk {
  path:PathBuf,
  targets:Vec<PathBuf>,
  reader:Option<ReadDir>,
  current:Option<PathBuf>
}

impl Walk {

  /// Create a new walker
  pub fn new(path:&Path) -> Walk {
    let mut root = PathBuf::new();
    root.push(path);
    let mut rtn = Walk {
      path: root,
      targets: Vec::new(),
      reader: None,
      current: None
    };
    rtn.reset();
    return rtn;
  }

  /// Reset this iterator
  pub fn reset(&mut self) {
    self.targets.clear();
    self.targets.push(self.path.clone());
  }

  /// Generate a new reader, if we currently have none
  /// @return false If no reader could be generated.
  fn next_reader(&mut self) -> bool {
    let mut rtn = true;
    let mut check = true;
    while check {
      if self.reader.is_none() {
        if let Some(target) = self.targets.pop() {
          if let Ok(reader) = read_dir(target.clone()) {
            self.reader = Some(reader);
            self.current = Some(target);
          }
          else {
            // TODO: Collect errors
            debug!("Failed to read dir: {:?}", target);
            self.reader = None;
          }
        }
        else {
          check = false;
          rtn = false;
        }
      }
      else {
        check = false;
      }
    }
    return rtn;
  }

  /// Return the next path, push it onto the set of targets if it's a directory
  pub fn next(&mut self) -> Option<PathBuf> {
    if self.next_reader() {
      if let Some(record) = self.reader.as_mut().unwrap().next() {
        if let Ok(path) = record {

          // Generate filename
          let mut rtn = self.path.clone();
          rtn.push(self.current.as_ref().unwrap().clone());
          rtn.push(path.file_name());

          // Add this to the list of paths to open
          if let Ok(tt) = path.file_type() {
            if tt.is_dir() {
              self.targets.push(rtn.clone());
            }
          }

          return Some(rtn);
        }

        // I/O Error
        else {
          debug!("IO ERror");
          self.reader = None;
          return self.next();
        }
      }

      // No records left on this iterator
      else {
        self.reader = None;
        return self.next();
      }
    }
    return None;
  }
}

#[cfg(test)]
mod test {

  use super::Walk;
  use std::path::Path;

  #[test]
  fn test_walk_dir() {
    let target = Path::new("/tmp");
    let mut walk = Walk::new(target);
    while let Some(p) = walk.next() {
      debug!("{:?}", p);
    }
  }
}