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