Skip to content

Commit c91c063

Browse files
committed
feat(examples): add Zig version compatibility layer
- create compat module to handle Zig 0.15 and 0.16 API differences - update build system to include and distribute compat module to examples - replace version-specific std.time and std.io calls with compatibility wrappers
1 parent a55153c commit c91c063

File tree

6 files changed

+121
-19
lines changed

6 files changed

+121
-19
lines changed

build.zig

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,13 @@ pub fn build(b: *Build) !void {
8686
// Setup documentation generation
8787
generate_docs(b, optimize, target, flags_module);
8888

89+
// Create compatibility module for Zig version differences
90+
const compat_module = b.addModule("compat", .{
91+
.root_source_file = b.path(b.pathJoin(&.{ "examples", "compat.zig" })),
92+
});
93+
8994
// Build example applications
90-
build_examples(b, optimize, target, webui_module, webui.artifact("webui")) catch |err| {
95+
build_examples(b, optimize, target, webui_module, compat_module, webui.artifact("webui")) catch |err| {
9196
log.err("failed to build examples: {}", .{err});
9297
std.process.exit(1);
9398
};
@@ -126,7 +131,7 @@ fn generate_docs(b: *Build, optimize: OptimizeMode, target: Build.ResolvedTarget
126131
}
127132

128133
// Function to build all example applications
129-
fn build_examples(b: *Build, optimize: OptimizeMode, target: Build.ResolvedTarget, webui_module: *Module, webui_lib: *Compile) !void {
134+
fn build_examples(b: *Build, optimize: OptimizeMode, target: Build.ResolvedTarget, webui_module: *Module, compat_module: *Module, webui_lib: *Compile) !void {
130135

131136
// Get the absolute path to the examples directory
132137
var lazy_path = b.path("examples");
@@ -174,8 +179,9 @@ fn build_examples(b: *Build, optimize: OptimizeMode, target: Build.ResolvedTarge
174179
}),
175180
});
176181

177-
// Add the webui module and link against the library
182+
// Add the webui and compat modules and link against the library
178183
exe.root_module.addImport("webui", webui_module);
184+
exe.root_module.addImport("compat", compat_module);
179185
exe.linkLibrary(webui_lib);
180186

181187
// Setup installation

examples/advanced_window/main.zig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const std = @import("std");
22
const webui = @import("webui");
33
const builtin = @import("builtin");
4+
const compat = @import("compat");
45

56
pub fn main() !void {
67
const window = webui.newWindow();
@@ -105,7 +106,7 @@ fn getPortInfo(e: *webui.Event) void {
105106
const window = e.getWindow();
106107

107108
var buffer: [256]u8 = undefined;
108-
var fbs = std.io.fixedBufferStream(&buffer);
109+
var fbs = compat.fixedBufferStream(&buffer);
109110
const writer = fbs.writer();
110111

111112
const port = window.getPort() catch 0;
@@ -125,7 +126,7 @@ fn getProcessInfo(e: *webui.Event) void {
125126
const window = e.getWindow();
126127

127128
var buffer: [512]u8 = undefined;
128-
var fbs = std.io.fixedBufferStream(&buffer);
129+
var fbs = compat.fixedBufferStream(&buffer);
129130
const writer = fbs.writer();
130131

131132
const parent_pid = window.getParentProcessId() catch 0;

examples/compat.zig

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//! Compatibility layer for Zig 0.15 and 0.16
2+
const std = @import("std");
3+
const builtin = @import("builtin");
4+
5+
// Check Zig version
6+
const zig_version = builtin.zig_version;
7+
const is_zig_0_16_or_later = zig_version.minor >= 16;
8+
9+
// C time function fallback for Zig 0.16
10+
extern "c" fn time(tloc: ?*i64) i64;
11+
12+
/// Get current Unix timestamp in seconds
13+
pub fn timestamp() i64 {
14+
if (is_zig_0_16_or_later) {
15+
// Zig 0.16: use C time function
16+
return time(null);
17+
} else {
18+
// Zig 0.15 and earlier
19+
return std.time.timestamp();
20+
}
21+
}
22+
23+
/// Get current timestamp in nanoseconds
24+
pub fn nanoTimestamp() i128 {
25+
if (is_zig_0_16_or_later) {
26+
// Zig 0.16: approximate with seconds precision
27+
return @as(i128, time(null)) * 1_000_000_000;
28+
} else {
29+
// Zig 0.15 and earlier
30+
return std.time.nanoTimestamp();
31+
}
32+
}
33+
34+
/// Create a fixed buffer stream compatible with both Zig 0.15 and 0.16
35+
/// Returns the appropriate FixedBufferStream type for the Zig version
36+
pub fn fixedBufferStream(buffer: []u8) FixedBufferStream {
37+
if (comptime is_zig_0_16_or_later) {
38+
// Zig 0.16: construct FixedBufferStream directly
39+
return .{ .buffer = buffer, .pos = 0 };
40+
} else {
41+
// Zig 0.15 and earlier: use helper function
42+
return std.io.fixedBufferStream(buffer);
43+
}
44+
}
45+
46+
/// Type alias for FixedBufferStream that works in both versions
47+
pub const FixedBufferStream = if (is_zig_0_16_or_later) blk: {
48+
// Zig 0.16: Define our own FixedBufferStream with custom Writer
49+
break :blk struct {
50+
buffer: []u8,
51+
pos: usize = 0,
52+
53+
const Self = @This();
54+
55+
// Custom Writer implementation for Zig 0.16
56+
pub const Writer = struct {
57+
context: *Self,
58+
59+
pub fn writeAll(self: Writer, bytes: []const u8) error{NoSpaceLeft}!void {
60+
const written = try self.context.write(bytes);
61+
if (written != bytes.len) return error.NoSpaceLeft;
62+
}
63+
64+
pub fn print(self: Writer, comptime format: []const u8, args: anytype) error{NoSpaceLeft}!void {
65+
const context = self.context;
66+
const remaining = context.buffer[context.pos..];
67+
const written_slice = std.fmt.bufPrint(remaining, format, args) catch return error.NoSpaceLeft;
68+
context.pos += written_slice.len;
69+
}
70+
};
71+
72+
pub fn writer(self: *Self) Writer {
73+
return .{ .context = self };
74+
}
75+
76+
fn write(self: *Self, bytes: []const u8) error{NoSpaceLeft}!usize {
77+
if (self.pos + bytes.len > self.buffer.len) {
78+
return error.NoSpaceLeft;
79+
}
80+
@memcpy(self.buffer[self.pos..][0..bytes.len], bytes);
81+
self.pos += bytes.len;
82+
return bytes.len;
83+
}
84+
85+
pub fn getWritten(self: Self) []const u8 {
86+
return self.buffer[0..self.pos];
87+
}
88+
};
89+
} else blk: {
90+
// Zig 0.15: Use standard library type
91+
break :blk @TypeOf(std.io.fixedBufferStream(@as([]u8, undefined)));
92+
};

examples/comprehensive/main.zig

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! This example demonstrates multiple WebUI features working together
33
const std = @import("std");
44
const webui = @import("webui");
5+
const compat = @import("compat");
56

67
const html = @embedFile("index.html");
78

@@ -148,7 +149,7 @@ fn getAppStatus(e: *webui.Event) void {
148149
var buffer: [1024]u8 = undefined;
149150
const json = std.fmt.bufPrintZ(buffer[0..],
150151
\\{{"status":"running","users":{},"messages":{},"files":{},"port":{},"url":"{s}","clientId":{},"timestamp":{}}}
151-
, .{ app_state.users_online, app_state.messages_sent, app_state.files_uploaded, port, url, e.client_id, std.time.timestamp() }) catch "{\"error\":\"format_error\"}";
152+
, .{ app_state.users_online, app_state.messages_sent, app_state.files_uploaded, port, url, e.client_id, compat.timestamp() }) catch "{\"error\":\"format_error\"}";
152153

153154
std.debug.print("App Status - Users: {}, Messages: {}, Files: {}\n", .{ app_state.users_online, app_state.messages_sent, app_state.files_uploaded });
154155

@@ -262,15 +263,15 @@ fn executeCommand(e: *webui.Event, command: [:0]const u8, args: [:0]const u8) vo
262263
if (std.mem.eql(u8, command, "echo")) {
263264
result = std.fmt.bufPrintZ(response[0..], "Echo: {s}", .{args}) catch "Error";
264265
} else if (std.mem.eql(u8, command, "time")) {
265-
const timestamp = std.time.timestamp();
266+
const timestamp = compat.timestamp();
266267
result = std.fmt.bufPrintZ(response[0..], "Current time: {}", .{timestamp}) catch "Error";
267268
} else if (std.mem.eql(u8, command, "random")) {
268-
var prng = std.Random.DefaultPrng.init(@intCast(std.time.timestamp()));
269+
var prng = std.Random.DefaultPrng.init(@intCast(compat.timestamp()));
269270
const random_num = prng.random().int(u32);
270271
result = std.fmt.bufPrintZ(response[0..], "Random number: {}", .{random_num}) catch "Error";
271272
} else if (std.mem.eql(u8, command, "memory")) {
272273
// Simple memory info (simulated)
273-
result = std.fmt.bufPrintZ(response[0..], "Memory usage: {}MB", .{50 + @rem(std.time.timestamp(), 100)}) catch "Error";
274+
result = std.fmt.bufPrintZ(response[0..], "Memory usage: {}MB", .{50 + @rem(compat.timestamp(), 100)}) catch "Error";
274275
} else {
275276
result = "Unknown command";
276277
}
@@ -282,15 +283,15 @@ fn getSystemInfo(e: *webui.Event) void {
282283
const builtin = @import("builtin");
283284

284285
var buffer: [1024]u8 = undefined;
285-
const info = std.fmt.bufPrintZ(buffer[0..],
286+
const info = std.fmt.bufPrintZ(buffer[0..],
286287
\\{{"os":"{s}","arch":"{s}","zigVersion":"{s}","webuiVersion":"2.5.0","timestamp":{}}}
287-
, .{ @tagName(builtin.os.tag), @tagName(builtin.cpu.arch), @import("builtin").zig_version_string, std.time.timestamp() }) catch "{}";
288+
, .{ @tagName(builtin.os.tag), @tagName(builtin.cpu.arch), @import("builtin").zig_version_string, compat.timestamp() }) catch "{}";
288289

289290
e.returnString(info);
290291
}
291292

292293
fn testPerformance(e: *webui.Event, iterations: i64, operation: [:0]const u8) void {
293-
const start_time = std.time.nanoTimestamp();
294+
const start_time = compat.nanoTimestamp();
294295

295296
var i: i64 = 0;
296297
var result: u64 = 0;
@@ -306,7 +307,7 @@ fn testPerformance(e: *webui.Event, iterations: i64, operation: [:0]const u8) vo
306307
}
307308
}
308309

309-
const end_time = std.time.nanoTimestamp();
310+
const end_time = compat.nanoTimestamp();
310311
const duration_ms = @as(f64, @floatFromInt(end_time - start_time)) / 1_000_000.0;
311312

312313
var response: [256]u8 = undefined;

examples/event_handling/main.zig

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const std = @import("std");
44
const webui = @import("webui");
55
const builtin = @import("builtin");
6+
const compat = @import("compat");
67

78
const html = @embedFile("index.html");
89

@@ -55,7 +56,7 @@ const UserContext = struct {
5556
context.* = UserContext{
5657
.user_id = user_id,
5758
.username = try allocator.dupe(u8, username),
58-
.session_start = std.time.timestamp(),
59+
.session_start = compat.timestamp(),
5960
.click_count = 0,
6061
};
6162
return context;
@@ -259,7 +260,7 @@ fn userLogout(e: *webui.Event) void {
259260
};
260261

261262
// Calculate session duration
262-
const session_duration = std.time.timestamp() - context.session_start;
263+
const session_duration = compat.timestamp() - context.session_start;
263264

264265
var response: [257]u8 = undefined; // +1 for null terminator
265266
const msg = std.fmt.bufPrint(response[0..256],
@@ -324,7 +325,7 @@ fn getUserInfo(e: *webui.Event) void {
324325
return;
325326
};
326327

327-
const session_time = std.time.timestamp() - context.session_start;
328+
const session_time = compat.timestamp() - context.session_start;
328329

329330
var response: [513]u8 = undefined; // +1 for null terminator
330331
const json = std.fmt.bufPrint(response[0..512],
@@ -371,7 +372,7 @@ fn broadcastUserListUpdate() void {
371372
var json_content: []const u8 = undefined;
372373

373374
if (online_users) |users| {
374-
var stream = std.io.fixedBufferStream(&users_json);
375+
var stream = compat.fixedBufferStream(&users_json);
375376
var writer = stream.writer();
376377

377378
writer.writeAll("[") catch return;
@@ -400,7 +401,7 @@ fn getOnlineUsers(e: *webui.Event) void {
400401
var json_content: []const u8 = undefined;
401402

402403
if (online_users) |users| {
403-
var stream = std.io.fixedBufferStream(&users_json);
404+
var stream = compat.fixedBufferStream(&users_json);
404405
var writer = stream.writer();
405406

406407
writer.writeAll("[") catch {

examples/js_execution/main.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! This example demonstrates running JavaScript from Zig and advanced communication
33
const std = @import("std");
44
const webui = @import("webui");
5+
const compat = @import("compat");
56

67
const html = @embedFile("index.html");
78

@@ -133,7 +134,7 @@ fn sendDataToJs(e: *webui.Event, message: [:0]const u8, value: i64) void {
133134
var data: [256]u8 = undefined;
134135
const json_data = std.fmt.bufPrint(data[0..],
135136
"{{\"message\":\"{s}\",\"value\":{},\"timestamp\":{}}}",
136-
.{message, value, std.time.timestamp()}) catch return;
137+
.{message, value, compat.timestamp()}) catch return;
137138

138139
// Send data to JavaScript function
139140
var js_call: [512]u8 = undefined;

0 commit comments

Comments
 (0)