Skip to content

Commit 81ce0de

Browse files
moonbit: lay groundwork for async runtime support (#1581)
* refactor(moonbit): lay groundwork for async runtime * style(moonbit): fix fmt and clippy * test(moonbit): restore async expected failures * fix(moonbit): keep async import codegen working
1 parent a55ad81 commit 81ce0de

File tree

13 files changed

+2028
-700
lines changed

13 files changed

+2028
-700
lines changed
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
// #region subtask
2+
3+
///|
4+
priv struct SubTask {
5+
handle : Int
6+
state : SubTaskState
7+
}
8+
9+
///|
10+
priv enum SubTaskState {
11+
Starting = 0
12+
Started = 1
13+
Returned = 2
14+
Cancelled_before_started = 3
15+
Cancelled_before_returned = 4
16+
}
17+
18+
///|
19+
fn SubTaskState::from(int : Int) -> SubTaskState {
20+
match int {
21+
0 => Starting
22+
1 => Started
23+
2 => Returned
24+
3 => Cancelled_before_started
25+
4 => Cancelled_before_returned
26+
_ => panic()
27+
}
28+
}
29+
30+
///|
31+
fn SubTask::from(code : Int) -> SubTask {
32+
{ handle: code >> 4, state: SubTaskState::from(code & 0xf) }
33+
}
34+
35+
///|
36+
/// None : the subtask is blocked
37+
fn SubTask::cancel(self : SubTask) -> SubTaskState? {
38+
let result = subtask_cancel(self.handle)
39+
if result == -1 {
40+
None
41+
} else {
42+
Some(SubTaskState::from(subtask_cancel(self.handle)))
43+
}
44+
}
45+
46+
// #endregion
47+
48+
// #region events
49+
50+
///|
51+
priv enum EventCode {
52+
None = 0
53+
SubTask = 1
54+
StreamRead = 2
55+
StreamWrite = 3
56+
FutureRead = 4
57+
FutureWrite = 5
58+
TaskCancelled = 6
59+
}
60+
61+
///|
62+
fn EventCode::from(int : Int) -> EventCode {
63+
match int {
64+
0 => EventCode::None
65+
1 => EventCode::SubTask
66+
2 => EventCode::StreamRead
67+
3 => EventCode::StreamWrite
68+
4 => EventCode::FutureRead
69+
5 => EventCode::FutureWrite
70+
6 => EventCode::TaskCancelled
71+
_ => panic()
72+
}
73+
}
74+
75+
///|
76+
priv enum Events {
77+
None
78+
Subtask(Int, SubTaskState)
79+
StreamRead(Int, StreamResult)
80+
StreamWrite(Int, StreamResult)
81+
FutureRead(Int, FutureReadResult)
82+
FutureWrite(Int, FutureWriteResult)
83+
TaskCancelled
84+
}
85+
86+
///|
87+
fn Events::new(code : EventCode, i : Int, j : Int) -> Events {
88+
match code {
89+
None => None
90+
SubTask => Subtask(i, SubTaskState::from(j))
91+
StreamRead => StreamRead(i, StreamResult::from(j))
92+
StreamWrite => StreamWrite(i, StreamResult::from(j))
93+
FutureRead => FutureRead(i, FutureReadResult::from(j))
94+
FutureWrite => FutureWrite(i, FutureWriteResult::from(j))
95+
TaskCancelled => TaskCancelled
96+
}
97+
}
98+
99+
// #endregion
100+
101+
// #region waitable set
102+
103+
///|
104+
struct WaitableSet(Int) derive(Eq, Show, Hash)
105+
106+
///|
107+
fn WaitableSet::new() -> WaitableSet {
108+
WaitableSet(waitable_set_new())
109+
}
110+
111+
///|
112+
fn WaitableSet::drop(self : Self) -> Unit {
113+
waitable_set_drop(self.0)
114+
}
115+
116+
// #endregion
117+
118+
// #region Future
119+
120+
///|
121+
priv enum FutureReadResult {
122+
Completed = 0
123+
Cancelled = 1
124+
}
125+
126+
///|
127+
fn FutureReadResult::from(int : Int) -> FutureReadResult {
128+
match int {
129+
0 => Completed
130+
1 => Cancelled
131+
_ => panic()
132+
}
133+
}
134+
135+
///|
136+
priv enum FutureWriteResult {
137+
Completed = 0
138+
Dropped = 1
139+
Cancelled = 2
140+
}
141+
142+
///|
143+
fn FutureWriteResult::from(int : Int) -> FutureWriteResult {
144+
match int {
145+
0 => Completed
146+
1 => Dropped
147+
2 => Cancelled
148+
_ => panic()
149+
}
150+
}
151+
152+
// #endregion
153+
154+
// #region Stream
155+
156+
///|
157+
priv struct StreamResult {
158+
progress : Int
159+
copy_result : CopyResult
160+
}
161+
162+
///|
163+
fn StreamResult::from(int : Int) -> StreamResult {
164+
let progress = int >> 4
165+
let copy_result = CopyResult::from(int & 0xf)
166+
{ progress, copy_result }
167+
}
168+
169+
///|
170+
priv enum CopyResult {
171+
Completed = 0
172+
Dropped = 1
173+
Cancelled = 2
174+
}
175+
176+
///|
177+
fn CopyResult::from(int : Int) -> CopyResult {
178+
match int {
179+
0 => Completed
180+
1 => Dropped
181+
2 => Cancelled
182+
_ => panic()
183+
}
184+
}
185+
186+
// #endregion
187+
188+
// #region callback code
189+
190+
///|
191+
/// Code to let the runtime know what to do in the callback
192+
priv enum CallbackCode {
193+
Completed
194+
Yield
195+
Wait(WaitableSet)
196+
Poll(WaitableSet)
197+
}
198+
199+
///|
200+
fn CallbackCode::encode(self : Self) -> Int {
201+
match self {
202+
Completed => 0
203+
Yield => 1
204+
Wait(id) => 2 | (id.0 << 4)
205+
Poll(id) => 3 | (id.0 << 4)
206+
}
207+
}
208+
209+
///|
210+
fn CallbackCode::decode(int : Int) -> CallbackCode {
211+
let id = int >> 4
212+
match int & 0xf {
213+
0 => Completed
214+
1 => Yield
215+
2 => Wait(id)
216+
3 => Poll(id)
217+
_ => panic()
218+
}
219+
}
220+
221+
// #endregion
222+
223+
// #region Component async primitives
224+
225+
///|
226+
/// Return whether is cancelled.
227+
/// Use for non-callback implementation.
228+
fn _yield() -> Bool = "$root" "[cancellable][yield]"
229+
230+
///|
231+
fn _backpressure_inc() = "$root" "[backpressure-inc]"
232+
233+
///|
234+
fn _backpressure_dec() = "$root" "[backpressure-dec]"
235+
236+
///|
237+
fn subtask_cancel(id : Int) -> Int = "$root" "[subtask-cancel]"
238+
239+
///|
240+
fn subtask_drop(id : Int) = "$root" "[subtask-drop]"
241+
242+
///|
243+
pub fn context_set(task : Int) = "$root" "[context-set-0]"
244+
245+
///|
246+
pub fn context_get() -> Int = "$root" "[context-get-0]"
247+
248+
///|
249+
fn tls_set(tls : Int) = "$root" "[context-set-0]"
250+
251+
///|
252+
fn tls_get() -> Int = "$root" "[context-get-0]"
253+
254+
///|
255+
pub fn task_cancel() = "[export]$root" "[task-cancel]"
256+
257+
///|
258+
fn waitable_set_new() -> Int = "$root" "[waitable-set-new]"
259+
260+
///|
261+
fn waitable_set_drop(set : Int) = "$root" "[waitable-set-drop]"
262+
263+
///|
264+
fn waitable_join(waitable : Int, set : Int) = "$root" "[waitable-join]"
265+
266+
// #endregion
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2025 International Digital Economy Academy
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
///|
16+
async fn[T] async_suspend(
17+
cb : ((T) -> Unit, (Cancelled) -> Unit) -> Unit,
18+
) -> T raise Cancelled = "%async.suspend"
19+
20+
///|
21+
fn run_async(f : async () -> Unit noraise) = "%async.run"

0 commit comments

Comments
 (0)