allow async job to return dynamic notification

This commit is contained in:
Stephan Dilly 2021-09-02 11:36:46 +02:00
parent e5688e3b8b
commit b9e4631ff4
8 changed files with 45 additions and 40 deletions

View file

@ -8,31 +8,30 @@ use std::sync::{Arc, Mutex};
/// trait that defines an async task we can run on a threadpool /// trait that defines an async task we can run on a threadpool
pub trait AsyncJob: Send + Sync + Clone { pub trait AsyncJob: Send + Sync + Clone {
/// defines what notification to send after finish running job
type Notification: Copy + Send + 'static;
/// can run a synchronous time intensive task /// can run a synchronous time intensive task
fn run(&mut self); fn run(&mut self) -> Self::Notification;
} }
/// Abstraction for a FIFO task queue that will only queue up **one** `next` job. /// Abstraction for a FIFO task queue that will only queue up **one** `next` job.
/// It keeps overwriting the next job until it is actually taken to be processed /// It keeps overwriting the next job until it is actually taken to be processed
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AsyncSingleJob<J: AsyncJob, T: Copy + Send + 'static> { pub struct AsyncSingleJob<J: AsyncJob> {
next: Arc<Mutex<Option<J>>>, next: Arc<Mutex<Option<J>>>,
last: Arc<Mutex<Option<J>>>, last: Arc<Mutex<Option<J>>>,
sender: Sender<T>, sender: Sender<J::Notification>,
pending: Arc<Mutex<()>>, pending: Arc<Mutex<()>>,
notification: T,
} }
impl<J: 'static + AsyncJob, T: Copy + Send + 'static> impl<J: 'static + AsyncJob> AsyncSingleJob<J> {
AsyncSingleJob<J, T>
{
/// ///
pub fn new(sender: Sender<T>, value: T) -> Self { pub fn new(sender: Sender<J::Notification>) -> Self {
Self { Self {
next: Arc::new(Mutex::new(None)), next: Arc::new(Mutex::new(None)),
last: Arc::new(Mutex::new(None)), last: Arc::new(Mutex::new(None)),
pending: Arc::new(Mutex::new(())), pending: Arc::new(Mutex::new(())),
notification: value,
sender, sender,
} }
} }
@ -96,13 +95,13 @@ impl<J: 'static + AsyncJob, T: Copy + Send + 'static>
{ {
let _pending = self.pending.lock()?; let _pending = self.pending.lock()?;
task.run(); let notification = task.run();
if let Ok(mut last) = self.last.lock() { if let Ok(mut last) = self.last.lock() {
*last = Some(task); *last = Some(task);
} }
self.sender.send(self.notification)?; self.sender.send(notification)?;
} }
self.check_for_job(); self.check_for_job();
@ -143,8 +142,12 @@ mod test {
value_to_add: u32, value_to_add: u32,
} }
type TestNotificaton = ();
impl AsyncJob for TestJob { impl AsyncJob for TestJob {
fn run(&mut self) { type Notification = TestNotificaton;
fn run(&mut self) -> Self::Notification {
println!("[job] wait"); println!("[job] wait");
while !self.finish.load(Ordering::SeqCst) { while !self.finish.load(Ordering::SeqCst) {
@ -161,17 +164,17 @@ mod test {
self.v.fetch_add(self.value_to_add, Ordering::SeqCst); self.v.fetch_add(self.value_to_add, Ordering::SeqCst);
println!("[job] value: {}", res); println!("[job] value: {}", res);
()
} }
} }
type Notificaton = ();
#[test] #[test]
fn test_overwrite() { fn test_overwrite() {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
let mut job: AsyncSingleJob<TestJob, Notificaton> = let mut job: AsyncSingleJob<TestJob> =
AsyncSingleJob::new(sender, ()); AsyncSingleJob::new(sender);
let task = TestJob { let task = TestJob {
v: Arc::new(AtomicU32::new(1)), v: Arc::new(AtomicU32::new(1)),
@ -199,7 +202,7 @@ mod test {
); );
} }
fn wait_for_job(job: &AsyncSingleJob<TestJob, Notificaton>) { fn wait_for_job(job: &AsyncSingleJob<TestJob>) {
while job.is_pending() { while job.is_pending() {
thread::sleep(Duration::from_millis(10)); thread::sleep(Duration::from_millis(10));
} }
@ -209,8 +212,8 @@ mod test {
fn test_cancel() { fn test_cancel() {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
let mut job: AsyncSingleJob<TestJob, Notificaton> = let mut job: AsyncSingleJob<TestJob> =
AsyncSingleJob::new(sender, ()); AsyncSingleJob::new(sender);
let task = TestJob { let task = TestJob {
v: Arc::new(AtomicU32::new(1)), v: Arc::new(AtomicU32::new(1)),

View file

@ -83,6 +83,8 @@ pub enum AsyncGitNotification {
Fetch, Fetch,
/// ///
Blame, Blame,
///
RemoteTags,
} }
/// current working directory `./` /// current working directory `./`

View file

@ -5,7 +5,7 @@ use crate::{
error::Result, error::Result,
sync::cred::BasicAuthCredential, sync::cred::BasicAuthCredential,
sync::remotes::{get_default_remote, tags_missing_remote}, sync::remotes::{get_default_remote, tags_missing_remote},
CWD, AsyncGitNotification, CWD,
}; };
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -50,7 +50,9 @@ impl AsyncRemoteTagsJob {
} }
impl AsyncJob for AsyncRemoteTagsJob { impl AsyncJob for AsyncRemoteTagsJob {
fn run(&mut self) { type Notification = AsyncGitNotification;
fn run(&mut self) -> Self::Notification {
if let Ok(mut state) = self.state.lock() { if let Ok(mut state) = self.state.lock() {
*state = state.take().map(|state| match state { *state = state.take().map(|state| match state {
JobState::Request(basic_credential) => { JobState::Request(basic_credential) => {
@ -70,5 +72,7 @@ impl AsyncJob for AsyncRemoteTagsJob {
} }
}); });
} }
AsyncGitNotification::RemoteTags
} }
} }

View file

@ -179,7 +179,7 @@ impl App {
), ),
tags_popup: TagListComponent::new( tags_popup: TagListComponent::new(
&queue, &queue,
sender_app, sender,
theme.clone(), theme.clone(),
key_config.clone(), key_config.clone(),
), ),

View file

@ -32,8 +32,7 @@ use tui::{
pub struct SyntaxTextComponent { pub struct SyntaxTextComponent {
current_file: Option<(String, Either<ui::SyntaxText, String>)>, current_file: Option<(String, Either<ui::SyntaxText, String>)>,
async_highlighting: async_highlighting: AsyncSingleJob<AsyncSyntaxJob>,
AsyncSingleJob<AsyncSyntaxJob, AsyncAppNotification>,
key_config: SharedKeyConfig, key_config: SharedKeyConfig,
paragraph_state: Cell<ParagraphState>, paragraph_state: Cell<ParagraphState>,
focused: bool, focused: bool,
@ -48,10 +47,7 @@ impl SyntaxTextComponent {
theme: SharedTheme, theme: SharedTheme,
) -> Self { ) -> Self {
Self { Self {
async_highlighting: AsyncSingleJob::new( async_highlighting: AsyncSingleJob::new(sender.clone()),
sender.clone(),
AsyncAppNotification::SyntaxHighlighting,
),
current_file: None, current_file: None,
paragraph_state: Cell::new(ParagraphState::default()), paragraph_state: Cell::new(ParagraphState::default()),
focused: false, focused: false,

View file

@ -8,7 +8,7 @@ use crate::{
queue::{Action, InternalEvent, Queue}, queue::{Action, InternalEvent, Queue},
strings, strings,
ui::{self, Size}, ui::{self, Size},
AsyncAppNotification, AsyncNotification, AsyncNotification,
}; };
use anyhow::Result; use anyhow::Result;
use asyncgit::{ use asyncgit::{
@ -46,8 +46,7 @@ pub struct TagListComponent {
current_height: std::cell::Cell<usize>, current_height: std::cell::Cell<usize>,
missing_remote_tags: Option<Vec<String>>, missing_remote_tags: Option<Vec<String>>,
basic_credential: Option<BasicAuthCredential>, basic_credential: Option<BasicAuthCredential>,
async_remote_tags: async_remote_tags: AsyncSingleJob<AsyncRemoteTagsJob>,
AsyncSingleJob<AsyncRemoteTagsJob, AsyncAppNotification>,
key_config: SharedKeyConfig, key_config: SharedKeyConfig,
} }
@ -251,7 +250,7 @@ impl Component for TagListComponent {
impl TagListComponent { impl TagListComponent {
pub fn new( pub fn new(
queue: &Queue, queue: &Queue,
sender: &Sender<AsyncAppNotification>, sender: &Sender<AsyncGitNotification>,
theme: SharedTheme, theme: SharedTheme,
key_config: SharedKeyConfig, key_config: SharedKeyConfig,
) -> Self { ) -> Self {
@ -264,10 +263,7 @@ impl TagListComponent {
current_height: std::cell::Cell::new(0), current_height: std::cell::Cell::new(0),
basic_credential: None, basic_credential: None,
missing_remote_tags: None, missing_remote_tags: None,
async_remote_tags: AsyncSingleJob::new( async_remote_tags: AsyncSingleJob::new(sender.clone()),
sender.clone(),
AsyncAppNotification::RemoteTags,
),
key_config, key_config,
} }
} }
@ -301,7 +297,7 @@ impl TagListComponent {
pub fn update(&mut self, ev: AsyncNotification) { pub fn update(&mut self, ev: AsyncNotification) {
if matches!( if matches!(
ev, ev,
AsyncNotification::App(AsyncAppNotification::RemoteTags) AsyncNotification::Git(AsyncGitNotification::RemoteTags)
) { ) {
if let Some(job) = self.async_remote_tags.take_last() { if let Some(job) = self.async_remote_tags.take_last() {
if let Some(Ok(missing_remote_tags)) = job.result() { if let Some(Ok(missing_remote_tags)) = job.result() {

View file

@ -80,8 +80,6 @@ pub enum QueueEvent {
pub enum AsyncAppNotification { pub enum AsyncAppNotification {
/// ///
SyntaxHighlighting, SyntaxHighlighting,
///
RemoteTags,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]

View file

@ -16,6 +16,8 @@ use syntect::{
}; };
use tui::text::{Span, Spans}; use tui::text::{Span, Spans};
use crate::AsyncAppNotification;
struct SyntaxLine { struct SyntaxLine {
items: Vec<(Style, usize, Range<usize>)>, items: Vec<(Style, usize, Range<usize>)>,
} }
@ -175,7 +177,9 @@ impl AsyncSyntaxJob {
} }
impl AsyncJob for AsyncSyntaxJob { impl AsyncJob for AsyncSyntaxJob {
fn run(&mut self) { type Notification = AsyncAppNotification;
fn run(&mut self) -> Self::Notification {
if let Ok(mut state) = self.state.lock() { if let Ok(mut state) = self.state.lock() {
*state = state.take().map(|state| match state { *state = state.take().map(|state| match state {
JobState::Request((content, path)) => { JobState::Request((content, path)) => {
@ -186,5 +190,7 @@ impl AsyncJob for AsyncSyntaxJob {
JobState::Response(res) => JobState::Response(res), JobState::Response(res) => JobState::Response(res),
}); });
} }
AsyncAppNotification::SyntaxHighlighting
} }
} }