|
//onReady takes a callback and a frame pointer, |
|
//and then at some point passes the frame pointer to the callback. |
|
//the frame pointer is typed as anyopaque (same as c void pointer) |
|
//instead of any frame because of compiler errors in get |
|
extern fn onReady( |
|
cb: fn ( frame: *anyopaque ) callconv(.C) void, |
|
frame: *anyopaque |
|
) void; |
|
|
|
//copies memory from host into pointer, up to len |
|
extern fn read(ptr: [*]const u8, len:usize) usize; |
|
//writes len bytes from ptr to stdout |
|
extern fn print(ptr: [*]const u8, len:usize) void; |
|
|
|
fn get (slice: []u8) usize { |
|
//put a suspend here, otherwise async get() |
|
//will run to the end then return frame at return value. |
|
//we don't want to do that because memory to read isn't ready yet. |
|
suspend { |
|
//because we pass a pointer to our own frame to an external function |
|
//that parameter must be typed *anyopaque. if it's typed anyframe |
|
//there are compiler errors that "@Frame(get) not analyzed yet" |
|
onReady(cb, @frame()); |
|
} |
|
return read(slice.ptr, slice.len); |
|
} |
|
|
|
fn cb (frame: *anyopaque) callconv(.C) void { |
|
//defer allocator.destroy(frame); |
|
//cast frame:*anyopaque to frame:*anyframe so we can resume it. |
|
//this requires also casting the alignment. |
|
resume @ptrCast(anyframe, @alignCast(4, frame)); |
|
} |
|
|
|
//internal _init function, this can have any sort of async pattern. |
|
fn _init () void { |
|
var array1:[1]u8 = [_]u8{0}; |
|
//note: because of zig's uncoloured async, this just looks like a normal loop |
|
while (0 != get(array1[0..array1.len])) { |
|
print(&array1, 1); |
|
} |
|
} |
|
|
|
//this is the essential trick, store the _init frame in global variable. |
|
var init_frame :@Frame(_init) = undefined; |
|
//the exported function can't be async |
|
//but we can call another function with async keyword |
|
//but if we did that with a local variable the memory wouldn't be alive |
|
//after init() returns |
|
//so, we make it a global. then, call async _init |
|
//and have any kind of async pattern in there. |
|
|
|
//(note, this does mean that init() should only be called exactly once, like main()) |
|
export fn init () void { |
|
init_frame = async _init(); |
|
} |
The data is really attractive. Explore coreball game world with different levels of advanced difficulty. Shoot the ball at an incredible speed to attach the ball to the center ring. The task is really simple but the challenge is really great.