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
/*
 * Copyright 2019 The Starlark in Rust Authors.
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::cell::{RefCell, RefMut};

use gazebo::prelude::*;

use crate::values::{Freezer, FrozenValue, Value};

#[derive(Clone, Copy, Dupe, Debug, PartialEq, Eq)]
pub(crate) struct ModuleSlotId(pub(crate) u32);

impl ModuleSlotId {
    pub fn new(index: u32) -> Self {
        Self(index)
    }
}

// Indexed slots of a module. May contain unassigned values as `None`.
#[derive(Debug)]
pub(crate) struct MutableSlots<'v>(RefCell<Vec<Option<Value<'v>>>>);

// Indexed slots of a module. May contain unassigned values as `None`.
#[derive(Debug)]
pub(crate) struct FrozenSlots(Vec<Option<FrozenValue>>);

impl<'v> MutableSlots<'v> {
    pub fn new() -> Self {
        Self(RefCell::new(Vec::new()))
    }

    pub(crate) fn get_slots_mut(&self) -> RefMut<Vec<Option<Value<'v>>>> {
        self.0.borrow_mut()
    }

    pub fn get_slot(&self, slot: ModuleSlotId) -> Option<Value<'v>> {
        self.0.borrow()[slot.0 as usize]
    }

    pub fn set_slot(&self, slot: ModuleSlotId, value: Value<'v>) {
        self.0.borrow_mut()[slot.0 as usize] = Some(value);
    }

    pub fn ensure_slot(&self, slot: ModuleSlotId) {
        // To ensure that `slot` exists, we need at least `slot + 1` slots.
        self.ensure_slots(slot.0 + 1);
    }

    pub fn ensure_slots(&self, count: u32) {
        let mut slots = self.0.borrow_mut();
        if slots.len() >= count as usize {
            return;
        }
        let extra = count as usize - slots.len();
        slots.reserve(extra);
        for _ in 0..extra {
            slots.push(None);
        }
    }

    pub(crate) fn freeze(self, freezer: &Freezer) -> anyhow::Result<FrozenSlots> {
        let slots = self
            .0
            .into_inner()
            .try_map(|x| x.into_try_map(|x| x.freeze(freezer)))?;
        Ok(FrozenSlots(slots))
    }
}

impl FrozenSlots {
    pub fn get_slot(&self, slot: ModuleSlotId) -> Option<FrozenValue> {
        self.0[slot.0 as usize]
    }
}