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::*;
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::*;
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::*;
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
183mod collections {
184    use super::*;
185    use std::collections::{BTreeMap, HashMap, HashSet, LinkedList, VecDeque};
186    use std::hash::Hash;
187
188    impl<K: Trace, V: Trace> Trace for BTreeMap<K, V> {
189        fn trace(&self, tracer: &mut Tracer) {
190            for (k, v) in self {
191                k.trace(tracer);
192                v.trace(tracer);
193            }
194        }
195
196        #[inline]
197        fn is_type_tracked() -> bool {
198            K::is_type_tracked() || V::is_type_tracked()
199        }
200    }
201    unsafe impl<K: Acyclic, V: Acyclic> Acyclic for BTreeMap<K, V> {}
202
203    impl<K: Eq + Hash + Trace, H: 'static> Trace for HashSet<K, H> {
204        fn trace(&self, tracer: &mut Tracer) {
205            for k in self {
206                k.trace(tracer);
207            }
208        }
209
210        #[inline]
211        fn is_type_tracked() -> bool {
212            K::is_type_tracked()
213        }
214    }
215    unsafe impl<K: Acyclic + Hash + Eq, H: 'static> Acyclic for HashSet<K, H> {}
216
217    impl<K: Eq + Hash + Trace, V: Trace, H: 'static> Trace for HashMap<K, V, H> {
218        fn trace(&self, tracer: &mut Tracer) {
219            for (k, v) in self {
220                k.trace(tracer);
221                v.trace(tracer);
222            }
223        }
224
225        #[inline]
226        fn is_type_tracked() -> bool {
227            K::is_type_tracked() || V::is_type_tracked()
228        }
229    }
230    unsafe impl<K: Acyclic + Hash + Eq, V: Acyclic, H: 'static> Acyclic for HashMap<K, V, H> {}
231
232    impl<T: Trace> Trace for LinkedList<T> {
233        fn trace(&self, tracer: &mut Tracer) {
234            for t in self {
235                t.trace(tracer);
236            }
237        }
238
239        #[inline]
240        fn is_type_tracked() -> bool {
241            T::is_type_tracked()
242        }
243    }
244    unsafe impl<T: Acyclic> Acyclic for LinkedList<T> {}
245
246    impl<T: Trace> Trace for VecDeque<T> {
247        fn trace(&self, tracer: &mut Tracer) {
248            for t in self {
249                t.trace(tracer);
250            }
251        }
252
253        #[inline]
254        fn is_type_tracked() -> bool {
255            T::is_type_tracked()
256        }
257    }
258    unsafe impl<T: Acyclic> Acyclic for VecDeque<T> {}
259}
260
261mod rustc_hash {}
262
263mod vec {
264    use super::*;
265    impl<T: Trace> Trace for Vec<T> {
266        fn trace(&self, tracer: &mut Tracer) {
267            for t in self {
268                t.trace(tracer);
269            }
270        }
271
272        #[inline]
273        fn is_type_tracked() -> bool {
274            T::is_type_tracked()
275        }
276    }
277    unsafe impl<T: Acyclic> Acyclic for Vec<T> {}
278}
279
280mod slice {
281    use crate::{Acyclic, Trace, Tracer};
282
283    impl<T: Trace> Trace for [T] {
284        fn trace(&self, tracer: &mut Tracer) {
285            for t in self {
286                t.trace(tracer);
287            }
288        }
289    }
290    unsafe impl<T: Acyclic> Acyclic for [T] {}
291}
292
293// See https://github.com/rust-lang/rust/issues/56105#issuecomment-465709105
294#[allow(unknown_lints)]
295#[allow(coherence_leak_check)]
296mod func {
297    trace_acyclic!(<X> fn() -> X);
298
299    trace_acyclic!(<A, X> fn(&A) -> X);
300    trace_acyclic!(<A, X> fn(A) -> X);
301
302    trace_acyclic!(<A, B, X> fn(&A, &B) -> X);
303    trace_acyclic!(<A, B, X> fn(A, &B) -> X);
304    trace_acyclic!(<A, B, X> fn(&A, B) -> X);
305    trace_acyclic!(<A, B, X> fn(A, B) -> X);
306
307    trace_acyclic!(<A, B, C, X> fn(&A, &B, &C) -> X);
308    trace_acyclic!(<A, B, C, X> fn(A, &B, &C) -> X);
309    trace_acyclic!(<A, B, C, X> fn(&A, B, &C) -> X);
310    trace_acyclic!(<A, B, C, X> fn(A, B, &C) -> X);
311    trace_acyclic!(<A, B, C, X> fn(&A, &B, C) -> X);
312    trace_acyclic!(<A, B, C, X> fn(A, &B, C) -> X);
313    trace_acyclic!(<A, B, C, X> fn(&A, B, C) -> X);
314    trace_acyclic!(<A, B, C, X> fn(A, B, C) -> X);
315
316    trace_acyclic!(<A, B, C, D, X> fn(&A, &B, &C, &D) -> X);
317    trace_acyclic!(<A, B, C, D, X> fn(A, &B, &C, &D) -> X);
318    trace_acyclic!(<A, B, C, D, X> fn(&A, B, &C, &D) -> X);
319    trace_acyclic!(<A, B, C, D, X> fn(A, B, &C, &D) -> X);
320    trace_acyclic!(<A, B, C, D, X> fn(&A, &B, C, &D) -> X);
321    trace_acyclic!(<A, B, C, D, X> fn(A, &B, C, &D) -> X);
322    trace_acyclic!(<A, B, C, D, X> fn(&A, B, C, &D) -> X);
323    trace_acyclic!(<A, B, C, D, X> fn(A, B, C, &D) -> X);
324    trace_acyclic!(<A, B, C, D, X> fn(&A, &B, &C, D) -> X);
325    trace_acyclic!(<A, B, C, D, X> fn(A, &B, &C, D) -> X);
326    trace_acyclic!(<A, B, C, D, X> fn(&A, B, &C, D) -> X);
327    trace_acyclic!(<A, B, C, D, X> fn(A, B, &C, D) -> X);
328    trace_acyclic!(<A, B, C, D, X> fn(&A, &B, C, D) -> X);
329    trace_acyclic!(<A, B, C, D, X> fn(A, &B, C, D) -> X);
330    trace_acyclic!(<A, B, C, D, X> fn(&A, B, C, D) -> X);
331    trace_acyclic!(<A, B, C, D, X> fn(A, B, C, D) -> X);
332
333    trace_acyclic!(<A, B, C, D, E, X> fn(A, B, C, D, E) -> X);
334    trace_acyclic!(<A, B, C, D, E, F, X> fn(A, B, C, D, E, F) -> X);
335}
336
337mod ffi {
338    use std::ffi;
339
340    trace_acyclic!(ffi::CString, ffi::NulError, ffi::OsString);
341}
342
343mod net {
344    use std::net;
345
346    trace_acyclic!(
347        net::AddrParseError,
348        net::Ipv4Addr,
349        net::Ipv6Addr,
350        net::SocketAddrV4,
351        net::SocketAddrV6,
352        net::TcpListener,
353        net::TcpStream,
354        net::UdpSocket
355    );
356}
357
358mod option {
359    use super::*;
360
361    impl<T: Trace> Trace for Option<T> {
362        fn trace(&self, tracer: &mut Tracer) {
363            if let Some(ref t) = *self {
364                t.trace(tracer);
365            }
366        }
367
368        fn is_type_tracked() -> bool {
369            T::is_type_tracked()
370        }
371    }
372    unsafe impl<T: Acyclic> Acyclic for Option<T> {}
373}
374
375mod path {
376    use std::path;
377
378    trace_acyclic!(path::PathBuf);
379}
380
381mod process {
382    use std::process;
383
384    trace_acyclic!(
385        process::Child,
386        process::ChildStderr,
387        process::ChildStdin,
388        process::ChildStdout,
389        process::Command,
390        process::ExitStatus,
391        process::Output,
392        process::Stdio
393    );
394}
395
396mod rc {
397    use std::rc::{Rc, Weak};
398
399    use crate::Acyclic;
400
401    trace_acyclic!(<T> Rc<T> where T: Acyclic + ?Sized);
402    trace_acyclic!(<T> Weak<T>);
403}
404
405mod result {
406    use super::*;
407
408    impl<T: Trace, U: Trace> Trace for Result<T, U> {
409        fn trace(&self, tracer: &mut Tracer) {
410            match *self {
411                Ok(ref t) => t.trace(tracer),
412                Err(ref u) => u.trace(tracer),
413            }
414        }
415
416        fn is_type_tracked() -> bool {
417            T::is_type_tracked() || U::is_type_tracked()
418        }
419    }
420    unsafe impl<T: Acyclic, U: Acyclic> Acyclic for Result<T, U> {}
421}
422
423mod sync {
424    use super::*;
425    use std::sync;
426
427    // See comment in Mutex for why this is acyclic.
428    trace_acyclic!(<T> sync::Arc<T>);
429
430    impl<T: Trace> Trace for sync::Mutex<T> {
431        fn trace(&self, tracer: &mut Tracer) {
432            // For single-thread collector (ObjectSpace):
433            // Locking is optional. See RefCell.
434            //
435            // For multi-thread collector (ThreadedObjectSpace):
436            // `ThreadedCcRef` is expected to be the only way to access a `T`
437            // stored in `ThreadedCc<T>`. `ThreadedCcRef` takes a lock so
438            // collector does not run. When the collector runs, `ThreadedCcRef`
439            // are dropped so locks are released.
440            // A special is when `T` is `Arc<Mutex<M>>`. It allows mutating `M`
441            // without going through `ThreadedCcRef`. This is handled by marking
442            // `Arc` as acyclic. The collector only cares about `trace`, and
443            // `trace` result for an `Arc` cannot be changed by another thread,
444            // even if `M` is mutable.
445            if let Ok(x) = self.try_lock() {
446                x.trace(tracer);
447            }
448        }
449
450        #[inline]
451        fn is_type_tracked() -> bool {
452            T::is_type_tracked()
453        }
454    }
455
456    impl<T: Trace> Trace for sync::RwLock<T> {
457        fn trace(&self, tracer: &mut Tracer) {
458            // See Mutex for why locking is optional.
459            //
460            // If read or write locks are already taken, that indicates
461            // outstanding references that keeps the objects alive.
462            if let Ok(x) = self.try_write() {
463                x.trace(tracer);
464            }
465        }
466
467        #[inline]
468        fn is_type_tracked() -> bool {
469            T::is_type_tracked()
470        }
471    }
472}
473
474mod thread {
475    use std::thread;
476
477    trace_acyclic!(<T> thread::JoinHandle<T>);
478    trace_acyclic!(<T> thread::LocalKey<T>);
479    trace_acyclic!(thread::Thread);
480}
481
482mod phantom {
483    use super::*;
484    use std::marker::PhantomData;
485    impl<T: 'static> Trace for PhantomData<T> {
486        fn trace(&self, _tracer: &mut Tracer) {}
487
488        #[inline]
489        fn is_type_tracked() -> bool {
490            false
491        }
492    }
493    unsafe impl<T: 'static> Acyclic for PhantomData<T> {}
494}
495
496#[cfg(test)]
497mod tests {
498    use super::*;
499    use crate::Cc;
500    use std::cell::{Cell, RefCell};
501
502    #[test]
503    fn test_is_type_tracked() {
504        assert!(!u8::is_type_tracked());
505        assert!(!<f32 as Trace>::is_type_tracked());
506        assert!(!String::is_type_tracked());
507        assert!(!Option::<u32>::is_type_tracked());
508        assert!(!Vec::<u8>::is_type_tracked());
509        assert!(!<(bool, f64)>::is_type_tracked());
510        assert!(!Cell::<u32>::is_type_tracked());
511        assert!(!RefCell::<String>::is_type_tracked());
512        assert!(TraceBox::<dyn Trace>::is_type_tracked());
513        assert!(RefCell::<TraceBox::<dyn Trace>>::is_type_tracked());
514        assert!(RefCell::<Vec::<TraceBox::<dyn Trace>>>::is_type_tracked());
515        assert!(Vec::<RefCell::<TraceBox::<dyn Trace>>>::is_type_tracked());
516        assert!(!Cc::<u8>::is_type_tracked());
517        assert!(!Vec::<Cc::<u8>>::is_type_tracked());
518
519        assert!(!<fn(u8) -> u8>::is_type_tracked());
520        assert!(!<fn(&u8) -> u8>::is_type_tracked());
521    }
522
523    #[test]
524    fn test_is_cyclic_type_tracked() {
525        type C2 = RefCell<Option<Cc<Box<S2>>>>;
526        struct S2(C2);
527        impl Trace for S2 {
528            fn trace(&self, t: &mut Tracer) {
529                self.0.trace(t);
530            }
531            fn is_type_tracked() -> bool {
532                // C2::is_type_tracked() can cause an infinite loop.
533                true
534            }
535        }
536
537        assert!(S2::is_type_tracked());
538    }
539}
540
541/// Box, that assumes inner type is tracked
542///
543/// Exists because plain `Box<T>` only accepts sized `T`
544#[derive(Debug, Clone)]
545pub struct TraceBox<T: ?Sized>(pub Box<T>);
546
547impl<T: ?Sized + Trace> Trace for TraceBox<T> {
548    fn trace(&self, tracer: &mut Tracer<'_>) {
549        self.0.trace(tracer);
550    }
551
552    fn is_type_tracked() -> bool {
553        true
554    }
555}
556unsafe impl<T: ?Sized> Acyclic for TraceBox<T> where T: Acyclic {}
557
558impl<T: ?Sized> From<Box<T>> for TraceBox<T> {
559    fn from(inner: Box<T>) -> Self {
560        Self(inner)
561    }
562}
563
564impl<T: ?Sized> Deref for TraceBox<T> {
565    type Target = T;
566
567    fn deref(&self) -> &Self::Target {
568        &self.0
569    }
570}
571impl<T: Trace + ?Sized> DerefMut for TraceBox<T> {
572    fn deref_mut(&mut self) -> &mut Self::Target {
573        &mut self.0
574    }
575}
576
577impl<T: ?Sized> Borrow<T> for TraceBox<T> {
578    fn borrow(&self) -> &T {
579        &self.0
580    }
581}
582
583impl<T: ?Sized> BorrowMut<T> for TraceBox<T> {
584    fn borrow_mut(&mut self) -> &mut T {
585        &mut self.0
586    }
587}
588
589impl<T: ?Sized> AsRef<T> for TraceBox<T> {
590    fn as_ref(&self) -> &T {
591        &self.0
592    }
593}
594
595impl<T: ?Sized> AsMut<T> for TraceBox<T> {
596    fn as_mut(&mut self) -> &mut T {
597        &mut self.0
598    }
599}