authorgravatar for benjamin.feng@glassdoor.comBenjamin Feng <benjamin.feng@glassdoor.com> 2020-02-29 11:59:37-06:00
committergravatar for benjamin.feng@glassdoor.comBenjamin Feng <benjamin.feng@glassdoor.com> 2020-03-12 09:04:18-05:00
log278b9ec1aaabb8bcfbbf9c964012dc5bd2ad154a
tree58a9426d91f6e1e9bb48697d3ddd21a434ad32c3
parentae3fb6df007807a37fe448fdef2b8ee669b29a5a

Blind translation


1 files changed, 170 insertions(+), 206 deletions(-)

lib/std/fmtstream.zig+170-206
...@@ -69,19 +69,17 @@ fn peekIsAlign(comptime fmt: []const u8) bool {...@@ -69,19 +69,17 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
69///69///
70/// If a formatted user type contains a function of the type70/// If a formatted user type contains a function of the type
71/// ```71/// ```
72/// 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!void72/// fn format(value: ?, comptime fmt: []const u8, options: std.fmtstream.FormatOptions, out_stream: var) !void
73/// ```73/// ```
74/// with `?` being the type formatted, this function will be called instead of the default implementation.74/// with `?` being the type formatted, this function will be called instead of the default implementation.
75/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.75/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
76///76///
77/// A user type may be a `struct`, `vector`, `union` or `enum` type.77/// A user type may be a `struct`, `vector`, `union` or `enum` type.
78pub fn format(78pub fn format(
79 context: var,79 out_stream: var,
80 comptime Errors: type,
81 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
82 comptime fmt: []const u8,80 comptime fmt: []const u8,
83 args: var,81 args: var,
84) Errors!void {82) !void {
85 const ArgSetType = u32;83 const ArgSetType = u32;
86 if (@typeInfo(@TypeOf(args)) != .Struct) {84 if (@typeInfo(@TypeOf(args)) != .Struct) {
87 @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));85 @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
...@@ -138,7 +136,7 @@ pub fn format(...@@ -138,7 +136,7 @@ pub fn format(
138 .Start => switch (c) {136 .Start => switch (c) {
139 '{' => {137 '{' => {
140 if (start_index < i) {138 if (start_index < i) {
141 try output(context, fmt[start_index..i]);139 try out_stream.writeAll(fmt[start_index..i]);
142 }140 }
143141
144 start_index = i;142 start_index = i;
...@@ -150,7 +148,7 @@ pub fn format(...@@ -150,7 +148,7 @@ pub fn format(
150 },148 },
151 '}' => {149 '}' => {
152 if (start_index < i) {150 if (start_index < i) {
153 try output(context, fmt[start_index..i]);151 try out_stream.writeAll(fmt[start_index..i]);
154 }152 }
155 state = .CloseBrace;153 state = .CloseBrace;
156 },154 },
...@@ -185,9 +183,7 @@ pub fn format(...@@ -185,9 +183,7 @@ pub fn format(
185 args[arg_to_print],183 args[arg_to_print],
186 fmt[0..0],184 fmt[0..0],
187 options,185 options,
188 context,186 out_stream,
189 Errors,
190 output,
191 default_max_depth,187 default_max_depth,
192 );188 );
193189
...@@ -218,9 +214,7 @@ pub fn format(...@@ -218,9 +214,7 @@ pub fn format(
218 args[arg_to_print],214 args[arg_to_print],
219 fmt[specifier_start..i],215 fmt[specifier_start..i],
220 options,216 options,
221 context,217 out_stream,
222 Errors,
223 output,
224 default_max_depth,218 default_max_depth,
225 );219 );
226 state = .Start;220 state = .Start;
...@@ -265,9 +259,7 @@ pub fn format(...@@ -265,9 +259,7 @@ pub fn format(
265 args[arg_to_print],259 args[arg_to_print],
266 fmt[specifier_start..specifier_end],260 fmt[specifier_start..specifier_end],
267 options,261 options,
268 context,262 out_stream,
269 Errors,
270 output,
271 default_max_depth,263 default_max_depth,
272 );264 );
273 state = .Start;265 state = .Start;
...@@ -293,9 +285,7 @@ pub fn format(...@@ -293,9 +285,7 @@ pub fn format(
293 args[arg_to_print],285 args[arg_to_print],
294 fmt[specifier_start..specifier_end],286 fmt[specifier_start..specifier_end],
295 options,287 options,
296 context,288 out_stream,
297 Errors,
298 output,
299 default_max_depth,289 default_max_depth,
300 );290 );
301 state = .Start;291 state = .Start;
...@@ -316,7 +306,7 @@ pub fn format(...@@ -316,7 +306,7 @@ pub fn format(
316 }306 }
317 }307 }
318 if (start_index < fmt.len) {308 if (start_index < fmt.len) {
319 try output(context, fmt[start_index..]);309 try out_stream.writeAll(fmt[start_index..]);
320 }310 }
321}311}
322312
...@@ -324,121 +314,119 @@ pub fn formatType(...@@ -324,121 +314,119 @@ pub fn formatType(
324 value: var,314 value: var,
325 comptime fmt: []const u8,315 comptime fmt: []const u8,
326 options: FormatOptions,316 options: FormatOptions,
327 context: var,317 out_stream: var,
328 comptime Errors: type,
329 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
330 max_depth: usize,318 max_depth: usize,
331) Errors!void {319) !void {
332 if (comptime std.mem.eql(u8, fmt, "*")) {320 if (comptime std.mem.eql(u8, fmt, "*")) {
333 try output(context, @typeName(@TypeOf(value).Child));321 try out_stream.writeAll(@typeName(@TypeOf(value).Child));
334 try output(context, "@");322 try out_stream.writeAll("@");
335 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, context, Errors, output);323 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, out_stream);
336 return;324 return;
337 }325 }
338326
339 const T = @TypeOf(value);327 const T = @TypeOf(value);
340 switch (@typeInfo(T)) {328 switch (@typeInfo(T)) {
341 .ComptimeInt, .Int, .Float => {329 .ComptimeInt, .Int, .Float => {
342 return formatValue(value, fmt, options, context, Errors, output);330 return formatValue(value, fmt, options, out_stream);
343 },331 },
344 .Void => {332 .Void => {
345 return output(context, "void");333 return out_stream.writeAll("void");
346 },334 },
347 .Bool => {335 .Bool => {
348 return output(context, if (value) "true" else "false");336 return out_stream.writeAll(if (value) "true" else "false");
349 },337 },
350 .Optional => {338 .Optional => {
351 if (value) |payload| {339 if (value) |payload| {
352 return formatType(payload, fmt, options, context, Errors, output, max_depth);340 return formatType(payload, fmt, options, out_stream, max_depth);
353 } else {341 } else {
354 return output(context, "null");342 return out_stream.writeAll("null");
355 }343 }
356 },344 },
357 .ErrorUnion => {345 .ErrorUnion => {
358 if (value) |payload| {346 if (value) |payload| {
359 return formatType(payload, fmt, options, context, Errors, output, max_depth);347 return formatType(payload, fmt, options, out_stream, max_depth);
360 } else |err| {348 } else |err| {
361 return formatType(err, fmt, options, context, Errors, output, max_depth);349 return formatType(err, fmt, options, out_stream, max_depth);
362 }350 }
363 },351 },
364 .ErrorSet => {352 .ErrorSet => {
365 try output(context, "error.");353 try out_stream.writeAll("error.");
366 return output(context, @errorName(value));354 return out_stream.writeAll(@errorName(value));
367 },355 },
368 .Enum => |enumInfo| {356 .Enum => |enumInfo| {
369 if (comptime std.meta.trait.hasFn("format")(T)) {357 if (comptime std.meta.trait.hasFn("format")(T)) {
370 return value.format(fmt, options, context, Errors, output);358 return value.format(fmt, options, out_stream);
371 }359 }
372360
373 try output(context, @typeName(T));361 try out_stream.writeAll(@typeName(T));
374 if (enumInfo.is_exhaustive) {362 if (enumInfo.is_exhaustive) {
375 try output(context, ".");363 try out_stream.writeAll(".");
376 try output(context, @tagName(value));364 try out_stream.writeAll(@tagName(value));
377 } else {365 } else {
378 // TODO: when @tagName works on exhaustive enums print known enum strings366 // TODO: when @tagName works on exhaustive enums print known enum strings
379 try output(context, "(");367 try out_stream.writeAll("(");
380 try formatType(@enumToInt(value), fmt, options, context, Errors, output, max_depth);368 try formatType(@enumToInt(value), fmt, options, out_stream, max_depth);
381 try output(context, ")");369 try out_stream.writeAll(")");
382 }370 }
383 },371 },
384 .Union => {372 .Union => {
385 if (comptime std.meta.trait.hasFn("format")(T)) {373 if (comptime std.meta.trait.hasFn("format")(T)) {
386 return value.format(fmt, options, context, Errors, output);374 return value.format(fmt, options, out_stream);
387 }375 }
388376
389 try output(context, @typeName(T));377 try out_stream.writeAll(@typeName(T));
390 if (max_depth == 0) {378 if (max_depth == 0) {
391 return output(context, "{ ... }");379 return out_stream.writeAll("{ ... }");
392 }380 }
393 const info = @typeInfo(T).Union;381 const info = @typeInfo(T).Union;
394 if (info.tag_type) |UnionTagType| {382 if (info.tag_type) |UnionTagType| {
395 try output(context, "{ .");383 try out_stream.writeAll("{ .");
396 try output(context, @tagName(@as(UnionTagType, value)));384 try out_stream.writeAll(@tagName(@as(UnionTagType, value)));
397 try output(context, " = ");385 try out_stream.writeAll(" = ");
398 inline for (info.fields) |u_field| {386 inline for (info.fields) |u_field| {
399 if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {387 if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
400 try formatType(@field(value, u_field.name), fmt, options, context, Errors, output, max_depth - 1);388 try formatType(@field(value, u_field.name), fmt, options, out_stream, max_depth - 1);
401 }389 }
402 }390 }
403 try output(context, " }");391 try out_stream.writeAll(" }");
404 } else {392 } else {
405 try format(context, Errors, output, "@{x}", .{@ptrToInt(&value)});393 try format(out_stream, "@{x}", .{@ptrToInt(&value)});
406 }394 }
407 },395 },
408 .Struct => |StructT| {396 .Struct => |StructT| {
409 if (comptime std.meta.trait.hasFn("format")(T)) {397 if (comptime std.meta.trait.hasFn("format")(T)) {
410 return value.format(fmt, options, context, Errors, output);398 return value.format(fmt, options, out_stream);
411 }399 }
412400
413 try output(context, @typeName(T));401 try out_stream.writeAll(@typeName(T));
414 if (max_depth == 0) {402 if (max_depth == 0) {
415 return output(context, "{ ... }");403 return out_stream.writeAll("{ ... }");
416 }404 }
417 try output(context, "{");405 try out_stream.writeAll("{");
418 inline for (StructT.fields) |f, i| {406 inline for (StructT.fields) |f, i| {
419 if (i == 0) {407 if (i == 0) {
420 try output(context, " .");408 try out_stream.writeAll(" .");
421 } else {409 } else {
422 try output(context, ", .");410 try out_stream.writeAll(", .");
423 }411 }
424 try output(context, f.name);412 try out_stream.writeAll(f.name);
425 try output(context, " = ");413 try out_stream.writeAll(" = ");
426 try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);414 try formatType(@field(value, f.name), fmt, options, out_stream, max_depth - 1);
427 }415 }
428 try output(context, " }");416 try out_stream.writeAll(" }");
429 },417 },
430 .Pointer => |ptr_info| switch (ptr_info.size) {418 .Pointer => |ptr_info| switch (ptr_info.size) {
431 .One => switch (@typeInfo(ptr_info.child)) {419 .One => switch (@typeInfo(ptr_info.child)) {
432 .Array => |info| {420 .Array => |info| {
433 if (info.child == u8) {421 if (info.child == u8) {
434 return formatText(value, fmt, options, context, Errors, output);422 return formatText(value, fmt, options, out_stream);
435 }423 }
436 return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });424 return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
437 },425 },
438 .Enum, .Union, .Struct => {426 .Enum, .Union, .Struct => {
439 return formatType(value.*, fmt, options, context, Errors, output, max_depth);427 return formatType(value.*, fmt, options, out_stream, max_depth);
440 },428 },
441 else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),429 else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
442 },430 },
443 .Many, .C => {431 .Many, .C => {
444 if (ptr_info.sentinel) |sentinel| {432 if (ptr_info.sentinel) |sentinel| {
...@@ -446,19 +434,19 @@ pub fn formatType(...@@ -446,19 +434,19 @@ pub fn formatType(
446 }434 }
447 if (ptr_info.child == u8) {435 if (ptr_info.child == u8) {
448 if (fmt.len > 0 and fmt[0] == 's') {436 if (fmt.len > 0 and fmt[0] == 's') {
449 return formatText(mem.span(value), fmt, options, context, Errors, output);437 return formatText(mem.span(value), fmt, options, out_stream);
450 }438 }
451 }439 }
452 return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });440 return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
453 },441 },
454 .Slice => {442 .Slice => {
455 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {443 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
456 return formatText(value, fmt, options, context, Errors, output);444 return formatText(value, fmt, options, out_stream);
457 }445 }
458 if (ptr_info.child == u8) {446 if (ptr_info.child == u8) {
459 return formatText(value, fmt, options, context, Errors, output);447 return formatText(value, fmt, options, out_stream);
460 }448 }
461 return format(context, Errors, output, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });449 return format(out_stream, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
462 },450 },
463 },451 },
464 .Array => |info| {452 .Array => |info| {
...@@ -473,24 +461,24 @@ pub fn formatType(...@@ -473,24 +461,24 @@ pub fn formatType(
473 .sentinel = null,461 .sentinel = null,
474 },462 },
475 });463 });
476 return formatType(@as(Slice, &value), fmt, options, context, Errors, output, max_depth);464 return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth);
477 },465 },
478 .Vector => {466 .Vector => {
479 const len = @typeInfo(T).Vector.len;467 const len = @typeInfo(T).Vector.len;
480 try output(context, "{ ");468 try out_stream.writeAll("{ ");
481 var i: usize = 0;469 var i: usize = 0;
482 while (i < len) : (i += 1) {470 while (i < len) : (i += 1) {
483 try formatValue(value[i], fmt, options, context, Errors, output);471 try formatValue(value[i], fmt, options, out_stream);
484 if (i < len - 1) {472 if (i < len - 1) {
485 try output(context, ", ");473 try out_stream.writeAll(", ");
486 }474 }
487 }475 }
488 try output(context, " }");476 try out_stream.writeAll(" }");
489 },477 },
490 .Fn => {478 .Fn => {
491 return format(context, Errors, output, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });479 return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
492 },480 },
493 .Type => return output(context, @typeName(T)),481 .Type => return out_stream.writeAll(@typeName(T)),
494 .EnumLiteral => {482 .EnumLiteral => {
495 const buffer = [_]u8{'.'} ++ @tagName(value);483 const buffer = [_]u8{'.'} ++ @tagName(value);
496 return formatType(buffer, fmt, options, context, Errors, output, max_depth);484 return formatType(buffer, fmt, options, context, Errors, output, max_depth);
...@@ -503,21 +491,19 @@ fn formatValue(...@@ -503,21 +491,19 @@ fn formatValue(
503 value: var,491 value: var,
504 comptime fmt: []const u8,492 comptime fmt: []const u8,
505 options: FormatOptions,493 options: FormatOptions,
506 context: var,494 out_stream: var,
507 comptime Errors: type,495) !void {
508 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
509) Errors!void {
510 if (comptime std.mem.eql(u8, fmt, "B")) {496 if (comptime std.mem.eql(u8, fmt, "B")) {
511 return formatBytes(value, options, 1000, context, Errors, output);497 return formatBytes(value, options, 1000, out_stream);
512 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {498 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
513 return formatBytes(value, options, 1024, context, Errors, output);499 return formatBytes(value, options, 1024, out_stream);
514 }500 }
515501
516 const T = @TypeOf(value);502 const T = @TypeOf(value);
517 switch (@typeInfo(T)) {503 switch (@typeInfo(T)) {
518 .Float => return formatFloatValue(value, fmt, options, context, Errors, output),504 .Float => return formatFloatValue(value, fmt, options, out_stream),
519 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output),505 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, out_stream),
520 .Bool => return output(context, if (value) "true" else "false"),506 .Bool => return out_stream.writeAll(if (value) "true" else "false"),
521 else => comptime unreachable,507 else => comptime unreachable,
522 }508 }
523}509}
...@@ -526,10 +512,8 @@ pub fn formatIntValue(...@@ -526,10 +512,8 @@ pub fn formatIntValue(
526 value: var,512 value: var,
527 comptime fmt: []const u8,513 comptime fmt: []const u8,
528 options: FormatOptions,514 options: FormatOptions,
529 context: var,515 out_stream: var,
530 comptime Errors: type,516) !void {
531 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
532) Errors!void {
533 comptime var radix = 10;517 comptime var radix = 10;
534 comptime var uppercase = false;518 comptime var uppercase = false;
535519
...@@ -544,7 +528,7 @@ pub fn formatIntValue(...@@ -544,7 +528,7 @@ pub fn formatIntValue(
544 uppercase = false;528 uppercase = false;
545 } else if (comptime std.mem.eql(u8, fmt, "c")) {529 } else if (comptime std.mem.eql(u8, fmt, "c")) {
546 if (@TypeOf(int_value).bit_count <= 8) {530 if (@TypeOf(int_value).bit_count <= 8) {
547 return formatAsciiChar(@as(u8, int_value), options, context, Errors, output);531 return formatAsciiChar(@as(u8, int_value), options, out_stream);
548 } else {532 } else {
549 @compileError("Cannot print integer that is larger than 8 bits as a ascii");533 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
550 }534 }
...@@ -561,21 +545,19 @@ pub fn formatIntValue(...@@ -561,21 +545,19 @@ pub fn formatIntValue(
561 @compileError("Unknown format string: '" ++ fmt ++ "'");545 @compileError("Unknown format string: '" ++ fmt ++ "'");
562 }546 }
563547
564 return formatInt(int_value, radix, uppercase, options, context, Errors, output);548 return formatInt(int_value, radix, uppercase, options, out_stream);
565}549}
566550
567fn formatFloatValue(551fn formatFloatValue(
568 value: var,552 value: var,
569 comptime fmt: []const u8,553 comptime fmt: []const u8,
570 options: FormatOptions,554 options: FormatOptions,
571 context: var,555 out_stream: var,
572 comptime Errors: type,556) !void {
573 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
574) Errors!void {
575 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {557 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
576 return formatFloatScientific(value, options, context, Errors, output);558 return formatFloatScientific(value, options, out_stream);
577 } else if (comptime std.mem.eql(u8, fmt, "d")) {559 } else if (comptime std.mem.eql(u8, fmt, "d")) {
578 return formatFloatDecimal(value, options, context, Errors, output);560 return formatFloatDecimal(value, options, out_stream);
579 } else {561 } else {
580 @compileError("Unknown format string: '" ++ fmt ++ "'");562 @compileError("Unknown format string: '" ++ fmt ++ "'");
581 }563 }
...@@ -585,17 +567,15 @@ pub fn formatText(...@@ -585,17 +567,15 @@ pub fn formatText(
585 bytes: []const u8,567 bytes: []const u8,
586 comptime fmt: []const u8,568 comptime fmt: []const u8,
587 options: FormatOptions,569 options: FormatOptions,
588 context: var,570 out_stream: var,
589 comptime Errors: type,571) !void {
590 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
591) Errors!void {
592 if (fmt.len == 0) {572 if (fmt.len == 0) {
593 return output(context, bytes);573 return out_stream.writeAll(bytes);
594 } else if (comptime std.mem.eql(u8, fmt, "s")) {574 } else if (comptime std.mem.eql(u8, fmt, "s")) {
595 return formatBuf(bytes, options, context, Errors, output);575 return formatBuf(bytes, options, out_stream);
596 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {576 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
597 for (bytes) |c| {577 for (bytes) |c| {
598 try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, context, Errors, output);578 try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, out_stream);
599 }579 }
600 return;580 return;
601 } else {581 } else {
...@@ -606,27 +586,23 @@ pub fn formatText(...@@ -606,27 +586,23 @@ pub fn formatText(
606pub fn formatAsciiChar(586pub fn formatAsciiChar(
607 c: u8,587 c: u8,
608 options: FormatOptions,588 options: FormatOptions,
609 context: var,589 out_stream: var,
610 comptime Errors: type,590) !void {
611 comptime output: fn (@TypeOf(context), []const u8) Errors!void,591 return out_stream.writeAll(@as(*const [1]u8, &c)[0..]);
612) Errors!void {
613 return output(context, @as(*const [1]u8, &c)[0..]);
614}592}
615593
616pub fn formatBuf(594pub fn formatBuf(
617 buf: []const u8,595 buf: []const u8,
618 options: FormatOptions,596 options: FormatOptions,
619 context: var,597 out_stream: var,
620 comptime Errors: type,598) !void {
621 comptime output: fn (@TypeOf(context), []const u8) Errors!void,599 try out_stream.writeAll(buf);
622) Errors!void {
623 try output(context, buf);
624600
625 const width = options.width orelse 0;601 const width = options.width orelse 0;
626 var leftover_padding = if (width > buf.len) (width - buf.len) else return;602 var leftover_padding = if (width > buf.len) (width - buf.len) else return;
627 const pad_byte: u8 = options.fill;603 const pad_byte: u8 = options.fill;
628 while (leftover_padding > 0) : (leftover_padding -= 1) {604 while (leftover_padding > 0) : (leftover_padding -= 1) {
629 try output(context, @as(*const [1]u8, &pad_byte)[0..1]);605 try out_stream.writeAll(@as(*const [1]u8, &pad_byte)[0..1]);
630 }606 }
631}607}
632608
...@@ -636,40 +612,38 @@ pub fn formatBuf(...@@ -636,40 +612,38 @@ pub fn formatBuf(
636pub fn formatFloatScientific(612pub fn formatFloatScientific(
637 value: var,613 value: var,
638 options: FormatOptions,614 options: FormatOptions,
639 context: var,615 out_stream: var,
640 comptime Errors: type,616) !void {
641 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
642) Errors!void {
643 var x = @floatCast(f64, value);617 var x = @floatCast(f64, value);
644618
645 // Errol doesn't handle these special cases.619 // Errol doesn't handle these special cases.
646 if (math.signbit(x)) {620 if (math.signbit(x)) {
647 try output(context, "-");621 try out_stream.writeAll("-");
648 x = -x;622 x = -x;
649 }623 }
650624
651 if (math.isNan(x)) {625 if (math.isNan(x)) {
652 return output(context, "nan");626 return out_stream.writeAll("nan");
653 }627 }
654 if (math.isPositiveInf(x)) {628 if (math.isPositiveInf(x)) {
655 return output(context, "inf");629 return out_stream.writeAll("inf");
656 }630 }
657 if (x == 0.0) {631 if (x == 0.0) {
658 try output(context, "0");632 try out_stream.writeAll("0");
659633
660 if (options.precision) |precision| {634 if (options.precision) |precision| {
661 if (precision != 0) {635 if (precision != 0) {
662 try output(context, ".");636 try out_stream.writeAll(".");
663 var i: usize = 0;637 var i: usize = 0;
664 while (i < precision) : (i += 1) {638 while (i < precision) : (i += 1) {
665 try output(context, "0");639 try out_stream.writeAll("0");
666 }640 }
667 }641 }
668 } else {642 } else {
669 try output(context, ".0");643 try out_stream.writeAll(".0");
670 }644 }
671645
672 try output(context, "e+00");646 try out_stream.writeAll("e+00");
673 return;647 return;
674 }648 }
675649
...@@ -679,50 +653,50 @@ pub fn formatFloatScientific(...@@ -679,50 +653,50 @@ pub fn formatFloatScientific(
679 if (options.precision) |precision| {653 if (options.precision) |precision| {
680 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);654 errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
681655
682 try output(context, float_decimal.digits[0..1]);656 try out_stream.writeAll(float_decimal.digits[0..1]);
683657
684 // {e0} case prints no `.`658 // {e0} case prints no `.`
685 if (precision != 0) {659 if (precision != 0) {
686 try output(context, ".");660 try out_stream.writeAll(".");
687661
688 var printed: usize = 0;662 var printed: usize = 0;
689 if (float_decimal.digits.len > 1) {663 if (float_decimal.digits.len > 1) {
690 const num_digits = math.min(float_decimal.digits.len, precision + 1);664 const num_digits = math.min(float_decimal.digits.len, precision + 1);
691 try output(context, float_decimal.digits[1..num_digits]);665 try out_stream.writeAll(float_decimal.digits[1..num_digits]);
692 printed += num_digits - 1;666 printed += num_digits - 1;
693 }667 }
694668
695 while (printed < precision) : (printed += 1) {669 while (printed < precision) : (printed += 1) {
696 try output(context, "0");670 try out_stream.writeAll("0");
697 }671 }
698 }672 }
699 } else {673 } else {
700 try output(context, float_decimal.digits[0..1]);674 try out_stream.writeAll(float_decimal.digits[0..1]);
701 try output(context, ".");675 try out_stream.writeAll(".");
702 if (float_decimal.digits.len > 1) {676 if (float_decimal.digits.len > 1) {
703 const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;677 const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;
704678
705 try output(context, float_decimal.digits[1..num_digits]);679 try out_stream.writeAll(float_decimal.digits[1..num_digits]);
706 } else {680 } else {
707 try output(context, "0");681 try out_stream.writeAll("0");
708 }682 }
709 }683 }
710684
711 try output(context, "e");685 try out_stream.writeAll("e");
712 const exp = float_decimal.exp - 1;686 const exp = float_decimal.exp - 1;
713687
714 if (exp >= 0) {688 if (exp >= 0) {
715 try output(context, "+");689 try out_stream.writeAll("+");
716 if (exp > -10 and exp < 10) {690 if (exp > -10 and exp < 10) {
717 try output(context, "0");691 try out_stream.writeAll("0");
718 }692 }
719 try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);693 try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
720 } else {694 } else {
721 try output(context, "-");695 try out_stream.writeAll("-");
722 if (exp > -10 and exp < 10) {696 if (exp > -10 and exp < 10) {
723 try output(context, "0");697 try out_stream.writeAll("0");
724 }698 }
725 try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);699 try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
726 }700 }
727}701}
728702
...@@ -731,36 +705,34 @@ pub fn formatFloatScientific(...@@ -731,36 +705,34 @@ pub fn formatFloatScientific(
731pub fn formatFloatDecimal(705pub fn formatFloatDecimal(
732 value: var,706 value: var,
733 options: FormatOptions,707 options: FormatOptions,
734 context: var,708 out_stream: var,
735 comptime Errors: type,709) !void {
736 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
737) Errors!void {
738 var x = @as(f64, value);710 var x = @as(f64, value);
739711
740 // Errol doesn't handle these special cases.712 // Errol doesn't handle these special cases.
741 if (math.signbit(x)) {713 if (math.signbit(x)) {
742 try output(context, "-");714 try out_stream.writeAll("-");
743 x = -x;715 x = -x;
744 }716 }
745717
746 if (math.isNan(x)) {718 if (math.isNan(x)) {
747 return output(context, "nan");719 return out_stream.writeAll("nan");
748 }720 }
749 if (math.isPositiveInf(x)) {721 if (math.isPositiveInf(x)) {
750 return output(context, "inf");722 return out_stream.writeAll("inf");
751 }723 }
752 if (x == 0.0) {724 if (x == 0.0) {
753 try output(context, "0");725 try out_stream.writeAll("0");
754726
755 if (options.precision) |precision| {727 if (options.precision) |precision| {
756 if (precision != 0) {728 if (precision != 0) {
757 try output(context, ".");729 try out_stream.writeAll(".");
758 var i: usize = 0;730 var i: usize = 0;
759 while (i < precision) : (i += 1) {731 while (i < precision) : (i += 1) {
760 try output(context, "0");732 try out_stream.writeAll("0");
761 }733 }
762 } else {734 } else {
763 try output(context, ".0");735 try out_stream.writeAll(".0");
764 }736 }
765 }737 }
766738
...@@ -782,14 +754,14 @@ pub fn formatFloatDecimal(...@@ -782,14 +754,14 @@ pub fn formatFloatDecimal(
782754
783 if (num_digits_whole > 0) {755 if (num_digits_whole > 0) {
784 // We may have to zero pad, for instance 1e4 requires zero padding.756 // We may have to zero pad, for instance 1e4 requires zero padding.
785 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);757 try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
786758
787 var i = num_digits_whole_no_pad;759 var i = num_digits_whole_no_pad;
788 while (i < num_digits_whole) : (i += 1) {760 while (i < num_digits_whole) : (i += 1) {
789 try output(context, "0");761 try out_stream.writeAll("0");
790 }762 }
791 } else {763 } else {
792 try output(context, "0");764 try out_stream.writeAll("0");
793 }765 }
794766
795 // {.0} special case doesn't want a trailing '.'767 // {.0} special case doesn't want a trailing '.'
...@@ -797,7 +769,7 @@ pub fn formatFloatDecimal(...@@ -797,7 +769,7 @@ pub fn formatFloatDecimal(
797 return;769 return;
798 }770 }
799771
800 try output(context, ".");772 try out_stream.writeAll(".");
801773
802 // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.774 // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
803 var printed: usize = 0;775 var printed: usize = 0;
...@@ -809,7 +781,7 @@ pub fn formatFloatDecimal(...@@ -809,7 +781,7 @@ pub fn formatFloatDecimal(
809781
810 var i: usize = 0;782 var i: usize = 0;
811 while (i < zeros_to_print) : (i += 1) {783 while (i < zeros_to_print) : (i += 1) {
812 try output(context, "0");784 try out_stream.writeAll("0");
813 printed += 1;785 printed += 1;
814 }786 }
815787
...@@ -821,14 +793,14 @@ pub fn formatFloatDecimal(...@@ -821,14 +793,14 @@ pub fn formatFloatDecimal(
821 // Remaining fractional portion, zero-padding if insufficient.793 // Remaining fractional portion, zero-padding if insufficient.
822 assert(precision >= printed);794 assert(precision >= printed);
823 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {795 if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
824 try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);796 try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
825 return;797 return;
826 } else {798 } else {
827 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);799 try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
828 printed += float_decimal.digits.len - num_digits_whole_no_pad;800 printed += float_decimal.digits.len - num_digits_whole_no_pad;
829801
830 while (printed < precision) : (printed += 1) {802 while (printed < precision) : (printed += 1) {
831 try output(context, "0");803 try out_stream.writeAll("0");
832 }804 }
833 }805 }
834 } else {806 } else {
...@@ -840,14 +812,14 @@ pub fn formatFloatDecimal(...@@ -840,14 +812,14 @@ pub fn formatFloatDecimal(
840812
841 if (num_digits_whole > 0) {813 if (num_digits_whole > 0) {
842 // We may have to zero pad, for instance 1e4 requires zero padding.814 // We may have to zero pad, for instance 1e4 requires zero padding.
843 try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);815 try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
844816
845 var i = num_digits_whole_no_pad;817 var i = num_digits_whole_no_pad;
846 while (i < num_digits_whole) : (i += 1) {818 while (i < num_digits_whole) : (i += 1) {
847 try output(context, "0");819 try out_stream.writeAll("0");
848 }820 }
849 } else {821 } else {
850 try output(context, "0");822 try out_stream.writeAll("0");
851 }823 }
852824
853 // Omit `.` if no fractional portion825 // Omit `.` if no fractional portion
...@@ -855,7 +827,7 @@ pub fn formatFloatDecimal(...@@ -855,7 +827,7 @@ pub fn formatFloatDecimal(
855 return;827 return;
856 }828 }
857829
858 try output(context, ".");830 try out_stream.writeAll(".");
859831
860 // Zero-fill until we reach significant digits or run out of precision.832 // Zero-fill until we reach significant digits or run out of precision.
861 if (float_decimal.exp < 0) {833 if (float_decimal.exp < 0) {
...@@ -863,11 +835,11 @@ pub fn formatFloatDecimal(...@@ -863,11 +835,11 @@ pub fn formatFloatDecimal(
863835
864 var i: usize = 0;836 var i: usize = 0;
865 while (i < zero_digit_count) : (i += 1) {837 while (i < zero_digit_count) : (i += 1) {
866 try output(context, "0");838 try out_stream.writeAll("0");
867 }839 }
868 }840 }
869841
870 try output(context, float_decimal.digits[num_digits_whole_no_pad..]);842 try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
871 }843 }
872}844}
873845
...@@ -875,12 +847,10 @@ pub fn formatBytes(...@@ -875,12 +847,10 @@ pub fn formatBytes(
875 value: var,847 value: var,
876 options: FormatOptions,848 options: FormatOptions,
877 comptime radix: usize,849 comptime radix: usize,
878 context: var,850 out_stream: var,
879 comptime Errors: type,851) !void {
880 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
881) Errors!void {
882 if (value == 0) {852 if (value == 0) {
883 return output(context, "0B");853 return out_stream.writeAll("0B");
884 }854 }
885855
886 const mags_si = " kMGTPEZY";856 const mags_si = " kMGTPEZY";
...@@ -897,10 +867,10 @@ pub fn formatBytes(...@@ -897,10 +867,10 @@ pub fn formatBytes(
897 else => unreachable,867 else => unreachable,
898 };868 };
899869
900 try formatFloatDecimal(new_value, options, context, Errors, output);870 try formatFloatDecimal(new_value, options, out_stream);
901871
902 if (suffix == ' ') {872 if (suffix == ' ') {
903 return output(context, "B");873 return out_stream.writeAll("B");
904 }874 }
905875
906 const buf = switch (radix) {876 const buf = switch (radix) {
...@@ -908,7 +878,7 @@ pub fn formatBytes(...@@ -908,7 +878,7 @@ pub fn formatBytes(
908 1024 => &[_]u8{ suffix, 'i', 'B' },878 1024 => &[_]u8{ suffix, 'i', 'B' },
909 else => unreachable,879 else => unreachable,
910 };880 };
911 return output(context, buf);881 return out_stream.writeAll(buf);
912}882}
913883
914pub fn formatInt(884pub fn formatInt(
...@@ -916,10 +886,8 @@ pub fn formatInt(...@@ -916,10 +886,8 @@ pub fn formatInt(
916 base: u8,886 base: u8,
917 uppercase: bool,887 uppercase: bool,
918 options: FormatOptions,888 options: FormatOptions,
919 context: var,889 out_stream: var,
920 comptime Errors: type,890) !void {
921 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
922) Errors!void {
923 const int_value = if (@TypeOf(value) == comptime_int) blk: {891 const int_value = if (@TypeOf(value) == comptime_int) blk: {
924 const Int = math.IntFittingRange(value, value);892 const Int = math.IntFittingRange(value, value);
925 break :blk @as(Int, value);893 break :blk @as(Int, value);
...@@ -927,9 +895,9 @@ pub fn formatInt(...@@ -927,9 +895,9 @@ pub fn formatInt(
927 value;895 value;
928896
929 if (@TypeOf(int_value).is_signed) {897 if (@TypeOf(int_value).is_signed) {
930 return formatIntSigned(int_value, base, uppercase, options, context, Errors, output);898 return formatIntSigned(int_value, base, uppercase, options, out_stream);
931 } else {899 } else {
932 return formatIntUnsigned(int_value, base, uppercase, options, context, Errors, output);900 return formatIntUnsigned(int_value, base, uppercase, options, out_stream);
933 }901 }
934}902}
935903
...@@ -938,10 +906,8 @@ fn formatIntSigned(...@@ -938,10 +906,8 @@ fn formatIntSigned(
938 base: u8,906 base: u8,
939 uppercase: bool,907 uppercase: bool,
940 options: FormatOptions,908 options: FormatOptions,
941 context: var,909 out_stream: var,
942 comptime Errors: type,910) !void {
943 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
944) Errors!void {
945 const new_options = FormatOptions{911 const new_options = FormatOptions{
946 .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,912 .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
947 .precision = options.precision,913 .precision = options.precision,
...@@ -950,15 +916,15 @@ fn formatIntSigned(...@@ -950,15 +916,15 @@ fn formatIntSigned(
950 const bit_count = @typeInfo(@TypeOf(value)).Int.bits;916 const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
951 const Uint = std.meta.IntType(false, bit_count);917 const Uint = std.meta.IntType(false, bit_count);
952 if (value < 0) {918 if (value < 0) {
953 try output(context, "-");919 try out_stream.writeAll("-");
954 const new_value = math.absCast(value);920 const new_value = math.absCast(value);
955 return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);921 return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
956 } else if (options.width == null or options.width.? == 0) {922 } else if (options.width == null or options.width.? == 0) {
957 return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, context, Errors, output);923 return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, out_stream);
958 } else {924 } else {
959 try output(context, "+");925 try out_stream.writeAll("+");
960 const new_value = @intCast(Uint, value);926 const new_value = @intCast(Uint, value);
961 return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);927 return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
962 }928 }
963}929}
964930
...@@ -967,10 +933,8 @@ fn formatIntUnsigned(...@@ -967,10 +933,8 @@ fn formatIntUnsigned(
967 base: u8,933 base: u8,
968 uppercase: bool,934 uppercase: bool,
969 options: FormatOptions,935 options: FormatOptions,
970 context: var,936 out_stream: var,
971 comptime Errors: type,937) !void {
972 comptime output: fn (@TypeOf(context), []const u8) Errors!void,
973) Errors!void {
974 assert(base >= 2);938 assert(base >= 2);
975 var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;939 var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
976 const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count);940 const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count);
...@@ -994,16 +958,16 @@ fn formatIntUnsigned(...@@ -994,16 +958,16 @@ fn formatIntUnsigned(
994 const zero_byte: u8 = options.fill;958 const zero_byte: u8 = options.fill;
995 var leftover_padding = padding - index;959 var leftover_padding = padding - index;
996 while (true) {960 while (true) {
997 try output(context, @as(*const [1]u8, &zero_byte)[0..]);961 try out_stream.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
998 leftover_padding -= 1;962 leftover_padding -= 1;
999 if (leftover_padding == 0) break;963 if (leftover_padding == 0) break;
1000 }964 }
1001 mem.set(u8, buf[0..index], options.fill);965 mem.set(u8, buf[0..index], options.fill);
1002 return output(context, &buf);966 return out_stream.writeAll(&buf);
1003 } else {967 } else {
1004 const padded_buf = buf[index - padding ..];968 const padded_buf = buf[index - padding ..];
1005 mem.set(u8, padded_buf[0..padding], options.fill);969 mem.set(u8, padded_buf[0..padding], options.fill);
1006 return output(context, padded_buf);970 return out_stream.writeAll(padded_buf);
1007 }971 }
1008}972}
1009973
...@@ -1451,12 +1415,12 @@ test "custom" {...@@ -1451,12 +1415,12 @@ test "custom" {
1451 options: FormatOptions,1415 options: FormatOptions,
1452 context: var,1416 context: var,
1453 comptime Errors: type,1417 comptime Errors: type,
1454 comptime output: fn (@TypeOf(context), []const u8) Errors!void,1418 comptime output: fn (@TypeOf(context), []const u8) !void,
1455 ) Errors!void {1419 ) !void {
1456 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {1420 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
1457 return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });1421 return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
1458 } else if (comptime std.mem.eql(u8, fmt, "d")) {1422 } else if (comptime std.mem.eql(u8, fmt, "d")) {
1459 return std.fmt.format(context, Errors, output, "{d:.3}x{d:.3}", .{ self.x, self.y });1423 return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
1460 } else {1424 } else {
1461 @compileError("Unknown format character: '" ++ fmt ++ "'");1425 @compileError("Unknown format character: '" ++ fmt ++ "'");
1462 }1426 }
...@@ -1658,10 +1622,10 @@ test "formatType max_depth" {...@@ -1658,10 +1622,10 @@ test "formatType max_depth" {
1658 options: FormatOptions,1622 options: FormatOptions,
1659 context: var,1623 context: var,
1660 comptime Errors: type,1624 comptime Errors: type,
1661 comptime output: fn (@TypeOf(context), []const u8) Errors!void,1625 comptime output: fn (@TypeOf(context), []const u8) !void,
1662 ) Errors!void {1626 ) !void {
1663 if (fmt.len == 0) {1627 if (fmt.len == 0) {
1664 return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });1628 return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
1665 } else {1629 } else {
1666 @compileError("Unknown format string: '" ++ fmt ++ "'");1630 @compileError("Unknown format string: '" ++ fmt ++ "'");
1667 }1631 }