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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use std::{
    any::Any,
    cell::{Cell, UnsafeCell},
    marker::PhantomData,
};

use crate::{
    ll::{
        bytecode::DispatchTable,
        gc::{Gc, GcRaw},
        value,
    },
    Error,
};

/// Marker trait for all user data types.
///
/// Due to limitations in Rust's type system each user-defined type must implement this.
pub trait UserData: Any {}

/// A type. This is used to represent user-defined Rust types in the VM (but not their instances).
#[derive(Debug)]
pub(crate) struct Type<T> {
    dtable: Gc<DispatchTable>,
    _data: PhantomData<T>,
}

impl<T> Type<T> {
    pub(crate) fn new(dtable: Gc<DispatchTable>) -> Self {
        Self { dtable, _data: PhantomData }
    }
}

impl<T> value::UserData for Type<T>
where
    T: Any,
{
    fn dtable_gcraw(&self) -> GcRaw<DispatchTable> {
        Gc::as_raw(&self.dtable)
    }

    fn as_any(&self) -> &dyn Any {
        self
    }
}

/// Represents a custom-typed value stored inside a VM.
///
/// Built-in types such as [`f64`] shouldn't be used as the `T` of an `Object`, because they are
/// can be represented by values inherently. `Object` however may be used for binding types that are
/// not directly supported by the VM, like [`std::fs::File`].
#[derive(Debug)]
pub(crate) struct Object<T> {
    pub(crate) dtable: Gc<DispatchTable>,
    // The functionality of the RefCell unfortunately has to be replicated because we need unsafe
    // guards that the standard RefCell doesn't provide.
    shared_borrows: Cell<usize>,
    borrowed_mutably: Cell<bool>,
    data: UnsafeCell<T>,
}

impl<T> Object<T> {
    pub(crate) fn new(dtable: GcRaw<DispatchTable>, data: T) -> Self {
        Self {
            dtable: unsafe { Gc::from_raw(dtable) },
            shared_borrows: Cell::new(0),
            borrowed_mutably: Cell::new(false),
            data: UnsafeCell::new(data),
        }
    }

    /// Borrows the object as immutably using an unsafe guard.
    ///
    /// # Safety
    /// This function is unsafe because the guard can be dropped accidentally while keeping the
    /// reference alive, which can lead to two mutable references to the data existing at once.
    #[doc(hidden)]
    pub(crate) unsafe fn unsafe_borrow(&self) -> Result<(&T, UnsafeRefGuard<T>), Error> {
        if self.borrowed_mutably.get() {
            return Err(Error::ReentrantMutableBorrow);
        }
        self.shared_borrows.set(self.shared_borrows.get() + 1);
        let reference = &*self.data.get();
        Ok((reference, UnsafeRefGuard { object: self as *const _ }))
    }

    /// Borrows the object mutably using an unsafe guard.
    ///
    /// # Safety
    /// This function is unsafe because the guard can be dropped accidentally while keeping the
    /// reference alive, which can lead to two mutable references to the data existing at once.
    #[doc(hidden)]
    pub(crate) unsafe fn unsafe_borrow_mut(&self) -> Result<(&mut T, UnsafeMutGuard<T>), Error> {
        if self.shared_borrows.get() > 0 {
            return Err(Error::ReentrantMutableBorrow);
        }
        self.borrowed_mutably.set(true);
        let reference = &mut *self.data.get();
        Ok((reference, UnsafeMutGuard { object: self as *const _ }))
    }
}

impl<T> value::UserData for Object<T>
where
    T: Any,
{
    fn dtable_gcraw(&self) -> GcRaw<DispatchTable> {
        Gc::as_raw(&self.dtable)
    }

    fn as_any(&self) -> &dyn Any {
        self
    }
}

/// An _unsafe_ guard for a `&T` borrowed from an `Object<T>`.
///
/// This is an **unsafe** guard because it must not outlive the `Object<T>` it guards, but that
/// is not guaranteed using the borrow checker. This type is needed because generic associated types
/// haven't been stabilized yet.
#[doc(hidden)]
#[derive(Debug)]
pub struct UnsafeRefGuard<T> {
    object: *const Object<T>,
}

impl<T> Drop for UnsafeRefGuard<T> {
    fn drop(&mut self) {
        unsafe {
            let object = &*self.object;
            object.shared_borrows.set(object.shared_borrows.get() - 1);
        }
    }
}

/// An _unsafe_ guard for a `&mut T` borrowed from an `Object<T>`.
///
/// This is an **unsafe** guard because it must not outlive the `Object<T>` it guards, but that
/// is not guaranteed using the borrow checker. This type is needed because generic associated types
/// haven't been stabilized yet.
#[doc(hidden)]
#[derive(Debug)]
pub struct UnsafeMutGuard<T> {
    object: *const Object<T>,
}

impl<T> Drop for UnsafeMutGuard<T> {
    fn drop(&mut self) {
        unsafe {
            let object = &*self.object;
            object.borrowed_mutably.set(false);
        }
    }
}