floooh / sokol-zig

Zig bindings for the sokol headers (https://github.com/floooh/sokol)
zlib License
355 stars 49 forks source link

wrapping c errors as zig errors #16

Open pfgithub opened 2 years ago

pfgithub commented 2 years ago

makeBuffer and many other make functions can return null

pub fn makeBuffer(desc: BufferDesc) Buffer {
    return sg_make_buffer(&desc);
}

pub fn makeBuffer(desc: BufferDesc) !Buffer {
    const res = sg_make_buffer(&desc);
    if(res.id == 0) return error.PoolExhausted;
    return res;
}

I think this could be done with a minor modification to gen_zig.py def gen_func_zig but I'm not sure if there's any way for it to know which functions to do this for or what field to check.

def gen_func_zig(decl, prefix):
    c_func_name = decl['name']
    zig_func_name = as_camel_case(check_name_override(decl['name']))
    zig_res_type = funcdecl_result_zig(decl, prefix)
+   can_error = decl['name'].startsWith("sg_make_")
    l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{")
+   if can_error:
+       s = f"    const res = {c_func_name}("
-   if zig_res_type != 'void':
+   elif zig_res_type != 'void':
        s = f"    return {c_func_name}("
    else:
        s = f"    {c_func_name}("
    for i, param_decl in enumerate(decl['params']):
        if i > 0:
            s += ", "
        arg_name = param_decl['name']
        arg_type = param_decl['type']
        if is_const_struct_ptr(arg_type):
            s += f"&{arg_name}"
        elif is_string_ptr(arg_type):
            s += f"@ptrCast([*c]const u8,{arg_name})"
        else:
            s += arg_name
    s += ");"
    l(s)
+   if can_error:
+       l("    if (res.id == 0) return error.PoolExhausted;")
+       l("    return res;")
    l("}")
floooh commented 2 years ago

Yes makes sense, I'm hesitant to implement this though before getting a better idea of how to map certain "Zig-isms" to the language bindings wrapper. For instance another "obvious" change would be to accept a Zig allocator in the sg.setup() function, but this requires additional work on the C side so that allocation calls from C can be forwarded into the Zig allocator (a more dynamic allocator interface using callback functions is on my mental todo list).

In general, error handling in the Sokol headers by far isn't as strictly designed as it would be required for Zig's error handling approach, and in general I preferred "silently ignored errors", which also isn't quite compatible with Zig's philosophy. In some headers this is mostly fine, but in others the error feedback should be better (for instance in sokol_gl.h).

I'll keep the ticket open as reminder and maybe further discussion.