1use super::{AsContext, AsContextMut, Stored};
2use crate::{
3 collections::arena::ArenaIndex,
4 core::{UntypedVal, ValType},
5 value::WithType,
6 Val,
7};
8use core::{fmt, fmt::Display, ptr::NonNull};
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
12pub struct GlobalIdx(u32);
13
14impl ArenaIndex for GlobalIdx {
15 fn into_usize(self) -> usize {
16 self.0 as usize
17 }
18
19 fn from_usize(value: usize) -> Self {
20 let value = value.try_into().unwrap_or_else(|error| {
21 panic!("index {value} is out of bounds as global index: {error}")
22 });
23 Self(value)
24 }
25}
26
27#[derive(Debug)]
29#[non_exhaustive]
30pub enum GlobalError {
31 ImmutableWrite,
33 TypeMismatch {
35 expected: ValType,
37 encountered: ValType,
39 },
40 UnsatisfyingGlobalType {
42 unsatisfying: GlobalType,
44 required: GlobalType,
46 },
47}
48
49#[cfg(feature = "std")]
50impl std::error::Error for GlobalError {}
51
52impl Display for GlobalError {
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 match self {
55 Self::ImmutableWrite => write!(f, "tried to write to immutable global variable"),
56 Self::TypeMismatch {
57 expected,
58 encountered,
59 } => {
60 write!(
61 f,
62 "type mismatch upon writing global variable. \
63 expected {expected:?} but encountered {encountered:?}.",
64 )
65 }
66 Self::UnsatisfyingGlobalType {
67 unsatisfying,
68 required,
69 } => {
70 write!(
71 f,
72 "global type {unsatisfying:?} does not \
73 satisfy requirements of {required:?}",
74 )
75 }
76 }
77 }
78}
79
80#[derive(Debug, Copy, Clone, PartialEq, Eq)]
82pub enum Mutability {
83 Const,
85 Var,
87}
88
89impl Mutability {
90 pub fn is_const(&self) -> bool {
92 matches!(self, Self::Const)
93 }
94
95 pub fn is_mut(&self) -> bool {
97 matches!(self, Self::Var)
98 }
99}
100
101#[derive(Debug, Copy, Clone, PartialEq, Eq)]
103pub struct GlobalType {
104 content: ValType,
106 mutability: Mutability,
108}
109
110impl GlobalType {
111 pub fn new(content: ValType, mutability: Mutability) -> Self {
113 Self {
114 content,
115 mutability,
116 }
117 }
118
119 pub fn content(&self) -> ValType {
121 self.content
122 }
123
124 pub fn mutability(&self) -> Mutability {
126 self.mutability
127 }
128
129 pub(crate) fn satisfies(&self, required: &GlobalType) -> Result<(), GlobalError> {
136 if self != required {
137 return Err(GlobalError::UnsatisfyingGlobalType {
138 unsatisfying: *self,
139 required: *required,
140 });
141 }
142 Ok(())
143 }
144}
145
146#[derive(Debug)]
148pub struct GlobalEntity {
149 value: UntypedVal,
151 ty: GlobalType,
153}
154
155impl GlobalEntity {
156 pub fn new(initial_value: Val, mutability: Mutability) -> Self {
158 Self {
159 ty: GlobalType::new(initial_value.ty(), mutability),
160 value: initial_value.into(),
161 }
162 }
163
164 pub fn ty(&self) -> GlobalType {
166 self.ty
167 }
168
169 pub fn set(&mut self, new_value: Val) -> Result<(), GlobalError> {
176 if !self.ty().mutability().is_mut() {
177 return Err(GlobalError::ImmutableWrite);
178 }
179 if self.ty().content() != new_value.ty() {
180 return Err(GlobalError::TypeMismatch {
181 expected: self.ty().content(),
182 encountered: new_value.ty(),
183 });
184 }
185 self.set_untyped(new_value.into());
186 Ok(())
187 }
188
189 pub(crate) fn set_untyped(&mut self, new_value: UntypedVal) {
198 self.value = new_value;
199 }
200
201 pub fn get(&self) -> Val {
203 self.get_untyped().with_type(self.ty().content())
204 }
205
206 pub(crate) fn get_untyped(&self) -> UntypedVal {
208 self.value
209 }
210
211 pub(crate) fn get_untyped_ptr(&mut self) -> NonNull<UntypedVal> {
213 NonNull::from(&mut self.value)
214 }
215}
216
217#[derive(Debug, Copy, Clone)]
219#[repr(transparent)]
220pub struct Global(Stored<GlobalIdx>);
221
222impl Global {
223 pub(super) fn from_inner(stored: Stored<GlobalIdx>) -> Self {
231 Self(stored)
232 }
233
234 pub(super) fn as_inner(&self) -> &Stored<GlobalIdx> {
236 &self.0
237 }
238
239 pub fn new(mut ctx: impl AsContextMut, initial_value: Val, mutability: Mutability) -> Self {
241 ctx.as_context_mut()
242 .store
243 .inner
244 .alloc_global(GlobalEntity::new(initial_value, mutability))
245 }
246
247 pub fn ty(&self, ctx: impl AsContext) -> GlobalType {
249 ctx.as_context().store.inner.resolve_global(self).ty()
250 }
251
252 pub fn set(&self, mut ctx: impl AsContextMut, new_value: Val) -> Result<(), GlobalError> {
263 ctx.as_context_mut()
264 .store
265 .inner
266 .resolve_global_mut(self)
267 .set(new_value)
268 }
269
270 pub fn get(&self, ctx: impl AsContext) -> Val {
276 ctx.as_context().store.inner.resolve_global(self).get()
277 }
278}