| ... | @@ -802,12 +802,14 @@ pub fn splatBytePreserve(w: *Writer, preserve: usize, byte: u8, n: usize) Error! | ... | @@ -802,12 +802,14 @@ pub fn splatBytePreserve(w: *Writer, preserve: usize, byte: u8, n: usize) Error! |
| 802 | return; | 802 | return; |
| 803 | } | 803 | } |
| 804 | } | 804 | } |
| 805 | // All the next bytes received must be preserved. | 805 | // Ensure the contract of `rebase` is upheld. |
| 806 | if (preserve < w.end) { | 806 | assert(w.end + remaining > w.buffer.len); |
| 807 | @memmove(w.buffer[0..preserve], w.buffer[w.end - preserve ..][0..preserve]); | 807 | // Offset the amount preserved by the amount we have left to splat |
| 808 | w.end = preserve; | 808 | // since the remaining splat is always going to be part of that |
| 809 | } | 809 | // preservation. |
| 810 | while (remaining > 0) remaining -= try w.splatByte(byte, remaining); | 810 | try w.vtable.rebase(w, preserve -| remaining, remaining); |
| | 811 | @memset(w.buffer[w.end..][0..remaining], byte); |
| | 812 | w.end += remaining; |
| 811 | } | 813 | } |
| 812 | | 814 | |
| 813 | /// Writes the same byte many times, allowing short writes. | 815 | /// Writes the same byte many times, allowing short writes. |
| ... | @@ -2887,3 +2889,46 @@ test "writableSlice with fixed writer" { | ... | @@ -2887,3 +2889,46 @@ test "writableSlice with fixed writer" { |
| 2887 | try w.writeByte(1); | 2889 | try w.writeByte(1); |
| 2888 | try std.testing.expectError(error.WriteFailed, w.writableSlice(2)); | 2890 | try std.testing.expectError(error.WriteFailed, w.writableSlice(2)); |
| 2889 | } | 2891 | } |
| | 2892 | |
| | 2893 | test splatBytePreserve { |
| | 2894 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .splat_len = 5 }); |
| | 2895 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 9, .preserve = 5, .splat_len = 2 }); |
| | 2896 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .splat_len = 6 }); |
| | 2897 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .splat_len = 6 }); |
| | 2898 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 5, .splat_len = 10 }); |
| | 2899 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .splat_len = 10 }); |
| | 2900 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .splat_len = 11 }); |
| | 2901 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .splat_len = 80 }); |
| | 2902 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 6, .splat_len = 85 }); |
| | 2903 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .splat_len = 6 }); |
| | 2904 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .splat_len = 11 }); |
| | 2905 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .splat_len = 80 }); |
| | 2906 | try testSplatBytePreserve(.{ .buf_len = 10, .fill_len = 5, .preserve = 10, .splat_len = 85 }); |
| | 2907 | } |
| | 2908 | |
| | 2909 | fn testSplatBytePreserve(options: struct { buf_len: u4, fill_len: u4, preserve: u4, splat_len: u8 }) !void { |
| | 2910 | assert(options.fill_len <= options.buf_len); |
| | 2911 | assert(options.preserve <= options.buf_len); |
| | 2912 | |
| | 2913 | const fill_buf = "abcdefghijklmno"; |
| | 2914 | const fill = fill_buf[0..options.fill_len]; |
| | 2915 | var expected_out_buf: [256]u8 = @splat('X'); |
| | 2916 | @memcpy(expected_out_buf[0..options.fill_len], fill); |
| | 2917 | const expected_out = expected_out_buf[0 .. options.fill_len + options.splat_len]; |
| | 2918 | const expected_preserved = expected_out[expected_out.len -| options.preserve..]; |
| | 2919 | |
| | 2920 | var out_buf: [256]u8 = undefined; |
| | 2921 | var fw: Writer = .fixed(&out_buf); |
| | 2922 | var indirect_buffer: [16]u8 = undefined; |
| | 2923 | var twi: std.testing.WriterIndirect = .init(&fw, indirect_buffer[0..options.buf_len]); |
| | 2924 | const w = &twi.interface; |
| | 2925 | |
| | 2926 | try w.writeAll(fill); |
| | 2927 | try w.splatBytePreserve(options.preserve, 'X', options.splat_len); |
| | 2928 | |
| | 2929 | try std.testing.expectEqualStrings(expected_preserved, w.buffer[w.end -| options.preserve..w.end]); |
| | 2930 | |
| | 2931 | try w.flush(); |
| | 2932 | |
| | 2933 | try std.testing.expectEqualStrings(expected_out, fw.buffer[0..fw.end]); |
| | 2934 | } |