Loading...
Loading...
Comprehensive Zig 0.15.2 development expert. Use when writing Zig code, debugging memory issues, designing build systems, implementing comptime metaprogramming, handling errors, or cross-compiling. Automatically activated for any .zig file or build.zig work.
npx skill4agent add lammesen/skills zig-expert!Ttrycatcherrdefercomptime T: type@typeInfo| Allocator | Use Case | Thread-Safe |
|---|---|---|
| Development/debugging, leak detection | Configurable |
| Batch operations, bulk deallocation | No |
| Stack-backed, embedded, no heap | No |
| Simple backing allocator | Yes |
| Performance-critical (requires libc) | Yes |
| Unit tests (auto leak detection) | No |
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
const status = gpa.deinit();
if (status == .leak) @panic("Memory leak detected!");
}
const allocator = gpa.allocator();
try run(allocator);
}var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); // Frees ALL allocations at once
const allocator = arena.allocator();
// No individual frees needed
_ = try allocator.alloc(u8, 100);
_ = try allocator.alloc(u8, 200);test "memory safety" {
var list = std.ArrayList(i32).init(std.testing.allocator);
defer list.deinit();
try list.append(42);
try std.testing.expectEqual(@as(i32, 42), list.pop());
}// Define specific error sets (preferred over anyerror)
const FileError = error{
AccessDenied,
FileNotFound,
OutOfMemory,
};
// Inferred error set (use sparingly)
fn process() !void {
// Error set inferred from all possible errors
}// try: Propagate error to caller
const file = try std.fs.cwd().openFile("data.txt", .{});
// catch: Handle error locally
const value = getValue() catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.FileNotFound => return default_value,
else => unreachable,
};
// catch with default
const result = mayFail() catch default;
// orelse: For optionals
const unwrapped = optional_value orelse default_value;fn initResource(allocator: Allocator) !*Resource {
const resource = try allocator.create(Resource);
errdefer allocator.destroy(resource); // Runs ONLY if error returned
resource.buffer = try allocator.alloc(u8, 1024);
errdefer allocator.free(resource.buffer);
try resource.initialize(); // If this fails, both errdefers run
return resource;
}fn example() !void {
const a = try allocate();
defer free(a); // Runs: 3rd (last defer, first to run)
errdefer cleanup(a); // Runs: only on error, before defers
const b = try allocate();
defer free(b); // Runs: 2nd
const c = try allocate();
defer free(c); // Runs: 1st
// Normal exit: free(c), free(b), free(a)
// Error exit: cleanup(a), then error propagates
}pub fn ArrayList(comptime T: type) type {
return struct {
items: []T,
capacity: usize,
allocator: std.mem.Allocator,
const Self = @This();
pub fn init(allocator: std.mem.Allocator) Self {
return .{ .items = &.{}, .capacity = 0, .allocator = allocator };
}
pub fn deinit(self: *Self) void {
if (self.capacity > 0) {
self.allocator.free(self.items.ptr[0..self.capacity]);
}
}
pub fn append(self: *Self, item: T) !void {
if (self.items.len >= self.capacity) {
try self.ensureCapacity(self.capacity * 2 + 1);
}
self.items.len += 1;
self.items[self.items.len - 1] = item;
}
};
}fn serialize(comptime T: type, value: T) ![]u8 {
const info = @typeInfo(T);
return switch (info) {
.@"struct" => |s| {
inline for (s.fields) |field| {
const field_value = @field(value, field.name);
// Process each field...
}
},
.int => std.fmt.allocPrint(allocator, "{d}", .{value}),
.float => std.fmt.allocPrint(allocator, "{d}", .{value}),
else => @compileError("Unsupported type: " ++ @typeName(T)),
};
}fn Vector(comptime size: usize) type {
if (size == 0) @compileError("Vector size must be > 0");
if (size > 1024) @compileError("Vector size too large");
return struct {
data: [size]f32,
pub fn dot(self: @This(), other: @This()) f32 {
var sum: f32 = 0;
inline for (0..size) |i| {
sum += self.data[i] * other.data[i];
}
return sum;
}
};
}fn print(writer: anytype, value: anytype) !void {
const T = @TypeOf(value);
if (@hasDecl(T, "format")) {
try value.format(writer);
} else {
try writer.print("{any}", .{value});
}
}const JsonValue = union(enum) {
null,
bool: bool,
number: f64,
string: []const u8,
array: []JsonValue,
object: std.StringHashMap(JsonValue),
pub fn isNull(self: JsonValue) bool {
return self == .null;
}
};
// Pattern matching with payload capture
fn processJson(value: JsonValue) void {
switch (value) {
.null => {},
.bool => |b| std.debug.print("bool: {}\n", .{b}),
.number => |n| std.debug.print("number: {d}\n", .{n}),
.string => |s| std.debug.print("string: {s}\n", .{s}),
.array => |arr| for (arr) |item| processJson(item),
.object => |obj| {
var it = obj.iterator();
while (it.next()) |entry| {
std.debug.print("{s}: ", .{entry.key_ptr.*});
processJson(entry.value_ptr.*);
}
},
}
}const Flags = packed struct(u8) {
enabled: bool, // bit 0
priority: u3, // bits 1-3
mode: enum(u2) { normal, fast, slow, custom }, // bits 4-5
reserved: u2 = 0, // bits 6-7
};
// Bitcast to/from backing integer
const flags = Flags{ .enabled = true, .priority = 5, .mode = .fast };
const byte: u8 = @bitCast(flags);
const restored: Flags = @bitCast(byte);const CStruct = extern struct {
x: c_int,
y: c_long,
data: [256]u8,
};
// Guaranteed C-compatible layout
comptime {
std.debug.assert(@sizeOf(CStruct) == @sizeOf(c_int) + @sizeOf(c_long) + 256);
}const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "myapp",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
b.installArtifact(exe);
// Run step
const run_exe = b.addRunArtifact(exe);
run_exe.step.dependOn(b.getInstallStep());
if (b.args) |args| run_exe.addArgs(args);
const run_step = b.step("run", "Run the application");
run_step.dependOn(&run_exe.step);
// Test step
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
const run_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_tests.step);
}const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const lib = b.addStaticLibrary(.{
.name = "mylib",
.root_module = b.createModule(.{
.root_source_file = b.path("src/lib.zig"),
.target = target,
.optimize = optimize,
}),
});
// Link system libraries
lib.linkSystemLibrary("z");
lib.linkLibC();
// Add C source files
lib.addCSourceFiles(.{
.files = &.{ "src/c/helper.c" },
.flags = &.{ "-std=c99", "-O2" },
});
lib.addIncludePath(b.path("include/"));
b.installArtifact(lib);
}.{
.name = "my_project",
.version = "0.1.0",
.dependencies = .{
.zap = .{
.url = "https://github.com/zigzap/zap/archive/refs/tags/v0.1.7.tar.gz",
.hash = "1220002d24d73672fe8b1e39717c0671598acc8ec27b8af2e1caf623a4fd0ce0d1bd",
},
.local_lib = .{
.path = "../lib",
},
},
.paths = .{ "build.zig", "build.zig.zon", "src" },
}zig build -Dtarget=x86_64-linux-gnu -Doptimize=ReleaseFast
zig build -Dtarget=aarch64-macos
zig build -Dtarget=x86_64-windows-gnu
zig build -Dtarget=wasm32-freestandingconst targets = [_]std.Target.Query{
.{}, // native
.{ .cpu_arch = .x86_64, .os_tag = .linux },
.{ .cpu_arch = .x86_64, .os_tag = .windows },
.{ .cpu_arch = .aarch64, .os_tag = .macos },
.{ .cpu_arch = .wasm32, .os_tag = .freestanding },
};
pub fn build(b: *std.Build) void {
for (targets) |t| {
const exe = b.addExecutable(.{
.name = "myapp",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = b.resolveTargetQuery(t),
.optimize = .ReleaseFast,
}),
});
b.installArtifact(exe);
}
}const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError;
test "basic functionality" {
var list = std.ArrayList(i32).init(std.testing.allocator);
defer list.deinit();
try list.append(42);
try expectEqual(@as(i32, 42), list.pop());
}
test "error handling" {
const result = mayFail();
try expectError(error.SomeError, result);
}
test "floating point comparison" {
const value = calculatePi();
try expect(@abs(value - 3.14159) < 0.00001);
}zig build test --summary all
zig test src/main.zig| Module | Purpose |
|---|---|
| Memory utilities, slices, allocator interface |
| Allocator implementations |
| File system operations |
| Networking (TCP/UDP, DNS) |
| JSON parsing/serialization |
| String formatting |
| I/O readers and writers |
| Dynamic arrays |
| Hash maps |
| Threading primitives |
| Unit testing utilities |
| Debug printing, assertions |
| Structured logging |
| Cryptographic primitives |
| Process management |
| Item | Convention | Example |
|---|---|---|
| Types | PascalCase | |
| Functions | camelCase | |
| Constants | snake_case | |
| Files | snake_case.zig | |
| Test names | Descriptive strings | |
allocdefer free_ = mayFail();_ = mayFail() catch {};errdefer+%+|[*:0]const u8.zigbuild.zigbuild.zig.zon