-
Notifications
You must be signed in to change notification settings - Fork 1
/
sapp_jsutils.js
156 lines (129 loc) · 5.24 KB
/
sapp_jsutils.js
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
var ctx = null;
js_objects = {}
unique_js_id = 0
register_plugin = function (importObject) {
importObject.env.js_create_string = function (buf, max_len) {
var string = UTF8ToString(buf, max_len);
return js_object(string);
}
// Copy given bytes into newly allocated Uint8Array
importObject.env.js_create_buffer = function (buf, max_len) {
var src = new Uint8Array(wasm_memory.buffer, buf, max_len);
var new_buffer = new Uint8Array(new ArrayBuffer(src.byteLength));
new_buffer.set(new Uint8Array(src));
return js_object(new_buffer);
}
importObject.env.js_create_object = function () {
var object = {};
return js_object(object);
}
importObject.env.js_set_field_f32 = function (js_object, buf, max_len, data) {
var field = UTF8ToString(buf, max_len);
js_objects[js_object][field] = data;
}
importObject.env.js_unwrap_to_str = function (js_object, buf, max_len) {
var str = js_objects[js_object];
var utf8array = toUTF8Array(str);
var length = utf8array.length;
var dest = new Uint8Array(wasm_memory.buffer, buf, max_len); // with max_len in case of buffer overflow we will panic (I BELIEVE) in js, no UB in rust
for (var i = 0; i < length; i++) {
dest[i] = utf8array[i];
}
}
importObject.env.js_unwrap_to_buf = function (js_object, buf, max_len) {
var src = js_objects[js_object];
var length = src.length;
var dest = new Uint8Array(wasm_memory.buffer, buf, max_len);
for (var i = 0; i < length; i++) {
dest[i] = src[i];
}
}
// measure length of the string. This function allocates because there is no way
// go get string byte length in JS
importObject.env.js_string_length = function (js_object) {
var str = js_objects[js_object];
return toUTF8Array(str).length;
}
// similar to .length call on Uint8Array in javascript.
importObject.env.js_buf_length = function (js_object) {
var buf = js_objects[js_object];
return buf.length;
}
importObject.env.js_free_object = function (js_object) {
delete js_objects[js_object];
}
importObject.env.js_have_field = function (js_object, buf, length) {
var field_name = UTF8ToString(buf, length);
return js_objects[js_object][field_name] == undefined;
}
importObject.env.js_field_num = function (js_object, buf, length) {
var field_name = UTF8ToString(buf, length);
return js_objects[js_object][field_name];
}
importObject.env.js_field = function (js_object, buf, length) {
// UTF8ToString is from gl.js wich should be in the scope now
var field_name = UTF8ToString(buf, length);
// apparently .field and ["field"] is the same thing in js
var field = js_objects[js_object][field_name];
var id = unique_js_id
js_objects[id] = field
unique_js_id += 1;
return id;
}
}
miniquad_add_plugin({ register_plugin, version: "0.1.4", name: "sapp_jsutils" });
// Its like https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder,
// but works on more browsers
function toUTF8Array(str) {
var utf8 = [];
for (var i = 0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) utf8.push(charcode);
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f));
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode >> 6) & 0x3f),
0x80 | (charcode & 0x3f));
}
// surrogate pair
else {
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
charcode = 0x10000 + (((charcode & 0x3ff) << 10)
| (str.charCodeAt(i) & 0x3ff))
utf8.push(0xf0 | (charcode >> 18),
0x80 | ((charcode >> 12) & 0x3f),
0x80 | ((charcode >> 6) & 0x3f),
0x80 | (charcode & 0x3f));
}
}
return utf8;
}
// Store js object reference to prevent JS garbage collector on destroying it
// And let Rust keep ownership of this reference
// There is no guarantees on JS side of this reference uniqueness, its good idea to use this only on rust functions arguments
function js_object(obj) {
var id = unique_js_id;
js_objects[id] = obj;
unique_js_id += 1;
return id;
}
/// Consume the JsObject returned from rust
/// Rust gives us ownership on the object. This method consume ownership from rust to normal JS garbage collector.
function consume_js_object(id) {
var object = js_objects[id];
// in JS delete operator does not delete (JS!), the intention here is to remove the value from hashmap, like "js_objects.remove(id)"
delete js_objects[id];
return object;
}
/// Get the real object from JsObject returned from rust
/// Acts like borrowing in rust, but without any checks
/// Be carefull, for most use cases "consume_js_object" is usually better option
function get_js_object(id) {
return js_objects[id];
}