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
/*
 * @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 crate::entry::{MutPresent, Spot};
#[cfg(feature = "debug-arena")]
use crate::nonce;
use crate::types::{Ix, Root, Weak};
use alloc::vec::Vec;
use core::cell::RefCell;
use core::fmt;

/**
 * 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(())
    }
}

/**
 * An entry inside the region, allowing
 * access to the underlying value and
 * the index, as well as Root and Weak creation.
 */
pub struct Entry<'a, T> {
    pub(crate) ix: Ix<T>,
    pub(crate) present: MutPresent<'a, T>,
    pub(crate) roots: &'a RefCell<Vec<Root<T>>>,
}

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

impl<'a, T> Entry<'a, T> {
    #[inline]
    pub fn root(&self) -> Root<T> {
        let i = self.ix;
        let r = self.present.root(i);
        if !r.is_otherwise_rooted() {
            self.roots.borrow_mut().push(r.clone());
        };
        r
    }

    #[inline]
    pub fn weak(&self) -> Weak<T> {
        self.present.weak(self.ix)
    }
    #[inline]
    pub fn ix(&self) -> Ix<T> {
        self.ix
    }
    #[inline]
    pub fn get(&self) -> &T {
        self.present.get()
    }
    #[inline]
    pub fn get_mut(&mut self) -> &mut T {
        self.present.reborrow().get_mut()
    }
    #[inline(always)]
    pub fn reborrow(&mut self) -> Entry<T> {
        let Entry { ix, present, roots } = self;
        let present = present.reborrow();
        Entry {
            ix: *ix,
            present,
            roots,
        }
    }
}