1#![allow(dead_code)]
29
30use core::hash::Hasher;
34
35use std::hash::Hash;
36use std::ops::Deref;
37use std::sync::atomic::{AtomicUsize, Ordering, fence};
38use std::sync::{Arc, Weak};
39
40pub trait Releasable {
43 type Context<'a>;
44
45 fn release<'a>(self: Self, c: Self::Context<'a>);
48}
49
50impl<T: Releasable> Releasable for Option<T> {
52 type Context<'a> = T::Context<'a>;
53
54 fn release<'a>(self: Self, c: Self::Context<'a>) {
55 if let Some(v) = self {
56 v.release(c);
57 }
58 }
59}
60
61impl<T: Releasable> Releasable for Vec<T>
63where
64 for<'a> T::Context<'a>: Clone,
65{
66 type Context<'a> = T::Context<'a>;
67
68 fn release<'a>(self: Self, c: Self::Context<'a>) {
69 for v in self {
70 v.release(c.clone());
71 }
72 }
73}
74
75impl<T: Releasable, E> Releasable for Result<T, E> {
77 type Context<'a> = T::Context<'a>;
78
79 fn release<'a>(self: Self, c: Self::Context<'a>) {
80 if let Ok(v) = self {
81 v.release(c);
82 }
83 }
84}
85
86impl<T: Releasable> Releasable for ReleaseGuard<T> {
87 type Context<'a> = T::Context<'a>;
88
89 fn release<'a>(self: Self, c: Self::Context<'a>) {
90 self.drop_guard.disarm();
91 self.value.release(c);
92 }
93}
94
95pub trait Share {
98 fn share(&self) -> Self;
99}
100
101impl<T: Share> Share for Option<T> {
102 fn share(&self) -> Self {
103 match self {
104 None => None,
105 Some(t) => Some(t.share()),
106 }
107 }
108}
109
110#[must_use = "OwnedRef must be released"]
114pub struct OwnedRef<T> {
115 inner: Option<Arc<RefInner<T>>>,
117
118 drop_guard: DropGuard,
120}
121
122impl<T> OwnedRef<T> {
123 pub fn new(value: T) -> Self {
124 Self { inner: Some(Arc::new(RefInner::new(value))), drop_guard: Default::default() }
125 }
126
127 pub fn new_cyclic<F>(data_fn: F) -> Self
128 where
129 F: FnOnce(WeakRef<T>) -> T,
130 {
131 let inner = Arc::new_cyclic(|weak_inner| {
132 let weak = WeakRef(weak_inner.clone());
133 RefInner::new(data_fn(weak))
134 });
135 Self { inner: Some(inner), drop_guard: Default::default() }
136 }
137
138 pub fn as_ptr(this: &Self) -> *const T {
142 &Self::inner(this).value.value as *const T
143 }
144
145 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
147 Self::as_ptr(this) == Self::as_ptr(other)
148 }
149
150 pub fn downgrade(this: &Self) -> WeakRef<T> {
152 WeakRef(Arc::downgrade(Self::inner(this)))
153 }
154
155 pub fn temp(this: &Self) -> TempRef<'_, T> {
158 TempRef::new(Arc::clone(Self::inner(this)))
159 }
160
161 fn inner(this: &Self) -> &Arc<RefInner<T>> {
162 this.inner.as_ref().unwrap_or_else(|| {
163 panic!("OwnedRef<{}> has been released.", std::any::type_name::<T>())
164 })
165 }
166
167 fn re_own(inner: Arc<RefInner<T>>) -> Option<Self> {
168 let mut owned_refs = inner.owned_refs_count.load(Ordering::Relaxed);
169 loop {
170 if owned_refs == 0 {
171 return None;
172 }
173 match inner.owned_refs_count.compare_exchange(
174 owned_refs,
175 owned_refs + 1,
176 Ordering::Acquire,
177 Ordering::Relaxed,
178 ) {
179 Ok(_) => {
180 return Some(Self { inner: Some(inner), drop_guard: Default::default() });
181 }
182 Err(v) => {
183 owned_refs = v;
184 }
185 }
186 }
187 }
188}
189
190impl<T: Releasable> OwnedRef<T> {
191 pub fn take(this: &mut Self) -> Option<ReleaseGuard<T>> {
194 this.drop_guard.disarm();
195 let inner = this.inner.take().unwrap_or_else(|| {
196 panic!("OwnedRef<{}> has been released.", std::any::type_name::<T>())
197 });
198 let previous_count = inner.owned_refs_count.fetch_sub(1, Ordering::Release);
199 if previous_count == 1 {
200 fence(Ordering::Acquire);
201 Some(Self::wait_and_take_value(inner))
202 } else {
203 None
204 }
205 }
206
207 fn wait_and_take_value(mut inner: Arc<RefInner<T>>) -> ReleaseGuard<T> {
211 loop {
212 debug_assert_eq!(inner.owned_refs_count.load(Ordering::Acquire), 0);
214 match Arc::try_unwrap(inner) {
215 Ok(value) => return value.value,
216 Err(value) => inner = value,
217 }
218 inner.wait_for_no_ref_once();
219 }
220 }
221}
222
223impl<T: std::fmt::Debug> std::fmt::Debug for OwnedRef<T> {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 Self::inner(self).value.fmt(f)
226 }
227}
228
229impl<T: Releasable> Share for OwnedRef<T> {
230 fn share(&self) -> Self {
232 let inner = Self::inner(self);
233 let previous_count = inner.owned_refs_count.fetch_add(1, Ordering::Relaxed);
234 debug_assert!(previous_count > 0, "OwnedRef should not be used after being released.");
235 Self { inner: Some(Arc::clone(inner)), drop_guard: Default::default() }
236 }
237}
238
239impl<T: Releasable> Releasable for OwnedRef<T> {
240 type Context<'a> = T::Context<'a>;
241
242 #[allow(unused_mut)]
245 fn release<'a>(mut self, c: Self::Context<'a>) {
246 OwnedRef::take(&mut self).release(c);
247 }
248}
249
250impl<T: Default> Default for OwnedRef<T> {
251 fn default() -> Self {
252 Self::new(T::default())
253 }
254}
255
256impl<T> std::ops::Deref for OwnedRef<T> {
257 type Target = T;
258
259 fn deref(&self) -> &Self::Target {
260 &Self::inner(self).deref().value
261 }
262}
263
264impl<T> std::borrow::Borrow<T> for OwnedRef<T> {
265 fn borrow(&self) -> &T {
266 self.deref()
267 }
268}
269
270impl<T> std::convert::AsRef<T> for OwnedRef<T> {
271 fn as_ref(&self) -> &T {
272 self.deref()
273 }
274}
275
276impl<T: PartialEq> PartialEq<TempRef<'_, T>> for OwnedRef<T> {
277 fn eq(&self, other: &TempRef<'_, T>) -> bool {
278 Arc::ptr_eq(Self::inner(self), &other.0)
279 }
280}
281
282impl<T: PartialEq> PartialEq for OwnedRef<T> {
283 fn eq(&self, other: &OwnedRef<T>) -> bool {
284 Arc::ptr_eq(Self::inner(self), Self::inner(other)) || **self == **other
285 }
286}
287
288impl<T: Eq> Eq for OwnedRef<T> {}
289
290impl<T: PartialOrd> PartialOrd for OwnedRef<T> {
291 fn partial_cmp(&self, other: &OwnedRef<T>) -> Option<std::cmp::Ordering> {
292 (**self).partial_cmp(&**other)
293 }
294}
295
296impl<T: Ord> Ord for OwnedRef<T> {
297 fn cmp(&self, other: &OwnedRef<T>) -> std::cmp::Ordering {
298 (**self).cmp(&**other)
299 }
300}
301
302impl<T: Hash> Hash for OwnedRef<T> {
303 fn hash<H: Hasher>(&self, state: &mut H) {
304 (**self).hash(state)
305 }
306}
307
308impl<T> From<&OwnedRef<T>> for WeakRef<T> {
309 fn from(owner: &OwnedRef<T>) -> Self {
310 OwnedRef::downgrade(owner)
311 }
312}
313
314impl<'a, T> From<&'a OwnedRef<T>> for TempRef<'a, T> {
315 fn from(owner: &'a OwnedRef<T>) -> Self {
316 OwnedRef::temp(owner)
317 }
318}
319
320impl<'a, T> From<&'a mut OwnedRef<T>> for TempRef<'a, T> {
321 fn from(owner: &'a mut OwnedRef<T>) -> Self {
322 OwnedRef::temp(owner)
323 }
324}
325
326#[derive(Debug)]
329pub struct WeakRef<T>(Weak<RefInner<T>>);
330
331impl<T> WeakRef<T> {
332 pub fn new() -> Self {
333 Self(Weak::new())
334 }
335
336 pub fn upgrade(&self) -> Option<TempRef<'_, T>> {
341 if let Some(value) = self.0.upgrade() {
342 let temp_ref = TempRef::new(value);
345 if temp_ref.0.owned_refs_count.load(Ordering::Acquire) > 0 {
348 return Some(temp_ref);
349 }
350 }
351 None
352 }
353
354 pub fn re_own(&self) -> Option<OwnedRef<T>> {
357 self.0.upgrade().and_then(OwnedRef::re_own)
358 }
359
360 pub fn as_ptr(&self) -> *const T {
365 if Weak::ptr_eq(&self.0, &Weak::new()) {
366 return std::ptr::null();
367 }
368 let base = self.0.as_ptr();
369 let value = memoffset::raw_field!(base, RefInner<T>, value);
370 memoffset::raw_field!(value, ReleaseGuard<T>, value)
371 }
372
373 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
375 Weak::ptr_eq(&this.0, &other.0)
376 }
377}
378
379impl<T> Default for WeakRef<T> {
380 fn default() -> Self {
381 Self::new()
382 }
383}
384
385impl<T> Clone for WeakRef<T> {
386 fn clone(&self) -> Self {
387 Self(self.0.clone())
388 }
389}
390
391impl<T> PartialEq for WeakRef<T> {
392 fn eq(&self, other: &Self) -> bool {
393 WeakRef::ptr_eq(self, other)
394 }
395}
396
397pub struct WeakRefKey<T>(pub WeakRef<T>);
399impl<T> PartialEq for WeakRefKey<T> {
400 fn eq(&self, other: &Self) -> bool {
401 WeakRef::ptr_eq(&self.0, &other.0)
402 }
403}
404impl<T> PartialOrd for WeakRefKey<T> {
405 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
406 Some(self.cmp(other))
407 }
408}
409impl<T> Ord for WeakRefKey<T> {
410 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
411 WeakRef::as_ptr(&self.0).cmp(&WeakRef::as_ptr(&other.0))
412 }
413}
414impl<T> From<WeakRef<T>> for WeakRefKey<T> {
415 fn from(weak_ref: WeakRef<T>) -> Self {
416 Self(weak_ref)
417 }
418}
419impl<'a, T> From<&TempRef<'a, T>> for WeakRefKey<T> {
420 fn from(temp_ref: &TempRef<'a, T>) -> Self {
421 Self(WeakRef::from(temp_ref))
422 }
423}
424impl<'a, T> From<&OwnedRef<T>> for WeakRefKey<T> {
425 fn from(owned_ref: &OwnedRef<T>) -> Self {
426 Self(WeakRef::from(owned_ref))
427 }
428}
429impl<T> Clone for WeakRefKey<T> {
430 fn clone(&self) -> Self {
431 Self(self.0.clone())
432 }
433}
434impl<T> Eq for WeakRefKey<T> {}
435impl<T> Hash for WeakRefKey<T> {
436 fn hash<H: Hasher>(&self, state: &mut H) {
437 WeakRef::as_ptr(&self.0).hash(state);
438 }
439}
440impl<T> std::ops::Deref for WeakRefKey<T> {
441 type Target = WeakRef<T>;
442 fn deref(&self) -> &Self::Target {
443 &self.0
444 }
445}
446impl<T> std::fmt::Debug for WeakRefKey<T> {
447 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
448 fmt.debug_tuple(std::any::type_name::<Self>()).field(&self.0.as_ptr()).finish()
449 }
450}
451
452pub struct TempRef<'a, T>(Arc<RefInner<T>>, std::marker::PhantomData<(&'a T, *mut u8)>);
459
460impl<'a, T> std::fmt::Debug for TempRef<'a, T>
461where
462 T: std::fmt::Debug,
463{
464 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
465 self.deref().fmt(f)
466 }
467}
468
469impl<'a, T> Drop for TempRef<'a, T> {
470 fn drop(&mut self) {
471 self.0.dec_temp_ref();
472 }
473}
474
475impl<'a, T> TempRef<'a, T> {
476 fn new(inner: Arc<RefInner<T>>) -> Self {
478 inner.inc_temp_ref();
479 Self(inner, Default::default())
480 }
481
482 pub fn as_ptr(this: &Self) -> *const T {
486 &this.0.value.value as *const T
487 }
488
489 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
491 Self::as_ptr(this) == Self::as_ptr(other)
492 }
493
494 pub fn into_static(this: Self) -> TempRef<'static, T> {
500 TempRef::new(this.0.clone())
501 }
502
503 pub fn re_own(&self) -> Option<OwnedRef<T>> {
506 OwnedRef::re_own(Arc::clone(&self.0))
507 }
508}
509
510impl<'a, T> From<&TempRef<'a, T>> for WeakRef<T> {
511 fn from(temp_ref: &TempRef<'a, T>) -> Self {
512 Self(Arc::downgrade(&temp_ref.0))
513 }
514}
515
516impl<'a, T> From<TempRef<'a, T>> for WeakRef<T> {
517 fn from(temp_ref: TempRef<'a, T>) -> Self {
518 Self(Arc::downgrade(&temp_ref.0))
519 }
520}
521
522impl<'a, T> std::ops::Deref for TempRef<'a, T> {
523 type Target = T;
524
525 fn deref(&self) -> &Self::Target {
526 &self.0.deref().value
527 }
528}
529
530impl<'a, T> std::borrow::Borrow<T> for TempRef<'a, T> {
531 fn borrow(&self) -> &T {
532 &self.0.deref().value
533 }
534}
535
536impl<'a, T> std::convert::AsRef<T> for TempRef<'a, T> {
537 fn as_ref(&self) -> &T {
538 &self.0.deref().value
539 }
540}
541
542impl<'a, T: PartialEq> PartialEq for TempRef<'a, T> {
543 fn eq(&self, other: &TempRef<'_, T>) -> bool {
544 Arc::ptr_eq(&self.0, &other.0) || **self == **other
545 }
546}
547
548impl<'a, T: Eq> Eq for TempRef<'a, T> {}
549
550impl<'a, T: PartialOrd> PartialOrd for TempRef<'a, T> {
551 fn partial_cmp(&self, other: &TempRef<'_, T>) -> Option<std::cmp::Ordering> {
552 (**self).partial_cmp(&**other)
553 }
554}
555
556impl<'a, T: Ord> Ord for TempRef<'a, T> {
557 fn cmp(&self, other: &TempRef<'_, T>) -> std::cmp::Ordering {
558 (**self).cmp(&**other)
559 }
560}
561
562impl<'a, T: Hash> Hash for TempRef<'a, T> {
563 fn hash<H: Hasher>(&self, state: &mut H) {
564 (**self).hash(state)
565 }
566}
567
568pub struct TempRefKey<'a, T>(pub TempRef<'a, T>);
570impl<'a, T> PartialEq for TempRefKey<'a, T> {
571 fn eq(&self, other: &Self) -> bool {
572 TempRef::ptr_eq(&self.0, &other.0)
573 }
574}
575impl<'a, T> Eq for TempRefKey<'a, T> {}
576impl<'a, T> Hash for TempRefKey<'a, T> {
577 fn hash<H: Hasher>(&self, state: &mut H) {
578 TempRef::as_ptr(&self.0).hash(state);
579 }
580}
581impl<'a, T> std::ops::Deref for TempRefKey<'a, T> {
582 type Target = T;
583 fn deref(&self) -> &Self::Target {
584 self.0.deref()
585 }
586}
587
588#[must_use = "ReleaseGuard must be released"]
591pub struct ReleaseGuard<T> {
592 value: T,
594
595 drop_guard: DropGuard,
597}
598
599#[cfg(test)]
600impl<T> ReleaseGuard<T> {
601 pub fn new_released(value: T) -> Self {
602 let result: Self = value.into();
603 result.drop_guard.disarm();
604 result
605 }
606}
607
608impl<T> ReleaseGuard<T> {
609 pub fn take(this: ReleaseGuard<T>) -> T {
613 this.drop_guard.disarm();
614 this.value
615 }
616}
617
618#[cfg(test)]
619impl<T: Default> ReleaseGuard<T> {
620 pub fn default_released() -> Self {
621 Self::new_released(T::default())
622 }
623}
624
625impl<T: std::fmt::Debug> std::fmt::Debug for ReleaseGuard<T> {
626 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
627 self.value.fmt(f)
628 }
629}
630
631impl<T: Default> Default for ReleaseGuard<T> {
632 fn default() -> Self {
633 T::default().into()
634 }
635}
636
637impl<T: Clone> Clone for ReleaseGuard<T> {
638 fn clone(&self) -> Self {
639 self.value.clone().into()
640 }
641}
642
643impl<T> From<T> for ReleaseGuard<T> {
644 fn from(value: T) -> Self {
645 Self { value, drop_guard: Default::default() }
646 }
647}
648
649impl<T> std::ops::Deref for ReleaseGuard<T> {
650 type Target = T;
651
652 fn deref(&self) -> &Self::Target {
653 &self.value
654 }
655}
656
657impl<T> std::ops::DerefMut for ReleaseGuard<T> {
658 fn deref_mut(&mut self) -> &mut Self::Target {
659 &mut self.value
660 }
661}
662
663impl<T> std::borrow::Borrow<T> for ReleaseGuard<T> {
664 fn borrow(&self) -> &T {
665 self.deref()
666 }
667}
668
669impl<T> std::convert::AsRef<T> for ReleaseGuard<T> {
670 fn as_ref(&self) -> &T {
671 self.deref()
672 }
673}
674
675impl<T: PartialEq> PartialEq for ReleaseGuard<T> {
676 fn eq(&self, other: &ReleaseGuard<T>) -> bool {
677 **self == **other
678 }
679}
680
681impl<T: Eq> Eq for ReleaseGuard<T> {}
682
683impl<T: PartialOrd> PartialOrd for ReleaseGuard<T> {
684 fn partial_cmp(&self, other: &ReleaseGuard<T>) -> Option<std::cmp::Ordering> {
685 (**self).partial_cmp(&**other)
686 }
687}
688
689impl<T: Ord> Ord for ReleaseGuard<T> {
690 fn cmp(&self, other: &ReleaseGuard<T>) -> std::cmp::Ordering {
691 (**self).cmp(&**other)
692 }
693}
694
695impl<T: Hash> Hash for ReleaseGuard<T> {
696 fn hash<H: Hasher>(&self, state: &mut H) {
697 (**self).hash(state)
698 }
699}
700
701#[derive(Default, Debug)]
702pub struct DropGuard {
703 #[cfg(any(test, debug_assertions))]
704 released: std::sync::atomic::AtomicBool,
705}
706
707impl DropGuard {
708 #[inline(always)]
709 pub fn disarm(&self) {
710 #[cfg(any(test, debug_assertions))]
711 {
712 if self
713 .released
714 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
715 .is_err()
716 {
717 panic!("Guard was disarmed twice");
718 }
719 }
720 }
721}
722
723#[cfg(any(test, debug_assertions))]
724impl Drop for DropGuard {
725 fn drop(&mut self) {
726 assert!(*self.released.get_mut());
727 }
728}
729#[cfg(any(test, debug_assertions))]
730thread_local! {
731 static TEMP_REF_LOCAL_COUNT: std::cell::RefCell<usize> = const { std::cell::RefCell::new(0) };
734}
735
736pub fn debug_assert_no_local_temp_ref() {
739 #[cfg(any(test, debug_assertions))]
740 {
741 TEMP_REF_LOCAL_COUNT.with(|count| {
742 assert_eq!(*count.borrow(), 0, "Current threads owns {} TempRef", *count.borrow());
743 });
744 }
745}
746
747struct RefInner<T> {
758 value: ReleaseGuard<T>,
760 owned_refs_count: AtomicUsize,
762 temp_refs_count: zx::Futex,
767}
768
769impl<T> RefInner<T> {
770 fn new(value: T) -> Self {
771 Self {
772 value: value.into(),
773 owned_refs_count: AtomicUsize::new(1),
774 temp_refs_count: zx::Futex::new(0),
775 }
776 }
777
778 fn inc_temp_ref(&self) {
780 self.temp_refs_count.fetch_add(1, Ordering::Relaxed);
781 #[cfg(any(test, debug_assertions))]
782 {
783 TEMP_REF_LOCAL_COUNT.with(|count| {
784 *count.borrow_mut() += 1;
785 });
786 }
787 }
788
789 fn dec_temp_ref(&self) {
793 let previous_count = self.temp_refs_count.fetch_sub(1, Ordering::Release);
794 if previous_count == 1 {
795 fence(Ordering::Acquire);
796 self.temp_refs_count.wake_single_owner();
797 }
798 #[cfg(any(test, debug_assertions))]
799 {
800 TEMP_REF_LOCAL_COUNT.with(|count| {
801 *count.borrow_mut() -= 1;
802 });
803 }
804 }
805
806 fn wait_for_no_ref_once(self: &Arc<Self>) {
808 let current_value = self.temp_refs_count.load(Ordering::Acquire);
810 if current_value == 0 {
811 return;
813 }
814 let result = self.temp_refs_count.wait(current_value, None, zx::MonotonicInstant::INFINITE);
817 debug_assert!(
818 result == Ok(()) || result == Err(zx::Status::BAD_STATE),
819 "Unexpected result: {result:?}"
820 );
821 }
822}
823
824#[macro_export]
827macro_rules! release_on_error {
828 ($releasable_name:ident, $context:expr, $body:block ) => {{
829 #[allow(clippy::redundant_closure_call)]
830 let result = { (|| $body)() };
831 match result {
832 Err(e) => {
833 $releasable_name.release($context);
834 return Err(e);
835 }
836 Ok(x) => x,
837 }
838 }};
839 ($releasable_name:ident, $body:block ) => {{ release_on_error!($releasable_name, (), $body) }};
840}
841
842#[macro_export]
844macro_rules! release_after {
845 ($releasable_name:ident, $context:expr, async || $($output_type:ty)? $body:block ) => {{
846 #[allow(clippy::redundant_closure_call)]
847 let result = { (async || $(-> $output_type)? { $body })().await };
848 $releasable_name.release($context);
849 result
850 }};
851 ($releasable_name:ident, $context:expr, $(|| -> $output_type:ty)? $body:block ) => {{
852 #[allow(clippy::redundant_closure_call)]
853 let result = { (|| $(-> $output_type)? { $body })() };
854 $releasable_name.release($context);
855 result
856 }};
857 ($releasable_name:ident, async || $($output_type:ty)? $body:block ) => {{
858 release_after!($releasable_name, (), async || $($output_type)? $body)
859 }};
860 ($releasable_name:ident, $(|| -> $output_type:ty)? $body:block ) => {{
861 release_after!($releasable_name, (), $(|| -> $output_type)? $body)
862 }};
863}
864
865#[macro_export]
868macro_rules! release_iter_after {
869 ($releasable_iter:ident, $context:expr, async || $(-> $output_type:ty)? $body:block ) => {{
870 #[allow(clippy::redundant_closure_call)]
871 let result = { (async || $(-> $output_type)? { $body })().await };
872 for item in $releasable_iter.into_iter() {
873 item.release($context);
874 }
875 result
876 }};
877 ($releasable_iter:ident, $context:expr, $(|| -> $output_type:ty)? $body:block ) => {{
878 #[allow(clippy::redundant_closure_call)]
879 let result = { (|| $(-> $output_type)? { $body })() };
880 for item in $releasable_iter.into_iter() {
881 item.release($context);
882 }
883 result
884 }};
885}
886
887pub use release_after;
888pub use release_iter_after;
889pub use release_on_error;
890
891#[cfg(test)]
892mod test {
893 use super::*;
894
895 #[derive(Default)]
896 struct Data;
897
898 impl Releasable for Data {
899 type Context<'a> = ();
900 fn release<'a>(self, _: ()) {}
901 }
902
903 #[derive(Default)]
904 struct DataWithMutableReleaseContext;
905
906 impl Releasable for DataWithMutableReleaseContext {
907 type Context<'a> = &'a mut ();
908 fn release<'a>(self, _: &'a mut ()) {}
909 }
910
911 #[::fuchsia::test]
912 #[should_panic]
913 fn drop_without_release() {
914 let _ = OwnedRef::new(Data {});
915 }
916
917 #[::fuchsia::test]
918 fn test_creation_and_reference() {
919 let value = OwnedRef::new(Data {});
920 let reference = WeakRef::from(&value);
921 reference.upgrade().expect("upgrade");
922 value.release(());
923 assert!(reference.upgrade().is_none());
924 }
925
926 #[::fuchsia::test]
927 fn test_clone() {
928 let value = OwnedRef::new(Data {});
929 {
930 let value2 = OwnedRef::share(&value);
931 value2.release(());
932 }
933 #[allow(clippy::redundant_clone)]
934 {
935 let reference = WeakRef::from(&value);
936 let _reference2 = reference.clone();
937 }
938 value.release(());
939 }
940
941 #[::fuchsia::test]
942 fn test_default() {
943 let reference = WeakRef::<Data>::default();
944 assert!(reference.upgrade().is_none());
945 }
946
947 #[::fuchsia::test]
948 fn test_default_as_ptr_is_null() {
949 let reference = WeakRef::<Data>::default();
950 assert!(reference.as_ptr().is_null());
951 assert!(WeakRef::ptr_eq(&reference, &WeakRef::default()));
952 }
953
954 #[::fuchsia::test]
955 fn test_release_on_error() {
956 fn release_on_error() -> Result<(), ()> {
957 let value = OwnedRef::new(Data {});
958 release_on_error!(value, (), {
959 if true {
960 return Err(());
961 }
962 Ok(())
963 });
964 Ok(())
965 }
966 assert_eq!(release_on_error(), Err(()));
967 }
968
969 #[::fuchsia::test]
970 fn test_into_static() {
971 let value = OwnedRef::new(Data {});
972 let weak = WeakRef::from(&value);
973 let static_ref = TempRef::into_static(weak.upgrade().unwrap());
975 std::mem::drop(weak);
977 std::mem::drop(static_ref);
979 value.release(());
980 }
981
982 #[::fuchsia::test]
983 fn test_debug_assert_no_local_temp_ref() {
984 debug_assert_no_local_temp_ref();
985 let value = OwnedRef::new(Data {});
986 debug_assert_no_local_temp_ref();
987 let _temp_ref = OwnedRef::temp(&value);
988 std::thread::spawn(|| {
989 debug_assert_no_local_temp_ref();
990 })
991 .join()
992 .expect("join");
993 std::mem::drop(_temp_ref);
994 debug_assert_no_local_temp_ref();
995 value.release(());
996 debug_assert_no_local_temp_ref();
997 }
998
999 #[::fuchsia::test]
1000 #[should_panic]
1001 fn test_debug_assert_no_local_temp_ref_aborts() {
1002 let value = OwnedRef::new(Data {});
1003 {
1004 let _temp_ref = OwnedRef::temp(&value);
1005 debug_assert_no_local_temp_ref();
1006 }
1007 value.release(());
1010 }
1011
1012 #[::fuchsia::test]
1013 #[should_panic]
1014 fn test_unrelease_release_guard() {
1015 let _value = ReleaseGuard::<Data>::default();
1016 }
1017
1018 #[::fuchsia::test]
1019 fn test_released_release_guard() {
1020 let _value = ReleaseGuard::<Data>::default_released();
1021 }
1022
1023 #[::fuchsia::test]
1024 fn release_with_mutable_context() {
1025 let value = OwnedRef::new(DataWithMutableReleaseContext {});
1026 let mut context = ();
1027 value.release(&mut context);
1028 }
1029
1030 #[::fuchsia::test]
1033 fn upgrade_while_release() {
1034 let value = OwnedRef::new(Data {});
1035 for _ in 0..10 {
1037 std::thread::spawn({
1038 let weak = OwnedRef::downgrade(&value);
1039 move || loop {
1040 if weak.upgrade().is_none() {
1041 return;
1042 }
1043 }
1044 });
1045 }
1046 std::thread::sleep(std::time::Duration::from_millis(10));
1048 value.release(());
1049 }
1051
1052 #[::fuchsia::test]
1053 fn new_cyclic() {
1054 let mut weak_value = None;
1055 let value = OwnedRef::new_cyclic(|weak| {
1056 weak_value = Some(weak);
1057 Data {}
1058 });
1059 let weak_value = weak_value.expect("weak_value");
1060 assert!(weak_value.upgrade().is_some());
1061 value.release(());
1062 assert!(weak_value.upgrade().is_none());
1063 }
1064
1065 #[::fuchsia::test]
1066 fn as_ptr() {
1067 let value = OwnedRef::new(Data {});
1068 let weak = OwnedRef::downgrade(&value);
1069 let temp = weak.upgrade().expect("upgrade");
1070 assert_eq!(OwnedRef::as_ptr(&value), weak.as_ptr());
1071 assert_eq!(OwnedRef::as_ptr(&value), TempRef::as_ptr(&temp));
1072 std::mem::drop(temp);
1073 value.release(());
1074 }
1075
1076 #[::fuchsia::test]
1077 fn test_re_own() {
1078 let data = Data::default();
1079 let owned = OwnedRef::new(data);
1080 let weak = WeakRef::from(&owned);
1081
1082 let re_owned = weak.re_own();
1083 assert!(re_owned.is_some());
1084
1085 owned.release(());
1087
1088 let re_owned_again = weak.re_own();
1090 assert!(re_owned_again.is_some());
1091 re_owned_again.release(());
1092
1093 re_owned.release(());
1095
1096 let re_owned_finally = weak.re_own();
1098 assert!(re_owned_finally.is_none());
1099 }
1100
1101 #[::fuchsia::test]
1102 fn test_re_own_concurrent() {
1103 let owned = OwnedRef::new(Data::default());
1104 let weak = WeakRef::from(&owned);
1105 let num_threads = 10;
1106
1107 let mut handles = vec![];
1108 for _ in 0..num_threads {
1109 let weak = weak.clone();
1110 let handle = std::thread::spawn(move || {
1111 loop {
1112 if let Some(re_owned) = weak.re_own() {
1113 re_owned.release(());
1114 } else {
1115 return;
1116 }
1117 }
1118 });
1119 handles.push(handle);
1120 }
1121
1122 owned.release(());
1123
1124 for handle in handles {
1125 handle.join().unwrap();
1126 }
1127
1128 assert!(weak.re_own().is_none());
1129 }
1130
1131 #[::fuchsia::test]
1132 fn test_release_after() {
1133 let owned = OwnedRef::new(Data::default());
1134 let value = release_after!(owned, (), { 0 });
1135 assert_eq!(value, 0);
1136 }
1137
1138 #[::fuchsia::test]
1139 async fn test_release_after_async() {
1140 let owned = OwnedRef::new(Data::default());
1141 let value = release_after!(owned, (), async || { 0 });
1142 assert_eq!(value, 0);
1143 }
1144}