diff --git a/src/spinner.rs b/src/spinner.rs index b3e7651..11a878c 100644 --- a/src/spinner.rs +++ b/src/spinner.rs @@ -1,3 +1,4 @@ +use std::sync::mpsc::RecvTimeoutError; use std::thread::JoinHandle; use std::time::Duration; use std::{iter::Cycle, slice::Iter, sync::mpsc::Receiver, thread}; @@ -5,10 +6,7 @@ use std::{iter::Cycle, slice::Iter, sync::mpsc::Receiver, thread}; use cursive_core::views::TextContent; use cursive_core::CbSink; -use crate::{ - view::{SpinnerControl, ThreadControl}, - Frames, IdlingFrame, MIN_FPS, -}; +use crate::{view::SpinnerControl, Frames, IdlingFrame}; type FrameCycle = Cycle>; @@ -19,7 +17,6 @@ pub(crate) struct Spinner { cb_sink: CbSink, text_content: TextContent, rx_spinner: Receiver, - rx_thread: Receiver, } impl Spinner { @@ -29,47 +26,48 @@ impl Spinner { cb_sink: CbSink, text_content: TextContent, rx_spinner: Receiver, - rx_thread: Receiver, ) -> Self { Self { frames_cycle: Self::cycle_iter(frames), idling_frame, - duration: Duration::from_secs_f32(1.0 / MIN_FPS as f32), + duration: Duration::ZERO, cb_sink, text_content, rx_spinner, - rx_thread, } } pub(crate) fn spin_loop(mut self) -> JoinHandle<()> { - thread::spawn(move || { - while let Ok(thread_control) = self.rx_thread.recv() { - match thread_control { - ThreadControl::Go => 'l: loop { - while let Ok(spinner_control) = self.rx_spinner.try_recv() { - match spinner_control { - SpinnerControl::Frames(frames) => { - self.frames_cycle = Self::cycle_iter(frames) - } - SpinnerControl::Duration(dur) => self.duration = dur, - SpinnerControl::Stop => { - match self.idling_frame { - IdlingFrame::Is(frame) => self.set_frame(frame), - IdlingFrame::Last => {} - } - - break 'l; - } - } + thread::spawn(move || loop { + let spinner_control = if self.duration.is_zero() { + Some(self.rx_spinner.recv().unwrap()) + } else { + match self.rx_spinner.recv_timeout(self.duration) { + Err(RecvTimeoutError::Timeout) => None, + Err(e) => panic!("{:?}", e), + Ok(some_ctrl) => Some(some_ctrl), + } + }; + match spinner_control { + Some(SpinnerControl::Drop) => { + break; + } + Some(SpinnerControl::Frames(frames)) => { + self.frames_cycle = Self::cycle_iter(frames) + } + Some(SpinnerControl::Duration(dur)) => { + self.duration = dur; + if self.duration.is_zero() { + match self.idling_frame { + IdlingFrame::Is(frame) => self.set_frame(frame), + IdlingFrame::Last => {} } - - self.set_next_frame(); - thread::sleep(self.duration); - }, - - ThreadControl::Drop => break, + } } + _ => {} + } + if !self.duration.is_zero() { + self.set_next_frame(); } }) } diff --git a/src/view.rs b/src/view.rs index e643dbb..8a6304a 100644 --- a/src/view.rs +++ b/src/view.rs @@ -4,7 +4,7 @@ use std::{sync::mpsc::Sender, time::Duration}; #[cfg(test)] use std::thread::JoinHandle; -use cursive_core::theme::Style; +use cursive_core::theme::{Style, StyleType}; use cursive_core::views::TextView; use cursive_core::CbSink; use cursive_core::{views::TextContent, Printer, Vec2, View}; @@ -13,15 +13,10 @@ use crate::{ spinner::Spinner, Frames, ACCCEL_FACTOR, DEFAULT_FRAMES, DEFAULT_IDLING_FRAME, MAX_FPS, MIN_FPS, }; -pub(crate) enum ThreadControl { - Go, - Drop, -} - pub(crate) enum SpinnerControl { Frames(Frames), Duration(Duration), - Stop, + Drop, } /// Spinner view @@ -31,7 +26,6 @@ pub struct SpinnerView { speeds: bool, text_view: TextView, tx_spinner: Sender, - tx_thread: Sender, #[cfg(test)] // Used in tests to prove that the spinner @@ -59,7 +53,6 @@ impl SpinnerView { let text_view = TextView::new_with_content(content.clone()).no_wrap(); let (tx_spinner, rx_spinner) = mpsc::channel(); - let (tx_thread, rx_thread) = mpsc::channel(); let spinner = Spinner::new( DEFAULT_FRAMES, @@ -67,7 +60,6 @@ impl SpinnerView { cb_sink.clone(), content, rx_spinner, - rx_thread, ); let _join_handle = spinner.spin_loop(); @@ -77,7 +69,6 @@ impl SpinnerView { speeds: true, //todo? create kinda GearBox instead speeds text_view, tx_spinner, - tx_thread, #[cfg(test)] join_handle: Some(_join_handle), @@ -88,11 +79,6 @@ impl SpinnerView { /// /// You can do it as many times as you need. pub fn spin_up(&mut self) { - if self.spin_ups == 0 { - // Wake up spinner thread - self.tx_thread.send(ThreadControl::Go).unwrap(); - } - self.spin_ups = self.spin_ups.saturating_add(1); self.recalc_duration(); @@ -103,10 +89,6 @@ impl SpinnerView { /// To stop the spinner the numbers of spin-downs /// have to be equal the numbers of spin-ups. pub fn spin_down(&mut self) { - if self.spin_ups == 1 { - self.tx_spinner.send(SpinnerControl::Stop).unwrap(); - } - self.spin_ups = self.spin_ups.saturating_sub(1); self.recalc_duration(); @@ -114,11 +96,8 @@ impl SpinnerView { /// Stop the spinner immediately pub fn stop(&mut self) { - if self.spin_ups != 0 { - self.tx_spinner.send(SpinnerControl::Stop).unwrap(); - } - self.spin_ups = 0; + self.recalc_duration(); } /// The number of spin-ups @@ -141,17 +120,20 @@ impl SpinnerView { } /// Set spinner's style - pub fn style>(&mut self, style: S) -> &mut Self { + pub fn style>(&mut self, style: S) -> &mut Self + where + StyleType: From, + { self.text_view.set_style(style); self } fn recalc_duration(&self) { - self.tx_spinner - .send(SpinnerControl::Duration(Duration::from_secs_f32( - 1.0 / Self::fps(self.spin_ups(), self.speeds) as f32, - ))) - .unwrap(); + let dur = match self.spin_ups() { + 0 => Duration::ZERO, + spin_ups => Duration::from_secs_f32(1.0 / Self::fps(spin_ups, self.speeds) as f32), + }; + self.tx_spinner.send(SpinnerControl::Duration(dur)).unwrap(); } fn fps(spin_ups: usize, speeds: bool) -> usize { @@ -177,8 +159,7 @@ impl SpinnerView { impl Drop for SpinnerView { fn drop(&mut self) { - let _ = self.tx_spinner.send(SpinnerControl::Stop); - let _ = self.tx_thread.send(ThreadControl::Drop); + let _ = self.tx_spinner.send(SpinnerControl::Drop); } } @@ -221,8 +202,8 @@ mod tests { thread::sleep(Duration::from_millis(10)); let handle = spinner.join_handle(); - drop(spinner); + drop(siv); assert!(matches!(handle.join(), Ok(()))); } @@ -239,6 +220,7 @@ mod tests { let handle = spinner.join_handle(); drop(spinner); + drop(siv); assert!(matches!(handle.join(), Ok(()))); }