about things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

zig 0.15: add ring buffer pattern, comptime string validation

- concurrency.md: ring buffer for metrics (fixed array, head pointer, percentiles)
- comptime.md: SQL placeholder validation pattern

from leaflet-search learnings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

zzstoatzz 53f42752 8d3cee01

+84 -2
+4 -2
languages/ziglang/0.15/README.md
··· 16 16 - [arraylist](./arraylist.md) - ownership patterns (toOwnedSlice vs deinit) 17 17 - [io](./io.md) - explicit buffers, http client/server, tls quirk 18 18 - [build](./build.md) - createModule + imports, hash trick 19 - - [comptime](./comptime.md) - type generation, tuple synthesis, validation 20 - - [concurrency](./concurrency.md) - atomics vs mutex, callback pattern 19 + - [comptime](./comptime.md) - type generation, tuple synthesis, string validation 20 + - [concurrency](./concurrency.md) - atomics vs mutex, callback pattern, ring buffers 21 21 - [crypto](./crypto.md) - ecdsa paths, signature verification 22 + - [database](./database.md) - zqlite, connection patterns, transactions 23 + - [interfaces](./interfaces.md) - comptime duck typing, type-returning functions, vtables 22 24 - [testing](./testing.md) - zig test vs build test, arena for leaky apis
+35
languages/ziglang/0.15/comptime.md
··· 75 75 76 76 see: [zql/src/parse.zig#L48](https://tangled.sh/@zzstoatzz.io/zql/tree/main/src/parse.zig#L48) 77 77 78 + ## simple string validation 79 + 80 + count occurrences in a comptime string and compare to something else. useful for SQL placeholder validation: 81 + 82 + ```zig 83 + fn validateArgs(comptime sql: []const u8, comptime ArgsType: type) void { 84 + const expected = countPlaceholders(sql); 85 + const provided = @typeInfo(ArgsType).@"struct".fields.len; 86 + if (expected != provided) { 87 + @compileError(std.fmt.comptimePrint( 88 + "SQL has {} placeholders but {} args provided", 89 + .{ expected, provided }, 90 + )); 91 + } 92 + } 93 + 94 + fn countPlaceholders(comptime sql: []const u8) usize { 95 + var count: usize = 0; 96 + for (sql) |c| { 97 + if (c == '?') count += 1; 98 + } 99 + return count; 100 + } 101 + 102 + // usage - compile error if mismatch 103 + pub fn query(self: *Client, comptime sql: []const u8, args: anytype) !Result { 104 + comptime validateArgs(sql, @TypeOf(args)); 105 + // ... 106 + } 107 + ``` 108 + 109 + the key: `comptime` on the sql parameter means the string is known at compile time, so you can iterate it and count characters. `@TypeOf(args)` gets the tuple type, and you can inspect its fields. 110 + 111 + see: [leaflet-search/db/Client.zig](https://tangled.sh/@zzstoatzz.io/leaflet-search/tree/main/backend/src/db/Client.zig) 112 + 78 113 ## constraints 79 114 80 115 a few things to know:
+45
languages/ziglang/0.15/concurrency.md
··· 73 73 ``` 74 74 75 75 starts at 1 second, doubles each failure, caps at 60 seconds. simple and effective. 76 + 77 + ## ring buffer for metrics 78 + 79 + when tracking recent activity (request latencies, event counts), use a fixed-size circular buffer: 80 + 81 + ```zig 82 + const SAMPLE_COUNT = 1000; 83 + 84 + const LatencyBuffer = struct { 85 + samples: [SAMPLE_COUNT]u32 = .{0} ** SAMPLE_COUNT, 86 + count: usize = 0, 87 + head: usize = 0, 88 + 89 + fn record(self: *LatencyBuffer, value: u32) void { 90 + self.samples[self.head] = value; 91 + self.head = (self.head + 1) % SAMPLE_COUNT; 92 + if (self.count < SAMPLE_COUNT) self.count += 1; 93 + } 94 + }; 95 + 96 + var buffer: LatencyBuffer = .{}; 97 + var mutex: std.Thread.Mutex = .{}; 98 + 99 + pub fn record(value: u32) void { 100 + mutex.lock(); 101 + defer mutex.unlock(); 102 + buffer.record(value); 103 + } 104 + ``` 105 + 106 + for percentiles, copy and sort: 107 + 108 + ```zig 109 + pub fn getP95(self: *const LatencyBuffer) u32 { 110 + if (self.count == 0) return 0; 111 + var sorted: [SAMPLE_COUNT]u32 = undefined; 112 + @memcpy(sorted[0..self.count], self.samples[0..self.count]); 113 + std.mem.sort(u32, sorted[0..self.count], {}, std.sort.asc(u32)); 114 + return sorted[(self.count * 95) / 100]; 115 + } 116 + ``` 117 + 118 + this pattern works for ephemeral stats that reset on restart. for persistent counters, use the database. 119 + 120 + see: [leaflet-search/timing.zig](https://tangled.sh/@zzstoatzz.io/leaflet-search/tree/main/backend/src/timing.zig)