Skip to content

Commit

Permalink
Merge pull request #12 from Syndica/19/pull_msgs
Browse files Browse the repository at this point in the history
gossip: pull request/response logic
  • Loading branch information
ultd committed Aug 9, 2023
2 parents 4afc993 + 49234c7 commit 735e6a4
Show file tree
Hide file tree
Showing 33 changed files with 1,839 additions and 432 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: setup-zig
uses: goto-bus-stop/setup-zig@v1
with:
version: 0.11.0-dev.3997+546212ff7
version: 0.11.0

- name: lint
run: |
Expand All @@ -40,7 +40,7 @@ jobs:
- name: setup-zig
uses: goto-bus-stop/setup-zig@v1
with:
version: 0.11.0-dev.3997+546212ff7
version: 0.11.0

- name: build
run: zig build
Expand Down
8 changes: 4 additions & 4 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
.hash = "1220227d746ee3f156059a22b0044c6d8ad062a7cfb15b060cc2e7cbae4d0631f34e",
},
.@"zig-network" = .{
.url = "https://github.com/MasterQ32/zig-network/archive/7b5f76ea09626b96755c027bf4bd5b7e45297027.tar.gz",
.hash = "122090e7cb4459c2224399a45c56f47462733b919aa547c96b8c14ee705bfa22976e",
.url = "https://github.com/MasterQ32/zig-network/archive/02ffa0fc310ff0746f06c9bfb73b008ce4fca200.tar.gz",
.hash = "1220fe0d4ca564aa15f3fd7f9f84ba04e031bb70c3a1432257e0d35c74b183550c24",
},
.@"zig-cli" = .{
.url = "https://github.com/sam701/zig-cli/archive/ea92821a797bdefb5df41ce602f8c7f387bcfb93.tar.gz",
.hash = "122044525df0d1896556da08c5ed50b456a672a52ab86a65834bb1e27d3ae7a847f2",
},
.getty = .{
.url = "https://github.com/0xNineteen/getty/archive/04e1d75c3b4f122232f0b8efeaf296742cb5c262.tar.gz",
.hash = "122034c0905da94ef750e5c225b1b58810ee2d6370c776f81fdea383ec5217c275a2",
.url = "https://github.com/getty-zig/getty/archive/5b0e750d92ee4ef8e46ad743bb8ced63723acd00.tar.gz",
.hash = "12209398657d260abcd6dae946d8da4cd3057b8c7990608476a9f8011aae570d2ebb",
},
},
}
186 changes: 107 additions & 79 deletions src/bincode/bincode.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ pub const Params = struct {
include_fixed_array_length: bool = false,
};

pub fn deserializer(r: anytype, params: Params) blk: {
break :blk Deserializer(@TypeOf(r));
} {
pub fn deserializer(r: anytype, params: Params) Deserializer(@TypeOf(r)) {
return Deserializer(@TypeOf(r)).init(r, params);
}

Expand Down Expand Up @@ -211,20 +209,21 @@ pub fn Deserializer(comptime Reader: type) type {
const params = dd.context.params;
var data: T = undefined;

if (getStructSerializer(T)) |deser_fcn| {
data = try deser_fcn(alloc, T, reader, params);
return data;
}

inline for (info.fields) |field| {
if (!field.is_comptime) {
if (shouldUseDefaultValue(T, field)) |val| {
@field(data, field.name) = @as(*const field.type, @ptrCast(@alignCast(val))).*;
} else if (getFieldDeserializer(T, field)) |deser_fcn| {
@field(data, field.name) = try (deser_fcn(alloc, field.type, reader, params) catch getty.de.Error.InvalidValue);
} else {
@field(data, field.name) = try getty.deserialize(alloc, field.type, dd);
if (get_field_config(T, field)) |config| {
if (shouldUseDefaultValue(field, config)) |default_val| {
@field(data, field.name) = @as(*const field.type, @ptrCast(@alignCast(default_val))).*;
continue;
}

if (config.deserializer) |deser_fcn| {
@field(data, field.name) = deser_fcn(alloc, reader, params) catch return getty.de.Error.InvalidValue;
continue;
}
}

@field(data, field.name) = try getty.deserialize(alloc, field.type, dd);
}
}
return data;
Expand Down Expand Up @@ -288,9 +287,7 @@ pub fn free(
}

// for ref: https://github.com/getty-zig/json/blob/a5c4d9f996dc3f472267f6210c30f96c39da576b/src/ser/serializer.zig
pub fn serializer(w: anytype, params: Params) blk: {
break :blk Serializer(@TypeOf(w));
} {
pub fn serializer(w: anytype, params: Params) Serializer(@TypeOf(w)) {
return Serializer(@TypeOf(w)).init(w, params);
}

Expand Down Expand Up @@ -429,19 +426,19 @@ pub fn Serializer(
var params = ss.context.params;
var writer = ss.context.writer;

if (getStructSerializer(T)) |ser_fcn| {
return ser_fcn(writer, value, params);
}

inline for (info.fields) |field| {
if (!field.is_comptime) {
if (!shouldSkipSerializingField(T, field)) {
if (getFieldSerializer(T, field)) |ser_fcn| {
try (ser_fcn(writer, @field(value, field.name), params) catch Error.IO);
} else {
try getty.serialize(alloc, @field(value, field.name), ss);
if (get_field_config(T, field)) |config| {
if (config.skip) {
continue;
}
if (config.serializer) |ser_fcn| {
ser_fcn(writer, @field(value, field.name), params) catch return Error.IO;
continue;
}
}

try getty.serialize(alloc, @field(value, field.name), ss);
}
}
},
Expand Down Expand Up @@ -485,72 +482,43 @@ pub fn Serializer(
};
}

pub inline fn shouldUseDefaultValue(comptime parent_type: type, comptime struct_field: std.builtin.Type.StructField) ?*const anyopaque {
const parent_type_name = @typeName(parent_type);

if (@hasDecl(parent_type, "!bincode-config:" ++ struct_field.name)) {
const config = @field(parent_type, "!bincode-config:" ++ struct_field.name);
if (config.skip and struct_field.default_value == null) {
@compileError("┓\n|\n|--> Invalid config: cannot skip field '" ++ parent_type_name ++ "." ++ struct_field.name ++ "' deserialization if no default value set\n\n");
}
return struct_field.default_value;
}

return null;
}

pub fn getFieldDeserializer(comptime parent_type: type, comptime struct_field: std.builtin.Type.StructField) ?DeserializeFunction {
if (@hasDecl(parent_type, "!bincode-config:" ++ struct_field.name)) {
const config = @field(parent_type, "!bincode-config:" ++ struct_field.name);
return config.deserializer;
}
return null;
// need this fn to define the return type T
pub fn DeserializeFunction(comptime T: type) type {
return fn (alloc: ?std.mem.Allocator, reader: anytype, params: Params) anyerror!T;
}

pub const SerializeFunction = fn (writer: anytype, data: anytype, params: Params) anyerror!void;
pub const DeserializeFunction = fn (alloc: ?std.mem.Allocator, comptime T: type, reader: anytype, params: Params) anyerror!void;

pub const FieldConfig = struct {
serializer: ?SerializeFunction = null,
deserializer: ?DeserializeFunction = null,
skip: bool = false,
};

pub const StructConfig = struct {
serializer: ?SerializeFunction = null,
deserializer: ?DeserializeFunction = null,
};

pub fn getStructSerializer(comptime parent_type: type) ?SerializeFunction {
if (@hasDecl(parent_type, "!bincode-config")) {
const config = @field(parent_type, "!bincode-config");
return config.serializer;
}
return null;
// ** Field Functions ** //
pub fn FieldConfig(comptime T: type) type {
return struct {
deserializer: ?DeserializeFunction(T) = null,
serializer: ?SerializeFunction = null,
skip: bool = false,
};
}

pub fn getFieldSerializer(comptime parent_type: type, comptime struct_field: std.builtin.Type.StructField) ?SerializeFunction {
if (@hasDecl(parent_type, "!bincode-config:" ++ struct_field.name)) {
const config = @field(parent_type, "!bincode-config:" ++ struct_field.name);
return config.serializer;
pub fn get_field_config(comptime struct_type: type, comptime field: std.builtin.Type.StructField) ?FieldConfig(field.type) {
const bincode_field = "!bincode-config:" ++ field.name;
if (@hasDecl(struct_type, bincode_field)) {
const config = @field(struct_type, bincode_field);
return config;
}
return null;
}

pub inline fn shouldSkipSerializingField(comptime parent_type: type, comptime struct_field: std.builtin.Type.StructField) bool {
const parent_type_name = @typeName(parent_type);

if (@hasDecl(parent_type, "!bincode-config:" ++ struct_field.name)) {
const config = @field(parent_type, "!bincode-config:" ++ struct_field.name);
if (config.skip and struct_field.default_value == null) {
@compileError("┓\n|\n|--> Invalid config: cannot skip field '" ++ parent_type_name ++ "." ++ struct_field.name ++ "' serialization if no default value set\n\n");
pub inline fn shouldUseDefaultValue(comptime field: std.builtin.Type.StructField, comptime config: FieldConfig(field.type)) ?*const anyopaque {
if (config.skip) {
if (field.default_value == null) {
const field_type_name = @typeName(field.type);
@compileError("┓\n|\n|--> Invalid config: cannot skip field '" ++ field_type_name ++ "." ++ field.name ++ "' deserialization if no default value set\n\n");
}
return config.skip;
return field.default_value;
} else {
return null;
}

return false;
}

// ** Writer/Reader functions ** //
pub fn writeToSlice(slice: []u8, data: anytype, params: Params) ![]u8 {
var stream = std.io.fixedBufferStream(slice);
var writer = stream.writer();
Expand Down Expand Up @@ -587,6 +555,66 @@ pub fn read(alloc: ?std.mem.Allocator, comptime T: type, reader: anytype, params
return v;
}

// ** Tests **//
fn TestSliceConfig(comptime Child: type) FieldConfig([]Child) {
const S = struct {
fn deserialize_test_slice(allocator: ?std.mem.Allocator, reader: anytype, params: Params) ![]Child {
var ally = allocator.?;
var len = try bincode.read(ally, u16, reader, params);
var elems = try ally.alloc(Child, len);
for (0..len) |i| {
elems[i] = try bincode.read(ally, Child, reader, params);
}
return elems;
}

pub fn serilaize_test_slice(writer: anytype, data: anytype, params: bincode.Params) !void {
var len = std.math.cast(u16, data.len) orelse return error.DataTooLarge;
try bincode.write(null, writer, len, params);
for (data) |item| {
try bincode.write(null, writer, item, params);
}
return;
}
};

return FieldConfig([]Child){
.serializer = S.serilaize_test_slice,
.deserializer = S.deserialize_test_slice,
};
}

test "bincode: custom field serialization" {
const Foo = struct {
accounts: []u8,
txs: []u32,
skip_me: u8 = 20,

pub const @"!bincode-config:accounts" = TestSliceConfig(u8);
pub const @"!bincode-config:txs" = TestSliceConfig(u32);
pub const @"!bincode-config:skip_me" = FieldConfig(u8){
.skip = true,
};
};

var accounts = [_]u8{ 1, 2, 3 };
var txs = [_]u32{ 1, 2, 3 };
var foo = Foo{ .accounts = &accounts, .txs = &txs };

var buf: [1000]u8 = undefined;
var out = try writeToSlice(&buf, foo, Params{});
std.debug.print("{any}", .{out});
try std.testing.expect(out[out.len - 1] != 20); // skip worked

var r = try readFromSlice(std.testing.allocator, Foo, out, Params{});
defer free(std.testing.allocator, r);
std.debug.print("{any}", .{r});

try std.testing.expect(r.accounts.len == foo.accounts.len);
try std.testing.expect(r.txs.len == foo.txs.len);
try std.testing.expect(r.skip_me == 20);
}

test "bincode: test serialization" {
var buf: [1]u8 = undefined;

Expand Down
Loading

0 comments on commit 735e6a4

Please sign in to comment.