1use core::error::Error;
2use core::fmt;
3#[cfg(panic="unwind")]
4use core::sync::atomic::{AtomicBool, Ordering};
5#[cfg(panic="unwind")]
6use panicking::panicking;
7
8pub struct Flag {
9 #[cfg(panic="unwind")]
10 failed: AtomicBool,
11}
12
13impl Flag {
25 pub const fn new() -> Flag {
26 Flag {
27 #[cfg(panic="unwind")]
28 failed: AtomicBool::new(false),
29 }
30 }
31
32 #[allow(unreachable_code)]
33 pub fn borrow(&self) -> LockResult<()> {
34 if self.get() { Err(PoisonError::new(())) } else { Ok(()) }
35 }
36
37 #[allow(unreachable_code)]
38 pub fn guard(&self) -> LockResult<Guard> {
39 let ret = Guard {
40 #[cfg(panic="unwind")]
41 panicking: panicking(),
42 };
43 if self.get() { Err(PoisonError::new(ret)) } else { Ok(ret) }
44 }
45
46 #[cfg(panic="unwind")]
47 pub fn done(&self, guard: &Guard) {
48 if !guard.panicking && panicking() {
49 self.failed.store(true, Ordering::Relaxed);
50 }
51 }
52
53 #[cfg(not(panic="unwind"))]
54 pub fn done(&self, _guard: &Guard) {}
55
56 #[cfg(panic="unwind")]
57 pub fn get(&self) -> bool {
58 self.failed.load(Ordering::Relaxed)
59 }
60
61 #[cfg(not(panic="unwind"))]
62 pub fn get(&self) -> bool {
63 false
64 }
65
66 pub fn clear(&self) {
67 #[cfg(panic="unwind")]
68 self.failed.store(false, Ordering::Relaxed)
69 }
70}
71
72#[derive(Clone)]
73pub struct Guard {
74 #[cfg(panic="unwind")]
75 panicking: bool,
76}
77
78pub struct PoisonError<T> {
79 guard: T,
80 #[cfg(not(panic="unwind"))]
81 _never: !,
82}
83
84pub enum TryLockError<T> {
85 Poisoned(PoisonError<T>),
86 WouldBlock,
87}
88
89pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
90
91pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
92
93impl<T> fmt::Debug for PoisonError<T> {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 f.debug_struct("PoisonError").finish_non_exhaustive()
96 }
97}
98
99impl<T> fmt::Display for PoisonError<T> {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 "poisoned lock: another task failed inside".fmt(f)
102 }
103}
104
105impl<T> Error for PoisonError<T> { }
106
107impl<T> PoisonError<T> {
108 #[cfg(panic="unwind")]
109 pub fn new(guard: T) -> PoisonError<T> {
110 PoisonError { guard }
111 }
112
113 #[cfg(not(panic="unwind"))]
114 pub fn new(_guard: T) -> PoisonError<T> {
115 panic!("PoisonError created in a libstd built with panic=\"abort\"")
116 }
117
118 pub fn into_inner(self) -> T {
119 self.guard
120 }
121
122 pub fn get_ref(&self) -> &T {
123 &self.guard
124 }
125
126 pub fn get_mut(&mut self) -> &mut T {
127 &mut self.guard
128 }
129}
130
131impl<T> From<PoisonError<T>> for TryLockError<T> {
132 fn from(err: PoisonError<T>) -> TryLockError<T> {
133 TryLockError::Poisoned(err)
134 }
135}
136
137impl<T> fmt::Debug for TryLockError<T> {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match *self {
140 #[cfg(panic="unwind")]
141 TryLockError::Poisoned(..) => "Poisoned(..)".fmt(f),
142 #[cfg(not(panic="unwind"))]
143 TryLockError::Poisoned(ref p) => match p._never {},
144 TryLockError::WouldBlock => "WouldBlock".fmt(f),
145 }
146 }
147}
148
149impl<T> fmt::Display for TryLockError<T> {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 match *self {
152 #[cfg(panic="unwind")]
153 TryLockError::Poisoned(..) => "poisoned lock: another task failed inside",
154 #[cfg(not(panic="unwind"))]
155 TryLockError::Poisoned(ref p) => match p._never {},
156 TryLockError::WouldBlock => "try_lock failed because the operation would block",
157 }
158 .fmt(f)
159 }
160}
161
162impl<T> Error for TryLockError<T> { }
163
164pub fn map_result<T, U, F>(result: LockResult<T>, f: F) -> LockResult<U>
165where
166 F: FnOnce(T) -> U,
167{
168 match result {
169 Ok(t) => Ok(f(t)),
170 #[cfg(panic="unwind")]
171 Err(PoisonError { guard }) => Err(PoisonError::new(f(guard))),
172 }
173}