refactor(ruff): Implement doc_lines_from_tokens as iterator (#3124)

This is a nit refactor... It implements the extraction of document lines as an iterator instead of a Vector to avoid the extra allocation.
This commit is contained in:
Micha Reiser 2023-02-22 15:22:06 +01:00 committed by GitHub
parent bc3a9ce003
commit 262e768fd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 51 additions and 37 deletions

View file

@ -3,31 +3,57 @@
use rustpython_parser::ast::{Constant, ExprKind, Stmt, StmtKind, Suite}; use rustpython_parser::ast::{Constant, ExprKind, Stmt, StmtKind, Suite};
use rustpython_parser::lexer::{LexResult, Tok}; use rustpython_parser::lexer::{LexResult, Tok};
use std::iter::FusedIterator;
use crate::ast::visitor; use crate::ast::visitor;
use crate::ast::visitor::Visitor; use crate::ast::visitor::Visitor;
/// Extract doc lines (standalone comments) from a token sequence. /// Extract doc lines (standalone comments) from a token sequence.
pub fn doc_lines_from_tokens(lxr: &[LexResult]) -> Vec<usize> { pub fn doc_lines_from_tokens(lxr: &[LexResult]) -> DocLines {
let mut doc_lines: Vec<usize> = Vec::default(); DocLines::new(lxr)
let mut prev: Option<usize> = None;
for (start, tok, end) in lxr.iter().flatten() {
if matches!(tok, Tok::Indent | Tok::Dedent | Tok::Newline) {
continue;
} }
if matches!(tok, Tok::Comment(..)) {
if let Some(prev) = prev { pub struct DocLines<'a> {
inner: std::iter::Flatten<core::slice::Iter<'a, LexResult>>,
prev: Option<usize>,
}
impl<'a> DocLines<'a> {
fn new(lxr: &'a [LexResult]) -> Self {
Self {
inner: lxr.iter().flatten(),
prev: None,
}
}
}
impl Iterator for DocLines<'_> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
loop {
let (start, tok, end) = self.inner.next()?;
match tok {
Tok::Indent | Tok::Dedent | Tok::Newline => continue,
Tok::Comment(..) => {
if let Some(prev) = self.prev {
if start.row() > prev { if start.row() > prev {
doc_lines.push(start.row()); break Some(start.row());
} }
} else { } else {
doc_lines.push(start.row()); break Some(start.row());
} }
} }
prev = Some(end.row()); _ => {}
} }
doc_lines
self.prev = Some(end.row());
} }
}
}
impl FusedIterator for DocLines<'_> {}
#[derive(Default)] #[derive(Default)]
struct StringLinesVisitor { struct StringLinesVisitor {

View file

@ -1,5 +1,3 @@
use std::fs::File;
use std::io::{BufReader, Read};
use std::ops::Deref; use std::ops::Deref;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -88,12 +86,3 @@ pub fn relativize_path(path: impl AsRef<Path>) -> String {
} }
format!("{}", path.display()) format!("{}", path.display())
} }
/// Read a file's contents from disk.
pub fn read_file<P: AsRef<Path>>(path: P) -> Result<String> {
let file = File::open(path)?;
let mut buf_reader = BufReader::new(file);
let mut contents = String::new();
buf_reader.read_to_string(&mut contents)?;
Ok(contents)
}

View file

@ -223,7 +223,7 @@ const MAX_ITERATIONS: usize = 100;
/// Add any missing `# noqa` pragmas to the source code at the given `Path`. /// Add any missing `# noqa` pragmas to the source code at the given `Path`.
pub fn add_noqa_to_path(path: &Path, package: Option<&Path>, settings: &Settings) -> Result<usize> { pub fn add_noqa_to_path(path: &Path, package: Option<&Path>, settings: &Settings) -> Result<usize> {
// Read the file from disk. // Read the file from disk.
let contents = fs::read_file(path)?; let contents = std::fs::read_to_string(path)?;
// Tokenize once. // Tokenize once.
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents); let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents);

View file

@ -5,7 +5,6 @@ use std::path::{Path, PathBuf};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::fs;
use crate::settings::options::Options; use crate::settings::options::Options;
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
@ -30,13 +29,13 @@ impl Pyproject {
/// Parse a `ruff.toml` file. /// Parse a `ruff.toml` file.
fn parse_ruff_toml<P: AsRef<Path>>(path: P) -> Result<Options> { fn parse_ruff_toml<P: AsRef<Path>>(path: P) -> Result<Options> {
let contents = fs::read_file(path)?; let contents = std::fs::read_to_string(path)?;
toml::from_str(&contents).map_err(Into::into) toml::from_str(&contents).map_err(Into::into)
} }
/// Parse a `pyproject.toml` file. /// Parse a `pyproject.toml` file.
fn parse_pyproject_toml<P: AsRef<Path>>(path: P) -> Result<Pyproject> { fn parse_pyproject_toml<P: AsRef<Path>>(path: P) -> Result<Pyproject> {
let contents = fs::read_file(path)?; let contents = std::fs::read_to_string(path)?;
toml::from_str(&contents).map_err(Into::into) toml::from_str(&contents).map_err(Into::into)
} }

View file

@ -12,7 +12,7 @@ use crate::packaging::detect_package_root;
use crate::registry::Diagnostic; use crate::registry::Diagnostic;
use crate::settings::{flags, Settings}; use crate::settings::{flags, Settings};
use crate::source_code::{Indexer, Locator, Stylist}; use crate::source_code::{Indexer, Locator, Stylist};
use crate::{directives, fs, rustpython_helpers}; use crate::{directives, rustpython_helpers};
pub fn test_resource_path(path: impl AsRef<Path>) -> std::path::PathBuf { pub fn test_resource_path(path: impl AsRef<Path>) -> std::path::PathBuf {
Path::new("./resources/test/").join(path) Path::new("./resources/test/").join(path)
@ -22,7 +22,7 @@ pub fn test_resource_path(path: impl AsRef<Path>) -> std::path::PathBuf {
/// asserts that autofixes converge after 10 iterations. /// asserts that autofixes converge after 10 iterations.
pub fn test_path(path: &Path, settings: &Settings) -> Result<Vec<Diagnostic>> { pub fn test_path(path: &Path, settings: &Settings) -> Result<Vec<Diagnostic>> {
let path = test_resource_path("fixtures").join(path); let path = test_resource_path("fixtures").join(path);
let contents = fs::read_file(&path)?; let contents = std::fs::read_to_string(&path)?;
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents); let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents);
let locator = Locator::new(&contents); let locator = Locator::new(&contents);
let stylist = Stylist::from_contents(&contents, &locator); let stylist = Stylist::from_contents(&contents, &locator);

View file

@ -81,7 +81,7 @@ pub fn lint_path(
}; };
// Read the file from disk. // Read the file from disk.
let contents = fs::read_file(path)?; let contents = std::fs::read_to_string(path)?;
// Lint the file. // Lint the file.
let ( let (