Skip to content

Commit 40e03ba

Browse files
author
Stephan Dilly
committed
allow async jobs to set intermediate progress
1 parent 0454e2a commit 40e03ba

File tree

6 files changed

+79
-32
lines changed

6 files changed

+79
-32
lines changed

asyncgit/src/asyncjob/mod.rs

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,54 @@
44

55
use crate::error::Result;
66
use crossbeam_channel::Sender;
7-
use std::sync::{Arc, Mutex};
7+
use std::sync::{Arc, Mutex, RwLock};
8+
9+
/// Passed to `AsyncJob::run` allowing sending intermediate progress notifications
10+
pub struct RunParams<T: Copy + Send, P: Clone + Send + Sync> {
11+
sender: Sender<T>,
12+
progress: Arc<RwLock<P>>,
13+
}
14+
15+
impl<T: Copy + Send, P: Clone + Send + Sync> RunParams<T, P> {
16+
/// send an intermediate update notification.
17+
/// do not confuse this with the return value of `run`.
18+
/// `send` should only be used about progress notifications
19+
/// and not for the final notifcation indicating the end of the async job.
20+
/// see `run` for more info
21+
pub fn send(&self, notification: T) -> Result<()> {
22+
self.sender.send(notification)?;
23+
Ok(())
24+
}
25+
26+
/// set the current progress
27+
pub fn set_progress(&self, p: P) -> Result<()> {
28+
*(self.progress.write()?) = p;
29+
Ok(())
30+
}
31+
}
832

933
/// trait that defines an async task we can run on a threadpool
1034
pub trait AsyncJob: Send + Sync + Clone {
11-
/// defines what notification to send after finish running job
12-
type Notification: Copy + Send + 'static;
13-
14-
/// can run a synchronous time intensive task
35+
/// defines what notification type is used to communicate outside
36+
type Notification: Copy + Send;
37+
/// type of progress
38+
type Progress: Clone + Default + Send + Sync;
39+
40+
/// can run a synchronous time intensive task.
41+
/// the returned notification is used to tell interested parties
42+
/// that the job finished and the job can be access via `take_last`.
43+
/// prior to this final notification it is not safe to assume `take_last`
44+
/// will already return the correct job
1545
fn run(
1646
&mut self,
17-
sender: Sender<Self::Notification>,
47+
params: RunParams<Self::Notification, Self::Progress>,
1848
) -> Result<Self::Notification>;
49+
50+
/// allows observers to get intermediate progress status if the job customizes it
51+
/// by default this will be returning ()::Default
52+
fn get_progress(&self) -> Self::Progress {
53+
Self::Progress::default()
54+
}
1955
}
2056

2157
/// Abstraction for a FIFO task queue that will only queue up **one** `next` job.
@@ -24,6 +60,7 @@ pub trait AsyncJob: Send + Sync + Clone {
2460
pub struct AsyncSingleJob<J: AsyncJob> {
2561
next: Arc<Mutex<Option<J>>>,
2662
last: Arc<Mutex<Option<J>>>,
63+
progress: Arc<RwLock<J::Progress>>,
2764
sender: Sender<J::Notification>,
2865
pending: Arc<Mutex<()>>,
2966
}
@@ -35,6 +72,7 @@ impl<J: 'static + AsyncJob> AsyncSingleJob<J> {
3572
next: Arc::new(Mutex::new(None)),
3673
last: Arc::new(Mutex::new(None)),
3774
pending: Arc::new(Mutex::new(())),
75+
progress: Arc::new(RwLock::new(J::Progress::default())),
3876
sender,
3977
}
4078
}
@@ -73,16 +111,20 @@ impl<J: 'static + AsyncJob> AsyncSingleJob<J> {
73111
self.check_for_job()
74112
}
75113

114+
///
115+
pub fn progress(&self) -> Option<J::Progress> {
116+
self.progress.read().ok().map(|d| (*d).clone())
117+
}
118+
76119
fn check_for_job(&self) -> bool {
77120
if self.is_pending() {
78121
return false;
79122
}
80123

81124
if let Some(task) = self.take_next() {
82-
let self_arc = self.clone();
83-
125+
let self_clone = (*self).clone();
84126
rayon_core::spawn(move || {
85-
if let Err(e) = self_arc.run_job(task) {
127+
if let Err(e) = self_clone.run_job(task) {
86128
log::error!("async job error: {}", e);
87129
}
88130
});
@@ -98,7 +140,10 @@ impl<J: 'static + AsyncJob> AsyncSingleJob<J> {
98140
{
99141
let _pending = self.pending.lock()?;
100142

101-
let notification = task.run(self.sender.clone())?;
143+
let notification = task.run(RunParams {
144+
progress: self.progress.clone(),
145+
sender: self.sender.clone(),
146+
})?;
102147

103148
if let Ok(mut last) = self.last.lock() {
104149
*last = Some(task);
@@ -149,10 +194,11 @@ mod test {
149194

150195
impl AsyncJob for TestJob {
151196
type Notification = TestNotificaton;
197+
type Progress = ();
152198

153199
fn run(
154200
&mut self,
155-
_sender: Sender<Self::Notification>,
201+
_params: RunParams<Self::Notification, Self::Progress>,
156202
) -> Result<Self::Notification> {
157203
println!("[job] wait");
158204

asyncgit/src/progress.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use easy_cast::{Conv, ConvFloat};
44
use std::cmp;
55

66
///
7-
#[derive(Clone, Copy, Debug, PartialEq)]
7+
#[derive(Clone, Copy, Default, Debug, PartialEq)]
88
pub struct ProgressPercent {
99
/// percent 0..100
1010
pub progress: u8,

asyncgit/src/remote_tags.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
//!
22
3-
use crossbeam_channel::Sender;
4-
53
use crate::{
6-
asyncjob::AsyncJob,
4+
asyncjob::{AsyncJob, RunParams},
75
error::Result,
86
sync::cred::BasicAuthCredential,
97
sync::remotes::{get_default_remote, tags_missing_remote},
@@ -53,10 +51,11 @@ impl AsyncRemoteTagsJob {
5351

5452
impl AsyncJob for AsyncRemoteTagsJob {
5553
type Notification = AsyncGitNotification;
54+
type Progress = ();
5655

5756
fn run(
5857
&mut self,
59-
_sender: Sender<Self::Notification>,
58+
_params: RunParams<Self::Notification, Self::Progress>,
6059
) -> Result<Self::Notification> {
6160
if let Ok(mut state) = self.state.lock() {
6261
*state = state.take().map(|state| match state {

src/components/syntax_text.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ impl SyntaxTextComponent {
6565
) = ev
6666
{
6767
match progress {
68-
SyntaxHighlightProgress::Progress(progress) => {
69-
self.syntax_progress = Some(progress);
68+
SyntaxHighlightProgress::Progress => {
69+
self.syntax_progress =
70+
self.async_highlighting.progress();
7071
}
7172
SyntaxHighlightProgress::Done => {
7273
self.syntax_progress = None;

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub enum QueueEvent {
7878

7979
#[derive(Clone, Copy, Debug, PartialEq)]
8080
pub enum SyntaxHighlightProgress {
81-
Progress(asyncgit::ProgressPercent),
81+
Progress,
8282
Done,
8383
}
8484

src/ui/syntax_text.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
use asyncgit::{asyncjob::AsyncJob, ProgressPercent};
2-
use crossbeam_channel::Sender;
1+
use asyncgit::{
2+
asyncjob::{AsyncJob, RunParams},
3+
ProgressPercent,
4+
};
35
use lazy_static::lazy_static;
46
use scopetime::scope_time;
57
use std::{
@@ -70,7 +72,7 @@ impl SyntaxText {
7072
pub fn new(
7173
text: String,
7274
file_path: &Path,
73-
sender: &Sender<AsyncAppNotification>,
75+
params: &RunParams<AsyncAppNotification, ProgressPercent>,
7476
) -> asyncgit::Result<Self> {
7577
scope_time!("syntax_highlighting");
7678
log::debug!("syntax: {:?}", file_path);
@@ -110,10 +112,9 @@ impl SyntaxText {
110112
total_count,
111113
Duration::from_millis(200),
112114
);
113-
sender.send(AsyncAppNotification::SyntaxHighlighting(
114-
SyntaxHighlightProgress::Progress(
115-
buffer.send_progress(),
116-
),
115+
params.set_progress(buffer.send_progress())?;
116+
params.send(AsyncAppNotification::SyntaxHighlighting(
117+
SyntaxHighlightProgress::Progress,
117118
))?;
118119

119120
for (number, line) in text.lines().enumerate() {
@@ -134,11 +135,10 @@ impl SyntaxText {
134135
});
135136

136137
if buffer.update(number) {
137-
sender.send(
138+
params.set_progress(buffer.send_progress())?;
139+
params.send(
138140
AsyncAppNotification::SyntaxHighlighting(
139-
SyntaxHighlightProgress::Progress(
140-
buffer.send_progress(),
141-
),
141+
SyntaxHighlightProgress::Progress,
142142
),
143143
)?;
144144
}
@@ -241,10 +241,11 @@ impl AsyncSyntaxJob {
241241

242242
impl AsyncJob for AsyncSyntaxJob {
243243
type Notification = AsyncAppNotification;
244+
type Progress = ProgressPercent;
244245

245246
fn run(
246247
&mut self,
247-
sender: Sender<Self::Notification>,
248+
params: RunParams<Self::Notification, Self::Progress>,
248249
) -> asyncgit::Result<Self::Notification> {
249250
let mut state_mutex = self.state.lock()?;
250251

@@ -254,7 +255,7 @@ impl AsyncJob for AsyncSyntaxJob {
254255
let syntax = SyntaxText::new(
255256
content,
256257
Path::new(&path),
257-
&sender,
258+
&params,
258259
)?;
259260
JobState::Response(syntax)
260261
}

0 commit comments

Comments
 (0)