Skip to content

Commit 475828b

Browse files
authored
Merge pull request #581 from wasmerio/wasi-imports
WASI imports should return a dict
2 parents 01f9201 + 6c988f0 commit 475828b

File tree

4 files changed

+123
-10
lines changed

4 files changed

+123
-10
lines changed

packages/api/src/import_object.rs

+51
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,20 @@ impl ImportObject {
163163
}
164164
}
165165

166+
impl ImportObject {
167+
/// Gets an `ImportObject` from a Python dictionary.
168+
pub(crate) fn from_pydict(dict: &PyDict) -> Result<Self, PyErr> {
169+
let mut io = ImportObject::new();
170+
for (namespace_name, namespace_dict) in dict.into_iter() {
171+
let namespace_name = namespace_name.to_string();
172+
let namespace_dict = namespace_dict
173+
.downcast::<PyDict>()?;
174+
io.register(&namespace_name, namespace_dict)?;
175+
}
176+
Ok(io)
177+
}
178+
}
179+
166180
#[pymethods]
167181
impl ImportObject {
168182
#[new]
@@ -186,6 +200,43 @@ impl ImportObject {
186200
self.inner.contains_namespace(namespace_name)
187201
}
188202

203+
/// Gets a Python dictionary from an `ImportObject`.
204+
#[pyo3(text_signature = "($self)")]
205+
pub(crate) fn to_dict<'py>(&'py self) -> Result<PyObject, PyErr> {
206+
let gil_guard = Python::acquire_gil();
207+
let py = gil_guard.python();
208+
209+
let dict = PyDict::new(py);
210+
for (namespace, name, export) in self.inner.externs_vec() {
211+
let elem = match export {
212+
wasmer::Extern::Function(function) => {
213+
Py::new(py, Function::raw_new(function.clone()))?.to_object(py)
214+
}
215+
wasmer::Extern::Global(global) => {
216+
Py::new(py, Global::raw_new(global.clone()))?.to_object(py)
217+
}
218+
wasmer::Extern::Memory(memory) => {
219+
Py::new(py, Memory::raw_new(memory.clone()))?.to_object(py)
220+
}
221+
wasmer::Extern::Table(table) => {
222+
Py::new(py, Table::raw_new(table.clone()))?.to_object(py)
223+
}
224+
};
225+
let namespace_dict = match dict.get_item(&namespace) {
226+
Some(namespace_dict) => {
227+
namespace_dict
228+
},
229+
None => {
230+
let namespace_dict = PyDict::new(py);
231+
dict.set_item(&namespace, namespace_dict)?;
232+
namespace_dict
233+
}
234+
};
235+
namespace_dict.set_item(&name, elem)?;
236+
}
237+
Ok(dict.to_object(py))
238+
}
239+
189240
/// Registers a set of `Function`, `Memory`, `Global` or `Table`
190241
/// to a particular namespace.
191242
///

packages/api/src/instance.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,8 @@ impl Instance {
113113
Ok(io) => wasmer::Instance::new(&module, io.borrow().inner()),
114114
Err(_e) => match import_object.downcast::<PyDict>() {
115115
Ok(dict) => {
116-
let mut io = ImportObject::new();
117-
for (namespace_name, namespace_dict) in dict.into_iter() {
118-
let namespace_name = namespace_name.to_string();
119-
let namespace_dict = namespace_dict
120-
.downcast::<PyDict>()
121-
.map_err(|e| InstanceError::PyErr(e.into()))?;
122-
io.register(&namespace_name, namespace_dict)
123-
.map_err(|e| InstanceError::PyErr(e.into()))?;
124-
}
116+
let io = ImportObject::from_pydict(dict)
117+
.map_err(|e| InstanceError::PyErr(e.into()))?;
125118
wasmer::Instance::new(&module, io.borrow().inner())
126119
}
127120
Err(e) => {

packages/api/src/wasi.rs

+21
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,27 @@ impl Environment {
474474

475475
ImportObject::raw_new(import_object)
476476
}
477+
478+
/// Create a dictionary of import with an existing
479+
/// `Environment`. The import object will be different according
480+
/// to the WASI version.
481+
///
482+
/// Use the `Version` enum to use a specific WASI version, or use
483+
/// `get_version` to read the WASI version from a `wasmer.Module`.
484+
///
485+
/// ## Example
486+
///
487+
/// ```py
488+
/// from wasmer import wasi, Store
489+
///
490+
/// store = Store()
491+
/// wasi_env = wasi.StateBuilder('test-program').argument('--foo').finalize()
492+
/// imports = wasi_env.generate_imports(store, wasi.Version.SNAPSHOT1)
493+
/// ```
494+
//#[pyo3(text_signature = "($self, store, wasi_version)")]
495+
fn generate_imports(&self, store: &Store, wasi_version: Version) -> PyResult<PyObject> {
496+
self.generate_import_object(store, wasi_version).to_dict()
497+
}
477498
}
478499

479500
pub fn get_version(module: &Module, strict: bool) -> Option<Version> {

tests/test_wasi.py

+49-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,55 @@ def test_wasi_env():
3333
def test_wasi_import_object():
3434
env = wasi.StateBuilder("foo").finalize()
3535

36-
assert isinstance(env.generate_import_object(Store(), wasi.Version.LATEST), ImportObject)
36+
import_object = env.generate_import_object(Store(), wasi.Version.LATEST)
37+
assert isinstance(import_object, dict)
38+
assert sorted(import_object['wasi_snapshot_preview1'].keys()) == [
39+
'args_get',
40+
'args_sizes_get',
41+
'clock_res_get',
42+
'clock_time_get',
43+
'environ_get',
44+
'environ_sizes_get',
45+
'fd_advise',
46+
'fd_allocate',
47+
'fd_close',
48+
'fd_datasync',
49+
'fd_fdstat_get',
50+
'fd_fdstat_set_flags',
51+
'fd_fdstat_set_rights',
52+
'fd_filestat_get',
53+
'fd_filestat_set_size',
54+
'fd_filestat_set_times',
55+
'fd_pread',
56+
'fd_prestat_dir_name',
57+
'fd_prestat_get',
58+
'fd_pwrite',
59+
'fd_read',
60+
'fd_readdir',
61+
'fd_renumber',
62+
'fd_seek',
63+
'fd_sync',
64+
'fd_tell',
65+
'fd_write',
66+
'path_create_directory',
67+
'path_filestat_get',
68+
'path_filestat_set_times',
69+
'path_link',
70+
'path_open',
71+
'path_readlink',
72+
'path_remove_directory',
73+
'path_rename',
74+
'path_symlink',
75+
'path_unlink_file',
76+
'poll_oneoff',
77+
'proc_exit',
78+
'proc_raise',
79+
'random_get',
80+
'sched_yield',
81+
'sock_recv',
82+
'sock_send',
83+
'sock_shutdown'
84+
]
3785

3886
def test_wasi_env_memory():
3987
store = Store()

0 commit comments

Comments
 (0)