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 @@
33![loc](https://sloc.xyz/github/nektro/zig-whatwg-url)
44[![license](https://img.shields.io/github/license/nektro/zig-whatwg-url.svg)](https://github.com/nektro/zig-whatwg-url/blob/master/LICENSE)
55[![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/)
77[![Zigmod](https://img.shields.io/badge/Zigmod-latest-f7a41d)](https://github.com/nektro/zigmod)
88
99A spec-compliant Zig implementation of WHATWG URL.
build.zig+1
......@@ -22,6 +22,7 @@ pub fn build(b: *std.Build) void {
2222 }),
2323 });
2424 deps.addAllTo(tests);
25 tests.root_module.link_libc = true;
2526 tests.use_llvm = !disable_llvm;
2627 tests.use_lld = !disable_llvm;
2728 b.getInstallStep().dependOn(&tests.step);
url.zig+37-36
......@@ -2,6 +2,7 @@ const std = @import("std");
22const builtin = @import("builtin");
33const extras = @import("extras");
44const unicode_idna = @import("unicode-idna");
5const nio = @import("nio");
56
67pub const URL = struct {
78 href: []const u8,
......@@ -47,13 +48,13 @@ pub const URL = struct {
4748 // input is a scalar value string
4849 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);
5152 defer inputl.deinit();
52 try inputl.appendSlice(input);
53 try inputl.writeAll(input);
5354
5455 // 1.
5556 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
5859 // 3.
5960 while (std.mem.indexOfScalar(u8, inputl.items, '\t')) |i| _ = inputl.orderedRemove(i);
......@@ -70,7 +71,7 @@ pub const URL = struct {
7071 // we always do utf-8
7172
7273 // 6.
73 var buffer = std.array_list.Managed(u8).init(alloc);
74 var buffer = nio.AllocatingWriter.init(alloc);
7475 defer buffer.deinit();
7576
7677 // 7.
......@@ -118,7 +119,7 @@ pub const URL = struct {
118119 std.debug.assert(pointer == 0);
119120 // 1. If c is an ASCII alpha, append c, lowercased, to buffer, and set state to scheme state.
120121 if (i < length and std.ascii.isAlphabetic(c)) {
121 try buffer.append(std.ascii.toLower(c));
122 try buffer.writeAll(&.{std.ascii.toLower(c)});
122123 state = .scheme;
123124 }
124125 // 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 {
134135 .scheme => {
135136 // 1. If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.), append c, lowercased, to buffer.
136137 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)});
138139 }
139140 // 2. Otherwise, if c is U+003A (:), then:
140141 else if (c == ':') {
......@@ -156,7 +157,7 @@ pub const URL = struct {
156157 // 2. Return.
157158 }
158159 // 4. Set buffer to the empty string.
159 buffer.clearRetainingCapacity();
160 buffer.items.len = 0;
160161 // 5. If url’s scheme is "file", then:
161162 if (std.mem.eql(u8, href.items(0), "file")) {
162163 // 1. If remaining does not start with "//", special-scheme-missing-following-solidus validation error.
......@@ -192,7 +193,7 @@ pub const URL = struct {
192193 }
193194 // 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).
194195 else if (state_override == null) {
195 buffer.clearRetainingCapacity();
196 buffer.items.len = 0;
196197 state = .no_scheme;
197198 pointer = 0;
198199 i = 0;
......@@ -380,7 +381,7 @@ pub const URL = struct {
380381 // 1. Invalid-credentials validation error.
381382 {}
382383 // 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");
384385 // 3. Set atSignSeen to true.
385386 atSignSeen = true;
386387 // 4. For each codePoint in buffer:
......@@ -401,7 +402,7 @@ pub const URL = struct {
401402 }
402403 }
403404 // 5. Set buffer to the empty string.
404 buffer.clearRetainingCapacity();
405 buffer.items.len = 0;
405406 }
406407 // 2. Otherwise, if one of the following is true:
407408 // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
......@@ -416,12 +417,12 @@ pub const URL = struct {
416417 i = lastcpi(inputl.items[0..i]);
417418 c = inputl.items[i];
418419 }
419 buffer.clearRetainingCapacity();
420 buffer.items.len = 0;
420421 state = .host;
421422 }
422423 // 3. Otherwise, append c to buffer.
423424 else {
424 try buffer.appendSlice(inputl.items[i..][0..l(c)]);
425 try buffer.writeAll(inputl.items[i..][0..l(c)]);
425426 }
426427 },
427428 .host, .hostname => {
......@@ -445,7 +446,7 @@ pub const URL = struct {
445446 // 5. Set url’s host to host, buffer to the empty string, and state to port state.
446447 try setHost(&href, h);
447448 hostname_kind = h;
448 buffer.clearRetainingCapacity();
449 buffer.items.len = 0;
449450 state = .port;
450451 }
451452 // 3. Otherwise, if one of the following is true:
......@@ -467,7 +468,7 @@ pub const URL = struct {
467468 // 5. Set url’s host to host, buffer to the empty string, and state to path start state.
468469 try setHost(&href, h);
469470 hostname_kind = h;
470 buffer.clearRetainingCapacity();
471 buffer.items.len = 0;
471472 state = .path_start;
472473 // 6. If state override is given, then return.
473474 if (state_override != null) break;
......@@ -479,13 +480,13 @@ pub const URL = struct {
479480 // 2. If c is U+005D (]), then set insideBrackets to false.
480481 if (c == ']') insideBrackets = false;
481482 // 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)]);
483484 }
484485 },
485486 .port => {
486487 // 1. If c is an ASCII digit, append c to buffer.
487488 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)]);
489490 }
490491 // 2. Otherwise, if one of the following is true:
491492 // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#);
......@@ -501,7 +502,7 @@ pub const URL = struct {
501502 // 3. Set url’s port to null, if port is url’s scheme’s default port; otherwise to port.
502503 if (schemeDefaultPort(href.items(0)) != p) try href.print(9, "{d}", .{p});
503504 // 4. Set buffer to the empty string.
504 buffer.clearRetainingCapacity();
505 buffer.items.len = 0;
505506 // 5. If state override is given, then return.
506507 if (state_override != null) break;
507508 }
......@@ -655,13 +656,13 @@ pub const URL = struct {
655656 // 5. If state override is given, then return.
656657 if (state_override != null) break;
657658 // 6. Set buffer to the empty string and state to path start state.
658 buffer.clearRetainingCapacity();
659 buffer.items.len = 0;
659660 state = .path_start;
660661 }
661662 }
662663 // 2. Otherwise, append c to buffer.
663664 else {
664 try buffer.appendSlice(inputl.items[i..][0..l(c)]);
665 try buffer.writeAll(inputl.items[i..][0..l(c)]);
665666 }
666667 },
667668 .path_start => {
......@@ -743,7 +744,7 @@ pub const URL = struct {
743744 try href.appendSlice(10, buffer.items);
744745 }
745746 // 5. Set buffer to the empty string.
746 buffer.clearRetainingCapacity();
747 buffer.items.len = 0;
747748 // 6. If c is U+003F (?), then set url’s query to the empty string and state to query state.
748749 if (c == '?') {
749750 href.clear(12);
......@@ -767,9 +768,9 @@ pub const URL = struct {
767768 if (is_path_percent_char(c)) {
768769 const pe = try percentEncode(alloc, inputl.items[i..][0..l(c)], is_path_percent_char);
769770 defer alloc.free(pe);
770 try buffer.appendSlice(pe);
771 try buffer.writeAll(pe);
771772 } else {
772 try buffer.appendSlice(inputl.items[i..][0..l(c)]);
773 try buffer.writeAll(inputl.items[i..][0..l(c)]);
773774 }
774775 }
775776 },
......@@ -828,7 +829,7 @@ pub const URL = struct {
828829 try percentEncodeML(&href, 12, buffer.items, is_query_percent_char);
829830 }
830831 // 3. Set buffer to the empty string.
831 buffer.clearRetainingCapacity();
832 buffer.items.len = 0;
832833 // 4. If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state.
833834 if (c == '#') {
834835 href.clear(14);
......@@ -843,7 +844,7 @@ pub const URL = struct {
843844 // 2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, invalid-URL-unit validation error.
844845 {}
845846 // 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)]);
847848 }
848849 },
849850 .fragment => {
......@@ -1140,12 +1141,12 @@ pub const SearchParams = struct {
11401141
11411142 pub fn encode(self: *const SearchParams) ![]u8 {
11421143 const alloc = self.allocator;
1143 var list = std.array_list.Managed(u8).init(alloc);
1144 var list = nio.AllocatingWriter.init(alloc);
11441145 errdefer list.deinit();
11451146 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("&");
11471148 try percentEncodeAL(&list, k, is_formurlencoded_percent_char);
1148 try list.append('=');
1149 try list.writeAll("=");
11491150 try percentEncodeAL(&list, v, is_formurlencoded_percent_char);
11501151 }
11511152 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
14581459/// https://url.spec.whatwg.org/#utf-8-percent-encode
14591460fn percentEncode(allocator: std.mem.Allocator, input: []const u8, comptime set: fn (u8) bool) ![]u8 {
14601461 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);
14621463 errdefer result.deinit();
14631464 try result.ensureUnusedCapacity(input.len);
14641465 try percentEncodeAL(&result, input, set);
......@@ -1467,10 +1468,10 @@ fn percentEncode(allocator: std.mem.Allocator, input: []const u8, comptime set:
14671468
14681469/// https://url.spec.whatwg.org/#string-percent-decode
14691470pub 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);
14711472 errdefer result.deinit();
14721473 try result.ensureUnusedCapacity(input.len);
1473 try percentDecodeW(result.writer(), input);
1474 try percentDecodeW(&result, input);
14741475 return result.toOwnedSlice();
14751476}
14761477pub fn percentDecodeW(writer: anytype, input: []const u8) !void {
......@@ -1792,11 +1793,11 @@ fn lastcpi(haystack: []const u8) usize {
17921793 while (haystack[i] & 0xC0 == 0x80) : (i -= 1) {}
17931794 return i;
17941795}
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 {
17961797 if (set(cp[0])) {
17971798 for (cp) |b| {
17981799 try list.append('%');
1799 try list.writer().print("{X:0>2}", .{b});
1800 try list.print("{X:0>2}", .{b});
18001801 }
18011802 } else {
18021803 try list.append(cp[0]);
......@@ -1815,16 +1816,16 @@ pub fn percentEncodeW(writer: anytype, input: []const u8, comptime set: fn (u8)
18151816 }
18161817 }
18171818}
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 {
18191820 var it = std.unicode.Utf8View.initUnchecked(input).iterator();
18201821 while (it.nextCodepointSlice()) |sl| {
18211822 if (set(sl[0])) {
18221823 for (sl) |b| {
1823 try list.append('%');
1824 try list.writer().print("{X:0>2}", .{b});
1824 try list.writeAll("%");
1825 try list.print("{X:0>2}", .{b});
18251826 }
18261827 } else {
1827 try list.appendSlice(sl);
1828 try list.writeAll(sl);
18281829 }
18291830 }
18301831}
zigmod.yml+1
......@@ -6,5 +6,6 @@ description: A WHATWG URL-compatible parser for Zig
66dependencies:
77 - src: git https://github.com/nektro/zig-extras
88 - src: git https://github.com/nektro/zig-unicode-idna
9 - src: git https://github.com/nektro/zig-nio
910root_dependencies:
1011 - src: git https://github.com/nektro/zig-expect