Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ env:
RUST_BACKTRACE: 1

jobs:
# Code quality checks
quality:
name: Quality Checks
common-quality:
name: Common Quality Checks
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1
Expand All @@ -23,15 +22,8 @@ jobs:
with:
save-cache: ${{ github.ref_name == 'main' }}
cache-key: warm
components: clippy rustfmt
tools: typos-cli,cargo-deny,cargo-shear

- name: Check formatting
run: cargo fmt --all -- --check

- name: Clippy
run: cargo clippy --all-targets --all-features -- -D warnings

- name: Check for typos
run: typos

Expand All @@ -41,6 +33,30 @@ jobs:
- name: Run cargo-shear
run: cargo shear

# Code quality checks
quality:
name: Quality Checks ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: taiki-e/checkout-action@b13d20b7cda4e2f325ef19895128f7ff735c0b3d # v1.3.1

- uses: oxc-project/setup-rust@cd82e1efec7fef815e2c23d296756f31c7cdc03d # v1.0.0
with:
save-cache: ${{ github.ref_name == 'main' }}
cache-key: warm
components: clippy rustfmt
tools: typos-cli,cargo-deny,cargo-shear

- name: Check formatting
run: cargo fmt -- --check

- name: Clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings

# Test on multiple platforms with different Rust versions
test:
name: Test ${{ matrix.os }} ${{ matrix.features != '' && format('({0})', matrix.features) || '' }}
Expand Down
58 changes: 58 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,64 @@ homepage = "https://github.com/notify-rs/notify"
repository = "https://github.com/notify-rs/notify.git"
edition = "2024"

[workspace.lints.clippy]
# Guidelines
# - We should only disable rules globally if they are either false positives, chaotic, or does not make sense.
# - Group are enabled with priority -1, so we could easily override some specific rules.
# - https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-lints-section

# --- restriction https://doc.rust-lang.org/clippy/usage.html#clippyrestriction
allow_attributes = "deny"
dbg_macro = "deny"
print_stdout = "deny"

# I like the explicitness of this rule as it removes confusion around `clone`.
# This increases readability, avoids `clone` mindlessly and heap allocating on accident.
clone_on_ref_ptr = "deny"
empty_drop = "deny"
exit = "deny"
filetype_is_file = "deny"
get_unwrap = "deny"
rc_buffer = "deny"
rc_mutex = "deny"
rest_pat_in_fully_bound_structs = "deny"
unnecessary_safety_comment = "deny"

# --- pedantic #https://doc.rust-lang.org/clippy/usage.html#clippypedantic
# To write the best rust code, pedantic group is enabled by default.
pedantic = { level = "deny", priority = -1 }
case_sensitive_file_extension_comparisons = "allow"

# Though the following are nursery rules, they’re still useful.
debug_assert_with_mut_call = "warn"
iter_on_single_items = "warn"
needless_pass_by_ref_mut = "warn"
redundant_clone = "warn"
redundant_pub_crate = "warn"
significant_drop_in_scrutinee = "warn"
unused_peekable = "warn"

# Wizards, naming is too hard.
module_inception = "allow"
module_name_repetitions = "allow"
similar_names = "allow"
struct_field_names = "allow"
# Forwarding `Result` is a common pattern, this rule is too pedantic.
missing_errors_doc = "allow"
doc_markdown = "allow"
inline_always = "allow"
wildcard_imports = "allow"
redundant_closure_for_method_calls = "allow"
items_after_statements = "allow"
redundant-pub-crate = "allow"
# Order doesn't really matter https://rust-lang.github.io/rust-clippy/master/index.html#/inconsistent_struct_constructor
inconsistent_struct_constructor = "allow"
# Single match is equally readable as if/else. https://rust-lang.github.io/rust-clippy/master/index.html#/single_match
single_match = "allow"
single_match_else = "allow"
# Rewriting `unwrap_or` to `map_or` requires to annotate type explicitly which is cumbersome
map_unwrap_or = "allow"

[workspace.dependencies]
bitflags = "2.7.0"
crossbeam-channel = "0.5.0"
Expand Down
1 change: 0 additions & 1 deletion clippy.toml

This file was deleted.

3 changes: 3 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ publish = false
edition = "2024"
license = "MIT OR Apache-2.0"

[lints]
workspace = true

[dev-dependencies]
rolldown-notify = { workspace = true }
rolldown-notify-debouncer-mini = { workspace = true }
Expand Down
12 changes: 7 additions & 5 deletions examples/async_monitor.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::print_stdout)]

use futures::{
SinkExt, StreamExt,
channel::mpsc::{Receiver, channel},
Expand All @@ -10,11 +12,11 @@ fn main() {
let path = std::env::args()
.nth(1)
.expect("Argument 1 needs to be a path");
println!("watching {}", path);
println!("watching {path}");

futures::executor::block_on(async {
if let Err(e) = async_watch(path).await {
println!("error: {:?}", e)
println!("error: {e:?}");
}
});
}
Expand All @@ -28,7 +30,7 @@ fn async_watcher() -> notify::Result<(RecommendedWatcher, Receiver<notify::Resul
move |res| {
futures::executor::block_on(async {
tx.send(res).await.unwrap();
})
});
},
Config::default(),
)?;
Expand All @@ -45,8 +47,8 @@ async fn async_watch<P: AsRef<Path>>(path: P) -> notify::Result<()> {

while let Some(res) = rx.next().await {
match res {
Ok(event) => println!("changed: {:?}", event),
Err(e) => println!("watch error: {:?}", e),
Ok(event) => println!("changed: {event:?}"),
Err(e) => println!("watch error: {e:?}"),
}
}

Expand Down
2 changes: 2 additions & 0 deletions examples/debouncer_full.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::print_stdout)]

use std::{fs, thread, time::Duration};

use notify::WatchMode;
Expand Down
2 changes: 2 additions & 0 deletions examples/debouncer_mini_custom.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::print_stdout)]

use std::{path::Path, time::Duration};

use notify::{self, WatchMode};
Expand Down
14 changes: 9 additions & 5 deletions examples/poll_sysfs.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#![allow(clippy::print_stdout)]
#![cfg_attr(target_os = "windows", expect(clippy::unnecessary_wraps))]

/// Example for watching kernel internal filesystems like `/sys` and `/proc`
/// These can't be watched by the default backend or unconfigured pollwatcher
/// This example can't be demonstrated under windows, it might be relevant for network shares
Expand All @@ -17,16 +20,17 @@ fn not_windows_main() -> notify::Result<()> {
eprintln!(
"Must provide path to watch, default system path was not found (probably you're not running on Linux?)"
);
#[expect(clippy::exit)]
std::process::exit(1);
}
println!(
"Trying {:?}, use `ping localhost` to see changes!",
lo_stats
"Trying {}, use `ping localhost` to see changes!",
lo_stats.display()
);
paths.push(lo_stats);
}

println!("watching {:?}...", paths);
println!("watching {paths:?}...");
// configure pollwatcher backend
let config = Config::default()
.with_compare_contents(true) // crucial part for pseudo filesystems
Expand All @@ -43,8 +47,8 @@ fn not_windows_main() -> notify::Result<()> {
// print all events, never returns
for res in rx {
match res {
Ok(event) => println!("changed: {:?}", event),
Err(e) => println!("watch error: {:?}", e),
Ok(event) => println!("changed: {event:?}"),
Err(e) => println!("watch error: {e:?}"),
}
}

Expand Down
6 changes: 4 additions & 2 deletions examples/pollwatcher_manual.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::print_stdout)]

use notify::{Config, PollWatcher, WatchMode, Watcher};
use std::path::Path;
use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
Expand Down Expand Up @@ -34,8 +36,8 @@ fn watch<P: AsRef<Path>>(path: P) -> notify::Result<()> {
std::thread::spawn(move || {
for res in rx {
match res {
Ok(event) => println!("changed: {:?}", event),
Err(e) => println!("watch error: {:?}", e),
Ok(event) => println!("changed: {event:?}"),
Err(e) => println!("watch error: {e:?}"),
}
}
});
Expand Down
2 changes: 2 additions & 0 deletions examples/pollwatcher_scan.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::print_stdout)]

use notify::{Config, PollWatcher, WatchMode, Watcher, poll::ScanEvent};
use std::path::Path;
use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
Expand Down
4 changes: 3 additions & 1 deletion examples/watcher_kind.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::print_stdout)]

use notify::*;
use std::{path::Path, time::Duration};

Expand All @@ -23,6 +25,6 @@ fn main() {

// just print all events, this blocks forever
for e in rx {
println!("{:?}", e);
println!("{e:?}");
}
}
3 changes: 3 additions & 0 deletions file-id/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ name = "file_id"
name = "file-id"
path = "bin/file_id.rs"

[lints]
workspace = true

[dependencies]
serde = { workspace = true, optional = true }

Expand Down
2 changes: 2 additions & 0 deletions file-id/bin/file_id.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::print_stdout)]

use std::io;

use file_id::FileId;
Expand Down
14 changes: 9 additions & 5 deletions file-id/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,23 @@ pub enum FileId {
}

impl FileId {
#[must_use]
pub fn new_inode(device_id: u64, inode_number: u64) -> Self {
FileId::Inode {
device_id,
inode_number,
}
}

#[must_use]
pub fn new_low_res(volume_serial_number: u32, file_index: u64) -> Self {
FileId::LowRes {
volume_serial_number,
file_index,
}
}

#[must_use]
pub fn new_high_res(volume_serial_number: u64, file_id: u128) -> Self {
FileId::HighRes {
volume_serial_number,
Expand Down Expand Up @@ -200,16 +203,17 @@ unsafe fn get_file_info_ex(file: &fs::File) -> Result<FileId, io::Error> {

unsafe {
let mut info: FILE_ID_INFO = mem::zeroed();
#[expect(clippy::cast_possible_truncation)]
let ret = GetFileInformationByHandleEx(
file.as_raw_handle() as HANDLE,
FileIdInfo,
&mut info as *mut FILE_ID_INFO as _,
(&raw mut info).cast(),
mem::size_of::<FILE_ID_INFO>() as u32,
);

if ret == 0 {
return Err(io::Error::last_os_error());
};
}

Ok(FileId::new_high_res(
info.VolumeSerialNumber,
Expand All @@ -228,14 +232,14 @@ unsafe fn get_file_info(file: &fs::File) -> Result<FileId, io::Error> {

unsafe {
let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed();
let ret = GetFileInformationByHandle(file.as_raw_handle() as HANDLE, &mut info);
let ret = GetFileInformationByHandle(file.as_raw_handle() as HANDLE, &raw mut info);
if ret == 0 {
return Err(io::Error::last_os_error());
};
}

Ok(FileId::new_low_res(
info.dwVolumeSerialNumber,
((info.nFileIndexHigh as u64) << 32) | (info.nFileIndexLow as u64),
(u64::from(info.nFileIndexHigh) << 32) | u64::from(info.nFileIndexLow),
))
}
}
Expand Down
3 changes: 3 additions & 0 deletions notify-debouncer-full/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ macos_fsevent = ["rolldown-notify/macos_fsevent"]
macos_kqueue = ["rolldown-notify/macos_kqueue"]
serialization-compat-6 = ["rolldown-notify/serialization-compat-6"]

[lints]
workspace = true

[dependencies]
rolldown-notify.workspace = true
rolldown-notify-types.workspace = true
Expand Down
6 changes: 4 additions & 2 deletions notify-debouncer-full/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ pub struct FileIdMap {

impl FileIdMap {
/// Construct an empty cache.
#[must_use]
pub fn new() -> Self {
Default::default()
FileIdMap::default()
}

fn dir_scan_depth(is_recursive: bool) -> usize {
Expand Down Expand Up @@ -94,8 +95,9 @@ pub struct NoCache;

impl NoCache {
/// Construct an empty cache.
#[must_use]
pub fn new() -> Self {
Default::default()
NoCache
}
}

Expand Down
Loading