lucet_module/
globals.rs

1use serde::{Deserialize, Serialize};
2
3/// A WebAssembly global along with its export specification.
4///
5/// The lifetime parameter exists to support zero-copy deserialization for the `&str` fields at the
6/// leaves of the structure. For a variant with owned types at the leaves, see
7/// [`OwnedGlobalSpec`](owned/struct.OwnedGlobalSpec.html).
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct GlobalSpec<'a> {
10    #[serde(borrow)]
11    global: Global<'a>,
12    export_names: Vec<&'a str>,
13}
14
15impl<'a> GlobalSpec<'a> {
16    pub fn new(global: Global<'a>, export_names: Vec<&'a str>) -> Self {
17        Self {
18            global,
19            export_names,
20        }
21    }
22
23    /// Create a new global definition with an initial value and export names.
24    pub fn new_def(init_val: i64, export_names: Vec<&'a str>) -> Self {
25        Self::new(Global::Def(GlobalDef::I64(init_val)), export_names)
26    }
27
28    /// Create a new global import definition with a module and field name, and export names.
29    pub fn new_import(module: &'a str, field: &'a str, export_names: Vec<&'a str>) -> Self {
30        Self::new(Global::Import { module, field }, export_names)
31    }
32
33    pub fn global(&self) -> &Global<'_> {
34        &self.global
35    }
36
37    pub fn export_names(&self) -> &[&str] {
38        &self.export_names
39    }
40
41    pub fn is_internal(&self) -> bool {
42        self.export_names.len() == 0
43    }
44}
45
46/// A WebAssembly global is either defined locally, or is defined in relation to a field of another
47/// WebAssembly module.
48///
49/// The lifetime parameter exists to support zero-copy deserialization for the `&str` fields at the
50/// leaves of the structure. For a variant with owned types at the leaves, see
51/// [`OwnedGlobal`](owned/struct.OwnedGlobal.html).
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
53pub enum Global<'a> {
54    Def(GlobalDef),
55    Import { module: &'a str, field: &'a str },
56}
57
58/// Definition for a global in this module (not imported).
59#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
60pub enum GlobalDef {
61    I32(i32),
62    I64(i64),
63    F32(f32),
64    F64(f64),
65}
66
67impl GlobalDef {
68    pub fn init_val(&self) -> GlobalValue {
69        match self {
70            GlobalDef::I32(i) => GlobalValue { i_32: *i },
71            GlobalDef::I64(i) => GlobalValue { i_64: *i },
72            GlobalDef::F32(f) => GlobalValue { f_32: *f },
73            GlobalDef::F64(f) => GlobalValue { f_64: *f },
74        }
75    }
76}
77
78#[derive(Copy, Clone)]
79pub union GlobalValue {
80    pub i_32: i32,
81    pub i_64: i64,
82    pub f_32: f32,
83    pub f_64: f64,
84}
85
86impl std::fmt::Debug for GlobalValue {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        // Because GlobalValue is a union of primitives, there won't be anything wrong,
89        // representation-wise, with printing the underlying data as an i64, f64, or
90        // another primitive. This still may incur UB by doing something like trying to
91        // read data from an uninitialized memory, if the union is initialized with a
92        // 32-bit value, and then read as a 64-bit value (as this code is about to do).
93        //
94        // In short, avoid using `<GlobalValue as Debug>`::fmt, please.
95
96        writeln!(f, "GlobalValue {{")?;
97        unsafe {
98            writeln!(f, "  i_32: {},", self.i_32)?;
99            writeln!(f, "  i_64: {},", self.i_64)?;
100            writeln!(f, "  f_32: {},", self.f_32)?;
101            writeln!(f, "  f_64: {},", self.f_64)?;
102        }
103        writeln!(f, "}}")
104    }
105}
106
107/////////////////////////////////////////////////////////////////////////////////////////////////////////
108
109/// A variant of [`GlobalSpec`](../struct.GlobalSpec.html) with owned strings throughout.
110///
111/// This type is useful when directly building up a value to be serialized.
112pub struct OwnedGlobalSpec {
113    global: OwnedGlobal,
114    export_names: Vec<String>,
115}
116
117impl OwnedGlobalSpec {
118    pub fn new(global: OwnedGlobal, export_names: Vec<String>) -> Self {
119        Self {
120            global,
121            export_names,
122        }
123    }
124
125    /// Create a new global definition with an initial value and export names.
126    pub fn new_def(init_val: i64, export_names: Vec<String>) -> Self {
127        Self::new(OwnedGlobal::Def(GlobalDef::I64(init_val)), export_names)
128    }
129
130    /// Create a new global import definition with a module and field name, and export names.
131    pub fn new_import(module: String, field: String, export_names: Vec<String>) -> Self {
132        Self::new(OwnedGlobal::Import { module, field }, export_names)
133    }
134
135    /// Create a [`GlobalSpec`](../struct.GlobalSpec.html) backed by the values in this
136    /// `OwnedGlobalSpec`.
137    pub fn to_ref<'a>(&'a self) -> GlobalSpec<'a> {
138        GlobalSpec::new(
139            self.global.to_ref(),
140            self.export_names.iter().map(|x| x.as_str()).collect(),
141        )
142    }
143}
144
145/// A variant of [`Global`](../struct.Global.html) with owned strings throughout.
146///
147/// This type is useful when directly building up a value to be serialized.
148pub enum OwnedGlobal {
149    Def(GlobalDef),
150    Import { module: String, field: String },
151}
152
153impl OwnedGlobal {
154    /// Create a [`Global`](../struct.Global.html) backed by the values in this `OwnedGlobal`.
155    pub fn to_ref<'a>(&'a self) -> Global<'a> {
156        match self {
157            OwnedGlobal::Def(def) => Global::Def(def.clone()),
158            OwnedGlobal::Import { module, field } => Global::Import {
159                module: module.as_str(),
160                field: field.as_str(),
161            },
162        }
163    }
164}