| ... | @@ -41,7 +41,7 @@ pub fn writer(bw: *BufferedWriter) Writer { | ... | @@ -41,7 +41,7 @@ pub fn writer(bw: *BufferedWriter) Writer { |
| 41 | | 41 | |
| 42 | const fixed_vtable: Writer.VTable = .{ | 42 | const fixed_vtable: Writer.VTable = .{ |
| 43 | .writeSplat = fixed_writeSplat, | 43 | .writeSplat = fixed_writeSplat, |
| 44 | .writeFile = fixed_writeFile, | 44 | .writeFile = Writer.unimplemented_writeFile, |
| 45 | }; | 45 | }; |
| 46 | | 46 | |
| 47 | /// Replaces the `BufferedWriter` with a new one that writes to `buffer` and | 47 | /// Replaces the `BufferedWriter` with a new one that writes to `buffer` and |
| ... | @@ -74,6 +74,10 @@ pub fn flush(bw: *BufferedWriter) anyerror!void { | ... | @@ -74,6 +74,10 @@ pub fn flush(bw: *BufferedWriter) anyerror!void { |
| 74 | bw.end = 0; | 74 | bw.end = 0; |
| 75 | } | 75 | } |
| 76 | | 76 | |
| | 77 | pub fn unusedCapacitySlice(bw: *const BufferedWriter) []u8 { |
| | 78 | return bw.buffer[bw.end..]; |
| | 79 | } |
| | 80 | |
| 77 | /// The `data` parameter is mutable because this function needs to mutate the | 81 | /// The `data` parameter is mutable because this function needs to mutate the |
| 78 | /// fields in order to handle partial writes from `Writer.VTable.writev`. | 82 | /// fields in order to handle partial writes from `Writer.VTable.writev`. |
| 79 | pub fn writevAll(bw: *BufferedWriter, data: [][]const u8) anyerror!void { | 83 | pub fn writevAll(bw: *BufferedWriter, data: [][]const u8) anyerror!void { |
| ... | @@ -93,6 +97,10 @@ pub fn writeSplat(bw: *BufferedWriter, data: []const []const u8, splat: usize) a | ... | @@ -93,6 +97,10 @@ pub fn writeSplat(bw: *BufferedWriter, data: []const []const u8, splat: usize) a |
| 93 | return passthru_writeSplat(bw, data, splat); | 97 | return passthru_writeSplat(bw, data, splat); |
| 94 | } | 98 | } |
| 95 | | 99 | |
| | 100 | pub fn writev(bw: *BufferedWriter, data: []const []const u8) anyerror!usize { |
| | 101 | return passthru_writeSplat(bw, data, 1); |
| | 102 | } |
| | 103 | |
| 96 | fn passthru_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize { | 104 | fn passthru_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize { |
| 97 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); | 105 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 98 | const buffer = bw.buffer; | 106 | const buffer = bw.buffer; |
| ... | @@ -523,23 +531,6 @@ pub fn writeFileAll(bw: *BufferedWriter, file: std.fs.File, options: WriteFileOp | ... | @@ -523,23 +531,6 @@ pub fn writeFileAll(bw: *BufferedWriter, file: std.fs.File, options: WriteFileOp |
| 523 | } | 531 | } |
| 524 | } | 532 | } |
| 525 | | 533 | |
| 526 | fn fixed_writeFile( | | |
| 527 | context: *anyopaque, | | |
| 528 | file: std.fs.File, | | |
| 529 | offset: u64, | | |
| 530 | len: Writer.VTable.FileLen, | | |
| 531 | headers_and_trailers: []const []const u8, | | |
| 532 | headers_len: usize, | | |
| 533 | ) anyerror!usize { | | |
| 534 | _ = context; | | |
| 535 | _ = file; | | |
| 536 | _ = offset; | | |
| 537 | _ = len; | | |
| 538 | _ = headers_and_trailers; | | |
| 539 | _ = headers_len; | | |
| 540 | return error.Unimplemented; | | |
| 541 | } | | |
| 542 | | | |
| 543 | pub fn alignBuffer( | 534 | pub fn alignBuffer( |
| 544 | bw: *BufferedWriter, | 535 | bw: *BufferedWriter, |
| 545 | buffer: []const u8, | 536 | buffer: []const u8, |
| ... | @@ -775,19 +766,22 @@ pub fn printValue( | ... | @@ -775,19 +766,22 @@ pub fn printValue( |
| 775 | }, | 766 | }, |
| 776 | .slice => { | 767 | .slice => { |
| 777 | if (actual_fmt.len == 0) | 768 | if (actual_fmt.len == 0) |
| 778 | @compileError("cannot format slice without a specifier (i.e. {s}, {x}, or {any})"); | 769 | @compileError("cannot format slice without a specifier (i.e. {s}, {x}, {b64}, or {any})"); |
| 779 | if (max_depth == 0) { | 770 | if (max_depth == 0) { |
| 780 | return bw.writeAll("{ ... }"); | 771 | return bw.writeAll("{ ... }"); |
| 781 | } | 772 | } |
| 782 | if (ptr_info.child == u8) { | 773 | if (ptr_info.child == u8) switch (actual_fmt.len) { |
| 783 | if (actual_fmt[0] == 's') { | 774 | 1 => switch (actual_fmt[0]) { |
| 784 | return alignBufferOptions(bw, value, options); | 775 | 's' => return alignBufferOptions(bw, value, options), |
| 785 | } else if (actual_fmt[0] == 'x') { | 776 | 'x' => return printHex(bw, value, .lower), |
| 786 | return printHex(bw, value, .lower); | 777 | 'X' => return printHex(bw, value, .upper), |
| 787 | } else if (actual_fmt[0] == 'X') { | 778 | else => {}, |
| 788 | return printHex(bw, value, .upper); | 779 | }, |
| 789 | } | 780 | 3 => if (actual_fmt[0] == 'b' and actual_fmt[1] == '6' and actual_fmt[2] == '4') { |
| 790 | } | 781 | return printBase64(bw, value); |
| | 782 | }, |
| | 783 | else => {}, |
| | 784 | }; |
| 791 | try bw.writeAll("{ "); | 785 | try bw.writeAll("{ "); |
| 792 | for (value, 0..) |elem, i| { | 786 | for (value, 0..) |elem, i| { |
| 793 | try printValue(bw, actual_fmt, options, elem, max_depth - 1); | 787 | try printValue(bw, actual_fmt, options, elem, max_depth - 1); |
| ... | @@ -1289,6 +1283,12 @@ pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) anye | ... | @@ -1289,6 +1283,12 @@ pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) anye |
| 1289 | } | 1283 | } |
| 1290 | } | 1284 | } |
| 1291 | | 1285 | |
| | 1286 | pub fn printBase64(bw: *BufferedWriter, bytes: []const u8) anyerror!void { |
| | 1287 | var chunker = std.mem.window(u8, bytes, 3, 3); |
| | 1288 | var temp: [5]u8 = undefined; |
| | 1289 | while (chunker.next()) |chunk| try bw.writeAll(std.base64.standard.Encoder.encode(&temp, chunk)); |
| | 1290 | } |
| | 1291 | |
| 1292 | test "formatValue max_depth" { | 1292 | test "formatValue max_depth" { |
| 1293 | const Vec2 = struct { | 1293 | const Vec2 = struct { |
| 1294 | const SelfType = @This(); | 1294 | const SelfType = @This(); |