Skip to content

Commit fde6044

Browse files
committed
update original
1 parent c9254f0 commit fde6044

18 files changed

Lines changed: 376 additions & 1 deletion

File tree

rust-cookbook/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["crates/algorithms/*", "crates/concurrency/*", "crates/development_tools/debugging/tracing", "crates/parsing/*", "crates/safety_critical/*", "crates/wasm", "crates/web", "xtask"]
2+
members = ["crates/algorithms/*", "crates/concurrency/*", "crates/development_tools/debugging/tracing", "crates/file/*", "crates/parsing/*", "crates/safety_critical/*", "crates/wasm", "crates/web", "xtask"]
33
exclude = ["crates/database/sea_orm", "crates/database/sqlx", "crates/web_leptos", "crates/web_leptos_hydrate", "crates/wasm_component_guest", "crates/wasm_component_host"]
44

55
[workspace.package]

rust-cookbook/build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ use walkdir::WalkDir;
22

33
const REMOVED_TESTS: &[&str] = &[
44
"./src/about.md",
5+
"./src/file/watch.md",
6+
"./src/file/watch/recursive.md",
7+
"./src/file/watch/debounce.md",
8+
"./src/file/which.md",
59
"./src/web/clients/requests/header.md",
610
"./src/web/clients/api/rate-limited.md",
711
"./src/concurrency/parallel/rayon-parallel-sort.md",

rust-cookbook/ci/dictionary.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ DateParse
9393
datetime
9494
DateTime
9595
DEadBEEfc
96+
debounce
97+
Debounce
98+
debouncer
9699
DecodeError
97100
dedup
98101
deduplicated
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "notify-example"
3+
version.workspace = true
4+
authors.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
publish.workspace = true
8+
9+
[dependencies]
10+
notify = "8"
11+
notify-debouncer-full = "0.7"
12+
13+
[dev-dependencies]
14+
tempfile = "3"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use notify::RecursiveMode;
2+
use notify_debouncer_full::new_debouncer;
3+
use std::path::PathBuf;
4+
use std::sync::mpsc;
5+
use std::time::Duration;
6+
7+
fn main() -> Result<(), Box<dyn std::error::Error>> {
8+
let path = std::env::args()
9+
.nth(1)
10+
.map(PathBuf::from)
11+
.unwrap_or_else(|| PathBuf::from("."));
12+
13+
let (tx, rx) = mpsc::channel();
14+
let mut debouncer = new_debouncer(Duration::from_secs(1), None, tx)?;
15+
debouncer.watch(&path, RecursiveMode::Recursive)?;
16+
17+
println!("watching {}. Press Ctrl-C to stop.", path.display());
18+
19+
for result in rx {
20+
match result {
21+
Ok(events) => {
22+
for event in events {
23+
println!("{:?}: {:?}", event.kind, event.paths);
24+
}
25+
}
26+
Err(errors) => {
27+
for error in errors {
28+
eprintln!("watch error: {error:?}");
29+
}
30+
}
31+
}
32+
}
33+
34+
Ok(())
35+
}
36+
37+
#[cfg(test)]
38+
mod tests {
39+
use super::*;
40+
use std::fs;
41+
42+
#[test]
43+
fn a_burst_collapses_into_one_batch() -> Result<(), Box<dyn std::error::Error>> {
44+
let dir = tempfile::tempdir()?;
45+
let (tx, rx) = mpsc::channel();
46+
let mut debouncer = new_debouncer(Duration::from_millis(200), None, tx)?;
47+
debouncer.watch(dir.path(), RecursiveMode::Recursive)?;
48+
49+
let file = dir.path().join("log.txt");
50+
for i in 0..5 {
51+
fs::write(&file, format!("line {i}\n"))?;
52+
}
53+
54+
let events = rx
55+
.recv_timeout(Duration::from_secs(5))?
56+
.map_err(|errors| format!("watch errors: {errors:?}"))?;
57+
assert!(events
58+
.iter()
59+
.any(|event| event.paths.iter().any(|p| p.ends_with("log.txt"))));
60+
Ok(())
61+
}
62+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use notify::event::{EventKind, ModifyKind};
2+
use notify::{RecursiveMode, Watcher};
3+
use std::path::PathBuf;
4+
use std::sync::mpsc;
5+
6+
fn main() -> Result<(), Box<dyn std::error::Error>> {
7+
let path = std::env::args()
8+
.nth(1)
9+
.map(PathBuf::from)
10+
.unwrap_or_else(|| PathBuf::from("."));
11+
12+
let (tx, rx) = mpsc::channel();
13+
let mut watcher = notify::recommended_watcher(tx)?;
14+
watcher.watch(&path, RecursiveMode::Recursive)?;
15+
16+
println!("watching {}. Press Ctrl-C to stop.", path.display());
17+
18+
for event in rx {
19+
let event = event?;
20+
match event.kind {
21+
EventKind::Create(_) => println!("created: {:?}", event.paths),
22+
EventKind::Modify(ModifyKind::Data(_)) => {
23+
println!("modified: {:?}", event.paths)
24+
}
25+
EventKind::Remove(_) => println!("removed: {:?}", event.paths),
26+
_ => {}
27+
}
28+
}
29+
30+
Ok(())
31+
}
32+
33+
#[cfg(test)]
34+
mod tests {
35+
use super::*;
36+
use std::fs;
37+
use std::time::{Duration, Instant};
38+
39+
#[test]
40+
fn create_emits_a_create_event() -> Result<(), Box<dyn std::error::Error>> {
41+
let dir = tempfile::tempdir()?;
42+
let (tx, rx) = mpsc::channel();
43+
let mut watcher = notify::recommended_watcher(tx)?;
44+
watcher.watch(dir.path(), RecursiveMode::Recursive)?;
45+
46+
let file = dir.path().join("created.txt");
47+
fs::write(&file, b"data")?;
48+
49+
let deadline = Instant::now() + Duration::from_secs(5);
50+
loop {
51+
let timeout = deadline.saturating_duration_since(Instant::now());
52+
let event = rx.recv_timeout(timeout)??;
53+
if matches!(event.kind, EventKind::Create(_))
54+
&& event.paths.iter().any(|p| p.ends_with("created.txt"))
55+
{
56+
return Ok(());
57+
}
58+
}
59+
}
60+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "which-example"
3+
version.workspace = true
4+
authors.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
publish.workspace = true
8+
9+
[dependencies]
10+
which = "8"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use which::{which, which_all};
2+
3+
fn main() -> Result<(), Box<dyn std::error::Error>> {
4+
let cargo = which("cargo")?;
5+
println!("cargo resolves to {}", cargo.display());
6+
assert!(cargo.is_absolute());
7+
8+
for path in which_all("cargo")? {
9+
println!("candidate: {}", path.display());
10+
}
11+
12+
match which("definitely-not-a-real-binary") {
13+
Ok(path) => println!("found at {}", path.display()),
14+
Err(error) => println!("not on PATH: {error}"),
15+
}
16+
17+
Ok(())
18+
}
19+
20+
#[cfg(test)]
21+
mod tests {
22+
use super::*;
23+
24+
#[test]
25+
fn resolves_cargo_to_an_absolute_path() -> Result<(), which::Error> {
26+
let cargo = which("cargo")?;
27+
assert!(cargo.is_absolute());
28+
Ok(())
29+
}
30+
31+
#[test]
32+
fn missing_binary_is_an_error() {
33+
assert!(which("definitely-not-a-real-binary").is_err());
34+
}
35+
}

rust-cookbook/src/SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
- [File System](file.md)
5757
- [Read & Write](file/read-write.md)
5858
- [Directory Traversal](file/dir.md)
59+
- [File Watching](file/watch.md)
60+
- [Find an Executable](file/which.md)
5961
- [Hardware Support](hardware.md)
6062
- [Processor](hardware/processor.md)
6163
- [Memory Management](mem.md)

rust-cookbook/src/file.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
| [Write a string to a file][ex-write-string] | [![std-badge]][std] [![tempfile-badge]][tempfile] | [![cat-filesystem-badge]][cat-filesystem] |
77
| [Read lines of strings from a file][ex-std-read-lines] | [![std-badge]][std] | [![cat-filesystem-badge]][cat-filesystem] |
88
| [Rename or atomically replace a file][ex-rename] | [![std-badge]][std] [![tempfile-badge]][tempfile] | [![cat-filesystem-badge]][cat-filesystem] |
9+
| [Create a temporary file][ex-tempfile] | [![tempfile-badge]][tempfile] | [![cat-filesystem-badge]][cat-filesystem] |
10+
| [Atomically replace a file with a temporary file][ex-atomic-write] | [![tempfile-badge]][tempfile] | [![cat-filesystem-badge]][cat-filesystem] |
911
| [Avoid writing and reading from a same file][ex-avoid-read-write] | [![same_file-badge]][same_file] | [![cat-filesystem-badge]][cat-filesystem] |
1012
| [Access a file randomly using a memory map][ex-random-file-access] | [![memmap-badge]][memmap] | [![cat-filesystem-badge]][cat-filesystem] |
1113
| [Read a file line by line with BufReader][ex-buf-reader] | [![std-badge]][std] [![tempfile-badge]][tempfile] | [![cat-filesystem-badge]][cat-filesystem] |
@@ -23,7 +25,11 @@
2325
| [Recursively calculate file sizes at given depth][ex-file-sizes] | [![walkdir-badge]][walkdir] | [![cat-filesystem-badge]][cat-filesystem] |
2426
| [Find all png files recursively][ex-glob-recursive] | [![glob-badge]][glob] | [![cat-filesystem-badge]][cat-filesystem] |
2527
| [Find all files with given pattern ignoring filename case][ex-glob-with] | [![glob-badge]][glob] | [![cat-filesystem-badge]][cat-filesystem] |
28+
| [Watch a directory for changes][ex-notify-watch] | [![notify-badge]][notify] | [![cat-filesystem-badge]][cat-filesystem] |
29+
| [Debounce a burst of file events][ex-notify-debounce] | [![notify-debouncer-full-badge]][notify-debouncer-full] | [![cat-filesystem-badge]][cat-filesystem] |
30+
| [Find a binary on the PATH][ex-which] | [![which-badge]][which] | [![cat-filesystem-badge]][cat-filesystem] |
2631

32+
[ex-atomic-write]: file/read-write.html#atomically-replace-a-file-with-a-temporary-file
2733
[ex-avoid-read-write]: file/read-write.html#avoid-writing-and-reading-from-a-same-file
2834
[ex-buf-reader]: file/read-write.html#read-a-file-line-by-line-with-bufreader
2935
[ex-buf-writer]: file/read-write.html#write-to-a-file-with-bufwriter
@@ -37,12 +43,16 @@
3743
[ex-find-file-loops]: file/dir.html#find-loops-for-a-given-path
3844
[ex-glob-recursive]: file/dir.html#find-all-png-files-recursively
3945
[ex-glob-with]: file/dir.html#find-all-files-with-given-pattern-ignoring-filename-case
46+
[ex-notify-debounce]: file/watch.html#debounce-a-burst-of-file-events
47+
[ex-notify-watch]: file/watch.html#watch-a-directory-for-changes
4048
[ex-path-inspect]: file/dir.html#construct-and-inspect-a-path
4149
[ex-random-file-access]: file/read-write.html#access-a-file-randomly-using-a-memory-map
4250
[ex-read-to-string]: file/read-write.html#read-a-whole-file-into-a-string
4351
[ex-rename]: file/read-write.html#rename-or-atomically-replace-a-file
4452
[ex-std-read-lines]: file/read-write.html#read-lines-of-strings-from-a-file
4553
[ex-stdin-readline]: file/read-write.html#read-a-line-from-stdin
54+
[ex-tempfile]: file/read-write.html#create-a-temporary-file
55+
[ex-which]: file/which.html#find-a-binary-on-the-path
4656
[ex-write-fmt]: file/read-write.html#format-text-into-a-string-with-write
4757
[ex-write-string]: file/read-write.html#write-a-string-to-a-file
4858

0 commit comments

Comments
 (0)