Skip to content

Commit ac31a14

Browse files
committed
convert float, int, nil, bool into T().write form
1 parent 6f253bc commit ac31a14

File tree

8 files changed

+462
-272
lines changed

8 files changed

+462
-272
lines changed

src/ComptimeFloat.zig

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const std = @import("std");
2+
const Float = @import("./root.zig").Float;
3+
4+
pub fn countSm(value: comptime_int) usize {
5+
return serializeSm(std.io.null_writer, value) catch unreachable;
6+
}
7+
8+
pub fn serializeSm(writer: anytype, value: comptime_int) !usize {
9+
const wontLosePrecision = @as(f32, @floatCast(value)) == value;
10+
11+
if (wontLosePrecision) {
12+
return Float(f32).serialize(writer, @floatCast(value));
13+
} else {
14+
return Float(f64).serialize(writer, @floatCast(value));
15+
}
16+
}
17+
18+
pub fn writeSm(dst: []u8, value: comptime_float) usize {
19+
var stream = std.io.fixedBufferStream(dst);
20+
return serializeSm(stream.writer(), value) catch unreachable;
21+
}
22+
23+
pub const count = countSm;
24+
pub const serialize = serializeSm;
25+
pub const write = writeSm;

src/ComptimeInt.zig

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
const std = @import("std");
2+
const compatstd = @import("./compatstd.zig");
3+
const toolkit = @import("./toolkit.zig");
4+
const countIntByteRounded = toolkit.countIntByteRounded;
5+
const makeFixIntNeg = toolkit.makeFixIntNeg;
6+
const makeFixIntPos = toolkit.makeFixIntPos;
7+
8+
pub fn count(value: comptime_int) usize {
9+
const signed: std.builtin.Signedness = if (value < 0) .signed else .unsigned;
10+
const bits = compatstd.meta.bitsOfNumber(value);
11+
if (bits > 64) {
12+
@compileError("the max integer size is 64 bits");
13+
}
14+
15+
const nbytes = countIntByteRounded(signed, bits);
16+
return 1 + nbytes;
17+
}
18+
19+
pub const countSm = count;
20+
21+
pub fn serialize(writer: anytype, value: comptime_int) !usize {
22+
const signed: std.builtin.Signedness = if (value < 0) .signed else .unsigned;
23+
const bits = compatstd.meta.bitsOfNumber(value);
24+
25+
if (bits > 64) {
26+
@compileError("the max integer size is 64 bits");
27+
}
28+
29+
const nbytes = countIntByteRounded(signed, bits);
30+
31+
const header: u8 = if (signed) switch (nbytes) {
32+
0 => makeFixIntNeg(@intCast(value)),
33+
1 => 0xd0,
34+
2 => 0xd1,
35+
4 => 0xd2,
36+
8 => 0xd3,
37+
else => unreachable,
38+
} else switch (nbytes) {
39+
0 => makeFixIntPos(@intCast(value)),
40+
1 => 0xcc,
41+
2 => 0xcd,
42+
4 => 0xce,
43+
8 => 0xcf,
44+
else => unreachable,
45+
};
46+
47+
_ = try writer.writeByte(header);
48+
if (nbytes == 0) {
49+
return 1;
50+
}
51+
52+
const W = std.meta.Int(if (signed) .signed else .unsigned, nbytes * 8);
53+
_ = try writer.writeInt(W, @as(W, value), .big);
54+
return 1 + nbytes;
55+
}
56+
57+
pub fn write(dst: []u8, value: comptime_int) usize {
58+
var stream = std.io.fixedBufferStream(dst);
59+
return serialize(stream.writer(), value) catch unreachable;
60+
}
61+
62+
pub const writeSm = write;

src/Prefix.zig

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! Optimized prefix.
2+
//!
3+
//! This is implemented as the BoundedArray, but is not copied-and-pasted.
4+
//! The functions here are unchecked by default.
5+
const std = @import("std");
6+
7+
buffer: [6]u8 = undefined,
8+
len: u3 = 0,
9+
10+
const Prefix = @This();
11+
12+
pub fn constSlice(self: Prefix) []const u8 {
13+
return self.buffer[0..self.len];
14+
}
15+
16+
pub fn slice(self: *Prefix) []u8 {
17+
return self.buffer[0..self.len];
18+
}
19+
20+
pub fn unusedCapacitySlice(self: *Prefix) []u8 {
21+
return self.buffer[self.len..];
22+
}
23+
24+
pub fn checkedAppend(self: *Prefix, item: u8) error{BufOverflow}!void {
25+
@setRuntimeSafety(false);
26+
if (self.len > std.math.maxInt(u3) - 1) {
27+
return error.BufOverflow;
28+
}
29+
self.unusedCapacitySlice()[0] = item;
30+
self.len += 1;
31+
}
32+
33+
pub fn append(self: *Prefix, item: u8) void {
34+
return self.checkedAppend(item) catch unreachable;
35+
}
36+
37+
pub fn checkedAppendSlice(self: *Prefix, items: []const u8) error{BufOverflow}!void {
38+
@setRuntimeSafety(false);
39+
if (std.math.maxInt(u3) - self.len < items.len) {
40+
return error.BufOverflow;
41+
}
42+
std.mem.copyForwards(u8, self.unusedCapacitySlice(), items);
43+
self.len += @intCast(items.len);
44+
}
45+
46+
pub fn appendSlice(self: *Prefix, items: []const u8) void {
47+
return self.checkedAppendSlice(items) catch unreachable;
48+
}
49+
50+
pub fn checkedWriteInt(self: *Prefix, T: type, value: T, endian: std.builtin.Endian) error{BufOverflow}!void {
51+
@setRuntimeSafety(false);
52+
const intsz = @divExact(@bitSizeOf(T), 8);
53+
if (std.math.maxInt(u3) - self.len < intsz) {
54+
return error.BufOverflow;
55+
}
56+
std.mem.writeInt(T, self.unusedCapacitySlice()[0..intsz], value, endian);
57+
self.len += intsz;
58+
}
59+
60+
pub fn writeInt(self: *Prefix, T: type, value: T, endian: std.builtin.Endian) void {
61+
return self.checkedWriteInt(T, value, endian) catch unreachable;
62+
}
63+
64+
pub fn fromSlice(value: []const u8) Prefix {
65+
var result: Prefix = .{};
66+
std.mem.copyForwards(u8, &result.buffer, value);
67+
result.len = @intCast(value.len);
68+
return result;
69+
}
70+
71+
pub const WriteError = error{BufOverflow};
72+
73+
fn write(self: *Prefix, items: []const u8) WriteError!usize {
74+
const dest = self.unusedCapacitySlice();
75+
if (items.len > slice.len) {
76+
return WriteError.BufferOverflow;
77+
}
78+
@memcpy(dest, items);
79+
self.len += @truncate(items.len);
80+
return items.len;
81+
}
82+
83+
pub const Writer = std.io.GenericWriter(*Prefix, WriteError, write);
84+
85+
pub fn writer(self: *Prefix) Writer {
86+
return Writer{ .context = self };
87+
}

src/compatstd.zig

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,16 @@ pub const meta = struct {
7171
}
7272
}
7373

74-
pub inline fn signedness(value: anytype) std.builtin.Signedness {
74+
pub inline fn signednessOf(T: type) std.builtin.Signedness {
7575
if (isZig0d14AndLater) {
76-
return switch (@typeInfo(@TypeOf(value))) {
76+
return switch (@typeInfo(T)) {
7777
.int => |i| i.signedness,
78-
.comptime_int => value < 0,
79-
else => @compileError("value must be int or comptime_int"),
78+
else => @compileError("T must be int type"),
8079
};
8180
} else {
82-
return switch (@typeInfo(@TypeOf(value))) {
81+
return switch (@typeInfo(T)) {
8382
.Int => |i| i.signedness,
84-
.ComptimeInt => value < 0,
85-
else => @compileError("value must be int or comptime_int"),
83+
else => @compileError("T must be int type"),
8684
};
8785
}
8886
}

src/io.zig

Lines changed: 3 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
//! - `writeStringPrefix`, `writeString`
88
//! - `writeBinaryPrefix`, `writeBinary`
99
//! - `writeExtPrefix`, `writeExt`
10-
//! - `writeBool`, `writeNil`
11-
//! - `writeInt`, `writeIntSm`, `writeFloat`
1210
//! - `writeArrayPrefix`, `writeMapPrefix`
1311
const fmt = @import("./root.zig");
1412
const std = @import("std");
@@ -51,61 +49,6 @@ pub fn writeExt(writer: anytype, extype: i8, payload: []const u8) !usize {
5149
return size1 + size2;
5250
}
5351

54-
pub fn writeBool(writer: anytype, value: bool) !usize {
55-
var buf = [_]u8{0};
56-
_ = fmt.writeBool(&buf, value);
57-
return try writer.write(&buf);
58-
}
59-
60-
pub fn writeNil(writer: anytype) !usize {
61-
var buf = [_]u8{0};
62-
_ = fmt.writeNil(&buf);
63-
return try writer.write(&buf);
64-
}
65-
66-
fn BufferForNumber(comptime T: type) type {
67-
const bsize = switch (@bitSizeOf(T)) {
68-
1...8 => 1,
69-
9...16 => 2,
70-
17...32 => 4,
71-
33...64 => 8,
72-
else => @compileError(comptimePrint("unsupported {}", .{@typeName(T)})),
73-
};
74-
return [bsize + 1]u8;
75-
}
76-
77-
pub fn writeInt(writer: anytype, value: anytype) !usize {
78-
const T = @TypeOf(value);
79-
var buf: BufferForNumber(T) = undefined;
80-
const bsize = fmt.writeInt(T, &buf, value);
81-
const wsize = try writer.write(buf[0..bsize]);
82-
return wsize;
83-
}
84-
85-
pub fn writeIntSm(writer: anytype, value: anytype) !usize {
86-
var buf: BufferForNumber(@TypeOf(value)) = undefined;
87-
// std.debug.print("writeIntSm value={} buf.len={}\n", .{ value, buf.len });
88-
const bsize = fmt.writeIntSm(@TypeOf(value), &buf, value);
89-
const wsize = try writer.write(buf[0..bsize]);
90-
return wsize;
91-
}
92-
93-
pub fn writeFloat(writer: anytype, value: anytype) !usize {
94-
const T = @TypeOf(value);
95-
var buf: BufferForNumber(@TypeOf(value)) = undefined;
96-
const bsize = fmt.writeFloat(T, &buf, value);
97-
const wsize = try writer.write(buf[0..bsize]);
98-
return wsize;
99-
}
100-
101-
pub fn writeFloatSm(writer: anytype, value: anytype) !usize {
102-
const T = @TypeOf(value);
103-
var buf: BufferForNumber(@TypeOf(value)) = undefined;
104-
const bsize = fmt.writeFloatSm(T, &buf, value);
105-
const wsize = try writer.write(buf[0..bsize]);
106-
return wsize;
107-
}
108-
10952
pub fn writeArrayPrefix(writer: anytype, length: u32) !usize {
11053
const prefix = fmt.prefixArray(length);
11154
const slice = prefix.constSlice();
@@ -138,6 +81,9 @@ pub const UnpackReader = struct {
13881
buffer: []u8,
13982
readsize: usize = 0,
14083

84+
/// Recommended min buffer size.
85+
pub const RECOMMENDED_BUFFER_SIZE = std.mem.page_size;
86+
14187
pub fn init(buffer: []u8) UnpackReader {
14288
std.debug.assert(buffer.len >= 8);
14389
return .{

src/rewriter.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ fn rewriteValue(
1212
switch (h.type.family()) {
1313
.nil => {
1414
_ = try values.nil(reader, ?*anyopaque, h);
15-
_ = try zigpak.io.writeNil(writer);
15+
_ = try zigpak.Nil.serialize(writer);
1616
},
17-
.bool => _ = try zigpak.io.writeBool(writer, try values.bool(reader, h)),
18-
.int => _ = try zigpak.io.writeIntSm(writer, try values.int(reader, i64, h)),
19-
.uint => _ = try zigpak.io.writeIntSm(writer, try values.int(reader, u64, h)),
20-
.float => _ = try zigpak.io.writeFloatSm(writer, try values.float(reader, f64, h)),
17+
.bool => _ = try zigpak.Bool.serialize(writer, try values.bool(reader, h)),
18+
.int => _ = try zigpak.SInt.serializeSm(writer, try values.int(reader, i64, h)),
19+
.uint => _ = try zigpak.UInt.serializeSm(writer, try values.int(reader, u64, h)),
20+
.float => _ = try zigpak.AnyFloat.serializeSm(writer, try values.float(reader, f64, h)),
2121
.str => {
2222
var strReader = try values.rawReader(reader, h);
2323
var strbuf: [4096]u8 = undefined;
@@ -63,7 +63,7 @@ fn rewriteValue(
6363
}
6464

6565
fn rewrite(reader: anytype, writer: anytype) !void {
66-
var buffer: [4096]u8 = undefined;
66+
var buffer: [zigpak.io.UnpackReader.RECOMMENDED_BUFFER_SIZE]u8 = undefined;
6767
var vread = zigpak.io.UnpackReader.init(&buffer);
6868
while (true) {
6969
const h = try vread.next(reader);

0 commit comments

Comments
 (0)