• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mattwparas / steel / 17772690385

16 Sep 2025 04:36PM UTC coverage: 43.331% (+0.04%) from 43.289%
17772690385

Pull #519

github

web-flow
Merge 98d4fd22c into 3c10433b9
Pull Request #519: fix a bunch more clippy lints

56 of 123 new or added lines in 30 files covered. (45.53%)

8 existing lines in 3 files now uncovered.

12416 of 28654 relevant lines covered (43.33%)

2985398.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.52
/crates/steel-core/src/gc.rs
1
use crate::rerrs::SteelErr;
2
use crate::rvals::SteelVal;
3
use crate::stop;
4

5
#[cfg(not(feature = "sync"))]
6
use std::cell::RefCell;
7

8
use std::fmt::Pointer;
9
use std::ops::Deref;
10
use std::sync::atomic::{AtomicUsize, Ordering};
11
use std::{ffi::OsStr, fmt};
12

13
pub static OBJECT_COUNT: AtomicUsize = AtomicUsize::new(0);
14
pub(crate) static MAXIMUM_OBJECTS: usize = 50000;
15

16
pub use shared::{GcMut, MutContainer, ShareableMut, Shared, SharedMut};
17
pub use unsafe_erased_pointers::is_reference_type;
18

19
#[cfg(feature = "sync")]
20
use parking_lot::RwLock;
21

22
pub mod shared {
23
    use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut};
24
    use std::ops::{Deref, DerefMut};
25
    use std::rc::Rc;
26

27
    // TODO: Replace these with `parking_lot` primitives instead
28
    use std::sync::{
29
        Arc,
30
        Mutex,
31
        MutexGuard,
32
        // RwLock, RwLockReadGuard, RwLockWriteGuard,
33
        TryLockResult,
34
    };
35

36
    use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
37

38
    #[cfg(feature = "sync")]
39
    use parking_lot::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
40

41
    use super::Gc;
42

43
    #[cfg(not(feature = "sync"))]
44
    pub type Shared<T> = Rc<T>;
45

46
    #[cfg(not(feature = "sync"))]
47
    pub type SharedMut<T> = Rc<RefCell<T>>;
48

49
    #[cfg(not(feature = "sync"))]
50
    pub type WeakSharedMut<T> = std::rc::Weak<RefCell<T>>;
51

52
    #[cfg(not(feature = "sync"))]
53
    pub type WeakShared<T> = std::rc::Weak<T>;
54

55
    #[cfg(not(feature = "sync"))]
56
    pub type MutContainer<T> = RefCell<T>;
57

58
    #[cfg(not(feature = "sync"))]
59
    pub type GcMut<T> = Gc<RefCell<T>>;
60

61
    #[cfg(feature = "sync")]
62
    pub type StandardShared<T> = std::sync::Arc<T>;
63

64
    #[cfg(feature = "sync")]
65
    pub type StandardSharedMut<T> = std::sync::Arc<RwLock<T>>;
66

67
    #[cfg(not(feature = "sync"))]
68
    pub type StandardShared<T> = std::rc::Rc<T>;
69

70
    #[cfg(not(feature = "sync"))]
71
    pub type StandardSharedMut<T> = std::rc::Rc<RefCell<T>>;
72

73
    #[cfg(all(feature = "sync", not(feature = "triomphe")))]
74
    pub type Shared<T> = Arc<T>;
75
    #[cfg(all(feature = "sync", not(feature = "triomphe")))]
76
    pub type SharedMut<T> = Arc<RwLock<T>>;
77

78
    #[cfg(all(feature = "sync", feature = "triomphe"))]
79
    pub type Shared<T> = triomphe::Arc<T>;
80
    #[cfg(all(feature = "sync", feature = "triomphe"))]
81
    pub type SharedMut<T> = triomphe::Arc<RwLock<T>>;
82

83
    #[cfg(feature = "sync")]
84
    pub type GcMut<T> = Gc<RwLock<T>>;
85

86
    #[cfg(feature = "sync")]
87
    pub type WeakSharedMut<T> = std::sync::Weak<RwLock<T>>;
88

89
    #[cfg(feature = "sync")]
90
    pub type WeakShared<T> = std::sync::Weak<T>;
91

92
    #[cfg(feature = "sync")]
93
    pub type MutContainer<T> = RwLock<T>;
94

95
    pub trait MutableContainer<T> {
96
        fn consume(self) -> T;
97
    }
98

99
    impl<T> MutableContainer<T> for RefCell<T> {
100
        fn consume(self) -> T {
×
101
            self.into_inner()
×
102
        }
103
    }
104

105
    impl<T> MutableContainer<T> for RwLock<T> {
106
        fn consume(self) -> T {
56✔
107
            self.into_inner()
112✔
108
        }
109
    }
110

111
    #[cfg(not(feature = "sync"))]
112
    pub type ScopedReadContainer<'a, T> = Ref<'a, T>;
113
    #[cfg(not(feature = "sync"))]
114
    pub type ScopedWriteContainer<'a, T> = RefMut<'a, T>;
115

116
    #[cfg(feature = "sync")]
117
    pub type ScopedReadContainer<'a, T> = RwLockReadGuard<'a, T>;
118
    #[cfg(feature = "sync")]
119
    pub type ScopedWriteContainer<'a, T> = RwLockWriteGuard<'a, T>;
120

121
    #[cfg(not(feature = "sync"))]
122
    pub type MappedScopedReadContainer<'a, T> = Ref<'a, T>;
123
    #[cfg(not(feature = "sync"))]
124
    pub type MappedScopedWriteContainer<'a, T> = RefMut<'a, T>;
125

126
    #[cfg(feature = "sync")]
127
    pub type MappedScopedReadContainer<'a, T> = MappedRwLockReadGuard<'a, T>;
128
    #[cfg(feature = "sync")]
129
    pub type MappedScopedWriteContainer<'a, T> = MappedRwLockWriteGuard<'a, T>;
130

131
    pub trait ShareableMut<T>: Clone {
132
        type ShareableRead<'a>: Deref<Target = T>
133
        where
134
            Self: 'a;
135
        type ShareableWrite<'a>: DerefMut<Target = T>
136
        where
137
            Self: 'a;
138

139
        type TryReadResult<'a>
140
        where
141
            Self: 'a;
142
        type TryWriteResult<'a>
143
        where
144
            Self: 'a;
145

146
        /// Obtain a scoped guard for reading
147
        fn read<'a>(&'a self) -> Self::ShareableRead<'a>;
148
        /// Obtain a scoped guard for writing
149
        fn write<'a>(&'a self) -> Self::ShareableWrite<'a>;
150

151
        /// Fallibly obtain a scoped guard for reading
152
        fn try_read<'a>(&'a self) -> Self::TryReadResult<'a>;
153

154
        /// Fallibly obtain a scoped guard for writing
155
        fn try_write<'a>(&'a self) -> Self::TryWriteResult<'a>;
156
    }
157

158
    impl<T> ShareableMut<T> for Rc<RefCell<T>> {
159
        type ShareableRead<'a>
160
            = Ref<'a, T>
161
        where
162
            T: 'a;
163
        type ShareableWrite<'a>
164
            = RefMut<'a, T>
165
        where
166
            T: 'a;
167
        type TryReadResult<'a>
168
            = Result<Ref<'a, T>, BorrowError>
169
        where
170
            T: 'a;
171
        type TryWriteResult<'a>
172
            = Result<RefMut<'a, T>, BorrowMutError>
173
        where
174
            T: 'a;
175

176
        fn read<'a>(&'a self) -> Self::ShareableRead<'a> {
×
177
            Rc::deref(self).borrow()
×
178
        }
179

180
        fn write<'a>(&'a self) -> Self::ShareableWrite<'a> {
×
181
            Rc::deref(self).borrow_mut()
×
182
        }
183

184
        fn try_write<'a>(&'a self) -> Self::TryWriteResult<'a> {
×
185
            Rc::deref(self).try_borrow_mut()
×
186
        }
187

188
        fn try_read<'a>(&'a self) -> Self::TryReadResult<'a> {
×
189
            Rc::deref(self).try_borrow()
×
190
        }
191
    }
192

193
    impl<T> ShareableMut<T> for Gc<RefCell<T>> {
194
        type ShareableRead<'a>
195
            = Ref<'a, T>
196
        where
197
            T: 'a;
198
        type ShareableWrite<'a>
199
            = RefMut<'a, T>
200
        where
201
            T: 'a;
202
        type TryReadResult<'a>
203
            = Result<Ref<'a, T>, BorrowError>
204
        where
205
            T: 'a;
206
        type TryWriteResult<'a>
207
            = Result<RefMut<'a, T>, BorrowMutError>
208
        where
209
            T: 'a;
210

211
        fn read<'a>(&'a self) -> Self::ShareableRead<'a> {
×
212
            Gc::deref(self).borrow()
×
213
        }
214

215
        fn write<'a>(&'a self) -> Self::ShareableWrite<'a> {
×
216
            Gc::deref(self).borrow_mut()
×
217
        }
218

219
        fn try_write<'a>(&'a self) -> Self::TryWriteResult<'a> {
×
220
            Gc::deref(self).try_borrow_mut()
×
221
        }
222

223
        fn try_read<'a>(&'a self) -> Self::TryReadResult<'a> {
×
224
            Gc::deref(self).try_borrow()
×
225
        }
226
    }
227

228
    impl<T> ShareableMut<T> for Arc<RwLock<T>> {
229
        type ShareableRead<'a>
230
            = RwLockReadGuard<'a, T>
231
        where
232
            T: 'a;
233
        type ShareableWrite<'a>
234
            = RwLockWriteGuard<'a, T>
235
        where
236
            T: 'a;
237
        // type TryReadResult<'a>
238
        // = TryLockResult<RwLockReadGuard<'a, T>> where T: 'a;
239
        type TryReadResult<'a>
240
            = Result<RwLockReadGuard<'a, T>, ()>
241
        where
242
            T: 'a;
243
        // type TryWriteResult<'a>
244
        // = TryLockResult<RwLockWriteGuard<'a, T>> where T: 'a;
245
        type TryWriteResult<'a>
246
            = Result<RwLockWriteGuard<'a, T>, ()>
247
        where
248
            T: 'a;
249

250
        fn read<'a>(&'a self) -> Self::ShareableRead<'a> {
106,012,392✔
251
            Arc::deref(self).read()
212,024,784✔
252
            // .expect("Read lock should not be poisoned")
253
        }
254

255
        fn write<'a>(&'a self) -> Self::ShareableWrite<'a> {
73,804,485✔
256
            Arc::deref(self).write()
147,608,970✔
257
            // .expect("Write lock should not be poisoned")
258
        }
259

260
        fn try_read<'a>(&'a self) -> Self::TryReadResult<'a> {
×
261
            match Arc::deref(self).try_read() {
×
262
                Some(v) => Ok(v),
×
263
                None => Err(()),
×
264
            }
265
        }
266

267
        fn try_write<'a>(&'a self) -> Self::TryWriteResult<'a> {
×
268
            match Arc::deref(self).try_write() {
×
269
                Some(v) => Ok(v),
×
270
                None => Err(()),
×
271
            }
272
        }
273
    }
274

275
    impl<T> ShareableMut<T> for Gc<RwLock<T>> {
276
        type ShareableRead<'a>
277
            = RwLockReadGuard<'a, T>
278
        where
279
            T: 'a;
280
        type ShareableWrite<'a>
281
            = RwLockWriteGuard<'a, T>
282
        where
283
            T: 'a;
284
        // type TryReadResult<'a>
285
        // = TryLockResult<RwLockReadGuard<'a, T>> where T: 'a;
286
        // type TryWriteResult<'a>
287
        // = TryLockResult<RwLockWriteGuard<'a, T>> where T: 'a;
288
        type TryReadResult<'a>
289
            = Result<RwLockReadGuard<'a, T>, ()>
290
        where
291
            T: 'a;
292
        type TryWriteResult<'a>
293
            = Result<RwLockWriteGuard<'a, T>, ()>
294
        where
295
            T: 'a;
296

297
        fn read<'a>(&'a self) -> Self::ShareableRead<'a> {
127,616✔
298
            Gc::deref(self).read()
255,232✔
299
            // .expect("Read lock should not be poisoned")
300
        }
301

302
        fn write<'a>(&'a self) -> Self::ShareableWrite<'a> {
36,664,488✔
303
            Gc::deref(self).write()
73,328,976✔
304
            // .expect("Write lock should not be poisoned")
305
        }
306

307
        fn try_read<'a>(&'a self) -> Self::TryReadResult<'a> {
×
308
            match Gc::deref(self).try_read() {
×
309
                Some(v) => Ok(v),
×
310
                None => Err(()),
×
311
            }
312
        }
313

314
        fn try_write<'a>(&'a self) -> Self::TryWriteResult<'a> {
×
315
            match Gc::deref(self).try_write() {
×
316
                Some(v) => Ok(v),
×
317
                None => Err(()),
×
318
            }
319
        }
320
    }
321

322
    impl<T> ShareableMut<T> for Arc<Mutex<T>> {
323
        type ShareableRead<'a>
324
            = MutexGuard<'a, T>
325
        where
326
            T: 'a;
327
        type ShareableWrite<'a>
328
            = MutexGuard<'a, T>
329
        where
330
            T: 'a;
331
        type TryReadResult<'a>
332
            = TryLockResult<MutexGuard<'a, T>>
333
        where
334
            T: 'a;
335
        type TryWriteResult<'a>
336
            = TryLockResult<MutexGuard<'a, T>>
337
        where
338
            T: 'a;
339

340
        fn read<'a>(&'a self) -> Self::ShareableRead<'a> {
×
341
            Arc::deref(self)
×
342
                .lock()
343
                .expect("Mutex should not be poisoned")
344
        }
345

346
        fn write<'a>(&'a self) -> Self::ShareableWrite<'a> {
×
347
            Arc::deref(self)
×
348
                .lock()
349
                .expect("Mutex should not be poisoned")
350
        }
351

352
        fn try_read<'a>(&'a self) -> Self::TryReadResult<'a> {
×
353
            Arc::deref(self).try_lock()
×
354
        }
355

356
        fn try_write<'a>(&'a self) -> Self::TryWriteResult<'a> {
×
357
            Arc::deref(self).try_lock()
×
358
        }
359
    }
360

361
    impl<T> ShareableMut<T> for Gc<Mutex<T>> {
362
        type ShareableRead<'a>
363
            = MutexGuard<'a, T>
364
        where
365
            T: 'a;
366
        type ShareableWrite<'a>
367
            = MutexGuard<'a, T>
368
        where
369
            T: 'a;
370
        type TryReadResult<'a>
371
            = TryLockResult<MutexGuard<'a, T>>
372
        where
373
            T: 'a;
374
        type TryWriteResult<'a>
375
            = TryLockResult<MutexGuard<'a, T>>
376
        where
377
            T: 'a;
378

379
        fn read<'a>(&'a self) -> Self::ShareableRead<'a> {
×
380
            Gc::deref(self)
×
381
                .lock()
382
                .expect("Mutex should not be poisoned")
383
        }
384

385
        fn write<'a>(&'a self) -> Self::ShareableWrite<'a> {
×
386
            Gc::deref(self)
×
387
                .lock()
388
                .expect("Mutex should not be poisoned")
389
        }
390

391
        fn try_read<'a>(&'a self) -> Self::TryReadResult<'a> {
×
392
            Gc::deref(self).try_lock()
×
393
        }
394

395
        fn try_write<'a>(&'a self) -> Self::TryWriteResult<'a> {
×
396
            Gc::deref(self).try_lock()
×
397
        }
398
    }
399
}
400

401
// TODO: Consider triomphe for a drop in replacement of Arc
402

403
/// Used for automatic detection of ref cycle
404
pub enum MaybeWeak<T: Clone> {
405
    StrongRef(Gc<T>),
406
    WeakRef(Gc<T>),
407
}
408

409
/// This is simply a newtype around the `Rc` type
410
/// When enabled, this allows for complete sandboxing of data types
411
/// It does not expose the full functionality of the `Rc` type
412
/// but it does allow for some
413
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
414
pub struct Gc<T: ?Sized>(pub(crate) Shared<T>);
415

416
impl<T: ?Sized> Pointer for Gc<T> {
417
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
418
        write!(f, "{:p}", self.0)
×
419
    }
420
}
421

422
impl fmt::Display for Gc<SteelVal> {
423
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
424
        write!(f, "{}", self.0)
×
425
    }
426
}
427

428
impl fmt::Display for Gc<String> {
429
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
430
        write!(f, "{}", self.0)
×
431
    }
432
}
433

434
pub fn get_object_count() -> usize {
×
435
    OBJECT_COUNT.fetch_add(0, Ordering::SeqCst)
×
436
}
437

438
impl<T: Clone> Gc<T> {
439
    /// Deep clone the object to remove it from the GC
440
    pub fn unwrap(&self) -> T {
2,745✔
441
        (*self.0).clone()
5,490✔
442
    }
443

444
    pub fn make_mut(&mut self) -> &mut T {
10,455,079✔
445
        Shared::make_mut(&mut self.0)
10,455,079✔
446
    }
447
}
448

449
impl<T> Gc<T> {
450
    pub fn new(val: T) -> Gc<T> {
29,563,242✔
451
        // OBJECT_COUNT.fetch_add(1, Ordering::SeqCst);
452
        Gc(Shared::new(val))
29,563,242✔
453
    }
454

455
    pub fn new_mut(val: T) -> GcMut<T> {
27,204✔
456
        #[cfg(not(feature = "sync"))]
457
        {
458
            Gc::new(RefCell::new(val))
×
459
        }
460

461
        #[cfg(feature = "sync")]
462
        Gc::new(RwLock::new(val))
81,612✔
463
    }
464

465
    pub fn try_new(val: T) -> Result<Gc<T>, SteelErr> {
×
466
        let mem: usize = OBJECT_COUNT.fetch_add(1, Ordering::SeqCst);
×
467
        if mem > MAXIMUM_OBJECTS {
×
468
            stop!(Generic => "ran out of memory!")
×
469
        }
470
        Ok(Gc(Shared::new(val)))
×
471
    }
472

473
    pub fn checked_allocate(allocations: usize) -> Result<(), SteelErr> {
×
474
        let mem: usize = OBJECT_COUNT.fetch_add(0, Ordering::SeqCst);
×
475
        if mem + allocations > MAXIMUM_OBJECTS {
×
476
            stop!(Generic => "allocation would exceed maximum allowed memory")
×
477
        }
478
        Ok(())
×
479
    }
480

481
    pub fn try_unwrap(self) -> Result<T, Gc<T>> {
8,777,788✔
482
        Shared::try_unwrap(self.0).map_err(|x| Gc(x))
26,446,497✔
483
    }
484

485
    pub fn check_memory() -> Result<usize, SteelErr> {
×
486
        let mem: usize = OBJECT_COUNT.fetch_add(0, Ordering::SeqCst);
×
487
        if mem > MAXIMUM_OBJECTS {
×
488
            stop!(Generic => "ran out of memory!")
×
489
        }
490
        Ok(mem)
×
491
    }
492
}
493

494
impl<T: ?Sized> Gc<T> {
495
    // in order to fully sandbox, I have to check the memory limit
496

497
    pub fn get_mut(&mut self) -> Option<&mut T> {
27,101,632✔
498
        Shared::get_mut(&mut self.0)
54,203,264✔
499
    }
500

501
    pub fn ptr_eq(this: &Self, other: &Self) -> bool {
8,921,642✔
502
        Shared::ptr_eq(&this.0, &other.0)
26,764,926✔
503
    }
504

505
    pub fn as_ptr(&self) -> *const T {
6,264,075✔
506
        Shared::as_ptr(&self.0)
12,528,150✔
507
    }
508

509
    pub fn into_raw(self) -> *const T {
×
510
        Shared::into_raw(self.0)
×
511
    }
512

513
    pub unsafe fn from_raw(this: *const T) -> Self {
64,521✔
514
        Self(Shared::from_raw(this))
64,521✔
515
    }
516

517
    pub fn strong_count(this: &Self) -> usize {
677,621✔
518
        Shared::strong_count(&this.0)
1,355,242✔
519
    }
520
}
521

522
impl<T> AsRef<T> for Gc<T> {
523
    fn as_ref(&self) -> &T {
110,465✔
524
        self.0.as_ref()
110,465✔
525
    }
526
}
527

528
impl<T: ?Sized> Deref for Gc<T> {
529
    type Target = T;
530
    fn deref(&self) -> &T {
211,443,750✔
531
        self.0.deref()
211,443,750✔
532
    }
533
}
534

535
impl<T: ?Sized> Clone for Gc<T> {
536
    #[inline(always)]
537
    fn clone(&self) -> Self {
21,016,944✔
538
        Gc(Shared::clone(&self.0))
21,016,944✔
539
    }
540
}
541

542
impl AsRef<OsStr> for Gc<String> {
543
    fn as_ref(&self) -> &OsStr {
×
544
        self.0.as_ref().as_ref()
×
545
    }
546
}
547

548
impl From<&str> for Gc<String> {
549
    fn from(val: &str) -> Self {
×
550
        Gc::new(val.to_string())
×
551
    }
552
}
553

554
impl From<String> for Gc<String> {
555
    fn from(val: String) -> Self {
×
556
        Gc::new(val)
×
557
    }
558
}
559

560
impl From<&String> for Gc<String> {
561
    fn from(val: &String) -> Self {
×
562
        Gc::new(val.clone())
×
563
    }
564
}
565

566
impl AsRef<str> for Gc<String> {
567
    fn as_ref(&self) -> &str {
×
568
        self.0.as_ref()
×
569
    }
570
}
571

572
#[cfg(feature = "unsafe-internals")]
573
pub mod unsafe_roots {
574

575
    use super::Gc;
576
    use std::ptr::NonNull;
577

578
    #[derive(Clone)]
579
    pub enum MaybeRooted<T> {
580
        Rooted(Rooted<T>),
581
        Reference(Gc<T>),
582
    }
583

584
    impl<T: std::fmt::Debug> std::fmt::Debug for MaybeRooted<T> {
585
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
586
            match self {
×
587
                Self::Rooted(v) => write!(f, "{:?}", unsafe { v.value.as_ref() }),
×
588
                Self::Reference(v) => write!(f, "{:?}", v),
×
589
            }
590
        }
591
    }
592

593
    impl<T> MaybeRooted<T> {
594
        pub fn from_root(value: &Gc<T>) -> Self {
×
595
            Self::Rooted(Rooted::from_ref(value))
×
596
        }
597
    }
598

599
    impl<T> AsRef<T> for MaybeRooted<T> {
600
        fn as_ref(&self) -> &T {
×
601
            match self {
×
602
                Self::Rooted(v) => unsafe { v.value.as_ref() },
×
603
                Self::Reference(v) => &v,
×
604
            }
605
        }
606
    }
607

608
    impl<T> std::ops::Deref for MaybeRooted<T> {
609
        type Target = T;
610

611
        fn deref(&self) -> &Self::Target {
×
612
            match self {
×
613
                Self::Rooted(v) => unsafe { v.value.as_ref() },
×
614
                Self::Reference(v) => &v,
×
615
            }
616
        }
617
    }
618

619
    #[derive(Clone)]
620
    pub struct Rooted<T> {
621
        value: NonNull<T>,
622
    }
623

624
    impl<T> Rooted<T> {
625
        pub fn from_ref(value: &Gc<T>) -> Self {
×
626
            Rooted {
627
                value: NonNull::new(Gc::as_ptr(value) as _).expect("Given pointer was null!"),
×
628
            }
629
        }
630
    }
631

632
    #[test]
633
    fn test_rooting() {
634
        use crate::SteelVal;
635

636
        let root = Gc::new(SteelVal::ListV(im_lists::list![]));
637

638
        let rooted_reference = Rooted::from_ref(&root);
639

640
        println!("{:?}", unsafe { rooted_reference.value.as_ref() });
641
    }
642

643
    #[test]
644
    fn recover_original_gc() {
645
        use crate::SteelVal;
646

647
        let root = Gc::new(SteelVal::ListV(im_lists::list![]));
648

649
        let rooted_reference = Rooted::from_ref(&root);
650

651
        let recovered = unsafe { rooted_reference.value.as_ref() };
652

653
        println!("{:?}", recovered);
654
    }
655
}
656

657
// #[cfg(feature = "unsafe-internals")]
658
#[allow(unused)]
659
pub mod unsafe_erased_pointers {
660
    /*
661
    Warning - here be dragons. Definitely a lot of unsafe things here, and when used incorrectly
662
    can lead to undefined behavior.
663
    */
664

665
    use std::cell::Cell;
666
    use std::rc::{Rc, Weak};
667
    use std::sync::atomic::AtomicBool;
668
    use std::sync::Arc;
669
    use std::{any::Any, cell::RefCell, marker::PhantomData};
670

671
    use crate::gc::shared::{
672
        MappedScopedReadContainer, MappedScopedWriteContainer, ScopedReadContainer,
673
        ScopedWriteContainer, StandardSharedMut,
674
    };
675
    use crate::steel_vm::engine::EngineId;
676
    use once_cell::sync::Lazy;
677
    use parking_lot::Mutex;
678
    use std::collections::HashMap;
679

680
    use crate::rvals::cycles::IterativeDropHandler;
681
    use crate::rvals::{AsRefSteelValFromRef, MaybeSendSyncStatic};
682
    use crate::{rerrs::ErrorKind, rvals::AsRefMutSteelValFromRef, SteelErr, SteelVal};
683

684
    use super::shared::{
685
        MutContainer, ShareableMut as _, StandardShared, WeakShared, WeakSharedMut,
686
    };
687
    use super::{Gc, Shared};
688

689
    // TODO: This needs to be exanded to n args, probably like 8 with a macro
690
    pub struct MutableReferenceArena<A, B> {
691
        _phantom1: PhantomData<A>,
692
        _phantom2: PhantomData<B>,
693
    }
694

695
    impl<A, B> MutableReferenceArena<A, B> {
696
        pub fn new() -> Self {
×
697
            Self {
698
                _phantom1: PhantomData,
699
                _phantom2: PhantomData,
700
            }
701
        }
702

703
        pub fn retain_reference(
×
704
            &mut self,
705
            original_a: &mut A,
706
            original_b: &mut B,
707
            mut thunk: impl FnMut(
708
                BorrowedObject<A>,
709
                BorrowedObject<B>,
710
            ) -> crate::rvals::Result<SteelVal>,
711
        ) -> crate::rvals::Result<SteelVal> {
712
            let erased = original_a as *mut _;
×
713

714
            // Wrap the original mutable pointer in an object that respects borrowing
715
            // rules for runtime borrow checking
716
            let wrapped = StandardShared::new(MutContainer::new(erased));
×
717
            let weak_ptr = StandardShared::downgrade(&wrapped);
×
718

719
            let borrowed = BorrowedObject::new(weak_ptr);
×
720

721
            let erased2 = original_b as *mut _;
×
722
            let wrapped2 = StandardShared::new(MutContainer::new(erased2));
×
723
            let weak_ptr2 = StandardShared::downgrade(&wrapped2);
×
724

725
            let borrowed2 = BorrowedObject::new(weak_ptr2);
×
726

727
            thunk(borrowed, borrowed2)
×
728
        }
729
    }
730

731
    pub struct MutableReferenceNursery<T> {
732
        _phantom: PhantomData<T>, // pointers: Vec<Rc<RefCell<*mut T>>>,
733
    }
734

735
    impl<T> MutableReferenceNursery<T> {
736
        pub fn new() -> Self {
1✔
737
            Self {
738
                _phantom: PhantomData, // pointers: Vec::new(),
739
            }
740
        }
741

742
        pub fn retain_readonly_reference(
×
743
            &mut self,
744
            original: &T,
745
            mut thunk: impl FnMut(ReadOnlyBorrowedObject<T>) -> crate::rvals::Result<SteelVal>,
746
        ) -> crate::rvals::Result<SteelVal> {
747
            let erased = original as *const _;
×
748

749
            // Wrap the original mutable pointer in an object that respects borrowing
750
            // rules for runtime borrow checking
751
            let wrapped = StandardShared::new(MutContainer::new(erased));
×
752
            let weak_ptr = StandardShared::downgrade(&wrapped);
×
753

754
            let borrowed = ReadOnlyBorrowedObject::new(weak_ptr, Arc::new(Mutex::new(0)));
×
755

756
            thunk(borrowed)
×
757
        }
758

759
        pub fn retain_reference(
1✔
760
            &mut self,
761
            original: &mut T,
762
            mut thunk: impl FnMut(BorrowedObject<T>) -> crate::rvals::Result<SteelVal>,
763
        ) -> crate::rvals::Result<SteelVal> {
764
            let erased = original as *mut _;
2✔
765

766
            // Wrap the original mutable pointer in an object that respects borrowing
767
            // rules for runtime borrow checking
768
            let wrapped = StandardShared::new(MutContainer::new(erased));
4✔
769
            let weak_ptr = StandardShared::downgrade(&wrapped);
3✔
770

771
            let borrowed = BorrowedObject::new(weak_ptr);
3✔
772

773
            thunk(borrowed)
1✔
774
        }
775

776
        // pub(crate) fn wrap_mut_borrow_object(original: &mut T) -> BorrowedObject<T> {
777
        //     let erased = original as *mut _;
778

779
        //     // Wrap the original mutable pointer in an object that respects borrowing
780
        //     // rules for runtime borrow checking
781
        //     let wrapped = Rc::new(RefCell::new(erased));
782
        //     let weak_ptr = Rc::downgrade(&wrapped);
783

784
        //     let borrowed = BorrowedObject { ptr: weak_ptr };
785

786
        //     borrowed
787
        // }
788
    }
789

790
    // TODO: Re-evaluate the necessity of this trait. Is it possible to overload it all into one? That could
791
    // help disambiguate the function call sites.
792
    pub trait CustomReference {
793
        fn walk(&self) {}
×
794
    }
795

796
    /// Warning - you should not implement this trait yourself. Use the `custom_reference` macro instead.
797
    /// Implementing this incorrectly could lead to undefined behavior.
798
    pub unsafe trait ReferenceMarker<'a> {
799
        type Static: ?Sized + 'static;
800
    }
801

802
    pub fn type_id<'a, T>() -> std::any::TypeId
3✔
803
    where
804
        T: ReferenceMarker<'a>,
805
        T::Static: Any,
806
    {
807
        std::any::TypeId::of::<T::Static>()
3✔
808
    }
809

810
    #[macro_export]
811
    macro_rules! custom_reference {
812
        ($t: ident) => {
813
            unsafe impl<'a> $crate::gc::unsafe_erased_pointers::ReferenceMarker<'a> for $t {
814
                type Static = $t;
815
            }
816
        };
817

818
        ($t: ident<'a>) => {
819
            unsafe impl<'a> $crate::gc::unsafe_erased_pointers::ReferenceMarker<'a> for $t<'a> {
820
                type Static = $t<'static>;
821
            }
822
        };
823
    }
824

825
    // Only works if this is explicitly, a reference type?
826
    impl CustomReference for &str {}
827

828
    pub trait ReferenceCustomType {
829
        fn as_any_ref(&self) -> &dyn Any;
830
        fn as_any_ref_mut(&mut self) -> &mut dyn Any;
831
        fn name(&self) -> &str {
×
832
            std::any::type_name::<Self>()
×
833
        }
834
        fn display(&self) -> std::result::Result<String, std::fmt::Error> {
×
835
            Ok(format!("#<{}>", self.name()))
×
836
        }
837
        fn visit(&self) {}
×
838
        fn drop_mut(&mut self, drop_handler: &mut IterativeDropHandler) {}
×
839
    }
840

841
    impl<'a, T: CustomReference + 'static> ReferenceCustomType for T {
842
        fn as_any_ref(&self) -> &dyn Any {
4✔
843
            self as &dyn Any
4✔
844
        }
845
        fn as_any_ref_mut(&mut self) -> &mut dyn Any {
×
846
            self as &mut dyn Any
×
847
        }
848
        fn display(&self) -> std::result::Result<String, std::fmt::Error> {
×
849
            Ok(format!("#<{}>", self.name()))
×
850
        }
851
        fn visit(&self) {
×
852
            self.walk()
×
853
        }
854
    }
855

856
    // impl<T: ReferenceCustomType + 'static> IntoSteelVal for T {
857
    //     fn into_steelval(self) -> crate::rvals::Result<SteelVal> {
858
    //         // Ok(self.new_steel_val())
859
    //         Ok(SteelVal::Custom(Rc::new(RefCell::new(Box::new(self)))))
860
    //     }
861
    // }
862

863
    /// This is for objects that are references FROM an already borrowed object.
864
    /// In order to make this safe - we create a scoped nursery which ties the lifetime
865
    /// of the object to the parent object, and all of those get dropped when the parent lifetime
866
    /// ends. This will also mean that allocating references repeatedly will continuously
867
    /// fill space in the nursery (at the moment). Once the original reference is done being borrowed,
868
    /// we purge the entire nursery. This could cause issues - however for now as a proof
869
    /// of concept, we will just treat the nursery as an allocation pool. Gc cycles should be able
870
    /// to be run over this pool - just check the amount of weak pointer allocations to each allocation
871
    /// and drop those from the vec.
872
    pub(crate) struct TemporaryObject<T> {
873
        pub(crate) ptr: StandardShared<MutContainer<*mut T>>,
874
    }
875

876
    #[cfg(feature = "sync")]
877
    unsafe impl<T> Send for TemporaryObject<T> {}
878
    #[cfg(feature = "sync")]
879
    unsafe impl<T> Sync for TemporaryObject<T> {}
880

881
    // TODO: Probably combine this and the above
882
    pub(crate) struct ReadOnlyTemporaryObject<T> {
883
        pub(crate) ptr: StandardShared<MutContainer<*const T>>,
884
    }
885

886
    #[cfg(feature = "sync")]
887
    unsafe impl<T> Send for ReadOnlyTemporaryObject<T> {}
888
    #[cfg(feature = "sync")]
889
    unsafe impl<T> Sync for ReadOnlyTemporaryObject<T> {}
890

891
    // Not a reference explicitly. This might contain a reference, but on its own it is a
892
    // value type. This should probably only deal with immutable references for now.
893
    pub(crate) struct Temporary<T> {
894
        pub(crate) ptr: StandardShared<T>,
895
    }
896

897
    // #[cfg(feature = "sync")]
898
    // unsafe impl<T> Send for Temporary<T> {}
899
    // #[cfg(feature = "sync")]
900
    // unsafe impl<T> Sync for Temporary<T> {}
901

902
    impl<T> CustomReference for Temporary<T> {}
903
    impl<T> CustomReference for TemporaryObject<T> {}
904
    impl<T> CustomReference for ReadOnlyTemporaryObject<T> {}
905

906
    impl<T: MaybeSendSyncStatic> TemporaryObject<T> {
907
        pub(crate) fn into_opaque_reference<'a>(self) -> OpaqueReference<'a> {
×
908
            OpaqueReference {
909
                inner: StandardShared::new(self),
×
910
            }
911
        }
912
    }
913

914
    impl<T: MaybeSendSyncStatic> ReadOnlyTemporaryObject<T> {
915
        pub(crate) fn into_opaque_reference<'a>(self) -> OpaqueReference<'a> {
×
916
            OpaqueReference {
917
                inner: StandardShared::new(self),
×
918
            }
919
        }
920
    }
921

922
    impl<T: MaybeSendSyncStatic> Temporary<T> {
923
        pub(crate) fn into_opaque_reference<'a>(self) -> OpaqueReference<'a> {
×
924
            OpaqueReference {
925
                inner: StandardShared::new(self),
×
926
            }
927
        }
928
    }
929

930
    pub struct ReadOnlyTemporary<T> {
931
        pub(crate) ptr: WeakShared<T>,
932
    }
933

934
    impl<T> CustomReference for ReadOnlyTemporary<T> {}
935

936
    impl<T> Clone for ReadOnlyTemporary<T> {
937
        fn clone(&self) -> Self {
×
938
            Self {
939
                ptr: WeakShared::clone(&self.ptr),
×
940
            }
941
        }
942
    }
943

944
    impl<T: MaybeSendSyncStatic> ReadOnlyTemporary<T> {
945
        pub(crate) fn into_opaque_reference<'a>(self) -> OpaqueReference<'a> {
×
946
            OpaqueReference {
947
                inner: StandardShared::new(self),
×
948
            }
949
        }
950
    }
951

952
    pub struct ReadOnlyBorrowedObject<T> {
953
        pub(crate) ptr: WeakSharedMut<*const T>,
954
        pub(crate) parent_borrow_count: Arc<Mutex<BorrowFlag>>,
955
    }
956

957
    impl<T> CustomReference for ReadOnlyBorrowedObject<T> {}
958

959
    impl<T> ReadOnlyBorrowedObject<T> {
960
        pub fn new(
1✔
961
            ptr: WeakSharedMut<*const T>,
962
            parent_borrow_count: Arc<Mutex<BorrowFlag>>,
963
        ) -> Self {
964
            Self {
965
                ptr,
966
                parent_borrow_count,
967
            }
968
        }
969
    }
970

971
    impl<T> Drop for ReadOnlyBorrowedObject<T> {
972
        fn drop(&mut self) {
1✔
973
            let mut guard = self.parent_borrow_count.lock();
2✔
974
            *guard = *guard - 1;
1✔
975
        }
976
    }
977

978
    impl<T> Clone for ReadOnlyBorrowedObject<T> {
979
        fn clone(&self) -> Self {
×
980
            Self {
981
                ptr: WeakShared::clone(&self.ptr),
×
982
                parent_borrow_count: Arc::clone(&self.parent_borrow_count),
×
983
            }
984
        }
985
    }
986

987
    impl<T: 'static> ReadOnlyBorrowedObject<T> {
988
        pub(crate) fn into_opaque_reference<'a>(self) -> OpaqueReference<'a> {
1✔
989
            OpaqueReference {
990
                inner: StandardShared::new(self),
1✔
991
            }
992
        }
993
    }
994

995
    #[cfg(feature = "sync")]
996
    unsafe impl<T> Send for ReadOnlyBorrowedObject<T> {}
997
    #[cfg(feature = "sync")]
998
    unsafe impl<T> Sync for ReadOnlyBorrowedObject<T> {}
999

1000
    type BorrowFlag = isize;
1001
    const UNUSED: BorrowFlag = 0;
1002

1003
    #[inline(always)]
1004
    fn is_writing(x: BorrowFlag) -> bool {
×
1005
        x < UNUSED
×
1006
    }
1007

1008
    #[inline(always)]
1009
    fn is_reading(x: BorrowFlag) -> bool {
×
1010
        x > UNUSED
×
1011
    }
1012

1013
    pub struct BorrowedObject<T> {
1014
        pub(crate) ptr: WeakSharedMut<*mut T>,
1015
        pub(crate) parent_borrow_flag: Arc<AtomicBool>,
1016
        pub(crate) child_borrow_flag: Arc<AtomicBool>,
1017
        pub(crate) borrow_count: Arc<Mutex<BorrowFlag>>,
1018
    }
1019

1020
    impl<T> Drop for BorrowedObject<T> {
1021
        fn drop(&mut self) {
3✔
1022
            // We're not borrowing anymore, so we can do this
1023
            self.parent_borrow_flag
6✔
1024
                .store(false, std::sync::atomic::Ordering::SeqCst);
3✔
1025
        }
1026
    }
1027

1028
    pub(crate) fn increment_borrow_flag(value: &Arc<Mutex<BorrowFlag>>) {
×
1029
        let mut guard = value.lock();
×
1030
        *guard = *guard + 1;
×
1031
    }
1032

1033
    impl<T> BorrowedObject<T> {
1034
        pub(crate) fn new(ptr: WeakSharedMut<*mut T>) -> Self {
3✔
1035
            Self {
1036
                ptr,
1037
                parent_borrow_flag: Arc::new(AtomicBool::new(false)),
9✔
1038
                child_borrow_flag: Arc::new(AtomicBool::new(false)),
9✔
1039
                borrow_count: Arc::new(Mutex::new(0)),
3✔
1040
            }
1041
        }
1042

1043
        pub(crate) fn with_parent_flag(mut self, parent_borrow_flag: Arc<AtomicBool>) -> Self {
×
1044
            self.parent_borrow_flag = parent_borrow_flag;
×
1045

1046
            self
×
1047
        }
1048
    }
1049

1050
    impl SteelVal {
1051
        pub(crate) fn get_borrow_flag_if_borrowed_object<T: AsRefMutSteelValFromRef + 'static>(
×
1052
            &self,
1053
        ) -> crate::rvals::Result<Arc<AtomicBool>> {
1054
            if let SteelVal::Reference(v) = self {
×
1055
                let res = v.inner.as_any_ref();
×
1056

1057
                if res.is::<BorrowedObject<T>>() {
×
1058
                    let borrowed_object = res.downcast_ref::<BorrowedObject<T>>().unwrap();
×
1059

1060
                    Ok(Arc::clone(&borrowed_object.child_borrow_flag))
×
1061
                } else {
1062
                    let error_message = format!(
×
1063
                        "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
1064
                        self,
×
1065
                        std::any::type_name::<Self>()
×
1066
                    );
1067
                    Err(SteelErr::new(ErrorKind::ConversionError, error_message))
×
1068
                }
1069
            } else {
1070
                let error_message = format!(
×
1071
                    "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
1072
                    self,
×
1073
                    std::any::type_name::<Self>()
×
1074
                );
1075

1076
                Err(SteelErr::new(ErrorKind::ConversionError, error_message))
×
1077
            }
1078
        }
1079

1080
        pub(crate) fn get_borrow_count_if_borrowed_object<T: AsRefMutSteelValFromRef + 'static>(
×
1081
            &self,
1082
        ) -> crate::rvals::Result<Arc<Mutex<BorrowFlag>>> {
1083
            if let SteelVal::Reference(v) = self {
×
1084
                let res = v.inner.as_any_ref();
×
1085

1086
                if res.is::<BorrowedObject<T>>() {
×
1087
                    let borrowed_object = res.downcast_ref::<BorrowedObject<T>>().unwrap();
×
1088

1089
                    Ok(Arc::clone(&borrowed_object.borrow_count))
×
1090
                } else {
1091
                    let error_message = format!(
×
1092
                        "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
1093
                        self,
×
1094
                        std::any::type_name::<Self>()
×
1095
                    );
1096
                    Err(SteelErr::new(ErrorKind::ConversionError, error_message))
×
1097
                }
1098
            } else {
1099
                let error_message = format!(
×
1100
                    "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
1101
                    self,
×
1102
                    std::any::type_name::<Self>()
×
1103
                );
1104

1105
                Err(SteelErr::new(ErrorKind::ConversionError, error_message))
×
1106
            }
1107
        }
1108
    }
1109

1110
    impl<T> CustomReference for BorrowedObject<T> {}
1111

1112
    impl<'a, T> Clone for BorrowedObject<T> {
1113
        fn clone(&self) -> Self {
×
1114
            Self {
1115
                ptr: WeakShared::clone(&self.ptr),
×
1116
                parent_borrow_flag: Arc::clone(&self.parent_borrow_flag),
×
1117
                child_borrow_flag: Arc::clone(&self.child_borrow_flag),
×
1118
                borrow_count: Arc::clone(&self.borrow_count),
×
1119
            }
1120
        }
1121
    }
1122

1123
    impl<T: 'static> BorrowedObject<T> {
1124
        pub(crate) fn into_opaque_reference<'a>(self) -> OpaqueReference<'a> {
2✔
1125
            OpaqueReference {
1126
                inner: StandardShared::new(self),
2✔
1127
            }
1128
        }
1129
    }
1130

1131
    #[cfg(feature = "sync")]
1132
    unsafe impl<T> Send for BorrowedObject<T> {}
1133
    #[cfg(feature = "sync")]
1134
    unsafe impl<T> Sync for BorrowedObject<T> {}
1135

1136
    pub(crate) trait Opaque {}
1137

1138
    // impl<T> Opaque for Shared<MutContainer<T>> {}
1139
    impl<T> Opaque for StandardShared<MutContainer<T>> {}
1140

1141
    // TODO: Use this to chain multiple references together. The engine should be able to accept something
1142
    // `with_reference` and then have the value be scoped to that lifetime.
1143

1144
    // #[cfg(not(feature = "sync"))]
1145
    #[derive(Clone, Default)]
1146
    pub(crate) struct OpaqueReferenceNursery {
1147
        // memory: Rc<RefCell<Vec<OpaqueReference<'static>>>>,
1148
        memory: Shared<MutContainer<Vec<Box<dyn Opaque>>>>,
1149
        weak_values: Shared<MutContainer<Vec<OpaqueReference<'static>>>>,
1150
    }
1151

1152
    // #[cfg(feature = "sync")]
1153
    // #[derive(Clone, Default)]
1154
    // pub(crate) struct OpaqueReferenceNursery {
1155
    //     // memory: Rc<RefCell<Vec<OpaqueReference<'static>>>>,
1156
    //     memory: Shared<MutContainer<Vec<Box<dyn Opaque>>>>,
1157
    //     weak_values: Shared<MutContainer<Vec<OpaqueReference<'static>>>>,
1158
    // }
1159

1160
    // #[cfg(feature = "sync")]
1161
    // unsafe impl Sync for OpaqueReferenceNursery {}
1162
    // #[cfg(feature = "sync")]
1163
    // unsafe impl Send for OpaqueReferenceNursery {}
1164

1165
    // #[cfg(feature = "sync")]
1166
    // static STATIC_NURSERY: Lazy<std::sync::Mutex<HashMap<EngineId, OpaqueReferenceNursery>>> =
1167
    //     Lazy::new(|| std::sync::Mutex::new(HashMap::new()));
1168

1169
    // #[cfg(feature = "sync")]
1170
    // static NURSERY: Lazy<OpaqueReferenceNursery> = Lazy::new(|| OpaqueReferenceNursery::new());
1171

1172
    // TODO: This needs to be like, engine-id -> nursery?
1173

1174
    // #[cfg(not(feature = "sync"))]
1175

1176
    // TODO: Think about if this makes sense, of it we need to move to something that isn't
1177
    // thread local. I _think_ this makes complete sense, given that the main thread of execution
1178
    // is not going to be moved across threads. Nothing ever references this?
1179
    thread_local! {
1180
        static NURSERY: OpaqueReferenceNursery = OpaqueReferenceNursery::new();
1181
    }
1182

1183
    impl OpaqueReferenceNursery {
1184
        const DEFAULT_CAPACITY: usize = 8;
1185

1186
        fn new() -> Self {
3✔
1187
            Self {
1188
                memory: Shared::new(MutContainer::new(Vec::with_capacity(
12✔
1189
                    Self::DEFAULT_CAPACITY,
1190
                ))),
1191
                weak_values: Shared::new(MutContainer::new(Vec::with_capacity(
6✔
1192
                    Self::DEFAULT_CAPACITY,
1193
                ))),
1194
            }
1195
        }
1196

1197
        pub fn tie_lifetime<'a, T>(_: &'a mut T) -> NurseryAccessToken<'a> {
×
1198
            NurseryAccessToken {
1199
                phantom: PhantomData,
1200
            }
1201
        }
1202

1203
        // pub(crate) fn allocate_ro_object<T: 'static>
1204

1205
        // Safety - these absolutely need to be the same type.
1206
        pub(crate) fn allocate_rw_object<'a, T: 'a, EXT: 'static>(obj: &mut T) {
2✔
1207
            let erased = obj as *mut _;
4✔
1208

1209
            let erased = unsafe { std::mem::transmute::<*mut T, *mut EXT>(erased) };
6✔
1210

1211
            // Wrap the original mutable pointer in an object that respects borrowing
1212
            // rules for runtime borrow checking
1213
            let wrapped = StandardShared::new(MutContainer::new(erased));
8✔
1214
            let weak_ptr = StandardShared::downgrade(&wrapped);
6✔
1215

1216
            let borrowed = BorrowedObject::new(weak_ptr);
6✔
1217

1218
            // #[cfg(not(feature = "sync"))]
1219
            // {
1220
            NURSERY.with(|x| x.memory.write().push(Box::new(wrapped)));
10✔
1221
            NURSERY.with(|x| x.weak_values.write().push(borrowed.into_opaque_reference()));
12✔
1222
            // }
1223

1224
            // #[cfg(feature = "sync")]
1225
            // {
1226
            //     if let Some(nursery) = STATIC_NURSERY.lock().unwrap().get(&id) {
1227
            //         nursery.memory.write().push(Box::new(wrapped));
1228
            //         nursery
1229
            //             .weak_values
1230
            //             .write()
1231
            //             .push(borrowed.into_opaque_reference());
1232
            //     } else {
1233
            //         let mut nursery = OpaqueReferenceNursery::new();
1234
            //         nursery.memory.write().push(Box::new(wrapped));
1235
            //         nursery
1236
            //             .weak_values
1237
            //             .write()
1238
            //             .push(borrowed.into_opaque_reference());
1239
            //     }
1240
            // }
1241
        }
1242

1243
        pub(crate) fn allocate_ro_object<'a, T: 'a, EXT: 'static>(obj: &T) {
1✔
1244
            let erased = obj as *const _;
2✔
1245

1246
            let erased = unsafe { std::mem::transmute::<*const T, *const EXT>(erased) };
3✔
1247

1248
            // Wrap the original mutable pointer in an object that respects borrowing
1249
            // rules for runtime borrow checking
1250
            let wrapped = StandardShared::new(MutContainer::new(erased));
4✔
1251
            let weak_ptr = StandardShared::downgrade(&wrapped);
3✔
1252

1253
            let borrowed = ReadOnlyBorrowedObject::new(weak_ptr, Arc::new(Mutex::new(0)));
5✔
1254
            // let borrowed = ReadOnlyBorrowedObject::new(weak_ptr);
1255

1256
            // #[cfg(feature = "sync")]
1257
            // {
1258
            //     if let Some(nursery) = STATIC_NURSERY.lock().unwrap().get(&id) {
1259
            //         nursery.memory.write().push(Box::new(wrapped));
1260
            //         nursery
1261
            //             .weak_values
1262
            //             .write()
1263
            //             .push(borrowed.into_opaque_reference());
1264
            //     } else {
1265
            //         let mut nursery = OpaqueReferenceNursery::new();
1266
            //         nursery.memory.write().push(Box::new(wrapped));
1267
            //         nursery
1268
            //             .weak_values
1269
            //             .write()
1270
            //             .push(borrowed.into_opaque_reference());
1271
            //     }
1272
            // }
1273

1274
            // #[cfg(not(feature = "sync"))]
1275
            // {
1276
            NURSERY.with(|x| x.memory.write().push(Box::new(wrapped)));
5✔
1277

1278
            // TODO: Consider doing the transmute in the into_opaque_reference function,
1279
            // to extend the lifetime, but nowhere else. Could save passing in the double types.
1280
            NURSERY.with(|x| x.weak_values.write().push(borrowed.into_opaque_reference()));
6✔
1281
            // }
1282
        }
1283

1284
        pub(crate) fn allocate(obj: OpaqueReference<'static>) {
×
1285
            NURSERY.with(|x| x.weak_values.write().push(obj));
×
1286
        }
1287

1288
        pub(crate) fn free_all() {
3✔
1289
            NURSERY.with(|x| x.memory.write().clear());
12✔
1290
            NURSERY.with(|x| x.weak_values.write().clear());
12✔
1291
        }
1292

1293
        pub(crate) fn drain_weak_references_to_steelvals() -> Vec<SteelVal> {
3✔
1294
            let res = NURSERY.with(|x| {
12✔
1295
                x.weak_values
6✔
1296
                    .write()
6✔
1297
                    .drain(..)
3✔
1298
                    .map(Gc::new)
3✔
1299
                    .map(SteelVal::Reference)
3✔
1300
                    .collect()
3✔
1301
            });
1302

1303
            // NURSERY.with(|x| x.memory.borrow_mut().clear());
1304

1305
            res
3✔
1306
        }
1307
    }
1308

1309
    pub struct NurseryAccessToken<'a> {
1310
        phantom: PhantomData<&'a ()>,
1311
    }
1312

1313
    impl<'a> NurseryAccessToken<'a> {
1314
        pub fn allocate(obj: OpaqueReference<'static>) {
×
1315
            OpaqueReferenceNursery::allocate(obj)
×
1316
        }
1317
    }
1318

1319
    impl<'a> Drop for NurseryAccessToken<'a> {
1320
        fn drop(&mut self) {
×
1321
            OpaqueReferenceNursery::free_all()
×
1322
        }
1323
    }
1324

1325
    // impl<T> BorrowedObject {
1326
    //     pub fn borrow_mut()
1327
    // }
1328

1329
    #[derive(Clone)]
1330
    pub struct OpaqueReference<'a> {
1331
        #[cfg(not(feature = "sync"))]
1332
        inner: Shared<dyn ReferenceCustomType + 'a>,
1333
        #[cfg(feature = "sync")]
1334
        inner: StandardShared<dyn ReferenceCustomType + 'a + Send + Sync>,
1335
    }
1336

1337
    impl OpaqueReference<'static> {
1338
        pub(crate) fn format(&self) -> std::result::Result<String, std::fmt::Error> {
×
1339
            self.display()
×
1340
        }
1341

1342
        pub(crate) fn drop_mut(&mut self, drop_handler: &mut IterativeDropHandler) {
×
1343
            if let Some(inner) = StandardShared::get_mut(&mut self.inner) {
×
1344
                inner.drop_mut(drop_handler);
1345
            }
1346
        }
1347
    }
1348

1349
    impl CustomReference for OpaqueReference<'static> {}
1350

1351
    pub(crate) struct TemporaryMutableView<T> {
1352
        view: StandardSharedMut<*mut T>,
1353
    }
1354

1355
    impl<T> TemporaryMutableView<T> {
1356
        pub(crate) fn as_mut(&mut self) -> MappedScopedWriteContainer<'_, T> {
2✔
1357
            ScopedWriteContainer::map(self.view.write(), |x| unsafe { &mut (**x) })
10✔
1358
        }
1359
    }
1360

1361
    pub(crate) enum TemporaryReadonlyView<T> {
1362
        Standard(StandardSharedMut<*const T>),
1363
        Slim(StandardShared<T>),
1364
    }
1365

1366
    impl<T> TemporaryReadonlyView<T> {
1367
        pub(crate) fn as_ro(&self) -> &T {
1✔
1368
            match self {
1✔
1369
                TemporaryReadonlyView::Standard(rw_lock) => unsafe { &(**rw_lock.read()) },
1✔
NEW
1370
                TemporaryReadonlyView::Slim(x) => x,
×
1371
            }
1372
        }
1373
    }
1374

1375
    impl<T: ReferenceCustomType + 'static> AsRefMutSteelValFromRef for T {
1376
        fn as_mut_ref_from_ref<'a>(
2✔
1377
            val: &'a SteelVal,
1378
        ) -> crate::rvals::Result<TemporaryMutableView<T>> {
1379
            if let SteelVal::Reference(v) = val {
4✔
1380
                let res = v.inner.as_any_ref();
×
1381

1382
                if res.is::<BorrowedObject<T>>() {
×
1383
                    let borrowed_object = res.downcast_ref::<BorrowedObject<T>>().unwrap();
8✔
1384

1385
                    if *borrowed_object.borrow_count.lock() > 0
2✔
1386
                        || borrowed_object
2✔
1387
                            .child_borrow_flag
2✔
1388
                            .load(std::sync::atomic::Ordering::SeqCst)
×
1389
                    {
1390
                        stop!(Generic => "Value is already borrowed!")
×
1391
                    }
1392

1393
                    let guard = borrowed_object.ptr.upgrade().ok_or_else(
2✔
1394
                        throw!(Generic => "opaque reference pointer dropped before use!"),
×
1395
                    )?;
1396

NEW
1397
                    Ok(TemporaryMutableView { view: guard })
×
1398
                } else {
1399
                    let error_message = format!(
×
1400
                        "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
1401
                        val,
×
1402
                        std::any::type_name::<Self>()
×
1403
                    );
1404
                    Err(SteelErr::new(ErrorKind::ConversionError, error_message))
×
1405
                }
1406
            } else {
1407
                let error_message = format!(
×
1408
                    "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
1409
                    val,
×
1410
                    std::any::type_name::<Self>()
×
1411
                );
1412

1413
                Err(SteelErr::new(ErrorKind::ConversionError, error_message))
×
1414
            }
1415
        }
1416
    }
1417

1418
    impl<T: ReferenceCustomType + 'static> AsRefSteelValFromRef for T {
1419
        fn as_ref_from_ref<'a>(
2✔
1420
            val: &'a SteelVal,
1421
        ) -> crate::rvals::Result<TemporaryReadonlyView<T>> {
1422
            if let SteelVal::Reference(v) = val {
4✔
1423
                let res = v.inner.as_any_ref();
×
1424

1425
                // TODO: Flatten these conversions - we're doing 2 checks when we only need to do one.
1426
                if res.is::<ReadOnlyBorrowedObject<T>>() {
×
1427
                    let borrowed_object = res.downcast_ref::<ReadOnlyBorrowedObject<T>>().unwrap();
8✔
1428

1429
                    let guard = borrowed_object.ptr.upgrade().ok_or_else(
7✔
1430
                        throw!(Generic => "opaque reference pointer dropped before use!"),
2✔
1431
                    )?;
1432

NEW
1433
                    Ok(TemporaryReadonlyView::Standard(guard))
×
1434
                } else if res.is::<ReadOnlyTemporary<T>>() {
×
1435
                    let borrowed_object = res.downcast_ref::<ReadOnlyTemporary<T>>().unwrap();
×
1436

1437
                    let guard = borrowed_object.ptr.upgrade().ok_or_else(
×
1438
                        throw!(Generic => "opaque reference pointer dropped before use!"),
×
1439
                    )?;
1440

NEW
1441
                    Ok(TemporaryReadonlyView::Slim(guard))
×
1442
                } else {
1443
                    let error_message = format!(
×
1444
                        "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
1445
                        val,
×
1446
                        std::any::type_name::<Self>()
×
1447
                    );
1448
                    Err(SteelErr::new(ErrorKind::ConversionError, error_message))
×
1449
                }
1450
            } else {
1451
                let error_message = format!(
×
1452
                    "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
1453
                    val,
×
1454
                    std::any::type_name::<Self>()
×
1455
                );
1456

1457
                Err(SteelErr::new(ErrorKind::ConversionError, error_message))
×
1458
            }
1459
        }
1460
    }
1461

1462
    pub fn is_reference_type<T: ReferenceCustomType + 'static>(value: &SteelVal) -> bool {
×
1463
        if let SteelVal::Reference(v) = value {
×
1464
            let res = v.inner.as_any_ref();
×
1465
            if res.is::<ReadOnlyBorrowedObject<T>>() {
×
1466
                true
×
1467
            } else if res.is::<ReadOnlyTemporary<T>>() {
×
1468
                true
×
1469
            } else {
1470
                false
×
1471
            }
1472
        } else {
1473
            false
×
1474
        }
1475
    }
1476

1477
    #[test]
1478
    fn test() {
1479
        #[derive(Debug)]
1480
        struct FooBar {
1481
            baz: String,
1482
        }
1483

1484
        struct Baz<'a> {
1485
            foo_bar: &'a mut FooBar,
1486
        }
1487

1488
        impl FooBar {
1489
            fn append_str(&mut self, suffix: &str) {
1490
                self.baz.push_str(suffix);
1491
            }
1492
        }
1493
        let mut nursery = MutableReferenceNursery::new();
1494

1495
        let mut object = FooBar {
1496
            baz: "hello world!".to_string(),
1497
        };
1498

1499
        let mut baz = Baz {
1500
            foo_bar: &mut object,
1501
        };
1502

1503
        // HAS to be around the whole time
1504
        nursery
1505
            .retain_reference(&mut baz, |erased| unsafe {
1506
                let guard = erased.ptr.upgrade().unwrap();
1507

1508
                let ref_mut: &mut Baz = &mut *(*guard.write());
1509

1510
                ref_mut.foo_bar.append_str("bananas");
1511

1512
                Ok(SteelVal::Void)
1513
            })
1514
            .unwrap();
1515

1516
        object.append_str("foobar");
1517

1518
        dbg!(object);
1519
    }
1520
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc