about things
0
fork

Configure Feed

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

add zig fetch --save, stream.socket.handle, TLS, epoll notes

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

+146 -32
+146 -32
languages/ziglang/0.16/migration.md
··· 1 1 # 0.16 migration notes 2 2 3 - verified with `zig-aarch64-macos-0.16.0-dev.2296+fd3657bf8` 3 + verified with `zig-aarch64-macos-0.16.0-dev.3059+42e33db9d` 4 4 5 5 ## high-impact changes 6 6 7 - - **std.net removed** - networking now via `Io.net` 8 - - **std.crypto.random removed** - randomness now via `io.random()` 9 - - **std.Thread.Pool removed** - use `Io.Group` with `Io.Threaded` 10 - - **posix.shutdown removed** - use `std.c.shutdown(fd, how)` 11 - - **posix.getrandom removed** - use `io.random()` 7 + - **std.net removed** — networking now via `Io.net` 8 + - **std.crypto.random removed** — randomness now via `io.random()` 9 + - **std.Thread.Pool removed** — thread-per-connection (`Thread.spawn` + `.detach()`) 10 + - **std.Thread.Mutex removed** — `Io.Mutex` (requires `io` param for lock/unlock) 11 + - **std.Thread.sleep removed** — `io.sleep(.{ .nanoseconds = N }, .awake) catch {}` 12 + - **std.time.timestamp/milliTimestamp removed** — `Io.Timestamp.now(io, .real)` 13 + - **posix.shutdown removed** — use `std.c.shutdown(fd, how)` 14 + - **posix.getenv removed** — use `std.c.getenv` + `std.mem.span()` (no Io equivalent) 15 + - **posix.getrandom removed** — use `io.random()` 16 + - **posix.exit removed** — use `std.process.exit()` 17 + - **GeneralPurposeAllocator removed** — `std.heap.DebugAllocator(.{}).init` (tests) or `smp_allocator` (prod) 18 + 19 + **rule of thumb**: use Io-based APIs. only fall back to `std.c.*` when no Io equivalent exists (just `getenv` and `shutdown` so far). 12 20 13 21 these require significant refactoring as they move to the Io-based paradigm. 14 22 ··· 33 41 }); 34 42 ``` 35 43 36 - ## package hashes 44 + ## package management 45 + 46 + 0.16 calculates hashes differently. use `zig fetch --save` to update deps — it writes the URL and correct hash directly into `build.zig.zon`: 47 + 48 + ```bash 49 + # add or update a dependency 50 + zig fetch --save=websocket "https://github.com/user/repo/archive/abc1234.tar.gz" 51 + 52 + # overwrites the existing entry if the name already exists 53 + ``` 37 54 38 - 0.16 calculates hashes differently. compiler will tell you the correct hash. 55 + no need for placeholder hashes or manual hash computation. 39 56 40 57 ## removed APIs 41 58 42 59 ### std.time.timestamp() / milliTimestamp() 43 60 44 - use libc directly: 61 + use `Io.Timestamp.now()`: 45 62 46 63 ```zig 47 - const c = std.c; 64 + const Io = std.Io; 48 65 49 - pub fn timestamp() i64 { 50 - var tv: c.timeval = undefined; 51 - _ = c.gettimeofday(&tv, null); 52 - return tv.sec; 66 + fn timestamp(io: Io) i64 { 67 + return @intCast(@divFloor(Io.Timestamp.now(io, .real).nanoseconds, std.time.ns_per_s)); 53 68 } 54 69 55 - pub fn milliTimestamp() i64 { 56 - var tv: c.timeval = undefined; 57 - _ = c.gettimeofday(&tv, null); 58 - return @as(i64, tv.sec) * 1000 + @divTrunc(@as(i64, tv.usec), 1000); 70 + fn milliTimestamp(io: Io) i64 { 71 + return @intCast(@divFloor(Io.Timestamp.now(io, .real).nanoseconds, std.time.ns_per_ms)); 59 72 } 73 + 74 + // if you don't have io in scope: 75 + const io = std.Options.debug_io; 76 + const now = milliTimestamp(io); 60 77 ``` 61 78 62 79 ### std.Thread.sleep() 63 80 64 - use libc nanosleep: 81 + use `io.sleep()`: 65 82 66 83 ```zig 67 - pub fn sleep(ns: u64) void { 68 - const secs = ns / std.time.ns_per_s; 69 - const nsecs = ns % std.time.ns_per_s; 70 - var ts: std.c.timespec = .{ 71 - .sec = @intCast(secs), 72 - .nsec = @intCast(nsecs), 73 - }; 74 - _ = std.c.nanosleep(&ts, null); 75 - } 84 + // 0.15 85 + std.Thread.sleep(3 * std.time.ns_per_s); 86 + 87 + // 0.16 88 + io.sleep(.{ .nanoseconds = 3 * std.time.ns_per_s }, .awake) catch {}; 89 + // .awake = monotonic clock (excludes suspend), .real = wall clock 90 + // returns Cancelable!void — catch {} for fire-and-forget 91 + ``` 92 + 93 + ### std.Thread.Mutex 94 + 95 + replaced by `Io.Mutex` (requires `io` parameter): 96 + 97 + ```zig 98 + // 0.15 99 + var mutex: std.Thread.Mutex = .{}; 100 + mutex.lock(); 101 + defer mutex.unlock(); 102 + 103 + // 0.16 104 + var mutex: std.Io.Mutex = std.Io.Mutex.init; 105 + mutex.lockUncancelable(io); 106 + defer mutex.unlock(io); 76 107 ``` 77 108 78 109 ### std.posix.getenv() ··· 100 131 // or @Struct(...) for non-tuples 101 132 ``` 102 133 134 + ### posix.Sigaction signal handler type 135 + 136 + handler parameter changed from `c_int` to `posix.SIG` (enum) on **all platforms** including macOS. 137 + builds with `c_int` on macOS but fails on Linux — cross-compilation trap. 138 + 139 + ```zig 140 + // 0.15 141 + fn handleSigterm(_: c_int) callconv(.c) void { ... } 142 + 143 + // 0.16 144 + fn handleSigterm(_: posix.SIG) callconv(.c) void { ... } 145 + ``` 146 + 103 147 ### posix.shutdown 104 148 105 149 use libc directly: ··· 124 168 try std.testing.expectEqual(expected, actual); 125 169 ``` 126 170 171 + ### net.Stream.handle → net.Stream.socket.handle 172 + 173 + ```zig 174 + // 0.15 175 + const fd = stream.handle; 176 + 177 + // 0.16 178 + const fd = stream.socket.handle; 179 + ``` 180 + 181 + ### TLS client options 182 + 183 + `tls.Client.Options` changed significantly: 184 + 185 + ```zig 186 + // 0.15 187 + .ca = .{ .bundle = bundle }, 188 + .realtime_now_seconds = seconds, 189 + 190 + // 0.16 - bundle variant requires gpa, io, lock, and pointer 191 + .ca = .{ .bundle = .{ .gpa = allocator, .io = io, .lock = rwlock_ptr, .bundle = bundle_ptr } }, 192 + .realtime_now = Io.Timestamp.now(io, .real), 193 + ``` 194 + 195 + ### Certificate.Bundle initialization 196 + 197 + ```zig 198 + // 0.15 — fields had defaults 199 + var b = Bundle{}; 200 + 201 + // 0.16 — no defaults on Linux, must initialize explicitly 202 + var b: Bundle = .{ .map = .empty, .bytes = .empty }; 203 + ``` 204 + 205 + ### Linux epoll_create1 return type 206 + 207 + `linux.epoll_create1` returns `usize` (raw syscall), but `linux.epoll_ctl` and `linux.epoll_wait` take `epoll_fd: i32`. cast at init: 208 + 209 + ```zig 210 + const q_raw = linux.epoll_create1(0); 211 + const q: i32 = std.math.cast(i32, q_raw) orelse return error.EpollError; 212 + ``` 213 + 127 214 ## networking 128 215 129 216 `std.net` is gone. use `Io.net`: ··· 157 244 const addr = std.net.Address.parseIp("127.0.0.1", 8080); 158 245 159 246 // 0.16 160 - const addr = Io.net.IpAddress.parse("127.0.0.1", 8080); 247 + var addr = try net.IpAddress.parse("::", port); // "::" for all interfaces 248 + var server = try net.IpAddress.listen(&addr, io, .{ .reuse_address = true }); 249 + defer server.deinit(io); 250 + ``` 251 + 252 + ### TCP server + HTTP (thread-per-connection) 253 + 254 + ```zig 255 + // accept loop — replaces Thread.Pool 256 + while (true) { 257 + const stream = server.accept(io) catch |err| { log.err(...); continue; }; 258 + const t = std.Thread.spawn(.{}, handleConnection, .{ stream, io }) catch |err| { 259 + stream.close(io); 260 + continue; 261 + }; 262 + t.detach(); 263 + } 264 + 265 + // handler — Stream → Reader/Writer → http.Server 266 + fn handleConnection(stream: net.Stream, io: Io) void { 267 + defer stream.close(io); 268 + var read_buf: [8192]u8 = undefined; 269 + var write_buf: [8192]u8 = undefined; 270 + var reader = net.Stream.Reader.init(stream, io, &read_buf); 271 + var writer = net.Stream.Writer.init(stream, io, &write_buf); 272 + var srv = std.http.Server.init(&reader.interface, &writer.interface); 273 + // ... handle requests ... 274 + } 161 275 ``` 162 276 163 277 ## randomness ··· 169 283 var bytes: [16]u8 = undefined; 170 284 std.crypto.random.bytes(&bytes); 171 285 172 - // 0.16 - io.random() returns typed value directly 286 + // 0.16 - io.random() fills a buffer 173 287 const io = std.Options.debug_io; 174 - const bytes: [16]u8 = io.random(); // returns [16]u8 directly 175 - const seed: u64 = io.random(); // returns u64 directly 288 + var bytes: [16]u8 = undefined; 289 + io.random(&bytes); // fills buffer in-place 176 290 ``` 177 291 178 292 ## file I/O