makepad_stitch/
global.rs

1use {
2    crate::{
3        decode::{Decode, DecodeError, Decoder},
4        downcast::{DowncastMut, DowncastRef},
5        extern_ref::UnguardedExternRef,
6        func_ref::UnguardedFuncRef,
7        store::{Handle, Store, StoreId, UnguardedHandle},
8        val::{UnguardedVal, Val, ValType},
9    },
10    std::{error::Error, fmt},
11};
12
13/// A Wasm global.
14#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
15#[repr(transparent)]
16pub struct Global(pub(crate) Handle<GlobalEntity>);
17
18impl Global {
19    /// Creates a new [`Global`] with the given [`GlobalType`] and initialization [`Val`] in the
20    /// given [`Store`].
21    ///
22    /// # Errors
23    ///
24    /// If the [`ValType`] of the initialiation [`Val`] does not match the [`ValType`] of the
25    /// [`Global`] to be created.
26    ///
27    /// # Panics
28    ///
29    /// If the initialization [`Val`] is not owned by the given [`Store`].
30    pub fn new(store: &mut Store, type_: GlobalType, val: Val) -> Result<Self, GlobalError> {
31        unsafe { Global::new_unguarded(store, type_, val.to_unguarded(store.id())) }
32    }
33
34    /// An unguarded version of [`Global::new`].
35    unsafe fn new_unguarded(
36        store: &mut Store,
37        type_: GlobalType,
38        val: UnguardedVal,
39    ) -> Result<Self, GlobalError> {
40        match (type_.val, val) {
41            (ValType::I32, UnguardedVal::I32(val)) => Ok(Self(
42                store.insert_global(GlobalEntity::I32(GlobalEntityT::new(type_.mut_, val))),
43            )),
44            (ValType::I64, UnguardedVal::I64(val)) => Ok(Self(
45                store.insert_global(GlobalEntity::I64(GlobalEntityT::new(type_.mut_, val))),
46            )),
47            (ValType::F32, UnguardedVal::F32(val)) => Ok(Self(
48                store.insert_global(GlobalEntity::F32(GlobalEntityT::new(type_.mut_, val))),
49            )),
50            (ValType::F64, UnguardedVal::F64(val)) => Ok(Self(
51                store.insert_global(GlobalEntity::F64(GlobalEntityT::new(type_.mut_, val))),
52            )),
53            (ValType::FuncRef, UnguardedVal::FuncRef(val)) => Ok(Self(
54                store.insert_global(GlobalEntity::FuncRef(GlobalEntityT::new(type_.mut_, val))),
55            )),
56            (ValType::ExternRef, UnguardedVal::ExternRef(val)) => Ok(Self(
57                store.insert_global(GlobalEntity::ExternRef(GlobalEntityT::new(type_.mut_, val))),
58            )),
59            _ => Err(GlobalError::ValTypeMismatch),
60        }
61    }
62
63    /// Returns the [`GlobalType`] of this [`Global`].
64    pub fn type_(self, store: &Store) -> GlobalType {
65        match self.0.as_ref(store) {
66            GlobalEntity::I32(global) => GlobalType {
67                mut_: global.mut_(),
68                val: ValType::I32,
69            },
70            GlobalEntity::I64(global) => GlobalType {
71                mut_: global.mut_(),
72                val: ValType::I64,
73            },
74            GlobalEntity::F32(global) => GlobalType {
75                mut_: global.mut_(),
76                val: ValType::F32,
77            },
78            GlobalEntity::F64(global) => GlobalType {
79                mut_: global.mut_(),
80                val: ValType::F64,
81            },
82            GlobalEntity::FuncRef(global) => GlobalType {
83                mut_: global.mut_(),
84                val: ValType::FuncRef,
85            },
86            GlobalEntity::ExternRef(global) => GlobalType {
87                mut_: global.mut_(),
88                val: ValType::ExternRef,
89            },
90        }
91    }
92
93    /// Returns the value of this [`Global`].
94    pub fn get(self, store: &Store) -> Val {
95        unsafe { Val::from_unguarded(self.get_unguarded(store), store.id()) }
96    }
97
98    /// An unguarded version of [`Global::get`].
99    fn get_unguarded(self, store: &Store) -> UnguardedVal {
100        match self.0.as_ref(store) {
101            GlobalEntity::I32(global) => UnguardedVal::I32(global.get()),
102            GlobalEntity::I64(global) => UnguardedVal::I64(global.get()),
103            GlobalEntity::F32(global) => UnguardedVal::F32(global.get()),
104            GlobalEntity::F64(global) => UnguardedVal::F64(global.get()),
105            GlobalEntity::FuncRef(global) => UnguardedVal::FuncRef(global.get()),
106            GlobalEntity::ExternRef(global) => UnguardedVal::ExternRef(global.get()),
107        }
108    }
109
110    /// Sets the value of this [`Global`] to the given [`Val`].
111    ///
112    /// # Errors
113    ///
114    /// - If the global is immutable.
115    /// - If the [`ValType`] of the given [`Val`] does not match the [`ValType`] of this [`Global`].
116    ///
117    /// # Panics
118    ///
119    /// If the given [`Val`] is not owned by the given [`Store`].
120    pub fn set(self, store: &mut Store, val: Val) -> Result<(), GlobalError> {
121        unsafe { self.set_unguarded(store, val.to_unguarded(store.id())) }
122    }
123
124    /// An unguarded version of [`Global::set`].
125    unsafe fn set_unguarded(self, store: &mut Store, val: UnguardedVal) -> Result<(), GlobalError> {
126        if self.type_(store).mut_ != Mut::Var {
127            return Err(GlobalError::Immutable);
128        }
129        match (self.0.as_mut(store), val) {
130            (GlobalEntity::I32(global), UnguardedVal::I32(val)) => Ok(global.set(val)),
131            (GlobalEntity::I64(global), UnguardedVal::I64(val)) => Ok(global.set(val)),
132            (GlobalEntity::F32(global), UnguardedVal::F32(val)) => Ok(global.set(val)),
133            (GlobalEntity::F64(global), UnguardedVal::F64(val)) => Ok(global.set(val)),
134            (GlobalEntity::FuncRef(global), UnguardedVal::FuncRef(val)) => Ok(global.set(val)),
135            (GlobalEntity::ExternRef(global), UnguardedVal::ExternRef(val)) => Ok(global.set(val)),
136            _ => Err(GlobalError::ValTypeMismatch),
137        }
138    }
139
140    /// Converts the given [`UnguardedGlobal`] to a [`Global`].
141    ///
142    /// # Safety
143    ///
144    /// The given [`UnguardedGlobal`] must be owned by the [`Store`] with the given [`StoreId`].
145    pub(crate) unsafe fn from_unguarded(global: UnguardedGlobal, store_id: StoreId) -> Self {
146        Self(Handle::from_unguarded(global, store_id))
147    }
148
149    /// Converts this [`Global`] to an [`UnguardedGlobal`].
150    ///
151    /// # Panics
152    ///
153    /// If this [`Global`] is not owned by the [`Store`] with the given [`StoreId`].
154    pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedGlobal {
155        self.0.to_unguarded(store_id).into()
156    }
157}
158
159/// An unguarded version of [`Global`].
160pub(crate) type UnguardedGlobal = UnguardedHandle<GlobalEntity>;
161
162/// The type of a [`Global`].
163#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
164pub struct GlobalType {
165    /// The [`Mut`] of the [`Global`]
166    pub mut_: Mut,
167    /// The [`ValType`] of the [`Global`].
168    pub val: ValType,
169}
170
171impl Decode for GlobalType {
172    fn decode(decoder: &mut Decoder<'_>) -> Result<Self, DecodeError> {
173        let val = decoder.decode()?;
174        let mut_ = decoder.decode()?;
175        Ok(Self { val, mut_ })
176    }
177}
178
179/// The mutability of a `Global`.
180#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
181pub enum Mut {
182    /// The global is a constant.
183    Const,
184    /// The global is a variable.
185    Var,
186}
187
188impl Decode for Mut {
189    fn decode(decoder: &mut Decoder<'_>) -> Result<Self, DecodeError> {
190        match decoder.read_byte()? {
191            0x00 => Ok(Self::Const),
192            0x01 => Ok(Self::Var),
193            _ => Err(DecodeError::new("malformed mutability")),
194        }
195    }
196}
197
198/// An error which can occur when operating on a [`Global`].
199#[derive(Clone, Copy, Debug)]
200#[non_exhaustive]
201pub enum GlobalError {
202    Immutable,
203    ValTypeMismatch,
204}
205
206impl fmt::Display for GlobalError {
207    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208        match self {
209            GlobalError::Immutable => write!(f, "global is immutable"),
210            GlobalError::ValTypeMismatch => write!(f, "value type mismatch"),
211        }
212    }
213}
214
215impl Error for GlobalError {}
216
217/// The representation of a [`Global`] in a [`Store`].
218#[derive(Debug)]
219pub(crate) enum GlobalEntity {
220    I32(GlobalEntityT<i32>),
221    I64(GlobalEntityT<i64>),
222    F32(GlobalEntityT<f32>),
223    F64(GlobalEntityT<f64>),
224    FuncRef(GlobalEntityT<UnguardedFuncRef>),
225    ExternRef(GlobalEntityT<UnguardedExternRef>),
226}
227
228impl GlobalEntity {
229    /// Returns a reference to the inner value of this [`GlobalEntity`] if it is a
230    /// [`GlobalEntityT<T>`].
231    pub(crate) fn downcast_ref<T>(&self) -> Option<&GlobalEntityT<T>>
232    where
233        GlobalEntityT<T>: DowncastRef<Self>,
234    {
235        GlobalEntityT::downcast_ref(self)
236    }
237
238    /// Returns a mutable reference to the inner value of this [`GlobalEntity`] if it is a
239    /// [`GlobalEntityT<T>`].
240    pub(crate) fn downcast_mut<T>(&mut self) -> Option<&mut GlobalEntityT<T>>
241    where
242        GlobalEntityT<T>: DowncastMut<Self>,
243    {
244        GlobalEntityT::downcast_mut(self)
245    }
246}
247
248/// A typed [`GlobalEntity`].
249#[derive(Debug)]
250pub(crate) struct GlobalEntityT<T> {
251    mut_: Mut,
252    val: T,
253}
254
255impl<T> GlobalEntityT<T>
256where
257    T: Copy,
258{
259    /// Creates a new [`GlobalEntityT`] with the given [`Mut`] and value.
260    fn new(mut_: Mut, val: T) -> Self {
261        Self { mut_, val }
262    }
263
264    /// Returns the [`Mut`] of this [`GlobalEntityT`].
265    fn mut_(&self) -> Mut {
266        self.mut_
267    }
268
269    /// Returns the value of this [`GlobalEntityT`].
270    pub(crate) fn get(&self) -> T {
271        self.val
272    }
273
274    /// Sets the value of this [`GlobalEntityT`] to the given value.
275    pub(crate) fn set(&mut self, val: T) {
276        self.val = val;
277    }
278}
279
280impl DowncastRef<GlobalEntity> for GlobalEntityT<i32> {
281    fn downcast_ref(global: &GlobalEntity) -> Option<&GlobalEntityT<i32>> {
282        match global {
283            GlobalEntity::I32(global) => Some(global),
284            _ => None,
285        }
286    }
287}
288
289impl DowncastMut<GlobalEntity> for GlobalEntityT<i32> {
290    fn downcast_mut(global: &mut GlobalEntity) -> Option<&mut GlobalEntityT<i32>> {
291        match global {
292            GlobalEntity::I32(global) => Some(global),
293            _ => None,
294        }
295    }
296}
297
298impl DowncastRef<GlobalEntity> for GlobalEntityT<i64> {
299    fn downcast_ref(global: &GlobalEntity) -> Option<&GlobalEntityT<i64>> {
300        match global {
301            GlobalEntity::I64(global) => Some(global),
302            _ => None,
303        }
304    }
305}
306
307impl DowncastMut<GlobalEntity> for GlobalEntityT<i64> {
308    fn downcast_mut(global: &mut GlobalEntity) -> Option<&mut GlobalEntityT<i64>> {
309        match global {
310            GlobalEntity::I64(global) => Some(global),
311            _ => None,
312        }
313    }
314}
315
316impl DowncastRef<GlobalEntity> for GlobalEntityT<f32> {
317    fn downcast_ref(global: &GlobalEntity) -> Option<&GlobalEntityT<f32>> {
318        match global {
319            GlobalEntity::F32(global) => Some(global),
320            _ => None,
321        }
322    }
323}
324
325impl DowncastMut<GlobalEntity> for GlobalEntityT<f32> {
326    fn downcast_mut(global: &mut GlobalEntity) -> Option<&mut GlobalEntityT<f32>> {
327        match global {
328            GlobalEntity::F32(global) => Some(global),
329            _ => None,
330        }
331    }
332}
333
334impl DowncastRef<GlobalEntity> for GlobalEntityT<f64> {
335    fn downcast_ref(global: &GlobalEntity) -> Option<&GlobalEntityT<f64>> {
336        match global {
337            GlobalEntity::F64(global) => Some(global),
338            _ => None,
339        }
340    }
341}
342
343impl DowncastMut<GlobalEntity> for GlobalEntityT<f64> {
344    fn downcast_mut(global: &mut GlobalEntity) -> Option<&mut GlobalEntityT<f64>> {
345        match global {
346            GlobalEntity::F64(global) => Some(global),
347            _ => None,
348        }
349    }
350}
351
352impl DowncastRef<GlobalEntity> for GlobalEntityT<UnguardedFuncRef> {
353    fn downcast_ref(global: &GlobalEntity) -> Option<&GlobalEntityT<UnguardedFuncRef>> {
354        match global {
355            GlobalEntity::FuncRef(global) => Some(global),
356            _ => None,
357        }
358    }
359}
360
361impl DowncastMut<GlobalEntity> for GlobalEntityT<UnguardedFuncRef> {
362    fn downcast_mut(global: &mut GlobalEntity) -> Option<&mut GlobalEntityT<UnguardedFuncRef>> {
363        match global {
364            GlobalEntity::FuncRef(global) => Some(global),
365            _ => None,
366        }
367    }
368}
369
370impl DowncastRef<GlobalEntity> for GlobalEntityT<UnguardedExternRef> {
371    fn downcast_ref(global: &GlobalEntity) -> Option<&GlobalEntityT<UnguardedExternRef>> {
372        match global {
373            GlobalEntity::ExternRef(global) => Some(global),
374            _ => None,
375        }
376    }
377}
378
379impl DowncastMut<GlobalEntity> for GlobalEntityT<UnguardedExternRef> {
380    fn downcast_mut(global: &mut GlobalEntity) -> Option<&mut GlobalEntityT<UnguardedExternRef>> {
381        match global {
382            GlobalEntity::ExternRef(global) => Some(global),
383            _ => None,
384        }
385    }
386}