Skip to content

Commit 4de2c4b

Browse files
committed
feat: add FileSnapshot::into_owned_or_cloned().
That way it's possible to efficiently take ownership if there happens to be only one instance of a snapshot.
1 parent 7bc540e commit 4de2c4b

File tree

9 files changed

+49
-2
lines changed

9 files changed

+49
-2
lines changed

gix-fs/src/snapshot.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// TODO: tests
2-
use std::ops::Deref;
3-
42
use gix_features::threading::{get_mut, get_ref, MutableOnDemand, OwnShared};
3+
use std::ops::Deref;
54

65
/// A structure holding enough information to reload a value if its on-disk representation changes as determined by its modified time.
76
#[derive(Debug)]
@@ -39,6 +38,16 @@ impl<T: Clone + std::fmt::Debug> Clone for FileSnapshot<T> {
3938
}
4039
}
4140

41+
impl<T: Clone + std::fmt::Debug> FileSnapshot<T> {
42+
/// Return the contained instance if nobody else is holding it, or clone it otherwise.
43+
pub fn into_owned_or_cloned(self: OwnShared<Self>) -> T {
44+
match OwnShared::try_unwrap(self) {
45+
Ok(this) => this.value,
46+
Err(this) => this.value.clone(),
47+
}
48+
}
49+
}
50+
4251
/// A snapshot of a resource which is up-to-date in the moment it is retrieved.
4352
pub type SharedFileSnapshot<T> = OwnShared<FileSnapshot<T>>;
4453

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

gix-fs/tests/fs.rs renamed to gix-fs/tests/fs/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send +
33
mod capabilities;
44
mod dir;
55
mod read_dir;
6+
mod snapshot;
67
mod stack;
File renamed without changes.

gix-fs/tests/fs/snapshot.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use gix_fs::SharedFileSnapshotMut;
2+
3+
#[test]
4+
fn journey() -> Result<(), Box<dyn std::error::Error>> {
5+
let tmp = tempfile::tempdir().unwrap();
6+
let file_path = tmp.path().join("content");
7+
let smut = SharedFileSnapshotMut::<String>::new();
8+
9+
let check = || file_path.metadata().ok()?.modified().ok();
10+
let open = || {
11+
Ok(match std::fs::read_to_string(&file_path) {
12+
Ok(s) => Some(s),
13+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
14+
Err(err) => return Err(err),
15+
})
16+
};
17+
let snap = smut.recent_snapshot(check, open)?;
18+
assert!(snap.is_none());
19+
20+
std::fs::write(&file_path, "content")?;
21+
let snap = smut.recent_snapshot(check, open)?.expect("content read");
22+
assert_eq!(&**snap, "content", "it read the file for the first time");
23+
24+
std::fs::write(&file_path, "change")?;
25+
let snap = smut.recent_snapshot(check, open)?.expect("content read");
26+
assert_eq!(&**snap, "change", "it picks up the change");
27+
28+
std::fs::remove_file(&file_path)?;
29+
let snap = smut.recent_snapshot(check, open)?;
30+
assert!(snap.is_none(), "file deleted, nothing to see here");
31+
32+
std::fs::write(&file_path, "new")?;
33+
let snap = smut.recent_snapshot(check, open)?.expect("content read again");
34+
let owned: String = snap.into_owned_or_cloned();
35+
assert_eq!(owned, "new", "owned versions are possible easily and efficiently");
36+
Ok(())
37+
}
File renamed without changes.

0 commit comments

Comments
 (0)