1extern crate radix_wasmi_arena as wasmi_arena;
2
3use super::{AsContext, AsContextMut, Stored};
4use crate::core::{Value, ValueType};
5use core::{fmt, fmt::Display, ptr::NonNull};
6use wasmi_arena::ArenaIndex;
7use wasmi_core::UntypedValue;
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
11pub struct GlobalIdx(u32);
12
13impl ArenaIndex for GlobalIdx {
14 fn into_usize(self) -> usize {
15 self.0 as usize
16 }
17
18 fn from_usize(value: usize) -> Self {
19 let value = value.try_into().unwrap_or_else(|error| {
20 panic!("index {value} is out of bounds as global index: {error}")
21 });
22 Self(value)
23 }
24}
25
26#[derive(Debug)]
28#[non_exhaustive]
29pub enum GlobalError {
30 ImmutableWrite,
32 TypeMismatch {
34 expected: ValueType,
36 encountered: ValueType,
38 },
39 UnsatisfyingGlobalType {
41 unsatisfying: GlobalType,
43 required: GlobalType,
45 },
46}
47
48impl Display for GlobalError {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 match self {
51 Self::ImmutableWrite => write!(f, "tried to write to immutable global variable"),
52 Self::TypeMismatch {
53 expected,
54 encountered,
55 } => {
56 write!(
57 f,
58 "type mismatch upon writing global variable. \
59 expected {expected} but encountered {encountered}.",
60 )
61 }
62 Self::UnsatisfyingGlobalType {
63 unsatisfying,
64 required,
65 } => {
66 write!(
67 f,
68 "global type {unsatisfying:?} does not \
69 satisfy requirements of {required:?}",
70 )
71 }
72 }
73 }
74}
75
76#[derive(Debug, Copy, Clone, PartialEq, Eq)]
78pub enum Mutability {
79 Const,
81 Var,
83}
84
85impl Mutability {
86 pub fn is_const(&self) -> bool {
88 matches!(self, Self::Const)
89 }
90
91 pub fn is_mut(&self) -> bool {
93 matches!(self, Self::Var)
94 }
95}
96
97#[derive(Debug, Copy, Clone, PartialEq, Eq)]
99pub struct GlobalType {
100 content: ValueType,
102 mutability: Mutability,
104}
105
106impl GlobalType {
107 pub fn new(content: ValueType, mutability: Mutability) -> Self {
109 Self {
110 content,
111 mutability,
112 }
113 }
114
115 pub fn content(&self) -> ValueType {
117 self.content
118 }
119
120 pub fn mutability(&self) -> Mutability {
122 self.mutability
123 }
124
125 pub(crate) fn satisfies(&self, required: &GlobalType) -> Result<(), GlobalError> {
132 if self != required {
133 return Err(GlobalError::UnsatisfyingGlobalType {
134 unsatisfying: *self,
135 required: *required,
136 });
137 }
138 Ok(())
139 }
140}
141
142#[derive(Debug, Clone)]
144pub struct GlobalEntity {
145 value: UntypedValue,
147 ty: GlobalType,
149}
150
151impl GlobalEntity {
152 pub fn new(initial_value: Value, mutability: Mutability) -> Self {
154 Self {
155 value: initial_value.into(),
156 ty: GlobalType::new(initial_value.ty(), mutability),
157 }
158 }
159
160 pub fn ty(&self) -> GlobalType {
162 self.ty
163 }
164
165 pub fn set(&mut self, new_value: Value) -> Result<(), GlobalError> {
172 if !self.ty().mutability().is_mut() {
173 return Err(GlobalError::ImmutableWrite);
174 }
175 if self.ty().content() != new_value.ty() {
176 return Err(GlobalError::TypeMismatch {
177 expected: self.ty().content(),
178 encountered: new_value.ty(),
179 });
180 }
181 self.set_untyped(new_value.into());
182 Ok(())
183 }
184
185 pub(crate) fn set_untyped(&mut self, new_value: UntypedValue) {
194 self.value = new_value;
195 }
196
197 pub fn get(&self) -> Value {
199 self.get_untyped().with_type(self.ty().content())
200 }
201
202 pub(crate) fn get_untyped(&self) -> UntypedValue {
204 self.value
205 }
206
207 pub(crate) fn get_untyped_ptr(&mut self) -> NonNull<UntypedValue> {
209 NonNull::from(&mut self.value)
210 }
211}
212
213#[derive(Debug, Copy, Clone)]
215#[repr(transparent)]
216pub struct Global(Stored<GlobalIdx>);
217
218impl Global {
219 pub(super) fn from_inner(stored: Stored<GlobalIdx>) -> Self {
227 Self(stored)
228 }
229
230 pub(super) fn into_inner(self) -> Stored<GlobalIdx> {
232 self.0
233 }
234
235 pub fn new(mut ctx: impl AsContextMut, initial_value: Value, mutability: Mutability) -> Self {
237 ctx.as_context_mut()
238 .store
239 .alloc_global(GlobalEntity::new(initial_value, mutability))
240 }
241
242 pub fn ty(&self, ctx: impl AsContext) -> GlobalType {
244 ctx.as_context().store.resolve_global(*self).ty()
245 }
246
247 pub fn set(&self, mut ctx: impl AsContextMut, new_value: Value) -> Result<(), GlobalError> {
258 ctx.as_context_mut()
259 .store
260 .resolve_global_mut(*self)
261 .set(new_value)
262 }
263
264 pub fn get(&self, ctx: impl AsContext) -> Value {
270 ctx.as_context().store.resolve_global(*self).get()
271 }
272}