rune/core/object/
cell.rs

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
use super::{Object, WithLifetime};
use crate::core::gc::{Markable, Trace};
use std::{cell::Cell, fmt};

/// This type represents and immutable view into an Object. The reason we have
/// an additional type is because there could be other references to this same
/// cell that can change the underlying data, so this is wrapper around
/// `std::cell::Cell` type. It is not valid to mutate the data under a reference
/// unless it is inside an `Unsafe` Cell. However because this struct could also
/// be used in an immutable data structure (function constants), we need to
/// ensure that this cell cannot be mutated by default. This type is not safe to
/// be copy or clone.
#[derive(PartialEq, Eq)]
#[repr(transparent)]
pub(crate) struct ObjCell(Cell<Object<'static>>);

impl std::hash::Hash for ObjCell {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.0.get().hash(state);
    }
}

impl ObjCell {
    pub(crate) fn get(&self) -> Object<'_> {
        unsafe { self.0.get().with_lifetime() }
    }

    pub(in crate::core) unsafe fn new(obj: Object) -> Self {
        Self(Cell::new(obj.with_lifetime()))
    }

    /// Casts to a `MutObjCell`. Caller must ensure that the data structure is
    /// mutable.
    pub(in crate::core) unsafe fn as_mut(&self) -> &MutObjCell {
        &*(self as *const Self).cast()
    }
}

impl fmt::Display for ObjCell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0.get(), f)
    }
}

impl fmt::Debug for ObjCell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{self}")
    }
}

impl Trace for ObjCell {
    fn trace(&self, state: &mut crate::core::gc::GcState) {
        let cell = unsafe { self.as_mut() };
        if let Some((new, moved)) = cell.get().move_value(&state.to_space) {
            cell.set(new);
            if moved {
                state.push(new);
            }
        }
    }
}

/// This represents a mutable view into an Object. See [`ObjCell`] for a more
/// detailed explanation. Holding this type means that we confirmed that the
/// data stucture is mutable, and we can use the [`MutObjCell::set`] method update this
/// cell.
#[derive(PartialEq)]
#[repr(transparent)]
pub(crate) struct MutObjCell(ObjCell);

impl std::ops::Deref for MutObjCell {
    type Target = ObjCell;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl MutObjCell {
    pub(crate) fn set(&self, value: Object) {
        unsafe {
            self.0 .0.set(value.with_lifetime());
        }
    }
}