@ruby/head-wasm-wasi 2.4.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -55,6 +55,107 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/browser.script.umd');\`
55
55
 
56
56
  class WASIProcExit extends Error{constructor(code){super("exit with exit code "+code);this.code=code;}}let WASI=class WASI{start(instance){this.inst=instance;try{instance.exports._start();}catch(e){if(e instanceof WASIProcExit){return e.code}else {throw e}}}initialize(instance){this.inst=instance;instance.exports._initialize();}constructor(args,env,fds,options={}){this.args=[];this.env=[];this.fds=[];debug.enable(options.debug);this.args=args;this.env=env;this.fds=fds;const self=this;this.wasiImport={args_sizes_get(argc,argv_buf_size){const buffer=new DataView(self.inst.exports.memory.buffer);buffer.setUint32(argc,self.args.length,true);let buf_size=0;for(const arg of self.args){buf_size+=arg.length+1;}buffer.setUint32(argv_buf_size,buf_size,true);debug.log(buffer.getUint32(argc,true),buffer.getUint32(argv_buf_size,true));return 0},args_get(argv,argv_buf){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);const orig_argv_buf=argv_buf;for(let i=0;i<self.args.length;i++){buffer.setUint32(argv,argv_buf,true);argv+=4;const arg=new TextEncoder().encode(self.args[i]);buffer8.set(arg,argv_buf);buffer.setUint8(argv_buf+arg.length,0);argv_buf+=arg.length+1;}if(debug.enabled){debug.log(new TextDecoder("utf-8").decode(buffer8.slice(orig_argv_buf,argv_buf)));}return 0},environ_sizes_get(environ_count,environ_size){const buffer=new DataView(self.inst.exports.memory.buffer);buffer.setUint32(environ_count,self.env.length,true);let buf_size=0;for(const environ of self.env){buf_size+=environ.length+1;}buffer.setUint32(environ_size,buf_size,true);debug.log(buffer.getUint32(environ_count,true),buffer.getUint32(environ_size,true));return 0},environ_get(environ,environ_buf){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);const orig_environ_buf=environ_buf;for(let i=0;i<self.env.length;i++){buffer.setUint32(environ,environ_buf,true);environ+=4;const e=new TextEncoder().encode(self.env[i]);buffer8.set(e,environ_buf);buffer.setUint8(environ_buf+e.length,0);environ_buf+=e.length+1;}if(debug.enabled){debug.log(new TextDecoder("utf-8").decode(buffer8.slice(orig_environ_buf,environ_buf)));}return 0},clock_res_get(id,res_ptr){let resolutionValue;switch(id){case CLOCKID_MONOTONIC:{resolutionValue=5000n;break}case CLOCKID_REALTIME:{resolutionValue=1000000n;break}default:return ERRNO_NOSYS}const view=new DataView(self.inst.exports.memory.buffer);view.setBigUint64(res_ptr,resolutionValue,true);return ERRNO_SUCCESS},clock_time_get(id,precision,time){const buffer=new DataView(self.inst.exports.memory.buffer);if(id===CLOCKID_REALTIME){buffer.setBigUint64(time,BigInt(new Date().getTime())*1000000n,true);}else if(id==CLOCKID_MONOTONIC){let monotonic_time;try{monotonic_time=BigInt(Math.round(performance.now()*1e6));}catch(e){monotonic_time=0n;}buffer.setBigUint64(time,monotonic_time,true);}else {buffer.setBigUint64(time,0n,true);}return 0},fd_advise(fd,offset,len,advice){if(self.fds[fd]!=undefined){return self.fds[fd].fd_advise(offset,len,advice)}else {return ERRNO_BADF}},fd_allocate(fd,offset,len){if(self.fds[fd]!=undefined){return self.fds[fd].fd_allocate(offset,len)}else {return ERRNO_BADF}},fd_close(fd){if(self.fds[fd]!=undefined){const ret=self.fds[fd].fd_close();self.fds[fd]=undefined;return ret}else {return ERRNO_BADF}},fd_datasync(fd){if(self.fds[fd]!=undefined){return self.fds[fd].fd_datasync()}else {return ERRNO_BADF}},fd_fdstat_get(fd,fdstat_ptr){if(self.fds[fd]!=undefined){const{ret,fdstat}=self.fds[fd].fd_fdstat_get();if(fdstat!=null){fdstat.write_bytes(new DataView(self.inst.exports.memory.buffer),fdstat_ptr);}return ret}else {return ERRNO_BADF}},fd_fdstat_set_flags(fd,flags){if(self.fds[fd]!=undefined){return self.fds[fd].fd_fdstat_set_flags(flags)}else {return ERRNO_BADF}},fd_fdstat_set_rights(fd,fs_rights_base,fs_rights_inheriting){if(self.fds[fd]!=undefined){return self.fds[fd].fd_fdstat_set_rights(fs_rights_base,fs_rights_inheriting)}else {return ERRNO_BADF}},fd_filestat_get(fd,filestat_ptr){if(self.fds[fd]!=undefined){const{ret,filestat}=self.fds[fd].fd_filestat_get();if(filestat!=null){filestat.write_bytes(new DataView(self.inst.exports.memory.buffer),filestat_ptr);}return ret}else {return ERRNO_BADF}},fd_filestat_set_size(fd,size){if(self.fds[fd]!=undefined){return self.fds[fd].fd_filestat_set_size(size)}else {return ERRNO_BADF}},fd_filestat_set_times(fd,atim,mtim,fst_flags){if(self.fds[fd]!=undefined){return self.fds[fd].fd_filestat_set_times(atim,mtim,fst_flags)}else {return ERRNO_BADF}},fd_pread(fd,iovs_ptr,iovs_len,offset,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Iovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nread}=self.fds[fd].fd_pread(buffer8,iovecs,offset);buffer.setUint32(nread_ptr,nread,true);return ret}else {return ERRNO_BADF}},fd_prestat_get(fd,buf_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,prestat}=self.fds[fd].fd_prestat_get();if(prestat!=null){prestat.write_bytes(buffer,buf_ptr);}return ret}else {return ERRNO_BADF}},fd_prestat_dir_name(fd,path_ptr,path_len){if(self.fds[fd]!=undefined){const{ret,prestat_dir_name}=self.fds[fd].fd_prestat_dir_name();if(prestat_dir_name!=null){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);buffer8.set(prestat_dir_name,path_ptr);}return ret}else {return ERRNO_BADF}},fd_pwrite(fd,iovs_ptr,iovs_len,offset,nwritten_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Ciovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nwritten}=self.fds[fd].fd_pwrite(buffer8,iovecs,offset);buffer.setUint32(nwritten_ptr,nwritten,true);return ret}else {return ERRNO_BADF}},fd_read(fd,iovs_ptr,iovs_len,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Iovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nread}=self.fds[fd].fd_read(buffer8,iovecs);buffer.setUint32(nread_ptr,nread,true);return ret}else {return ERRNO_BADF}},fd_readdir(fd,buf,buf_len,cookie,bufused_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){let bufused=0;while(true){const{ret,dirent}=self.fds[fd].fd_readdir_single(cookie);if(ret!=0){buffer.setUint32(bufused_ptr,bufused,true);return ret}if(dirent==null){break}if(buf_len-bufused<dirent.head_length()){bufused=buf_len;break}const head_bytes=new ArrayBuffer(dirent.head_length());dirent.write_head_bytes(new DataView(head_bytes),0);buffer8.set(new Uint8Array(head_bytes).slice(0,Math.min(head_bytes.byteLength,buf_len-bufused)),buf);buf+=dirent.head_length();bufused+=dirent.head_length();if(buf_len-bufused<dirent.name_length()){bufused=buf_len;break}dirent.write_name_bytes(buffer8,buf,buf_len-bufused);buf+=dirent.name_length();bufused+=dirent.name_length();cookie=dirent.d_next;}buffer.setUint32(bufused_ptr,bufused,true);return 0}else {return ERRNO_BADF}},fd_renumber(fd,to){if(self.fds[fd]!=undefined&&self.fds[to]!=undefined){const ret=self.fds[to].fd_close();if(ret!=0){return ret}self.fds[to]=self.fds[fd];self.fds[fd]=undefined;return 0}else {return ERRNO_BADF}},fd_seek(fd,offset,whence,offset_out_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,offset:offset_out}=self.fds[fd].fd_seek(offset,whence);buffer.setBigInt64(offset_out_ptr,offset_out,true);return ret}else {return ERRNO_BADF}},fd_sync(fd){if(self.fds[fd]!=undefined){return self.fds[fd].fd_sync()}else {return ERRNO_BADF}},fd_tell(fd,offset_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const{ret,offset}=self.fds[fd].fd_tell();buffer.setBigUint64(offset_ptr,offset,true);return ret}else {return ERRNO_BADF}},fd_write(fd,iovs_ptr,iovs_len,nwritten_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const iovecs=Ciovec.read_bytes_array(buffer,iovs_ptr,iovs_len);const{ret,nwritten}=self.fds[fd].fd_write(buffer8,iovecs);buffer.setUint32(nwritten_ptr,nwritten,true);return ret}else {return ERRNO_BADF}},path_create_directory(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_create_directory(path)}},path_filestat_get(fd,flags,path_ptr,path_len,filestat_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));const{ret,filestat}=self.fds[fd].path_filestat_get(flags,path);if(filestat!=null){filestat.write_bytes(buffer,filestat_ptr);}return ret}else {return ERRNO_BADF}},path_filestat_set_times(fd,flags,path_ptr,path_len,atim,mtim,fst_flags){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_filestat_set_times(flags,path,atim,mtim,fst_flags)}else {return ERRNO_BADF}},path_link(old_fd,old_flags,old_path_ptr,old_path_len,new_fd,new_path_ptr,new_path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[old_fd]!=undefined&&self.fds[new_fd]!=undefined){const old_path=new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr,old_path_ptr+old_path_len));const new_path=new TextDecoder("utf-8").decode(buffer8.slice(new_path_ptr,new_path_ptr+new_path_len));return self.fds[new_fd].path_link(old_fd,old_flags,old_path,new_path)}else {return ERRNO_BADF}},path_open(fd,dirflags,path_ptr,path_len,oflags,fs_rights_base,fs_rights_inheriting,fd_flags,opened_fd_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));debug.log(path);const{ret,fd_obj}=self.fds[fd].path_open(dirflags,path,oflags,fs_rights_base,fs_rights_inheriting,fd_flags);if(ret!=0){return ret}self.fds.push(fd_obj);const opened_fd=self.fds.length-1;buffer.setUint32(opened_fd_ptr,opened_fd,true);return 0}else {return ERRNO_BADF}},path_readlink(fd,path_ptr,path_len,buf_ptr,buf_len,nread_ptr){const buffer=new DataView(self.inst.exports.memory.buffer);const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));debug.log(path);const{ret,data}=self.fds[fd].path_readlink(path);if(data!=null){if(data.length>buf_len){buffer.setUint32(nread_ptr,0,true);return ERRNO_BADF}buffer8.set(data,buf_ptr);buffer.setUint32(nread_ptr,data.length,true);}return ret}else {return ERRNO_BADF}},path_remove_directory(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_remove_directory(path)}else {return ERRNO_BADF}},path_rename(fd,old_path_ptr,old_path_len,new_fd,new_path_ptr,new_path_len){throw "FIXME what is the best abstraction for this?"},path_symlink(old_path_ptr,old_path_len,fd,new_path_ptr,new_path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const old_path=new TextDecoder("utf-8").decode(buffer8.slice(old_path_ptr,old_path_ptr+old_path_len));const new_path=new TextDecoder("utf-8").decode(buffer8.slice(new_path_ptr,new_path_ptr+new_path_len));return self.fds[fd].path_symlink(old_path,new_path)}else {return ERRNO_BADF}},path_unlink_file(fd,path_ptr,path_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);if(self.fds[fd]!=undefined){const path=new TextDecoder("utf-8").decode(buffer8.slice(path_ptr,path_ptr+path_len));return self.fds[fd].path_unlink_file(path)}else {return ERRNO_BADF}},poll_oneoff(in_,out,nsubscriptions){throw "async io not supported"},proc_exit(exit_code){throw new WASIProcExit(exit_code)},proc_raise(sig){throw "raised signal "+sig},sched_yield(){},random_get(buf,buf_len){const buffer8=new Uint8Array(self.inst.exports.memory.buffer);for(let i=0;i<buf_len;i++){buffer8[buf+i]=Math.random()*256|0;}},sock_recv(fd,ri_data,ri_flags){throw "sockets not supported"},sock_send(fd,si_data,si_flags){throw "sockets not supported"},sock_shutdown(fd,how){throw "sockets not supported"},sock_accept(fd,flags){throw "sockets not supported"}};}};
57
57
 
58
+ /**
59
+ * Create a console printer that can be used as an overlay of WASI imports.
60
+ * See the example below for how to use it.
61
+ *
62
+ * ```javascript
63
+ * const imports = {
64
+ * "wasi_snapshot_preview1": wasi.wasiImport,
65
+ * }
66
+ * const printer = consolePrinter();
67
+ * printer.addToImports(imports);
68
+ *
69
+ * const instance = await WebAssembly.instantiate(module, imports);
70
+ * printer.setMemory(instance.exports.memory);
71
+ * ```
72
+ *
73
+ * Note that the `stdout` and `stderr` functions are called with text, not
74
+ * bytes. This means that bytes written to stdout/stderr will be decoded as
75
+ * UTF-8 and then passed to the `stdout`/`stderr` functions every time a write
76
+ * occurs without buffering.
77
+ *
78
+ * @param stdout A function that will be called when stdout is written to.
79
+ * Defaults to `console.log`.
80
+ * @param stderr A function that will be called when stderr is written to.
81
+ * Defaults to `console.warn`.
82
+ * @returns An object that can be used as an overlay of WASI imports.
83
+ */
84
+ function consolePrinter({ stdout, stderr, } = {
85
+ stdout: console.log,
86
+ stderr: console.warn,
87
+ }) {
88
+ let memory = undefined;
89
+ let _view = undefined;
90
+ function getMemoryView() {
91
+ if (typeof memory === "undefined") {
92
+ throw new Error("Memory is not set");
93
+ }
94
+ if (_view === undefined || _view.buffer.byteLength === 0) {
95
+ _view = new DataView(memory.buffer);
96
+ }
97
+ return _view;
98
+ }
99
+ const decoder = new TextDecoder();
100
+ return {
101
+ addToImports(imports) {
102
+ const wasiImport = imports.wasi_snapshot_preview1;
103
+ const original_fd_write = wasiImport.fd_write;
104
+ wasiImport.fd_write = (fd, iovs, iovsLen, nwritten) => {
105
+ if (fd !== 1 && fd !== 2) {
106
+ return original_fd_write(fd, iovs, iovsLen, nwritten);
107
+ }
108
+ const view = getMemoryView();
109
+ const buffers = Array.from({ length: iovsLen }, (_, i) => {
110
+ const ptr = iovs + i * 8;
111
+ const buf = view.getUint32(ptr, true);
112
+ const bufLen = view.getUint32(ptr + 4, true);
113
+ return new Uint8Array(memory.buffer, buf, bufLen);
114
+ });
115
+ let written = 0;
116
+ let str = "";
117
+ for (const buffer of buffers) {
118
+ str += decoder.decode(buffer);
119
+ written += buffer.byteLength;
120
+ }
121
+ view.setUint32(nwritten, written, true);
122
+ const log = fd === 1 ? stdout : stderr;
123
+ log(str);
124
+ return 0;
125
+ };
126
+ const original_fd_filestat_get = wasiImport.fd_filestat_get;
127
+ wasiImport.fd_filestat_get = (fd, filestat) => {
128
+ if (fd !== 1 && fd !== 2) {
129
+ return original_fd_filestat_get(fd, filestat);
130
+ }
131
+ const view = getMemoryView();
132
+ const result = original_fd_filestat_get(fd, filestat);
133
+ if (result !== 0) {
134
+ return result;
135
+ }
136
+ const filetypePtr = filestat + 0;
137
+ view.setUint8(filetypePtr, 2); // FILETYPE_CHARACTER_DEVICE
138
+ return 0;
139
+ };
140
+ const original_fd_fdstat_get = wasiImport.fd_fdstat_get;
141
+ wasiImport.fd_fdstat_get = (fd, fdstat) => {
142
+ if (fd !== 1 && fd !== 2) {
143
+ return original_fd_fdstat_get(fd, fdstat);
144
+ }
145
+ const view = getMemoryView();
146
+ const fs_filetypePtr = fdstat + 0;
147
+ view.setUint8(fs_filetypePtr, 2); // FILETYPE_CHARACTER_DEVICE
148
+ const fs_rights_basePtr = fdstat + 8;
149
+ view.setBigUint64(fs_rights_basePtr, BigInt(1)); // RIGHTS_FD_WRITE
150
+ return 0;
151
+ };
152
+ },
153
+ setMemory(m) {
154
+ memory = m;
155
+ },
156
+ };
157
+ }
158
+
58
159
  let DATA_VIEW = new DataView(new ArrayBuffer());
59
160
 
60
161
  function data_view(mem) {
@@ -652,107 +753,6 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/browser.script.umd');\`
652
753
  };
653
754
  }
654
755
 
655
- /**
656
- * Create a console printer that can be used as an overlay of WASI imports.
657
- * See the example below for how to use it.
658
- *
659
- * ```javascript
660
- * const imports = {
661
- * "wasi_snapshot_preview1": wasi.wasiImport,
662
- * }
663
- * const printer = consolePrinter();
664
- * printer.addToImports(imports);
665
- *
666
- * const instance = await WebAssembly.instantiate(module, imports);
667
- * printer.setMemory(instance.exports.memory);
668
- * ```
669
- *
670
- * Note that the `stdout` and `stderr` functions are called with text, not
671
- * bytes. This means that bytes written to stdout/stderr will be decoded as
672
- * UTF-8 and then passed to the `stdout`/`stderr` functions every time a write
673
- * occurs without buffering.
674
- *
675
- * @param stdout A function that will be called when stdout is written to.
676
- * Defaults to `console.log`.
677
- * @param stderr A function that will be called when stderr is written to.
678
- * Defaults to `console.warn`.
679
- * @returns An object that can be used as an overlay of WASI imports.
680
- */
681
- function consolePrinter({ stdout, stderr, } = {
682
- stdout: console.log,
683
- stderr: console.warn,
684
- }) {
685
- let memory = undefined;
686
- let _view = undefined;
687
- function getMemoryView() {
688
- if (typeof memory === "undefined") {
689
- throw new Error("Memory is not set");
690
- }
691
- if (_view === undefined || _view.buffer.byteLength === 0) {
692
- _view = new DataView(memory.buffer);
693
- }
694
- return _view;
695
- }
696
- const decoder = new TextDecoder();
697
- return {
698
- addToImports(imports) {
699
- const wasiImport = imports.wasi_snapshot_preview1;
700
- const original_fd_write = wasiImport.fd_write;
701
- wasiImport.fd_write = (fd, iovs, iovsLen, nwritten) => {
702
- if (fd !== 1 && fd !== 2) {
703
- return original_fd_write(fd, iovs, iovsLen, nwritten);
704
- }
705
- const view = getMemoryView();
706
- const buffers = Array.from({ length: iovsLen }, (_, i) => {
707
- const ptr = iovs + i * 8;
708
- const buf = view.getUint32(ptr, true);
709
- const bufLen = view.getUint32(ptr + 4, true);
710
- return new Uint8Array(memory.buffer, buf, bufLen);
711
- });
712
- let written = 0;
713
- let str = "";
714
- for (const buffer of buffers) {
715
- str += decoder.decode(buffer);
716
- written += buffer.byteLength;
717
- }
718
- view.setUint32(nwritten, written, true);
719
- const log = fd === 1 ? stdout : stderr;
720
- log(str);
721
- return 0;
722
- };
723
- const original_fd_filestat_get = wasiImport.fd_filestat_get;
724
- wasiImport.fd_filestat_get = (fd, filestat) => {
725
- if (fd !== 1 && fd !== 2) {
726
- return original_fd_filestat_get(fd, filestat);
727
- }
728
- const view = getMemoryView();
729
- const result = original_fd_filestat_get(fd, filestat);
730
- if (result !== 0) {
731
- return result;
732
- }
733
- const filetypePtr = filestat + 0;
734
- view.setUint8(filetypePtr, 2); // FILETYPE_CHARACTER_DEVICE
735
- return 0;
736
- };
737
- const original_fd_fdstat_get = wasiImport.fd_fdstat_get;
738
- wasiImport.fd_fdstat_get = (fd, fdstat) => {
739
- if (fd !== 1 && fd !== 2) {
740
- return original_fd_fdstat_get(fd, fdstat);
741
- }
742
- const view = getMemoryView();
743
- const fs_filetypePtr = fdstat + 0;
744
- view.setUint8(fs_filetypePtr, 2); // FILETYPE_CHARACTER_DEVICE
745
- const fs_rights_basePtr = fdstat + 8;
746
- view.setBigUint64(fs_rights_basePtr, BigInt(1)); // RIGHTS_FD_WRITE
747
- return 0;
748
- };
749
- },
750
- setMemory(m) {
751
- memory = m;
752
- },
753
- };
754
- }
755
-
756
756
  /**
757
757
  * A Ruby VM instance
758
758
  *
@@ -825,11 +825,12 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/browser.script.umd');\`
825
825
  * @param args The command line arguments to pass to Ruby. Must be
826
826
  * an array of strings starting with the Ruby program name.
827
827
  */
828
- initialize(args = ["ruby.wasm", "--disable-gems", "-EUTF-8", "-e_=0"]) {
828
+ initialize(args = ["ruby.wasm", "-EUTF-8", "-e_=0"]) {
829
829
  const c_args = args.map((arg) => arg + "\0");
830
830
  this.guest.rubyInit();
831
831
  this.guest.rubySysinit(c_args);
832
832
  this.guest.rubyOptions(c_args);
833
+ this.eval(`require "/bundle/setup"`);
833
834
  }
834
835
  /**
835
836
  * Set a given instance to interact JavaScript and Ruby's
@@ -1064,13 +1065,8 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/browser.script.umd');\`
1064
1065
  */
1065
1066
  evalAsync(code) {
1066
1067
  const JS = this.eval("require 'js'; JS");
1067
- return new Promise((resolve, reject) => {
1068
- JS.call("__eval_async_rb", this.wrap(code), this.wrap({
1069
- resolve,
1070
- reject: (error) => {
1071
- reject(new RbError(this.exceptionFormatter.format(error, this, this.privateObject())));
1072
- },
1073
- }));
1068
+ return newRbPromise(this, this.privateObject(), (future) => {
1069
+ JS.call("__eval_async_rb", this.wrap(code), future);
1074
1070
  });
1075
1071
  }
1076
1072
  /**
@@ -1155,17 +1151,42 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/browser.script.umd');\`
1155
1151
  *
1156
1152
  * @param callee name of the Ruby method to call
1157
1153
  * @param args arguments to pass to the method. Must be an array of RbValue
1154
+ * @returns The result of the method call as a new RbValue.
1158
1155
  *
1159
1156
  * @example
1160
1157
  * const ary = vm.eval("[1, 2, 3]");
1161
1158
  * ary.call("push", 4);
1162
1159
  * console.log(ary.call("sample").toString());
1163
- *
1164
1160
  */
1165
1161
  call(callee, ...args) {
1166
1162
  const innerArgs = args.map((arg) => arg.inner);
1167
1163
  return new RbValue(callRbMethod(this.vm, this.privateObject, this.inner, callee, innerArgs), this.vm, this.privateObject);
1168
1164
  }
1165
+ /**
1166
+ * Call a given method that may call `JS::Object#await` with given arguments
1167
+ *
1168
+ * @param callee name of the Ruby method to call
1169
+ * @param args arguments to pass to the method. Must be an array of RbValue
1170
+ * @returns A Promise that resolves to the result of the method call as a new RbValue.
1171
+ *
1172
+ * @example
1173
+ * const client = vm.eval(`
1174
+ * require 'js'
1175
+ * class HttpClient
1176
+ * def get(url)
1177
+ * JS.global.fetch(url).await
1178
+ * end
1179
+ * end
1180
+ * HttpClient.new
1181
+ * `);
1182
+ * const response = await client.callAsync("get", vm.eval(`"https://example.com"`));
1183
+ */
1184
+ callAsync(callee, ...args) {
1185
+ const JS = this.vm.eval("require 'js'; JS");
1186
+ return newRbPromise(this.vm, this.privateObject, (future) => {
1187
+ JS.call("__call_async_method", this, this.vm.wrap(callee), future, ...args);
1188
+ });
1189
+ }
1169
1190
  /**
1170
1191
  * @see {@link https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive}
1171
1192
  * @param hint Preferred type of the result primitive value. `"number"`, `"string"`, or `"default"`.
@@ -1364,6 +1385,18 @@ Please replace your \`require('ruby-head-wasm-wasi/dist/browser.script.umd');\`
1364
1385
  return new RbValue(value, vm, privateObject);
1365
1386
  });
1366
1387
  };
1388
+ function newRbPromise(vm, privateObject, body) {
1389
+ return new Promise((resolve, reject) => {
1390
+ const future = vm.wrap({
1391
+ resolve,
1392
+ reject: (error) => {
1393
+ const rbError = new RbError(privateObject.exceptionFormatter.format(error, vm, privateObject));
1394
+ reject(rbError);
1395
+ },
1396
+ });
1397
+ body(future);
1398
+ });
1399
+ }
1367
1400
  /**
1368
1401
  * Error class thrown by Ruby execution
1369
1402
  */