aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Uri.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2025-06-27 20:05:22 -0700
committerAndrew Kelley <andrew@ziglang.org>2025-07-07 22:43:51 -0700
commit0e37ff0d591dd75ceec9208196bec29efaec607a (patch)
treec126fa823a1f3864e9c363aac70e3a3db0219957 /lib/std/Uri.zig
parent0b3f0124dc33403d329fb8ee63a93215d9af1f1e (diff)
downloadzig-0e37ff0d591dd75ceec9208196bec29efaec607a.tar.gz
zig-0e37ff0d591dd75ceec9208196bec29efaec607a.zip
std.fmt: breaking API changes
added adapter to AnyWriter and GenericWriter to help bridge the gap between old and new API make std.testing.expectFmt work at compile-time std.fmt no longer has a dependency on std.unicode. Formatted printing was never properly unicode-aware. Now it no longer pretends to be. Breakage/deprecations: * std.fs.File.reader -> std.fs.File.deprecatedReader * std.fs.File.writer -> std.fs.File.deprecatedWriter * std.io.GenericReader -> std.io.Reader * std.io.GenericWriter -> std.io.Writer * std.io.AnyReader -> std.io.Reader * std.io.AnyWriter -> std.io.Writer * std.fmt.format -> std.fmt.deprecatedFormat * std.fmt.fmtSliceEscapeLower -> std.ascii.hexEscape * std.fmt.fmtSliceEscapeUpper -> std.ascii.hexEscape * std.fmt.fmtSliceHexLower -> {x} * std.fmt.fmtSliceHexUpper -> {X} * std.fmt.fmtIntSizeDec -> {B} * std.fmt.fmtIntSizeBin -> {Bi} * std.fmt.fmtDuration -> {D} * std.fmt.fmtDurationSigned -> {D} * {} -> {f} when there is a format method * format method signature - anytype -> *std.io.Writer - inferred error set -> error{WriteFailed} - options -> (deleted) * std.fmt.Formatted - now takes context type explicitly - no fmt string
Diffstat (limited to 'lib/std/Uri.zig')
-rw-r--r--lib/std/Uri.zig98
1 files changed, 40 insertions, 58 deletions
diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig
index ee0c602125..b1dc845eb5 100644
--- a/lib/std/Uri.zig
+++ b/lib/std/Uri.zig
@@ -34,27 +34,22 @@ pub const Component = union(enum) {
return switch (component) {
.raw => |raw| raw,
.percent_encoded => |percent_encoded| if (std.mem.indexOfScalar(u8, percent_encoded, '%')) |_|
- try std.fmt.allocPrint(arena, "{raw}", .{component})
+ try std.fmt.allocPrint(arena, "{fraw}", .{component})
else
percent_encoded,
};
}
- pub fn format(
- component: Component,
- comptime fmt_str: []const u8,
- _: std.fmt.FormatOptions,
- writer: anytype,
- ) @TypeOf(writer).Error!void {
+ pub fn format(component: Component, w: *std.io.Writer, comptime fmt_str: []const u8) std.io.Writer.Error!void {
if (fmt_str.len == 0) {
- try writer.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{
+ try w.print("std.Uri.Component{{ .{s} = \"{f}\" }}", .{
@tagName(component),
- std.zig.fmtEscapes(switch (component) {
+ std.zig.fmtString(switch (component) {
.raw, .percent_encoded => |string| string,
}),
});
} else if (comptime std.mem.eql(u8, fmt_str, "raw")) switch (component) {
- .raw => |raw| try writer.writeAll(raw),
+ .raw => |raw| try w.writeAll(raw),
.percent_encoded => |percent_encoded| {
var start: usize = 0;
var index: usize = 0;
@@ -63,51 +58,47 @@ pub const Component = union(enum) {
if (percent_encoded.len - index < 2) continue;
const percent_encoded_char =
std.fmt.parseInt(u8, percent_encoded[index..][0..2], 16) catch continue;
- try writer.print("{s}{c}", .{
+ try w.print("{s}{c}", .{
percent_encoded[start..percent],
percent_encoded_char,
});
start = percent + 3;
index = percent + 3;
}
- try writer.writeAll(percent_encoded[start..]);
+ try w.writeAll(percent_encoded[start..]);
},
} else if (comptime std.mem.eql(u8, fmt_str, "%")) switch (component) {
- .raw => |raw| try percentEncode(writer, raw, isUnreserved),
- .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ .raw => |raw| try percentEncode(w, raw, isUnreserved),
+ .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt_str, "user")) switch (component) {
- .raw => |raw| try percentEncode(writer, raw, isUserChar),
- .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ .raw => |raw| try percentEncode(w, raw, isUserChar),
+ .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt_str, "password")) switch (component) {
- .raw => |raw| try percentEncode(writer, raw, isPasswordChar),
- .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ .raw => |raw| try percentEncode(w, raw, isPasswordChar),
+ .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt_str, "host")) switch (component) {
- .raw => |raw| try percentEncode(writer, raw, isHostChar),
- .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ .raw => |raw| try percentEncode(w, raw, isHostChar),
+ .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt_str, "path")) switch (component) {
- .raw => |raw| try percentEncode(writer, raw, isPathChar),
- .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ .raw => |raw| try percentEncode(w, raw, isPathChar),
+ .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt_str, "query")) switch (component) {
- .raw => |raw| try percentEncode(writer, raw, isQueryChar),
- .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ .raw => |raw| try percentEncode(w, raw, isQueryChar),
+ .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
} else if (comptime std.mem.eql(u8, fmt_str, "fragment")) switch (component) {
- .raw => |raw| try percentEncode(writer, raw, isFragmentChar),
- .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
+ .raw => |raw| try percentEncode(w, raw, isFragmentChar),
+ .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
} else @compileError("invalid format string '" ++ fmt_str ++ "'");
}
- pub fn percentEncode(
- writer: anytype,
- raw: []const u8,
- comptime isValidChar: fn (u8) bool,
- ) @TypeOf(writer).Error!void {
+ pub fn percentEncode(w: *std.io.Writer, raw: []const u8, comptime isValidChar: fn (u8) bool) std.io.Writer.Error!void {
var start: usize = 0;
for (raw, 0..) |char, index| {
if (isValidChar(char)) continue;
- try writer.print("{s}%{X:0>2}", .{ raw[start..index], char });
+ try w.print("{s}%{X:0>2}", .{ raw[start..index], char });
start = index + 1;
}
- try writer.writeAll(raw[start..]);
+ try w.writeAll(raw[start..]);
}
};
@@ -247,11 +238,7 @@ pub const WriteToStreamOptions = struct {
port: bool = true,
};
-pub fn writeToStream(
- uri: Uri,
- options: WriteToStreamOptions,
- writer: anytype,
-) @TypeOf(writer).Error!void {
+pub fn writeToStream(uri: Uri, writer: *std.io.Writer, options: WriteToStreamOptions) std.io.Writer.Error!void {
if (options.scheme) {
try writer.print("{s}:", .{uri.scheme});
if (options.authority and uri.host != null) {
@@ -261,39 +248,34 @@ pub fn writeToStream(
if (options.authority) {
if (options.authentication and uri.host != null) {
if (uri.user) |user| {
- try writer.print("{user}", .{user});
+ try writer.print("{fuser}", .{user});
if (uri.password) |password| {
- try writer.print(":{password}", .{password});
+ try writer.print(":{fpassword}", .{password});
}
try writer.writeByte('@');
}
}
if (uri.host) |host| {
- try writer.print("{host}", .{host});
+ try writer.print("{fhost}", .{host});
if (options.port) {
if (uri.port) |port| try writer.print(":{d}", .{port});
}
}
}
if (options.path) {
- try writer.print("{path}", .{
+ try writer.print("{fpath}", .{
if (uri.path.isEmpty()) Uri.Component{ .percent_encoded = "/" } else uri.path,
});
if (options.query) {
- if (uri.query) |query| try writer.print("?{query}", .{query});
+ if (uri.query) |query| try writer.print("?{fquery}", .{query});
}
if (options.fragment) {
- if (uri.fragment) |fragment| try writer.print("#{fragment}", .{fragment});
+ if (uri.fragment) |fragment| try writer.print("#{ffragment}", .{fragment});
}
}
}
-pub fn format(
- uri: Uri,
- comptime fmt_str: []const u8,
- _: std.fmt.FormatOptions,
- writer: anytype,
-) @TypeOf(writer).Error!void {
+pub fn format(uri: Uri, writer: *std.io.Writer, comptime fmt_str: []const u8) std.io.Writer.Error!void {
const scheme = comptime std.mem.indexOfScalar(u8, fmt_str, ';') != null or fmt_str.len == 0;
const authentication = comptime std.mem.indexOfScalar(u8, fmt_str, '@') != null or fmt_str.len == 0;
const authority = comptime std.mem.indexOfScalar(u8, fmt_str, '+') != null or fmt_str.len == 0;
@@ -301,14 +283,14 @@ pub fn format(
const query = comptime std.mem.indexOfScalar(u8, fmt_str, '?') != null or fmt_str.len == 0;
const fragment = comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null or fmt_str.len == 0;
- return writeToStream(uri, .{
+ return writeToStream(uri, writer, .{
.scheme = scheme,
.authentication = authentication,
.authority = authority,
.path = path,
.query = query,
.fragment = fragment,
- }, writer);
+ });
}
/// Parses the URI or returns an error.
@@ -447,7 +429,7 @@ test remove_dot_segments {
fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Component {
var aux = std.io.fixedBufferStream(aux_buf.*);
if (!base.isEmpty()) {
- try aux.writer().print("{path}", .{base});
+ try aux.writer().print("{fpath}", .{base});
aux.pos = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse
return remove_dot_segments(new);
}
@@ -812,7 +794,7 @@ test "Special test" {
test "URI percent encoding" {
try std.testing.expectFmt(
"%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad",
- "{%}",
+ "{f%}",
.{Component{ .raw = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad" }},
);
}
@@ -822,7 +804,7 @@ test "URI percent decoding" {
const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";
var input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad".*;
- try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});
+ try std.testing.expectFmt(expected, "{fraw}", .{Component{ .percent_encoded = &input }});
var output: [expected.len]u8 = undefined;
try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
@@ -834,7 +816,7 @@ test "URI percent decoding" {
const expected = "/abc%";
var input = expected.*;
- try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});
+ try std.testing.expectFmt(expected, "{fraw}", .{Component{ .percent_encoded = &input }});
var output: [expected.len]u8 = undefined;
try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
@@ -848,7 +830,7 @@ test "URI query encoding" {
const parsed = try Uri.parse(address);
// format the URI to percent encode it
- try std.testing.expectFmt("/?response-content-type=application%2Foctet-stream", "{/?}", .{parsed});
+ try std.testing.expectFmt("/?response-content-type=application%2Foctet-stream", "{f/?}", .{parsed});
}
test "format" {
@@ -862,7 +844,7 @@ test "format" {
.query = null,
.fragment = null,
};
- try std.testing.expectFmt("file:/foo/bar/baz", "{;/?#}", .{uri});
+ try std.testing.expectFmt("file:/foo/bar/baz", "{f;/?#}", .{uri});
}
test "URI malformed input" {