1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#[cfg(all(feature = "interrupt-handler", not(feature = "disable-interrupts")))]
mod _impl {
use std::{
io,
sync::atomic::{AtomicUsize, Ordering},
};
pub fn init_handler(mut message_channel: impl io::Write + Send + 'static) {
ctrlc::set_handler(move || {
const MESSAGES: &[&str] = &[
"interrupt requested",
"please wait…",
"the program will respond soon…",
"if the program doesn't respond quickly enough, please let us know here: https://github.com/Byron/gitoxide/issues"
];
static CURRENT_MESSAGE: AtomicUsize = AtomicUsize::new(0);
if !super::is_triggered() {
CURRENT_MESSAGE.store(0, Ordering::Relaxed);
}
let msg_idx = CURRENT_MESSAGE.fetch_add(1, Ordering::Relaxed);
super::IS_INTERRUPTED.store(true, Ordering::Relaxed);
writeln!(message_channel, "{}", MESSAGES[msg_idx % MESSAGES.len()]).ok();
})
.expect("it is up to the application to ensure only one interrupt handler is installed, and this function is called only once.")
}
}
use std::io;
#[cfg(not(feature = "disable-interrupts"))]
use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(any(feature = "disable-interrupts", not(feature = "interrupt-handler")))]
mod _impl {
use std::io;
pub fn init_handler(_message_channel: impl io::Write + Send + 'static) {}
}
pub use _impl::init_handler;
pub struct Read<R> {
pub inner: R,
}
impl<R> io::Read for Read<R>
where
R: io::Read,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if is_triggered() {
return Err(io::Error::new(io::ErrorKind::Other, "interrupted by user"));
}
self.inner.read(buf)
}
}
impl<R> io::BufRead for Read<R>
where
R: io::BufRead,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf()
}
fn consume(&mut self, amt: usize) {
self.inner.consume(amt)
}
}
#[cfg(not(feature = "disable-interrupts"))]
static IS_INTERRUPTED: AtomicBool = AtomicBool::new(false);
#[cfg(not(feature = "disable-interrupts"))]
pub fn is_triggered() -> bool {
IS_INTERRUPTED.load(Ordering::Relaxed)
}
#[cfg(feature = "disable-interrupts")]
pub fn is_triggered() -> bool {
false
}
pub fn trigger() {
#[cfg(not(feature = "disable-interrupts"))]
IS_INTERRUPTED.store(true, Ordering::Relaxed);
}
pub fn reset() {
#[cfg(not(feature = "disable-interrupts"))]
IS_INTERRUPTED.store(false, Ordering::Relaxed);
}
pub struct ResetOnDrop {
was_interrupted: bool,
}
impl Default for ResetOnDrop {
fn default() -> Self {
ResetOnDrop {
was_interrupted: is_triggered(),
}
}
}
impl Drop for ResetOnDrop {
fn drop(&mut self) {
if self.was_interrupted {
trigger()
} else {
reset()
}
}
}