Commit f87dd43c12

Arwalk <siragentprovocateurarwalk@gmail.com>
2024-09-04 10:10:12
stdlib : base64 encode to writer (#20961)
1 parent e5ee9c1
Changed files (1)
lib
lib/std/base64.zig
@@ -5,6 +5,7 @@ const assert = std.debug.assert;
 const builtin = @import("builtin");
 const testing = std.testing;
 const mem = std.mem;
+const window = mem.window;
 
 pub const Error = error{
     InvalidCharacter,
@@ -98,6 +99,32 @@ pub const Base64Encoder = struct {
         }
     }
 
+    // dest must be compatible with std.io.Writer's writeAll interface
+    pub fn encodeWriter(encoder: *const Base64Encoder, dest: anytype, source: []const u8) !void {
+        var chunker = window(u8, source, 3, 3);
+        while (chunker.next()) |chunk| {
+            var temp: [5]u8 = undefined;
+            const s = encoder.encode(&temp, chunk);
+            try dest.writeAll(s);
+        }
+    }
+
+    // destWriter must be compatible with std.io.Writer's writeAll interface
+    // sourceReader must be compatible with std.io.Reader's read interface
+    pub fn encodeFromReaderToWriter(encoder: *const Base64Encoder, destWriter: anytype, sourceReader: anytype) !void {
+        while (true) {
+            var tempSource: [3]u8 = undefined;
+            const bytesRead = try sourceReader.read(&tempSource);
+            if (bytesRead == 0) {
+                break;
+            }
+
+            var temp: [5]u8 = undefined;
+            const s = encoder.encode(&temp, tempSource[0..bytesRead]);
+            try destWriter.writeAll(s);
+        }
+    }
+
     /// dest.len must at least be what you get from ::calcSize.
     pub fn encode(encoder: *const Base64Encoder, dest: []u8, source: []const u8) []const u8 {
         const out_len = encoder.calcSize(source.len);
@@ -477,9 +504,21 @@ fn testBase64UrlSafeNoPad() !void {
 fn testAllApis(codecs: Codecs, expected_decoded: []const u8, expected_encoded: []const u8) !void {
     // Base64Encoder
     {
+        // raw encode
         var buffer: [0x100]u8 = undefined;
         const encoded = codecs.Encoder.encode(&buffer, expected_decoded);
         try testing.expectEqualSlices(u8, expected_encoded, encoded);
+
+        // stream encode
+        var list = try std.BoundedArray(u8, 0x100).init(0);
+        try codecs.Encoder.encodeWriter(list.writer(), expected_decoded);
+        try testing.expectEqualSlices(u8, expected_encoded, list.slice());
+
+        // reader to writer encode
+        var stream = std.io.fixedBufferStream(expected_decoded);
+        list = try std.BoundedArray(u8, 0x100).init(0);
+        try codecs.Encoder.encodeFromReaderToWriter(list.writer(), stream.reader());
+        try testing.expectEqualSlices(u8, expected_encoded, list.slice());
     }
 
     // Base64Decoder