authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-06-04 19:36:42 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-06-04 19:36:42 -07:00
log52205ca7e4c322e29d40767553027f973830bfcf
tree716a7848e09bee289802d3de8655136e2258ae44
parentb50692b29e80b28ca7672530143ebf7ac7387f98
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

update to zig 0.16.0


4 files changed, 40 insertions(+), 37 deletions(-)

README.md+1-1
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3![loc](https://sloc.xyz/github/nektro/zig-whatwg-url)3![loc](https://sloc.xyz/github/nektro/zig-whatwg-url)
4[![license](https://img.shields.io/github/license/nektro/zig-whatwg-url.svg)](https://github.com/nektro/zig-whatwg-url/blob/master/LICENSE)4[![license](https://img.shields.io/github/license/nektro/zig-whatwg-url.svg)](https://github.com/nektro/zig-whatwg-url/blob/master/LICENSE)
5[![nektro @ github sponsors](https://img.shields.io/badge/sponsors-nektro-purple?logo=github)](https://github.com/sponsors/nektro)5[![nektro @ github sponsors](https://img.shields.io/badge/sponsors-nektro-purple?logo=github)](https://github.com/sponsors/nektro)
6[![Zig](https://img.shields.io/badge/Zig-0.15-f7a41d)](https://ziglang.org/)6[![Zig](https://img.shields.io/badge/Zig-0.16-f7a41d)](https://ziglang.org/)
7[![Zigmod](https://img.shields.io/badge/Zigmod-latest-f7a41d)](https://github.com/nektro/zigmod)7[![Zigmod](https://img.shields.io/badge/Zigmod-latest-f7a41d)](https://github.com/nektro/zigmod)
88
9A spec-compliant Zig implementation of WHATWG URL.9A spec-compliant Zig implementation of WHATWG URL.
build.zig+1
...@@ -22,6 +22,7 @@ pub fn build(b: *std.Build) void {...@@ -22,6 +22,7 @@ pub fn build(b: *std.Build) void {
22 }),22 }),
23 });23 });
24 deps.addAllTo(tests);24 deps.addAllTo(tests);
25 tests.root_module.link_libc = true;
25 tests.use_llvm = !disable_llvm;26 tests.use_llvm = !disable_llvm;
26 tests.use_lld = !disable_llvm;27 tests.use_lld = !disable_llvm;
27 b.getInstallStep().dependOn(&tests.step);28 b.getInstallStep().dependOn(&tests.step);
url.zig+37-36
...@@ -2,6 +2,7 @@ const std = @import("std");...@@ -2,6 +2,7 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const extras = @import("extras");3const extras = @import("extras");
4const unicode_idna = @import("unicode-idna");4const unicode_idna = @import("unicode-idna");
5const nio = @import("nio");
56
6pub const URL = struct {7pub const URL = struct {
7 href: []const u8,8 href: []const u8,
...@@ -47,13 +48,13 @@ pub const URL = struct {...@@ -47,13 +48,13 @@ pub const URL = struct {
47 // input is a scalar value string48 // input is a scalar value string
48 if (!std.unicode.utf8ValidateSlice(input)) return error.InvalidURL;49 if (!std.unicode.utf8ValidateSlice(input)) return error.InvalidURL;
4950
50 var inputl = std.array_list.Managed(u8).init(alloc);51 var inputl = nio.AllocatingWriter.init(alloc);
51 defer inputl.deinit();52 defer inputl.deinit();
52 try inputl.appendSlice(input);53 try inputl.writeAll(input);
5354
54 // 1.55 // 1.
55 while (inputl.items.len > 0 and is_c0control_or_space(inputl.items[0])) _ = inputl.orderedRemove(0);56 while (inputl.items.len > 0 and is_c0control_or_space(inputl.items[0])) _ = inputl.orderedRemove(0);
56 while (inputl.items.len > 0 and is_c0control_or_space(inputl.getLast())) inputl.items.len -= 1;57 while (inputl.items.len > 0 and is_c0control_or_space(inputl.last())) inputl.items.len -= 1;
5758
58 // 3.59 // 3.
59 while (std.mem.indexOfScalar(u8, inputl.items, '\t')) |i| _ = inputl.orderedRemove(i);60 while (std.mem.indexOfScalar(u8, inputl.items, '\t')) |i| _ = inputl.orderedRemove(i);
...@@ -70,7 +71,7 @@ pub const URL = struct {...@@ -70,7 +71,7 @@ pub const URL = struct {
70 // we always do utf-871 // we always do utf-8
7172
72 // 6.73 // 6.
73 var buffer = std.array_list.Managed(u8).init(alloc);74 var buffer = nio.AllocatingWriter.init(alloc);
74 defer buffer.deinit();75 defer buffer.deinit();
7576
76 // 7.77 // 7.
...@@ -118,7 +119,7 @@ pub const URL = struct {...@@ -118,7 +119,7 @@ pub const URL = struct {
118 std.debug.assert(pointer == 0);119 std.debug.assert(pointer == 0);
119 // 1. If c is an ASCII alpha, append c, lowercased, to buffer, and set state to scheme state.120 // 1. If c is an ASCII alpha, append c, lowercased, to buffer, and set state to scheme state.
120 if (i < length and std.ascii.isAlphabetic(c)) {121 if (i < length and std.ascii.isAlphabetic(c)) {
121 try buffer.append(std.ascii.toLower(c));122 try buffer.writeAll(&.{std.ascii.toLower(c)});
122 state = .scheme;123 state = .scheme;
123 }124 }
124 // 2. Otherwise, if state override is not given, set state to no scheme state and decrease pointer by 1.125 // 2. Otherwise, if state override is not given, set state to no scheme state and decrease pointer by 1.
...@@ -134,7 +135,7 @@ pub const URL = struct {...@@ -134,7 +135,7 @@ pub const URL = struct {
134 .scheme => {135 .scheme => {
135 // 1. If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), append c, lowercased, to buffer.136 // 1. If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), append c, lowercased, to buffer.
136 if (std.ascii.isAlphanumeric(c) or c == '+' or c == '-' or c == '.') {137 if (std.ascii.isAlphanumeric(c) or c == '+' or c == '-' or c == '.') {
137 try buffer.append(std.ascii.toLower(c));138 try buffer.writeAll(&.{std.ascii.toLower(c)});
138 }139 }
139 // 2. Otherwise, if c is U+003A (:), then:140 // 2. Otherwise, if c is U+003A (:), then:
140 else if (c == ':') {141 else if (c == ':') {
...@@ -156,7 +157,7 @@ pub const URL = struct {...@@ -156,7 +157,7 @@ pub const URL = struct {
156 // 2. Return.157 // 2. Return.
157 }158 }
158 // 4. Set buffer to the empty string.159 // 4. Set buffer to the empty string.
159 buffer.clearRetainingCapacity();160 buffer.items.len = 0;
160 // 5. If url’s scheme is "file", then:161 // 5. If url’s scheme is "file", then:
161 if (std.mem.eql(u8, href.items(0), "file")) {162 if (std.mem.eql(u8, href.items(0), "file")) {
162 // 1. If remaining does not start with "//", special-scheme-missing-following-solidus validation error.163 // 1. If remaining does not start with "//", special-scheme-missing-following-solidus validation error.
...@@ -192,7 +193,7 @@ pub const URL = struct {...@@ -192,7 +193,7 @@ pub const URL = struct {
192 }193 }
193 // 3. Otherwise, if state override is not given, set buffer to the empty string, state to no scheme state, and start over (from the first code point in input).194 // 3. Otherwise, if state override is not given, set buffer to the empty string, state to no scheme state, and start over (from the first code point in input).
194 else if (state_override == null) {195 else if (state_override == null) {
195 buffer.clearRetainingCapacity();196 buffer.items.len = 0;
196 state = .no_scheme;197 state = .no_scheme;
197 pointer = 0;198 pointer = 0;
198 i = 0;199 i = 0;
...@@ -380,7 +381,7 @@ pub const URL = struct {...@@ -380,7 +381,7 @@ pub const URL = struct {
380 // 1. Invalid-credentials validation error.381 // 1. Invalid-credentials validation error.
381 {}382 {}
382 // 2. If atSignSeen is true, then prepend "%40" to buffer.383 // 2. If atSignSeen is true, then prepend "%40" to buffer.
383 if (atSignSeen) try buffer.insertSlice(0, "%40");384 if (atSignSeen) try buffer.insertAt(0, "%40");
384 // 3. Set atSignSeen to true.385 // 3. Set atSignSeen to true.
385 atSignSeen = true;386 atSignSeen = true;
386 // 4. For each codePoint in buffer:387 // 4. For each codePoint in buffer:
...@@ -401,7 +402,7 @@ pub const URL = struct {...@@ -401,7 +402,7 @@ pub const URL = struct {
401 }402 }
402 }403 }
403 // 5. Set buffer to the empty string.404 // 5. Set buffer to the empty string.
404 buffer.clearRetainingCapacity();405 buffer.items.len = 0;
405 }406 }
406 // 2. Otherwise, if one of the following is true:407 // 2. Otherwise, if one of the following is true:
407 // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)408 // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
...@@ -416,12 +417,12 @@ pub const URL = struct {...@@ -416,12 +417,12 @@ pub const URL = struct {
416 i = lastcpi(inputl.items[0..i]);417 i = lastcpi(inputl.items[0..i]);
417 c = inputl.items[i];418 c = inputl.items[i];
418 }419 }
419 buffer.clearRetainingCapacity();420 buffer.items.len = 0;
420 state = .host;421 state = .host;
421 }422 }
422 // 3. Otherwise, append c to buffer.423 // 3. Otherwise, append c to buffer.
423 else {424 else {
424 try buffer.appendSlice(inputl.items[i..][0..l(c)]);425 try buffer.writeAll(inputl.items[i..][0..l(c)]);
425 }426 }
426 },427 },
427 .host, .hostname => {428 .host, .hostname => {
...@@ -445,7 +446,7 @@ pub const URL = struct {...@@ -445,7 +446,7 @@ pub const URL = struct {
445 // 5. Set url’s host to host, buffer to the empty string, and state to port state.446 // 5. Set url’s host to host, buffer to the empty string, and state to port state.
446 try setHost(&href, h);447 try setHost(&href, h);
447 hostname_kind = h;448 hostname_kind = h;
448 buffer.clearRetainingCapacity();449 buffer.items.len = 0;
449 state = .port;450 state = .port;
450 }451 }
451 // 3. Otherwise, if one of the following is true:452 // 3. Otherwise, if one of the following is true:
...@@ -467,7 +468,7 @@ pub const URL = struct {...@@ -467,7 +468,7 @@ pub const URL = struct {
467 // 5. Set url’s host to host, buffer to the empty string, and state to path start state.468 // 5. Set url’s host to host, buffer to the empty string, and state to path start state.
468 try setHost(&href, h);469 try setHost(&href, h);
469 hostname_kind = h;470 hostname_kind = h;
470 buffer.clearRetainingCapacity();471 buffer.items.len = 0;
471 state = .path_start;472 state = .path_start;
472 // 6. If state override is given, then return.473 // 6. If state override is given, then return.
473 if (state_override != null) break;474 if (state_override != null) break;
...@@ -479,13 +480,13 @@ pub const URL = struct {...@@ -479,13 +480,13 @@ pub const URL = struct {
479 // 2. If c is U+005D (]), then set insideBrackets to false.480 // 2. If c is U+005D (]), then set insideBrackets to false.
480 if (c == ']') insideBrackets = false;481 if (c == ']') insideBrackets = false;
481 // 3. Append c to buffer.482 // 3. Append c to buffer.
482 try buffer.appendSlice(inputl.items[i..][0..l(c)]);483 try buffer.writeAll(inputl.items[i..][0..l(c)]);
483 }484 }
484 },485 },
485 .port => {486 .port => {
486 // 1. If c is an ASCII digit, append c to buffer.487 // 1. If c is an ASCII digit, append c to buffer.
487 if (std.ascii.isDigit(c)) {488 if (std.ascii.isDigit(c)) {
488 try buffer.appendSlice(inputl.items[i..][0..l(c)]);489 try buffer.writeAll(inputl.items[i..][0..l(c)]);
489 }490 }
490 // 2. Otherwise, if one of the following is true:491 // 2. Otherwise, if one of the following is true:
491 // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#);492 // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#);
...@@ -501,7 +502,7 @@ pub const URL = struct {...@@ -501,7 +502,7 @@ pub const URL = struct {
501 // 3. Set url’s port to null, if port is url’s scheme’s default port; otherwise to port.502 // 3. Set url’s port to null, if port is url’s scheme’s default port; otherwise to port.
502 if (schemeDefaultPort(href.items(0)) != p) try href.print(9, "{d}", .{p});503 if (schemeDefaultPort(href.items(0)) != p) try href.print(9, "{d}", .{p});
503 // 4. Set buffer to the empty string.504 // 4. Set buffer to the empty string.
504 buffer.clearRetainingCapacity();505 buffer.items.len = 0;
505 // 5. If state override is given, then return.506 // 5. If state override is given, then return.
506 if (state_override != null) break;507 if (state_override != null) break;
507 }508 }
...@@ -655,13 +656,13 @@ pub const URL = struct {...@@ -655,13 +656,13 @@ pub const URL = struct {
655 // 5. If state override is given, then return.656 // 5. If state override is given, then return.
656 if (state_override != null) break;657 if (state_override != null) break;
657 // 6. Set buffer to the empty string and state to path start state.658 // 6. Set buffer to the empty string and state to path start state.
658 buffer.clearRetainingCapacity();659 buffer.items.len = 0;
659 state = .path_start;660 state = .path_start;
660 }661 }
661 }662 }
662 // 2. Otherwise, append c to buffer.663 // 2. Otherwise, append c to buffer.
663 else {664 else {
664 try buffer.appendSlice(inputl.items[i..][0..l(c)]);665 try buffer.writeAll(inputl.items[i..][0..l(c)]);
665 }666 }
666 },667 },
667 .path_start => {668 .path_start => {
...@@ -743,7 +744,7 @@ pub const URL = struct {...@@ -743,7 +744,7 @@ pub const URL = struct {
743 try href.appendSlice(10, buffer.items);744 try href.appendSlice(10, buffer.items);
744 }745 }
745 // 5. Set buffer to the empty string.746 // 5. Set buffer to the empty string.
746 buffer.clearRetainingCapacity();747 buffer.items.len = 0;
747 // 6. If c is U+003F (?), then set url’s query to the empty string and state to query state.748 // 6. If c is U+003F (?), then set url’s query to the empty string and state to query state.
748 if (c == '?') {749 if (c == '?') {
749 href.clear(12);750 href.clear(12);
...@@ -767,9 +768,9 @@ pub const URL = struct {...@@ -767,9 +768,9 @@ pub const URL = struct {
767 if (is_path_percent_char(c)) {768 if (is_path_percent_char(c)) {
768 const pe = try percentEncode(alloc, inputl.items[i..][0..l(c)], is_path_percent_char);769 const pe = try percentEncode(alloc, inputl.items[i..][0..l(c)], is_path_percent_char);
769 defer alloc.free(pe);770 defer alloc.free(pe);
770 try buffer.appendSlice(pe);771 try buffer.writeAll(pe);
771 } else {772 } else {
772 try buffer.appendSlice(inputl.items[i..][0..l(c)]);773 try buffer.writeAll(inputl.items[i..][0..l(c)]);
773 }774 }
774 }775 }
775 },776 },
...@@ -828,7 +829,7 @@ pub const URL = struct {...@@ -828,7 +829,7 @@ pub const URL = struct {
828 try percentEncodeML(&href, 12, buffer.items, is_query_percent_char);829 try percentEncodeML(&href, 12, buffer.items, is_query_percent_char);
829 }830 }
830 // 3. Set buffer to the empty string.831 // 3. Set buffer to the empty string.
831 buffer.clearRetainingCapacity();832 buffer.items.len = 0;
832 // 4. If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state.833 // 4. If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state.
833 if (c == '#') {834 if (c == '#') {
834 href.clear(14);835 href.clear(14);
...@@ -843,7 +844,7 @@ pub const URL = struct {...@@ -843,7 +844,7 @@ pub const URL = struct {
843 // 2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, invalid-URL-unit validation error.844 // 2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, invalid-URL-unit validation error.
844 {}845 {}
845 // 3. Append c to buffer.846 // 3. Append c to buffer.
846 try buffer.appendSlice(inputl.items[i..][0..l(c)]);847 try buffer.writeAll(inputl.items[i..][0..l(c)]);
847 }848 }
848 },849 },
849 .fragment => {850 .fragment => {
...@@ -1140,12 +1141,12 @@ pub const SearchParams = struct {...@@ -1140,12 +1141,12 @@ pub const SearchParams = struct {
11401141
1141 pub fn encode(self: *const SearchParams) ![]u8 {1142 pub fn encode(self: *const SearchParams) ![]u8 {
1142 const alloc = self.allocator;1143 const alloc = self.allocator;
1143 var list = std.array_list.Managed(u8).init(alloc);1144 var list = nio.AllocatingWriter.init(alloc);
1144 errdefer list.deinit();1145 errdefer list.deinit();
1145 for (self.inner.items(.key), self.inner.items(.value), 0..) |k, v, i| {1146 for (self.inner.items(.key), self.inner.items(.value), 0..) |k, v, i| {
1146 if (i > 0) try list.writer().writeAll("&");1147 if (i > 0) try list.writeAll("&");
1147 try percentEncodeAL(&list, k, is_formurlencoded_percent_char);1148 try percentEncodeAL(&list, k, is_formurlencoded_percent_char);
1148 try list.append('=');1149 try list.writeAll("=");
1149 try percentEncodeAL(&list, v, is_formurlencoded_percent_char);1150 try percentEncodeAL(&list, v, is_formurlencoded_percent_char);
1150 }1151 }
1151 list.items.len -= std.mem.replace(u8, list.items, "%20", "+", list.items) * 2;1152 list.items.len -= std.mem.replace(u8, list.items, "%20", "+", list.items) * 2;
...@@ -1458,7 +1459,7 @@ fn parseHostOpaque(allocator: std.mem.Allocator, input: []const u8) ![]const u8...@@ -1458,7 +1459,7 @@ fn parseHostOpaque(allocator: std.mem.Allocator, input: []const u8) ![]const u8
1458/// https://url.spec.whatwg.org/#utf-8-percent-encode1459/// https://url.spec.whatwg.org/#utf-8-percent-encode
1459fn percentEncode(allocator: std.mem.Allocator, input: []const u8, comptime set: fn (u8) bool) ![]u8 {1460fn percentEncode(allocator: std.mem.Allocator, input: []const u8, comptime set: fn (u8) bool) ![]u8 {
1460 if (!extras.matchesAny(u8, input, set)) return allocator.dupe(u8, input);1461 if (!extras.matchesAny(u8, input, set)) return allocator.dupe(u8, input);
1461 var result = std.array_list.Managed(u8).init(allocator);1462 var result = nio.AllocatingWriter.init(allocator);
1462 errdefer result.deinit();1463 errdefer result.deinit();
1463 try result.ensureUnusedCapacity(input.len);1464 try result.ensureUnusedCapacity(input.len);
1464 try percentEncodeAL(&result, input, set);1465 try percentEncodeAL(&result, input, set);
...@@ -1467,10 +1468,10 @@ fn percentEncode(allocator: std.mem.Allocator, input: []const u8, comptime set:...@@ -1467,10 +1468,10 @@ fn percentEncode(allocator: std.mem.Allocator, input: []const u8, comptime set:
14671468
1468/// https://url.spec.whatwg.org/#string-percent-decode1469/// https://url.spec.whatwg.org/#string-percent-decode
1469pub fn percentDecode(allocator: std.mem.Allocator, input: []const u8) ![]u8 {1470pub fn percentDecode(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
1470 var result = std.array_list.Managed(u8).init(allocator);1471 var result = nio.AllocatingWriter.init(allocator);
1471 errdefer result.deinit();1472 errdefer result.deinit();
1472 try result.ensureUnusedCapacity(input.len);1473 try result.ensureUnusedCapacity(input.len);
1473 try percentDecodeW(result.writer(), input);1474 try percentDecodeW(&result, input);
1474 return result.toOwnedSlice();1475 return result.toOwnedSlice();
1475}1476}
1476pub fn percentDecodeW(writer: anytype, input: []const u8) !void {1477pub fn percentDecodeW(writer: anytype, input: []const u8) !void {
...@@ -1792,11 +1793,11 @@ fn lastcpi(haystack: []const u8) usize {...@@ -1792,11 +1793,11 @@ fn lastcpi(haystack: []const u8) usize {
1792 while (haystack[i] & 0xC0 == 0x80) : (i -= 1) {}1793 while (haystack[i] & 0xC0 == 0x80) : (i -= 1) {}
1793 return i;1794 return i;
1794}1795}
1795pub fn percentEncodeScalarAL(list: *std.array_list.Managed(u8), cp: []const u8, comptime set: fn (u8) bool) !void {1796pub fn percentEncodeScalarAL(list: *nio.AllocatingWriter, cp: []const u8, comptime set: fn (u8) bool) !void {
1796 if (set(cp[0])) {1797 if (set(cp[0])) {
1797 for (cp) |b| {1798 for (cp) |b| {
1798 try list.append('%');1799 try list.append('%');
1799 try list.writer().print("{X:0>2}", .{b});1800 try list.print("{X:0>2}", .{b});
1800 }1801 }
1801 } else {1802 } else {
1802 try list.append(cp[0]);1803 try list.append(cp[0]);
...@@ -1815,16 +1816,16 @@ pub fn percentEncodeW(writer: anytype, input: []const u8, comptime set: fn (u8)...@@ -1815,16 +1816,16 @@ pub fn percentEncodeW(writer: anytype, input: []const u8, comptime set: fn (u8)
1815 }1816 }
1816 }1817 }
1817}1818}
1818pub fn percentEncodeAL(list: *std.array_list.Managed(u8), input: []const u8, comptime set: fn (u8) bool) !void {1819pub fn percentEncodeAL(list: *nio.AllocatingWriter, input: []const u8, comptime set: fn (u8) bool) !void {
1819 var it = std.unicode.Utf8View.initUnchecked(input).iterator();1820 var it = std.unicode.Utf8View.initUnchecked(input).iterator();
1820 while (it.nextCodepointSlice()) |sl| {1821 while (it.nextCodepointSlice()) |sl| {
1821 if (set(sl[0])) {1822 if (set(sl[0])) {
1822 for (sl) |b| {1823 for (sl) |b| {
1823 try list.append('%');1824 try list.writeAll("%");
1824 try list.writer().print("{X:0>2}", .{b});1825 try list.print("{X:0>2}", .{b});
1825 }1826 }
1826 } else {1827 } else {
1827 try list.appendSlice(sl);1828 try list.writeAll(sl);
1828 }1829 }
1829 }1830 }
1830}1831}
zigmod.yml+1
...@@ -6,5 +6,6 @@ description: A WHATWG URL-compatible parser for Zig...@@ -6,5 +6,6 @@ description: A WHATWG URL-compatible parser for Zig
6dependencies:6dependencies:
7 - src: git https://github.com/nektro/zig-extras7 - src: git https://github.com/nektro/zig-extras
8 - src: git https://github.com/nektro/zig-unicode-idna8 - src: git https://github.com/nektro/zig-unicode-idna
9 - src: git https://github.com/nektro/zig-nio
9root_dependencies:10root_dependencies:
10 - src: git https://github.com/nektro/zig-expect11 - src: git https://github.com/nektro/zig-expect