A single pkt-line in the Git protocol.
The format of a pkt-line is documented in protocol-common. The special meanings of the delimiter and response-end packets are documented in protocol-v2.
pub const Packet = union(enum)
pub const Packet = union(enum) {
flush,
delimiter,
response_end,
data: []const u8,
pub const max_data_length = 65516;
/// Reads a packet in pkt-line format.
fn read(reader: *Io.Reader) !Packet {
const packet: Packet = try .peek(reader);
switch (packet) {
.data => |data| reader.toss(data.len),
else => {},
}
return packet;
}
/// Consumes the header of a pkt-line packet and reads any associated data
/// into the reader's buffer, but does not consume the data.
fn peek(reader: *Io.Reader) !Packet {
const length = std.fmt.parseUnsigned(u16, try reader.take(4), 16) catch return error.InvalidPacket;
switch (length) {
0 => return .flush,
1 => return .delimiter,
2 => return .response_end,
3 => return error.InvalidPacket,
else => if (length - 4 > max_data_length) return error.InvalidPacket,
}
return .{ .data = try reader.peek(length - 4) };
}
/// Writes a packet in pkt-line format.
fn write(packet: Packet, writer: *Io.Writer) !void {
switch (packet) {
.flush => try writer.writeAll("0000"),
.delimiter => try writer.writeAll("0001"),
.response_end => try writer.writeAll("0002"),
.data => |data| {
assert(data.len <= max_data_length);
try writer.print("{x:0>4}", .{data.len + 4});
try writer.writeAll(data);
},
}
}
/// Returns the normalized form of textual packet data, stripping any
/// trailing '\n'.
///
/// As documented in
/// [protocol-common](https://git-scm.com/docs/protocol-common#_pkt_line_format),
/// non-binary (textual) pkt-line data should contain a trailing '\n', but
/// is not required to do so (implementations must support both forms).
fn normalizeText(data: []const u8) []const u8 {
return if (mem.endsWith(u8, data, "\n"))
data[0 .. data.len - 1]
else
data;
}
}