feat: add deinit and decodeCollReply to protocol
This commit is contained in:
1 parent
eb441341cb
commit
c928cc7302
1 file changed
+152
@@ -649,3 +649,155 @@ pub const OwnedCollReply = union(enum) {
|
||||
pairList: []OwnedCollPair,
|
||||
scorePairList: []OwnedCollScorePair,
|
||||
|
||||
pub fn deinit(self: *OwnedCollReply, allocator: Allocator) void {
|
||||
switch (self.*) {
|
||||
.bytes => |b| allocator.free(b),
|
||||
.stringList => |items| {
|
||||
for (items) |it| allocator.free(it);
|
||||
allocator.free(items);
|
||||
},
|
||||
.pairList => |items| {
|
||||
for (items) |p| {
|
||||
allocator.free(p.field);
|
||||
allocator.free(p.value);
|
||||
}
|
||||
allocator.free(items);
|
||||
},
|
||||
.scorePairList => |items| {
|
||||
for (items) |p| allocator.free(p.member);
|
||||
allocator.free(items);
|
||||
},
|
||||
.nil, .ok, .int, .real => {},
|
||||
}
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn decodeCollReply(allocator: Allocator, payload: []const u8) !OwnedCollReply {
|
||||
var c = Cursor{ .data = payload };
|
||||
const tag = std.meta.intToEnum(CollReplyTag, try c.takeByte()) catch return error.Malformed;
|
||||
return switch (tag) {
|
||||
.nil => .nil,
|
||||
.ok => .ok,
|
||||
.int => .{ .int = @bitCast(try c.takeU64()) },
|
||||
.real => .{ .real = @bitCast(try c.takeU64()) },
|
||||
.bytes => .{ .bytes = try allocator.dupe(u8, c.data[c.pos..]) },
|
||||
.stringList => blk: {
|
||||
const count = try c.takeU32();
|
||||
var list = try std.ArrayList([]u8).initCapacity(allocator, count);
|
||||
errdefer {
|
||||
for (list.items) |it| allocator.free(it);
|
||||
list.deinit();
|
||||
}
|
||||
var i: u32 = 0;
|
||||
while (i < count) : (i += 1) {
|
||||
const raw = try c.takeLenPrefixed();
|
||||
list.appendAssumeCapacity(try allocator.dupe(u8, raw));
|
||||
}
|
||||
break :blk .{ .stringList = try list.toOwnedSlice() };
|
||||
},
|
||||
.pairList => blk: {
|
||||
const count = try c.takeU32();
|
||||
var list = try std.ArrayList(OwnedCollPair).initCapacity(allocator, count);
|
||||
errdefer {
|
||||
for (list.items) |p| {
|
||||
allocator.free(p.field);
|
||||
allocator.free(p.value);
|
||||
}
|
||||
list.deinit();
|
||||
}
|
||||
var i: u32 = 0;
|
||||
while (i < count) : (i += 1) {
|
||||
const field = try c.takeLenPrefixed();
|
||||
const value = try c.takeLenPrefixed();
|
||||
list.appendAssumeCapacity(.{ .field = try allocator.dupe(u8, field), .value = try allocator.dupe(u8, value) });
|
||||
}
|
||||
break :blk .{ .pairList = try list.toOwnedSlice() };
|
||||
},
|
||||
.scorePairList => blk: {
|
||||
const count = try c.takeU32();
|
||||
var list = try std.ArrayList(OwnedCollScorePair).initCapacity(allocator, count);
|
||||
errdefer {
|
||||
for (list.items) |p| allocator.free(p.member);
|
||||
list.deinit();
|
||||
}
|
||||
var i: u32 = 0;
|
||||
while (i < count) : (i += 1) {
|
||||
const member = try c.takeLenPrefixed();
|
||||
const score: f64 = @bitCast(try c.takeU64());
|
||||
list.appendAssumeCapacity(.{ .member = try allocator.dupe(u8, member), .score = score });
|
||||
}
|
||||
break :blk .{ .scorePairList = try list.toOwnedSlice() };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// --- txn_op ---
|
||||
|
||||
/// Remote counterpart of the CLI's local `txn <script-file>` (main.zig's
|
||||
/// `runTxn`, backed by `txn.zig`/`txn_table.zig`): a batch of put/delete row
|
||||
/// operations, possibly spanning several tables, applied as one atomic
|
||||
/// `Transaction` commit - the same "every op succeeds together or none of
|
||||
/// them do" guarantee the local CLI gives, now reachable from a process that
|
||||
/// only has a `Client`, not a `*Db`. Unlike `coll_op`/`ttl_op` (one action
|
||||
/// against one key/collection per request) this opcode carries a LIST of
|
||||
/// entries, since a transaction script is inherently a batch.
|
||||
pub const TxnVerb = enum(u8) {
|
||||
put = 0,
|
||||
del = 1,
|
||||
|
||||
pub fn fromByte(b: u8) !TxnVerb {
|
||||
return std.meta.intToEnum(TxnVerb, b) catch error.Malformed;
|
||||
}
|
||||
};
|
||||
|
||||
/// One staged operation as the caller supplies it. `fields` is ignored for
|
||||
/// `.del` (callers pass `&.{}`) - same "unused argument still there, just
|
||||
/// empty" convention as `encodeUserAdmin`'s zeroed `role`/`rounds` on
|
||||
/// actions that do not need them.
|
||||
pub const TxnOpEntry = struct {
|
||||
verb: TxnVerb,
|
||||
table: []const u8,
|
||||
pk: rowmod.Value,
|
||||
fields: []const rowmod.Field = &.{},
|
||||
};
|
||||
|
||||
pub fn encodeTxnOp(allocator: Allocator, entries: []const TxnOpEntry) ![]u8 {
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
errdefer buf.deinit();
|
||||
const w = encode.ByteWriter.init(&buf);
|
||||
try w.putU32(@intCast(entries.len));
|
||||
for (entries) |e| {
|
||||
try w.byte(@intFromEnum(e.verb));
|
||||
try putLenPrefixed(w, e.table);
|
||||
|
||||
const pkBytes = try rowmod.encodeValue(allocator, e.pk);
|
||||
defer allocator.free(pkBytes);
|
||||
try putLenPrefixed(w, pkBytes);
|
||||
|
||||
// Reuses `Row.encode` for the field list exactly the way
|
||||
// `encodeRows` does for a whole result set, instead of inventing a
|
||||
// second name+value framing just for this opcode.
|
||||
var fieldsRow = rowmod.Row.init(allocator);
|
||||
defer fieldsRow.deinit();
|
||||
for (e.fields) |f| try fieldsRow.set(f.name, f.value);
|
||||
const fieldsBytes = try fieldsRow.encode(allocator);
|
||||
defer allocator.free(fieldsBytes);
|
||||
try putLenPrefixed(w, fieldsBytes);
|
||||
}
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
/// Decoded entry with every slice borrowed from the frame `payload` that
|
||||
/// carried it - same convention as `decodeCollOp`/`decodeTableSelect`, valid
|
||||
/// only as long as that payload is alive. `pkBytes`/`fieldsBytes` still need
|
||||
/// `rowmod.decodeValue`/`rowmod.Row.decode` to become a real `Value`/field
|
||||
/// list; kept undecoded here so a malformed table name or verb byte fails
|
||||
/// fast without touching row-decoding at all.
|
||||
pub const DecodedTxnOpEntry = struct {
|
||||
verb: TxnVerb,
|
||||
table: []const u8,
|
||||
pkBytes: []const u8,
|
||||
fieldsBytes: []const u8,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user