diff options
Diffstat (limited to 'src/bencode.zig')
-rw-r--r-- | src/bencode.zig | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/src/bencode.zig b/src/bencode.zig index b78ee9f..44dec0d 100644 --- a/src/bencode.zig +++ b/src/bencode.zig @@ -2,6 +2,7 @@ //! See specification here https://wiki.theory.org/BitTorrentSpecification#Bencoding const std = @import("std"); +const AnyWriter = @import("anywriter.zig"); pub const Error = error.Malformatted || std.io.AnyReader.Error; @@ -12,6 +13,41 @@ pub const BValue = union(enum) { list: std.ArrayList(BValue), dict: std.StringArrayHashMap(BValue), + pub fn bencode(self: *const BValue, base_writer: anytype) !void { + var wrap = AnyWriter.wrapper(base_writer); + var writer = wrap.any(); + try self.bencodeInner(writer); + } + + // Note: uses defined types only to avoid trying to recursively evaulate this function + // at compile time, otherwise we run into https://github.com/ziglang/zig/issues/13724 + fn bencodeInner(self: *const BValue, writer: AnyWriter) !void { + switch (self.*) { + .string => |s| { + try std.fmt.format(writer, "{}:{s}", .{ s.len, s }); + }, + .list => |l| { + try writer.writeByte('l'); + for (l.items) |i| { + try i.bencodeInner(writer); + } + try writer.writeByte('e'); + }, + .dict => |d| { + try writer.writeByte('d'); + var it = d.iterator(); + while (it.next()) |entry| { + try std.fmt.format(writer, "{}:{s}", .{ entry.key_ptr.*.len, entry.key_ptr.* }); + try entry.value_ptr.*.bencodeInner(writer); + } + try writer.writeByte('e'); + }, + .int => |i| { + try std.fmt.format(writer, "i{}e", .{i}); + }, + } + } + pub fn deinit(self: *BValue, a: std.mem.Allocator) void { switch (self.*) { .string => |s| { @@ -237,3 +273,17 @@ test "nested structure" { try std.testing.expectEqualDeep(v2.*.list.items[1], BValue{ .int = 456 }); try std.testing.expectEqualStrings("nest", v2.*.list.items[2].list.items[0].string); } + +test "round trip" { + var a = std.testing.allocator; + const in = "d5:hello5:world2:hili123ei456el4:nesteee"; + var bval = try bdecodeBuf(a, in); + defer bval.deinit(a); + var bw = std.ArrayList(u8).init(a); + defer bw.deinit(); + var writer = bw.writer(); + try bval.bencode(writer); + var out = try bw.toOwnedSlice(); + defer a.free(out); + try std.testing.expectEqualStrings(in, out); +} |