Skip to content

Commit

Permalink
Merge pull request #2 from c-jiph/fixes
Browse files Browse the repository at this point in the history
Fix a panic on spinner thread shutdown and a compile error
  • Loading branch information
otov4its authored Sep 14, 2023
2 parents 282a90e + 7fcbbf8 commit 710e4ef
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 66 deletions.
64 changes: 31 additions & 33 deletions src/spinner.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use std::sync::mpsc::RecvTimeoutError;
use std::thread::JoinHandle;
use std::time::Duration;
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<Iter<'static, &'static str>>;

Expand All @@ -19,7 +17,6 @@ pub(crate) struct Spinner {
cb_sink: CbSink,
text_content: TextContent,
rx_spinner: Receiver<SpinnerControl>,
rx_thread: Receiver<ThreadControl>,
}

impl Spinner {
Expand All @@ -29,47 +26,48 @@ impl Spinner {
cb_sink: CbSink,
text_content: TextContent,
rx_spinner: Receiver<SpinnerControl>,
rx_thread: Receiver<ThreadControl>,
) -> 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();
}
})
}
Expand Down
48 changes: 15 additions & 33 deletions src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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
Expand All @@ -31,7 +26,6 @@ pub struct SpinnerView {
speeds: bool,
text_view: TextView,
tx_spinner: Sender<SpinnerControl>,
tx_thread: Sender<ThreadControl>,

#[cfg(test)]
// Used in tests to prove that the spinner
Expand Down Expand Up @@ -59,15 +53,13 @@ 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,
DEFAULT_IDLING_FRAME,
cb_sink.clone(),
content,
rx_spinner,
rx_thread,
);

let _join_handle = spinner.spin_loop();
Expand All @@ -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),
Expand All @@ -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();
Expand All @@ -103,22 +89,15 @@ 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();
}

/// 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
Expand All @@ -141,17 +120,20 @@ impl SpinnerView {
}

/// Set spinner's style
pub fn style<S: Into<Style>>(&mut self, style: S) -> &mut Self {
pub fn style<S: Into<Style>>(&mut self, style: S) -> &mut Self
where
StyleType: From<S>,
{
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 {
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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(())));
}
Expand All @@ -239,6 +220,7 @@ mod tests {
let handle = spinner.join_handle();

drop(spinner);
drop(siv);

assert!(matches!(handle.join(), Ok(())));
}
Expand Down

0 comments on commit 710e4ef

Please sign in to comment.