|
1 | | -use core::mem::ManuallyDrop; |
2 | | - |
3 | 1 | use crate::{DispatchObject, DispatchRetained}; |
4 | 2 |
|
5 | 3 | use crate::{DispatchTime, WaitError}; |
@@ -37,20 +35,54 @@ impl DispatchSemaphore { |
37 | 35 | pub struct DispatchSemaphoreGuard(DispatchRetained<DispatchSemaphore>); |
38 | 36 |
|
39 | 37 | impl DispatchSemaphoreGuard { |
40 | | - /// Release the [`DispatchSemaphore`]. |
41 | | - pub fn release(self) -> bool { |
42 | | - let this = ManuallyDrop::new(self); |
43 | | - |
| 38 | + /// Signal the associated [`DispatchSemaphore`]. |
| 39 | + /// |
| 40 | + /// This is an internal helper, called by wrappers that ensure it is called exactly |
| 41 | + /// once, immediately prior to dropping the guard. |
| 42 | + fn signal(&self) -> bool { |
44 | 43 | // SAFETY: DispatchSemaphore cannot be null. |
45 | | - let result = this.0.signal(); |
| 44 | + self.0.signal() != 0 |
| 45 | + } |
46 | 46 |
|
47 | | - result != 0 |
| 47 | + /// Release the [`DispatchSemaphore`]. |
| 48 | + pub fn release(self) -> bool { |
| 49 | + self.signal() |
48 | 50 | } |
49 | 51 | } |
50 | 52 |
|
51 | 53 | impl Drop for DispatchSemaphoreGuard { |
52 | 54 | fn drop(&mut self) { |
53 | | - // SAFETY: DispatchSemaphore cannot be null. |
54 | | - self.0.signal(); |
| 55 | + self.signal(); |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +#[cfg(test)] |
| 60 | +mod tests { |
| 61 | + use super::*; |
| 62 | + |
| 63 | + #[test] |
| 64 | + #[cfg(feature = "objc2")] |
| 65 | + #[cfg_attr(not(target_vendor = "apple"), ignore = "only Apple's libdisptch is interoperable with `objc2`")] |
| 66 | + fn acquire_release() { |
| 67 | + fn retain_count(semaphore: &DispatchSemaphore) -> usize { |
| 68 | + // SAFETY: semaphore is valid and the method signature is correct. |
| 69 | + unsafe { objc2::msg_send![semaphore, retainCount] } |
| 70 | + } |
| 71 | + |
| 72 | + let semaphore = DispatchSemaphore::new(1); |
| 73 | + |
| 74 | + assert_eq!(retain_count(&semaphore), 1); |
| 75 | + { |
| 76 | + let _guard = semaphore.try_acquire(DispatchTime::NOW).unwrap(); |
| 77 | + assert_eq!(retain_count(&semaphore), 2); |
| 78 | + } |
| 79 | + assert_eq!(retain_count(&semaphore), 1); |
| 80 | + { |
| 81 | + let guard = semaphore.try_acquire(DispatchTime::NOW).unwrap(); |
| 82 | + assert_eq!(retain_count(&semaphore), 2); |
| 83 | + guard.release(); |
| 84 | + assert_eq!(retain_count(&semaphore), 1); |
| 85 | + } |
| 86 | + assert_eq!(retain_count(&semaphore), 1); |
55 | 87 | } |
56 | 88 | } |
0 commit comments