312 lines
7.4 KiB
Markdown
312 lines
7.4 KiB
Markdown
# Agent Solutions Guide: Zig 0.15 Issues
|
|
|
|
This document catalogs common issues encountered when working with Zig 0.15 and their solutions. Written for AI coding assistants to avoid repeating mistakes.
|
|
|
|
## Critical: ArrayList API Changed in Zig 0.15
|
|
|
|
### Problem
|
|
`std.ArrayList` is now an alias to `std.ArrayListUnmanaged` in Zig 0.15. The managed version has been removed.
|
|
|
|
### Old (Pre-0.15) Code - DOES NOT WORK
|
|
```zig
|
|
var list = std.ArrayList(u8).init(allocator);
|
|
defer list.deinit();
|
|
try list.append(item);
|
|
```
|
|
|
|
### New (0.15+) Code - CORRECT
|
|
```zig
|
|
// Empty initialization
|
|
var list = std.ArrayList(u8){};
|
|
defer list.deinit(allocator);
|
|
try list.append(allocator, item);
|
|
|
|
// Or with capacity
|
|
var list = try std.ArrayList(u8).initCapacity(allocator, 100);
|
|
defer list.deinit(allocator);
|
|
try list.append(allocator, item);
|
|
```
|
|
|
|
### Key Changes
|
|
1. **Initialization**: Use `{}` or `initCapacity()`, not `init()`
|
|
2. **All methods take allocator**: `append(allocator, item)` not `append(item)`
|
|
3. **Deinit takes allocator**: `deinit(allocator)` not `deinit()`
|
|
|
|
## AST Rendering API Changed
|
|
|
|
### Problem
|
|
The `ast.render()` function signature changed in Zig 0.15.
|
|
|
|
### Old Code - DOES NOT WORK
|
|
```zig
|
|
var ast = try std.zig.Ast.parse(allocator, source, .zig);
|
|
const output = try ast.render(allocator);
|
|
```
|
|
|
|
### New Code - CORRECT
|
|
```zig
|
|
var ast = try std.zig.Ast.parse(allocator, source, .zig);
|
|
const output = try ast.renderAlloc(allocator);
|
|
defer allocator.free(output);
|
|
```
|
|
|
|
### The API
|
|
- `renderAlloc(allocator)` - Returns allocated string
|
|
- `render(tree, gpa, writer, fixups)` - Low-level version for custom output
|
|
|
|
## Type Conversion: SDL Types to Zig
|
|
|
|
### Pointer Types
|
|
|
|
| C Type | Zig Type | Notes |
|
|
|--------|----------|-------|
|
|
| `const char *` | `[*c]const u8` | C string |
|
|
| `void *` | `?*anyopaque` | Nullable any pointer |
|
|
| `const void *` | `?*const anyopaque` | Const version |
|
|
| `SDL_Type *` | `?*Type` | Nullable pointer to opaque/struct |
|
|
| `const SDL_Type *` | `*const Type` | Non-null const pointer |
|
|
| `SDL_Type **` | `?*?*Type` | Output parameter (double pointer) |
|
|
| `SDL_Type *const *` | `[*c]*const Type` | Array of const pointers |
|
|
| `Uint32 *` | `*u32` | Output parameter (primitive) |
|
|
|
|
### Key Principles
|
|
1. **Non-nullable by default** for const pointers to structs
|
|
2. **Nullable (`?*`)** for pointers that can be NULL
|
|
3. **Use `*` not `[*c]`** when you know it's not a C-style array
|
|
4. **Double pointers**: `?*?*Type` for output parameters
|
|
|
|
## Function Signature Formatting
|
|
|
|
### Trailing Commas
|
|
Only use trailing commas for functions with **more than 3 parameters**. This triggers multi-line formatting.
|
|
|
|
```zig
|
|
// 1-3 parameters: single line, no trailing comma
|
|
pub fn foo(a: i32, b: i32, c: i32) void {}
|
|
|
|
// 4+ parameters: multi-line with trailing comma
|
|
pub fn bar(
|
|
a: i32,
|
|
b: i32,
|
|
c: i32,
|
|
d: i32,
|
|
) void {}
|
|
```
|
|
|
|
### Why?
|
|
- Trailing comma with no parameters: `(,)` is **syntax error**
|
|
- Trailing comma with 1-3 params: unnecessary, wastes vertical space
|
|
- Trailing comma with 4+ params: makes diffs cleaner, easier to read
|
|
|
|
## Method Organization
|
|
|
|
### Place Methods Inside Opaque Types
|
|
Functions where the first parameter is a pointer to an opaque type should be methods:
|
|
|
|
```zig
|
|
// Good - method syntax
|
|
pub const GPUDevice = opaque {
|
|
pub fn destroy(device: *GPUDevice) void {
|
|
c.SDL_DestroyGPUDevice(device);
|
|
}
|
|
};
|
|
|
|
// Usage: device.destroy()
|
|
|
|
// Bad - standalone function
|
|
pub fn destroyGPUDevice(device: ?*GPUDevice) void {
|
|
c.SDL_DestroyGPUDevice(device);
|
|
}
|
|
|
|
// Usage: destroyGPUDevice(device)
|
|
```
|
|
|
|
### Benefits
|
|
1. Cleaner API: `device.create()` vs `createGPUDevice(device)`
|
|
2. IDE autocomplete works better
|
|
3. Namespacing prevents naming conflicts
|
|
4. More idiomatic Zig
|
|
|
|
## Casting Guidelines
|
|
|
|
### When to Cast
|
|
|
|
| Scenario | Cast | Example |
|
|
|----------|------|---------|
|
|
| Opaque pointer | `@ptrCast` | `@ptrCast(device)` |
|
|
| Flags (packed struct) | `@bitCast` | `@bitCast(flags)` |
|
|
| Enum to int | `@intFromEnum` | `@intFromEnum(enum_val)` |
|
|
| Struct passed by value | None | Just pass it |
|
|
| Const pointer to struct | `@ptrCast` | `@ptrCast(info)` |
|
|
|
|
### Don't Over-Cast
|
|
```zig
|
|
// Bad - unnecessary cast for value type
|
|
fn setColor(color: FColor) void {
|
|
c.SDL_SetColor(@bitCast(color)); // Wrong!
|
|
}
|
|
|
|
// Good - no cast needed
|
|
fn setColor(color: FColor) void {
|
|
c.SDL_SetColor(color); // Correct
|
|
}
|
|
```
|
|
|
|
## StringHashMap Usage
|
|
|
|
### Correct Pattern
|
|
```zig
|
|
var map = std.StringHashMap(ValueType).init(allocator);
|
|
defer map.deinit(); // No allocator needed for deinit
|
|
|
|
try map.put("key", value);
|
|
const val = map.get("key");
|
|
```
|
|
|
|
### Iteration
|
|
```zig
|
|
var it = map.keyIterator();
|
|
while (it.next()) |key| {
|
|
// Use key.*
|
|
}
|
|
|
|
var it = map.valueIterator();
|
|
while (it.next()) |value| {
|
|
// Use value.* if needed
|
|
}
|
|
```
|
|
|
|
## Common Pitfalls
|
|
|
|
### 1. Forgetting Allocator in Unmanaged Collections
|
|
```zig
|
|
// Wrong
|
|
list.append(item);
|
|
|
|
// Right
|
|
list.append(allocator, item);
|
|
```
|
|
|
|
### 2. Using .init() on ArrayList
|
|
```zig
|
|
// Wrong
|
|
var list = std.ArrayList(u8).init(allocator);
|
|
|
|
// Right
|
|
var list = std.ArrayList(u8){};
|
|
// or
|
|
var list = try std.ArrayList(u8).initCapacity(allocator, size);
|
|
```
|
|
|
|
### 3. Not Checking AST Errors Before Rendering
|
|
```zig
|
|
// Wrong - will panic if there are errors
|
|
const output = try ast.renderAlloc(allocator);
|
|
|
|
// Right - check first
|
|
if (ast.errors.len > 0) {
|
|
// Handle errors
|
|
return error.ParseError;
|
|
}
|
|
const output = try ast.renderAlloc(allocator);
|
|
```
|
|
|
|
### 4. Incorrect Double Pointer Types
|
|
```zig
|
|
// Wrong - C-style for output params
|
|
texture: [*c]*GPUTexture
|
|
|
|
// Right - Zig optional pointers
|
|
texture: ?*?*GPUTexture
|
|
```
|
|
|
|
## Testing Patterns
|
|
|
|
### Simple Test
|
|
```zig
|
|
test "description" {
|
|
const result = try someFunction();
|
|
try std.testing.expectEqual(expected, result);
|
|
}
|
|
```
|
|
|
|
### Test with Allocator
|
|
```zig
|
|
test "with allocator" {
|
|
const allocator = std.testing.allocator;
|
|
const result = try allocateAndDoSomething(allocator);
|
|
defer allocator.free(result);
|
|
|
|
try std.testing.expectEqualStrings("expected", result);
|
|
}
|
|
```
|
|
|
|
## Build System Integration
|
|
|
|
### Adding Parser to Dependencies
|
|
```zig
|
|
// build.zig.zon
|
|
.dependencies = .{
|
|
.sdl3_parser = .{ .path = "parser/" },
|
|
},
|
|
|
|
// build.zig
|
|
const parser_dep = b.dependency("sdl3_parser", .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
});
|
|
const parser_exe = parser_dep.artifact("sdl-parser");
|
|
```
|
|
|
|
### Run Step
|
|
```zig
|
|
const run_parser = b.addRunArtifact(parser_exe);
|
|
run_parser.addFileArg(b.path("input.h"));
|
|
run_parser.addArg("--output=output.zig");
|
|
|
|
const step = b.step("generate", "Generate bindings");
|
|
step.dependOn(&run_parser.step);
|
|
```
|
|
|
|
## Quick Reference Card
|
|
|
|
```zig
|
|
// Collections
|
|
var list = std.ArrayList(T){};
|
|
defer list.deinit(allocator);
|
|
try list.append(allocator, item);
|
|
|
|
var map = std.StringHashMap(V).init(allocator);
|
|
defer map.deinit();
|
|
try map.put("key", value);
|
|
|
|
// AST
|
|
var ast = try std.zig.Ast.parse(allocator, source, .zig);
|
|
defer ast.deinit(allocator);
|
|
const formatted = try ast.renderAlloc(allocator);
|
|
defer allocator.free(formatted);
|
|
|
|
// Type Patterns
|
|
?*Type // Nullable pointer
|
|
*const Type // Non-null const pointer
|
|
?*?*Type // Output parameter
|
|
[*c]*const Type // C array of const pointers
|
|
|
|
// Casts
|
|
@ptrCast(ptr) // Pointers
|
|
@bitCast(value) // Packed structs, flags
|
|
@intFromEnum(e) // Enum to int
|
|
// No cast for value types!
|
|
```
|
|
|
|
## Version Info
|
|
|
|
- **Zig Version**: 0.15.2
|
|
- **Date**: 2025-01-22
|
|
- **SDL Version**: 3.2.0
|
|
|
|
## References
|
|
|
|
- Zig 0.15 Release Notes: https://ziglang.org/download/0.15.0/release-notes.html
|
|
- Zig Standard Library Docs: https://ziglang.org/documentation/master/std/
|