This is my first Rust project (I'm primarily a C guy). I want to know if my code is properly idiomatic (Rusty?). Also, are there any inefficiencies?
The code defines an iterator (Searcher) that takes a regex, a starting directory, and an optional maximum search depth.  It generates locations of regex matches within the file system.
use std::fs;
use std::io;
use std::io::BufRead;
use std::iter;
use std::path;
use std::vec::Vec;
use regex;
pub struct Location {
    pub file: path::PathBuf,
    pub line: usize,
    pub text: String,
}
struct FileScanner<'a> {
    path: path::PathBuf,
    pattern: &'a regex::Regex,
    lines: iter::Enumerate<io::Lines<io::BufReader<fs::File>>>,
}
fn is_line_printable(line: &str) -> bool {
    line.chars()
        .all(|c| c.is_ascii_graphic() || c.is_whitespace())
}
impl<'a> FileScanner<'a> {
    fn build(path: path::PathBuf, pattern: &'a regex::Regex) -> Option<Self> {
        let handle = match fs::File::open(&path) {
            Ok(h) => h,
            Err(_) => return None,
        };
        let reader = io::BufReader::new(handle);
        Some(FileScanner {
            path,
            pattern,
            lines: reader.lines().into_iter().enumerate(),
        })
    }
}
impl<'a> Iterator for FileScanner<'a> {
    type Item = Location;
    fn next(&mut self) -> Option<Location> {
        loop {
            let (index, line) = match self.lines.next() {
                Some((i, Ok(l))) => (i, l),
                _ => return None,
            };
            if !is_line_printable(&line) {
                return None;
            }
            let pattern_match = match self.pattern.find(&line) {
                Some(m) => m,
                None => continue,
            };
            let start = pattern_match.start();
            let end = pattern_match.end();
            return Some(Location {
                file: self.path.to_path_buf(),
                line: index + 1,
                text: String::from(&line[start..end]),
            });
        }
    }
}
pub struct Searcher<'a> {
    pattern: &'a regex::Regex,
    max_depth: Option<u8>,
    readers: Vec<fs::ReadDir>,
    current_scanner: Option<FileScanner<'a>>,
}
impl<'a> Searcher<'a> {
    pub fn build(
        pattern: &'a regex::Regex,
        directory: &'a path::Path,
        depth: Option<u8>,
    ) -> Result<Self, String> {
        match depth {
            Some(0) => return Err(String::from("Depth cannot be 0")),
            _ => (),
        };
        let reader = match fs::read_dir(directory) {
            Ok(r) => r,
            Err(error) => return Err(error.to_string()),
        };
        let readers = vec![reader];
        Ok(Searcher {
            pattern,
            max_depth: depth,
            readers,
            current_scanner: None,
        })
    }
    fn push_directory(&mut self, directory: path::PathBuf) {
        match self.max_depth {
            Some(depth) if usize::from(depth) == self.readers.len() => return,
            _ => (),
        }
        let reader = match fs::read_dir(directory) {
            Ok(r) => r,
            Err(_) => return,
        };
        self.readers.push(reader);
    }
    fn next_match_from_file(&mut self) -> Option<Location> {
        let scanner = match &mut self.current_scanner {
            Some(s) => s,
            None => return None,
        };
        let location = scanner.next();
        if location.is_none() {
            self.current_scanner = None;
        }
        location
    }
}
impl<'a> Iterator for Searcher<'a> {
    type Item = Location;
    fn next(&mut self) -> Option<Location> {
        let location = self.next_match_from_file();
        if location.is_some() {
            return location;
        }
        while self.readers.len() > 0 {
            let current_reader = self.readers.last_mut().unwrap();
            let entry = match current_reader.next() {
                Some(Ok(ent)) => ent,
                Some(Err(_)) | None => {
                    self.readers.pop();
                    continue;
                }
            };
            let path = entry.path();
            if path.is_dir() {
                self.push_directory(path);
                continue;
            }
            self.current_scanner = FileScanner::build(path, self.pattern);
            let location = self.next_match_from_file();
            if location.is_some() {
                return location;
            }
        }
        None
    }
}

