core
Clients use this module and renders state struct managed by this. Every function is blocking, so client is responsible for making them asynchronous.
Code Styles
This section describes module internal rules for writing code.
Struct creation function
A function that creates struct Foo,
- should be named
init - should return a value (
Foo), rather than a pointer ofFoo(*Foo) - can return an error union
This is what many Zig projects, including std, uses.
Let the caller decide where to store.
const std = @import("std");
pub const Foo = struct {
bar: i32,
pub fn init() Foo {
return .{ bar = 0 };
}
}
Struct creation and allocation function
A function that allocates and initializes struct Foo,
- should be named
make - should return a pointer (
*Foo) - should NOT take an allocator
- can return an error union
const std = @import("std");
pub const Foo = extern struct {
const allocator = std.heap.c_allocator;
bar: i32,
pub fn make() callconv(.C) std.mem.Allocator.Error!*Foo {
const dst = try allocator.create(Foo);
dst.* = .{
.bar = 0,
};
return dst;
}
}
comptime {
@export(&Foo.make, .{ .name = "plac_foo_make" });
}
Exported struct internal
Exported structs’ initial field must be a pointer to an internal struct:
// plac.h
typedef struct {
void *__pri;
uint32_t bar;
} plac_foo;
// foo.zig
pub const Foo = extern struct {
internal: *Internal,
bar: u32,
const Internal = struct {
baz: u32,
};
};
Non-ABI stable fields (e.g. slices, reference counter) and internal fields should go inside internal field.
Function parameters
Zig team has a plan to drop automatic pass-by-reference conversion for function parameters.
To minimize the cost of future migration, do not annotate a parameter with value type if pass-by-value is not desirable.
For this reason, struct methods should use pointer type for self parameter.
pub const Foo = struct {
// OK
pub fn bar(self: *Foo): void {}
// OK
pub fn bar(self: *const Foo): void {}
// NG
pub fn bar(self: Foo): void {}
}
Exported functions
When an exported function takes a pointer, it should be an optional pointer rather than regular pointer, to guard against accidentally passing NULL pointer.
pub const Foo = extern struct {
pub fn bar(self: *const Foo) void {
// ...
}
}
export fn do_something(foo_ptr: ?*const Foo) void {
const foo = foo_ptr orelse return;
foo.bar();
}
If the function returns result code, define a code for receiving a NULL pointer. If the function returns a pointer, return a NULL pointer and document about it in header file.