Skip to content

Commit

Permalink
V2: use objects to define imports
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed Apr 22, 2023
1 parent 47d1f7e commit fc2aecc
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 38 deletions.
27 changes: 13 additions & 14 deletions examples/imports.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
<?php

$instance = Wasm\InstanceBuilder::fromWat(
<<<'EOWAT'
(module
(import "env" "global" (global $global (mut i32)))
(func (export "read_g") (result i32)
global.get $global)
(func (export "write_g") (param i32)
local.get 0
global.set $global))
EOWAT
)->withImports([
'env' => [
'global' => 33
]
])->build();
<<<'EOWAT'
(module
(import "env" "global" (global $global (mut i32)))
(func (export "read_g") (result i32)
global.get $global)
(func (export "write_g") (param i32)
local.get 0
global.set $global))
EOWAT
)->withImports(
Wasm\Imports::create()
->define('env', 'global', \Wasm\Type\Global::mutable(32))
)->build();

var_dump($instance->read_g());
107 changes: 83 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
mod types;

use std::collections::HashMap;

use ext_php_rs::prelude::*;
use ext_php_rs::zend::ModuleEntry;
use ext_php_rs::types::{ZendClassObject};
use ext_php_rs::*;
use crate::types::Value;
use crate::types::value::Value;

#[php_class(name="Wasm\\WasmInstance")]
pub struct WasmInstance {
Expand Down Expand Up @@ -62,13 +61,13 @@ impl WasmInstance {
}
}

type ImportsType = HashMap<String, HashMap<String, Value>>;
type ImportsType = HashMap<String, HashMap<String, i32>>;

#[php_class(name="Wasm\\InstanceBuilder")]
#[derive(Default)]
pub struct InstanceBuilder {
pub wat: Box<String>,
pub imports : Box<ImportsType>,
pub imports : Option<Box<WasmImports>>,
}

#[php_impl]
Expand All @@ -80,11 +79,11 @@ impl InstanceBuilder {
}.into()
}

pub fn with_imports(
pub fn with_imports<'a>(
#[this] this: &mut ZendClassObject<InstanceBuilder>,
imports: ImportsType
) -> &mut ZendClassObject<InstanceBuilder> {
this.imports = imports.into();
imports: &mut ZendClassObject<WasmImports>
) -> &'static mut ZendClassObject<InstanceBuilder> {
this.imports = Some((*imports).clone().into());

this
}
Expand All @@ -96,22 +95,8 @@ impl InstanceBuilder {

// Build imports
let mut import_object = wasmer::Imports::new();
for (namespace_name, namespace_dict) in (&*self.imports).into_iter() {
let namespace_name = namespace_name.to_string();
let namespace_dict_wasmer: Vec<(String, wasmer::Extern)> = namespace_dict
.into_iter()
.map(|(key, value)| (
key.clone(),
wasmer::Extern::Global(
wasmer::Global::new_mut(&mut store, value.clone().into()) // TODO : define mutability..
)
))
.collect();

import_object.register_namespace(
&namespace_name,
namespace_dict_wasmer
);
if self.imports.is_some() {
import_object = (self.imports.as_mut().unwrap()).into_wasmer_imports(&mut store)
}

let instance = wasmer::Instance::new(&mut store, &module, &import_object)
Expand All @@ -121,6 +106,80 @@ impl InstanceBuilder {
}
}


#[php_class(name="Wasm\\Imports")]
#[derive(Clone)]
pub struct WasmImports {
pub registry : HashMap<(String, String), WasmGlobal>,
}

#[php_impl]
impl WasmImports {
pub fn create() -> WasmImports {
WasmImports {
registry: HashMap::new().into()
}.into()
}

pub fn define(
//&mut self,
#[this] this: &mut ZendClassObject<WasmImports>,
namespace : String,
variable : String,
value : &mut ZendClassObject<WasmGlobal>,
) -> &'static mut ZendClassObject<WasmImports> {
this.registry.insert((namespace.clone(), variable.clone()), (*value).clone().into());

this
}
}

impl WasmImports {
pub fn into_wasmer_imports(&mut self, store : &mut wasmer::Store) -> wasmer::Imports {
let mut import_object = wasmer::Imports::new();

for ((namespace, name), value) in (&self.registry).into_iter() {
let converted = value.clone().into_wasmer_global(store);
import_object.define(&namespace, &name, converted);
}

import_object
}
}

#[php_class(name="Wasm\\Type\\Global")]
#[derive(Clone)]
pub struct WasmGlobal {
pub value : Box<Value>,
pub mutable : bool,
}

#[php_impl]
impl WasmGlobal {
pub fn mutable(value: Value) -> WasmGlobal {
WasmGlobal {value: value.into(), mutable: true}.into()
}

pub fn immutable(value: Value) -> WasmGlobal {
WasmGlobal {value: value.into(), mutable: false}.into()
}
}

impl WasmGlobal {
pub fn into_wasmer_global(&mut self, store : &mut wasmer::Store) -> wasmer::Global {
match self.mutable {
true => wasmer::Global::new_mut(store, (*self.value).into()),
false => wasmer::Global::new(store, (*self.value).into()),
}
}

pub fn into_wasmer_extern(&mut self, store : &mut wasmer::Store) -> wasmer::Extern {
wasmer::Extern::Global(
self.into_wasmer_global(store)
)
}
}

/// Used by the `phpinfo()` function and when you run `php -i`.
pub extern "C" fn php_module_info(_module: *mut ModuleEntry) {
info_table_start!();
Expand Down
1 change: 1 addition & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod value;
File renamed without changes.
68 changes: 68 additions & 0 deletions tests/ImportsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace Test;

use PHPUnit\Framework\TestCase;
use Wasm\InstanceBuilder;

class ImportsTest extends TestCase
{
public function test_it_fails_on_missing_imports() {
$this->expectException(\Exception::class);
$this->createBuilderFromWat()->build();
}

public function test_it_fails_on_unkown_env() {
$this->expectException(\Exception::class);
$this->createBuilderFromWat()->withImports(
\Wasm\Imports::create()
->define('unkown', 'global', \Wasm\Type\Global::mutable(32))
)->build();
}

public function test_it_fails_on_unkown_import_key() {
$this->expectException(\Exception::class);
$this->createBuilderFromWat()->withImports(
\Wasm\Imports::create()
->define('env', 'unkown', \Wasm\Type\Global::mutable(32))
)->build();
}

public function test_it_fails_on_invalid_type() {
$this->expectException(\Exception::class);
$this->createBuilderFromWat()->withImports(
\Wasm\Imports::create()
->define('env', 'global', \Wasm\Type\Global::mutable(1.1))
)->build();
}

public function test_it_fails_on_invalid_mutability() {
$this->expectException(\Exception::class);
$this->createBuilderFromWat()->withImports(
\Wasm\Imports::create()
->define('env', 'global', \Wasm\Type\Global::immutable(32))
)->build();
}

public function test_it_imports_simple_globals() {
$instance = $this->createBuilderFromWat()->withImports(
\Wasm\Imports::create()
->define('env', 'global', \Wasm\Type\Global::mutable(32))
)->build();

self::assertSame(32, $instance->read_g());
}

private function createBuilderFromWat(?string $wat = null): InstanceBuilder
{
return InstanceBuilder::fromWat($wat ?? <<<'EOWAT'
(module
(import "env" "global" (global $global (mut i32)))
(func (export "read_g") (result i32)
global.get $global)
(func (export "write_g") (param i32)
local.get 0
global.set $global))
EOWAT);
}
}

0 comments on commit fc2aecc

Please sign in to comment.