Skip to content

Commit 8b409c7

Browse files
authored
Pass pointer (#5)
1 parent 120fad8 commit 8b409c7

File tree

11 files changed

+84
-86
lines changed

11 files changed

+84
-86
lines changed

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
# ssz-z
2-
An implementation of Ethereum Consensus Spec SimpleSerialize https://github.com/ethereum/consensus-specs/tree/dev/ssz. This follows Typescript implementation of Lodestar team https://github.com/ChainSafe/ssz. Some features:
3-
- support generic. If you have an application struct, just write a respective ssz struct and create a ssz type then you have an ssz implementation. More on that in the example below.
4-
- designed to support batch hash through `merkleize` function
5-
- support generic `HashFn` as a parameter when creating a new type
2+
An implementation of the Simple Serialize (SSZ) specification written in the Zig programming language.
63

7-
## Examples
4+
## About
5+
This library provides an implementation of the [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/tree/dev/ssz) specification, written in [Zig](https://ziglang.org/).
86

9-
## Commands:
7+
This follows Typescript implementation of Lodestar team https://github.com/ChainSafe/ssz
8+
9+
## Features
10+
- **generic**: If you have an application struct, just write a respective ssz struct and create a ssz type then you have an ssz implementation. More on that in the example below.
11+
- **batch hash** designed to support batch hash through `merkleize` function
12+
- **HashFn by type** support generic `HashFn` as a parameter when creating a new type
13+
14+
## Installation
15+
Clone the repository and build the project using Zig `git clone https://github.com/twoeths/ssz-z.git`
1016
- `zig build test:unit` to run all unit tests
1117
- `zig build test:int` to run all integration tests (tests across types)
1218
- `zig test --dep util -Mroot=src/hash/merkleize.zig -Mutil=lib/hex.zig` run tests in merkleize.zig

src/root.zig

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ pub const ByteVectorType = @import("type/byte_vector_type.zig").ByteVectorType;
1212
pub const createVectorCompositeType = @import("type/vector_composite.zig").createVectorCompositeType;
1313
pub const Parsed = @import("type/type.zig").Parsed;
1414

15-
export fn add(a: i32, b: i32) i32 {
16-
return a + b;
17-
}
18-
19-
test "basic add functionality" {
20-
try testing.expect(add(3, 7) == 10);
21-
}
22-
2315
test {
2416
testing.refAllDecls(@This());
2517
}

src/type/byte_list.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn createByteListType(comptime limit_bytes: usize) type {
3232
return @This(){ .allocator = allocator, .block_bytes = try BlockBytes.initCapacity(allocator, init_capacity), .mix_in_length_block_bytes = try allocator.alloc(u8, 64) };
3333
}
3434

35-
pub fn deinit(self: @This()) void {
35+
pub fn deinit(self: *const @This()) void {
3636
self.block_bytes.deinit();
3737
self.allocator.free(self.mix_in_length_block_bytes);
3838
}

src/type/byte_vector_type.zig

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub const ByteVectorType = struct {
4545
};
4646
}
4747

48-
pub fn deinit(self: @This()) void {
48+
pub fn deinit(self: *const @This()) void {
4949
self.allocator.free(self.block_bytes);
5050
}
5151

@@ -68,15 +68,15 @@ pub const ByteVectorType = struct {
6868
try merkleize(sha256Hash, self.block_bytes, self.max_chunk_count, out);
6969
}
7070

71-
pub fn fromSsz(self: @This(), ssz: []const u8) SszError!ParsedResult {
71+
pub fn fromSsz(self: *const @This(), ssz: []const u8) SszError!ParsedResult {
7272
return SingleType.fromSsz(self, ssz);
7373
}
7474

75-
pub fn fromJson(self: @This(), json: []const u8) FromHexError!ParsedResult {
75+
pub fn fromJson(self: *const @This(), json: []const u8) FromHexError!ParsedResult {
7676
return SingleType.fromJson(self, json);
7777
}
7878

79-
pub fn clone(self: @This(), value: []const u8) SszError!ParsedResult {
79+
pub fn clone(self: *const @This(), value: []const u8) SszError!ParsedResult {
8080
return SingleType.clone(self, value);
8181
}
8282

@@ -89,11 +89,11 @@ pub const ByteVectorType = struct {
8989
}
9090

9191
// Serialization + deserialization
92-
pub fn serializedSize(self: @This(), _: []const u8) usize {
92+
pub fn serializedSize(self: *const @This(), _: []const u8) usize {
9393
return self.fixed_size.?;
9494
}
9595

96-
pub fn serializeToBytes(self: @This(), value: []const u8, out: []u8) !usize {
96+
pub fn serializeToBytes(self: *const @This(), value: []const u8, out: []u8) !usize {
9797
if (out.len != self.fixed_size) {
9898
return error.InCorrectLen;
9999
}
@@ -102,7 +102,7 @@ pub const ByteVectorType = struct {
102102
return self.fixed_size.?;
103103
}
104104

105-
pub fn deserializeFromBytes(self: @This(), data: []const u8, out: []u8) !void {
105+
pub fn deserializeFromBytes(self: *const @This(), data: []const u8, out: []u8) !void {
106106
if (data.len != self.fixed_size) {
107107
return error.InCorrectLen;
108108
}
@@ -117,7 +117,7 @@ pub const ByteVectorType = struct {
117117
/// Same to deserializeFromBytes but this returns *T instead of out param
118118
/// Consumer need to free the memory
119119
/// out parameter is unused because parent does not allocate, just to conform to the api
120-
pub fn deserializeFromSlice(self: @This(), arenaAllocator: Allocator, slice: []const u8, _: ?[]u8) SszError![]u8 {
120+
pub fn deserializeFromSlice(self: *const @This(), arenaAllocator: Allocator, slice: []const u8, _: ?[]u8) SszError![]u8 {
121121
if (slice.len != self.fixed_size) {
122122
return error.InCorrectLen;
123123
}
@@ -130,7 +130,7 @@ pub const ByteVectorType = struct {
130130
/// Implementation for parent
131131
/// Consumer need to free the memory
132132
/// out parameter is unused because parent does not allocate, just to conform to the api
133-
pub fn deserializeFromJson(self: @This(), arena_allocator: Allocator, source: *Scanner, _: ?[]u8) ![]u8 {
133+
pub fn deserializeFromJson(self: *const @This(), arena_allocator: Allocator, source: *Scanner, _: ?[]u8) ![]u8 {
134134
const value = try source.next();
135135
const result = try arena_allocator.alloc(u8, self.fixed_size.?);
136136
try switch (value) {
@@ -143,7 +143,7 @@ pub const ByteVectorType = struct {
143143
return result;
144144
}
145145

146-
pub fn doClone(self: @This(), arena_allocator: Allocator, value: []const u8, out: ?[]u8) ![]u8 {
146+
pub fn doClone(self: *const @This(), arena_allocator: Allocator, value: []const u8, out: ?[]u8) ![]u8 {
147147
const out2 = if (out != null) out.? else try arena_allocator.alloc(u8, self.fixed_size.?);
148148
@memcpy(out2, value);
149149
return out2;

src/type/container.zig

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
7878
};
7979
}
8080

81-
pub fn deinit(self: @This()) void {
81+
pub fn deinit(self: *const @This()) void {
8282
self.allocator.free(self.blocks_bytes);
8383
}
8484

@@ -100,21 +100,21 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
100100
return result;
101101
}
102102

103-
pub fn fromSsz(self: @This(), ssz: []const u8) SszError!ParsedResult {
103+
pub fn fromSsz(self: *const @This(), ssz: []const u8) SszError!ParsedResult {
104104
return SingleType.fromSsz(self, ssz);
105105
}
106106

107107
/// public function for consumers
108-
pub fn fromJson(self: @This(), json: []const u8) JsonError!ParsedResult {
108+
pub fn fromJson(self: *const @This(), json: []const u8) JsonError!ParsedResult {
109109
return SingleType.fromJson(self, json);
110110
}
111111

112112
// public function for consumers
113-
pub fn clone(self: @This(), value: *const ZT) SszError!ParsedResult {
113+
pub fn clone(self: *const @This(), value: *const ZT) SszError!ParsedResult {
114114
return SingleType.clone(self, value);
115115
}
116116

117-
pub fn equals(self: @This(), a: *const ZT, b: *const ZT) bool {
117+
pub fn equals(self: *const @This(), a: *const ZT, b: *const ZT) bool {
118118
inline for (zig_fields_info) |field_info| {
119119
const field_name = field_info.name;
120120
const ssz_type = &@field(self.ssz_fields, field_name);
@@ -134,7 +134,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
134134
// Fixed part Variable part
135135
// [field1 offset][field2 data ][field1 data ]
136136
// [0x000000c] [0xaabbaabbaabbaabb][0xffffffffffffffffffffffff]
137-
pub fn serializedSize(self: @This(), value: *const ZT) usize {
137+
pub fn serializedSize(self: *const @This(), value: *const ZT) usize {
138138
var size: usize = 0;
139139
inline for (zig_fields_info) |field_info| {
140140
const field_name = field_info.name;
@@ -150,7 +150,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
150150
return size;
151151
}
152152

153-
pub fn serializeToBytes(self: @This(), value: *const ZT, out: []u8) !usize {
153+
pub fn serializeToBytes(self: *const @This(), value: *const ZT, out: []u8) !usize {
154154
var fixed_index: usize = 0;
155155
var variable_index = self.fixed_end;
156156

@@ -174,7 +174,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
174174
}
175175

176176
// TODO: not sure if we need this or not as there is no way to know the size of internal slice size
177-
pub fn deserializeFromBytes(self: @This(), data: []const u8, out: *ZT) !void {
177+
pub fn deserializeFromBytes(self: *const @This(), data: []const u8, out: *ZT) !void {
178178
// TODO: validate data length
179179
// max_chunk_count is known at compile time so we can allocate on stack
180180
var field_ranges = [_]BytesRange{.{ .start = 0, .end = 0 }} ** max_chunk_count;
@@ -191,7 +191,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
191191

192192
/// for embedded struct, it's allocated by the parent struct
193193
/// for pointer or slice, it's allocated on its own
194-
pub fn deserializeFromSlice(self: @This(), arenaAllocator: Allocator, slice: []const u8, out: ?*ZT) SszError!*ZT {
194+
pub fn deserializeFromSlice(self: *const @This(), arenaAllocator: Allocator, slice: []const u8, out: ?*ZT) SszError!*ZT {
195195
var out2 = if (out != null) out.? else try arenaAllocator.create(ZT);
196196

197197
// TODO: validate data length
@@ -215,7 +215,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
215215
}
216216

217217
/// a recursive implementation for parent types or fromJson
218-
pub fn deserializeFromJson(self: @This(), arena_allocator: Allocator, source: *Scanner, out: ?*ZT) JsonError!*ZT {
218+
pub fn deserializeFromJson(self: *const @This(), arena_allocator: Allocator, source: *Scanner, out: ?*ZT) JsonError!*ZT {
219219
var out2 = if (out != null) out.? else try arena_allocator.create(ZT);
220220
// validate begin token "{"
221221
const begin_object_token = try source.next();
@@ -253,7 +253,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
253253
return out2;
254254
}
255255

256-
pub fn doClone(self: @This(), arena_allocator: Allocator, value: *const ZT, out: ?*ZT) !*ZT {
256+
pub fn doClone(self: *const @This(), arena_allocator: Allocator, value: *const ZT, out: ?*ZT) !*ZT {
257257
var out2 = if (out != null) out.? else try arena_allocator.create(ZT);
258258
inline for (zig_fields_info) |field_info| {
259259
const field_name = field_info.name;
@@ -274,7 +274,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
274274
// Fields may not be contiguous in the serialized bytes, so the returned ranges are [start, end].
275275
// - For fixed size fields re-uses the pre-computed values this.fieldRangesFixedLen
276276
// - For variable size fields does a first pass over the fixed section to read offsets
277-
fn getFieldRanges(self: @This(), data: []const u8, out: []BytesRange) !void {
277+
fn getFieldRanges(self: *const @This(), data: []const u8, out: []BytesRange) !void {
278278
if (out.len != max_chunk_count) {
279279
return error.InCorrectLen;
280280
}
@@ -302,7 +302,7 @@ pub fn createContainerType(comptime ST: type, comptime ZT: type, hashFn: HashFn)
302302
}
303303

304304
// Returns the byte ranges of all variable size fields.
305-
fn readVariableOffsets(self: @This(), data: []const u8, offsets: []u32) void {
305+
fn readVariableOffsets(self: *const @This(), data: []const u8, offsets: []u32) void {
306306
var variable_index: usize = 0;
307307
var fixed_index: usize = 0;
308308
inline for (zig_fields_info) |field_info| {

src/type/list_basic.zig

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub fn createListBasicType(comptime ST: type, comptime ZT: type) type {
4949
return @This(){ .allocator = allocator, .element_type = element_type, .limit = limit, .fixed_size = null, .depth = depth, .chunk_depth = chunk_depth, .max_chunk_count = max_chunk_count, .min_size = 0, .max_size = limit * element_type.max_size, .block_bytes = try BlockBytes.initCapacity(allocator, init_capacity_bytes), .mix_in_length_block_bytes = try allocator.alloc(u8, 64) };
5050
}
5151

52-
pub fn deinit(self: @This()) void {
52+
pub fn deinit(self: *const @This()) void {
5353
self.block_bytes.deinit();
5454
self.allocator.free(self.mix_in_length_block_bytes);
5555
}
@@ -88,50 +88,50 @@ pub fn createListBasicType(comptime ST: type, comptime ZT: type) type {
8888
try merkleize(sha256Hash, self.mix_in_length_block_bytes, chunk_count, out);
8989
}
9090

91-
pub fn fromSsz(self: @This(), ssz: []const u8) SszError!ParsedResult {
91+
pub fn fromSsz(self: *const @This(), ssz: []const u8) SszError!ParsedResult {
9292
return ArrayBasic.fromSsz(self, ssz);
9393
}
9494

95-
pub fn fromJson(self: @This(), json: []const u8) JsonError!ParsedResult {
95+
pub fn fromJson(self: *const @This(), json: []const u8) JsonError!ParsedResult {
9696
return ArrayBasic.fromJson(self, json);
9797
}
9898

99-
pub fn clone(self: @This(), value: []const ZT) SszError!ParsedResult {
99+
pub fn clone(self: *const @This(), value: []const ZT) SszError!ParsedResult {
100100
return ArrayBasic.clone(self, value);
101101
}
102102

103103
// Serialization + deserialization
104-
pub fn serializedSize(self: @This(), value: []const ZT) usize {
104+
pub fn serializedSize(self: *const @This(), value: []const ZT) usize {
105105
return self.element_type.byte_length * value.len;
106106
}
107107

108-
pub fn serializeToBytes(self: @This(), value: []const ZT, out: []u8) !usize {
108+
pub fn serializeToBytes(self: *const @This(), value: []const ZT, out: []u8) !usize {
109109
return try ArrayBasic.serializeToBytes(self.element_type, value, out);
110110
}
111111

112-
pub fn deserializeFromBytes(self: @This(), data: []const u8, out: []ZT) !void {
112+
pub fn deserializeFromBytes(self: *const @This(), data: []const u8, out: []ZT) !void {
113113
try ArrayBasic.deserializeFromBytes(self.element_type, data, out);
114114
}
115115

116116
/// Same to deserializeFromBytes but this returns *T instead of out param
117117
/// Consumer need to free the memory
118118
/// out parameter is unused, just to conform to the api
119-
pub fn deserializeFromSlice(self: @This(), arenaAllocator: Allocator, slice: []const u8, out: ?[]ZT) SszError![]ZT {
119+
pub fn deserializeFromSlice(self: *const @This(), arenaAllocator: Allocator, slice: []const u8, out: ?[]ZT) SszError![]ZT {
120120
return try ArrayBasic.deserializeFromSlice(arenaAllocator, self.element_type, slice, out);
121121
}
122122

123123
/// Implementation for parent
124124
/// Consumer need to free the memory
125125
/// out parameter is unused because parent does not allocate, just to conform to the api
126-
pub fn deserializeFromJson(self: @This(), arena_allocator: Allocator, source: *Scanner, out: ?[]ZT) JsonError![]ZT {
126+
pub fn deserializeFromJson(self: *const @This(), arena_allocator: Allocator, source: *Scanner, out: ?[]ZT) JsonError![]ZT {
127127
return try ArrayBasic.deserializeFromJson(arena_allocator, self.element_type, source, null, out);
128128
}
129129

130-
pub fn equals(self: @This(), a: []const ZT, b: []const ZT) bool {
130+
pub fn equals(self: *const @This(), a: []const ZT, b: []const ZT) bool {
131131
return ArrayBasic.itemEquals(self.element_type, a, b);
132132
}
133133

134-
pub fn doClone(self: @This(), arena_allocator: Allocator, value: []const ZT, out: ?[]ZT) ![]ZT {
134+
pub fn doClone(self: *const @This(), arena_allocator: Allocator, value: []const ZT, out: ?[]ZT) ![]ZT {
135135
return try ArrayBasic.itemClone(self.element_type, arena_allocator, value, out);
136136
}
137137
};

src/type/list_composite.zig

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub fn createListCompositeType(comptime ST: type, comptime ZT: type) type {
6262
};
6363
}
6464

65-
pub fn deinit(self: @This()) void {
65+
pub fn deinit(self: *const @This()) void {
6666
self.block_bytes.deinit();
6767
self.allocator.free(self.mix_in_length_block_bytes);
6868
}
@@ -103,24 +103,24 @@ pub fn createListCompositeType(comptime ST: type, comptime ZT: type) type {
103103
try merkleize(sha256Hash, self.mix_in_length_block_bytes, chunk_count, out);
104104
}
105105

106-
pub fn fromSsz(self: @This(), ssz: []const u8) SszError!ParsedResult {
106+
pub fn fromSsz(self: *const @This(), ssz: []const u8) SszError!ParsedResult {
107107
return ArrayComposite.fromSsz(self, ssz);
108108
}
109109

110-
pub fn fromJson(self: @This(), json: []const u8) JsonError!ParsedResult {
110+
pub fn fromJson(self: *const @This(), json: []const u8) JsonError!ParsedResult {
111111
return ArrayComposite.fromJson(self, json);
112112
}
113113

114-
pub fn clone(self: @This(), value: []const ZT) SszError!ParsedResult {
114+
pub fn clone(self: *const @This(), value: []const ZT) SszError!ParsedResult {
115115
return ArrayComposite.clone(self, value);
116116
}
117117

118118
// Serialization + deserialization
119-
pub fn serializedSize(self: @This(), value: []const ZT) usize {
119+
pub fn serializedSize(self: *const @This(), value: []const ZT) usize {
120120
return ArrayComposite.serializedSize(self.element_type, value);
121121
}
122122

123-
pub fn serializeToBytes(self: @This(), value: []const ZT, out: []u8) !usize {
123+
pub fn serializeToBytes(self: *const @This(), value: []const ZT, out: []u8) !usize {
124124
// TODO: do we need this validation?
125125
const size = self.serializedSize(value);
126126
if (out.len != size) {
@@ -130,24 +130,24 @@ pub fn createListCompositeType(comptime ST: type, comptime ZT: type) type {
130130
return try ArrayComposite.serializeToBytes(self.element_type, value, out);
131131
}
132132

133-
pub fn deserializeFromBytes(self: @This(), data: []const u8, out: []ZT) !void {
133+
pub fn deserializeFromBytes(self: *const @This(), data: []const u8, out: []ZT) !void {
134134
try ArrayComposite.deserializeFromBytes(self.allocator, self.element_type, data, out);
135135
}
136136

137-
pub fn deserializeFromSlice(self: @This(), arena_allocator: Allocator, data: []const u8, _: ?[]ZT) SszError![]ZT {
137+
pub fn deserializeFromSlice(self: *const @This(), arena_allocator: Allocator, data: []const u8, _: ?[]ZT) SszError![]ZT {
138138
return try ArrayComposite.deserializeFromSlice(arena_allocator, self.element_type, data, null);
139139
}
140140

141141
/// out parameter is not used because memory is always allocated inside the function
142-
pub fn deserializeFromJson(self: @This(), arena_allocator: Allocator, source: *Scanner, _: ?[]ZT) JsonError![]ZT {
142+
pub fn deserializeFromJson(self: *const @This(), arena_allocator: Allocator, source: *Scanner, _: ?[]ZT) JsonError![]ZT {
143143
return try ArrayComposite.deserializeFromJson(arena_allocator, self.element_type, source, null, null);
144144
}
145145

146-
pub fn equals(self: @This(), a: []const ZT, b: []const ZT) bool {
146+
pub fn equals(self: *const @This(), a: []const ZT, b: []const ZT) bool {
147147
return ArrayComposite.itemEquals(self.element_type, a, b);
148148
}
149149

150-
pub fn doClone(self: @This(), arena_allocator: Allocator, value: []const ZT, out: ?[]ZT) ![]ZT {
150+
pub fn doClone(self: *const @This(), arena_allocator: Allocator, value: []const ZT, out: ?[]ZT) ![]ZT {
151151
return try ArrayComposite.itemClone(self.element_type, arena_allocator, value, out);
152152
}
153153
};

0 commit comments

Comments
 (0)