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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use byteorder::{LittleEndian, ReadBytesExt};
use std::fs::File;
use std::io::prelude::*;
use romy_core::output::*;
use romy_core::runtime::*;
use romy_core::*;
use wasmer_runtime::memory::MemoryView;
use wasmer_runtime::{imports, instantiate, Func, Instance, Memory};
struct RomyWasmer {
instance: Instance,
info: Info,
memory: Vec<u8>,
}
impl RomyWasmer {
fn new(mut instance: Instance) -> Self {
let info: Info = Self::call_on_instance(&mut instance, "init", Option::<&i32>::None);
let mut memory = Vec::new();
Self::dump_memory(instance.context().memory(0), &mut memory);
Self {
instance,
info,
memory,
}
}
fn dump_memory(_memory: &Memory, _to: &mut Vec<u8>) {
}
fn restore_memory(_memory: &Memory, _data: &[u8]) {
}
fn get<'a, T: serde::Deserialize<'a>>(instance: &mut Instance, pointer: usize) -> T {
let view: MemoryView<u8> = instance.context_mut().memory(0).view();
let slice: Vec<_> = view[pointer..(pointer + 8)]
.iter()
.map(std::cell::Cell::get)
.collect();
let size = (&slice[0..8]).read_u64::<LittleEndian>().unwrap() as usize;
let slice: Vec<_> = view[pointer..(pointer + size + 8)]
.iter()
.map(std::cell::Cell::get)
.collect();
let result = unsafe { serial::decode_with_size_ptr(slice.as_ptr()) };
Self::free(instance, pointer);
result
}
fn set(instance: &mut Instance, object: &impl serde::Serialize) -> usize {
let params = serial::encode_with_size(object);
let alloc: Func<i32, u32> = instance.func("allocate").unwrap();
let location = alloc.call(params.len() as i32).unwrap() as usize;
let view: MemoryView<u8> = instance.context_mut().memory(0).view();
let slice = &view[location..(location + params.len())];
for i in 0..params.len() {
slice[i].set(params[i]);
}
location
}
fn free(instance: &mut Instance, pointer: usize) {
let deallocate: Func<u32, ()> = instance.func("deallocate").unwrap();
deallocate.call(pointer as u32).unwrap()
}
fn call_on_instance<'a, T: serde::Deserialize<'a>>(
instance: &mut Instance,
id: &str,
arg: Option<&impl serde::Serialize>,
) -> T {
let pointer = match arg {
Some(arg) => {
let location = Self::set(instance, arg);
let func: Func<u32, u32> = instance.func(id).unwrap();
let result = func.call(location as u32).unwrap() as usize;
Self::free(instance, location);
result
}
None => {
let func: Func<(), u32> = instance.func(id).unwrap();
func.call().unwrap() as usize
}
};
Self::get(instance, pointer)
}
fn call<'a, T: serde::Deserialize<'a>>(
&mut self,
id: &str,
arg: Option<&impl serde::Serialize>,
) -> T {
Self::call_on_instance(&mut self.instance, id, arg)
}
fn call_without_return(&mut self, id: &str, arg: Option<&impl serde::Serialize>) {
let instance = &mut self.instance;
match arg {
Some(arg) => {
let location = Self::set(instance, arg);
let func: Func<u32, ()> = instance.func(id).unwrap();
func.call(location as u32).unwrap();
Self::free(instance, location);
}
None => {
let func: Func<(), ()> = instance.func(id).unwrap();
func.call().unwrap();
}
};
}
}
impl GameMut for RomyWasmer {
fn step(&mut self, arguments: &StepArguments) {
Self::restore_memory(self.instance.context_mut().memory(0), &self.memory);
self.call_without_return("step", Some(arguments));
Self::dump_memory(self.instance.context().memory(0), &mut self.memory);
}
fn draw(&mut self, arguments: &DrawArguments) -> Image {
self.call("draw", Some(arguments))
}
fn render_audio(&mut self, arguments: &RenderAudioArguments) -> Sound {
self.call("render_audio", Some(arguments))
}
}
pub fn load(path: &str) -> Option<RunBundle> {
if let Ok(mut file) = File::open(path) {
let mut buffer = Vec::new();
if file.read_to_end(&mut buffer).is_ok() {
return load_bytes(&buffer);
}
}
None
}
pub fn load_bytes(buffer: &[u8]) -> Option<RunBundle> {
let import_object = imports! {};
if let Ok(instance) = instantiate(&buffer, &import_object) {
let wasm = RomyWasmer::new(instance);
let info = wasm.info.clone();
return Some(RunBundle::new(Box::new(wasm), info));
}
None
}