Skip to content

Commit a670e8c

Browse files
authored
C# future simple codegen (#1357)
* C# Move export and import types to respective classes. Capitilase import and export Add initial future support * Address feedback Combine FutureReader and FutureWriter to AsyncSupport. Start the process of adding futures per type * fallout from merging head. Remove async and update tests. * align names for runner runtime projects * cargo fmt * switch to generic FutureReader/Writer with vtable * Apply feedback * take advantage of the copy trait. * add Handle check
1 parent 44225ca commit a670e8c

File tree

47 files changed

+1474
-537
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1474
-537
lines changed

crates/csharp/src/AsyncSupport.cs

Lines changed: 323 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,330 @@
22
* Helpers for the async support.
33
*/
44

5-
public enum CallbackCode
5+
public enum CallbackCode
66
{
77
Exit = 0,
88
Yield = 1,
99
}
10+
11+
public partial class WaitableSet(int handle) : IDisposable
12+
{
13+
public int Handle { get; } = handle;
14+
15+
void Dispose(bool _disposing)
16+
{
17+
AsyncSupport.WaitableSetDrop(this);
18+
}
19+
20+
public void Dispose()
21+
{
22+
Dispose(true);
23+
GC.SuppressFinalize(this);
24+
}
25+
26+
~WaitableSet()
27+
{
28+
Dispose(false);
29+
}
30+
}
31+
32+
public static class AsyncSupport
33+
{
34+
private static class Interop
35+
{
36+
[global::System.Runtime.InteropServices.DllImportAttribute("$root", EntryPoint = "[waitable-set-new]"), global::System.Runtime.InteropServices.WasmImportLinkageAttribute]
37+
internal static extern int WaitableSetNew();
38+
39+
[global::System.Runtime.InteropServices.DllImportAttribute("$root", EntryPoint = "[waitable-join]"), global::System.Runtime.InteropServices.WasmImportLinkageAttribute]
40+
internal static extern void WaitableJoin(int waitable, int set);
41+
42+
[global::System.Runtime.InteropServices.DllImportAttribute("$root", EntryPoint = "[waitable-set-wait]"), global::System.Runtime.InteropServices.WasmImportLinkageAttribute]
43+
internal static unsafe extern int WaitableSetWait(int waitable, int* waitableHandlePtr);
44+
45+
[global::System.Runtime.InteropServices.DllImportAttribute("$root", EntryPoint = "[waitable-set-drop]"), global::System.Runtime.InteropServices.WasmImportLinkageAttribute]
46+
internal static unsafe extern void WaitableSetDrop(int waitable);
47+
}
48+
49+
public static WaitableSet WaitableSetNew()
50+
{{
51+
var waitableSet = Interop.WaitableSetNew();
52+
return new WaitableSet(waitableSet );
53+
}}
54+
55+
public static void Join(FutureWriter writer, WaitableSet set)
56+
{{
57+
Interop.WaitableJoin(writer.Handle, set.Handle);
58+
}}
59+
60+
public unsafe static EventWaitable WaitableSetWait(WaitableSet set)
61+
{{
62+
int* buffer = stackalloc int[2];
63+
var eventCode = (EventCode)Interop.WaitableSetWait(set.Handle, buffer);
64+
return new EventWaitable(eventCode, buffer[0], buffer[1]);
65+
}}
66+
67+
public static void WaitableSetDrop(WaitableSet set)
68+
{{
69+
Interop.WaitableSetDrop(set.Handle);
70+
}}
71+
}
72+
73+
/**
74+
* Helpers for future support.
75+
*/
76+
public delegate ulong New();
77+
public delegate int StartRead(int handle, IntPtr buffer);
78+
public delegate void DropReader(int handle);
79+
public delegate void DropWriter(int handle);
80+
public delegate int Write(int handle, IntPtr buffer);
81+
82+
public struct FutureVTable
83+
{
84+
public New New;
85+
public StartRead StartRead;
86+
public Write Write;
87+
public DropReader DropReader;
88+
public DropWriter DropWriter;
89+
}
90+
91+
public static class FutureHelpers
92+
{
93+
/// Helper function to create a new read/write pair for a component model
94+
/// future.
95+
public static (FutureReader, FutureWriter) RawFutureNew(FutureVTable vtable)
96+
{
97+
var packed = vtable.New();
98+
var readerHandle = (int)(packed & 0xFFFFFFFF);
99+
var writerHandle = (int)(packed >> 32);
100+
101+
return (new FutureReader(readerHandle, vtable), new FutureWriter(writerHandle, vtable));
102+
}
103+
104+
public static (FutureReader<T>, FutureWriter<T>) RawFutureNew<T>(FutureVTable vtable)
105+
{
106+
var packed = vtable.New();
107+
var readerHandle = (int)(packed & 0xFFFFFFFF);
108+
var writerHandle = (int)(packed >> 32);
109+
110+
return (new FutureReader<T>(readerHandle, vtable), new FutureWriter<T>(writerHandle, vtable));
111+
}
112+
}
113+
114+
public class FutureReader(int handle, FutureVTable vTable) : IDisposable // : TODO Waitable
115+
{
116+
public int Handle { get; private set; } = handle;
117+
public FutureVTable VTable { get; private set; } = vTable;
118+
119+
public int TakeHandle()
120+
{
121+
if (Handle == 0)
122+
{
123+
throw new InvalidOperationException("Handle already taken");
124+
}
125+
var handle = Handle;
126+
Handle = 0;
127+
return handle;
128+
}
129+
130+
// TODO: Generate per type for this instrinsic.
131+
public Task Read()
132+
{
133+
// TODO: Generate for the interop name and the namespace.
134+
if (Handle == 0)
135+
{
136+
throw new InvalidOperationException("Handle already taken");
137+
}
138+
139+
var status = new WaitableStatus(vTable.StartRead(Handle, IntPtr.Zero));
140+
if (status.IsBlocked)
141+
{
142+
//TODO: store somewhere so we can complete it later.
143+
var tcs = new TaskCompletionSource();
144+
145+
return tcs.Task;
146+
}
147+
if (status.IsCompleted)
148+
{
149+
return Task.CompletedTask;
150+
}
151+
152+
throw new NotImplementedException();
153+
}
154+
155+
void Dispose(bool _disposing)
156+
{
157+
// Free unmanaged resources if any.
158+
if (Handle != 0)
159+
{
160+
vTable.DropReader(Handle);
161+
}
162+
}
163+
164+
public void Dispose()
165+
{
166+
Dispose(true);
167+
GC.SuppressFinalize(this);
168+
}
169+
170+
~FutureReader()
171+
{
172+
Dispose(false);
173+
}
174+
}
175+
176+
public class FutureReader<T>(int handle, FutureVTable vTable) : IDisposable // : TODO Waitable
177+
{
178+
public int Handle { get; private set; } = handle;
179+
public FutureVTable VTable { get; private set; } = vTable;
180+
181+
public int TakeHandle()
182+
{
183+
if (Handle == 0)
184+
{
185+
throw new InvalidOperationException("Handle already taken");
186+
}
187+
var handle = Handle;
188+
Handle = 0;
189+
return handle;
190+
}
191+
192+
// TODO: Generate per type for this instrinsic.
193+
public Task Read()
194+
{
195+
// TODO: Generate for the interop name and the namespace.
196+
if (Handle == 0)
197+
{
198+
throw new InvalidOperationException("Handle already taken");
199+
}
200+
201+
var status = new WaitableStatus(vTable.StartRead(Handle, IntPtr.Zero));
202+
if (status.IsBlocked)
203+
{
204+
//TODO: store somewhere so we can complete it later.
205+
var tcs = new TaskCompletionSource();
206+
207+
return tcs.Task;
208+
}
209+
if (status.IsCompleted)
210+
{
211+
return Task.CompletedTask;
212+
}
213+
214+
throw new NotImplementedException();
215+
}
216+
217+
void Dispose(bool _disposing)
218+
{
219+
// Free unmanaged resources if any.
220+
if (Handle != 0)
221+
{
222+
vTable.DropReader(Handle);
223+
}
224+
}
225+
226+
public void Dispose()
227+
{
228+
Dispose(true);
229+
GC.SuppressFinalize(this);
230+
}
231+
232+
~FutureReader()
233+
{
234+
Dispose(false);
235+
}
236+
}
237+
238+
/**
239+
* Helpers for future writer support.
240+
*/
241+
public class FutureWriter(int handle, FutureVTable vTable) // : TODO Waitable
242+
{
243+
public int Handle { get; } = handle;
244+
public FutureVTable VTable { get; private set; } = vTable;
245+
246+
// TODO: Generate per type for this instrinsic.
247+
public Task Write()
248+
{
249+
// TODO: Generate for the interop name.
250+
if (Handle == 0)
251+
{
252+
throw new InvalidOperationException("Handle already taken");
253+
}
254+
255+
var status = new WaitableStatus(VTable.Write(Handle, IntPtr.Zero));
256+
if (status.IsBlocked)
257+
{
258+
//TODO: store somewhere so we can complete it later.
259+
var tcs = new TaskCompletionSource();
260+
return tcs.Task;
261+
}
262+
263+
throw new NotImplementedException();
264+
}
265+
266+
void Dispose(bool _disposing)
267+
{
268+
// Free unmanaged resources if any.
269+
if (Handle != 0)
270+
{
271+
VTable.DropWriter(Handle);
272+
}
273+
}
274+
275+
public void Dispose()
276+
{
277+
Dispose(true);
278+
GC.SuppressFinalize(this);
279+
}
280+
281+
~FutureWriter()
282+
{
283+
Dispose(false);
284+
}
285+
}
286+
287+
public class FutureWriter<T>(int handle, FutureVTable vTable) // : TODO Waitable
288+
{
289+
public int Handle { get; } = handle;
290+
public FutureVTable VTable { get; private set; } = vTable;
291+
292+
// TODO: Generate per type for this instrinsic.
293+
public Task Write()
294+
{
295+
// TODO: Generate for the interop name.
296+
if (Handle == 0)
297+
{
298+
throw new InvalidOperationException("Handle already taken");
299+
}
300+
301+
var status = new WaitableStatus(VTable.Write(Handle, IntPtr.Zero));
302+
if (status.IsBlocked)
303+
{
304+
//TODO: store somewhere so we can complete it later.
305+
var tcs = new TaskCompletionSource();
306+
return tcs.Task;
307+
}
308+
309+
throw new NotImplementedException();
310+
}
311+
312+
void Dispose(bool _disposing)
313+
{
314+
// Free unmanaged resources if any.
315+
if (Handle != 0)
316+
{
317+
VTable.DropWriter(Handle);
318+
}
319+
}
320+
321+
public void Dispose()
322+
{
323+
Dispose(true);
324+
GC.SuppressFinalize(this);
325+
}
326+
327+
~FutureWriter()
328+
{
329+
Dispose(false);
330+
}
331+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Helpers for future support.
3+
*/
4+
5+
public readonly struct WaitableStatus (int status)
6+
{
7+
public int State => status & 0xf;
8+
public int Count => (int)(status >> 4);
9+
public bool IsBlocked => status == -1;
10+
public bool IsCompleted => State == 0;
11+
public bool IsDropped => State == 1;
12+
}
13+
14+
public enum EventCode
15+
{
16+
None,
17+
Subtask,
18+
StreamRead,
19+
StreamWrite,
20+
FutureRead,
21+
FutureWrite,
22+
Cancel,
23+
}
24+
25+
public readonly struct EventWaitable
26+
{
27+
public EventWaitable(EventCode eventCode, int waitable, int code)
28+
{
29+
Event = eventCode;
30+
Waitable = waitable;
31+
Status = new WaitableStatus(code);
32+
}
33+
public readonly EventCode Event;
34+
public readonly int Waitable;
35+
public readonly int Code;
36+
37+
public readonly WaitableStatus Status;
38+
}
39+

0 commit comments

Comments
 (0)