You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-15 13:50:27 +02:00
Introduce a cargo clippy
run
Personally, I don’t always agree with Clippy, but it a very widely recommended tool for writing idiomatic Rust. So on balance, I think it’s overall a good idea to enable it for both our exercises and our tooling.
This commit is contained in:
30
.github/workflows/build.yml
vendored
30
.github/workflows/build.yml
vendored
@ -10,36 +10,6 @@ env:
|
|||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install formatting dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install gettext yapf3
|
|
||||||
|
|
||||||
- name: Install nightly rustfmt
|
|
||||||
run: |
|
|
||||||
rustup default nightly
|
|
||||||
rustup component add rustfmt
|
|
||||||
|
|
||||||
- name: Check formatting
|
|
||||||
uses: dprint/check@v2.2
|
|
||||||
|
|
||||||
typos:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Check for typos
|
|
||||||
uses: crate-ci/typos@v1.23.2
|
|
||||||
with:
|
|
||||||
config: ./.github/typos.toml
|
|
||||||
|
|
||||||
cargo:
|
cargo:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
53
.github/workflows/lint.yml
vendored
Normal file
53
.github/workflows/lint.yml
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
name: Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install formatting dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install gettext yapf3
|
||||||
|
|
||||||
|
- name: Install nightly rustfmt
|
||||||
|
run: |
|
||||||
|
rustup default nightly
|
||||||
|
rustup component add rustfmt
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
uses: dprint/check@v2.2
|
||||||
|
|
||||||
|
typos:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check for typos
|
||||||
|
uses: crate-ci/typos@v1.23.2
|
||||||
|
with:
|
||||||
|
config: ./.github/typos.toml
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Rust cache
|
||||||
|
uses: ./.github/workflows/setup-rust-cache
|
||||||
|
|
||||||
|
- name: Clippy
|
||||||
|
run: cargo clippy
|
@ -48,7 +48,7 @@ fn timediff(actual: u64, target: u64, slop: u64) -> String {
|
|||||||
} else if actual + slop < target {
|
} else if actual + slop < target {
|
||||||
format!("{}: ({} short)", duration(actual), duration(target - actual),)
|
format!("{}: ({} short)", duration(actual), duration(target - actual),)
|
||||||
} else {
|
} else {
|
||||||
format!("{}", duration(actual))
|
duration(actual).to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ fn main() {
|
|||||||
);
|
);
|
||||||
let matches = app.get_matches();
|
let matches = app.get_matches();
|
||||||
|
|
||||||
if let Some(_) = matches.subcommand_matches("supports") {
|
if matches.subcommand_matches("supports").is_some() {
|
||||||
// Support all renderers.
|
// Support all renderers.
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ impl Courses {
|
|||||||
fn course_mut(&mut self, name: impl AsRef<str>) -> &mut Course {
|
fn course_mut(&mut self, name: impl AsRef<str>) -> &mut Course {
|
||||||
let name = name.as_ref();
|
let name = name.as_ref();
|
||||||
if let Some(found_idx) =
|
if let Some(found_idx) =
|
||||||
self.courses.iter().position(|course| &course.name == name)
|
self.courses.iter().position(|course| course.name == name)
|
||||||
{
|
{
|
||||||
return &mut self.courses[found_idx];
|
return &mut self.courses[found_idx];
|
||||||
}
|
}
|
||||||
@ -177,9 +177,7 @@ impl Courses {
|
|||||||
&self,
|
&self,
|
||||||
chapter: &Chapter,
|
chapter: &Chapter,
|
||||||
) -> Option<(&Course, &Session, &Segment, &Slide)> {
|
) -> Option<(&Course, &Session, &Segment, &Slide)> {
|
||||||
let Some(ref source_path) = chapter.source_path else {
|
let source_path = chapter.source_path.as_ref()?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
for course in self {
|
for course in self {
|
||||||
for session in course {
|
for session in course {
|
||||||
@ -193,7 +191,7 @@ impl Courses {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +200,7 @@ impl<'a> IntoIterator for &'a Courses {
|
|||||||
type IntoIter = std::slice::Iter<'a, Course>;
|
type IntoIter = std::slice::Iter<'a, Course>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
(&self.courses).into_iter()
|
self.courses.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +214,7 @@ impl Course {
|
|||||||
fn session_mut(&mut self, name: impl AsRef<str>) -> &mut Session {
|
fn session_mut(&mut self, name: impl AsRef<str>) -> &mut Session {
|
||||||
let name = name.as_ref();
|
let name = name.as_ref();
|
||||||
if let Some(found_idx) =
|
if let Some(found_idx) =
|
||||||
self.sessions.iter().position(|session| &session.name == name)
|
self.sessions.iter().position(|session| session.name == name)
|
||||||
{
|
{
|
||||||
return &mut self.sessions[found_idx];
|
return &mut self.sessions[found_idx];
|
||||||
}
|
}
|
||||||
@ -275,7 +273,7 @@ impl<'a> IntoIterator for &'a Course {
|
|||||||
type IntoIter = std::slice::Iter<'a, Session>;
|
type IntoIter = std::slice::Iter<'a, Session>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
(&self.sessions).into_iter()
|
self.sessions.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +348,7 @@ impl<'a> IntoIterator for &'a Session {
|
|||||||
type IntoIter = std::slice::Iter<'a, Segment>;
|
type IntoIter = std::slice::Iter<'a, Segment>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
(&self.segments).into_iter()
|
self.segments.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +401,7 @@ impl<'a> IntoIterator for &'a Segment {
|
|||||||
type IntoIter = std::slice::Iter<'a, Slide>;
|
type IntoIter = std::slice::Iter<'a, Slide>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
(&self.slides).into_iter()
|
self.slides.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,7 +449,7 @@ impl Slide {
|
|||||||
pub fn is_sub_chapter(&self, chapter: &Chapter) -> bool {
|
pub fn is_sub_chapter(&self, chapter: &Chapter) -> bool {
|
||||||
// The first `source_path` in the slide is the "parent" chapter, so anything
|
// The first `source_path` in the slide is the "parent" chapter, so anything
|
||||||
// else is a sub-chapter.
|
// else is a sub-chapter.
|
||||||
chapter.source_path.as_ref() != self.source_paths.get(0)
|
chapter.source_path.as_ref() != self.source_paths.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the total duration of this slide.
|
/// Return the total duration of this slide.
|
||||||
|
@ -83,7 +83,7 @@ impl<const N: usize> Table<N> {
|
|||||||
for cell in iter {
|
for cell in iter {
|
||||||
write!(f, " {} |", cell)?;
|
write!(f, " {} |", cell)?;
|
||||||
}
|
}
|
||||||
write!(f, "\n")
|
writeln!(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ pub fn replace(
|
|||||||
}
|
}
|
||||||
["course", "outline", course_name] => {
|
["course", "outline", course_name] => {
|
||||||
let Some(course) = courses.find_course(course_name) else {
|
let Some(course) = courses.find_course(course_name) else {
|
||||||
return format!("not found - {}", captures[0].to_string());
|
return format!("not found - {}", &captures[0]);
|
||||||
};
|
};
|
||||||
course.schedule()
|
course.schedule()
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ pub fn process(output_directory: &Path, input_contents: &str) -> anyhow::Result<
|
|||||||
Event::Text(text) => {
|
Event::Text(text) => {
|
||||||
info!("Text: {:?}", text);
|
info!("Text: {:?}", text);
|
||||||
if let Some(output_file) = &mut current_file {
|
if let Some(output_file) = &mut current_file {
|
||||||
output_file.write(text.as_bytes())?;
|
output_file.write_all(text.as_bytes())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::End(TagEnd::CodeBlock) => {
|
Event::End(TagEnd::CodeBlock) => {
|
||||||
|
@ -41,7 +41,7 @@ async fn main() -> Result<(), tokio_websockets::Error> {
|
|||||||
println!("From server: {}", text);
|
println!("From server: {}", text);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(Err(err)) => return Err(err.into()),
|
Some(Err(err)) => return Err(err),
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,9 +107,7 @@ enum ParserError {
|
|||||||
fn parse(input: &str) -> Result<Expression, ParserError> {
|
fn parse(input: &str) -> Result<Expression, ParserError> {
|
||||||
let mut tokens = tokenize(input);
|
let mut tokens = tokenize(input);
|
||||||
|
|
||||||
fn parse_expr<'a>(
|
fn parse_expr(tokens: &mut Tokenizer<'_>) -> Result<Expression, ParserError> {
|
||||||
tokens: &mut Tokenizer<'a>,
|
|
||||||
) -> Result<Expression, ParserError> {
|
|
||||||
let tok = tokens.next().ok_or(ParserError::UnexpectedEOF)??;
|
let tok = tokens.next().ok_or(ParserError::UnexpectedEOF)??;
|
||||||
let expr = match tok {
|
let expr = match tok {
|
||||||
Token::Number(num) => {
|
Token::Number(num) => {
|
||||||
|
@ -25,8 +25,8 @@ where
|
|||||||
N: Copy + std::ops::Sub<Output = N>,
|
N: Copy + std::ops::Sub<Output = N>,
|
||||||
{
|
{
|
||||||
// ANCHOR_END: offset_differences
|
// ANCHOR_END: offset_differences
|
||||||
let a = (&values).into_iter();
|
let a = values.iter();
|
||||||
let b = (&values).into_iter().cycle().skip(offset);
|
let b = values.iter().cycle().skip(offset);
|
||||||
a.zip(b).map(|(a, b)| *b - *a).collect()
|
a.zip(b).map(|(a, b)| *b - *a).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Iterators are covered later.
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
// ANCHOR: solution
|
// ANCHOR: solution
|
||||||
// ANCHOR: transpose
|
// ANCHOR: transpose
|
||||||
fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
|
fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Omitting `return` is covered later.
|
||||||
|
#[allow(clippy::needless_return)]
|
||||||
// ANCHOR: solution
|
// ANCHOR: solution
|
||||||
// ANCHOR: fib
|
// ANCHOR: fib
|
||||||
fn fib(n: u32) -> u32 {
|
fn fib(n: u32) -> u32 {
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
// ANCHOR: solution
|
// ANCHOR: solution
|
||||||
// ANCHOR: ffi
|
// ANCHOR: ffi
|
||||||
mod ffi {
|
mod ffi {
|
||||||
@ -40,7 +41,7 @@ mod ffi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Layout according to the macOS man page for dir(5).
|
// Layout according to the macOS man page for dir(5).
|
||||||
#[cfg(all(target_os = "macos"))]
|
#[cfg(target_os = "macos")]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct dirent {
|
pub struct dirent {
|
||||||
pub d_fileno: u64,
|
pub d_fileno: u64,
|
||||||
|
@ -37,12 +37,9 @@ impl User {
|
|||||||
patient_name: &self.name,
|
patient_name: &self.name,
|
||||||
visit_count: self.visit_count as u32,
|
visit_count: self.visit_count as u32,
|
||||||
height_change: measurements.height - self.height,
|
height_change: measurements.height - self.height,
|
||||||
blood_pressure_change: match self.last_blood_pressure {
|
blood_pressure_change: self
|
||||||
Some(lbp) => {
|
.last_blood_pressure
|
||||||
Some((bp.0 as i32 - lbp.0 as i32, bp.1 as i32 - lbp.1 as i32))
|
.map(|lbp| (bp.0 as i32 - lbp.0 as i32, bp.1 as i32 - lbp.1 as i32)),
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
self.height = measurements.height;
|
self.height = measurements.height;
|
||||||
self.last_blood_pressure = Some(bp);
|
self.last_blood_pressure = Some(bp);
|
||||||
|
Reference in New Issue
Block a user