-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathstring.zig
128 lines (106 loc) · 4.19 KB
/
string.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const std = @import("std");
const hdrs = @import("headers.zig");
const isOptional = @import("utils.zig").isOptional;
const NonOptional = @import("utils.zig").NonOptional;
const maybePackNull = @import("null.zig").maybePackNull;
const maybeUnpackNull = @import("null.zig").maybeUnpackNull;
const packIntValue = @import("int.zig").packIntValue;
const unpackIntValue = @import("int.zig").unpackIntValue;
const unpackShortIntValue = @import("int.zig").unpackShortIntValue;
pub fn sizeOfPackedStringHeader(len: usize) !usize {
if (len <= hdrs.FIXSTR_MAX - hdrs.FIXSTR_MIN) {
return 1;
} else if (len <= std.math.maxInt(u8)) {
return 1 + @sizeOf(u8);
} else if (len <= std.math.maxInt(u16)) {
return 1 + @sizeOf(u16);
} else if (len <= std.math.maxInt(u32)) {
return 1 + @sizeOf(u32);
} else {
return error.StringTooLong;
}
}
pub fn sizeOfPackedString(len: usize) !usize {
return try sizeOfPackedStringHeader(len) + len;
}
pub fn packStringHeader(writer: anytype, len: usize) !void {
if (len <= hdrs.FIXSTR_MAX - hdrs.FIXSTR_MIN) {
try writer.writeByte(hdrs.FIXSTR_MIN + @as(u8, @intCast(len)));
} else if (len <= std.math.maxInt(u8)) {
try writer.writeByte(hdrs.STR8);
try packIntValue(writer, u8, @intCast(len));
} else if (len <= std.math.maxInt(u16)) {
try writer.writeByte(hdrs.STR16);
try packIntValue(writer, u16, @intCast(len));
} else if (len <= std.math.maxInt(u32)) {
try writer.writeByte(hdrs.STR32);
try packIntValue(writer, u32, @intCast(len));
} else {
return error.StringTooLong;
}
}
pub fn unpackStringHeader(reader: anytype, comptime MaybeOptionalType: type) !MaybeOptionalType {
const Type = NonOptional(MaybeOptionalType);
const header = try reader.readByte();
switch (header) {
hdrs.FIXSTR_MIN...hdrs.FIXSTR_MAX => return try unpackShortIntValue(header, hdrs.FIXSTR_MIN, hdrs.FIXSTR_MAX, Type),
hdrs.STR8 => return try unpackIntValue(reader, u8, Type),
hdrs.STR16 => return try unpackIntValue(reader, u16, Type),
hdrs.STR32 => return try unpackIntValue(reader, u32, Type),
else => return maybeUnpackNull(header, MaybeOptionalType),
}
}
pub fn packString(writer: anytype, value_or_maybe_null: ?[]const u8) !void {
const value = try maybePackNull(writer, @TypeOf(value_or_maybe_null), value_or_maybe_null) orelse return;
try packStringHeader(writer, value.len);
try writer.writeAll(value);
}
pub fn unpackString(reader: anytype, allocator: std.mem.Allocator) ![]u8 {
const len = try unpackStringHeader(reader, u32);
const data = try allocator.alloc(u8, len);
errdefer allocator.free(data);
try reader.readNoEof(data);
return data;
}
pub fn unpackStringInto(reader: anytype, buf: []u8) ![]u8 {
const len = try unpackStringHeader(reader, u32);
if (len > buf.len) {
return error.NoSpaceLeft;
}
const data = buf[0..len];
try reader.readNoEof(data);
return data;
}
pub const String = struct {
data: []const u8,
pub fn msgpackWrite(self: String, packer: anytype) !void {
try packer.writeString(self.data);
}
pub fn msgpackRead(unpacker: anytype) !String {
const data = try unpacker.readString();
return String{ .data = data };
}
};
const packed_null = [_]u8{0xc0};
const packed_abc = [_]u8{ 0xa3, 0x61, 0x62, 0x63 };
test "packString: abc" {
var buffer: [16]u8 = undefined;
var stream = std.io.fixedBufferStream(&buffer);
try packString(stream.writer(), "abc");
try std.testing.expectEqualSlices(u8, &packed_abc, stream.getWritten());
}
test "unpackString: abc" {
var stream = std.io.fixedBufferStream(&packed_abc);
const data = try unpackString(stream.reader(), std.testing.allocator);
defer std.testing.allocator.free(data);
try std.testing.expectEqualSlices(u8, "abc", data);
}
test "packString: null" {
var buffer: [16]u8 = undefined;
var stream = std.io.fixedBufferStream(&buffer);
try packString(stream.writer(), null);
try std.testing.expectEqualSlices(u8, &packed_null, stream.getWritten());
}
test "sizeOfPackedString" {
try std.testing.expectEqual(1, sizeOfPackedString(0));
}