1use std::ops::Index;
11
12use crate::{Value, opcode::UpvalueIdx};
13
14pub struct UpvalueData(u64);
18
19impl UpvalueData {
20 #[inline]
21 pub fn new(count: usize, captures_with: bool) -> Self {
22 debug_assert!(
23 count < (i64::MAX as usize),
24 "upvalue count exceeds storage size"
25 );
26
27 let raw = ((count as u64) << 1) | (if captures_with { 1 } else { 0 });
28 Self(raw)
29 }
30
31 #[inline]
32 pub fn from_raw(value: u64) -> Self {
33 Self(value)
34 }
35
36 #[inline]
37 pub fn count(&self) -> usize {
38 (self.0 as usize) >> 1
39 }
40
41 #[inline]
42 pub fn captures_with(&self) -> bool {
43 self.0 & 0b1 == 1
44 }
45
46 #[inline]
47 pub fn into_raw(self) -> u64 {
48 self.0
49 }
50}
51
52#[derive(Clone, Debug)]
66pub struct Upvalues {
67 static_upvalues: Vec<Value>,
71
72 with_stack: Vec<Value>,
76}
77
78impl Upvalues {
79 pub fn with_capacity(count: usize) -> Self {
80 Upvalues {
81 static_upvalues: Vec::with_capacity(count),
82 with_stack: vec![],
83 }
84 }
85
86 pub fn from_raw_parts(static_upvalues: Vec<Value>, with_stack: Vec<Value>) -> Self {
88 Self {
89 static_upvalues,
90 with_stack,
91 }
92 }
93
94 pub fn len(&self) -> usize {
96 self.static_upvalues.len()
97 }
98
99 pub fn get_from_with_stack(&self, index: usize) -> Option<Value> {
102 self.with_stack.get(index).cloned()
103 }
104
105 pub fn with_stack(&self) -> &Vec<Value> {
106 self.with_stack.as_ref()
107 }
108
109 pub fn with_stack_len(&self) -> usize {
110 self.with_stack.len()
111 }
112
113 pub fn into_static_upvalues(self) -> Vec<Value> {
114 self.static_upvalues
115 }
116
117 pub fn resolve_deferred_upvalues(&mut self, stack: &[Value]) {
120 for upvalue in self.static_upvalues.iter_mut() {
121 if let Value::DeferredUpvalue(update_from_idx) = upvalue {
122 *upvalue = stack[update_from_idx.0].clone();
123 }
124 }
125 }
126}
127
128impl Index<UpvalueIdx> for Upvalues {
129 type Output = Value;
130
131 fn index(&self, index: UpvalueIdx) -> &Self::Output {
132 &self.static_upvalues[index.0]
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::UpvalueData;
139 #[test]
140 fn test_upvalue() {
141 assert_eq!(
142 std::mem::size_of::<UpvalueData>(),
143 std::mem::size_of::<usize>(),
144 "The size of the UpvalueData should match the size of usize/u64."
145 );
146 let value = UpvalueData::new(456, false);
147 assert!(!value.captures_with());
148 assert_eq!(value.count(), 456);
149
150 let value = UpvalueData::from_raw(value.into_raw());
151 assert!(!value.captures_with());
152 assert_eq!(value.count(), 456);
153
154 let value = UpvalueData::new(1024, true);
155 assert!(value.captures_with());
156 assert_eq!(value.count(), 1024);
157
158 let value = UpvalueData::from_raw(value.into_raw());
159 assert!(value.captures_with());
160 assert_eq!(value.count(), 1024);
161 }
162}