@pilllesss/yorn 1.0.182 → 1.0.183
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @pilllesss/yorn might be problematic. Click here for more details.
- package/README.md +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/skills/code-review/LICENSE +21 -0
- package/dist/skills/code-review/SKILL.md +233 -0
- package/dist/skills/code-review/assets/pr-review-template.md +137 -0
- package/dist/skills/code-review/assets/review-checklist.md +123 -0
- package/dist/skills/code-review/reference/angular.md +768 -0
- package/dist/skills/code-review/reference/architecture-review-guide.md +472 -0
- package/dist/skills/code-review/reference/c.md +890 -0
- package/dist/skills/code-review/reference/code-quality-universal.md +488 -0
- package/dist/skills/code-review/reference/code-review-best-practices.md +136 -0
- package/dist/skills/code-review/reference/common-bugs-checklist.md +302 -0
- package/dist/skills/code-review/reference/cpp.md +893 -0
- package/dist/skills/code-review/reference/cross-cutting/async-concurrency-patterns.md +515 -0
- package/dist/skills/code-review/reference/cross-cutting/error-handling-principles.md +492 -0
- package/dist/skills/code-review/reference/cross-cutting/n-plus-one-queries.md +309 -0
- package/dist/skills/code-review/reference/cross-cutting/sql-injection-prevention.md +308 -0
- package/dist/skills/code-review/reference/cross-cutting/xss-prevention.md +264 -0
- package/dist/skills/code-review/reference/csharp.md +525 -0
- package/dist/skills/code-review/reference/css-less-sass.md +661 -0
- package/dist/skills/code-review/reference/dart.md +670 -0
- package/dist/skills/code-review/reference/django.md +985 -0
- package/dist/skills/code-review/reference/fastapi.md +580 -0
- package/dist/skills/code-review/reference/go.md +993 -0
- package/dist/skills/code-review/reference/java.md +409 -0
- package/dist/skills/code-review/reference/java8.md +586 -0
- package/dist/skills/code-review/reference/kotlin.md +1018 -0
- package/dist/skills/code-review/reference/nestjs.md +593 -0
- package/dist/skills/code-review/reference/performance-review-guide.md +816 -0
- package/dist/skills/code-review/reference/php.md +684 -0
- package/dist/skills/code-review/reference/python.md +1073 -0
- package/dist/skills/code-review/reference/qt.md +757 -0
- package/dist/skills/code-review/reference/react.md +871 -0
- package/dist/skills/code-review/reference/ruby.md +964 -0
- package/dist/skills/code-review/reference/rust.md +846 -0
- package/dist/skills/code-review/reference/security-review-guide.md +494 -0
- package/dist/skills/code-review/reference/svelte.md +1064 -0
- package/dist/skills/code-review/reference/swift.md +936 -0
- package/dist/skills/code-review/reference/typescript.md +1016 -0
- package/dist/skills/code-review/reference/vue.md +924 -0
- package/dist/skills/code-review/reference/zig.md +440 -0
- package/dist/skills/code-review/scripts/pr-analyzer.py +435 -0
- package/dist/skills/code-review/scripts/test_pr_analyzer.py +380 -0
- package/dist/yorn.cjs +628 -628
- package/package.json +2 -2
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
# Zig Code Review Guide
|
|
2
|
+
|
|
3
|
+
> Code review guidelines for Zig focusing on explicit memory ownership, error unions, defer/errdefer cleanup, comptime usage, safety-checked operations, C interop, and tests.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Memory & Allocators](#memory--allocators)
|
|
8
|
+
- [Errors & Cleanup](#errors--cleanup)
|
|
9
|
+
- [Pointers, Slices & Optionals](#pointers-slices--optionals)
|
|
10
|
+
- [Comptime & Generics](#comptime--generics)
|
|
11
|
+
- [Safety, Undefined Behavior & Casts](#safety-undefined-behavior--casts)
|
|
12
|
+
- [C Interop](#c-interop)
|
|
13
|
+
- [Testing](#testing)
|
|
14
|
+
- [Style & API Design](#style--api-design)
|
|
15
|
+
- [Review Checklist](#review-checklist)
|
|
16
|
+
- [References](#references)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Memory & Allocators
|
|
21
|
+
|
|
22
|
+
### Make Allocator Ownership Explicit
|
|
23
|
+
|
|
24
|
+
Zig code should make allocation policy visible. Libraries should usually accept an `std.mem.Allocator` from the caller rather than creating a global allocator internally.
|
|
25
|
+
|
|
26
|
+
```zig
|
|
27
|
+
const std = @import("std");
|
|
28
|
+
|
|
29
|
+
// ❌ Bad: hides allocation policy and lifetime from callers.
|
|
30
|
+
fn readNamesBad() ![][]const u8 {
|
|
31
|
+
var gpa = std.heap.DebugAllocator(.{}){};
|
|
32
|
+
const allocator = gpa.allocator();
|
|
33
|
+
return try allocator.alloc([]const u8, 10);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ✅ Good: caller chooses allocator and owns the returned memory.
|
|
37
|
+
fn readNames(allocator: std.mem.Allocator) ![][]const u8 {
|
|
38
|
+
return try allocator.alloc([]const u8, 10);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Review questions:
|
|
43
|
+
- Does the caller know who owns allocated memory?
|
|
44
|
+
- Does the API document whether returned slices must be freed?
|
|
45
|
+
- Is the allocator parameter passed through instead of replaced by an internal global allocator?
|
|
46
|
+
|
|
47
|
+
### Pair Allocations With Cleanup
|
|
48
|
+
|
|
49
|
+
Every allocation path should have a visible cleanup path. Look for missing `defer`, missing `errdefer`, and containers that are initialized but never deinitialized.
|
|
50
|
+
|
|
51
|
+
```zig
|
|
52
|
+
const std = @import("std");
|
|
53
|
+
|
|
54
|
+
fn collectBad(allocator: std.mem.Allocator) ![]u8 {
|
|
55
|
+
// ❌ Bad: returns a slice whose backing memory is freed as the function exits.
|
|
56
|
+
var bad_list: std.ArrayListUnmanaged(u8) = .empty;
|
|
57
|
+
defer bad_list.deinit(allocator);
|
|
58
|
+
try bad_list.append(allocator, 'a');
|
|
59
|
+
return bad_list.items;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fn collect(allocator: std.mem.Allocator) ![]u8 {
|
|
63
|
+
// ✅ Good: `errdefer` cleans up only on failure; success transfers ownership.
|
|
64
|
+
var list: std.ArrayListUnmanaged(u8) = .empty;
|
|
65
|
+
errdefer list.deinit(allocator);
|
|
66
|
+
|
|
67
|
+
try list.append(allocator, 'a');
|
|
68
|
+
try list.append(allocator, 'b');
|
|
69
|
+
return try list.toOwnedSlice(allocator);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Review questions:
|
|
74
|
+
- Is cleanup registered immediately after acquisition?
|
|
75
|
+
- Is `errdefer` used when ownership transfers only on success?
|
|
76
|
+
- Are `deinit` calls paired with all container initializations?
|
|
77
|
+
|
|
78
|
+
### Choose Allocators Deliberately
|
|
79
|
+
|
|
80
|
+
Allocator choice is part of the design. A review should flag broad use of a debug/general-purpose allocator where a fixed buffer, arena, page allocator, or caller-provided allocator better matches the lifetime.
|
|
81
|
+
|
|
82
|
+
```zig
|
|
83
|
+
// ❌ Bad: allocation lifetime is scattered across many individual frees.
|
|
84
|
+
const user = try allocator.create(User);
|
|
85
|
+
const events = try allocator.alloc(Event, event_count);
|
|
86
|
+
|
|
87
|
+
// ✅ Good: request/frame-scoped allocations are freed together.
|
|
88
|
+
var arena = std.heap.ArenaAllocator.init(parent_allocator);
|
|
89
|
+
defer arena.deinit();
|
|
90
|
+
const allocator = arena.allocator();
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Review questions:
|
|
94
|
+
- Are arena allocations freed at a clear lifetime boundary?
|
|
95
|
+
- Is a test using `std.testing.allocator` to catch leaks?
|
|
96
|
+
- Is a library avoiding policy decisions that belong to its caller?
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Errors & Cleanup
|
|
101
|
+
|
|
102
|
+
### Keep Error Sets Useful
|
|
103
|
+
|
|
104
|
+
Avoid flattening meaningful errors into `anyerror` unless the boundary genuinely needs it. Specific error sets improve API contracts and make callers handle expected failures.
|
|
105
|
+
|
|
106
|
+
```zig
|
|
107
|
+
// ❌ Bad: erases the expected parse failures behind `anyerror`.
|
|
108
|
+
fn parseDigitAny(input: []const u8) anyerror!u8 {
|
|
109
|
+
if (input.len == 0) return error.EmptyInput;
|
|
110
|
+
if (input[0] < '0' or input[0] > '9') return error.InvalidDigit;
|
|
111
|
+
return input[0] - '0';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ✅ Good: names the domain failures that callers should handle.
|
|
115
|
+
const ParseError = error{
|
|
116
|
+
EmptyInput,
|
|
117
|
+
InvalidDigit,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
fn parseDigit(input: []const u8) ParseError!u8 {
|
|
121
|
+
if (input.len == 0) return error.EmptyInput;
|
|
122
|
+
if (input[0] < '0' or input[0] > '9') return error.InvalidDigit;
|
|
123
|
+
return input[0] - '0';
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Review questions:
|
|
128
|
+
- Are expected domain failures named explicitly?
|
|
129
|
+
- Is `anyerror` only used at integration boundaries?
|
|
130
|
+
- Does the caller preserve context when converting errors?
|
|
131
|
+
|
|
132
|
+
### Use `try`, `catch`, and `errdefer` Intentionally
|
|
133
|
+
|
|
134
|
+
Blind `catch unreachable` is a code smell unless the invariant is mechanically guaranteed. Prefer propagating errors with `try`, converting them at boundaries, or adding a comment for unreachable invariants.
|
|
135
|
+
|
|
136
|
+
```zig
|
|
137
|
+
// ❌ Bad: hides a real allocation failure.
|
|
138
|
+
const buffer_bad = allocator.alloc(u8, size) catch unreachable;
|
|
139
|
+
|
|
140
|
+
// ✅ Good: caller can handle OutOfMemory.
|
|
141
|
+
const buffer = try allocator.alloc(u8, size);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Review questions:
|
|
145
|
+
- Does `catch unreachable` mask I/O, allocation, parsing, or user-input errors?
|
|
146
|
+
- Are errors converted close to a boundary where the abstraction changes?
|
|
147
|
+
- Does `errdefer` undo partial state changes on failure?
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Pointers, Slices & Optionals
|
|
152
|
+
|
|
153
|
+
### Prefer Slices Over Pointer Plus Length
|
|
154
|
+
|
|
155
|
+
Slices carry pointer and length together, improving bounds checking and API clarity. Raw pointer plus length should be reserved for FFI or very low-level code.
|
|
156
|
+
|
|
157
|
+
```zig
|
|
158
|
+
// ❌ Bad: easy to mismatch pointer and length.
|
|
159
|
+
fn checksumRaw(ptr: [*]const u8, len: usize) u32 {
|
|
160
|
+
var sum: u32 = 0;
|
|
161
|
+
for (ptr[0..len]) |byte| sum += byte;
|
|
162
|
+
return sum;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ✅ Good: one value represents the buffer.
|
|
166
|
+
fn checksum(bytes: []const u8) u32 {
|
|
167
|
+
var sum: u32 = 0;
|
|
168
|
+
for (bytes) |byte| sum += byte;
|
|
169
|
+
return sum;
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Review questions:
|
|
174
|
+
- Can a raw pointer API become a slice API?
|
|
175
|
+
- Is nullability modeled with `?T` instead of sentinel values?
|
|
176
|
+
- Are pointer lifetimes clear after returning from a function?
|
|
177
|
+
|
|
178
|
+
### Avoid Returning Pointers to Stack Data
|
|
179
|
+
|
|
180
|
+
Review returned slices and pointers carefully. Zig makes many lifetime issues visible, but reviewers should still check that returned data outlives the function.
|
|
181
|
+
|
|
182
|
+
```zig
|
|
183
|
+
// ❌ Bad: returned slice points to stack memory.
|
|
184
|
+
fn labelStack() []const u8 {
|
|
185
|
+
var buf: [16]u8 = undefined;
|
|
186
|
+
_ = &buf;
|
|
187
|
+
return buf[0..];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ✅ Good: caller owns the allocated result and can free it.
|
|
191
|
+
fn label(allocator: std.mem.Allocator) ![]u8 {
|
|
192
|
+
return try allocator.dupe(u8, "ready");
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Review questions:
|
|
197
|
+
- Does returned memory come from the caller, allocator, static storage, or a stable owner?
|
|
198
|
+
- Does a slice escape after its backing buffer is mutated or freed?
|
|
199
|
+
- Is aliasing intentional and documented for mutable slices?
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Comptime & Generics
|
|
204
|
+
|
|
205
|
+
### Keep Comptime Work Bounded and Readable
|
|
206
|
+
|
|
207
|
+
`comptime` is powerful, but complex compile-time code can make error messages and build times worse. Prefer small generic helpers with clear type contracts.
|
|
208
|
+
|
|
209
|
+
```zig
|
|
210
|
+
fn RingBuffer(comptime T: type, comptime capacity: usize) type {
|
|
211
|
+
// ✅ Good: invalid generic parameters fail with an actionable message.
|
|
212
|
+
if (capacity == 0) @compileError("capacity must be greater than zero");
|
|
213
|
+
|
|
214
|
+
return struct {
|
|
215
|
+
items: [capacity]T = undefined,
|
|
216
|
+
len: usize = 0,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Review questions:
|
|
222
|
+
- Does `comptime` enforce a real invariant?
|
|
223
|
+
- Are compile errors explicit and actionable?
|
|
224
|
+
- Is reflection code isolated from ordinary runtime logic?
|
|
225
|
+
|
|
226
|
+
### Avoid Overly Broad `anytype`
|
|
227
|
+
|
|
228
|
+
`anytype` can make APIs flexible, but it can also hide required capabilities. Add comptime checks or prefer concrete interfaces when possible.
|
|
229
|
+
|
|
230
|
+
```zig
|
|
231
|
+
// ✅ Good: the required writer capability is obvious at the call site.
|
|
232
|
+
fn writeAll(writer: anytype, bytes: []const u8) !void {
|
|
233
|
+
try writer.writeAll(bytes);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Review questions:
|
|
238
|
+
- Is the required shape of `anytype` clear from the function body or docs?
|
|
239
|
+
- Would a concrete type or smaller helper be easier to review?
|
|
240
|
+
- Are compile errors understandable when the wrong type is passed?
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Safety, Undefined Behavior & Casts
|
|
245
|
+
|
|
246
|
+
### Treat `undefined`, `unreachable`, and Casts as Review Hotspots
|
|
247
|
+
|
|
248
|
+
Zig exposes low-level control directly. Review every `undefined`, `unreachable`, `@ptrCast`, `@alignCast`, `@intCast`, and pointer/int conversion.
|
|
249
|
+
|
|
250
|
+
```zig
|
|
251
|
+
// ❌ Bad: assumes data layout, byte order, length, and alignment without proof.
|
|
252
|
+
const header: *const Header = @ptrCast(@alignCast(bytes.ptr));
|
|
253
|
+
|
|
254
|
+
// ✅ Good: parse fields explicitly and check length before reading.
|
|
255
|
+
if (bytes.len < 4) return error.ShortInput;
|
|
256
|
+
const magic = std.mem.readInt(u16, bytes[0..2], .little);
|
|
257
|
+
const flags = std.mem.readInt(u16, bytes[2..4], .little);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Review questions:
|
|
261
|
+
- Is `undefined` overwritten before being read?
|
|
262
|
+
- Is `unreachable` only used for impossible states, with a nearby explanation when non-obvious?
|
|
263
|
+
- Are casts preceded by checks for layout, range, alignment, size, byte order, and nullability?
|
|
264
|
+
|
|
265
|
+
### Prefer Checked Arithmetic Unless Wrapping Is Intentional
|
|
266
|
+
|
|
267
|
+
Wrapping operators such as `+%` and `-%` are useful, but they should communicate a deliberate modular arithmetic choice.
|
|
268
|
+
|
|
269
|
+
```zig
|
|
270
|
+
// ❌ Bad: wrapping silences overflow that should expose a logic bug.
|
|
271
|
+
index = index +% 1;
|
|
272
|
+
|
|
273
|
+
// ✅ Good: checked arithmetic traps on unexpected overflow.
|
|
274
|
+
sum += byte;
|
|
275
|
+
|
|
276
|
+
// ✅ Good: wrapping is intentional for modular hash behavior.
|
|
277
|
+
hash = hash *% 16777619;
|
|
278
|
+
hash = hash +% byte;
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Review questions:
|
|
282
|
+
- Is wrapping arithmetic required by an algorithm?
|
|
283
|
+
- Would overflow indicate invalid input or a bug?
|
|
284
|
+
- Are integer width changes explicit and tested around boundaries?
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## C Interop
|
|
289
|
+
|
|
290
|
+
### Contain C Boundaries
|
|
291
|
+
|
|
292
|
+
Keep `@cImport`, C pointer handling, and ABI assumptions close to a wrapper layer. Convert C data into Zig types before it spreads through the codebase.
|
|
293
|
+
|
|
294
|
+
```zig
|
|
295
|
+
const std = @import("std");
|
|
296
|
+
|
|
297
|
+
// ❌ Bad: uses C strlen when no external C boundary is needed.
|
|
298
|
+
fn strlenC(input: [*:0]const u8) usize {
|
|
299
|
+
const c = @cImport({
|
|
300
|
+
@cInclude("string.h");
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
return c.strlen(input);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ✅ Good: use Zig's sentinel-aware standard library helper.
|
|
307
|
+
fn strlenZ(input: [*:0]const u8) usize {
|
|
308
|
+
return std.mem.len(input);
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Review questions:
|
|
313
|
+
- Are C pointers represented with the correct Zig pointer type?
|
|
314
|
+
- Are sentinel-terminated strings modeled as sentinel pointers or slices?
|
|
315
|
+
- Are ownership and cleanup rules from the C library documented?
|
|
316
|
+
- Are C error codes converted into Zig error unions near the boundary?
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Testing
|
|
321
|
+
|
|
322
|
+
### Use `std.testing` Assertions and Leak Detection
|
|
323
|
+
|
|
324
|
+
Tests that allocate should use `std.testing.allocator` where practical so leaks are reported by the test runner.
|
|
325
|
+
|
|
326
|
+
```zig
|
|
327
|
+
const std = @import("std");
|
|
328
|
+
|
|
329
|
+
test "collect returns owned memory on success" {
|
|
330
|
+
const allocator = std.testing.allocator;
|
|
331
|
+
const names = try collect(allocator);
|
|
332
|
+
defer allocator.free(names);
|
|
333
|
+
|
|
334
|
+
try std.testing.expectEqual(@as(usize, 2), names.len);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
test "collect handles allocation failures cleanly" {
|
|
338
|
+
var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{
|
|
339
|
+
.fail_index = 0,
|
|
340
|
+
});
|
|
341
|
+
try std.testing.expectError(error.OutOfMemory, collect(failing.allocator()));
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Review questions:
|
|
346
|
+
- Are allocation-heavy paths covered by tests?
|
|
347
|
+
- Are error paths tested with `std.testing.expectError`?
|
|
348
|
+
- Do tests cover boundary sizes such as empty input, one element, max capacity, and invalid encodings?
|
|
349
|
+
|
|
350
|
+
### Test Build Modes and Targets When Relevant
|
|
351
|
+
|
|
352
|
+
Behavior can differ across safety modes, targets, and ABIs. For low-level code, ask whether the PR was tested with the intended target and optimization mode.
|
|
353
|
+
|
|
354
|
+
Review questions:
|
|
355
|
+
- Does code rely on debug-only safety checks?
|
|
356
|
+
- Does packed/aligned/extern layout code have target-aware tests?
|
|
357
|
+
- Are endian, pointer-width, and ABI assumptions tested or documented?
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Style & API Design
|
|
362
|
+
|
|
363
|
+
### Follow Zig Naming Conventions
|
|
364
|
+
|
|
365
|
+
Use the official style guide as the baseline: `TitleCase` for types, `camelCase` for functions, and `snake_case` for variables. Avoid redundant words such as `Value`, `Data`, `Manager`, or `State` when the surrounding namespace already provides that meaning.
|
|
366
|
+
|
|
367
|
+
```zig
|
|
368
|
+
// ❌ Bad: redundant namespace and vague type name.
|
|
369
|
+
pub const json_bad = struct {
|
|
370
|
+
pub const JsonValueManager = struct {};
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// ✅ Good: name is meaningful in its fully-qualified namespace.
|
|
374
|
+
pub const json = struct {
|
|
375
|
+
pub const Value = union(enum) {};
|
|
376
|
+
};
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Review questions:
|
|
380
|
+
- Does the fully-qualified name read naturally?
|
|
381
|
+
- Are file and directory names consistent with the style guide?
|
|
382
|
+
- Are underscore-prefixed declarations avoided unless they come from an external convention?
|
|
383
|
+
- Are public APIs documented with doc comments where helpful?
|
|
384
|
+
|
|
385
|
+
### Keep Public APIs Small
|
|
386
|
+
|
|
387
|
+
Zig modules often expose declarations directly from files and structs. Review public declarations for accidental exports.
|
|
388
|
+
|
|
389
|
+
Review questions:
|
|
390
|
+
- Should this declaration be `pub`?
|
|
391
|
+
- Is the public API stable enough to expose?
|
|
392
|
+
- Are implementation details hidden behind a smaller surface?
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Review Checklist
|
|
397
|
+
|
|
398
|
+
### Memory & Lifetime
|
|
399
|
+
- [ ] Allocator ownership is explicit.
|
|
400
|
+
- [ ] Allocations have matching `free`, `deinit`, `defer`, or `errdefer`.
|
|
401
|
+
- [ ] Returned slices and pointers outlive the function.
|
|
402
|
+
- [ ] Arena or temporary allocations have a clear lifetime boundary.
|
|
403
|
+
|
|
404
|
+
### Errors & Cleanup
|
|
405
|
+
- [ ] Expected failures use specific error sets where practical.
|
|
406
|
+
- [ ] `catch unreachable` does not hide real runtime failures.
|
|
407
|
+
- [ ] Partial initialization is rolled back with `errdefer`.
|
|
408
|
+
- [ ] Error conversions happen at abstraction boundaries.
|
|
409
|
+
|
|
410
|
+
### Pointers & Safety
|
|
411
|
+
- [ ] Raw pointers are justified; slices are used for ordinary buffers.
|
|
412
|
+
- [ ] Casts check size, range, alignment, and nullability.
|
|
413
|
+
- [ ] `undefined` is not read before initialization.
|
|
414
|
+
- [ ] Wrapping arithmetic is intentional and tested.
|
|
415
|
+
|
|
416
|
+
### Comptime & API Design
|
|
417
|
+
- [ ] `comptime` logic enforces useful invariants.
|
|
418
|
+
- [ ] `anytype` usage has clear expectations.
|
|
419
|
+
- [ ] Public declarations are intentional.
|
|
420
|
+
- [ ] Names follow Zig style conventions.
|
|
421
|
+
|
|
422
|
+
### C Interop & Portability
|
|
423
|
+
- [ ] C boundaries are isolated behind wrappers.
|
|
424
|
+
- [ ] C ownership and cleanup rules are documented.
|
|
425
|
+
- [ ] Target, endian, pointer-width, and ABI assumptions are tested or documented.
|
|
426
|
+
|
|
427
|
+
### Tests
|
|
428
|
+
- [ ] Tests use `std.testing.allocator` for allocation-heavy code.
|
|
429
|
+
- [ ] Error paths use `std.testing.expectError`.
|
|
430
|
+
- [ ] Boundary cases are covered.
|
|
431
|
+
- [ ] Relevant build modes and targets are considered.
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## References
|
|
436
|
+
|
|
437
|
+
- [Zig 0.16.0 Language Reference](https://ziglang.org/documentation/0.16.0/)
|
|
438
|
+
- [Zig 0.16.0 Standard Library documentation](https://ziglang.org/documentation/0.16.0/std/)
|
|
439
|
+
- [Zig 0.16.0 Style Guide](https://ziglang.org/documentation/0.16.0/#Style-Guide)
|
|
440
|
+
- [Choosing an Allocator](https://ziglang.org/documentation/0.16.0/#Choosing-an-Allocator)
|