static_rc/
rc.rs

1//! `StaticRc` is a compile-time referenced counted heap-allocated pointer.
2
3use core::{
4    any,
5    borrow,
6    cmp,
7    convert,
8    fmt,
9    future,
10    hash,
11    iter,
12    marker,
13    mem::{self, MaybeUninit},
14    ops,
15    pin,
16    ptr::{self, NonNull},
17    task,
18};
19
20use alloc::boxed::Box;
21
22#[cfg(feature = "nightly-async-iterator")]
23use core::async_iter;
24
25#[cfg(feature = "nightly-coerce-unsized")]
26use core::ops::CoerceUnsized;
27
28#[cfg(feature = "nightly-dispatch-from-dyn")]
29use core::ops::DispatchFromDyn;
30
31/// A compile-time reference-counted pointer.
32///
33/// The inherent methods of `StaticRc` are all associated functions to avoid conflicts with the the methods of the
34/// inner type `T` which are brought into scope by the `Deref` implementation.
35///
36/// The parameters `NUM` and `DEN` DENote the ratio (`NUM / DEN`) of ownership of the pointer:
37///
38/// -   The ratio is always in the (0, 1] interval, that is: `NUM > 0` and `NUM <= DEN`.
39/// -   When the ratio is equal to 1, that is when `NUM == DEN`, then the instance has full ownership of the pointee
40///     and extra capabilities are unlocked.
41pub struct StaticRc<T: ?Sized, const NUM: usize, const DEN: usize> {
42    pointer: NonNull<T>,
43}
44
45impl<T, const N: usize> StaticRc<T, N, N> {
46    /// Constructs a new `StaticRc<T, N, N>`.
47    ///
48    /// This uses `Box` under the hood.
49    ///
50    /// #   Example
51    ///
52    /// ```rust
53    /// use static_rc::StaticRc;
54    ///
55    /// type Full = StaticRc<i32, 1, 1>;
56    ///
57    /// let rc = Full::new(42);
58    /// assert_eq!(42, *rc);
59    /// ```
60    #[inline(always)]
61    pub fn new(value: T) -> Self
62    where
63        AssertLeType!(1, N): Sized,
64    {
65        #[cfg(not(feature = "compile-time-ratio"))]
66        assert!(N > 0);
67
68        let pointer = NonNull::from(Box::leak(Box::new(value)));
69        Self { pointer }
70    }
71
72    /// Constructs a new `Pin<StaticRc<T, N, N>>`.
73    ///
74    /// #   Example
75    ///
76    /// ```rust
77    /// use static_rc::StaticRc;
78    ///
79    /// type Full = StaticRc<i32, 1, 1>;
80    ///
81    /// let rc = Full::pin(42);
82    /// assert_eq!(42, *rc);
83    /// ```
84    #[inline(always)]
85    pub fn pin(value: T) -> pin::Pin<Self>
86    where
87        AssertLeType!(1, N): Sized,
88    {
89        #[cfg(not(feature = "compile-time-ratio"))]
90        assert!(N > 0);
91
92        //  Safety:
93        //  -   The `value` is placed on the heap, and cannot be moved out of the heap without full ownership.
94        unsafe { pin::Pin::new_unchecked(Self::new(value)) }
95    }
96
97    /// Returns the inner value.
98    ///
99    /// #   Example
100    ///
101    /// ```rust
102    /// use static_rc::StaticRc;
103    ///
104    /// type Full = StaticRc<i32, 1, 1>;
105    ///
106    /// let rc = Full::new(42);
107    /// assert_eq!(42, Full::into_inner(rc));
108    /// ```
109    #[inline(always)]
110    pub fn into_inner(this: Self) -> T {
111        //  Safety:
112        //  -   Ratio = 1, hence full ownership.
113        let boxed = unsafe { Box::from_raw(this.pointer.as_ptr()) };
114        mem::forget(this);
115
116        *boxed
117    }
118}
119
120impl<T: ?Sized, const N: usize> StaticRc<T, N, N> {
121    /// Returns a mutable reference into the given `StaticRc`.
122    ///
123    /// #   Example
124    ///
125    /// ```rust
126    /// use static_rc::StaticRc;
127    ///
128    /// type Full = StaticRc<i32, 1, 1>;
129    ///
130    /// let mut rc = Full::new(42);
131    /// let r: &mut i32 = Full::get_mut(&mut rc);
132    /// *r = 33;
133    /// assert_eq!(33, *rc);
134    /// ```
135    #[inline(always)]
136    pub fn get_mut(this: &mut Self) -> &mut T {
137        //  Safety:
138        //  -   Ratio = 1, hence full ownership.
139        unsafe { this.pointer.as_mut() }
140    }
141
142    /// Returns the inner value, boxed
143    ///
144    /// #   Example
145    ///
146    /// ```rust
147    /// use static_rc::StaticRc;
148    ///
149    /// type Full = StaticRc<i32, 1, 1>;
150    ///
151    /// let mut rc = Full::new(42);
152    /// let boxed: Box<_> = Full::into_box(rc);
153    /// assert_eq!(42, *boxed);
154    /// ```
155    #[inline(always)]
156    pub fn into_box(this: Self) -> Box<T> {
157        let pointer = this.pointer;
158        mem::forget(this);
159
160        //  Safety:
161        //  -   Ratio = 1, hence full ownership.
162        //  -   `pointer` was allocated by Box.
163        unsafe { Box::from_raw(pointer.as_ptr()) }
164    }
165}
166
167impl<T: ?Sized, const NUM: usize, const DEN: usize> StaticRc<T, NUM, DEN> {
168    /// Consumes the `StaticRc`, returning the wrapped pointer.
169    ///
170    /// To avoid a memory leak, the pointer must be converted back to `Self` using `StaticRc::from_raw`.
171    ///
172    /// #   Example
173    ///
174    /// ```rust
175    /// use static_rc::StaticRc;
176    ///
177    /// type Full = StaticRc<i32, 1, 1>;
178    ///
179    /// let rc = Full::new(42);
180    /// let leaked = Full::into_raw(rc);
181    ///
182    /// let rc = unsafe { Full::from_raw(leaked) };
183    /// assert_eq!(42, *rc);
184    /// ```
185    #[inline(always)]
186    pub fn into_raw(this: Self) -> NonNull<T> {
187        let pointer = this.pointer;
188        mem::forget(this);
189
190        pointer
191    }
192
193    /// Provides a raw pointer to the data.
194    ///
195    /// `StaticRc` is not consumed or affected in any way, the pointer is valid as long as there are shared owners of
196    /// the value.
197    ///
198    /// #   Example
199    ///
200    /// ```rust
201    /// use static_rc::StaticRc;
202    ///
203    /// type Full = StaticRc<i32, 1, 1>;
204    ///
205    /// let rc = Full::new(42);
206    /// let pointer = Full::as_ptr(&rc);
207    /// assert_eq!(42, unsafe { *pointer.as_ref() });
208    /// ```
209    #[inline(always)]
210    pub fn as_ptr(this: &Self) -> NonNull<T> { this.pointer }
211
212    /// Provides a reference to the data.
213    ///
214    /// #   Example
215    ///
216    /// ```rust
217    /// use static_rc::StaticRc;
218    ///
219    /// type Full = StaticRc<i32, 1, 1>;
220    ///
221    /// let rc = Full::new(42);
222    /// assert_eq!(42, *Full::get_ref(&rc));
223    /// ```
224    #[inline(always)]
225    pub fn get_ref(this: &Self) -> &T {
226        //  Safety:
227        //  -   The data is valid for as long as `this` lives.
228        unsafe { this.pointer.as_ref() }
229    }
230
231    /// Constructs a `StaticRc<T, NUM, DEN>` from a raw pointer.
232    ///
233    /// #   Safety
234    ///
235    /// The raw pointer must have been previously returned by a call to `StaticRc<U, N, D>::into_raw`:
236    ///
237    /// -   If `U` is different from `T`, then specific restrictions on size and alignment apply. See `mem::transmute`
238    ///     for the restrictions applying to transmuting references.
239    /// -   If `N / D` is different from `NUM / DEN`, then specific restrictions apply. The user is responsible for
240    ///     ensuring proper management of the ratio of shares, and ultimately that the value is not dropped twice.
241    ///
242    /// #   Example
243    ///
244    /// ```rust
245    /// use static_rc::StaticRc;
246    ///
247    /// type Full = StaticRc<i32, 2, 2>;
248    /// type Half = StaticRc<i32, 1, 2>;
249    ///
250    /// let rc = Full::new(42);
251    /// let leaked = Full::into_raw(rc);
252    ///
253    /// let (one, two) = unsafe { (Half::from_raw(leaked), Half::from_raw(leaked)) };
254    /// let rc = Full::join(one, two);
255    ///
256    /// assert_eq!(42, *rc);
257    /// ```
258    #[inline(always)]
259    pub unsafe fn from_raw(pointer: NonNull<T>) -> Self
260    where
261        AssertLeType!(1, NUM): Sized,
262    {
263        #[cfg(not(feature = "compile-time-ratio"))]
264        assert!(NUM > 0);
265
266        Self { pointer }
267    }
268
269    /// Returns true if the two `StaticRc` point to the same allocation.
270    ///
271    /// #   Example
272    ///
273    /// ```rust
274    /// use static_rc::StaticRc;
275    ///
276    /// type Full = StaticRc<i32, 2, 2>;
277    ///
278    /// let rc = Full::new(42);
279    /// let (one, two) = Full::split::<1, 1>(rc);
280    ///
281    /// assert!(StaticRc::ptr_eq(&one, &two));
282    ///
283    /// Full::join(one, two);
284    /// ```
285    #[inline(always)]
286    pub fn ptr_eq<const N: usize, const D: usize>(this: &Self, other: &StaticRc<T, N, D>) -> bool {
287        StaticRc::as_ptr(this) == StaticRc::as_ptr(other)
288    }
289
290    /// Adjusts the NUMerator and DENUMerator of the ratio of the instance, preserving the ratio.
291    ///
292    /// #   Panics
293    ///
294    /// If the compile-time-ratio feature is not used, and the ratio is not preserved; that is `N / D <> NUM / DEN`.
295    ///
296    /// #   Example
297    ///
298    /// ```rust
299    /// use static_rc::StaticRc;
300    ///
301    /// type Full = StaticRc<i32, 2, 2>;
302    ///
303    /// let rc = Full::new(42);
304    /// let rc = Full::adjust::<1, 1>(rc);
305    ///
306    /// assert_eq!(42, *rc);
307    /// ```
308    #[inline(always)]
309    pub fn adjust<const N: usize, const D: usize>(this: Self) -> StaticRc<T, N, D>
310    where
311        AssertLeType!(1, N): Sized,
312        AssertEqType!(N * DEN, NUM * D): Sized,
313    {
314        #[cfg(not(feature = "compile-time-ratio"))]
315        {
316            assert!(N > 0);
317            assert_eq!(NUM * D, N * DEN, "{} / {} != {} / {}", NUM, DEN, N, D);
318        }
319
320        let pointer = this.pointer;
321        mem::forget(this);
322
323        StaticRc { pointer }
324    }
325
326    /// Converts an instance into a [`StaticRcRef`](super::StaticRcRef).
327    /// 
328    /// The current instance is mutably borrowed for the duration the result can be used.
329    /// 
330    /// #   Example
331    ///   
332    /// ```rust
333    /// use static_rc::StaticRc;
334    /// use static_rc::StaticRcRef;
335    /// let rc: StaticRc<_, 2, 2> = StaticRc::new(5);
336    /// let (mut rc1, mut rc2) = StaticRc::split::<1, 1>(rc);
337    /// {
338    ///     // Modify without moving `rc1`, `rc2`.
339    ///     let rcref1 = StaticRc::as_rcref(&mut rc1);
340    ///     let rcref2 = StaticRc::as_rcref(&mut rc2);
341    ///     let mut rcref_owning: StaticRcRef<_, 2, 2> = StaticRcRef::join(rcref1, rcref2);
342    ///     *rcref_owning = 9;
343    ///     // Refs not used anymore, original rcs can be used again
344    /// }
345    /// let rc: StaticRc<_, 2, 2> = StaticRc::join(rc1, rc2);
346    /// assert_eq!(*rc, 9);
347    /// assert_eq!(*StaticRc::into_box(rc), 9);
348    /// ```
349    #[inline(always)]
350    pub fn as_rcref<'a>(this: &'a mut Self) -> super::StaticRcRef<'a, T, NUM, DEN> 
351    where
352        AssertLeType!(1, NUM): Sized,
353    {
354        //  Safety:
355        //  -   The public documentation says that `StaticRcRef::from_raw`
356        //      can only be called on pointers returned from `StaticRcRef::into_raw`.
357        //      which this isn't.
358        //  -   However, internally the library knows that `rc` and `rcref` have the same invariants:
359        //      -  `this.pointer` is a valid aligned pointer into a valid value of `T`.
360        //  -   The result is only usable for lifetime `'a`, and for the duration
361        //      of the lifetime `'a` `this` is mutably borrowed.
362        //  -   `this` has NUM/DEN of the ownership. So it can lend NUM/DEN
363        //      of the right to mutate the value. Therefore, this is semantically sound
364        //      according to the general principle of this library.
365        //
366        //  This is safe for generally the same reason `StaticRcRef::reborrow` is safe.
367        //
368        //  `StaticRcRef::from_raw` has to have a comment documenting
369        //  internally that such a use is allowed.
370        let ptr = this.pointer;
371        unsafe {
372            super::StaticRcRef::from_raw(ptr)
373        }
374    }
375
376    /// Splits the current instance into two instances with the specified NUMerators.
377    ///
378    /// #   Panics
379    ///
380    /// If the compile-time-ratio feature is not used, and the ratio is not preserved; that is `A + B <> NUM`.
381    ///
382    /// #   Example
383    ///
384    /// ```rust
385    /// use static_rc::StaticRc;
386    ///
387    /// type Full = StaticRc<i32, 2, 2>;
388    /// type Half = StaticRc<i32, 1, 2>;
389    ///
390    /// let rc = Full::new(42);
391    /// let (one, two): (Half, Half) = Full::split::<1, 1>(rc);
392    ///
393    /// assert_eq!(42, *one);
394    ///
395    /// Full::join(one, two);
396    /// ```
397    #[inline(always)]
398    pub fn split<const A: usize, const B: usize>(this: Self) -> (StaticRc<T, A, DEN>, StaticRc<T, B, DEN>)
399    where
400        AssertLeType!(1, A): Sized,
401        AssertLeType!(1, B): Sized,
402        AssertEqType!(A + B, NUM): Sized,
403    {
404        #[cfg(not(feature = "compile-time-ratio"))]
405        {
406            assert!(A > 0);
407            assert!(B > 0);
408            assert_eq!(NUM, A + B, "{} != {} + {}", NUM, A, B);
409        }
410
411        let pointer = this.pointer;
412        mem::forget(this);
413
414        (StaticRc { pointer }, StaticRc { pointer })
415    }
416
417    /// Splits the current instance into `DIM` instances with the specified Numerators and Denominators.
418    ///
419    /// #   Panics
420    ///
421    /// If the compile-time-ratio feature is not used, and the ratio is not preserved; that is `N * DIM <> NUM`.
422    ///
423    /// #   Example
424    ///
425    /// ```rust
426    /// use static_rc::StaticRc;
427    ///
428    /// type Full = StaticRc<i32, 2, 2>;
429    ///
430    /// let rc = Full::new(42);
431    /// let array = Full::split_array::<1, 2>(rc);
432    ///
433    /// assert_eq!(42, *array[0]);
434    ///
435    /// Full::join_array(array);
436    /// ```
437    #[inline(always)]
438    pub fn split_array<const N: usize, const DIM: usize>(this: Self) -> [StaticRc<T, N, DEN>; DIM]
439    where
440        AssertEqType!(N * DIM, NUM ): Sized,
441        AssertLeType!(mem::size_of::<[StaticRc<T, N, DEN>; DIM]>(), usize::MAX / 2 + 1): Sized,
442    {
443        #[cfg(not(feature = "compile-time-ratio"))]
444        assert_eq!(NUM, N * DIM, "{} != {} * {}", NUM, N, DIM);
445
446        #[cfg(not(feature = "compile-time-ratio"))]
447        assert!(mem::size_of::<[StaticRc<T, N, DEN>; DIM]>() <= (isize::MAX as usize),
448            "Size of result ({}) exceeeds isize::MAX", mem::size_of::<[StaticRc<T, N, DEN>; DIM]>());
449
450        let pointer = this.pointer;
451        mem::forget(this);
452
453        let mut array = MaybeUninit::uninit();
454
455        for i in 0..DIM {
456            //  Safety:
457            //  -   `destination` within bounds of allocated array (< DIM).
458            //  -   Offset doesn't overflow `isize`, as per array-size assertion.
459            //  -   Offset doesn't wrap around, as per array-size assertion.
460            let destination = unsafe { (array.as_mut_ptr() as *mut StaticRc<T, N, DEN>).add(i) };
461
462            //  Safety:
463            //  -   `destination` is valid for writes.
464            //  -   `destination` is correctly aligned.
465            unsafe { ptr::write(destination, StaticRc { pointer }); }
466        }
467
468        //  Safety:
469        //  -   Every element of the array is now initialized.
470        unsafe { array.assume_init() }
471    }
472
473    /// Joins two instances into a single instance.
474    ///
475    /// #   Panics
476    ///
477    /// If the two instances do no point to the same allocation, as determined by `StaticRc::ptr_eq`.
478    ///
479    /// If the compile-time-ratio feature is not used and the ratio is not preserved; that is `A + B <> NUM`.
480    ///
481    /// #   Example
482    ///
483    /// ```rust
484    /// use static_rc::StaticRc;
485    ///
486    /// type Full = StaticRc<i32, 3, 3>;
487    ///
488    /// let rc = Full::new(42);
489    /// let (one, two) = Full::split::<1, 2>(rc);
490    ///
491    /// let rc = Full::join(one, two);
492    /// assert_eq!(42, *rc);
493    /// ```
494    #[inline(always)]
495    pub fn join<const A: usize, const B: usize>(left: StaticRc<T, A, DEN>, right: StaticRc<T, B, DEN>) -> Self
496    where
497        AssertEqType!(NUM, A + B): Sized,
498    {
499        let (left, right) = Self::validate_pair(left, right);
500
501        //  Safety:
502        //  -   `left` and `right` point to the same pointer.
503        unsafe { Self::join_impl(left, right) }
504    }
505
506    /// Joins two instances into a single instance without checking whether they point to the same allocation.
507    ///
508    /// Unless `compile-time-ratio` is activated, the ratios are checked nevertheless.
509    ///
510    /// # Safety
511    ///
512    /// The caller must guarantee that those instances point to the same allocation.
513    ///
514    /// #   Panics
515    ///
516    /// If the compile-time-ratio feature is not used and the ratio is not preserved; that is `A + B <> NUM`.
517    ///
518    /// In debug, if the two instances do not point to the same allocation, as determined by `StaticRc::ptr_eq`.
519    ///
520    /// #   Example
521    ///
522    /// ```rust
523    /// use static_rc::StaticRc;
524    ///
525    /// type Full = StaticRc<i32, 3, 3>;
526    ///
527    /// let rc = Full::new(42);
528    /// let (one, two) = Full::split::<1, 2>(rc);
529    ///
530    /// let rc = unsafe { Full::join_unchecked(one, two) };
531    /// assert_eq!(42, *rc);
532    /// ```
533    #[inline(always)]
534    pub unsafe fn join_unchecked<const A: usize, const B: usize>(
535        left: StaticRc<T, A, DEN>,
536        right: StaticRc<T, B, DEN>,
537    ) -> Self
538    where
539        AssertEqType!(NUM, A + B): Sized,
540    {
541        #[cfg(debug_assertions)]
542        let (left, right) = Self::validate_pair(left, right);
543
544        Self::join_impl(left, right)
545    }
546
547    /// Joins DIM instances into a single instance.
548    ///
549    /// #   Panics
550    ///
551    /// If all instances do not point to the same allocation, as determined by `StaticRc::ptr_eq`.
552    ///
553    /// If the compile-time-ratio feature is not used and the ratio is not preserved; that is `N * DIM <> NUM`.
554    ///
555    /// #   Example
556    ///
557    /// ```rust
558    /// use static_rc::StaticRc;
559    ///
560    /// type Full = StaticRc<i32, 2, 2>;
561    ///
562    /// let rc = Full::new(42);
563    /// let array = Full::split_array::<1, 2>(rc);
564    /// let rc = Full::join_array(array);
565    ///
566    /// assert_eq!(42, *rc);
567    /// ```
568    #[inline(always)]
569    pub fn join_array<const N: usize, const DIM: usize>(array: [StaticRc<T, N, DEN>; DIM]) -> Self
570    where
571        AssertLeType!(1, NUM): Sized,
572        AssertEqType!(N * DIM, NUM): Sized,
573    {
574        let array = Self::validate_array(array);
575
576        unsafe { Self::join_array_impl(array) }
577    }
578
579    /// Joins DIM instances into a single instance.
580    ///
581    /// #   Panics
582    ///
583    /// If the compile-time-ratio feature is not used and the ratio is not preserved; that is `N * DIM <> NUM`.
584    ///
585    /// In debug, if all instances do not point to the same allocation, as determined by `StaticRc::ptr_eq`.
586    ///
587    /// #   Example
588    ///
589    /// ```rust
590    /// use static_rc::StaticRc;
591    ///
592    /// type Full = StaticRc<i32, 2, 2>;
593    ///
594    /// let rc = Full::new(42);
595    /// let array = Full::split_array::<1, 2>(rc);
596    /// let rc = unsafe { Full::join_array_unchecked(array) };
597    ///
598    /// assert_eq!(42, *rc);
599    /// ```
600    #[inline(always)]
601    pub unsafe fn join_array_unchecked<const N: usize, const DIM: usize>(array: [StaticRc<T, N, DEN>; DIM])
602        -> Self
603    where
604        AssertLeType!(1, NUM): Sized,
605        AssertEqType!(N * DIM, NUM): Sized,
606    {
607        #[cfg(debug_assertions)]
608        let array = Self::validate_array(array);
609
610        Self::join_array_impl(array)
611    }
612
613    //  Internal; joins without validating origin.
614    #[inline(always)]
615    unsafe fn join_impl<const A: usize, const B: usize>(
616        left: StaticRc<T, A, DEN>,
617        right: StaticRc<T, B, DEN>,
618    ) -> Self
619    where
620        AssertEqType!(NUM, A + B): Sized,
621    {
622        #[cfg(not(feature = "compile-time-ratio"))]
623        if NUM != A + B {
624            mem::forget(left);
625            mem::forget(right);
626
627            panic!("{} != {} + {}", NUM, A, B);
628        }
629
630        let pointer = left.pointer;
631        mem::forget(left);
632        mem::forget(right);
633
634        Self { pointer }
635    }
636
637    //  Internal; joins without validating origin.
638    #[inline(always)]
639    unsafe fn join_array_impl<const N: usize, const DIM: usize>(array: [StaticRc<T, N, DEN>; DIM])
640        -> Self
641    where
642        AssertLeType!(1, NUM): Sized,
643        AssertEqType!(N * DIM, NUM): Sized,
644    {
645        #[cfg(not(feature = "compile-time-ratio"))]
646        {
647            if NUM <= 0 {
648                mem::forget(array);
649
650                panic!("NUM <= 0");
651            }
652            if NUM != N * DIM {
653                mem::forget(array);
654
655                panic!("{} != {} * {}", NUM, N, DIM);
656            }
657        }
658
659        let pointer = array[0].pointer;
660        mem::forget(array);
661
662        Self { pointer, }
663    }
664
665    fn validate_pair<const A: usize, const B: usize>(left: StaticRc<T, A, DEN>, right: StaticRc<T, B, DEN>)
666        -> (StaticRc<T, A, DEN>, StaticRc<T, B, DEN>)
667    {
668        if StaticRc::ptr_eq(&left, &right) {
669            return (left, right);
670        }
671
672        let left = StaticRc::into_raw(left);
673        let right = StaticRc::into_raw(right);
674
675        panic!("Cannot join pair with multiple origins: {:?} != {:?}", left.as_ptr(), right.as_ptr());
676    }
677
678    fn validate_array<const N: usize, const DIM: usize>(array: [StaticRc<T, N, DEN>; DIM]) -> [StaticRc<T, N, DEN>; DIM] {
679        let first = &array[0];
680        let divergent = array[1..].iter().find(|e| !StaticRc::ptr_eq(&first, e));
681
682        if let Some(divergent) = divergent {
683            let first = first.pointer.as_ptr();
684            let divergent = divergent.pointer.as_ptr();
685
686            mem::forget(array);
687
688            panic!("Cannot join array with multiple origins: {:?} != {:?}", first, divergent);
689        }
690
691        array
692    } 
693}
694
695impl<const NUM: usize, const DEN: usize> StaticRc<dyn any::Any, NUM, DEN> {
696    /// Attempts to downcast `Self` to a concrete type.
697    pub fn downcast<T: any::Any>(self) -> Result<StaticRc<T, NUM, DEN>, Self> {
698        if Self::get_ref(&self).is::<T>() {
699            let pointer = Self::into_raw(self).cast::<T>();
700            Ok(StaticRc { pointer })
701        } else {
702            Err(self)
703        }
704    }
705}
706
707impl<T: ?Sized, const NUM: usize, const DEN: usize> Drop for StaticRc<T, NUM, DEN> {
708    #[inline(always)]
709    fn drop(&mut self) {
710        debug_assert_eq!(NUM, DEN, "{} != {}", NUM, DEN);
711
712        if NUM == DEN {
713            //  Safety:
714            //  -   Ratio = 1, hence full ownership.
715            //  -   `self.pointer` was allocated by Box.
716            unsafe { Box::from_raw(self.pointer.as_ptr()) };
717        }
718    }
719}
720
721impl<T: ?Sized, const N: usize> convert::AsMut<T> for StaticRc<T, N, N> {
722    #[inline(always)]
723    fn as_mut(&mut self) -> &mut T { Self::get_mut(self) }
724}
725
726impl<T: ?Sized, const NUM: usize, const DEN: usize> convert::AsRef<T> for StaticRc<T, NUM, DEN> {
727    #[inline(always)]
728    fn as_ref(&self) -> &T { Self::get_ref(self) }
729}
730
731impl<T: ?Sized, const NUM: usize, const DEN: usize> borrow::Borrow<T> for StaticRc<T, NUM, DEN> {
732    #[inline(always)]
733    fn borrow(&self) -> &T { Self::get_ref(self) }
734}
735
736impl<T: ?Sized, const N: usize> borrow::BorrowMut<T> for StaticRc<T, N, N> {
737    #[inline(always)]
738    fn borrow_mut(&mut self) -> &mut T { Self::get_mut(self) }
739}
740
741#[cfg(feature = "nightly-coerce-unsized")]
742impl<T, U, const NUM: usize, const DEN: usize> CoerceUnsized<StaticRc<U, NUM, DEN>> for StaticRc<T, NUM, DEN>
743where
744    T: ?Sized + marker::Unsize<U>,
745    U: ?Sized,
746{}
747
748impl<T: ?Sized + fmt::Debug, const NUM: usize, const DEN: usize> fmt::Debug for StaticRc<T, NUM, DEN> {
749    #[inline(always)]
750    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
751        fmt::Debug::fmt(Self::get_ref(self), f)
752    }
753}
754
755impl<T: Default, const N: usize> Default for StaticRc<T, N, N>
756where
757    AssertLeType!(1, N): Sized,
758{
759    #[inline(always)]
760    fn default() -> Self { Self::new(T::default()) }
761}
762
763impl<T: ?Sized, const NUM: usize, const DEN: usize> ops::Deref for StaticRc<T, NUM, DEN> {
764    type Target = T;
765
766    #[inline(always)]
767    fn deref(&self) -> &T { Self::get_ref(self) }
768}
769
770impl<T: ?Sized, const N: usize> ops::DerefMut for StaticRc<T, N, N> {
771    #[inline(always)]
772    fn deref_mut(&mut self) -> &mut T { Self::get_mut(self) }
773}
774
775impl<T: ?Sized + fmt::Display, const NUM: usize, const DEN: usize> fmt::Display for StaticRc<T, NUM, DEN> {
776    #[inline(always)]
777    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
778        fmt::Display::fmt(Self::get_ref(self), f)
779    }
780}
781
782#[cfg(feature = "nightly-dispatch-from-dyn")]
783impl<T, U, const NUM: usize, const DEN: usize> DispatchFromDyn<StaticRc<U, NUM, DEN>> for StaticRc<T, NUM, DEN>
784where
785    T: ?Sized + marker::Unsize<U>,
786    U: ?Sized,
787{}
788
789impl<I: iter::DoubleEndedIterator + ?Sized, const N: usize> iter::DoubleEndedIterator for StaticRc<I, N, N> {
790    #[inline(always)]
791    fn next_back(&mut self) -> Option<I::Item> { Self::get_mut(self).next_back() }
792
793    #[inline(always)]
794    fn nth_back(&mut self, n: usize) -> Option<I::Item> { Self::get_mut(self).nth_back(n) }
795}
796
797impl<T: ?Sized + cmp::Eq, const NUM: usize, const DEN: usize> cmp::Eq for StaticRc<T, NUM, DEN> {}
798
799impl<I: iter::ExactSizeIterator + ?Sized, const N: usize> iter::ExactSizeIterator for StaticRc<I, N, N> {
800    #[inline(always)]
801    fn len(&self) -> usize { Self::get_ref(self).len() }
802}
803
804impl<T: ?Sized, const N: usize> From<Box<T>> for StaticRc<T, N, N> {
805    #[inline(always)]
806    fn from(value: Box<T>) -> Self {
807        let pointer = NonNull::from(Box::leak(value));
808        Self { pointer }
809    }
810}
811
812impl<T: Copy, const N: usize> From<&'_ [T]> for StaticRc<[T], N, N> {
813    #[inline(always)]
814    fn from(value: &[T]) -> Self { Self::from(Box::from(value)) }
815}
816
817impl<const N: usize> From<&'_ str> for StaticRc<str, N, N> {
818    #[inline(always)]
819    fn from(value: &str) -> Self { Self::from(Box::from(value)) }
820}
821
822impl<T, const LEN: usize, const N: usize> From<[T; LEN]> for StaticRc<[T], N, N> {
823    #[inline(always)]
824    fn from(value: [T; LEN]) -> Self { Self::from(Box::from(value)) }
825}
826
827impl<T: Copy, const N: usize> From<alloc::borrow::Cow<'_, [T]>> for StaticRc<[T], N, N> {
828    #[inline(always)]
829    fn from(value: alloc::borrow::Cow<'_, [T]>) -> Self { Self::from(Box::from(value)) }
830}
831
832impl<const N: usize> From<alloc::borrow::Cow<'_, str>> for StaticRc<str, N, N> {
833    #[inline(always)]
834    fn from(value: alloc::borrow::Cow<'_, str>) -> Self { Self::from(Box::from(value)) }
835}
836
837impl<const N: usize> From<alloc::string::String> for StaticRc<str, N, N> {
838    #[inline(always)]
839    fn from(value: alloc::string::String) -> Self { Self::from(Box::from(value)) }
840}
841
842impl<T, const N: usize> From<T> for StaticRc<T, N, N> {
843    #[inline(always)]
844    fn from(value: T) -> Self { Self::from(Box::from(value)) }
845}
846
847impl<T, const N: usize> From<alloc::vec::Vec<T>> for StaticRc<[T], N, N> {
848    #[inline(always)]
849    fn from(value: alloc::vec::Vec<T>) -> Self { Self::from(Box::from(value)) }
850}
851
852impl<T, const N: usize> From<StaticRc<[T], N, N>> for alloc::vec::Vec<T> {
853    #[inline(always)]
854    fn from(value: StaticRc<[T], N, N>) -> Self { Self::from(StaticRc::into_box(value)) }
855}
856
857impl<T: ?Sized, const N: usize> From<StaticRc<T, N, N>> for alloc::rc::Rc<T> {
858    #[inline(always)]
859    fn from(value: StaticRc<T, N, N>) -> Self { Self::from(StaticRc::into_box(value)) }
860}
861
862impl<T: ?Sized, const N: usize> From<StaticRc<T, N, N>> for alloc::sync::Arc<T> {
863    #[inline(always)]
864    fn from(value: StaticRc<T, N, N>) -> Self { Self::from(StaticRc::into_box(value)) }
865}
866
867impl<const N: usize> From<StaticRc<str, N, N>> for alloc::string::String {
868    #[inline(always)]
869    fn from(value: StaticRc<str, N, N>) -> Self { Self::from(StaticRc::into_box(value)) }
870}
871
872impl<const NUM: usize, const DEN: usize> From<StaticRc<str, NUM, DEN>> for StaticRc<[u8], NUM, DEN> {
873    #[inline(always)]
874    fn from(value: StaticRc<str, NUM, DEN>) -> Self {
875        let pointer = value.pointer.as_ptr() as *mut [u8];
876        mem::forget(value);
877
878        //  Safety:
879        //  -   `value.pointer` was not null, hence `pointer` is not null.
880        debug_assert!(!pointer.is_null());
881        let pointer = unsafe { NonNull::new_unchecked(pointer) };
882
883        Self { pointer }
884    }
885}
886
887impl<const N: usize> iter::FromIterator<StaticRc<str, N, N>> for alloc::string::String {
888    #[inline(always)]
889    fn from_iter<I: IntoIterator<Item = StaticRc<str, N, N>>>(iter: I) -> Self {
890        Self::from_iter(iter.into_iter().map(StaticRc::into_box))
891    }
892}
893
894impl<T, const N: usize> iter::FromIterator<T> for StaticRc<[T], N, N> {
895    #[inline(always)]
896    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { Self::from(Box::from_iter(iter)) }
897}
898
899impl<I: iter::FusedIterator + ?Sized, const N: usize> iter::FusedIterator for StaticRc<I, N, N> {}
900
901impl<F: ?Sized + future::Future + marker::Unpin, const N: usize> future::Future for StaticRc<F, N, N> {
902    type Output = F::Output;
903
904    fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
905        F::poll(pin::Pin::new(&mut *self), cx)
906    }
907}
908
909#[cfg(feature = "nightly-generator-trait")]
910impl<G: ?Sized + ops::Generator<R> + marker::Unpin, R, const N: usize> ops::Generator<R> for StaticRc<G, N, N> {
911    type Yield = G::Yield;
912    type Return = G::Return;
913
914        fn resume(mut self: pin::Pin<&mut Self>, arg: R) -> ops::GeneratorState<Self::Yield, Self::Return> {
915            G::resume(pin::Pin::new(&mut *self), arg)
916        }
917}
918
919#[cfg(feature = "nightly-generator-trait")]
920impl<G: ?Sized + ops::Generator<R>, R, const N: usize> ops::Generator<R> for pin::Pin<StaticRc<G, N, N>> {
921    type Yield = G::Yield;
922    type Return = G::Return;
923
924        fn resume(mut self: pin::Pin<&mut Self>, arg: R) -> ops::GeneratorState<Self::Yield, Self::Return> {
925            G::resume((*self).as_mut(), arg)
926        }
927}
928
929impl<T: ?Sized + hash::Hash, const NUM: usize, const DEN: usize> hash::Hash for StaticRc<T, NUM, DEN> {
930    #[inline(always)]
931    fn hash<H: hash::Hasher>(&self, state: &mut H) {
932        Self::get_ref(self).hash(state);
933    }
934}
935
936impl<I: iter::Iterator + ?Sized, const N: usize> iter::Iterator for StaticRc<I, N, N> {
937    type Item = I::Item;
938
939    #[inline(always)]
940    fn next(&mut self) -> Option<I::Item> { Self::get_mut(self).next() }
941
942    #[inline(always)]
943    fn size_hint(&self) -> (usize, Option<usize>) { Self::get_ref(self).size_hint() }
944
945    #[inline(always)]
946    fn nth(&mut self, n: usize) -> Option<I::Item> { Self::get_mut(self).nth(n) }
947
948    #[inline(always)]
949    fn last(self) -> Option<I::Item> { Self::into_box(self).last() }
950}
951
952impl<T: ?Sized + cmp::Ord, const NUM: usize, const DEN: usize> cmp::Ord for StaticRc<T, NUM, DEN> {
953    #[inline(always)]
954    fn cmp(&self, other: &Self) -> cmp::Ordering {
955        if Self::ptr_eq(self, other) {
956            cmp::Ordering::Equal
957        } else {
958            Self::get_ref(self).cmp(Self::get_ref(other))
959        }
960    }
961}
962
963impl<T, const NUM: usize, const DEN: usize, const N: usize, const D: usize> cmp::PartialEq<StaticRc<T, N, D>>
964    for StaticRc<T, NUM, DEN>
965where
966    T: ?Sized + PartialEq<T>
967{
968    #[inline(always)]
969    fn eq(&self, other: &StaticRc<T, N, D>) -> bool { Self::get_ref(self).eq(StaticRc::get_ref(other)) }
970
971    #[inline(always)]
972    fn ne(&self, other: &StaticRc<T, N, D>) -> bool { Self::get_ref(self).ne(StaticRc::get_ref(other)) }
973}
974
975impl<T, const NUM: usize, const DEN: usize, const N: usize, const D: usize> cmp::PartialOrd<StaticRc<T, N, D>>
976    for StaticRc<T, NUM, DEN>
977where
978    T: ?Sized + PartialOrd<T>
979{
980    #[inline(always)]
981    fn partial_cmp(&self, other: &StaticRc<T, N, D>) -> Option<cmp::Ordering> {
982        Self::get_ref(self).partial_cmp(StaticRc::get_ref(other))
983    }
984
985    #[inline(always)]
986    fn lt(&self, other: &StaticRc<T, N, D>) -> bool {
987        Self::get_ref(self).lt(StaticRc::get_ref(other))
988    }
989
990    #[inline(always)]
991    fn le(&self, other: &StaticRc<T, N, D>) -> bool {
992        Self::get_ref(self).le(StaticRc::get_ref(other))
993    }
994
995    #[inline(always)]
996    fn gt(&self, other: &StaticRc<T, N, D>) -> bool {
997        Self::get_ref(self).gt(StaticRc::get_ref(other))
998    }
999
1000    #[inline(always)]
1001    fn ge(&self, other: &StaticRc<T, N, D>) -> bool {
1002        Self::get_ref(self).ge(StaticRc::get_ref(other))
1003    }
1004}
1005
1006impl<T: ?Sized, const NUM: usize, const DEN: usize> fmt::Pointer for StaticRc<T, NUM, DEN> {
1007    #[inline(always)]
1008    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1009        fmt::Pointer::fmt(&Self::as_ptr(self).as_ptr(), f)
1010    }
1011}
1012
1013#[cfg(feature = "nightly-async-iterator")]
1014impl<S: ?Sized + async_iter::AsyncIterator + marker::Unpin, const N: usize> async_iter::AsyncIterator for StaticRc<S, N, N> {
1015    type Item = S::Item;
1016
1017    fn poll_next(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Option<Self::Item>> {
1018        pin::Pin::new(&mut **self).poll_next(cx)
1019    }
1020
1021    fn size_hint(&self) -> (usize, Option<usize>) { (**self).size_hint() }
1022}
1023
1024impl<T: ?Sized, const NUM: usize, const DEN: usize> marker::Unpin for StaticRc<T, NUM, DEN> {}
1025
1026unsafe impl<T: ?Sized + marker::Send, const NUM: usize, const DEN: usize> marker::Send for StaticRc<T, NUM, DEN> {}
1027
1028unsafe impl<T: ?Sized + marker::Sync, const NUM: usize, const DEN: usize> marker::Sync for StaticRc<T, NUM, DEN> {}
1029
1030#[doc(hidden)]
1031pub mod compile_tests {
1032
1033/// ```compile_fail,E0505
1034/// let mut a = String::from("foo");
1035/// let mut rc = static_rc::StaticRc::<_,1,1>::new(a);
1036/// 
1037/// let mut reborrow = static_rc::StaticRc::as_rcref(&mut rc);
1038/// std::mem::drop(rc);
1039/// assert_eq!(*reborrow, "foo"); // This should fail to compile.
1040/// ```
1041pub fn rc_reborrow_and_move() {}
1042
1043/// ```compile_fail,E0502
1044/// let mut a = String::from("foo");
1045/// let mut rc = static_rc::StaticRc::<_,1,1>::new(a);
1046/// 
1047/// let mut reborrow = static_rc::StaticRc::as_rcref(&mut rc);
1048/// assert_eq!(*rc, "foo");
1049/// assert_eq!(*reborrow, "foo"); // This should fail to compile.
1050/// ```
1051pub fn rc_reborrow_and_use() {}
1052
1053} // mod compile_tests
1054
1055#[doc(hidden)]
1056#[cfg(feature = "compile-time-ratio")]
1057pub mod compile_ratio_tests {
1058
1059/// ```compile_fail,E0080
1060/// type Zero = static_rc::StaticRc<i32, 0, 0>;
1061///
1062/// Zero::new(42);
1063/// ```
1064pub fn rc_new_zero() {}
1065
1066/// ```compile_fail,E0080
1067/// type Zero = static_rc::StaticRc<i32, 0, 0>;
1068///
1069/// Zero::pin(42);
1070/// ```
1071pub fn rc_pin_zero() {}
1072
1073/// ```compile_fail,E0080
1074/// type Zero = static_rc::StaticRc<i32, 0, 0>;
1075///
1076/// let pointer = core::ptr::NonNull::dangling();
1077///
1078/// unsafe { Zero::from_raw(pointer) };
1079/// ```
1080pub fn rc_from_raw_zero() {}
1081
1082/// ```compile_fail,E0080
1083/// type One = static_rc::StaticRc<i32, 1, 1>;
1084///
1085/// let rc = One::new(42);
1086///
1087/// One::adjust::<0, 0>(rc);
1088/// ```
1089pub fn rc_adjust_zero() {}
1090
1091/// ```compile_fail,E0080
1092/// type One = static_rc::StaticRc<i32, 1, 1>;
1093///
1094/// let rc = One::new(42);
1095///
1096/// One::adjust::<2, 3>(rc);
1097/// ```
1098pub fn rc_adjust_ratio() {}
1099
1100/// ```compile_fail,E0080
1101/// type Two = static_rc::StaticRc<i32, 2, 2>;
1102///
1103/// let rc = Two::new(42);
1104///
1105/// Two::split::<0, 2>(rc);
1106/// ```
1107pub fn rc_split_zero_first() {}
1108
1109/// ```compile_fail,E0080
1110/// type Two = static_rc::StaticRc<i32, 2, 2>;
1111///
1112/// let rc = Two::new(42);
1113///
1114/// Two::split::<2, 0>(rc);
1115/// ```
1116pub fn rc_split_zero_second() {}
1117
1118/// ```compile_fail,E0080
1119/// type Two = static_rc::StaticRc<i32, 2, 2>;
1120///
1121/// let rc = Two::new(42);
1122///
1123/// Two::split::<1, 2>(rc);
1124/// ```
1125pub fn rc_split_sum() {}
1126
1127/// ```compile_fail,E0080
1128/// type Two = static_rc::StaticRc<i32, 2, 2>;
1129///
1130/// let rc = Two::new(42);
1131///
1132/// Two::split_array::<2, 2>(rc);
1133/// ```
1134pub fn rc_split_array_ratio() {}
1135
1136/// ```compile_fail,E0080
1137/// type Two = static_rc::StaticRc<i32, 2, 2>;
1138///
1139/// let rc = Two::new(42);
1140/// let (one, two) = Two::split::<1, 1>(rc);
1141///
1142/// static_rc::StaticRc::<_, 1, 2>::join(one, two);
1143/// ```
1144pub fn rc_join_ratio() {}
1145
1146/// ```compile_fail,E0080
1147/// type Two = static_rc::StaticRc<i32, 2, 2>;
1148///
1149/// let rc = Two::new(42);
1150/// let (one, two) = Two::split::<1, 1>(rc);
1151///
1152/// unsafe { static_rc::StaticRc::<_, 1, 2>::join_unchecked(one, two) };
1153/// ```
1154pub fn rc_join_unchecked_ratio() {}
1155
1156/// ```compile_fail,E0080
1157/// type Two = static_rc::StaticRc<i32, 2, 2>;
1158///
1159/// let rc = Two::new(42);
1160/// let array: [_; 2] = Two::split_array::<1, 2>(rc);
1161///
1162/// static_rc::StaticRc::<_, 1, 2>::join_array(array);
1163/// ```
1164pub fn rc_join_array_ratio() {}
1165
1166/// ```compile_fail,E0080
1167/// type Two = static_rc::StaticRc<i32, 2, 2>;
1168///
1169/// let rc = Two::new(42);
1170/// let array: [_; 2] = Two::split_array::<1, 2>(rc);
1171///
1172/// unsafe { static_rc::StaticRc::<_, 1, 2>::join_array_unchecked(array) };
1173/// ```
1174pub fn rc_join_array_unchecked_ratio() {}
1175
1176} // mod compile_ratio_tests
1177
1178#[cfg(all(test, not(feature = "compile-time-ratio")))]
1179mod panic_ratio_tests {
1180
1181use super::*;
1182
1183type Zero = StaticRc<i32, 0, 0>;
1184type One = StaticRc<i32, 1, 1>;
1185type Two = StaticRc<i32, 2, 2>;
1186
1187#[test]
1188#[should_panic]
1189fn rc_new_zero() {
1190    Zero::new(42);
1191}
1192
1193#[test]
1194#[should_panic]
1195fn rc_pin_zero() {
1196    Zero::pin(42);
1197}
1198
1199#[test]
1200#[should_panic]
1201fn rc_from_raw_zero() {
1202    let pointer = NonNull::dangling();
1203
1204    unsafe { Zero::from_raw(pointer) };
1205}
1206
1207#[test]
1208#[should_panic]
1209fn rc_adjust_zero() {
1210    let rc = One::new(42);
1211
1212    One::adjust::<0, 0>(rc);
1213}
1214
1215#[test]
1216#[should_panic]
1217fn rc_adjust_ratio() {
1218    let rc = One::new(42);
1219
1220    One::adjust::<2, 3>(rc);
1221}
1222
1223#[test]
1224#[should_panic]
1225fn rc_split_zero_first() {
1226    let rc = Two::new(42);
1227
1228    Two::split::<0, 2>(rc);
1229}
1230
1231#[test]
1232#[should_panic]
1233fn rc_split_zero_second() {
1234    let rc = Two::new(42);
1235
1236    Two::split::<0, 2>(rc);
1237}
1238
1239#[test]
1240#[should_panic]
1241fn rc_split_sum() {
1242    let rc = Two::new(42);
1243
1244    Two::split::<1, 2>(rc);
1245}
1246
1247#[test]
1248#[should_panic]
1249fn rc_split_array_ratio() {
1250    let rc = Two::new(42);
1251
1252    Two::split_array::<2, 2>(rc);
1253}
1254
1255#[test]
1256#[should_panic]
1257fn rc_join_ratio() {
1258    let rc = Two::new(42);
1259    will_leak(&rc);
1260
1261    let (one, two) = Two::split::<1, 1>(rc);
1262
1263    StaticRc::<_, 1, 2>::join(one, two);
1264}
1265
1266#[test]
1267#[should_panic]
1268fn rc_join_different() {
1269    let (rc, other) = (Two::new(42), Two::new(33));
1270    will_leak(&rc);
1271    will_leak(&other);
1272
1273    let (one, two) = Two::split::<1, 1>(rc);
1274    let (other_one, other_two) = Two::split::<1, 1>(other);
1275
1276    mem::forget([two, other_two]);
1277
1278    Two::join(one, other_one);
1279}
1280
1281#[test]
1282#[should_panic]
1283fn rc_join_unchecked_ratio() {
1284    let rc = Two::new(42);
1285    will_leak(&rc);
1286
1287    let (one, two) = Two::split::<1, 1>(rc);
1288
1289    unsafe { StaticRc::<_, 1, 2>::join_unchecked(one, two) };
1290}
1291
1292#[test]
1293#[should_panic]
1294fn rc_join_array_ratio() {
1295    let rc = Two::new(42);
1296    will_leak(&rc);
1297
1298    let array: [_; 2] = Two::split_array::<1, 2>(rc);
1299
1300    StaticRc::<_, 1, 2>::join_array(array);
1301}
1302
1303#[test]
1304#[should_panic]
1305fn rc_join_array_different() {
1306    let (rc, other) = (Two::new(42), Two::new(33));
1307    will_leak(&rc);
1308    will_leak(&other);
1309
1310    let (one, two) = Two::split::<1, 1>(rc);
1311    let (other_one, other_two) = Two::split::<1, 1>(other);
1312
1313    mem::forget([two, other_two]);
1314
1315    Two::join_array([one, other_one]);
1316}
1317
1318#[test]
1319#[should_panic]
1320fn rc_join_array_unchecked_ratio() {
1321    let rc = Two::new(42);
1322    will_leak(&rc);
1323
1324    let array = Two::split_array::<1, 2>(rc);
1325
1326    unsafe { StaticRc::<_, 1, 2>::join_array_unchecked(array) };
1327}
1328
1329//  Indicates that the pointed to memory will be leaked, to avoid it being reported.
1330fn will_leak<T, const NUM: usize, const DEN: usize>(_rc: &StaticRc<T, NUM, DEN>) {
1331    #[cfg(miri)]
1332    {
1333        unsafe { miri_static_root(StaticRc::as_ptr(_rc).as_ptr() as *const u8) };
1334    }
1335}
1336
1337#[cfg(miri)]
1338extern "Rust" {
1339    /// Miri-provided extern function to mark the block `ptr` points to as a "root"
1340    /// for some static memory. This memory and everything reachable by it is not
1341    /// considered leaking even if it still exists when the program terminates.
1342    ///
1343    /// `ptr` has to point to the beginning of an allocated block.
1344    fn miri_static_root(ptr: *const u8);
1345}
1346
1347} // mod panic_ratio_tests