1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use crate::{RawVal, TypedRawVal, ValType};
use core::{error::Error, fmt, fmt::Display, ptr::NonNull};
/// An error that may occur upon operating on global variables.
#[derive(Debug)]
#[non_exhaustive]
pub enum GlobalError {
/// Occurs when trying to write to an immutable global variable.
ImmutableWrite,
/// Occurs when trying writing a value with mismatching type to a global variable.
TypeMismatch,
}
impl Error for GlobalError {}
impl Display for GlobalError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let message = match self {
Self::ImmutableWrite => "tried to write to immutable global variable",
Self::TypeMismatch => "tried to write value of non-matching type to global variable",
};
write!(f, "{message}")
}
}
/// The mutability of a global variable.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Mutability {
/// The value of the global variable is a constant.
Const,
/// The value of the global variable is mutable.
Var,
}
impl Mutability {
/// Returns `true` if this mutability is [`Mutability::Const`].
pub fn is_const(&self) -> bool {
matches!(self, Self::Const)
}
/// Returns `true` if this mutability is [`Mutability::Var`].
pub fn is_mut(&self) -> bool {
matches!(self, Self::Var)
}
}
/// The type of a global variable.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct GlobalType {
/// The value type of the global variable.
content: ValType,
/// The mutability of the global variable.
mutability: Mutability,
}
impl GlobalType {
/// Creates a new [`GlobalType`] from the given [`ValType`] and [`Mutability`].
pub fn new(content: ValType, mutability: Mutability) -> Self {
Self {
content,
mutability,
}
}
/// Returns the [`ValType`] of the global variable.
pub fn content(&self) -> ValType {
self.content
}
/// Returns the [`Mutability`] of the global variable.
pub fn mutability(&self) -> Mutability {
self.mutability
}
}
/// A global variable entity.
#[derive(Debug)]
pub struct Global {
/// The current value of the global variable.
value: RawVal,
/// The type of the global variable.
ty: GlobalType,
}
impl Global {
/// Creates a new global variable with the given initial `value` and type `ty`.
pub fn new(value: RawVal, ty: GlobalType) -> Self {
Self { value, ty }
}
/// Returns the [`GlobalType`] of the global variable.
pub fn ty(&self) -> GlobalType {
self.ty
}
/// Sets a new value to the global variable.
///
/// # Errors
///
/// - If the [`Global`] is immutable.
/// - If `new_value` does not match the type of the [`Global`].
pub fn set(&mut self, new_value: TypedRawVal) -> Result<(), GlobalError> {
if !self.ty().mutability().is_mut() {
return Err(GlobalError::ImmutableWrite);
}
if self.ty().content() != new_value.ty() {
return Err(GlobalError::TypeMismatch);
}
self.value = new_value.into();
Ok(())
}
/// Returns the current [`TypedRawVal`] of the [`Global`].
pub fn get(&self) -> TypedRawVal {
TypedRawVal::new(self.ty().content(), self.value)
}
/// Returns the current [`RawVal`] of the [`Global`].
pub fn get_raw(&self) -> &RawVal {
&self.value
}
/// Returns a pointer to the [`RawVal`] of the [`Global`].
///
/// # Panics (Debug)
///
/// If the underlying global value is immutable.
pub fn get_raw_ptr(&mut self) -> NonNull<RawVal> {
debug_assert!(matches!(self.ty.mutability(), Mutability::Var));
NonNull::from(&mut self.value)
}
}