1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
use crate::collector::InternalGcRef; use crate::marker::GcSafe; /// A trait capturing the ability of data to be scanned for references to data in a `Gc`. /// /// This is unsafe, since a bad `scan` implementation can cause memory unsafety in two ways: /// 1) If `scan` scans data that this object does not own /// 2) If `scan` does anything other than `scan` data with a non-`'static` lifetime /// 3) If `scan` is non-deterministic about what owned data it scans /// /// The importance of (1) is so that the collector does not collect data that is in use. The /// importance of (2) is so that data can still be scanned even after its lifetime has /// technically expired. /// /// Regarding (1): Note that it's okay to miss data that you own. Missing connected data can only /// cause memory leaks--not memory unsafety. /// Regarding (2): In particular, `scan` should not call anything but `Scan` on `R` and `RMut`. Even /// implicitly using the `deref` implementations on these structs is incorrect. /// /// Importantly, any empty `scan` implementation is safe (assuming the `GcSafe` impl is correct) /// /// NB: It's important that `scan` only scans data that is truly owned. `Rc`/`Arc` cannot have /// sensible `scan` implementations, since each individual smart pointer doesn't own the underlying /// data. /// /// # Examples /// In practice you probably want to use the derive macro: /// ``` /// use shredder::Scan; /// /// #[derive(Scan)] /// struct Example { /// v: u32 /// } /// ``` /// /// This also comes with a `#[shredder(skip_scan)]` attribute, for when some data implements /// `GcSafe` but not `Scan` /// ``` /// use std::sync::Arc; /// use shredder::Scan; /// /// #[derive(Scan)] /// struct Example { /// #[shredder(skip_scan)] /// v: Arc<u32> /// } /// ``` /// /// This can work for any `Send+ 'static` data using `GcSafeWrapper` /// ``` /// use std::sync::Arc; /// /// use shredder::marker::GcSafeWrapper; /// use shredder::Scan; /// /// struct SendDataButNotScan { /// i: u32 /// } /// /// #[derive(Scan)] /// #[shredder(cant_drop)] // <- To understand why we need this, read the docs of the derive itself /// struct Example { /// #[shredder(skip_scan)] /// v: GcSafeWrapper<SendDataButNotScan> /// } /// ``` /// /// In emergencies, you can break out `#[shredder(unsafe_skip_gc_safe)]`, but this is potentially /// unsafe (the field you're skipping MUST uphold invariants as-if it was `GcSafe`) /// ``` /// use std::sync::Arc; /// use shredder::Scan; /// /// struct NotEvenSendData { /// data: *mut u32 /// } /// /// #[derive(Scan)] /// #[shredder(cant_drop)] // <- To understand why we need this, read the docs of the derive itself /// struct Example { /// #[shredder(unsafe_skip_gc_safe)] /// v: NotEvenSendData /// } /// ``` /// /// IMPORTANT NOTE: You may have problems with the derive complaining your data is not-`GcDrop`. To /// find a resolution, read the documentation of the derive itself. pub unsafe trait Scan: GcSafe { /// `scan` should use the scanner to scan all of its directly owned data fn scan(&self, scanner: &mut Scanner<'_>); } /// A trait that allows something that is `Scan` to be converted to a `dyn` ref. /// /// Implementing this trait is only necessary if you need to allocate an owned pointer to a DST, /// e.g. `Gc::from_box(Box<dyn MyTrait>)` /// /// This is unsafe because `to_scan` must always be implemented as `&*self` pub unsafe trait ToScan { /// Converts this value to a `dyn Scan` reference value. fn to_scan(&self) -> &(dyn Scan + 'static); } unsafe impl<T: Scan + Sized + 'static> ToScan for T { fn to_scan(&self) -> &(dyn Scan + 'static) { &*self } } /// Scanner is a struct used to manage the scanning of data, sort of analogous to `Hasher` /// Usually you will only care about this while implementing `Scan` pub struct Scanner<'a> { pub(crate) scan_callback: Box<dyn FnMut(InternalGcRef) + 'a>, } #[allow(clippy::unused_self)] impl<'a> Scanner<'a> { #[must_use] pub(crate) fn new<F: FnMut(InternalGcRef) + 'a>(callback: F) -> Self { Self { scan_callback: Box::new(callback), } } /// Scan a piece of data, tracking any `Gc`s found #[inline] pub fn scan<T: Scan + ?Sized>(&mut self, from: &T) { from.scan(self); } #[inline] pub(crate) fn add_internal_handle(&mut self, gc_ref: InternalGcRef) { (self.scan_callback)(gc_ref); } }