luau_vm/function/
upvalue.rs1use core::mem::{ManuallyDrop, size_of};
2use core::ptr::{self, NonNull};
3
4use crate::handle::RawHandle;
5use crate::state::GlobalState;
6use crate::value::{RawTValue, TValue, TValueCursor};
7
8#[repr(C)]
9pub struct RawUpVal {
10 pub tt: u8,
11 pub marked: u8,
12 pub memcat: u8,
13 pub marked_open: u8,
14 pub value: *mut RawTValue,
15 pub data: RawUpValData,
16}
17
18#[repr(C)]
19pub struct RawUpValOpen {
20 pub prev: *mut RawUpVal,
21 pub next: *mut RawUpVal,
22 pub thread_next: *mut RawUpVal,
23}
24
25#[repr(C)]
26pub union RawUpValData {
27 pub value: ManuallyDrop<RawTValue>,
28 pub open: ManuallyDrop<RawUpValOpen>,
29}
30
31#[derive(Clone, Copy, PartialEq, Eq)]
32#[repr(transparent)]
33pub struct UpVal {
41 raw: NonNull<RawUpVal>,
42}
43
44#[derive(Clone, Copy, PartialEq, Eq)]
45#[repr(transparent)]
46pub struct UpValOpen {
51 raw: NonNull<RawUpValOpen>,
52}
53
54#[allow(
55 clippy::missing_safety_doc,
56 reason = "UpVal's shared raw-handle contract is documented on UpVal"
57)]
58impl UpVal {
59 pub const fn allocation_size() -> usize {
60 size_of::<RawUpVal>()
61 }
62
63 pub const unsafe fn from_raw(raw: NonNull<RawUpVal>) -> Self {
64 Self { raw }
65 }
66
67 pub unsafe fn from_ref(raw: &RawUpVal) -> Self {
68 Self {
69 raw: NonNull::from(raw),
70 }
71 }
72
73 pub unsafe fn open_data(&self) -> UpValOpen {
74 unsafe {
75 UpValOpen::from_raw(NonNull::new_unchecked(
76 (&raw mut (*self.as_ptr()).data.open).cast::<RawUpValOpen>(),
77 ))
78 }
79 }
80
81 pub unsafe fn value_ptr(&self) -> *mut RawTValue {
82 unsafe { self.as_ptr().as_ref().unwrap_unchecked().value }
83 }
84
85 pub unsafe fn value(&self) -> TValue {
86 unsafe { TValue::from_raw(NonNull::new_unchecked(self.value_ptr())) }
87 }
88
89 pub unsafe fn closed_value(&self) -> TValue {
90 unsafe {
91 TValue::from_raw(NonNull::new_unchecked(
92 (&raw mut (*self.as_ptr()).data.value).cast::<RawTValue>(),
93 ))
94 }
95 }
96
97 pub unsafe fn set_value(&self, value: TValue) {
98 unsafe {
99 (*self.as_ptr()).value = value.as_ptr();
100 }
101 }
102
103 pub unsafe fn rebase_value(&self, old_stack: TValueCursor, new_stack: TValueCursor) {
104 debug_assert!(unsafe { self.is_open() });
105
106 unsafe {
107 let value = TValueCursor::from_ptr(self.value_ptr());
108 let value_offset = value.addr_offset_from(old_stack) as usize;
109 (*self.as_ptr()).value = new_stack.add(value_offset).as_ptr();
110 }
111 }
112
113 pub unsafe fn close(&self) {
114 unsafe {
115 let closed_value = self.closed_value();
116 closed_value.set_obj(self.value());
117 self.set_value(closed_value);
118 }
119 }
120
121 pub unsafe fn is_open(&self) -> bool {
122 let closed_value = unsafe { (&raw const (*self.as_ptr()).data.value).cast::<RawTValue>() };
123 !core::ptr::eq(unsafe { self.value_ptr() }.cast_const(), closed_value)
124 }
125}
126
127#[allow(
128 clippy::missing_safety_doc,
129 reason = "UpValOpen's shared raw-view contract is documented on UpValOpen"
130)]
131impl UpValOpen {
132 pub const unsafe fn from_raw(raw: NonNull<RawUpValOpen>) -> Self {
133 Self { raw }
134 }
135
136 pub unsafe fn prev(&self) -> UpVal {
137 unsafe {
138 UpVal::from_raw(NonNull::new_unchecked(
139 self.as_ptr().as_ref().unwrap_unchecked().prev,
140 ))
141 }
142 }
143
144 pub unsafe fn set_prev(&self, prev: UpVal) {
145 unsafe {
146 self.as_ptr().as_mut().unwrap_unchecked().prev = prev.as_ptr();
147 }
148 }
149
150 pub unsafe fn next(&self) -> UpVal {
151 unsafe {
152 UpVal::from_raw(NonNull::new_unchecked(
153 self.as_ptr().as_ref().unwrap_unchecked().next,
154 ))
155 }
156 }
157
158 pub unsafe fn set_next(&self, next: UpVal) {
159 unsafe {
160 self.as_ptr().as_mut().unwrap_unchecked().next = next.as_ptr();
161 }
162 }
163
164 pub unsafe fn thread_next(&self) -> Option<UpVal> {
165 unsafe {
166 NonNull::new(self.as_ptr().as_ref().unwrap_unchecked().thread_next)
167 .map(|upvalue| UpVal::from_raw(upvalue))
168 }
169 }
170
171 pub unsafe fn set_thread_next(&self, thread_next: Option<UpVal>) {
172 unsafe {
173 self.as_ptr().as_mut().unwrap_unchecked().thread_next =
174 thread_next.map_or(ptr::null_mut(), |upvalue| upvalue.as_ptr());
175 }
176 }
177}
178
179#[allow(
180 clippy::missing_safety_doc,
181 reason = "GlobalState's shared raw-handle contract is documented on GlobalState"
182)]
183impl GlobalState {
184 pub unsafe fn uv_head(&self) -> UpVal {
185 unsafe { UpVal::from_raw(NonNull::new_unchecked(&raw mut (*self.as_ptr()).uv_head)) }
186 }
187}
188impl crate::handle::sealed::Sealed for UpVal {}
189impl crate::handle::sealed::Sealed for UpValOpen {}
190impl RawHandle for UpVal {
191 type Raw = RawUpVal;
192
193 fn as_ptr(&self) -> *mut Self::Raw {
194 self.raw.as_ptr()
195 }
196}
197
198impl AsRef<UpVal> for UpVal {
199 fn as_ref(&self) -> &UpVal {
200 self
201 }
202}
203
204impl RawHandle for UpValOpen {
205 type Raw = RawUpValOpen;
206
207 fn as_ptr(&self) -> *mut Self::Raw {
208 self.raw.as_ptr()
209 }
210}
211
212impl AsRef<UpValOpen> for UpValOpen {
213 fn as_ref(&self) -> &UpValOpen {
214 self
215 }
216}