Skip to content

Commit 5701d0c

Browse files
authored
fix: support optional custom formats (#15)
1 parent 34acb35 commit 5701d0c

2 files changed

Lines changed: 112 additions & 8 deletions

File tree

src/struct.zig

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ pub fn packStruct(writer: *std.Io.Writer, comptime T: type, value_or_maybe_null:
144144
if (has_custom_write_fn) {
145145
return try value.msgpackWrite(packer(writer));
146146
} else {
147-
const format = comptime if (std.meta.hasFn(Type, "msgpackFormat")) T.msgpackFormat() else default_struct_format;
147+
const format = comptime if (std.meta.hasFn(Type, "msgpackFormat")) Type.msgpackFormat() else default_struct_format;
148148
switch (format) {
149149
.as_map => |opts| {
150150
return packStructAsMap(writer, Type, value, opts);
@@ -160,7 +160,7 @@ pub fn unpackStructFromMapBody(reader: *std.Io.Reader, allocator: std.mem.Alloca
160160
const Type = NonOptional(T);
161161
const type_info = @typeInfo(Type);
162162
const fields = type_info.@"struct".fields;
163-
const FieldEnum = std.meta.FieldEnum(T);
163+
const FieldEnum = std.meta.FieldEnum(Type);
164164

165165
var fields_seen = std.bit_set.StaticBitSet(fields.len).initEmpty();
166166

@@ -208,10 +208,10 @@ pub fn unpackStructFromMapBody(reader: *std.Io.Reader, allocator: std.mem.Alloca
208208
}
209209
},
210210
.custom => {
211-
const KeyType = comptime @typeInfo(@TypeOf(T.msgpackFieldKey)).@"fn".return_type.?;
211+
const KeyType = comptime @typeInfo(@TypeOf(Type.msgpackFieldKey)).@"fn".return_type.?;
212212
const key = try unpackAny(reader, allocator, KeyType);
213213
inline for (fields, 0..) |field, i| {
214-
if (T.msgpackFieldKey(@field(FieldEnum, field.name)) == key) {
214+
if (Type.msgpackFieldKey(@field(FieldEnum, field.name)) == key) {
215215
fields_seen.set(i);
216216
@field(result, field.name) = try unpackAny(reader, allocator, field.type);
217217
break;
@@ -280,9 +280,9 @@ pub fn unpackStruct(reader: *std.Io.Reader, allocator: std.mem.Allocator, compti
280280

281281
const has_custom_read_fn = std.meta.hasFn(Type, "msgpackRead");
282282
if (has_custom_read_fn) {
283-
return try T.msgpackRead(unpacker(reader, allocator));
283+
return try Type.msgpackRead(unpacker(reader, allocator));
284284
} else {
285-
const format = comptime if (std.meta.hasFn(Type, "msgpackFormat")) T.msgpackFormat() else default_struct_format;
285+
const format = comptime if (std.meta.hasFn(Type, "msgpackFormat")) Type.msgpackFormat() else default_struct_format;
286286
switch (format) {
287287
.as_map => |opts| {
288288
return try unpackStructAsMap(reader, allocator, T, opts);
@@ -318,6 +318,68 @@ test "writeStruct: map_by_index" {
318318
}, writer.buffered());
319319
}
320320

321+
test "writeStruct: optional custom format" {
322+
const Msg = struct {
323+
a: u32,
324+
325+
pub fn msgpackFormat() StructFormat {
326+
return .{ .as_map = .{ .key = .field_index } };
327+
}
328+
};
329+
330+
var buffer: [100]u8 = undefined;
331+
var writer = std.Io.Writer.fixed(&buffer);
332+
try packStruct(&writer, ?Msg, Msg{ .a = 1 });
333+
334+
try std.testing.expectEqualSlices(u8, &.{
335+
0x81,
336+
0x00,
337+
0x01,
338+
}, writer.buffered());
339+
}
340+
341+
test "readStruct: optional custom field key" {
342+
const Msg = struct {
343+
a: u32,
344+
345+
pub fn msgpackFormat() StructFormat {
346+
return .{ .as_map = .{ .key = .custom } };
347+
}
348+
349+
pub fn msgpackFieldKey(field: std.meta.FieldEnum(@This())) u8 {
350+
return switch (field) {
351+
.a => 1,
352+
};
353+
}
354+
};
355+
356+
const packed_msg = [_]u8{
357+
0x81,
358+
0x01,
359+
0x2a,
360+
};
361+
var reader = std.Io.Reader.fixed(&packed_msg);
362+
const decoded = try unpackStruct(&reader, std.testing.allocator, ?Msg);
363+
364+
try std.testing.expectEqual(@as(?Msg, Msg{ .a = 42 }), decoded);
365+
}
366+
367+
test "readStruct: optional custom reader" {
368+
const Msg = struct {
369+
a: u32,
370+
371+
pub fn msgpackRead(unpacker_value: anytype) !@This() {
372+
return .{ .a = try unpacker_value.readInt(u32) };
373+
}
374+
};
375+
376+
const packed_msg = [_]u8{0x2a};
377+
var reader = std.Io.Reader.fixed(&packed_msg);
378+
const decoded = try unpackStruct(&reader, std.testing.allocator, ?Msg);
379+
380+
try std.testing.expectEqual(@as(?Msg, Msg{ .a = 42 }), decoded);
381+
}
382+
321383
test "writeStruct: map by field_name" {
322384
const Msg = struct {
323385
a: u32,

src/union.zig

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ pub fn packUnion(writer: *std.Io.Writer, comptime T: type, value_or_maybe_null:
139139
@compileError("Expected union type");
140140
}
141141

142-
const format = if (std.meta.hasFn(Type, "msgpackFormat")) T.msgpackFormat() else default_union_format;
142+
const format = if (std.meta.hasFn(Type, "msgpackFormat")) Type.msgpackFormat() else default_union_format;
143143
switch (format) {
144144
.as_map => |opts| {
145145
return packUnionAsMap(writer, Type, value, opts);
@@ -281,7 +281,7 @@ pub fn unpackUnionAsTagged(reader: *std.Io.Reader, allocator: std.mem.Allocator,
281281
pub fn unpackUnion(reader: *std.Io.Reader, allocator: std.mem.Allocator, comptime T: type) !T {
282282
const Type = NonOptional(T);
283283

284-
const format = if (std.meta.hasFn(Type, "msgpackFormat")) T.msgpackFormat() else default_union_format;
284+
const format = if (std.meta.hasFn(Type, "msgpackFormat")) Type.msgpackFormat() else default_union_format;
285285
switch (format) {
286286
.as_map => |opts| {
287287
return try unpackUnionAsMap(reader, allocator, T, opts);
@@ -329,6 +329,48 @@ test "writeUnion: int field" {
329329
try std.testing.expectEqualSlices(u8, &msg1_packed, writer.buffered());
330330
}
331331

332+
test "writeUnion: optional custom format" {
333+
const Msg = union(enum) {
334+
a: u32,
335+
b: u64,
336+
337+
pub fn msgpackFormat() UnionFormat {
338+
return .{ .as_map = .{ .key = .field_index } };
339+
}
340+
};
341+
342+
var buffer: [100]u8 = undefined;
343+
var writer = std.Io.Writer.fixed(&buffer);
344+
try packUnion(&writer, ?Msg, Msg{ .a = 1 });
345+
346+
try std.testing.expectEqualSlices(u8, &.{
347+
0x81,
348+
0x00,
349+
0x01,
350+
}, writer.buffered());
351+
}
352+
353+
test "readUnion: optional custom format" {
354+
const Msg = union(enum) {
355+
a: u32,
356+
b: u64,
357+
358+
pub fn msgpackFormat() UnionFormat {
359+
return .{ .as_map = .{ .key = .field_index } };
360+
}
361+
};
362+
363+
const packed_msg = [_]u8{
364+
0x81,
365+
0x00,
366+
0x2a,
367+
};
368+
var reader = std.Io.Reader.fixed(&packed_msg);
369+
const decoded = try unpackUnion(&reader, std.testing.allocator, ?Msg);
370+
371+
try std.testing.expectEqualDeep(@as(?Msg, Msg{ .a = 42 }), decoded);
372+
}
373+
332374
test "writeUnion: void field" {
333375
var buffer: [100]u8 = undefined;
334376
var writer = std.Io.Writer.fixed(&buffer);

0 commit comments

Comments
 (0)