Skip to main content

jrsonnet_gcmodule/
trace_impls.rs

1use std::borrow::{Borrow, BorrowMut};
2use std::ops::{Deref, DerefMut};
3
4use crate::Acyclic;
5use crate::trace::{Trace, Tracer};
6
7/// Mark types as acyclic. Opt-out the cycle collector.
8///
9/// See [`Trace::is_type_tracked`](trait.Trace.html#method.is_type_tracked) for details.
10/// In general, types including trait objects (directly or indirectly) should
11/// not be acyclic.
12///
13/// ## Examples
14///
15/// ```
16/// use jrsonnet_gcmodule::trace_acyclic;
17///
18/// struct X(u32);
19/// struct Y(String);
20/// struct Z<T>(fn (T));
21///
22/// trace_acyclic!(X);
23/// trace_acyclic!(Y);
24/// trace_acyclic!(<T> Z<T>);
25/// ```
26#[macro_export]
27macro_rules! trace_acyclic {
28    ( <$( $g:ident ),*> $( $t: tt )* ) => {
29        impl<$( $g: 'static + $crate::Acyclic ),*> $crate::Trace for $($t)* {
30            #[inline]
31            fn is_type_tracked() -> bool where Self: Sized { false }
32        }
33        unsafe impl<$( $g: 'static + $crate::Acyclic ),*> $crate::Acyclic for $($t)* {}
34    };
35    ( $( $t: ty ),* ) => {
36        $( trace_acyclic!(<> $t); )*
37    };
38}
39
40/// Implement [`Trace`](trait.Trace.html) for simple container types.
41///
42/// ## Examples
43///
44/// ```
45/// use jrsonnet_gcmodule::Trace;
46/// use jrsonnet_gcmodule::trace_fields;
47///
48/// struct X<T1, T2> { a: T1, b: T2 };
49/// struct Y<T>(Box<T>);
50/// struct Z(Box<dyn Trace>);
51///
52/// trace_fields!(
53///     X<T1, T2> { a: T1, b: T2 }
54///     Y<T> { 0: T }
55///     Z { 0 }
56/// );
57/// ```
58#[macro_export]
59macro_rules! trace_fields {
60    ( $( $type:ty { $( $field:tt $(: $tp:ident )? ),* } )* ) => {
61        $(
62            impl< $( $( $tp: $crate::Trace )? ),* > $crate::Trace for $type {
63                fn trace(&self, tracer: &mut $crate::Tracer) {
64                    let _ = tracer;
65                    $( (&self . $field ).trace(tracer); )*
66                }
67                #[inline]
68                fn is_type_tracked() -> bool {
69                    $( $( if $tp::is_type_tracked() { return true } )? )*
70                    false
71                }
72            }
73            unsafe impl< $( $( $tp: $crate::Acyclic )? ),* > $crate::Acyclic for $type {}
74        )*
75    };
76}
77
78trace_acyclic!(
79    bool, char, f32, f64, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize
80);
81trace_acyclic!(());
82trace_acyclic!(String, &'static str);
83
84mod tuples {
85    trace_fields!(
86        (A,) { 0: A }
87        (A, B,) { 0: A, 1: B }
88        (A, B, C,) { 0: A, 1: B, 2: C }
89        (A, B, C, D,) { 0: A, 1: B, 2: C, 3: D }
90        (A, B, C, D, E,) { 0: A, 1: B, 2: C, 3: D, 4: E }
91        (A, B, C, D, E, F,) { 0: A, 1: B, 2: C, 3: D, 4: E, 5: F }
92        (A, B, C, D, E, F, G,) { 0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G }
93    );
94}
95
96mod borrow {
97    use super::{Acyclic, Trace, Tracer};
98    use std::borrow::Cow;
99
100    impl<T: ToOwned + ?Sized> Trace for Cow<'static, T>
101    where
102        T::Owned: Trace,
103    {
104        fn trace(&self, tracer: &mut Tracer) {
105            if let Cow::Owned(v) = self {
106                v.trace(tracer);
107            }
108        }
109
110        #[inline]
111        fn is_type_tracked() -> bool {
112            T::Owned::is_type_tracked()
113        }
114    }
115    unsafe impl<T: ToOwned + ?Sized> Acyclic for Cow<'static, T> where T::Owned: Acyclic {}
116}
117
118mod boxed {
119    use super::{Acyclic, Trace, Tracer};
120    impl<T: Trace> Trace for Box<T> {
121        fn trace(&self, tracer: &mut Tracer) {
122            self.as_ref().trace(tracer);
123        }
124
125        #[inline]
126        fn is_type_tracked() -> bool {
127            T::is_type_tracked()
128        }
129    }
130    unsafe impl<T: Acyclic> Acyclic for Box<T> {}
131}
132
133mod cell {
134    use super::{Acyclic, Trace, Tracer};
135    use std::cell::{Cell, OnceCell, RefCell};
136
137    impl<T: Copy + Trace> Trace for Cell<T> {
138        fn trace(&self, tracer: &mut Tracer) {
139            self.get().trace(tracer);
140        }
141
142        #[inline]
143        fn is_type_tracked() -> bool {
144            T::is_type_tracked()
145        }
146    }
147    unsafe impl<T: Acyclic + Copy> Acyclic for Cell<T> {}
148
149    impl<T: Trace> Trace for RefCell<T> {
150        fn trace(&self, tracer: &mut Tracer) {
151            // If the RefCell is currently borrowed we
152            // assume there's an outstanding reference to this
153            // cycle so it's ok if we don't trace through it.
154            // If the borrow gets leaked somehow then we're going
155            // to leak the cycle.
156            if let Ok(x) = self.try_borrow() {
157                x.trace(tracer);
158            }
159        }
160
161        #[inline]
162        fn is_type_tracked() -> bool {
163            T::is_type_tracked()
164        }
165    }
166    unsafe impl<T: Acyclic> Acyclic for RefCell<T> {}
167
168    impl<T: Trace> Trace for OnceCell<T> {
169        fn trace(&self, tracer: &mut Tracer) {
170            if let Some(x) = self.get() {
171                x.trace(tracer);
172            }
173        }
174
175        #[inline]
176        fn is_type_tracked() -> bool {
177            T::is_type_tracked()
178        }
179    }
180    unsafe impl<T: Acyclic> Acyclic for OnceCell<T> {}
181}
182
183#[cfg(feature = "im-rc")]
184mod im_collections {
185    use super::*;
186    use im_rc::{HashMap, HashSet, OrdMap, OrdSet, Vector};
187    impl<T: Trace + Clone> Trace for Vector<T> {
188        fn trace(&self, tracer: &mut Tracer) {
189            let _ = tracer;
190            for v in self.iter() {
191                v.trace(tracer);
192            }
193        }
194
195        fn is_type_tracked() -> bool
196        where
197            Self: Sized,
198        {
199            T::is_type_tracked()
200        }
201    }
202    impl<T: Trace + Clone, H: 'static> Trace for HashSet<T, H> {
203        fn trace(&self, tracer: &mut Tracer) {
204            let _ = tracer;
205            for v in self.iter() {
206                v.trace(tracer);
207            }
208        }
209
210        fn is_type_tracked() -> bool
211        where
212            Self: Sized,
213        {
214            T::is_type_tracked()
215        }
216    }
217    impl<T: Trace + Clone + Ord> Trace for OrdSet<T> {
218        fn trace(&self, tracer: &mut Tracer) {
219            let _ = tracer;
220            for v in self.iter() {
221                v.trace(tracer);
222            }
223        }
224
225        fn is_type_tracked() -> bool
226        where
227            Self: Sized,
228        {
229            T::is_type_tracked()
230        }
231    }
232    impl<K: Trace + Clone, V: Trace + Clone, H: 'static> Trace for HashMap<K, V, H> {
233        fn trace(&self, tracer: &mut Tracer) {
234            let _ = tracer;
235            for (k, v) in self.iter() {
236                k.trace(tracer);
237                v.trace(tracer);
238            }
239        }
240
241        fn is_type_tracked() -> bool
242        where
243            Self: Sized,
244        {
245            K::is_type_tracked() || V::is_type_tracked()
246        }
247    }
248    impl<K: Trace + Clone + Ord, V: Trace + Clone> Trace for OrdMap<K, V> {
249        fn trace(&self, tracer: &mut Tracer) {
250            let _ = tracer;
251            for (k, v) in self.iter() {
252                k.trace(tracer);
253                v.trace(tracer);
254            }
255        }
256
257        fn is_type_tracked() -> bool
258        where
259            Self: Sized,
260        {
261            K::is_type_tracked() || V::is_type_tracked()
262        }
263    }
264}
265
266mod collections {
267    use super::{Acyclic, Trace, Tracer};
268    use std::collections::{BTreeMap, HashMap, HashSet, LinkedList, VecDeque};
269    use std::hash::Hash;
270
271    impl<K: Trace, V: Trace> Trace for BTreeMap<K, V> {
272        fn trace(&self, tracer: &mut Tracer) {
273            for (k, v) in self {
274                k.trace(tracer);
275                v.trace(tracer);
276            }
277        }
278
279        #[inline]
280        fn is_type_tracked() -> bool {
281            K::is_type_tracked() || V::is_type_tracked()
282        }
283    }
284    unsafe impl<K: Acyclic, V: Acyclic> Acyclic for BTreeMap<K, V> {}
285
286    impl<K: Eq + Hash + Trace, H: 'static> Trace for HashSet<K, H> {
287        fn trace(&self, tracer: &mut Tracer) {
288            for k in self {
289                k.trace(tracer);
290            }
291        }
292
293        #[inline]
294        fn is_type_tracked() -> bool {
295            K::is_type_tracked()
296        }
297    }
298    unsafe impl<K: Acyclic + Hash + Eq, H: 'static> Acyclic for HashSet<K, H> {}
299
300    impl<K: Eq + Hash + Trace, V: Trace, H: 'static> Trace for HashMap<K, V, H> {
301        fn trace(&self, tracer: &mut Tracer) {
302            for (k, v) in self {
303                k.trace(tracer);
304                v.trace(tracer);
305            }
306        }
307
308        #[inline]
309        fn is_type_tracked() -> bool {
310            K::is_type_tracked() || V::is_type_tracked()
311        }
312    }
313    unsafe impl<K: Acyclic + Hash + Eq, V: Acyclic, H: 'static> Acyclic for HashMap<K, V, H> {}
314
315    impl<T: Trace> Trace for LinkedList<T> {
316        fn trace(&self, tracer: &mut Tracer) {
317            for t in self {
318                t.trace(tracer);
319            }
320        }
321
322        #[inline]
323        fn is_type_tracked() -> bool {
324            T::is_type_tracked()
325        }
326    }
327    unsafe impl<T: Acyclic> Acyclic for LinkedList<T> {}
328
329    impl<T: Trace> Trace for VecDeque<T> {
330        fn trace(&self, tracer: &mut Tracer) {
331            for t in self {
332                t.trace(tracer);
333            }
334        }
335
336        #[inline]
337        fn is_type_tracked() -> bool {
338            T::is_type_tracked()
339        }
340    }
341    unsafe impl<T: Acyclic> Acyclic for VecDeque<T> {}
342}
343
344mod rustc_hash {}
345
346mod vec {
347    use super::{Acyclic, Trace, Tracer};
348    impl<T: Trace> Trace for Vec<T> {
349        fn trace(&self, tracer: &mut Tracer) {
350            for t in self {
351                t.trace(tracer);
352            }
353        }
354
355        #[inline]
356        fn is_type_tracked() -> bool {
357            T::is_type_tracked()
358        }
359    }
360    unsafe impl<T: Acyclic> Acyclic for Vec<T> {}
361}
362
363mod slice {
364    use crate::{Acyclic, Trace, Tracer};
365
366    impl<T: Trace> Trace for [T] {
367        fn trace(&self, tracer: &mut Tracer) {
368            for t in self {
369                t.trace(tracer);
370            }
371        }
372    }
373    unsafe impl<T: Acyclic> Acyclic for [T] {}
374}
375
376// See https://github.com/rust-lang/rust/issues/56105#issuecomment-465709105
377#[allow(unknown_lints)]
378#[allow(coherence_leak_check)]
379mod func {
380    trace_acyclic!(<X> fn() -> X);
381
382    trace_acyclic!(<A, X> fn(&A) -> X);
383    trace_acyclic!(<A, X> fn(A) -> X);
384
385    trace_acyclic!(<A, B, X> fn(&A, &B) -> X);
386    trace_acyclic!(<A, B, X> fn(A, &B) -> X);
387    trace_acyclic!(<A, B, X> fn(&A, B) -> X);
388    trace_acyclic!(<A, B, X> fn(A, B) -> X);
389
390    trace_acyclic!(<A, B, C, X> fn(&A, &B, &C) -> X);
391    trace_acyclic!(<A, B, C, X> fn(A, &B, &C) -> X);
392    trace_acyclic!(<A, B, C, X> fn(&A, B, &C) -> X);
393    trace_acyclic!(<A, B, C, X> fn(A, B, &C) -> X);
394    trace_acyclic!(<A, B, C, X> fn(&A, &B, C) -> X);
395    trace_acyclic!(<A, B, C, X> fn(A, &B, C) -> X);
396    trace_acyclic!(<A, B, C, X> fn(&A, B, C) -> X);
397    trace_acyclic!(<A, B, C, X> fn(A, B, C) -> X);
398
399    trace_acyclic!(<A, B, C, D, X> fn(&A, &B, &C, &D) -> X);
400    trace_acyclic!(<A, B, C, D, X> fn(A, &B, &C, &D) -> X);
401    trace_acyclic!(<A, B, C, D, X> fn(&A, B, &C, &D) -> X);
402    trace_acyclic!(<A, B, C, D, X> fn(A, B, &C, &D) -> X);
403    trace_acyclic!(<A, B, C, D, X> fn(&A, &B, C, &D) -> X);
404    trace_acyclic!(<A, B, C, D, X> fn(A, &B, C, &D) -> X);
405    trace_acyclic!(<A, B, C, D, X> fn(&A, B, C, &D) -> X);
406    trace_acyclic!(<A, B, C, D, X> fn(A, B, C, &D) -> X);
407    trace_acyclic!(<A, B, C, D, X> fn(&A, &B, &C, D) -> X);
408    trace_acyclic!(<A, B, C, D, X> fn(A, &B, &C, D) -> X);
409    trace_acyclic!(<A, B, C, D, X> fn(&A, B, &C, D) -> X);
410    trace_acyclic!(<A, B, C, D, X> fn(A, B, &C, D) -> X);
411    trace_acyclic!(<A, B, C, D, X> fn(&A, &B, C, D) -> X);
412    trace_acyclic!(<A, B, C, D, X> fn(A, &B, C, D) -> X);
413    trace_acyclic!(<A, B, C, D, X> fn(&A, B, C, D) -> X);
414    trace_acyclic!(<A, B, C, D, X> fn(A, B, C, D) -> X);
415
416    trace_acyclic!(<A, B, C, D, E, X> fn(A, B, C, D, E) -> X);
417    trace_acyclic!(<A, B, C, D, E, F, X> fn(A, B, C, D, E, F) -> X);
418}
419
420mod ffi {
421    use std::ffi;
422
423    trace_acyclic!(ffi::CString, ffi::NulError, ffi::OsString);
424}
425
426mod net {
427    use std::net;
428
429    trace_acyclic!(
430        net::AddrParseError,
431        net::Ipv4Addr,
432        net::Ipv6Addr,
433        net::SocketAddrV4,
434        net::SocketAddrV6,
435        net::TcpListener,
436        net::TcpStream,
437        net::UdpSocket
438    );
439}
440
441mod option {
442    use super::{Acyclic, Trace, Tracer};
443
444    impl<T: Trace> Trace for Option<T> {
445        fn trace(&self, tracer: &mut Tracer) {
446            if let Some(ref t) = *self {
447                t.trace(tracer);
448            }
449        }
450
451        fn is_type_tracked() -> bool {
452            T::is_type_tracked()
453        }
454    }
455    unsafe impl<T: Acyclic> Acyclic for Option<T> {}
456}
457
458mod path {
459    use std::path;
460
461    trace_acyclic!(path::PathBuf);
462}
463
464mod process {
465    use std::process;
466
467    trace_acyclic!(
468        process::Child,
469        process::ChildStderr,
470        process::ChildStdin,
471        process::ChildStdout,
472        process::Command,
473        process::ExitStatus,
474        process::Output,
475        process::Stdio
476    );
477}
478
479mod rc {
480    use std::rc::{Rc, Weak};
481
482    use crate::Acyclic;
483
484    trace_acyclic!(<T> Rc<T> where T: Acyclic + ?Sized);
485    trace_acyclic!(<T> Weak<T>);
486}
487
488mod result {
489    use super::{Acyclic, Trace, Tracer};
490
491    impl<T: Trace, U: Trace> Trace for Result<T, U> {
492        fn trace(&self, tracer: &mut Tracer) {
493            match *self {
494                Ok(ref t) => t.trace(tracer),
495                Err(ref u) => u.trace(tracer),
496            }
497        }
498
499        fn is_type_tracked() -> bool {
500            T::is_type_tracked() || U::is_type_tracked()
501        }
502    }
503    unsafe impl<T: Acyclic, U: Acyclic> Acyclic for Result<T, U> {}
504}
505
506mod sync {
507    use super::{Trace, Tracer};
508    use std::sync;
509
510    // See comment in Mutex for why this is acyclic.
511    trace_acyclic!(<T> sync::Arc<T>);
512
513    impl<T: Trace> Trace for sync::Mutex<T> {
514        fn trace(&self, tracer: &mut Tracer) {
515            // For single-thread collector (ObjectSpace):
516            // Locking is optional. See RefCell.
517            //
518            // For multi-thread collector (ThreadedObjectSpace):
519            // `ThreadedCcRef` is expected to be the only way to access a `T`
520            // stored in `ThreadedCc<T>`. `ThreadedCcRef` takes a lock so
521            // collector does not run. When the collector runs, `ThreadedCcRef`
522            // are dropped so locks are released.
523            // A special is when `T` is `Arc<Mutex<M>>`. It allows mutating `M`
524            // without going through `ThreadedCcRef`. This is handled by marking
525            // `Arc` as acyclic. The collector only cares about `trace`, and
526            // `trace` result for an `Arc` cannot be changed by another thread,
527            // even if `M` is mutable.
528            if let Ok(x) = self.try_lock() {
529                x.trace(tracer);
530            }
531        }
532
533        #[inline]
534        fn is_type_tracked() -> bool {
535            T::is_type_tracked()
536        }
537    }
538
539    impl<T: Trace> Trace for sync::RwLock<T> {
540        fn trace(&self, tracer: &mut Tracer) {
541            // See Mutex for why locking is optional.
542            //
543            // If read or write locks are already taken, that indicates
544            // outstanding references that keeps the objects alive.
545            if let Ok(x) = self.try_write() {
546                x.trace(tracer);
547            }
548        }
549
550        #[inline]
551        fn is_type_tracked() -> bool {
552            T::is_type_tracked()
553        }
554    }
555}
556
557mod thread {
558    use std::thread;
559
560    trace_acyclic!(<T> thread::JoinHandle<T>);
561    trace_acyclic!(<T> thread::LocalKey<T>);
562    trace_acyclic!(thread::Thread);
563}
564
565mod phantom {
566    use super::{Acyclic, Trace, Tracer};
567    use std::marker::PhantomData;
568    impl<T: 'static> Trace for PhantomData<T> {
569        fn trace(&self, _tracer: &mut Tracer) {}
570
571        #[inline]
572        fn is_type_tracked() -> bool {
573            false
574        }
575    }
576    unsafe impl<T: 'static> Acyclic for PhantomData<T> {}
577}
578
579#[cfg(test)]
580mod tests {
581    use super::*;
582    use crate::Cc;
583    use std::cell::{Cell, RefCell};
584
585    #[test]
586    fn test_is_type_tracked() {
587        assert!(!u8::is_type_tracked());
588        assert!(!<f32 as Trace>::is_type_tracked());
589        assert!(!String::is_type_tracked());
590        assert!(!Option::<u32>::is_type_tracked());
591        assert!(!Vec::<u8>::is_type_tracked());
592        assert!(!<(bool, f64)>::is_type_tracked());
593        assert!(!Cell::<u32>::is_type_tracked());
594        assert!(!RefCell::<String>::is_type_tracked());
595        assert!(TraceBox::<dyn Trace>::is_type_tracked());
596        assert!(RefCell::<TraceBox::<dyn Trace>>::is_type_tracked());
597        assert!(RefCell::<Vec::<TraceBox::<dyn Trace>>>::is_type_tracked());
598        assert!(Vec::<RefCell::<TraceBox::<dyn Trace>>>::is_type_tracked());
599        assert!(!Cc::<u8>::is_type_tracked());
600        assert!(!Vec::<Cc::<u8>>::is_type_tracked());
601
602        assert!(!<fn(u8) -> u8>::is_type_tracked());
603        assert!(!<fn(&u8) -> u8>::is_type_tracked());
604    }
605
606    #[test]
607    fn test_is_cyclic_type_tracked() {
608        type C2 = RefCell<Option<Cc<Box<S2>>>>;
609        struct S2(C2);
610        impl Trace for S2 {
611            fn trace(&self, t: &mut Tracer) {
612                self.0.trace(t);
613            }
614            fn is_type_tracked() -> bool {
615                // C2::is_type_tracked() can cause an infinite loop.
616                true
617            }
618        }
619
620        assert!(S2::is_type_tracked());
621    }
622}
623
624/// Box, that assumes inner type is tracked
625///
626/// Exists because plain `Box<T>` only accepts sized `T`
627#[derive(Debug, Clone)]
628pub struct TraceBox<T: ?Sized>(pub Box<T>);
629
630impl<T: ?Sized + Trace> Trace for TraceBox<T> {
631    fn trace(&self, tracer: &mut Tracer<'_>) {
632        self.0.trace(tracer);
633    }
634
635    fn is_type_tracked() -> bool {
636        true
637    }
638}
639unsafe impl<T: ?Sized> Acyclic for TraceBox<T> where T: Acyclic {}
640
641impl<T: ?Sized> From<Box<T>> for TraceBox<T> {
642    fn from(inner: Box<T>) -> Self {
643        Self(inner)
644    }
645}
646
647impl<T: ?Sized> Deref for TraceBox<T> {
648    type Target = T;
649
650    fn deref(&self) -> &Self::Target {
651        &self.0
652    }
653}
654impl<T: Trace + ?Sized> DerefMut for TraceBox<T> {
655    fn deref_mut(&mut self) -> &mut Self::Target {
656        &mut self.0
657    }
658}
659
660impl<T: ?Sized> Borrow<T> for TraceBox<T> {
661    fn borrow(&self) -> &T {
662        &self.0
663    }
664}
665
666impl<T: ?Sized> BorrowMut<T> for TraceBox<T> {
667    fn borrow_mut(&mut self) -> &mut T {
668        &mut self.0
669    }
670}
671
672impl<T: ?Sized> AsRef<T> for TraceBox<T> {
673    fn as_ref(&self) -> &T {
674        &self.0
675    }
676}
677
678impl<T: ?Sized> AsMut<T> for TraceBox<T> {
679    fn as_mut(&mut self) -> &mut T {
680        &mut self.0
681    }
682}