gnostr_asyncgit/
commit_files.rs1use std::sync::{
2 atomic::{AtomicUsize, Ordering},
3 Arc, Mutex,
4};
5
6use crossbeam_channel::Sender;
7
8use crate::{
9 error::Result,
10 sync::{self, commit_files::OldNew, CommitId, RepoPath},
11 AsyncGitNotification, StatusItem,
12};
13
14type ResultType = Vec<StatusItem>;
15struct Request<R, A>(R, A);
16
17#[derive(Debug, Copy, Clone, PartialEq, Eq)]
19pub struct CommitFilesParams {
20 pub id: CommitId,
22 pub other: Option<CommitId>,
24}
25
26impl From<CommitId> for CommitFilesParams {
27 fn from(id: CommitId) -> Self {
28 Self { id, other: None }
29 }
30}
31
32impl From<(CommitId, CommitId)> for CommitFilesParams {
33 fn from((id, other): (CommitId, CommitId)) -> Self {
34 Self {
35 id,
36 other: Some(other),
37 }
38 }
39}
40
41impl From<OldNew<CommitId>> for CommitFilesParams {
42 fn from(old_new: OldNew<CommitId>) -> Self {
43 Self {
44 id: old_new.new,
45 other: Some(old_new.old),
46 }
47 }
48}
49
50pub struct AsyncCommitFiles {
52 current: Arc<Mutex<Option<Request<CommitFilesParams, ResultType>>>>,
53 sender: Sender<AsyncGitNotification>,
54 pending: Arc<AtomicUsize>,
55 repo: RepoPath,
56}
57
58impl AsyncCommitFiles {
59 pub fn new(repo: RepoPath, sender: &Sender<AsyncGitNotification>) -> Self {
61 Self {
62 repo,
63 current: Arc::new(Mutex::new(None)),
64 sender: sender.clone(),
65 pending: Arc::new(AtomicUsize::new(0)),
66 }
67 }
68
69 pub fn current(&mut self) -> Result<Option<(CommitFilesParams, ResultType)>> {
71 let c = self.current.lock()?;
72
73 c.as_ref()
74 .map_or(Ok(None), |c| Ok(Some((c.0, c.1.clone()))))
75 }
76
77 pub fn is_pending(&self) -> bool {
79 self.pending.load(Ordering::Relaxed) > 0
80 }
81
82 pub fn fetch(&mut self, params: CommitFilesParams) -> Result<()> {
84 if self.is_pending() {
85 return Ok(());
86 }
87
88 log::trace!("request: {:?}", params);
89
90 {
91 let current = self.current.lock()?;
92 if let Some(c) = &*current {
93 if c.0 == params {
94 return Ok(());
95 }
96 }
97 }
98
99 let arc_current = Arc::clone(&self.current);
100 let sender = self.sender.clone();
101 let arc_pending = Arc::clone(&self.pending);
102 let repo = self.repo.clone();
103
104 self.pending.fetch_add(1, Ordering::Relaxed);
105
106 rayon_core::spawn(move || {
107 Self::fetch_helper(&repo, params, &arc_current).expect("failed to fetch");
108
109 arc_pending.fetch_sub(1, Ordering::Relaxed);
110
111 sender
112 .send(AsyncGitNotification::CommitFiles)
113 .expect("error sending");
114 });
115
116 Ok(())
117 }
118
119 fn fetch_helper(
120 repo_path: &RepoPath,
121 params: CommitFilesParams,
122 arc_current: &Arc<Mutex<Option<Request<CommitFilesParams, ResultType>>>>,
123 ) -> Result<()> {
124 let res = sync::get_commit_files(repo_path, params.id, params.other)?;
125
126 log::trace!("get_commit_files: {:?} ({})", params, res.len());
127
128 {
129 let mut current = arc_current.lock()?;
130 *current = Some(Request(params, res));
131 }
132
133 Ok(())
134 }
135}