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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * @Copyright 2020 Jason Carr
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use core::cell::{RefCell};
use core::fmt;
use alloc::vec::Vec;
use crate::types::{Ix, Weak, Root, Error};
use crate::entry::{Entry, Spot};
#[cfg(feature = "debug-arena")]
use crate::nonce;

/**
 * The type of a collectable region.
 *
 * This object can be used to allocate, collect,
 * traverse and update the objects within it.
 *
 * Access to the region is exposed through methods
 * on the corresponding reference types, and requires
 * references to this region in order to safely
 * reference the data within. This ensures that
 * garbage collections do not interrupt accesses and
 * vice versa, and allows for a conservative compile-time check for uniqueness, rather than
 * requiring use of an internal Cell type.
 *
 * Since garbage collection is a property of the region, it is not statically checked for indices.
 * Weak and Root will always be in sync with their
 * source region, but raw indices Ix may be invalidated.
 * Some methods (which necessarily take &mut self) may invalidate raw indices by moving the
 * objects, such as for a garbage collection.
 * These will be documented.
 *
 */
pub struct Region<T> {
    pub(crate) data: Vec<Spot<T>>,
    pub(crate) roots: RefCell<Vec<Root<T>>>,

    #[cfg(feature = "debug-arena")]
    pub(crate) nonce: u64,
    #[cfg(feature = "debug-arena")]
    pub(crate) generation: u64,
}

impl <T> Region<T> {

    #[inline]
    pub fn new() -> Self {
        Region {
            data: Vec::new(),
            roots: RefCell::new(Vec::new()),
            #[cfg(feature = "debug-arena")]
            nonce: nonce::next(),
            #[cfg(feature = "debug-arena")]
            generation: 0,
        }
    }
}
impl <T> Default for Region<T> {
    fn default() -> Self {
        Self::new()
    }
}
impl <T> fmt::Debug for Region<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.write_str("(Region")?;
        #[cfg(feature = "debug-arena")]
        {
            f.write_str("(")?;
            self.nonce.fmt(f)?;
            f.write_str(", ")?;
            self.generation.fmt(f)?;
            f.write_str(")")?;
        }
        f.write_str(")")?;
        Ok(())
    }
}

impl <T> Root<T> {
    /**
     * Gets the value at this location, when
     * passed the correct region. As with Ix,
     * the behavior when the region or location is
     * unspecified (but is still safe).
     */
    #[inline]
    pub fn get<'a>(&self, r: &'a Region<T>) -> &'a T {
        self.try_get(r).unwrap()
    }
    #[inline]
    pub fn get_mut<'a>(&self, r: &'a mut Region<T>) -> &'a mut T {
        self.try_get_mut(r).unwrap()
    }
    /**
     * Try to get a reference to this data, possibly returning an error.
     *
     * If the region is correct, then an error always indicates that the pointed-to
     * entry is no longer valid
     */
    #[inline]
    pub fn try_get<'a>(&self, r: &'a Region<T>) -> Result<&'a T, Error> {
        self.ix().try_get(&r)
    }
    #[inline]
    pub fn try_get_mut<'a>(&self, r: &'a mut Region<T>) -> Result<&'a mut T, Error> {
        self.ix().try_get_mut(r)
    }
}

/**
 * A freshly created entry, allowing root/weak creation, and mutation
 *
 * This entry is created by calls to [`Region::alloc`](struct.Region.html#method.alloc)
 * and will allow the creation of external and internal indices,
 * as well as allowing access to the freshly-created object.
 */
pub struct MutEntry<'a, T> {
    pub(crate) ix: Ix<T>,
    pub(crate) entry: &'a mut Entry<T>,
    pub(crate) roots: &'a RefCell<Vec<Root<T>>>,
}

impl <'a, T: fmt::Debug> fmt::Debug for MutEntry<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.write_str("MutEntry { ix: ")?;
        self.ix.fmt(f)?;
        f.write_str(", entry: ")?;
        self.entry.get().fmt(f)?;
        f.write_str("}")?;
        Ok(())
    }
}


impl <'a, T> MutEntry<'a, T> {
    /**
     * Create a root pointer, which will keep this object
     * live across garbage collections.
     */
    pub fn root(&self) -> Root<T> {
        let i = self.ix;
        let r = self.entry.root(i);
        // we have a new root
        // if the total count including our new copy
        // is still not rooted, i.e. we have just these two
        if !r.is_rooted() {
            self.roots.borrow_mut().push(r.clone());
        };
        r
    }

    /**
     * Create a weak pointer, which can be used to access
     * a consistent location in the region, but does not
     * act as a root for garbage collection
     */
    #[inline]
    pub fn weak(&self) -> Weak<T> {
        self.entry.weak(self.ix)
    }
    #[inline]
    pub fn ix(&self) -> Ix<T> {
        self.ix
    }
    #[inline]
    #[deprecated(since="0.2.0", note="Please use MutEntry::get")]
    pub fn as_ref(&self) -> &T {
        self.entry.get()
    }
    #[inline]
    #[deprecated(since="0.2.0", note="Please use MutEntry::get_mut")]
    pub fn as_mut_ref(&mut self) -> &mut T {
        self.entry.get_mut()
    }
    #[inline]
    pub fn get(&self) -> &T {
        self.entry.get()
    }
    #[inline]
    pub fn get_mut(&mut self) -> &mut T {
        self.entry.get_mut()
    }
}