├── .gitignore
├── .vscode
└── settings.json
├── LICENSE
├── Makefile
├── README.md
├── examples
├── hello.gr
├── net.gr
├── simpleProcess.gr
├── sleep.gr
├── spawn.gr
└── version.gr
├── lunatic.gr
└── src
├── api
├── distributed.gr
├── error.gr
├── message.gr
├── networking.gr
├── process.gr
├── registry.gr
├── timer.gr
├── version.gr
└── wasi.gr
├── net.gr
├── process.gr
└── version.gr
/.gitignore:
--------------------------------------------------------------------------------
1 | *.wasm
2 | *.wat
3 | .vscode/*.log
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "grain.cliFlags": "-I . "
3 | }
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Grain
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | examples:
2 | make hello
3 | make net
4 | make sleep
5 | make spawn
6 | make version
7 |
8 | hello:
9 | grain compile -I . --use-start-section --no-wasm-tail-call --release examples/hello.gr
10 | net:
11 | grain compile -I . --use-start-section --no-wasm-tail-call --release examples/net.gr
12 | sleep:
13 | grain compile -I . --use-start-section --no-wasm-tail-call --release examples/sleep.gr
14 | spawn:
15 | grain compile -I . --use-start-section --no-wasm-tail-call --release examples/spawn.gr
16 | version:
17 | grain compile -I . --use-start-section --no-wasm-tail-call --release examples/version.gr
18 | simpleProcess:
19 | grain compile -I . --use-start-section --no-wasm-tail-call --release examples/simpleProcess.gr
20 |
21 | .PHONY: examples hello net sleep spawn version
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # lunatic-gr
2 |
3 | Grain bindings to [Lunatic](https://lunatic.solutions).
4 |
5 | ## Buidling the examples
6 |
7 | With the latest version of Grain on your PATH, run `make examples`. The examples can be run via the `lunatic` command:
8 |
9 | ```sh
10 | lunatic examples/hello.gr.wasm
11 | ```
12 |
--------------------------------------------------------------------------------
/examples/hello.gr:
--------------------------------------------------------------------------------
1 | module Hello
2 |
3 | provide let _start = () => {
4 | print("Hello from Lunatic!")
5 | }
6 |
--------------------------------------------------------------------------------
/examples/net.gr:
--------------------------------------------------------------------------------
1 | module Net
2 |
3 | from "lunatic" include Lunatic
4 | use Lunatic.{ module Net }
5 |
6 | provide let _start = () => {
7 | match (Net.DNS.resolve("google.com:80")) {
8 | Ok(addresses) => print(addresses),
9 | Err(err) => print(err),
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/simpleProcess.gr:
--------------------------------------------------------------------------------
1 | module Main
2 |
3 | from "lunatic" include Lunatic
4 | use Lunatic.{ module Process }
5 |
6 | @externalName("_start")
7 | provide let main = () => {
8 | print("[main process] Hello from the main process!")
9 | print("[main process] Spawning a child...")
10 |
11 | Process.spawn(() => {
12 | print("[subprocess] 👋 from spawned process!")
13 | })
14 |
15 | void
16 | }
17 |
18 | provide let __lunatic_bootstrap = Process.__lunatic_bootstrap
19 |
--------------------------------------------------------------------------------
/examples/sleep.gr:
--------------------------------------------------------------------------------
1 | module Sleep
2 |
3 | from "lunatic" include Lunatic
4 | use Lunatic.{ module Process }
5 |
6 | provide let _start = () => {
7 | print("Counting...")
8 |
9 | for (let mut i = 0; i < 10; i += 1) {
10 | Process.sleep(200L)
11 | print(i)
12 | }
13 |
14 | print("Done.")
15 | }
16 |
--------------------------------------------------------------------------------
/examples/spawn.gr:
--------------------------------------------------------------------------------
1 | module Spawn
2 |
3 | from "bytes" include Bytes
4 | from "int64" include Int64
5 | from "result" include Result
6 |
7 | from "lunatic" include Lunatic
8 | use Lunatic.{ module Process }
9 |
10 | record SomeData {
11 | key: String,
12 | value: a,
13 | }
14 |
15 | let mailbox = Process.createMailbox()
16 |
17 | provide let _start = () => {
18 | let localdata = { key: "localdata", value: 54321 }
19 |
20 | print("[main process] Hello from the main process!")
21 | print("[main process] Spawning a child...")
22 |
23 | let child = Result.unwrap(Process.spawn(() => {
24 | print("[subprocess] 👋 from spawned process!")
25 | print("[subprocess] receiving some data...")
26 | print(Result.unwrap(Process.receive(mailbox)))
27 | print("[subprocess] data within the closure:")
28 | print(localdata)
29 | }))
30 |
31 | print("[main process] sending some data...")
32 |
33 | Process.send(child, { key: "datakey", value: 42 }, mailbox)
34 | Process.sleep(100L)
35 | }
36 |
37 | provide let __lunatic_bootstrap = Process.__lunatic_bootstrap
38 |
--------------------------------------------------------------------------------
/examples/version.gr:
--------------------------------------------------------------------------------
1 | module Version
2 |
3 | from "lunatic" include Lunatic
4 | use Lunatic.{ module Version }
5 |
6 | let semverString = (major, minor, patch) => {
7 | let (major, minor, patch) = (
8 | toString(major),
9 | toString(minor),
10 | toString(patch),
11 | )
12 | "v" ++ major ++ "." ++ minor ++ "." ++ patch
13 | }
14 |
15 | provide let _start = () => {
16 | print(
17 | "Hello from Lunatic " ++
18 | semverString(Version.major(), Version.minor(), Version.patch())
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/lunatic.gr:
--------------------------------------------------------------------------------
1 | module Lunatic
2 |
3 | from "./src/net.gr" include Net
4 | from "./src/process.gr" include Process
5 | from "./src/version.gr" include Version
6 |
7 | provide { module Net, module Process, module Version }
8 |
--------------------------------------------------------------------------------
/src/api/distributed.gr:
--------------------------------------------------------------------------------
1 | module Distributed
2 |
3 | provide foreign wasm get_nodes: (
4 | WasmI32,
5 | WasmI32,
6 | ) -> WasmI32 as getNodes from "lunatic::distributed"
7 | provide foreign wasm nodes_count: () -> WasmI32 as nodesCount from "lunatic::distributed"
8 | provide foreign wasm node_id: () -> WasmI64 as nodeId from "lunatic::distributed"
9 | provide foreign wasm module_id: () -> WasmI64 as moduleId from "lunatic::distributed"
10 | provide foreign wasm send: (
11 | WasmI64,
12 | WasmI64,
13 | ) -> Void as send from "lunatic::distributed"
14 | provide foreign wasm send_receive_skip_search: (
15 | WasmI64,
16 | WasmI64,
17 | WasmI64,
18 | ) -> WasmI32 as sendReceiveSkipSearch from "lunatic::distributed"
19 | provide foreign wasm spawn: (
20 | WasmI64,
21 | WasmI64,
22 | WasmI64,
23 | WasmI32,
24 | WasmI32,
25 | WasmI32,
26 | WasmI32,
27 | WasmI32,
28 | ) -> WasmI32 as spawn from "lunatic::distributed"
29 |
--------------------------------------------------------------------------------
/src/api/error.gr:
--------------------------------------------------------------------------------
1 | module Error
2 |
3 | provide foreign wasm string_size: WasmI64 -> WasmI32 as stringSize from "lunatic::error"
4 | provide foreign wasm to_string: (
5 | WasmI64,
6 | WasmI32,
7 | ) -> Void as toString from "lunatic::error"
8 | provide foreign wasm drop: WasmI64 -> Void as drop from "lunatic::error"
9 |
--------------------------------------------------------------------------------
/src/api/message.gr:
--------------------------------------------------------------------------------
1 | module Message
2 |
3 | provide foreign wasm create_data: (
4 | WasmI64,
5 | WasmI64,
6 | ) -> Void as createData from "lunatic::message"
7 | provide foreign wasm write_data: (
8 | WasmI32,
9 | WasmI32,
10 | ) -> WasmI32 as writeData from "lunatic::message"
11 | provide foreign wasm read_data: (
12 | WasmI32,
13 | WasmI32,
14 | ) -> WasmI32 as readData from "lunatic::message"
15 | provide foreign wasm seek_data: WasmI64 -> Void as seekData from "lunatic::message"
16 | provide foreign wasm get_tag: () -> WasmI64 as getTag from "lunatic::message"
17 | provide foreign wasm data_size: () -> WasmI64 as dataSize from "lunatic::message"
18 | provide foreign wasm push_module: WasmI64 -> WasmI64 as pushModule from "lunatic::message"
19 | provide foreign wasm take_module: WasmI64 -> WasmI64 as takeModule from "lunatic::message"
20 | provide foreign wasm push_tcp_stream: WasmI64 -> WasmI64 as pushTcpStream from "lunatic::message"
21 | provide foreign wasm take_tcp_stream: WasmI64 -> WasmI64 as takeTcpStream from "lunatic::message"
22 | provide foreign wasm push_tls_stream: WasmI64 -> WasmI64 as pushTlsStream from "lunatic::message"
23 | provide foreign wasm take_tls_stream: WasmI64 -> WasmI64 as takeTlsStream from "lunatic::message"
24 | provide foreign wasm send: WasmI64 -> WasmI32 as send from "lunatic::message"
25 | provide foreign wasm send_receive_skip_search: (
26 | WasmI64,
27 | WasmI64,
28 | ) -> WasmI32 as sendReceiveSkipSearch from "lunatic::message"
29 | provide foreign wasm receive: (
30 | WasmI32,
31 | WasmI32,
32 | WasmI64,
33 | ) -> WasmI32 as receive from "lunatic::message"
34 |
--------------------------------------------------------------------------------
/src/api/networking.gr:
--------------------------------------------------------------------------------
1 | module Networking
2 |
3 | provide foreign wasm resolve: (
4 | WasmI32,
5 | WasmI32,
6 | WasmI64,
7 | WasmI32,
8 | ) -> WasmI32 from "lunatic::networking"
9 | provide foreign wasm drop_dns_iterator: WasmI64 -> Void as dropDnsIterator from "lunatic::networking"
10 | provide foreign wasm resolve_next: (
11 | WasmI64,
12 | WasmI32,
13 | WasmI32,
14 | WasmI32,
15 | WasmI32,
16 | WasmI32,
17 | ) -> WasmI32 as resolveNext from "lunatic::networking"
18 | provide foreign wasm tcp_bind: (
19 | WasmI32,
20 | WasmI32,
21 | WasmI32,
22 | WasmI32,
23 | WasmI32,
24 | WasmI32,
25 | ) -> WasmI32 as tcpBind from "lunatic::networking"
26 | provide foreign wasm udp_bind: (
27 | WasmI32,
28 | WasmI32,
29 | WasmI32,
30 | WasmI32,
31 | WasmI32,
32 | WasmI32,
33 | ) -> WasmI32 as udpBind from "lunatic::networking"
34 | provide foreign wasm drop_tcp_listener: WasmI64 -> Void as dropTcpListener from "lunatic::networking"
35 | provide foreign wasm drop_tls_listener: WasmI64 -> Void as dropTlsListener from "lunatic::networking"
36 | provide foreign wasm drop_udp_socket: WasmI64 -> Void as dropUdpSocket from "lunatic::networking"
37 | provide foreign wasm tcp_local_addr: (
38 | WasmI64,
39 | WasmI32,
40 | ) -> WasmI32 as tcpLocalAddr from "lunatic::networking"
41 | provide foreign wasm tls_local_addr: (
42 | WasmI64,
43 | WasmI32,
44 | ) -> WasmI32 as tlsLocalAddr from "lunatic::networking"
45 | provide foreign wasm udp_local_addr: (
46 | WasmI64,
47 | WasmI32,
48 | ) -> WasmI32 as udpLocalAddr from "lunatic::networking"
49 | provide foreign wasm tcp_accept: (
50 | WasmI64,
51 | WasmI32,
52 | WasmI32,
53 | ) -> WasmI32 as tcpAccept from "lunatic::networking"
54 | provide foreign wasm tcp_connect: (
55 | WasmI32,
56 | WasmI32,
57 | WasmI32,
58 | WasmI32,
59 | WasmI32,
60 | WasmI64,
61 | WasmI32,
62 | ) -> WasmI32 as tcpConnect from "lunatic::networking"
63 | provide foreign wasm udp_connect: (
64 | WasmI64,
65 | WasmI32,
66 | WasmI32,
67 | WasmI32,
68 | WasmI32,
69 | WasmI32,
70 | WasmI64,
71 | WasmI32,
72 | ) -> WasmI32 as udpConnect from "lunatic::networking"
73 | provide foreign wasm drop_tcp_stream: WasmI64 -> Void as dropTcpStream from "lunatic::networking"
74 | provide foreign wasm clone_tcp_stream: WasmI64 -> WasmI64 as cloneTcpStream from "lunatic::networking"
75 | provide foreign wasm tcp_write_vectored: (
76 | WasmI64,
77 | WasmI32,
78 | WasmI32,
79 | WasmI32,
80 | ) -> WasmI32 as tcpWriteVectored from "lunatic::networking"
81 | provide foreign wasm tcp_read: (
82 | WasmI64,
83 | WasmI32,
84 | WasmI32,
85 | WasmI32,
86 | ) -> WasmI32 as tcpRead from "lunatic::networking"
87 | provide foreign wasm tcp_peek: (
88 | WasmI64,
89 | WasmI32,
90 | WasmI32,
91 | WasmI32,
92 | ) -> WasmI32 as tcpPeek from "lunatic::networking"
93 | provide foreign wasm udp_send: (
94 | WasmI64,
95 | WasmI32,
96 | WasmI32,
97 | WasmI32,
98 | ) -> WasmI32 as udpSend from "lunatic::networking"
99 | provide foreign wasm udp_send_to: (
100 | WasmI64,
101 | WasmI32,
102 | WasmI32,
103 | WasmI32,
104 | WasmI32,
105 | WasmI32,
106 | WasmI32,
107 | WasmI32,
108 | WasmI32,
109 | ) -> WasmI32 as udpSendTo from "lunatic::networking"
110 | provide foreign wasm udp_receive: (
111 | WasmI64,
112 | WasmI32,
113 | WasmI32,
114 | WasmI32,
115 | ) -> WasmI32 as udpReceive from "lunatic::networking"
116 | provide foreign wasm udp_receive_from: (
117 | WasmI64,
118 | WasmI32,
119 | WasmI32,
120 | WasmI32,
121 | WasmI32,
122 | ) -> WasmI32 as udpReceiveFrom from "lunatic::networking"
123 | provide foreign wasm set_udp_socket_ttl: (
124 | WasmI64,
125 | WasmI32,
126 | ) -> Void as setUdpSocketTtl from "lunatic::networking"
127 | provide foreign wasm set_udp_socket_broadcast: (
128 | WasmI64,
129 | WasmI32,
130 | ) -> Void as setUdpSocketBroadcast from "lunatic::networking"
131 | provide foreign wasm get_udp_socket_ttl: WasmI64 -> WasmI32 as getUdpSocketTtl from "lunatic::networking"
132 | provide foreign wasm get_udp_socket_broadcast: WasmI64 -> WasmI32 as getUdpSocketBroadcast from "lunatic::networking"
133 | provide foreign wasm clone_udp_socket: WasmI64 -> WasmI64 as cloneUdpSocket from "lunatic::networking"
134 | provide foreign wasm tcp_flush: (
135 | WasmI64,
136 | WasmI32,
137 | ) -> WasmI32 as tcpFlush from "lunatic::networking"
138 | provide foreign wasm tls_flush: (
139 | WasmI64,
140 | WasmI32,
141 | ) -> WasmI32 as tlsFlush from "lunatic::networking"
142 | provide foreign wasm set_read_timeout: (
143 | WasmI64,
144 | WasmI64,
145 | ) -> Void as setReadTimeout from "lunatic::networking"
146 | provide foreign wasm get_read_timeout: WasmI64 -> WasmI64 as getReadTimeout from "lunatic::networking"
147 | provide foreign wasm set_write_timeout: (
148 | WasmI64,
149 | WasmI64,
150 | ) -> Void as setWriteTimeout from "lunatic::networking"
151 | provide foreign wasm get_write_timeout: WasmI64 -> WasmI64 as getWriteTimeout from "lunatic::networking"
152 | provide foreign wasm set_peek_timeout: (
153 | WasmI64,
154 | WasmI64,
155 | ) -> Void as setPeekTimeout from "lunatic::networking"
156 | provide foreign wasm get_peek_timeout: WasmI64 -> WasmI64 as getPeekTimeout from "lunatic::networking"
157 | provide foreign wasm tls_bind: (
158 | WasmI32,
159 | WasmI32,
160 | WasmI32,
161 | WasmI32,
162 | WasmI32,
163 | WasmI32,
164 | WasmI32,
165 | WasmI32,
166 | WasmI32,
167 | WasmI32,
168 | ) -> WasmI32 as tlsBind from "lunatic::networking"
169 | provide foreign wasm tls_accept: (
170 | WasmI64,
171 | WasmI32,
172 | WasmI32,
173 | ) -> WasmI32 as tlsAccept from "lunatic::networking"
174 | provide foreign wasm tls_connect: (
175 | WasmI32,
176 | WasmI32,
177 | WasmI32,
178 | WasmI64,
179 | WasmI32,
180 | WasmI32,
181 | WasmI32,
182 | ) -> WasmI32 as tlsConnect from "lunatic::networking"
183 | provide foreign wasm drop_tls_stream: WasmI64 -> Void as dropTlsStream from "lunatic::networking"
184 | provide foreign wasm clone_tls_stream: WasmI64 -> WasmI64 as cloneTlsStream from "lunatic::networking"
185 | provide foreign wasm tls_write_vectored: (
186 | WasmI64,
187 | WasmI32,
188 | WasmI32,
189 | WasmI32,
190 | ) -> WasmI32 as tlsWriteVectored from "lunatic::networking"
191 | provide foreign wasm tls_read: (
192 | WasmI64,
193 | WasmI32,
194 | WasmI32,
195 | WasmI32,
196 | ) -> WasmI32 as tlsRead from "lunatic::networking"
197 | provide foreign wasm set_tls_read_timeout: (
198 | WasmI64,
199 | WasmI64,
200 | ) -> Void as setTlsReadTimeout from "lunatic::networking"
201 | provide foreign wasm get_tls_read_timeout: WasmI64 -> WasmI64 as getTlsReadTimeout from "lunatic::networking"
202 | provide foreign wasm set_tls_write_timeout: (
203 | WasmI64,
204 | WasmI64,
205 | ) -> Void as setTlsWriteTimeout from "lunatic::networking"
206 | provide foreign wasm get_tls_write_timeout: WasmI64 -> WasmI64 as getTlsWriteTimeout from "lunatic::networking"
207 |
--------------------------------------------------------------------------------
/src/api/process.gr:
--------------------------------------------------------------------------------
1 | module Process
2 |
3 | provide foreign wasm compile_module: (
4 | WasmI32,
5 | WasmI32,
6 | WasmI32,
7 | ) -> WasmI32 as compileModule from "lunatic::process"
8 | provide foreign wasm drop_module: WasmI64 -> Void as dropModule from "lunatic::process"
9 | provide foreign wasm create_config: () -> WasmI64 as createConfig from "lunatic::process"
10 | provide foreign wasm drop_config: WasmI64 -> Void as dropConfig from "lunatic::process"
11 | provide foreign wasm config_set_max_memory: (
12 | WasmI64,
13 | WasmI64,
14 | ) -> Void as configSetMaxMemory from "lunatic::process"
15 | provide foreign wasm config_get_max_memory: WasmI64 -> WasmI64 as configGetMaxMemory from "lunatic::process"
16 | provide foreign wasm config_set_max_fuel: (
17 | WasmI64,
18 | WasmI64,
19 | ) -> Void as configSetMaxFuel from "lunatic::process"
20 | provide foreign wasm config_get_max_fuel: WasmI64 -> WasmI64 as configGetMaxFuel from "lunatic::process"
21 | provide foreign wasm config_can_compile_modules: WasmI64 -> WasmI32 as configCanCompileModules from "lunatic::process"
22 | provide foreign wasm config_set_can_compile_modules: (
23 | WasmI64,
24 | WasmI32,
25 | ) -> Void as configSetCanCompileModules from "lunatic::process"
26 | provide foreign wasm config_can_create_configs: WasmI64 -> WasmI32 as configCanCreateConfigs from "lunatic::process"
27 | provide foreign wasm config_set_can_create_configs: (
28 | WasmI64,
29 | WasmI32,
30 | ) -> Void as configSetCanCreateConfigs from "lunatic::process"
31 | provide foreign wasm config_can_spawn_processes: WasmI64 -> WasmI32 as configCanSpawnProcesses from "lunatic::process"
32 | provide foreign wasm config_set_can_spawn_processes: (
33 | WasmI64,
34 | WasmI32,
35 | ) -> Void as configSetCanSpawnProcesses from "lunatic::process"
36 | provide foreign wasm spawn: (
37 | WasmI64,
38 | WasmI64,
39 | WasmI64,
40 | WasmI32,
41 | WasmI32,
42 | WasmI32,
43 | WasmI32,
44 | WasmI32,
45 | ) -> WasmI32 as spawn from "lunatic::process"
46 | provide foreign wasm sleep_ms: WasmI64 -> Void as sleepMs from "lunatic::process"
47 | provide foreign wasm die_when_link_dies: WasmI32 -> Void as dieWhenLinkDies from "lunatic::process"
48 | provide foreign wasm process_id: () -> WasmI64 as processId from "lunatic::process"
49 | provide foreign wasm link: (
50 | WasmI64,
51 | WasmI64,
52 | ) -> Void as link from "lunatic::process"
53 | provide foreign wasm unlink: WasmI64 -> Void as unlink from "lunatic::process"
54 | provide foreign wasm kill: WasmI64 -> Void as kill from "lunatic::process"
55 |
--------------------------------------------------------------------------------
/src/api/registry.gr:
--------------------------------------------------------------------------------
1 | module Registry
2 |
3 | provide foreign wasm put: (
4 | WasmI32,
5 | WasmI32,
6 | WasmI64,
7 | WasmI64,
8 | ) -> Void as put from "lunatic::registry"
9 | provide foreign wasm get: (
10 | WasmI32,
11 | WasmI32,
12 | WasmI32,
13 | WasmI32,
14 | ) -> WasmI32 as get from "lunatic::registry"
15 | provide foreign wasm remove: (
16 | WasmI32,
17 | WasmI32,
18 | ) -> Void as remove from "lunatic::registry"
19 |
--------------------------------------------------------------------------------
/src/api/timer.gr:
--------------------------------------------------------------------------------
1 | module Timer
2 |
3 | provide foreign wasm send_after: (
4 | WasmI64,
5 | WasmI64,
6 | ) -> WasmI64 as sendAfter from "lunatic::timer"
7 | provide foreign wasm cancel_timer: WasmI64 -> WasmI32 as cancelTimer from "lunatic::timer"
8 |
--------------------------------------------------------------------------------
/src/api/version.gr:
--------------------------------------------------------------------------------
1 | module Version
2 |
3 | provide foreign wasm major: () -> WasmI32 from "lunatic::version"
4 | provide foreign wasm minor: () -> WasmI32 from "lunatic::version"
5 | provide foreign wasm patch: () -> WasmI32 from "lunatic::version"
6 |
--------------------------------------------------------------------------------
/src/api/wasi.gr:
--------------------------------------------------------------------------------
1 | module Wasi
2 |
3 | provide foreign wasm config_add_environment_variable: (
4 | WasmI64,
5 | WasmI32,
6 | WasmI32,
7 | WasmI32,
8 | WasmI32,
9 | ) -> Void as configAddEnvironmentVariable from "lunatic::wasi"
10 | provide foreign wasm config_add_command_line_argument: (
11 | WasmI64,
12 | WasmI32,
13 | WasmI32,
14 | ) -> Void as configAddCommandLineArgument from "lunatic::wasi"
15 | provide foreign wasm config_preopen_dir: (
16 | WasmI64,
17 | WasmI32,
18 | WasmI32,
19 | ) -> Void as configPreopenDir from "lunatic::wasi"
20 |
--------------------------------------------------------------------------------
/src/net.gr:
--------------------------------------------------------------------------------
1 | module Net
2 |
3 | from "pervasives" include Pervasives
4 | from "runtime/unsafe/conv" include Conv
5 | from "runtime/unsafe/wasmi32" include WasmI32
6 | from "runtime/unsafe/wasmi64" include WasmI64
7 | from "runtime/unsafe/memory" include Memory
8 | from "runtime/dataStructures" include DataStructures
9 | from "runtime/numberUtils" include NumberUtils
10 | from "bigint" include BigInt
11 | from "string" include String
12 |
13 | from "./api/message.gr" include Message
14 | from "./api/networking.gr" include Networking
15 |
16 | provide enum IPType {
17 | IPv4(Uint32),
18 | IPv6(BigInt),
19 | }
20 |
21 | provide record IPAddress {
22 | address: IPType,
23 | port: Uint16,
24 | flowInfo: Uint32,
25 | scopeId: Uint32,
26 | }
27 |
28 | primitive magic = "@magic"
29 |
30 | provide module DNS {
31 | use Networking.{ resolve, resolveNext, dropDnsIterator }
32 |
33 | @unsafe
34 | let ipPointer = Memory.malloc(30n)
35 | @unsafe
36 | let _ADDRESS_OFFSET = 0n
37 | @unsafe
38 | let _TYPE_OFFSET = 16n
39 | @unsafe
40 | let _PORT_OFFSET = 20n
41 | @unsafe
42 | let _FLOW_INFO_OFFSET = 22n
43 | @unsafe
44 | let _SCOPE_ID_OFFSET = 26n
45 |
46 | @unsafe
47 | let resolveDNSIterator = id => {
48 | let add = (+)
49 | use WasmI32.{ (+) }
50 |
51 | let mut addresses = []
52 |
53 | while (
54 | WasmI32.eqz(
55 | resolveNext(
56 | id,
57 | ipPointer + _TYPE_OFFSET,
58 | ipPointer + _ADDRESS_OFFSET,
59 | ipPointer + _PORT_OFFSET,
60 | ipPointer + _FLOW_INFO_OFFSET,
61 | ipPointer + _SCOPE_ID_OFFSET
62 | )
63 | )
64 | ) {
65 | let address = match (WasmI32.load(ipPointer, _TYPE_OFFSET)) {
66 | 4n => {
67 | use WasmI32.{ (<<), (|) }
68 |
69 | // These bytes are big endian, but WebAssembly is little endian
70 |
71 | let mut ip = 0n
72 | ip = ip | WasmI32.load8U(ipPointer, _ADDRESS_OFFSET) << 24n
73 | ip = ip | WasmI32.load8U(ipPointer, _ADDRESS_OFFSET + 1n) << 16n
74 | ip = ip | WasmI32.load8U(ipPointer, _ADDRESS_OFFSET + 2n) << 8n
75 | ip = ip | WasmI32.load8U(ipPointer, _ADDRESS_OFFSET + 3n)
76 |
77 | IPv4(WasmI32.toGrain(DataStructures.newInt32(ip)))
78 | },
79 | 6n => {
80 | use WasmI64.{ (<<), (|) }
81 |
82 | // These bytes are big endian, but WebAssembly is little endian
83 |
84 | let mut high = 0N
85 | high = high | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET) << 56N
86 | high = high | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 1n) << 48N
87 | high = high | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 2n) << 40N
88 | high = high | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 3n) << 32N
89 | high = high | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 4n) << 24N
90 | high = high | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 5n) << 16N
91 | high = high | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 6n) << 8N
92 | high = high | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 7n)
93 |
94 | let mut low = 0N
95 | low = low | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 8n) << 56N
96 | low = low | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 9n) << 48N
97 | low = low | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 10n) << 40N
98 | low = low | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 11n) << 32N
99 | low = low | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 12n) << 24N
100 | low = low | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 13n) << 16N
101 | low = low | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 14n) << 8N
102 | low = low | WasmI64.load8U(ipPointer, _ADDRESS_OFFSET + 15n)
103 |
104 | let high = WasmI32.toGrain(DataStructures.newInt64(high)): Number
105 | let low = WasmI32.toGrain(DataStructures.newInt64(low)): Number
106 |
107 | IPv6(BigInt.fromNumber(add(high * 0x100000000, low)))
108 | },
109 | _ => fail "unknown IP type",
110 | }
111 |
112 | let port = DataStructures.tagUint16(
113 | WasmI32.load16U(ipPointer, _PORT_OFFSET)
114 | )
115 |
116 | let flowInfo = WasmI32.toGrain(
117 | DataStructures.newUint32(WasmI32.load(ipPointer, _FLOW_INFO_OFFSET))
118 | ): Uint32
119 |
120 | let scopeId = WasmI32.toGrain(
121 | DataStructures.newUint32(WasmI32.load(ipPointer, _SCOPE_ID_OFFSET))
122 | ): Uint32
123 |
124 | let address = { address, port, flowInfo, scopeId }
125 |
126 | addresses = [address, ...addresses]
127 | }
128 |
129 | dropDnsIterator(id)
130 |
131 | addresses
132 | }
133 |
134 | @unsafe
135 | let _ID_PTR = Memory.malloc(8n)
136 |
137 | @unsafe
138 | provide let resolveTimeout = (host: String, timeout: Int64) => {
139 | use WasmI32.{ (+) }
140 | let hostPtr = WasmI32.fromGrain(host) + 8n
141 | let hostSize = WasmI32.load(WasmI32.fromGrain(host), 4n)
142 |
143 | let timeout = WasmI64.load(WasmI32.fromGrain(timeout), 8n)
144 |
145 | let result = resolve(hostPtr, hostSize, timeout, _ID_PTR)
146 |
147 | if (WasmI32.eqz(result)) {
148 | let id = WasmI64.load(_ID_PTR, 0n)
149 | Ok(resolveDNSIterator(id))
150 | } else {
151 | match (result) {
152 | 9027n => Err("timed out"),
153 | _ => Err("unknown error"),
154 | }
155 | }
156 | }
157 |
158 | provide let resolve = (host: String) => {
159 | resolveTimeout(host, -1L)
160 | }
161 | }
162 |
163 | provide module Tcp {
164 | abstract type TcpListener = Int64
165 | abstract type TcpStream = Int64
166 |
167 | provide enum TcpError {
168 | FailedToResolveBindAddress,
169 | FailedToBind,
170 | FailedToAcceptConnection,
171 | TcpTimeout,
172 | TcpSocketClosed,
173 | TcpFlushFailed,
174 | }
175 |
176 | @unsafe
177 | let _ID_PTR = Memory.malloc(8n)
178 | @unsafe
179 | let _DNS_ITERATOR_PTR = Memory.malloc(8n)
180 |
181 | @unsafe
182 | provide let bind = address => {
183 | use WasmI32.{ (+) }
184 |
185 | let addresses = DNS.resolve(address)
186 | let ip = match (addresses) {
187 | Ok([ip, ..._]) => ip,
188 | _ => return Err(FailedToResolveBindAddress),
189 | }
190 |
191 | let mut ipType = 0n
192 | let mut ipPtr = 0n
193 | match (ip.address) {
194 | IPv4(addr) => {
195 | ipType = 4n
196 | ipPtr = WasmI32.load(WasmI32.fromGrain(addr), 4n)
197 | },
198 | IPv6(addr) => {
199 | ipType = 6n
200 | ipPtr = WasmI32.fromGrain(addr) + 16n
201 | },
202 | }
203 |
204 | let port = DataStructures.untagUint16(ip.port)
205 | let flowInfo = WasmI32.load(WasmI32.fromGrain(ip.flowInfo), 4n)
206 | let scopeId = WasmI32.load(WasmI32.fromGrain(ip.scopeId), 4n)
207 |
208 | let err = Networking.tcpBind(
209 | ipType,
210 | ipPtr,
211 | port,
212 | flowInfo,
213 | scopeId,
214 | _ID_PTR
215 | )
216 | ignore(ip)
217 |
218 | return if (WasmI32.eqz(err)) {
219 | Ok(
220 | WasmI32.toGrain(DataStructures.newUint64(WasmI64.load(_ID_PTR, 0n))):
221 | TcpListener,
222 | )
223 | } else {
224 | Err(FailedToBind)
225 | }
226 | }
227 |
228 | @unsafe
229 | provide let accept = (listener: TcpListener) => {
230 | let listenerId = WasmI64.load(WasmI32.fromGrain(listener), 8n)
231 |
232 | let err = Networking.tcpAccept(listenerId, _ID_PTR, _DNS_ITERATOR_PTR)
233 | return if (WasmI32.eqz(err)) {
234 | Ok(
235 | WasmI32.toGrain(DataStructures.newUint64(WasmI64.load(_ID_PTR, 0n))):
236 | TcpStream,
237 | )
238 | } else {
239 | Err(FailedToAcceptConnection)
240 | }
241 | }
242 |
243 | @unsafe
244 | let _BYTES_AFFECTED_PTR = Memory.malloc(8n)
245 | @unsafe
246 | let _SINGLE_IOV = Memory.malloc(8n)
247 |
248 | @unsafe
249 | provide let read = (stream: TcpStream, buffer: Bytes) => {
250 | use WasmI32.{ (+) }
251 |
252 | let streamId = WasmI64.load(WasmI32.fromGrain(stream), 8n)
253 | let mut bufPtr = WasmI32.fromGrain(buffer)
254 | let bufSize = WasmI32.load(bufPtr, 4n)
255 | bufPtr += 8n
256 |
257 | let err = Networking.tcpRead(streamId, bufPtr, bufSize, _BYTES_AFFECTED_PTR)
258 | match (err) {
259 | 0n => {
260 | let bytesRead = WasmI32.wrapI64(WasmI64.load(_BYTES_AFFECTED_PTR, 0n))
261 | Ok(DataStructures.tagSimpleNumber(bytesRead))
262 | },
263 | 1n => Err(TcpSocketClosed),
264 | _ => Err(TcpTimeout),
265 | }
266 | }
267 |
268 | @unsafe
269 | provide let write = (stream: TcpStream, buffer: Bytes) => {
270 | use WasmI32.{ (+) }
271 |
272 | let streamId = WasmI64.load(WasmI32.fromGrain(stream), 8n)
273 | let mut bufPtr = WasmI32.fromGrain(buffer)
274 | let bufSize = WasmI32.load(bufPtr, 4n)
275 | bufPtr += 8n
276 |
277 | WasmI32.store(_SINGLE_IOV, bufPtr, 0n)
278 | WasmI32.store(_SINGLE_IOV, bufSize, 4n)
279 |
280 | let err = Networking.tcpWriteVectored(
281 | streamId,
282 | _SINGLE_IOV,
283 | 1n,
284 | _BYTES_AFFECTED_PTR
285 | )
286 | match (err) {
287 | 0n => {
288 | let bytesWritten = WasmI32.wrapI64(
289 | WasmI64.load(_BYTES_AFFECTED_PTR, 0n)
290 | )
291 | Ok(DataStructures.tagSimpleNumber(bytesWritten))
292 | },
293 | 1n => Err(TcpSocketClosed),
294 | _ => Err(TcpTimeout),
295 | }
296 | }
297 |
298 | provide let writeString = (stream, string: String) => {
299 | write(stream, magic(string))
300 | }
301 |
302 | @unsafe
303 | provide let clone = (stream: TcpStream) => {
304 | let streamId = WasmI64.load(WasmI32.fromGrain(stream), 8n)
305 | let newId = Networking.cloneTcpStream(streamId)
306 | WasmI32.toGrain(DataStructures.newUint64(newId)): TcpStream
307 | }
308 |
309 | @unsafe
310 | provide let flush = (stream: TcpStream) => {
311 | let streamId = WasmI64.load(WasmI32.fromGrain(stream), 8n)
312 | let err = Networking.tcpFlush(streamId, _ID_PTR)
313 | match (err) {
314 | 0n => Ok(void),
315 | _ => Err(TcpFlushFailed),
316 | }
317 | }
318 | }
319 |
--------------------------------------------------------------------------------
/src/process.gr:
--------------------------------------------------------------------------------
1 | module Process
2 |
3 | from "runtime/unsafe/wasmi32" include WasmI32
4 | from "runtime/unsafe/wasmi64" include WasmI64
5 | from "runtime/unsafe/conv" include Conv
6 | from "runtime/unsafe/memory" include Memory
7 | from "runtime/dataStructures" include DataStructures
8 | from "runtime/unsafe/tags" include Tags
9 |
10 | from "array" include Array
11 | from "bytes" include Bytes
12 | from "int64" include Int64
13 | from "marshal" include Marshal
14 | from "result" include Result
15 |
16 | from "./api/distributed.gr" include Distributed
17 | use Distributed.{ nodeId }
18 | from "./api/process.gr" include Process
19 | use Process.{
20 | compileModule,
21 | dropModule,
22 | createConfig,
23 | dropConfig,
24 | configSetMaxMemory,
25 | configGetMaxMemory,
26 | configSetMaxFuel,
27 | configGetMaxFuel,
28 | configCanCompileModules,
29 | configSetCanCompileModules,
30 | configCanCreateConfigs,
31 | configSetCanCreateConfigs,
32 | configCanSpawnProcesses,
33 | configSetCanSpawnProcesses,
34 | spawn,
35 | sleepMs,
36 | dieWhenLinkDies,
37 | processId,
38 | link,
39 | unlink,
40 | kill,
41 | }
42 | from "./api/message.gr" include Message
43 | use Message.{
44 | createData,
45 | writeData,
46 | readData,
47 | seekData,
48 | getTag,
49 | dataSize,
50 | send,
51 | receive,
52 | }
53 |
54 | from "./api/registry.gr" include Registry
55 | from "./net.gr" include Net
56 |
57 | provide record Process {
58 | nodeId: Int64,
59 | pid: Int64,
60 | }
61 |
62 | provide enum Resource {
63 | TcpStream(Net.Tcp.TcpStream),
64 | }
65 |
66 | provide exception LunaticError
67 | provide exception ReceiveTimeout
68 | provide exception MarshalError(String)
69 |
70 | abstract type Mailbox = Int64
71 |
72 | /* Tags 0 - 127 are reserved for special purposes. */
73 |
74 | @unsafe
75 | let mut currentTag = 128N
76 |
77 | let bootstrapMailbox: Mailbox<() => Void> = 1L
78 |
79 | @unsafe
80 | provide let createMailbox = () => {
81 | use WasmI64.{ (+) }
82 | let tag = currentTag
83 | currentTag += 1N
84 | WasmI32.toGrain(DataStructures.newInt64(tag)): Mailbox
85 | }
86 |
87 | @unsafe
88 | let createData = (tag: Int64, capacity: Int64) => {
89 | createData(
90 | WasmI64.load(WasmI32.fromGrain(tag), 8n),
91 | WasmI64.load(WasmI32.fromGrain(capacity), 8n)
92 | )
93 | ignore(tag)
94 | ignore(capacity)
95 | }
96 |
97 | @unsafe
98 | let writeData = (bytes: Bytes) => {
99 | use WasmI32.{ (+) }
100 | let bytesPtr = WasmI32.fromGrain(bytes)
101 | let bytesWritten = writeData(bytesPtr + 8n, WasmI32.load(bytesPtr, 4n))
102 | WasmI32.toGrain(DataStructures.newInt32(bytesWritten)): Int32
103 | }
104 |
105 | @unsafe
106 | let readData = (bytes: Bytes) => {
107 | use WasmI32.{ (+) }
108 | let bytesPtr = WasmI32.fromGrain(bytes)
109 | let bytesRead = readData(bytesPtr + 8n, WasmI32.load(bytesPtr, 4n))
110 | WasmI32.toGrain(DataStructures.newInt32(bytesRead)): Int32
111 | }
112 |
113 | @unsafe
114 | let seekData = (position: Int64) => {
115 | seekData(WasmI64.load(WasmI32.fromGrain(position), 8n))
116 | }
117 |
118 | @unsafe
119 | let getTag = () => {
120 | WasmI32.toGrain(DataStructures.newInt64(getTag())): Int64
121 | }
122 |
123 | @unsafe
124 | let dataSize = () => {
125 | WasmI32.toGrain(DataStructures.newInt64(dataSize())): Int64
126 | }
127 |
128 | @unsafe
129 | let sendRaw = (process: Process) => {
130 | let err = send(WasmI64.load(WasmI32.fromGrain(process.pid), 8n))
131 | ignore(process)
132 | if (WasmI32.eqz(err)) {
133 | Ok(void)
134 | } else {
135 | Err(LunaticError)
136 | }
137 | }
138 |
139 | @unsafe
140 | let receive = (tags: Option>, timeout: Uint64) => {
141 | use WasmI32.{ (*), (+) }
142 | let tags = match (tags) {
143 | Some(tags) => Array.fromList(tags),
144 | None => [>],
145 | }
146 |
147 | let count = DataStructures.untagSimpleNumber(Array.length(tags))
148 |
149 | let tagsBuf = Memory.malloc(count * 8n)
150 |
151 | for (let mut i = 0n; WasmI32.ltU(i, count); i += 1n) {
152 | WasmI64.store(
153 | tagsBuf,
154 | WasmI64.load(
155 | WasmI32.fromGrain(tags[DataStructures.tagSimpleNumber(i)]),
156 | 8n
157 | ),
158 | i * 8n
159 | )
160 | }
161 |
162 | let result = receive(
163 | tagsBuf,
164 | count,
165 | WasmI64.load(WasmI32.fromGrain(timeout), 8n)
166 | )
167 |
168 | match (result) {
169 | 0n => {
170 | Ok(void)
171 | },
172 | 9027n => Err(ReceiveTimeout),
173 | 1n => fail "can't recieve link failed message",
174 | _ => fail "unknown receive error",
175 | }
176 | }
177 |
178 | @unsafe
179 | let idPtr = Memory.malloc(8n)
180 |
181 | /**
182 | * Cause the current process to sleep for the given number of milliseconds.
183 | *
184 | * @param ms: The number of milliseconds to sleep
185 | */
186 | @unsafe
187 | provide let sleep = (ms: Int64) => {
188 | let ms = WasmI64.load(WasmI32.fromGrain(ms), 8n)
189 | sleepMs(ms)
190 | }
191 |
192 | @unsafe
193 | provide let this = () => {
194 | let nodeId = Conv.toInt64(nodeId())
195 | let pid = Conv.toInt64(processId())
196 | { nodeId, pid }: Process
197 | }
198 |
199 | @unsafe
200 | provide let send: (Process, a, Mailbox) => Result = (
201 | process,
202 | data,
203 | mailbox,
204 | ) => {
205 | let payload = Marshal.marshal(data)
206 | createData(mailbox, Int64.fromNumber(Bytes.length(payload)))
207 | writeData(payload)
208 | sendRaw(process)
209 | }
210 |
211 | provide let receive: (?timeout: Uint64, Mailbox) => Result = (
212 | timeout=0xffffffffffffffffuL,
213 | mailbox,
214 | ) => {
215 | Result.flatMap((_) => {
216 | let size = dataSize()
217 | let buf = Bytes.make(Int64.toNumber(size))
218 | readData(buf)
219 | Result.mapErr(msg => MarshalError(msg), Marshal.unmarshal(buf))
220 | }, receive(Some([mailbox]), timeout))
221 | }
222 |
223 | let tcpStreamMailbox = createMailbox(): Mailbox
224 |
225 | @unsafe
226 | provide let transferTcpStream = (process, stream) => {
227 | createData(tcpStreamMailbox, 8L)
228 | let streamId = WasmI64.load(WasmI32.fromGrain(stream), 8n)
229 | let index = WasmI32.toGrain(
230 | DataStructures.newUint64(Message.pushTcpStream(streamId))
231 | ): Uint64
232 | let payload = Marshal.marshal(index)
233 | writeData(payload)
234 | sendRaw(process)
235 | }
236 |
237 | @unsafe
238 | provide let takeTcpStream = () => {
239 | Result.flatMap(index => {
240 | let index = WasmI64.load(WasmI32.fromGrain(index), 8n)
241 | let stream = WasmI32.toGrain(
242 | DataStructures.newUint64(Message.takeTcpStream(index))
243 | ): Net.Tcp.TcpStream
244 | Ok(stream)
245 | }, receive(tcpStreamMailbox))
246 | }
247 |
248 | @unsafe
249 | provide let spawn = (func: () => Void) => {
250 | use WasmI32.{ (+) }
251 | let funcName = WasmI32.fromGrain("__lunatic_bootstrap")
252 |
253 | let result = spawn(
254 | 0N,
255 | -1N,
256 | -1N,
257 | funcName + 8n,
258 | WasmI32.load(funcName, 4n),
259 | 0n,
260 | 0n,
261 | idPtr
262 | )
263 |
264 | let spawnId = WasmI32.toGrain(
265 | DataStructures.newInt64(WasmI64.load(idPtr, 0n))
266 | )
267 |
268 | if (WasmI32.eqz(result)) {
269 | let process = { pid: spawnId, nodeId: Conv.toInt64(nodeId()) }
270 | match (send(process, func, bootstrapMailbox)) {
271 | Ok(_) => Ok(process),
272 | Err(_) => Err(spawnId: Int64),
273 | }
274 | } else {
275 | Err(spawnId: Int64)
276 | }
277 | }
278 |
279 | @unsafe
280 | provide let register = (name: String, process: Process) => {
281 | use WasmI32.{ (+) }
282 | let namePtr = WasmI32.fromGrain(name)
283 | let nameLen = WasmI32.load(namePtr, 4n)
284 | let namePtr = namePtr + 8n
285 |
286 | let nodeIdValue = WasmI64.load(WasmI32.fromGrain(process.nodeId), 8n)
287 | let processId = WasmI64.load(WasmI32.fromGrain(process.pid), 8n)
288 |
289 | Registry.put(namePtr, nameLen, nodeIdValue, processId)
290 |
291 | ignore(name)
292 | ignore(process)
293 | }
294 |
295 | @unsafe
296 | provide let lookup = (name: String) => {
297 | use WasmI32.{ (+) }
298 | let namePtr = WasmI32.fromGrain(name)
299 | let nameLen = WasmI32.load(namePtr, 4n)
300 | let namePtr = namePtr + 8n
301 |
302 | let nodeId = DataStructures.allocateInt64()
303 | let pid = DataStructures.allocateInt64()
304 |
305 | let err = Registry.get(namePtr, nameLen, nodeId + 8n, pid + 8n)
306 | if (WasmI32.eqz(err)) {
307 | Some({ nodeId: WasmI32.toGrain(nodeId), pid: WasmI32.toGrain(pid) })
308 | } else {
309 | Memory.free(nodeId)
310 | Memory.free(pid)
311 | None
312 | }
313 | }
314 |
315 | @unsafe
316 | provide let deregister = (name: String) => {
317 | use WasmI32.{ (+) }
318 | let namePtr = WasmI32.fromGrain(name)
319 | let nameLen = WasmI32.load(namePtr, 4n)
320 | let namePtr = namePtr + 8n
321 |
322 | Registry.remove(namePtr, nameLen)
323 |
324 | ignore(name)
325 | }
326 |
327 | @unsafe
328 | provide let dieWhenLinkDies = shouldDie => {
329 | if (shouldDie) {
330 | dieWhenLinkDies(1n)
331 | } else {
332 | dieWhenLinkDies(0n)
333 | }
334 | }
335 |
336 | @unsafe
337 | provide let __lunatic_bootstrap = () => {
338 | // The mailbox type is not propagated within this module for some reason so
339 | // we use an explicit type annotation.
340 | // https://github.com/grain-lang/grain/issues/1356
341 | let result: Result<() => Void, Exception> = receive(bootstrapMailbox)
342 | match (result) {
343 | Ok(func) => func(),
344 | Err(ReceiveTimeout) => fail "didn't receive bootstrap message",
345 | Err(MarshalError(_)) => fail "corrupted bootsrap message",
346 | Err(_) => fail "unknown error",
347 | }
348 | }
349 |
--------------------------------------------------------------------------------
/src/version.gr:
--------------------------------------------------------------------------------
1 | module Version
2 |
3 | from "runtime/unsafe/wasmi32" include WasmI32
4 | from "runtime/dataStructures" include DataStructures
5 | use DataStructures.{ newInt32 }
6 |
7 | from "./api/version.gr" include Version
8 | use Version.{ major, minor, patch }
9 |
10 | @unsafe
11 | provide let major = () => {
12 | WasmI32.toGrain(newInt32(major())): Int32
13 | }
14 |
15 | @unsafe
16 | provide let minor = () => {
17 | WasmI32.toGrain(newInt32(minor())): Int32
18 | }
19 |
20 | @unsafe
21 | provide let patch = () => {
22 | WasmI32.toGrain(newInt32(patch())): Int32
23 | }
24 |
--------------------------------------------------------------------------------