1use std::ops::Deref;
3
4use gix_features::threading::{get_mut, get_ref, MutableOnDemand, OwnShared};
5
6#[derive(Debug)]
8pub struct FileSnapshot<T: std::fmt::Debug> {
9 value: T,
10 modified: std::time::SystemTime,
11}
12
13impl<T: std::fmt::Debug> FileSnapshot<T> {
15 pub fn new(value: T) -> Self {
20 FileSnapshot {
21 value,
22 modified: std::time::UNIX_EPOCH,
23 }
24 }
25}
26
27impl<T: std::fmt::Debug> From<T> for FileSnapshot<T> {
28 fn from(value: T) -> Self {
29 FileSnapshot::new(value)
30 }
31}
32
33impl<T: Clone + std::fmt::Debug> Clone for FileSnapshot<T> {
34 fn clone(&self) -> Self {
35 Self {
36 value: self.value.clone(),
37 modified: self.modified,
38 }
39 }
40}
41
42impl<T: Clone + std::fmt::Debug> FileSnapshot<T> {
43 pub fn into_owned_or_cloned(self: OwnShared<Self>) -> T {
45 match OwnShared::try_unwrap(self) {
46 Ok(this) => this.value,
47 Err(this) => this.value.clone(),
48 }
49 }
50}
51
52pub type SharedFileSnapshot<T> = OwnShared<FileSnapshot<T>>;
54
55#[derive(Debug, Default)]
60pub struct SharedFileSnapshotMut<T: std::fmt::Debug>(pub MutableOnDemand<Option<SharedFileSnapshot<T>>>);
61
62impl<T: std::fmt::Debug> Deref for FileSnapshot<T> {
63 type Target = T;
64
65 fn deref(&self) -> &Self::Target {
66 &self.value
67 }
68}
69
70impl<T: std::fmt::Debug> std::ops::DerefMut for FileSnapshot<T> {
71 fn deref_mut(&mut self) -> &mut Self::Target {
72 &mut self.value
73 }
74}
75
76impl<T: std::fmt::Debug> Deref for SharedFileSnapshotMut<T> {
77 type Target = MutableOnDemand<Option<SharedFileSnapshot<T>>>;
78
79 fn deref(&self) -> &Self::Target {
80 &self.0
81 }
82}
83
84impl<T: std::fmt::Debug> SharedFileSnapshotMut<T> {
85 pub fn new() -> Self {
89 SharedFileSnapshotMut(MutableOnDemand::new(None))
90 }
91
92 pub fn force_refresh<E>(
95 &self,
96 open: impl FnOnce() -> Result<Option<(std::time::SystemTime, T)>, E>,
97 ) -> Result<(), E> {
98 let mut state = get_mut(&self.0);
99 *state = open()?.map(|(modified, value)| OwnShared::new(FileSnapshot { value, modified }));
100 Ok(())
101 }
102
103 pub fn recent_snapshot<E>(
110 &self,
111 mut current_modification_time: impl FnMut() -> Option<std::time::SystemTime>,
112 open: impl FnOnce() -> Result<Option<T>, E>,
113 ) -> Result<Option<SharedFileSnapshot<T>>, E> {
114 let state = get_ref(self);
115 let recent_modification = current_modification_time();
116 let buffer = match (&*state, recent_modification) {
117 (None, None) => (*state).clone(),
118 (Some(_), None) => {
119 drop(state);
120 let mut state = get_mut(self);
121 *state = None;
122 (*state).clone()
123 }
124 (Some(snapshot), Some(modified_time)) => {
125 if snapshot.modified < modified_time {
126 drop(state);
127 let mut state = get_mut(self);
128
129 if let (Some(_snapshot), Some(modified_time)) = (&*state, current_modification_time()) {
130 *state = open()?.map(|value| {
131 OwnShared::new(FileSnapshot {
132 value,
133 modified: modified_time,
134 })
135 });
136 }
137
138 (*state).clone()
139 } else {
140 Some(snapshot.clone())
143 }
144 }
145 (None, Some(_modified_time)) => {
146 drop(state);
147 let mut state = get_mut(self);
148 if let (None, Some(modified_time)) = (&*state, current_modification_time()) {
151 *state = open()?.map(|value| {
152 OwnShared::new(FileSnapshot {
153 value,
154 modified: modified_time,
155 })
156 });
157 }
158 (*state).clone()
159 }
160 };
161 Ok(buffer)
162 }
163}