Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions docs/xev-zig.7.scd
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ over the C API. For example, all callbacks in the Zig API must be available
at comptime because the callback call is always inlined -- this results in
a noticable performance improvement over equivalent C consumption of libxev.

The primary Zig API is visible in `src/main.zig` in the libxev source. The main file uses a somewhat convoluted `usingnamespace` to setup the
API so it isn't immediately obvious, but the API is provided by the `Xev`
function. For example, available consts are: `xev.Loop`, `xev.Completion`,
etc.
The primary Zig API is visible in `src/main.zig` in the libxev source.

# INSTALLATION

Expand Down
88 changes: 88 additions & 0 deletions src/api.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const builtin = @import("builtin");
const stream = @import("watcher/stream.zig");
const Backend = @import("backend.zig").Backend;

/// Creates the Xev API based on a backend type.
///
/// For the default backend type for your system (i.e. io_uring on Linux),
/// this is the main API you interact with. It is forwarded into the main
/// the "xev" package so you'd use types such as `xev.Loop`, `xev.Completion`,
/// etc.
///
/// Unless you're using a custom or specific backend type, you do NOT ever
/// need to call the Xev function itself.
pub fn Xev(comptime be: Backend, comptime T: type) type {
return struct {
const Self = @This();
const loop = @import("loop.zig");

/// This is used to detect a static vs dynamic API at comptime.
pub const dynamic = false;

/// The backend that this is. This is supplied at comptime so
/// it is up to the caller to say the right thing. This lets custom
/// implementations also "quack" like an implementation.
pub const backend = be;

/// A function to test if this API is available on the
/// current system.
pub const available = T.available;

/// The core loop APIs.
pub const Loop = T.Loop;
pub const Completion = T.Completion;
pub const Result = T.Result;
pub const ReadBuffer = T.ReadBuffer;
pub const WriteBuffer = T.WriteBuffer;
pub const Options = loop.Options;
pub const RunMode = loop.RunMode;
pub const CallbackAction = loop.CallbackAction;
pub const CompletionState = loop.CompletionState;

/// Error types
pub const AcceptError = T.AcceptError;
pub const CancelError = T.CancelError;
pub const CloseError = T.CloseError;
pub const ConnectError = T.ConnectError;
pub const ShutdownError = T.ShutdownError;
pub const WriteError = T.WriteError;
pub const ReadError = T.ReadError;

/// Shared stream types
const SharedStream = stream.Shared(Self);
pub const PollError = SharedStream.PollError;
pub const PollEvent = SharedStream.PollEvent;
pub const WriteQueue = SharedStream.WriteQueue;
pub const WriteRequest = SharedStream.WriteRequest;

/// The high-level helper interfaces that make it easier to perform
/// common tasks. These may not work with all possible Loop implementations.
pub const Async = @import("watcher/async.zig").Async(Self);
pub const File = @import("watcher/file.zig").File(Self);
pub const Process = @import("watcher/process.zig").Process(Self);
pub const Stream = stream.GenericStream(Self);
pub const Timer = @import("watcher/timer.zig").Timer(Self);
pub const TCP = @import("watcher/tcp.zig").TCP(Self);
pub const UDP = @import("watcher/udp.zig").UDP(Self);

/// The callback of the main Loop operations. Higher level interfaces may
/// use a different callback mechanism.
pub const Callback = loop.Callback(T);

/// A callback that does nothing and immediately disarms. This
/// implements xev.Callback and is the default value for completions.
pub const noopCallback = loop.NoopCallback(T);

/// A way to access the raw type.
pub const Sys = T;

test {
@import("std").testing.refAllDecls(@This());
}

test "completion is zero-able" {
const c: Self.Completion = .{};
_ = c;
}
};
}
52 changes: 52 additions & 0 deletions src/backend.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const builtin = @import("builtin");
const stream = @import("watcher/stream.zig");

/// The backend types.
pub const Backend = enum {
io_uring,
epoll,
kqueue,
wasi_poll,
iocp,

/// Returns a recommend default backend from inspecting the system.
pub fn default() Backend {
return switch (builtin.os.tag) {
.linux => .io_uring,
.ios, .macos => .kqueue,
.freebsd => .kqueue,
.wasi => .wasi_poll,
.windows => .iocp,
else => {
@compileLog(builtin.os);
@compileError("no default backend for this target");
},
};
}

/// Candidate backends for this platform in priority order.
pub fn candidates() []const Backend {
return switch (builtin.os.tag) {
.linux => &.{ .io_uring, .epoll },
.ios, .macos => &.{.kqueue},
.freebsd => &.{.kqueue},
.wasi => &.{.wasi_poll},
.windows => &.{.iocp},
else => {
@compileLog(builtin.os);
@compileError("no candidate backends for this target");
},
};
}

/// Returns the Api (return value of Xev) for the given backend type.
pub fn Api(comptime self: Backend) type {
return switch (self) {
.io_uring => @import("main.zig").IO_Uring,
.epoll => @import("main.zig").Epoll,
.kqueue => @import("main.zig").Kqueue,
.wasi_poll => @import("main.zig").WasiPoll,
.iocp => @import("main.zig").IOCP,
};
}
};
Loading
Loading