Skip to main content
deleted 8 characters in body
Source Link
toolic
  • 16.4k
  • 6
  • 29
  • 221

This is my first Rust project (I'm primarily a C guy). What I I want to know is if my code is properly idiomatic (Rusty?). Also, are there any inefficiencies?

This is my first Rust project (I'm primarily a C guy). What I want to know is if my code is properly idiomatic (Rusty?). Also, are there any inefficiencies?

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?

add tags; add new line at end so fence won't be displayed with code- see https://codereview.meta.stackexchange.com/q/9148/120114
Source Link
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
    }
}
```
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
    }
}
```
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
    }
}
deleted 48 characters in body
Source Link

This is my first Rust project (I'm primarily a C guy). What I want to know is if my code is properly idiomatic (I don't know what the Rust equivalent of "Pythonic" isRusty?). Also, are there any inefficiencies?

This is my first Rust project (I'm primarily a C guy). What I want to know is if my code is properly idiomatic (I don't know what the Rust equivalent of "Pythonic" is). Also, are there any inefficiencies?

This is my first Rust project (I'm primarily a C guy). What I want to know is if my code is properly idiomatic (Rusty?). Also, are there any inefficiencies?

Source Link
Loading