Skip to main content

thin_cell/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
4#![deny(rustdoc::broken_intra_doc_links)]
5
6mod state;
7
8mod fat_ptr;
9
10pub mod sync;
11pub mod unsync;
12
13macro_rules! thin_cell {
14    {
15        $( #[$doc:meta] )*
16    } => {
17        use std::{
18            any::{Any, TypeId},
19            cell::UnsafeCell,
20            fmt::{self, Debug, Display},
21            marker::PhantomData,
22            mem::ManuallyDrop,
23            ops::{Deref, DerefMut},
24            ptr::NonNull,
25        };
26
27        use crate::fat_ptr::*;
28
29        /// The inner allocation of `ThinCell`
30        ///
31        /// This should not be used except in unsize coercion solely as a type.
32        #[repr(C)]
33        pub struct Inner<T: ?Sized> {
34            // metadata MUST be at offset 0 so that `*mut Inner<T>` is also a valid `*mut usize`
35            // points to the metadata
36            metadata: usize,
37            state: State,
38            data: UnsafeCell<T>,
39        }
40
41        $( #[$doc] )*
42        pub struct ThinCell<T: ?Sized> {
43            ptr: NonNull<()>,
44            _marker: PhantomData<Inner<T>>,
45        }
46
47        /// A mutable guard returned by [`ThinCell::borrow`]
48        pub struct Ref<'a, T: ?Sized> {
49            value: &'a mut T,
50            state: &'a State,
51        }
52
53        /// A weak reference to a [`ThinCell`] that doesn't prevent dropping.
54        ///
55        /// `Weak` references don't keep the value alive. The value will be dropped
56        /// when all strong references (`ThinCell`) are dropped, even if weak
57        /// references still exist.
58        ///
59        /// Use [`Weak::upgrade`] to attempt to convert a weak reference back to a
60        /// strong reference (`ThinCell`). This will fail if the value has already
61        /// been dropped.
62        #[cfg(feature = "weak")]
63        pub struct Weak<T: ?Sized> {
64            ptr: NonNull<()>,
65            _marker: PhantomData<Inner<T>>,
66        }
67
68        impl<T> ThinCell<T> {
69            /// Creates a new `ThinCell` wrapping the given data.
70            pub fn new(data: T) -> Self {
71                let alloc = Box::new(Inner {
72                    metadata: 0,
73                    state: State::new(),
74                    data: UnsafeCell::new(data),
75                });
76
77                let ptr = Box::into_raw(alloc);
78
79                ThinCell {
80                    ptr: unsafe { NonNull::new_unchecked(ptr as _) },
81                    _marker: PhantomData,
82                }
83            }
84
85            /// Consumes the `ThinCell` and try to get inner value.
86            ///
87            /// Returns the inner value in [`Ok`] if there are no other owners and it is
88            /// not currently borrowed, return `Err(self)` otherwise.
89            pub fn try_unwrap(self) -> Result<T, Self> {
90                if !self.inner().state.try_unwrap() {
91                    return Err(self);
92                }
93
94                // SAFETY: As tested above, there are no other owners and it is not borrowed
95                Ok(unsafe { self.unwrap_unchecked() })
96            }
97
98            /// Consumes the `ThinCell`, returning the inner value.
99            ///
100            /// # Safety
101            /// The caller must guarantee that there are no other owners and it is not
102            /// currently borrowed.
103            #[cfg(not(feature = "weak"))]
104            pub unsafe fn unwrap_unchecked(self) -> T {
105                let this = ManuallyDrop::new(self);
106                // SAFETY: guaranteed by caller to have unique ownership and is not borrowed
107                let inner = unsafe { Box::from_raw(this.inner_ptr() as *mut Inner<T>) };
108
109                inner.data.into_inner()
110            }
111
112            /// Consumes the `ThinCell`, returning the inner value.
113            ///
114            /// # Safety
115            /// The caller must guarantee that there are no other strong owners and it is not
116            /// currently borrowed.
117            #[cfg(feature = "weak")]
118            pub unsafe fn unwrap_unchecked(self) -> T {
119                let this = ManuallyDrop::new(self);
120                let inner = this.inner();
121
122                let _weak: Weak<T> = Weak {
123                    ptr: this.ptr,
124                    _marker: PhantomData,
125                };
126
127                // SAFETY: guaranteed by caller to have unique strong ownership and
128                // not be borrowed. This moves out `T` without touching the
129                // allocation so outstanding weak refs remain valid.
130                unsafe { std::ptr::read(inner.data.get()) }
131            }
132        }
133
134        impl<T: ?Sized> ThinCell<T> {
135            const IS_SIZED: bool = is_sized::<T>();
136
137            /// Reconstructs the raw pointer to the inner allocation.
138            fn inner_ptr(&self) -> *const Inner<T> {
139                let ptr = self.ptr.as_ptr();
140
141                if Self::IS_SIZED {
142                    // SIZED CASE: Cast pointer-to-pointer
143                    // Doing this trick to workaround Rust not allowing `ptr as *const Inner<T>`
144                    // due to `T` being `?Sized` directly even when we know it's `Sized`
145                    let ptr_ref = &ptr as *const *mut () as *const *const Inner<T>;
146
147                    // SAFETY: `self.ptr` is a valid pointer of `Inner<T>`
148                    unsafe { *ptr_ref }
149                } else {
150                    // UNSIZED CASE: Read metadata
151                    // SAFETY: pointer returned by `self.ptr` is valid, and `metadata` is at offset
152                    // 0 of `Inner<T>`, which is guaranteed by `repr(C)` and the definition of
153                    // `Inner<T>`
154                    let metadata = unsafe { *(ptr as *const usize) };
155
156                    // Miri will complain about this:
157                    // - https://github.com/thepowersgang/stack_dst-rs/issues/14
158                    // - https://github.com/uazu/stakker/blob/5821c30409c19ca9167808b669c928c94bc5f177/src/queue/flat.rs#L14-L17
159                    // But this should be sound as per Rust's fat pointer and metadata construction
160                    FatPtr { ptr, metadata }.into_ptr()
161                }
162            }
163
164            /// Returns a reference to the inner allocation.
165            fn inner(&self) -> &Inner<T> {
166                unsafe { &*self.inner_ptr() }
167            }
168
169            /// Returns a reference to the state cell.
170            fn state(&self) -> &State {
171                &self.inner().state
172            }
173
174            /// Deallocates the inner allocation.
175            ///
176            /// # Safety
177            ///
178            /// `self` must be the last owner and it must not be used after this call.
179            #[cfg(not(feature = "weak"))]
180            unsafe fn drop_in_place(&mut self) {
181                drop(unsafe { Box::from_raw(self.inner_ptr() as *mut Inner<T>) })
182            }
183
184            /// Leaks the `ThinCell`, returning a raw pointer to the inner allocation.
185            ///
186            /// The returned pointer points to the inner allocation. To restore the
187            /// `ThinCell`, use [`ThinCell::from_raw`].
188            pub fn leak(self) -> *mut () {
189                let this = ManuallyDrop::new(self);
190                this.ptr.as_ptr()
191            }
192
193            /// Reconstructs a `ThinCell<T>` from a raw pointer.
194            ///
195            /// # Safety
196            /// The pointer must have been obtained from a previous call to
197            /// [`ThinCell::leak`], and the [`ThinCell`] must not have been dropped in
198            /// the meantime.
199            pub unsafe fn from_raw(ptr: *mut ()) -> Self {
200                ThinCell {
201                    // SAFETY: caller guarantees `ptr` is valid
202                    ptr: unsafe { NonNull::new_unchecked(ptr) },
203                    _marker: PhantomData,
204                }
205            }
206
207            /// Returns the number of strong owners.
208            pub fn count(&self) -> usize {
209                self.state().load().count()
210            }
211
212            /// Borrows the value mutably.
213            ///
214            /// Returns a [`Ref`] guard that provides mutable access to the inner value.
215            /// The borrow lasts until the guard is dropped. See module-level documentation
216            /// for details on borrowing behavior.
217            ///
218            /// # Examples
219            ///
220            /// ```
221            /// # use thin_cell::unsync::ThinCell;
222            /// let cell = ThinCell::new(5);
223            ///
224            /// {
225            ///     let mut borrowed = cell.borrow();
226            ///     *borrowed = 10;
227            /// } // borrow is released here
228            ///
229            /// assert_eq!(*cell.borrow(), 10);
230            /// ```
231            pub fn borrow(&self) -> Ref<'_, T> {
232                let inner = self.inner();
233                inner.state.borrow();
234
235                // SAFETY: We have exclusive access via borrow flag and block further access
236                // with `Ordering::Acquire`/`Release` pair.
237                let value = unsafe { &mut *inner.data.get() };
238
239                Ref {
240                    value,
241                    state: &inner.state,
242                }
243            }
244
245            /// Attempts to borrow the value mutably.
246            ///
247            /// Returns `Some(Ref)` if the value is not currently borrowed, or `None` if
248            /// it is already borrowed.
249            ///
250            /// This is the non-blocking variant of [`borrow`](ThinCell::borrow).
251            ///
252            /// # Examples
253            ///
254            /// ```
255            /// # use thin_cell::unsync::ThinCell;
256            /// let cell = ThinCell::new(5);
257            ///
258            /// let borrow1 = cell.borrow();
259            /// assert!(cell.try_borrow().is_none()); // Already borrowed
260            /// drop(borrow1);
261            /// assert!(cell.try_borrow().is_some()); // Now available
262            /// ```
263            pub fn try_borrow(&self) -> Option<Ref<'_, T>> {
264                let inner = self.inner();
265                if !inner.state.try_borrow() {
266                    return None;
267                }
268
269                // SAFETY: We have exclusive access via borrow flag and block further access
270                // with `Ordering::Acquire`/`Release` pair.
271                let value = unsafe { &mut *inner.data.get() };
272
273                Some(Ref {
274                    value,
275                    state: &inner.state,
276                })
277            }
278
279            /// Get a mutable reference to the inner value without any checks.
280            ///
281            /// # Safety
282            ///
283            /// The caller must guarantee that there are no other owners and it is not
284            /// borrowed now and during the entire lifetime of the returned reference.
285            pub unsafe fn borrow_unchecked(&mut self) -> &mut T {
286                let inner = self.inner();
287                unsafe { &mut *inner.data.get() }
288            }
289
290            /// Creates a new `ThinCell<U>` from `data: U` and coerces it to
291            /// `ThinCell<T>`.
292            ///
293            /// # Safety
294            ///
295            /// `coerce` function must ensure the returned pointer is:
296            ///
297            /// - a valid unsizing of `Inner<T>`, e.g., some `Inner<dyn Trait>` or
298            ///   `Inner<[_]>`
299            /// - with same address (bare data pointer without metadata) as input
300            pub unsafe fn new_unsize<U>(
301                data: U,
302                coerce: impl Fn(*const Inner<U>) -> *const Inner<T>,
303            ) -> Self {
304                let this = ThinCell::new(data);
305                // SAFETY: We're holding unique ownership and is not borrowed.
306                unsafe { this.unsize_unchecked(coerce) }
307            }
308
309            /// Manually coerce to unsize.
310            ///
311            /// # Safety
312            ///
313            /// `coerce` has the same requirements as [`ThinCell::new_unsize`].
314            ///
315            /// # Panics
316            ///
317            /// Panics if the `ThinCell` is currently shared (count > 1) or borrowed.
318            ///
319            /// See [`ThinCell::unsize_unchecked`] for details.
320            pub unsafe fn unsize<U: ?Sized>(
321                self,
322                coerce: impl Fn(*const Inner<T>) -> *const Inner<U>,
323            ) -> ThinCell<U> {
324                let inner = self.inner();
325                let s = inner.state.load();
326
327                assert!(!s.is_shared(), "Cannot coerce shared `ThinCell`");
328                assert!(!s.is_borrowed(), "Cannot coerce borrowed `ThinCell`");
329
330                // SAFETY: As tested above, the `ThinCell` is:
331                // - not shared, and
332                // - not borrowed
333                // - validity of `coerce` is guaranteed by caller
334                unsafe { self.unsize_unchecked(coerce) }
335            }
336
337            /// Manually coerce to unsize without checks.
338            ///
339            /// # Safety
340            ///
341            /// - The `ThinCell` must have unique ownership (count == 1)
342            /// - The `ThinCell` must not be borrowed
343            /// - `coerce` has the same requirements as [`ThinCell::new_unsize`].
344            ///
345            /// In particular, first two requirement is the exact state after
346            /// [`ThinCell::new`].
347            pub unsafe fn unsize_unchecked<U: ?Sized>(
348                self,
349                coerce: impl Fn(*const Inner<T>) -> *const Inner<U>,
350            ) -> ThinCell<U> {
351                let this = ManuallyDrop::new(self);
352
353                let old_ptr = this.inner_ptr();
354                let fat_ptr = coerce(old_ptr);
355
356                let FatPtr { ptr, metadata } = FatPtr::from_ptr::<Inner<U>>(fat_ptr);
357
358                // SAFETY: `Inner` is `repr(C)` and has `metadata` at offset 0
359                unsafe { *(old_ptr as *mut usize) = metadata };
360
361                ThinCell {
362                    // SAFETY: `ptr` is valid as it comes from `self`
363                    ptr: unsafe { NonNull::new_unchecked(ptr) },
364                    _marker: PhantomData,
365                }
366            }
367
368            /// Returns the raw pointer to the inner allocation.
369            pub fn as_ptr(&self) -> *const () {
370                self.ptr.as_ptr()
371            }
372
373            /// Returns `true` if the two `ThinCell`s point to the same allocation.
374            pub fn ptr_eq(&self, other: &Self) -> bool {
375                std::ptr::eq(self.as_ptr(), other.as_ptr())
376            }
377
378            /// Downcasts the `ThinCell<T>` to `ThinCell<U>`.
379            ///
380            /// # Safety
381            ///
382            /// The caller must make sure that the inner value is actually of type `U`.
383            pub unsafe fn downcast_unchecked<U>(self) -> ThinCell<U> {
384                let this = ManuallyDrop::new(self);
385
386                ThinCell {
387                    ptr: this.ptr,
388                    _marker: PhantomData,
389                }
390            }
391        }
392
393        #[cfg(feature = "weak")]
394        impl<T: ?Sized> ThinCell<T> {
395            /// Returns the number of strong references.
396            pub fn strong_count(&self) -> usize {
397                self.state().load().strong_count()
398            }
399
400            /// Returns the number of weak references.
401            pub fn weak_count(&self) -> usize {
402                self.state().load().weak_count()
403            }
404
405            /// Creates a new weak reference to this `ThinCell`.
406            ///
407            /// # Examples
408            ///
409            /// ```
410            /// # #[cfg(feature = "weak")]
411            /// # {
412            /// # use thin_cell::sync::ThinCell;
413            /// let cell = ThinCell::new(42);
414            /// let weak = cell.downgrade();
415            ///
416            /// assert_eq!(cell.strong_count(), 1);
417            /// assert_eq!(cell.weak_count(), 2);
418            ///
419            /// drop(cell);
420            /// assert!(weak.upgrade().is_none());
421            /// # }
422            /// ```
423            pub fn downgrade(&self) -> Weak<T> {
424                self.state().inc_weak();
425                Weak {
426                    ptr: self.ptr,
427                    _marker: PhantomData,
428                }
429            }
430        }
431
432        impl<T, const N: usize> ThinCell<[T; N]> {
433            /// Coerce an array [`ThinCell`] to a slice one.
434            pub fn unsize_slice(self) -> ThinCell<[T]> {
435                // Safety: unsized coercion from array to slice is safe
436                unsafe { self.unsize(|ptr| ptr as _) }
437            }
438        }
439
440        /// Error returned by [`ThinCell::downcast`] when downcasting fails.
441        #[derive(Debug)]
442        pub enum DowncastError<T: ?Sized> {
443            /// The [`ThinCell`] is currently borrowed.
444            Borrowed(ThinCell<T>),
445
446            /// The inner value is not of the target type.
447            Type(ThinCell<T>),
448        }
449
450        impl<T: ?Sized> DowncastError<T> {
451            /// Consumes the error and returns the original `ThinCell<T>`.
452            pub fn into_inner(self) -> ThinCell<T> {
453                match self {
454                    DowncastError::Borrowed(cell) | DowncastError::Type(cell) => cell,
455                }
456            }
457        }
458
459        impl<T: Any + ?Sized> ThinCell<T> {
460            /// Attempts to downcast the `ThinCell<T>` to `ThinCell<U>`.
461            ///
462            /// # Returns
463            ///
464            /// - `Ok(ThinCell<U>)` if the inner value is of type `U` and is not
465            ///   currently borrowed
466            /// - `Err(DowncastError::Borrowed(self))` if the inner value is currently
467            ///   borrowed
468            /// - `Err(DowncastError::Type(self))` if the inner value is not of type `U`
469            pub fn downcast<U: Any>(self) -> Result<ThinCell<U>, DowncastError<T>> {
470                let inner = self.inner();
471                if !inner.state.try_borrow() {
472                    return Err(DowncastError::Borrowed(self));
473                }
474
475                // SAFETY: We have exclusive access via borrow flag.
476                let data_ref = unsafe { &*inner.data.get() };
477                let type_id = data_ref.type_id();
478                inner.state.unborrow();
479
480                if TypeId::of::<U>() == type_id {
481                    // SAFETY: We have verified that the inner value is of type `U`
482                    Ok(unsafe { self.downcast_unchecked::<U>() })
483                } else {
484                    Err(DowncastError::Type(self))
485                }
486            }
487        }
488
489        /// `ThinCell` is `Unpin` as it does not move its inner data.
490        impl<T: ?Sized> Unpin for ThinCell<T> {}
491
492        impl<'a, T: ?Sized> Drop for Ref<'a, T> {
493            fn drop(&mut self) {
494                self.state.unborrow();
495            }
496        }
497
498        impl<'a, T: ?Sized> Deref for Ref<'a, T> {
499            type Target = T;
500
501            fn deref(&self) -> &T {
502                self.value
503            }
504        }
505
506        impl<'a, T: ?Sized> DerefMut for Ref<'a, T> {
507            fn deref_mut(&mut self) -> &mut T {
508                self.value
509            }
510        }
511
512        impl<'a, T: Debug + ?Sized> Debug for Ref<'a, T> {
513            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514                Debug::fmt(&**self, f)
515            }
516        }
517
518        impl<'a, T: Display + ?Sized> Display for Ref<'a, T> {
519            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
520                Display::fmt(&**self, f)
521            }
522        }
523
524        impl<T: ?Sized> Clone for ThinCell<T> {
525            fn clone(&self) -> Self {
526                self.state().inc();
527
528                ThinCell {
529                    ptr: self.ptr,
530                    _marker: PhantomData,
531                }
532            }
533        }
534
535        #[cfg(not(feature = "weak"))]
536        impl<T: ?Sized> Drop for ThinCell<T> {
537            fn drop(&mut self) {
538                let inner = self.inner();
539                if !inner.state.dec() {
540                    // Not last owner, nothing to do
541                    return;
542                }
543
544                // SAFETY: We are the last owner, so we have unique ownership, and we're not
545                // using `self` after this call.
546                unsafe {
547                    self.drop_in_place();
548                }
549            }
550        }
551
552        #[cfg(feature = "weak")]
553        impl<T: ?Sized> Drop for ThinCell<T> {
554            fn drop(&mut self) {
555                let inner = self.inner();
556                if !inner.state.dec() {
557                    // Not last strong owner, nothing to do
558                    return;
559                }
560
561                // Keep the strong side's collective weak ref alive as a real `Weak`
562                // guard so unwinding through `T::drop` still releases the allocation.
563                let _weak: Weak<T> = Weak {
564                    ptr: self.ptr,
565                    _marker: PhantomData,
566                };
567
568                // Drop the value in place.
569                // SAFETY: We are the last strong owner, so we have unique ownership.
570                unsafe {
571                    std::ptr::drop_in_place(inner.data.get());
572                }
573            }
574        }
575
576        #[cfg(feature = "weak")]
577        impl<T: ?Sized> Weak<T> {
578            /// Reconstructs the raw pointer to the inner allocation.
579            fn inner_ptr(&self) -> *const Inner<T> {
580                let ptr = self.ptr.as_ptr();
581
582                if ThinCell::<T>::IS_SIZED {
583                    // SIZED CASE: Cast pointer-to-pointer
584                    let ptr_ref = &ptr as *const *mut () as *const *const Inner<T>;
585                    unsafe { *ptr_ref }
586                } else {
587                    // UNSIZED CASE: Read metadata
588                    let metadata = unsafe { *(ptr as *const usize) };
589                    FatPtr { ptr, metadata }.into_ptr()
590                }
591            }
592
593            /// Returns a reference to the inner allocation.
594            fn inner(&self) -> &Inner<T> {
595                unsafe { &*self.inner_ptr() }
596            }
597
598            /// Returns a reference to the state cell.
599            fn state(&self) -> &State {
600                &self.inner().state
601            }
602
603            /// Attempts to upgrade the weak reference to a strong reference.
604            ///
605            /// Returns `Some(ThinCell)` if the value still exists, or `None` if it
606            /// has been dropped.
607            ///
608            /// # Examples
609            ///
610            /// ```
611            /// # #[cfg(feature = "weak")]
612            /// # {
613            /// # use thin_cell::sync::ThinCell;
614            /// let cell = ThinCell::new(42);
615            /// let weak = cell.downgrade();
616            ///
617            /// let strong = weak.upgrade().unwrap();
618            /// assert_eq!(*strong.borrow(), 42);
619            ///
620            /// drop(cell);
621            /// drop(strong);
622            /// assert!(weak.upgrade().is_none());
623            /// # }
624            /// ```
625            pub fn upgrade(&self) -> Option<ThinCell<T>> {
626                let state = self.state();
627
628                // Atomically try to increment strong count only if non-zero
629                if !state.try_inc() {
630                    return None;
631                }
632
633                Some(ThinCell {
634                    ptr: self.ptr,
635                    _marker: PhantomData,
636                })
637            }
638
639            /// Returns the number of strong references.
640            pub fn strong_count(&self) -> usize {
641                self.state().load().strong_count()
642            }
643
644            /// Returns the number of weak references.
645            pub fn weak_count(&self) -> usize {
646                self.state().load().weak_count()
647            }
648
649            /// Gets a raw pointer to the inner allocation.
650            ///
651            /// The pointer is valid only if the strong count is non-zero.
652            pub fn as_ptr(&self) -> *const () {
653                self.ptr.as_ptr()
654            }
655        }
656
657        #[cfg(feature = "weak")]
658        impl<T: ?Sized> Clone for Weak<T> {
659            fn clone(&self) -> Self {
660                self.state().inc_weak();
661                Weak {
662                    ptr: self.ptr,
663                    _marker: PhantomData,
664                }
665            }
666        }
667
668        #[cfg(feature = "weak")]
669        impl<T: ?Sized> Drop for Weak<T> {
670            fn drop(&mut self) {
671                let inner = self.inner();
672                if !inner.state.dec_weak() {
673                    // Not last weak ref, nothing to do
674                    return;
675                }
676
677                // Last weak ref and no strong refs - deallocate memory only
678                // The value T was already dropped when the last strong ref was dropped
679                // SAFETY: We are the last weak owner and no strong owners exist
680                unsafe {
681                    let layout = std::alloc::Layout::for_value(inner);
682                    std::alloc::dealloc(self.inner_ptr() as *mut u8, layout);
683                }
684            }
685        }
686
687        #[cfg(feature = "weak")]
688        impl<T: ?Sized> Debug for Weak<T> {
689            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690                write!(f, "(Weak)")
691            }
692        }
693
694        impl<T: Default> Default for ThinCell<T> {
695            fn default() -> Self {
696                ThinCell::new(T::default())
697            }
698        }
699
700        impl<T: Debug + ?Sized> Debug for ThinCell<T> {
701            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
702                let inner = self.inner();
703                let state = inner.state.load();
704                let mut d = f.debug_struct("ThinCell");
705                match self.try_borrow() {
706                    Some(borrowed) => d.field("value", &borrowed),
707                    None => d.field("value", &"<borrowed>"),
708                }
709                .field("state", &state)
710                .finish()
711            }
712        }
713
714        impl<T: Display + ?Sized> Display for ThinCell<T> {
715            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
716                match self.try_borrow() {
717                    Some(borrowed) => Display::fmt(&*borrowed, f),
718                    None => write!(f, "<borrowed>"),
719                }
720            }
721        }
722
723        impl<T: PartialEq + ?Sized> PartialEq<ThinCell<T>> for ThinCell<T> {
724            /// Compares the inner values for equality.
725            ///
726            /// This will block on `sync` version or panic on `unsync` version if either `ThinCell` is currently borrowed.
727            ///
728            /// If a shallow comparison is desired, use [`ptr_eq`](ThinCell::ptr_eq)
729            /// instead.
730            fn eq(&self, other: &Self) -> bool {
731                self.borrow().eq(&other.borrow())
732            }
733        }
734
735        impl<T: Eq + ?Sized> Eq for ThinCell<T> {}
736
737        #[allow(clippy::non_canonical_partial_ord_impl)]
738        impl<T: Ord + ?Sized> PartialOrd<ThinCell<T>> for ThinCell<T> {
739            /// Compares the inner values.
740            ///
741            /// This will block on `sync` version or panic on `unsync` version if either `ThinCell` is currently borrowed.
742            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
743                self.borrow().partial_cmp(&other.borrow())
744            }
745        }
746
747        impl<T: Ord + ?Sized> Ord for ThinCell<T> {
748            /// Compares the inner values.
749            ///
750            /// This will block on `sync` version or panic on `unsync` version if either `ThinCell` is currently borrowed.
751            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
752                self.borrow().cmp(&other.borrow())
753            }
754        }
755    }
756}
757
758use thin_cell;