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
2 changes: 1 addition & 1 deletion .github/actions/setup-zig/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ inputs:
version:
description: 'Zig version to install'
required: false
default: '0.15.1'
default: '0.16.0-dev.3153+d6f43caad'

runs:
using: 'composite'
Expand Down
7 changes: 6 additions & 1 deletion .github/actions/setup-zig/install-zig.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ else
EXTRACT_CMD="tar -xf"
fi

URL="https://ziglang.org/download/${VERSION}/${FILENAME}"
# Dev/nightly builds are served from /builds/, stable releases from /download/<version>/
if [[ "$VERSION" == *"-dev."* ]]; then
URL="https://ziglang.org/builds/${FILENAME}"
else
URL="https://ziglang.org/download/${VERSION}/${FILENAME}"
fi
ARCHIVE_PATH="${INSTALL_DIR}/${FILENAME}"
EXTRACTED_DIR="${INSTALL_DIR}/zig-${ARCH}-${OS}-${VERSION}"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest]
zig-version: ['0.15.1']
zig-version: ['0.16.0-dev.3153+d6f43caad']

defaults:
run:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.zig-cache/
zig-out/
zig-pkg/
*.o

.claude/settings.local.json
48 changes: 31 additions & 17 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ pub fn build(b: *std.Build) !void {

// Luau VM lib
const luau_vm = blk: {
const mod = b.createModule(.{ .target = target, .optimize = optimize });
const mod = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libcpp = true,
});

try addSrcFiles(b, mod, luau_dep, "VM/src", flags);

Expand All @@ -52,7 +56,6 @@ pub fn build(b: *std.Build) !void {
const lib = b.addLibrary(.{ .name = "luau_vm", .root_module = mod, .linkage = .static });

lib.installHeadersDirectory(luau_dep.path("VM/include"), "", .{});
lib.linkLibCpp();

b.installArtifact(lib);

Expand All @@ -63,7 +66,11 @@ pub fn build(b: *std.Build) !void {

// Luau CodeGen lib
const luau_codegen = blk: {
const mod = b.createModule(.{ .target = target, .optimize = optimize });
const mod = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libcpp = true,
});

try addSrcFiles(b, mod, luau_dep, "CodeGen/src", flags);

Expand All @@ -72,13 +79,12 @@ pub fn build(b: *std.Build) !void {
mod.addIncludePath(luau_dep.path("Common/include"));
mod.addIncludePath(luau_dep.path("VM/src"));

mod.linkLibrary(luau_vm);

const lib = b.addLibrary(.{ .name = "luau_codegen", .root_module = mod, .linkage = .static });

lib.installHeader(luau_dep.path("CodeGen/include/luacodegen.h"), "luacodegen.h");

lib.linkLibCpp();
lib.linkLibrary(luau_vm);

b.installArtifact(lib);

steps.luau_codegen.dependOn(&lib.step);
Expand All @@ -88,7 +94,11 @@ pub fn build(b: *std.Build) !void {

// Luau compiler lib
const luau_compiler = blk: {
const mod = b.createModule(.{ .target = target, .optimize = optimize });
const mod = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libcpp = true,
});

try addSrcFiles(b, mod, luau_dep, "Compiler/src", flags);
try addSrcFiles(b, mod, luau_dep, "Ast/src", flags);
Expand All @@ -104,7 +114,6 @@ pub fn build(b: *std.Build) !void {
const lib = b.addLibrary(.{ .name = "luau_compiler", .root_module = mod, .linkage = .static });

lib.installHeader(luau_dep.path("Compiler/include/luacode.h"), "luacode.h");
lib.linkLibCpp();

b.installArtifact(lib);

Expand All @@ -113,7 +122,11 @@ pub fn build(b: *std.Build) !void {

// Luau compiler binary
{
const mod = b.createModule(.{ .target = target, .optimize = optimize });
const mod = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libcpp = true,
});

mod.addCSourceFiles(.{
.root = luau_dep.path("."),
Expand Down Expand Up @@ -143,7 +156,11 @@ pub fn build(b: *std.Build) !void {

// Luau analyze binary
{
const mod = b.createModule(.{ .target = target, .optimize = optimize });
const mod = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libcpp = true,
});

try addSrcFiles(b, mod, luau_dep, "Analysis/src", flags);
try addSrcFiles(b, mod, luau_dep, "Config/src", flags);
Expand Down Expand Up @@ -172,8 +189,6 @@ pub fn build(b: *std.Build) !void {
.root_module = mod,
});

exe.linkLibCpp();

const run = b.addRunArtifact(exe);
if (b.args) |args| {
run.addArgs(args);
Expand Down Expand Up @@ -269,6 +284,7 @@ pub fn build(b: *std.Build) !void {
.root_source_file = b.path("src/tests.zig"),
.target = target,
.optimize = optimize,
.link_libcpp = true,
});

test_mod.addImport("luaz", b.modules.get("luaz").?);
Expand All @@ -287,8 +303,6 @@ pub fn build(b: *std.Build) !void {
});
}

unit_tests.linkLibCpp();

const run_tests = b.addRunArtifact(unit_tests);
steps.@"test".dependOn(&run_tests.step);
}
Expand Down Expand Up @@ -332,15 +346,15 @@ fn addSrcFiles(
const extensions = [_][]const u8{ ".cpp", ".c" };

const abs_path = dep.path(dir_path).getPath(b);
var dir = try std.fs.openDirAbsolute(abs_path, .{ .iterate = true });
defer dir.close();
var dir = try b.build_root.handle.openDir(b.graph.io, abs_path, .{ .iterate = true });
defer dir.close(b.graph.io);

var walker = try dir.walk(b.allocator);
defer walker.deinit();

var files: std.ArrayList([]const u8) = .empty;

while (try walker.next()) |entry| {
while (try walker.next(b.graph.io)) |entry| {
const ext = std.fs.path.extension(entry.basename);
const include = for (extensions) |e| {
if (std.mem.eql(u8, ext, e))
Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},

.fingerprint = 0xceb8ffd87c49e0c3, // Changing this has security and trust implications.
.minimum_zig_version = "0.14.1",
.minimum_zig_version = "0.16.0-dev.3153+d6f43caad",

.paths = .{
"build.zig",
Expand Down
34 changes: 16 additions & 18 deletions examples/guided_tour.zig
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ const Counter = struct {

pub fn main() !void {
// Create an allocator (you can use any Zig allocator)
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var gpa = std.heap.DebugAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

Expand Down Expand Up @@ -682,31 +682,29 @@ pub fn main() !void {
print("Version: 0x{X:0>8}\n", .{std.mem.readInt(u32, buf.data[4..8], .little)});

// Use std.io patterns for structured reading/writing
var stream = buf.stream();
var w = buf.writer();
w.end = 16; // Seek past header

// Seek past header and write structured data
try stream.seekTo(16);

// Write various data types using the stream writer
const writer = stream.writer();
try writer.writeInt(u16, 0xABCD, .big); // 16-bit big-endian
try writer.writeInt(u32, 0x12345678, .little); // 32-bit little-endian
try writer.writeAll("Binary data chunk"); // Raw bytes
// Write various data types using the writer
try w.writeInt(u16, 0xABCD, .big); // 16-bit big-endian
try w.writeInt(u32, 0x12345678, .little); // 32-bit little-endian
try w.writeAll("Binary data chunk"); // Raw bytes
// Write float as raw bytes (IEEE 754 double)
const write_float_bytes = std.mem.toBytes(@as(f64, 3.14159));
try writer.writeAll(&write_float_bytes);
try w.writeAll(&write_float_bytes);

// Read back the data using stream reader
try stream.seekTo(16);
const reader = stream.reader();
const val16 = try reader.readInt(u16, .big);
const val32 = try reader.readInt(u32, .little);
// Read back the data using the reader
var r = buf.reader();
r.seek = 16;
r.end = w.end; // Limit to bytes written
const val16 = try r.takeInt(u16, .big);
const val32 = try r.takeInt(u32, .little);

var text_buf: [17]u8 = undefined;
_ = try reader.read(&text_buf);
try r.readSliceAll(&text_buf);
// Read float as raw bytes and convert back
var float_bytes: [8]u8 = undefined;
_ = try reader.read(&float_bytes);
try r.readSliceAll(&float_bytes);
const float_val = std.mem.bytesToValue(f64, &float_bytes);

print("Read back: u16=0x{X}, u32=0x{X}, text='{s}', float={d:.5}\n", .{ val16, val32, text_buf, float_val });
Expand Down
59 changes: 38 additions & 21 deletions src/Lua.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1499,8 +1499,8 @@ pub inline fn createTable(self: Self, opts: struct { arr: u32 = 0, rec: u32 = 0
/// @memcpy(buf.data[10..15], "hello");
///
/// // Use with I/O patterns
/// var stream = buf.stream();
/// try stream.writer().writeInt(u32, 0x12345678, .little);
/// var w = buf.writer();
/// try w.writeInt(u32, 0x12345678, .little);
/// ```
///
/// Returns: `Buffer` - A wrapper around the newly created buffer
Expand Down Expand Up @@ -1886,10 +1886,12 @@ pub const Function = struct {
/// @memcpy(buf.data[10..20], "hello");
///
/// // Use with std.io patterns
/// var stream = buf.stream();
/// try stream.writer().writeInt(u32, 0x12345678, .little);
/// try stream.seekTo(0);
/// const value = try stream.reader().readInt(u32, .little);
/// var w = buf.writer();
/// try w.writeInt(u32, 0x12345678, .little);
///
/// var r = buf.reader();
/// r.end = w.end; // Limit to bytes written
/// const value = try r.takeVarInt(u32, .little, 4);
/// ```
pub const Buffer = struct {
ref: Ref,
Expand All @@ -1910,23 +1912,38 @@ pub const Buffer = struct {
return self.data.len;
}

/// Returns a stream for reading/writing/seeking within the buffer.
/// Returns a Writer for sequential writing to the buffer.
///
/// The stream provides standard I/O operations on the buffer memory:
/// - `.writer()` - Get a writer for sequential writing
/// - `.reader()` - Get a reader for sequential reading
/// - `.seekTo(pos)` - Seek to a specific position
/// - `.getPos()` - Get current position
/// The writer uses the entire buffer capacity. It returns `error.WriteFailed`
/// when the buffer is full. Check `writer.end` for the current write position.
///
/// Example:
/// ```zig
/// var stream = buf.stream();
/// try stream.writer().writeAll("Hello");
/// try stream.seekTo(0);
/// const data = try stream.reader().readAllAlloc(allocator, 1024);
/// var w = buf.writer();
/// try w.writeInt(u32, 0x12345678, .little);
/// const bytes_written = w.end;
/// ```
pub fn writer(self: *Buffer) std.Io.Writer {
return std.Io.Writer.fixed(self.data);
}

/// Returns a Reader for sequential reading from the buffer.
///
/// By default, reads from position 0 to the end of the buffer. Adjust
/// `reader.seek` and `reader.end` fields to control the read range.
///
/// Example:
/// ```zig
/// // Read only bytes that were written
/// var w = buf.writer();
/// try w.writeAll("hello");
///
/// var r = buf.reader();
/// r.end = w.end; // Limit to bytes written
/// const data = try r.peek(r.end);
/// ```
pub fn stream(self: *Buffer) std.io.FixedBufferStream([]u8) {
return std.io.fixedBufferStream(self.data);
pub fn reader(self: *Buffer) std.Io.Reader {
return std.Io.Reader.fixed(self.data);
}

/// Returns the registry reference ID if valid, otherwise null.
Expand Down Expand Up @@ -2526,9 +2543,9 @@ pub fn registerUserData(self: Self, comptime T: type) !void {
/// Returns: Allocated string containing the stack dump. Caller owns the memory.
/// Errors: `std.mem.Allocator.Error` if memory allocation fails
pub fn dumpStack(self: Self, allocator: std.mem.Allocator) ![]u8 {
var list: std.ArrayList(u8) = .empty;
var list = std.Io.Writer.Allocating.init(allocator);
const writer = &list.writer;

const writer = list.writer(allocator);
const stack_size = self.state.getTop();

if (stack_size == 0) {
Expand All @@ -2548,7 +2565,7 @@ pub fn dumpStack(self: Self, allocator: std.mem.Allocator) ![]u8 {
n -= 1;
}

return list.toOwnedSlice(allocator);
return list.toOwnedSlice();
}

/// Apply sandbox restrictions to create a secure execution environment.
Expand Down
32 changes: 15 additions & 17 deletions src/tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1495,25 +1495,23 @@ test "buffer with std.io patterns" {
var buf = try lua.createBuffer(256);
defer buf.deinit();

// Test writing with stream
var stream = buf.stream();

// Write various integer types
try stream.writer().writeInt(u32, 0x12345678, .little);
try stream.writer().writeInt(u16, 0xABCD, .little);
try stream.writer().writeInt(u8, 0xFF, .little);

// Write string
try stream.writer().writeAll("Hello");

// Seek back and read
try stream.seekTo(0);
try expectEq(try stream.reader().readInt(u32, .little), 0x12345678);
try expectEq(try stream.reader().readInt(u16, .little), 0xABCD);
try expectEq(try stream.reader().readInt(u8, .little), 0xFF);
// Write with writer
var w = buf.writer();
try w.writeInt(u32, 0x12345678, .little);
try w.writeInt(u16, 0xABCD, .little);
try w.writeByte(0xFF);
try w.writeAll("Hello");
const bytes_written = w.end;

// Read with reader - limit to bytes written
var r = buf.reader();
r.end = bytes_written;
try expectEq(try r.takeVarInt(u32, .little, 4), 0x12345678);
try expectEq(try r.takeVarInt(u16, .little, 2), 0xABCD);
try expectEq(try r.takeByte(), 0xFF);

var read_buf: [5]u8 = undefined;
_ = try stream.reader().read(&read_buf);
try r.readSliceAll(&read_buf);
try expect(std.mem.eql(u8, &read_buf, "Hello"));
}

Expand Down
Loading