mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-28 03:17:08 +03:00
Merge branch 'fengb-format-stream'
This commit is contained in:
+4
-12
@@ -65,13 +65,9 @@ pub const Buffer = struct {
|
||||
}
|
||||
|
||||
pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: var) !Buffer {
|
||||
const countSize = struct {
|
||||
fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
|
||||
size.* += bytes.len;
|
||||
}
|
||||
}.countSize;
|
||||
var size: usize = 0;
|
||||
std.fmt.format(&size, error{}, countSize, format, args) catch |err| switch (err) {};
|
||||
const size = std.math.cast(usize, std.fmt.count(format, args)) catch |err| switch (err) {
|
||||
error.Overflow => return error.OutOfMemory,
|
||||
};
|
||||
var self = try Buffer.initSize(allocator, size);
|
||||
assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size);
|
||||
return self;
|
||||
@@ -154,10 +150,6 @@ pub const Buffer = struct {
|
||||
mem.copy(u8, self.list.toSlice(), m);
|
||||
}
|
||||
|
||||
pub fn print(self: *Buffer, comptime fmt: []const u8, args: var) !void {
|
||||
return std.fmt.format(self, error{OutOfMemory}, Buffer.append, fmt, args);
|
||||
}
|
||||
|
||||
pub fn outStream(self: *Buffer) std.io.OutStream(*Buffer, error{OutOfMemory}, appendWrite) {
|
||||
return .{ .context = self };
|
||||
}
|
||||
@@ -216,7 +208,7 @@ test "Buffer.print" {
|
||||
var buf = try Buffer.init(testing.allocator, "");
|
||||
defer buf.deinit();
|
||||
|
||||
try buf.print("Hello {} the {}", .{ 2, "world" });
|
||||
try buf.outStream().print("Hello {} the {}", .{ 2, "world" });
|
||||
testing.expect(buf.eql("Hello 2 the world"));
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -436,19 +436,17 @@ pub const Version = struct {
|
||||
self: Version,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
context: var,
|
||||
comptime Error: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Error!void,
|
||||
) Error!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
if (fmt.len == 0) {
|
||||
if (self.patch == 0) {
|
||||
if (self.minor == 0) {
|
||||
return std.fmt.format(context, Error, output, "{}", .{self.major});
|
||||
return std.fmt.format(out_stream, "{}", .{self.major});
|
||||
} else {
|
||||
return std.fmt.format(context, Error, output, "{}.{}", .{ self.major, self.minor });
|
||||
return std.fmt.format(out_stream, "{}.{}", .{ self.major, self.minor });
|
||||
}
|
||||
} else {
|
||||
return std.fmt.format(context, Error, output, "{}.{}.{}", .{ self.major, self.minor, self.patch });
|
||||
return std.fmt.format(out_stream, "{}.{}.{}", .{ self.major, self.minor, self.patch });
|
||||
}
|
||||
} else {
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
|
||||
+13
-3
@@ -293,8 +293,18 @@ pub fn LinearFifo(
|
||||
|
||||
pub usingnamespace if (T == u8)
|
||||
struct {
|
||||
pub fn print(self: *Self, comptime format: []const u8, args: var) !void {
|
||||
return std.fmt.format(self, error{OutOfMemory}, Self.write, format, args);
|
||||
const OutStream = std.io.OutStream(*Self, Error, appendWrite);
|
||||
const Error = error{OutOfMemory};
|
||||
|
||||
/// Same as `write` except it returns the number of bytes written, which is always the same
|
||||
/// as `bytes.len`. The purpose of this function existing is to match `std.io.OutStream` API.
|
||||
pub fn appendWrite(fifo: *Self, bytes: []const u8) Error!usize {
|
||||
try fifo.write(bytes);
|
||||
return bytes.len;
|
||||
}
|
||||
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -407,7 +417,7 @@ test "LinearFifo(u8, .Dynamic)" {
|
||||
fifo.shrink(0);
|
||||
|
||||
{
|
||||
try fifo.print("{}, {}!", .{ "Hello", "World" });
|
||||
try fifo.outStream().print("{}, {}!", .{ "Hello", "World" });
|
||||
var result: [30]u8 = undefined;
|
||||
testing.expectEqualSlices(u8, "Hello, World!", result[0..fifo.read(&result)]);
|
||||
testing.expectEqual(@as(usize, 0), fifo.readableLength());
|
||||
|
||||
+219
-292
@@ -69,19 +69,17 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
|
||||
///
|
||||
/// If a formatted user type contains a function of the type
|
||||
/// ```
|
||||
/// fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, context: var, comptime Errors: type, comptime output: fn (@TypeOf(context), []const u8) Errors!void) Errors!void
|
||||
/// fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void
|
||||
/// ```
|
||||
/// with `?` being the type formatted, this function will be called instead of the default implementation.
|
||||
/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
|
||||
///
|
||||
/// A user type may be a `struct`, `vector`, `union` or `enum` type.
|
||||
pub fn format(
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
out_stream: var,
|
||||
comptime fmt: []const u8,
|
||||
args: var,
|
||||
) Errors!void {
|
||||
) !void {
|
||||
const ArgSetType = u32;
|
||||
if (@typeInfo(@TypeOf(args)) != .Struct) {
|
||||
@compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
|
||||
@@ -138,7 +136,7 @@ pub fn format(
|
||||
.Start => switch (c) {
|
||||
'{' => {
|
||||
if (start_index < i) {
|
||||
try output(context, fmt[start_index..i]);
|
||||
try out_stream.writeAll(fmt[start_index..i]);
|
||||
}
|
||||
|
||||
start_index = i;
|
||||
@@ -150,7 +148,7 @@ pub fn format(
|
||||
},
|
||||
'}' => {
|
||||
if (start_index < i) {
|
||||
try output(context, fmt[start_index..i]);
|
||||
try out_stream.writeAll(fmt[start_index..i]);
|
||||
}
|
||||
state = .CloseBrace;
|
||||
},
|
||||
@@ -185,9 +183,7 @@ pub fn format(
|
||||
args[arg_to_print],
|
||||
fmt[0..0],
|
||||
options,
|
||||
context,
|
||||
Errors,
|
||||
output,
|
||||
out_stream,
|
||||
default_max_depth,
|
||||
);
|
||||
|
||||
@@ -218,9 +214,7 @@ pub fn format(
|
||||
args[arg_to_print],
|
||||
fmt[specifier_start..i],
|
||||
options,
|
||||
context,
|
||||
Errors,
|
||||
output,
|
||||
out_stream,
|
||||
default_max_depth,
|
||||
);
|
||||
state = .Start;
|
||||
@@ -265,9 +259,7 @@ pub fn format(
|
||||
args[arg_to_print],
|
||||
fmt[specifier_start..specifier_end],
|
||||
options,
|
||||
context,
|
||||
Errors,
|
||||
output,
|
||||
out_stream,
|
||||
default_max_depth,
|
||||
);
|
||||
state = .Start;
|
||||
@@ -293,9 +285,7 @@ pub fn format(
|
||||
args[arg_to_print],
|
||||
fmt[specifier_start..specifier_end],
|
||||
options,
|
||||
context,
|
||||
Errors,
|
||||
output,
|
||||
out_stream,
|
||||
default_max_depth,
|
||||
);
|
||||
state = .Start;
|
||||
@@ -316,7 +306,7 @@ pub fn format(
|
||||
}
|
||||
}
|
||||
if (start_index < fmt.len) {
|
||||
try output(context, fmt[start_index..]);
|
||||
try out_stream.writeAll(fmt[start_index..]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,141 +314,131 @@ pub fn formatType(
|
||||
value: var,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
out_stream: var,
|
||||
max_depth: usize,
|
||||
) Errors!void {
|
||||
) @TypeOf(out_stream).Error!void {
|
||||
if (comptime std.mem.eql(u8, fmt, "*")) {
|
||||
try output(context, @typeName(@TypeOf(value).Child));
|
||||
try output(context, "@");
|
||||
try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, context, Errors, output);
|
||||
try out_stream.writeAll(@typeName(@TypeOf(value).Child));
|
||||
try out_stream.writeAll("@");
|
||||
try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, out_stream);
|
||||
return;
|
||||
}
|
||||
|
||||
const T = @TypeOf(value);
|
||||
if (comptime std.meta.trait.hasFn("format")(T)) {
|
||||
return try value.format(fmt, options, out_stream);
|
||||
}
|
||||
|
||||
switch (@typeInfo(T)) {
|
||||
.ComptimeInt, .Int, .Float => {
|
||||
return formatValue(value, fmt, options, context, Errors, output);
|
||||
return formatValue(value, fmt, options, out_stream);
|
||||
},
|
||||
.Void => {
|
||||
return output(context, "void");
|
||||
return out_stream.writeAll("void");
|
||||
},
|
||||
.Bool => {
|
||||
return output(context, if (value) "true" else "false");
|
||||
return out_stream.writeAll(if (value) "true" else "false");
|
||||
},
|
||||
.Optional => {
|
||||
if (value) |payload| {
|
||||
return formatType(payload, fmt, options, context, Errors, output, max_depth);
|
||||
return formatType(payload, fmt, options, out_stream, max_depth);
|
||||
} else {
|
||||
return output(context, "null");
|
||||
return out_stream.writeAll("null");
|
||||
}
|
||||
},
|
||||
.ErrorUnion => {
|
||||
if (value) |payload| {
|
||||
return formatType(payload, fmt, options, context, Errors, output, max_depth);
|
||||
return formatType(payload, fmt, options, out_stream, max_depth);
|
||||
} else |err| {
|
||||
return formatType(err, fmt, options, context, Errors, output, max_depth);
|
||||
return formatType(err, fmt, options, out_stream, max_depth);
|
||||
}
|
||||
},
|
||||
.ErrorSet => {
|
||||
try output(context, "error.");
|
||||
return output(context, @errorName(value));
|
||||
try out_stream.writeAll("error.");
|
||||
return out_stream.writeAll(@errorName(value));
|
||||
},
|
||||
.Enum => |enumInfo| {
|
||||
if (comptime std.meta.trait.hasFn("format")(T)) {
|
||||
return value.format(fmt, options, context, Errors, output);
|
||||
}
|
||||
|
||||
try output(context, @typeName(T));
|
||||
try out_stream.writeAll(@typeName(T));
|
||||
if (enumInfo.is_exhaustive) {
|
||||
try output(context, ".");
|
||||
try output(context, @tagName(value));
|
||||
try out_stream.writeAll(".");
|
||||
try out_stream.writeAll(@tagName(value));
|
||||
} else {
|
||||
// TODO: when @tagName works on exhaustive enums print known enum strings
|
||||
try output(context, "(");
|
||||
try formatType(@enumToInt(value), fmt, options, context, Errors, output, max_depth);
|
||||
try output(context, ")");
|
||||
try out_stream.writeAll("(");
|
||||
try formatType(@enumToInt(value), fmt, options, out_stream, max_depth);
|
||||
try out_stream.writeAll(")");
|
||||
}
|
||||
},
|
||||
.Union => {
|
||||
if (comptime std.meta.trait.hasFn("format")(T)) {
|
||||
return value.format(fmt, options, context, Errors, output);
|
||||
}
|
||||
|
||||
try output(context, @typeName(T));
|
||||
try out_stream.writeAll(@typeName(T));
|
||||
if (max_depth == 0) {
|
||||
return output(context, "{ ... }");
|
||||
return out_stream.writeAll("{ ... }");
|
||||
}
|
||||
const info = @typeInfo(T).Union;
|
||||
if (info.tag_type) |UnionTagType| {
|
||||
try output(context, "{ .");
|
||||
try output(context, @tagName(@as(UnionTagType, value)));
|
||||
try output(context, " = ");
|
||||
try out_stream.writeAll("{ .");
|
||||
try out_stream.writeAll(@tagName(@as(UnionTagType, value)));
|
||||
try out_stream.writeAll(" = ");
|
||||
inline for (info.fields) |u_field| {
|
||||
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
|
||||
try formatType(@field(value, u_field.name), fmt, options, context, Errors, output, max_depth - 1);
|
||||
try formatType(@field(value, u_field.name), fmt, options, out_stream, max_depth - 1);
|
||||
}
|
||||
}
|
||||
try output(context, " }");
|
||||
try out_stream.writeAll(" }");
|
||||
} else {
|
||||
try format(context, Errors, output, "@{x}", .{@ptrToInt(&value)});
|
||||
try format(out_stream, "@{x}", .{@ptrToInt(&value)});
|
||||
}
|
||||
},
|
||||
.Struct => |StructT| {
|
||||
if (comptime std.meta.trait.hasFn("format")(T)) {
|
||||
return value.format(fmt, options, context, Errors, output);
|
||||
}
|
||||
|
||||
try output(context, @typeName(T));
|
||||
try out_stream.writeAll(@typeName(T));
|
||||
if (max_depth == 0) {
|
||||
return output(context, "{ ... }");
|
||||
return out_stream.writeAll("{ ... }");
|
||||
}
|
||||
try output(context, "{");
|
||||
try out_stream.writeAll("{");
|
||||
inline for (StructT.fields) |f, i| {
|
||||
if (i == 0) {
|
||||
try output(context, " .");
|
||||
try out_stream.writeAll(" .");
|
||||
} else {
|
||||
try output(context, ", .");
|
||||
try out_stream.writeAll(", .");
|
||||
}
|
||||
try output(context, f.name);
|
||||
try output(context, " = ");
|
||||
try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);
|
||||
try out_stream.writeAll(f.name);
|
||||
try out_stream.writeAll(" = ");
|
||||
try formatType(@field(value, f.name), fmt, options, out_stream, max_depth - 1);
|
||||
}
|
||||
try output(context, " }");
|
||||
try out_stream.writeAll(" }");
|
||||
},
|
||||
.Pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.One => switch (@typeInfo(ptr_info.child)) {
|
||||
.Array => |info| {
|
||||
if (info.child == u8) {
|
||||
return formatText(value, fmt, options, context, Errors, output);
|
||||
return formatText(value, fmt, options, out_stream);
|
||||
}
|
||||
return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
},
|
||||
.Enum, .Union, .Struct => {
|
||||
return formatType(value.*, fmt, options, context, Errors, output, max_depth);
|
||||
return formatType(value.*, fmt, options, out_stream, max_depth);
|
||||
},
|
||||
else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
|
||||
else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
|
||||
},
|
||||
.Many, .C => {
|
||||
if (ptr_info.sentinel) |sentinel| {
|
||||
return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
|
||||
return formatType(mem.span(value), fmt, options, out_stream, max_depth);
|
||||
}
|
||||
if (ptr_info.child == u8) {
|
||||
if (fmt.len > 0 and fmt[0] == 's') {
|
||||
return formatText(mem.span(value), fmt, options, context, Errors, output);
|
||||
return formatText(mem.span(value), fmt, options, out_stream);
|
||||
}
|
||||
}
|
||||
return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
},
|
||||
.Slice => {
|
||||
if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
|
||||
return formatText(value, fmt, options, context, Errors, output);
|
||||
return formatText(value, fmt, options, out_stream);
|
||||
}
|
||||
if (ptr_info.child == u8) {
|
||||
return formatText(value, fmt, options, context, Errors, output);
|
||||
return formatText(value, fmt, options, out_stream);
|
||||
}
|
||||
return format(context, Errors, output, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
|
||||
return format(out_stream, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
|
||||
},
|
||||
},
|
||||
.Array => |info| {
|
||||
@@ -473,27 +453,27 @@ pub fn formatType(
|
||||
.sentinel = null,
|
||||
},
|
||||
});
|
||||
return formatType(@as(Slice, &value), fmt, options, context, Errors, output, max_depth);
|
||||
return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth);
|
||||
},
|
||||
.Vector => {
|
||||
const len = @typeInfo(T).Vector.len;
|
||||
try output(context, "{ ");
|
||||
try out_stream.writeAll("{ ");
|
||||
var i: usize = 0;
|
||||
while (i < len) : (i += 1) {
|
||||
try formatValue(value[i], fmt, options, context, Errors, output);
|
||||
try formatValue(value[i], fmt, options, out_stream);
|
||||
if (i < len - 1) {
|
||||
try output(context, ", ");
|
||||
try out_stream.writeAll(", ");
|
||||
}
|
||||
}
|
||||
try output(context, " }");
|
||||
try out_stream.writeAll(" }");
|
||||
},
|
||||
.Fn => {
|
||||
return format(context, Errors, output, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
|
||||
return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
|
||||
},
|
||||
.Type => return output(context, @typeName(T)),
|
||||
.Type => return out_stream.writeAll(@typeName(T)),
|
||||
.EnumLiteral => {
|
||||
const buffer = [_]u8{'.'} ++ @tagName(value);
|
||||
return formatType(buffer, fmt, options, context, Errors, output, max_depth);
|
||||
return formatType(buffer, fmt, options, out_stream, max_depth);
|
||||
},
|
||||
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
@@ -503,21 +483,19 @@ fn formatValue(
|
||||
value: var,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
if (comptime std.mem.eql(u8, fmt, "B")) {
|
||||
return formatBytes(value, options, 1000, context, Errors, output);
|
||||
return formatBytes(value, options, 1000, out_stream);
|
||||
} else if (comptime std.mem.eql(u8, fmt, "Bi")) {
|
||||
return formatBytes(value, options, 1024, context, Errors, output);
|
||||
return formatBytes(value, options, 1024, out_stream);
|
||||
}
|
||||
|
||||
const T = @TypeOf(value);
|
||||
switch (@typeInfo(T)) {
|
||||
.Float => return formatFloatValue(value, fmt, options, context, Errors, output),
|
||||
.Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output),
|
||||
.Bool => return output(context, if (value) "true" else "false"),
|
||||
.Float => return formatFloatValue(value, fmt, options, out_stream),
|
||||
.Int, .ComptimeInt => return formatIntValue(value, fmt, options, out_stream),
|
||||
.Bool => return out_stream.writeAll(if (value) "true" else "false"),
|
||||
else => comptime unreachable,
|
||||
}
|
||||
}
|
||||
@@ -526,10 +504,8 @@ pub fn formatIntValue(
|
||||
value: var,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
comptime var radix = 10;
|
||||
comptime var uppercase = false;
|
||||
|
||||
@@ -544,7 +520,7 @@ pub fn formatIntValue(
|
||||
uppercase = false;
|
||||
} else if (comptime std.mem.eql(u8, fmt, "c")) {
|
||||
if (@TypeOf(int_value).bit_count <= 8) {
|
||||
return formatAsciiChar(@as(u8, int_value), options, context, Errors, output);
|
||||
return formatAsciiChar(@as(u8, int_value), options, out_stream);
|
||||
} else {
|
||||
@compileError("Cannot print integer that is larger than 8 bits as a ascii");
|
||||
}
|
||||
@@ -561,21 +537,19 @@ pub fn formatIntValue(
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
}
|
||||
|
||||
return formatInt(int_value, radix, uppercase, options, context, Errors, output);
|
||||
return formatInt(int_value, radix, uppercase, options, out_stream);
|
||||
}
|
||||
|
||||
fn formatFloatValue(
|
||||
value: var,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
|
||||
return formatFloatScientific(value, options, context, Errors, output);
|
||||
return formatFloatScientific(value, options, out_stream);
|
||||
} else if (comptime std.mem.eql(u8, fmt, "d")) {
|
||||
return formatFloatDecimal(value, options, context, Errors, output);
|
||||
return formatFloatDecimal(value, options, out_stream);
|
||||
} else {
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
}
|
||||
@@ -585,17 +559,15 @@ pub fn formatText(
|
||||
bytes: []const u8,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
if (fmt.len == 0) {
|
||||
return output(context, bytes);
|
||||
return out_stream.writeAll(bytes);
|
||||
} else if (comptime std.mem.eql(u8, fmt, "s")) {
|
||||
return formatBuf(bytes, options, context, Errors, output);
|
||||
return formatBuf(bytes, options, out_stream);
|
||||
} else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
|
||||
for (bytes) |c| {
|
||||
try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, context, Errors, output);
|
||||
try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, out_stream);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
@@ -606,27 +578,23 @@ pub fn formatText(
|
||||
pub fn formatAsciiChar(
|
||||
c: u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
return output(context, @as(*const [1]u8, &c)[0..]);
|
||||
out_stream: var,
|
||||
) !void {
|
||||
return out_stream.writeAll(@as(*const [1]u8, &c));
|
||||
}
|
||||
|
||||
pub fn formatBuf(
|
||||
buf: []const u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
try output(context, buf);
|
||||
out_stream: var,
|
||||
) !void {
|
||||
try out_stream.writeAll(buf);
|
||||
|
||||
const width = options.width orelse 0;
|
||||
var leftover_padding = if (width > buf.len) (width - buf.len) else return;
|
||||
const pad_byte: u8 = options.fill;
|
||||
const pad_byte = [1]u8{options.fill};
|
||||
while (leftover_padding > 0) : (leftover_padding -= 1) {
|
||||
try output(context, @as(*const [1]u8, &pad_byte)[0..1]);
|
||||
try out_stream.writeAll(&pad_byte);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,40 +604,38 @@ pub fn formatBuf(
|
||||
pub fn formatFloatScientific(
|
||||
value: var,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
var x = @floatCast(f64, value);
|
||||
|
||||
// Errol doesn't handle these special cases.
|
||||
if (math.signbit(x)) {
|
||||
try output(context, "-");
|
||||
try out_stream.writeAll("-");
|
||||
x = -x;
|
||||
}
|
||||
|
||||
if (math.isNan(x)) {
|
||||
return output(context, "nan");
|
||||
return out_stream.writeAll("nan");
|
||||
}
|
||||
if (math.isPositiveInf(x)) {
|
||||
return output(context, "inf");
|
||||
return out_stream.writeAll("inf");
|
||||
}
|
||||
if (x == 0.0) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
|
||||
if (options.precision) |precision| {
|
||||
if (precision != 0) {
|
||||
try output(context, ".");
|
||||
try out_stream.writeAll(".");
|
||||
var i: usize = 0;
|
||||
while (i < precision) : (i += 1) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try output(context, ".0");
|
||||
try out_stream.writeAll(".0");
|
||||
}
|
||||
|
||||
try output(context, "e+00");
|
||||
try out_stream.writeAll("e+00");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -679,50 +645,50 @@ pub fn formatFloatScientific(
|
||||
if (options.precision) |precision| {
|
||||
errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
|
||||
|
||||
try output(context, float_decimal.digits[0..1]);
|
||||
try out_stream.writeAll(float_decimal.digits[0..1]);
|
||||
|
||||
// {e0} case prints no `.`
|
||||
if (precision != 0) {
|
||||
try output(context, ".");
|
||||
try out_stream.writeAll(".");
|
||||
|
||||
var printed: usize = 0;
|
||||
if (float_decimal.digits.len > 1) {
|
||||
const num_digits = math.min(float_decimal.digits.len, precision + 1);
|
||||
try output(context, float_decimal.digits[1..num_digits]);
|
||||
try out_stream.writeAll(float_decimal.digits[1..num_digits]);
|
||||
printed += num_digits - 1;
|
||||
}
|
||||
|
||||
while (printed < precision) : (printed += 1) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try output(context, float_decimal.digits[0..1]);
|
||||
try output(context, ".");
|
||||
try out_stream.writeAll(float_decimal.digits[0..1]);
|
||||
try out_stream.writeAll(".");
|
||||
if (float_decimal.digits.len > 1) {
|
||||
const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;
|
||||
|
||||
try output(context, float_decimal.digits[1..num_digits]);
|
||||
try out_stream.writeAll(float_decimal.digits[1..num_digits]);
|
||||
} else {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
}
|
||||
|
||||
try output(context, "e");
|
||||
try out_stream.writeAll("e");
|
||||
const exp = float_decimal.exp - 1;
|
||||
|
||||
if (exp >= 0) {
|
||||
try output(context, "+");
|
||||
try out_stream.writeAll("+");
|
||||
if (exp > -10 and exp < 10) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
|
||||
try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
|
||||
} else {
|
||||
try output(context, "-");
|
||||
try out_stream.writeAll("-");
|
||||
if (exp > -10 and exp < 10) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
|
||||
try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,36 +697,34 @@ pub fn formatFloatScientific(
|
||||
pub fn formatFloatDecimal(
|
||||
value: var,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
var x = @as(f64, value);
|
||||
|
||||
// Errol doesn't handle these special cases.
|
||||
if (math.signbit(x)) {
|
||||
try output(context, "-");
|
||||
try out_stream.writeAll("-");
|
||||
x = -x;
|
||||
}
|
||||
|
||||
if (math.isNan(x)) {
|
||||
return output(context, "nan");
|
||||
return out_stream.writeAll("nan");
|
||||
}
|
||||
if (math.isPositiveInf(x)) {
|
||||
return output(context, "inf");
|
||||
return out_stream.writeAll("inf");
|
||||
}
|
||||
if (x == 0.0) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
|
||||
if (options.precision) |precision| {
|
||||
if (precision != 0) {
|
||||
try output(context, ".");
|
||||
try out_stream.writeAll(".");
|
||||
var i: usize = 0;
|
||||
while (i < precision) : (i += 1) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
} else {
|
||||
try output(context, ".0");
|
||||
try out_stream.writeAll(".0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,14 +746,14 @@ pub fn formatFloatDecimal(
|
||||
|
||||
if (num_digits_whole > 0) {
|
||||
// We may have to zero pad, for instance 1e4 requires zero padding.
|
||||
try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
|
||||
var i = num_digits_whole_no_pad;
|
||||
while (i < num_digits_whole) : (i += 1) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
} else {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
|
||||
// {.0} special case doesn't want a trailing '.'
|
||||
@@ -797,7 +761,7 @@ pub fn formatFloatDecimal(
|
||||
return;
|
||||
}
|
||||
|
||||
try output(context, ".");
|
||||
try out_stream.writeAll(".");
|
||||
|
||||
// Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
|
||||
var printed: usize = 0;
|
||||
@@ -809,7 +773,7 @@ pub fn formatFloatDecimal(
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < zeros_to_print) : (i += 1) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
printed += 1;
|
||||
}
|
||||
|
||||
@@ -821,14 +785,14 @@ pub fn formatFloatDecimal(
|
||||
// Remaining fractional portion, zero-padding if insufficient.
|
||||
assert(precision >= printed);
|
||||
if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
|
||||
try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
|
||||
return;
|
||||
} else {
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
printed += float_decimal.digits.len - num_digits_whole_no_pad;
|
||||
|
||||
while (printed < precision) : (printed += 1) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -840,14 +804,14 @@ pub fn formatFloatDecimal(
|
||||
|
||||
if (num_digits_whole > 0) {
|
||||
// We may have to zero pad, for instance 1e4 requires zero padding.
|
||||
try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
|
||||
|
||||
var i = num_digits_whole_no_pad;
|
||||
while (i < num_digits_whole) : (i += 1) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
} else {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
|
||||
// Omit `.` if no fractional portion
|
||||
@@ -855,7 +819,7 @@ pub fn formatFloatDecimal(
|
||||
return;
|
||||
}
|
||||
|
||||
try output(context, ".");
|
||||
try out_stream.writeAll(".");
|
||||
|
||||
// Zero-fill until we reach significant digits or run out of precision.
|
||||
if (float_decimal.exp < 0) {
|
||||
@@ -863,11 +827,11 @@ pub fn formatFloatDecimal(
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < zero_digit_count) : (i += 1) {
|
||||
try output(context, "0");
|
||||
try out_stream.writeAll("0");
|
||||
}
|
||||
}
|
||||
|
||||
try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -875,12 +839,10 @@ pub fn formatBytes(
|
||||
value: var,
|
||||
options: FormatOptions,
|
||||
comptime radix: usize,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
if (value == 0) {
|
||||
return output(context, "0B");
|
||||
return out_stream.writeAll("0B");
|
||||
}
|
||||
|
||||
const mags_si = " kMGTPEZY";
|
||||
@@ -897,10 +859,10 @@ pub fn formatBytes(
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
try formatFloatDecimal(new_value, options, context, Errors, output);
|
||||
try formatFloatDecimal(new_value, options, out_stream);
|
||||
|
||||
if (suffix == ' ') {
|
||||
return output(context, "B");
|
||||
return out_stream.writeAll("B");
|
||||
}
|
||||
|
||||
const buf = switch (radix) {
|
||||
@@ -908,7 +870,7 @@ pub fn formatBytes(
|
||||
1024 => &[_]u8{ suffix, 'i', 'B' },
|
||||
else => unreachable,
|
||||
};
|
||||
return output(context, buf);
|
||||
return out_stream.writeAll(buf);
|
||||
}
|
||||
|
||||
pub fn formatInt(
|
||||
@@ -916,10 +878,8 @@ pub fn formatInt(
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
const int_value = if (@TypeOf(value) == comptime_int) blk: {
|
||||
const Int = math.IntFittingRange(value, value);
|
||||
break :blk @as(Int, value);
|
||||
@@ -927,9 +887,9 @@ pub fn formatInt(
|
||||
value;
|
||||
|
||||
if (@TypeOf(int_value).is_signed) {
|
||||
return formatIntSigned(int_value, base, uppercase, options, context, Errors, output);
|
||||
return formatIntSigned(int_value, base, uppercase, options, out_stream);
|
||||
} else {
|
||||
return formatIntUnsigned(int_value, base, uppercase, options, context, Errors, output);
|
||||
return formatIntUnsigned(int_value, base, uppercase, options, out_stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,10 +898,8 @@ fn formatIntSigned(
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
const new_options = FormatOptions{
|
||||
.width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
|
||||
.precision = options.precision,
|
||||
@@ -950,15 +908,15 @@ fn formatIntSigned(
|
||||
const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
|
||||
const Uint = std.meta.IntType(false, bit_count);
|
||||
if (value < 0) {
|
||||
try output(context, "-");
|
||||
try out_stream.writeAll("-");
|
||||
const new_value = math.absCast(value);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
|
||||
} else if (options.width == null or options.width.? == 0) {
|
||||
return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, context, Errors, output);
|
||||
return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, out_stream);
|
||||
} else {
|
||||
try output(context, "+");
|
||||
try out_stream.writeAll("+");
|
||||
const new_value = @intCast(Uint, value);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -967,10 +925,8 @@ fn formatIntUnsigned(
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
assert(base >= 2);
|
||||
var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
|
||||
const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count);
|
||||
@@ -994,34 +950,23 @@ fn formatIntUnsigned(
|
||||
const zero_byte: u8 = options.fill;
|
||||
var leftover_padding = padding - index;
|
||||
while (true) {
|
||||
try output(context, @as(*const [1]u8, &zero_byte)[0..]);
|
||||
try out_stream.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
|
||||
leftover_padding -= 1;
|
||||
if (leftover_padding == 0) break;
|
||||
}
|
||||
mem.set(u8, buf[0..index], options.fill);
|
||||
return output(context, &buf);
|
||||
return out_stream.writeAll(&buf);
|
||||
} else {
|
||||
const padded_buf = buf[index - padding ..];
|
||||
mem.set(u8, padded_buf[0..padding], options.fill);
|
||||
return output(context, padded_buf);
|
||||
return out_stream.writeAll(padded_buf);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
|
||||
var context = FormatIntBuf{
|
||||
.out_buf = out_buf,
|
||||
.index = 0,
|
||||
};
|
||||
formatInt(value, base, uppercase, options, &context, error{}, formatIntCallback) catch unreachable;
|
||||
return context.index;
|
||||
}
|
||||
const FormatIntBuf = struct {
|
||||
out_buf: []u8,
|
||||
index: usize,
|
||||
};
|
||||
fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
|
||||
mem.copy(u8, context.out_buf[context.index..], bytes);
|
||||
context.index += bytes.len;
|
||||
var fbs = std.io.fixedBufferStream(out_buf);
|
||||
formatInt(value, base, uppercase, options, fbs.outStream()) catch unreachable;
|
||||
return fbs.pos;
|
||||
}
|
||||
|
||||
pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
|
||||
@@ -1121,44 +1066,36 @@ fn digitToChar(digit: u8, uppercase: bool) u8 {
|
||||
};
|
||||
}
|
||||
|
||||
const BufPrintContext = struct {
|
||||
remaining: []u8,
|
||||
};
|
||||
|
||||
fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
|
||||
if (context.remaining.len < bytes.len) {
|
||||
mem.copy(u8, context.remaining, bytes[0..context.remaining.len]);
|
||||
return error.BufferTooSmall;
|
||||
}
|
||||
mem.copy(u8, context.remaining, bytes);
|
||||
context.remaining = context.remaining[bytes.len..];
|
||||
}
|
||||
|
||||
pub const BufPrintError = error{
|
||||
/// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
|
||||
BufferTooSmall,
|
||||
NoSpaceLeft,
|
||||
};
|
||||
pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
|
||||
var context = BufPrintContext{ .remaining = buf };
|
||||
try format(&context, BufPrintError, bufPrintWrite, fmt, args);
|
||||
return buf[0 .. buf.len - context.remaining.len];
|
||||
var fbs = std.io.fixedBufferStream(buf);
|
||||
try format(fbs.outStream(), fmt, args);
|
||||
return fbs.getWritten();
|
||||
}
|
||||
|
||||
// Count the characters needed for format. Useful for preallocating memory
|
||||
pub fn count(comptime fmt: []const u8, args: var) u64 {
|
||||
var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
|
||||
format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
|
||||
return counting_stream.bytes_written;
|
||||
}
|
||||
|
||||
pub const AllocPrintError = error{OutOfMemory};
|
||||
|
||||
pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
|
||||
var size: usize = 0;
|
||||
format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
|
||||
const size = math.cast(usize, count(fmt, args)) catch |err| switch (err) {
|
||||
// Output too long. Can't possibly allocate enough memory to display it.
|
||||
error.Overflow => return error.OutOfMemory,
|
||||
};
|
||||
const buf = try allocator.alloc(u8, size);
|
||||
return bufPrint(buf, fmt, args) catch |err| switch (err) {
|
||||
error.BufferTooSmall => unreachable, // we just counted the size above
|
||||
error.NoSpaceLeft => unreachable, // we just counted the size above
|
||||
};
|
||||
}
|
||||
|
||||
fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
|
||||
size.* += bytes.len;
|
||||
}
|
||||
|
||||
pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
|
||||
const result = try allocPrint(allocator, fmt ++ "\x00", args);
|
||||
return result[0 .. result.len - 1 :0];
|
||||
@@ -1251,20 +1188,17 @@ test "int.padded" {
|
||||
test "buffer" {
|
||||
{
|
||||
var buf1: [32]u8 = undefined;
|
||||
var context = BufPrintContext{ .remaining = buf1[0..] };
|
||||
try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
|
||||
var res = buf1[0 .. buf1.len - context.remaining.len];
|
||||
std.testing.expect(mem.eql(u8, res, "1234"));
|
||||
var fbs = std.io.fixedBufferStream(&buf1);
|
||||
try formatType(1234, "", FormatOptions{}, fbs.outStream(), default_max_depth);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
|
||||
|
||||
context = BufPrintContext{ .remaining = buf1[0..] };
|
||||
try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
|
||||
res = buf1[0 .. buf1.len - context.remaining.len];
|
||||
std.testing.expect(mem.eql(u8, res, "a"));
|
||||
fbs.reset();
|
||||
try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "a"));
|
||||
|
||||
context = BufPrintContext{ .remaining = buf1[0..] };
|
||||
try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
|
||||
res = buf1[0 .. buf1.len - context.remaining.len];
|
||||
std.testing.expect(mem.eql(u8, res, "1100"));
|
||||
fbs.reset();
|
||||
try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1449,14 +1383,12 @@ test "custom" {
|
||||
self: SelfType,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
|
||||
return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });
|
||||
return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
|
||||
} else if (comptime std.mem.eql(u8, fmt, "d")) {
|
||||
return std.fmt.format(context, Errors, output, "{d:.3}x{d:.3}", .{ self.x, self.y });
|
||||
return std.fmt.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
|
||||
} else {
|
||||
@compileError("Unknown format character: '" ++ fmt ++ "'");
|
||||
}
|
||||
@@ -1640,10 +1572,10 @@ test "hexToBytes" {
|
||||
test "formatIntValue with comptime_int" {
|
||||
const value: comptime_int = 123456789123456789;
|
||||
|
||||
var buf = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer buf.deinit();
|
||||
try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
|
||||
std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
|
||||
var buf: [20]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
try formatIntValue(value, "", FormatOptions{}, fbs.outStream());
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789"));
|
||||
}
|
||||
|
||||
test "formatType max_depth" {
|
||||
@@ -1656,12 +1588,10 @@ test "formatType max_depth" {
|
||||
self: SelfType,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
if (fmt.len == 0) {
|
||||
return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });
|
||||
return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
|
||||
} else {
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
}
|
||||
@@ -1695,25 +1625,22 @@ test "formatType max_depth" {
|
||||
inst.a = &inst;
|
||||
inst.tu.ptr = &inst.tu;
|
||||
|
||||
var buf0 = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer buf0.deinit();
|
||||
try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
|
||||
std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
|
||||
var buf: [1000]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
try formatType(inst, "", FormatOptions{}, fbs.outStream(), 0);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));
|
||||
|
||||
var buf1 = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer buf1.deinit();
|
||||
try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
|
||||
std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
fbs.reset();
|
||||
try formatType(inst, "", FormatOptions{}, fbs.outStream(), 1);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
|
||||
var buf2 = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer buf2.deinit();
|
||||
try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
|
||||
std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
fbs.reset();
|
||||
try formatType(inst, "", FormatOptions{}, fbs.outStream(), 2);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
|
||||
var buf3 = std.ArrayList(u8).init(std.testing.allocator);
|
||||
defer buf3.deinit();
|
||||
try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
|
||||
std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
fbs.reset();
|
||||
try formatType(inst, "", FormatOptions{}, fbs.outStream(), 3);
|
||||
std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
|
||||
}
|
||||
|
||||
test "positional" {
|
||||
|
||||
@@ -350,15 +350,13 @@ pub const Headers = struct {
|
||||
self: Self,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
for (self.toSlice()) |entry| {
|
||||
try output(context, entry.name);
|
||||
try output(context, ": ");
|
||||
try output(context, entry.value);
|
||||
try output(context, "\n");
|
||||
try out_stream.writeAll(entry.name);
|
||||
try out_stream.writeAll(": ");
|
||||
try out_stream.writeAll(entry.value);
|
||||
try out_stream.writeAll("\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -103,7 +103,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
|
||||
return self.pos;
|
||||
}
|
||||
|
||||
pub fn getWritten(self: Self) []const u8 {
|
||||
pub fn getWritten(self: Self) Buffer {
|
||||
return self.buffer[0..self.pos];
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ pub fn OutStream(
|
||||
}
|
||||
|
||||
pub fn print(self: Self, comptime format: []const u8, args: var) Error!void {
|
||||
return std.fmt.format(self, Error, writeAll, format, args);
|
||||
return std.fmt.format(self, format, args);
|
||||
}
|
||||
|
||||
pub fn writeByte(self: Self, byte: u8) Error!void {
|
||||
|
||||
+72
-62
@@ -2252,45 +2252,43 @@ pub const StringifyOptions = struct {
|
||||
pub fn stringify(
|
||||
value: var,
|
||||
options: StringifyOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
out_stream: var,
|
||||
) !void {
|
||||
const T = @TypeOf(value);
|
||||
switch (@typeInfo(T)) {
|
||||
.Float, .ComptimeFloat => {
|
||||
return std.fmt.formatFloatScientific(value, std.fmt.FormatOptions{}, context, Errors, output);
|
||||
return std.fmt.formatFloatScientific(value, std.fmt.FormatOptions{}, out_stream);
|
||||
},
|
||||
.Int, .ComptimeInt => {
|
||||
return std.fmt.formatIntValue(value, "", std.fmt.FormatOptions{}, context, Errors, output);
|
||||
return std.fmt.formatIntValue(value, "", std.fmt.FormatOptions{}, out_stream);
|
||||
},
|
||||
.Bool => {
|
||||
return output(context, if (value) "true" else "false");
|
||||
return out_stream.writeAll(if (value) "true" else "false");
|
||||
},
|
||||
.Optional => {
|
||||
if (value) |payload| {
|
||||
return try stringify(payload, options, context, Errors, output);
|
||||
return try stringify(payload, options, out_stream);
|
||||
} else {
|
||||
return output(context, "null");
|
||||
return out_stream.writeAll("null");
|
||||
}
|
||||
},
|
||||
.Enum => {
|
||||
if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
|
||||
return value.jsonStringify(options, context, Errors, output);
|
||||
return value.jsonStringify(options, out_stream);
|
||||
}
|
||||
|
||||
@compileError("Unable to stringify enum '" ++ @typeName(T) ++ "'");
|
||||
},
|
||||
.Union => {
|
||||
if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
|
||||
return value.jsonStringify(options, context, Errors, output);
|
||||
return value.jsonStringify(options, out_stream);
|
||||
}
|
||||
|
||||
const info = @typeInfo(T).Union;
|
||||
if (info.tag_type) |UnionTagType| {
|
||||
inline for (info.fields) |u_field| {
|
||||
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
|
||||
return try stringify(@field(value, u_field.name), options, context, Errors, output);
|
||||
return try stringify(@field(value, u_field.name), options, out_stream);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2299,10 +2297,10 @@ pub fn stringify(
|
||||
},
|
||||
.Struct => |S| {
|
||||
if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
|
||||
return value.jsonStringify(options, context, Errors, output);
|
||||
return value.jsonStringify(options, out_stream);
|
||||
}
|
||||
|
||||
try output(context, "{");
|
||||
try out_stream.writeAll("{");
|
||||
comptime var field_output = false;
|
||||
inline for (S.fields) |Field, field_i| {
|
||||
// don't include void fields
|
||||
@@ -2311,39 +2309,39 @@ pub fn stringify(
|
||||
if (!field_output) {
|
||||
field_output = true;
|
||||
} else {
|
||||
try output(context, ",");
|
||||
try out_stream.writeAll(",");
|
||||
}
|
||||
|
||||
try stringify(Field.name, options, context, Errors, output);
|
||||
try output(context, ":");
|
||||
try stringify(@field(value, Field.name), options, context, Errors, output);
|
||||
try stringify(Field.name, options, out_stream);
|
||||
try out_stream.writeAll(":");
|
||||
try stringify(@field(value, Field.name), options, out_stream);
|
||||
}
|
||||
try output(context, "}");
|
||||
try out_stream.writeAll("}");
|
||||
return;
|
||||
},
|
||||
.Pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.One => {
|
||||
// TODO: avoid loops?
|
||||
return try stringify(value.*, options, context, Errors, output);
|
||||
return try stringify(value.*, options, out_stream);
|
||||
},
|
||||
// TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
|
||||
.Slice => {
|
||||
if (ptr_info.child == u8 and std.unicode.utf8ValidateSlice(value)) {
|
||||
try output(context, "\"");
|
||||
try out_stream.writeAll("\"");
|
||||
var i: usize = 0;
|
||||
while (i < value.len) : (i += 1) {
|
||||
switch (value[i]) {
|
||||
// normal ascii characters
|
||||
0x20...0x21, 0x23...0x2E, 0x30...0x5B, 0x5D...0x7F => try output(context, value[i .. i + 1]),
|
||||
0x20...0x21, 0x23...0x2E, 0x30...0x5B, 0x5D...0x7F => try out_stream.writeAll(value[i .. i + 1]),
|
||||
// control characters with short escapes
|
||||
'\\' => try output(context, "\\\\"),
|
||||
'\"' => try output(context, "\\\""),
|
||||
'/' => try output(context, "\\/"),
|
||||
0x8 => try output(context, "\\b"),
|
||||
0xC => try output(context, "\\f"),
|
||||
'\n' => try output(context, "\\n"),
|
||||
'\r' => try output(context, "\\r"),
|
||||
'\t' => try output(context, "\\t"),
|
||||
'\\' => try out_stream.writeAll("\\\\"),
|
||||
'\"' => try out_stream.writeAll("\\\""),
|
||||
'/' => try out_stream.writeAll("\\/"),
|
||||
0x8 => try out_stream.writeAll("\\b"),
|
||||
0xC => try out_stream.writeAll("\\f"),
|
||||
'\n' => try out_stream.writeAll("\\n"),
|
||||
'\r' => try out_stream.writeAll("\\r"),
|
||||
'\t' => try out_stream.writeAll("\\t"),
|
||||
else => {
|
||||
const ulen = std.unicode.utf8ByteSequenceLength(value[i]) catch unreachable;
|
||||
const codepoint = std.unicode.utf8Decode(value[i .. i + ulen]) catch unreachable;
|
||||
@@ -2351,40 +2349,40 @@ pub fn stringify(
|
||||
// If the character is in the Basic Multilingual Plane (U+0000 through U+FFFF),
|
||||
// then it may be represented as a six-character sequence: a reverse solidus, followed
|
||||
// by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point.
|
||||
try output(context, "\\u");
|
||||
try std.fmt.formatIntValue(codepoint, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output);
|
||||
try out_stream.writeAll("\\u");
|
||||
try std.fmt.formatIntValue(codepoint, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
|
||||
} else {
|
||||
// To escape an extended character that is not in the Basic Multilingual Plane,
|
||||
// the character is represented as a 12-character sequence, encoding the UTF-16 surrogate pair.
|
||||
const high = @intCast(u16, (codepoint - 0x10000) >> 10) + 0xD800;
|
||||
const low = @intCast(u16, codepoint & 0x3FF) + 0xDC00;
|
||||
try output(context, "\\u");
|
||||
try std.fmt.formatIntValue(high, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output);
|
||||
try output(context, "\\u");
|
||||
try std.fmt.formatIntValue(low, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output);
|
||||
try out_stream.writeAll("\\u");
|
||||
try std.fmt.formatIntValue(high, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
|
||||
try out_stream.writeAll("\\u");
|
||||
try std.fmt.formatIntValue(low, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
|
||||
}
|
||||
i += ulen - 1;
|
||||
},
|
||||
}
|
||||
}
|
||||
try output(context, "\"");
|
||||
try out_stream.writeAll("\"");
|
||||
return;
|
||||
}
|
||||
|
||||
try output(context, "[");
|
||||
try out_stream.writeAll("[");
|
||||
for (value) |x, i| {
|
||||
if (i != 0) {
|
||||
try output(context, ",");
|
||||
try out_stream.writeAll(",");
|
||||
}
|
||||
try stringify(x, options, context, Errors, output);
|
||||
try stringify(x, options, out_stream);
|
||||
}
|
||||
try output(context, "]");
|
||||
try out_stream.writeAll("]");
|
||||
return;
|
||||
},
|
||||
else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
|
||||
},
|
||||
.Array => |info| {
|
||||
return try stringify(value[0..], options, context, Errors, output);
|
||||
return try stringify(value[0..], options, out_stream);
|
||||
},
|
||||
else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
@@ -2392,10 +2390,26 @@ pub fn stringify(
|
||||
}
|
||||
|
||||
fn teststringify(expected: []const u8, value: var) !void {
|
||||
const TestStringifyContext = struct {
|
||||
const ValidationOutStream = struct {
|
||||
const Self = @This();
|
||||
pub const OutStream = std.io.OutStream(*Self, Error, write);
|
||||
pub const Error = error{
|
||||
TooMuchData,
|
||||
DifferentData,
|
||||
};
|
||||
|
||||
expected_remaining: []const u8,
|
||||
fn testStringifyWrite(context: *@This(), bytes: []const u8) !void {
|
||||
if (context.expected_remaining.len < bytes.len) {
|
||||
|
||||
fn init(exp: []const u8) Self {
|
||||
return .{ .expected_remaining = exp };
|
||||
}
|
||||
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
fn write(self: *Self, bytes: []const u8) Error!usize {
|
||||
if (self.expected_remaining.len < bytes.len) {
|
||||
std.debug.warn(
|
||||
\\====== expected this output: =========
|
||||
\\{}
|
||||
@@ -2403,12 +2417,12 @@ fn teststringify(expected: []const u8, value: var) !void {
|
||||
\\{}
|
||||
\\======================================
|
||||
, .{
|
||||
context.expected_remaining,
|
||||
self.expected_remaining,
|
||||
bytes,
|
||||
});
|
||||
return error.TooMuchData;
|
||||
}
|
||||
if (!mem.eql(u8, context.expected_remaining[0..bytes.len], bytes)) {
|
||||
if (!mem.eql(u8, self.expected_remaining[0..bytes.len], bytes)) {
|
||||
std.debug.warn(
|
||||
\\====== expected this output: =========
|
||||
\\{}
|
||||
@@ -2416,21 +2430,19 @@ fn teststringify(expected: []const u8, value: var) !void {
|
||||
\\{}
|
||||
\\======================================
|
||||
, .{
|
||||
context.expected_remaining[0..bytes.len],
|
||||
self.expected_remaining[0..bytes.len],
|
||||
bytes,
|
||||
});
|
||||
return error.DifferentData;
|
||||
}
|
||||
context.expected_remaining = context.expected_remaining[bytes.len..];
|
||||
self.expected_remaining = self.expected_remaining[bytes.len..];
|
||||
return bytes.len;
|
||||
}
|
||||
};
|
||||
var buf: [100]u8 = undefined;
|
||||
var context = TestStringifyContext{ .expected_remaining = expected };
|
||||
try stringify(value, StringifyOptions{}, &context, error{
|
||||
TooMuchData,
|
||||
DifferentData,
|
||||
}, TestStringifyContext.testStringifyWrite);
|
||||
if (context.expected_remaining.len > 0) return error.NotEnoughData;
|
||||
|
||||
var vos = ValidationOutStream.init(expected);
|
||||
try stringify(value, StringifyOptions{}, vos.outStream());
|
||||
if (vos.expected_remaining.len > 0) return error.NotEnoughData;
|
||||
}
|
||||
|
||||
test "stringify basic types" {
|
||||
@@ -2498,13 +2510,11 @@ test "stringify struct with custom stringifier" {
|
||||
pub fn jsonStringify(
|
||||
value: Self,
|
||||
options: StringifyOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
out_stream: var,
|
||||
) !void {
|
||||
try output(context, "[\"something special\",");
|
||||
try stringify(42, options, context, Errors, output);
|
||||
try output(context, "]");
|
||||
try out_stream.writeAll("[\"something special\",");
|
||||
try stringify(42, options, out_stream);
|
||||
try out_stream.writeAll("]");
|
||||
}
|
||||
}{ .foo = 42 });
|
||||
}
|
||||
|
||||
@@ -519,16 +519,14 @@ pub const Int = struct {
|
||||
self: Int,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
context: var,
|
||||
comptime FmtError: type,
|
||||
output: fn (@TypeOf(context), []const u8) FmtError!void,
|
||||
out_stream: var,
|
||||
) FmtError!void {
|
||||
self.assertWritable();
|
||||
// TODO look at fmt and support other bases
|
||||
// TODO support read-only fixed integers
|
||||
const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating");
|
||||
defer self.allocator.?.free(str);
|
||||
return output(context, str);
|
||||
return out_stream.print(str);
|
||||
}
|
||||
|
||||
/// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
|
||||
|
||||
+9
-11
@@ -269,15 +269,13 @@ pub const Address = extern union {
|
||||
self: Address,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
out_stream: var,
|
||||
) !void {
|
||||
switch (self.any.family) {
|
||||
os.AF_INET => {
|
||||
const port = mem.bigToNative(u16, self.in.port);
|
||||
const bytes = @ptrCast(*const [4]u8, &self.in.addr);
|
||||
try std.fmt.format(context, Errors, output, "{}.{}.{}.{}:{}", .{
|
||||
try std.fmt.format(out_stream, "{}.{}.{}.{}:{}", .{
|
||||
bytes[0],
|
||||
bytes[1],
|
||||
bytes[2],
|
||||
@@ -288,7 +286,7 @@ pub const Address = extern union {
|
||||
os.AF_INET6 => {
|
||||
const port = mem.bigToNative(u16, self.in6.port);
|
||||
if (mem.eql(u8, self.in6.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {
|
||||
try std.fmt.format(context, Errors, output, "[::ffff:{}.{}.{}.{}]:{}", .{
|
||||
try std.fmt.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{
|
||||
self.in6.addr[12],
|
||||
self.in6.addr[13],
|
||||
self.in6.addr[14],
|
||||
@@ -308,30 +306,30 @@ pub const Address = extern union {
|
||||
break :blk buf;
|
||||
},
|
||||
};
|
||||
try output(context, "[");
|
||||
try out_stream.writeAll("[");
|
||||
var i: usize = 0;
|
||||
var abbrv = false;
|
||||
while (i < native_endian_parts.len) : (i += 1) {
|
||||
if (native_endian_parts[i] == 0) {
|
||||
if (!abbrv) {
|
||||
try output(context, if (i == 0) "::" else ":");
|
||||
try out_stream.writeAll(if (i == 0) "::" else ":");
|
||||
abbrv = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
try std.fmt.format(context, Errors, output, "{x}", .{native_endian_parts[i]});
|
||||
try std.fmt.format(out_stream, "{x}", .{native_endian_parts[i]});
|
||||
if (i != native_endian_parts.len - 1) {
|
||||
try output(context, ":");
|
||||
try out_stream.writeAll(":");
|
||||
}
|
||||
}
|
||||
try std.fmt.format(context, Errors, output, "]:{}", .{port});
|
||||
try std.fmt.format(out_stream, "]:{}", .{port});
|
||||
},
|
||||
os.AF_UNIX => {
|
||||
if (!has_unix_sockets) {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
try std.fmt.format(context, Errors, output, "{}", .{&self.un.path});
|
||||
try std.fmt.format(out_stream, "{}", .{&self.un.path});
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
+3
-7
@@ -5,8 +5,6 @@ pub const protocols = @import("uefi/protocols.zig");
|
||||
pub const Status = @import("uefi/status.zig").Status;
|
||||
pub const tables = @import("uefi/tables.zig");
|
||||
|
||||
const fmt = @import("std").fmt;
|
||||
|
||||
/// The EFI image's handle that is passed to its entry point.
|
||||
pub var handle: Handle = undefined;
|
||||
|
||||
@@ -29,13 +27,11 @@ pub const Guid = extern struct {
|
||||
pub fn format(
|
||||
self: @This(),
|
||||
comptime f: []const u8,
|
||||
options: fmt.FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Errors!void,
|
||||
options: std.fmt.FormatOptions,
|
||||
out_stream: var,
|
||||
) Errors!void {
|
||||
if (f.len == 0) {
|
||||
return fmt.format(context, Errors, output, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
|
||||
return std.fmt.format(out_stream, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
|
||||
self.time_low,
|
||||
self.time_mid,
|
||||
self.time_high_and_version,
|
||||
|
||||
@@ -190,7 +190,7 @@ pub const Progress = struct {
|
||||
end.* += amt;
|
||||
self.columns_written += amt;
|
||||
} else |err| switch (err) {
|
||||
error.BufferTooSmall => {
|
||||
error.NoSpaceLeft => {
|
||||
self.columns_written += self.output_buffer.len - end.*;
|
||||
end.* = self.output_buffer.len;
|
||||
},
|
||||
|
||||
@@ -504,22 +504,22 @@ pub const CrossTarget = struct {
|
||||
if (self.os_version_min != null or self.os_version_max != null) {
|
||||
switch (self.getOsVersionMin()) {
|
||||
.none => {},
|
||||
.semver => |v| try result.print(".{}", .{v}),
|
||||
.windows => |v| try result.print(".{}", .{@tagName(v)}),
|
||||
.semver => |v| try result.outStream().print(".{}", .{v}),
|
||||
.windows => |v| try result.outStream().print(".{}", .{@tagName(v)}),
|
||||
}
|
||||
}
|
||||
if (self.os_version_max) |max| {
|
||||
switch (max) {
|
||||
.none => {},
|
||||
.semver => |v| try result.print("...{}", .{v}),
|
||||
.windows => |v| try result.print("...{}", .{@tagName(v)}),
|
||||
.semver => |v| try result.outStream().print("...{}", .{v}),
|
||||
.windows => |v| try result.outStream().print("...{}", .{@tagName(v)}),
|
||||
}
|
||||
}
|
||||
|
||||
if (self.glibc_version) |v| {
|
||||
try result.print("-{}.{}", .{ @tagName(self.getAbi()), v });
|
||||
try result.outStream().print("-{}.{}", .{ @tagName(self.getAbi()), v });
|
||||
} else if (self.abi) |abi| {
|
||||
try result.print("-{}", .{@tagName(abi)});
|
||||
try result.outStream().print("-{}", .{@tagName(abi)});
|
||||
}
|
||||
|
||||
return result.toOwnedSlice();
|
||||
|
||||
@@ -306,12 +306,12 @@ pub const Tokenizer = struct {
|
||||
|
||||
fn errorPosition(self: *Tokenizer, position: usize, bytes: []const u8, comptime fmt: []const u8, args: var) Error {
|
||||
var buffer = try std.Buffer.initSize(&self.arena.allocator, 0);
|
||||
std.fmt.format(&buffer, anyerror, std.Buffer.append, fmt, args) catch {};
|
||||
try buffer.outStream().print(fmt, args);
|
||||
try buffer.append(" '");
|
||||
var out = makeOutput(std.Buffer.append, &buffer);
|
||||
try printCharValues(&out, bytes);
|
||||
try buffer.append("'");
|
||||
std.fmt.format(&buffer, anyerror, std.Buffer.append, " at position {}", .{position - (bytes.len - 1)}) catch {};
|
||||
try buffer.outStream().print(" at position {}", .{position - (bytes.len - 1)});
|
||||
self.error_text = buffer.toSlice();
|
||||
return Error.InvalidInput;
|
||||
}
|
||||
@@ -319,10 +319,9 @@ pub const Tokenizer = struct {
|
||||
fn errorIllegalChar(self: *Tokenizer, position: usize, char: u8, comptime fmt: []const u8, args: var) Error {
|
||||
var buffer = try std.Buffer.initSize(&self.arena.allocator, 0);
|
||||
try buffer.append("illegal char ");
|
||||
var out = makeOutput(std.Buffer.append, &buffer);
|
||||
try printUnderstandableChar(&out, char);
|
||||
std.fmt.format(&buffer, anyerror, std.Buffer.append, " at position {}", .{position}) catch {};
|
||||
if (fmt.len != 0) std.fmt.format(&buffer, anyerror, std.Buffer.append, ": " ++ fmt, args) catch {};
|
||||
try printUnderstandableChar(&buffer, char);
|
||||
try buffer.outStream().print(" at position {}", .{position});
|
||||
if (fmt.len != 0) try buffer.outStream().print(": " ++ fmt, args);
|
||||
self.error_text = buffer.toSlice();
|
||||
return Error.InvalidInput;
|
||||
}
|
||||
@@ -996,14 +995,13 @@ fn printCharValues(out: var, bytes: []const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn printUnderstandableChar(out: var, char: u8) !void {
|
||||
fn printUnderstandableChar(buffer: *std.Buffer, char: u8) !void {
|
||||
if (!std.ascii.isPrint(char) or char == ' ') {
|
||||
const output = @typeInfo(@TypeOf(out)).Pointer.child.output;
|
||||
std.fmt.format(out.context, anyerror, output, "\\x{X:2}", .{char}) catch {};
|
||||
try buffer.outStream().print("\\x{X:2}", .{char});
|
||||
} else {
|
||||
try out.write("'");
|
||||
try out.write(&[_]u8{printable_char_tab[char]});
|
||||
try out.write("'");
|
||||
try buffer.append("'");
|
||||
try buffer.appendByte(printable_char_tab[char]);
|
||||
try buffer.append("'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1019,7 +1019,7 @@ const Stage2Target = extern struct {
|
||||
.macosx,
|
||||
.netbsd,
|
||||
.openbsd,
|
||||
=> try os_builtin_str_buffer.print(
|
||||
=> try os_builtin_str_buffer.outStream().print(
|
||||
\\ .semver = .{{
|
||||
\\ .min = .{{
|
||||
\\ .major = {},
|
||||
@@ -1043,7 +1043,7 @@ const Stage2Target = extern struct {
|
||||
target.os.version_range.semver.max.patch,
|
||||
}),
|
||||
|
||||
.linux => try os_builtin_str_buffer.print(
|
||||
.linux => try os_builtin_str_buffer.outStream().print(
|
||||
\\ .linux = .{{
|
||||
\\ .range = .{{
|
||||
\\ .min = .{{
|
||||
@@ -1078,7 +1078,7 @@ const Stage2Target = extern struct {
|
||||
target.os.version_range.linux.glibc.patch,
|
||||
}),
|
||||
|
||||
.windows => try os_builtin_str_buffer.print(
|
||||
.windows => try os_builtin_str_buffer.outStream().print(
|
||||
\\ .windows = .{{
|
||||
\\ .min = .{},
|
||||
\\ .max = .{},
|
||||
|
||||
@@ -4752,15 +4752,10 @@ fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenInd
|
||||
}
|
||||
|
||||
fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: var) !ast.TokenIndex {
|
||||
const S = struct {
|
||||
fn callback(context: *Context, bytes: []const u8) error{OutOfMemory}!void {
|
||||
return context.source_buffer.append(bytes);
|
||||
}
|
||||
};
|
||||
const start_index = c.source_buffer.len();
|
||||
errdefer c.source_buffer.shrink(start_index);
|
||||
|
||||
try std.fmt.format(c, error{OutOfMemory}, S.callback, format, args);
|
||||
try c.source_buffer.outStream().print(format, args);
|
||||
const end_index = c.source_buffer.len();
|
||||
const token_index = c.tree.tokens.len;
|
||||
const new_token = try c.tree.tokens.addOne();
|
||||
|
||||
Reference in New Issue
Block a user