|
20 | 20 | import Foundation |
21 | 21 |
|
22 | 22 | package enum BazelProtobufBindings { |
23 | | - package static func parseQueryTargets(data: Data) throws -> [BlazeQuery_Target] { |
24 | | - var targets: [BlazeQuery_Target] = [] |
25 | | - let messages = try parseMultipleDelimitedMessages(from: data) |
26 | | - for message in messages { |
27 | | - let target = try BlazeQuery_Target(serializedBytes: message) |
28 | | - targets.append(target) |
29 | | - } |
30 | | - |
31 | | - return targets |
32 | | - } |
33 | | - |
34 | 23 | package static func parseActionGraph(data: Data) throws -> Analysis_ActionGraphContainer { |
35 | 24 | try Analysis_ActionGraphContainer(serializedBytes: data) |
36 | 25 | } |
37 | | -} |
38 | | - |
39 | | -extension BazelProtobufBindings { |
40 | | - /// Bazel query outputs a series of messages and each one is prefixed with length to indicate |
41 | | - /// the number of bytes in the payload. Returns a tuple of (value, bytesConsumed). |
42 | | - /// Protobuf [documentation](https://protobuf.dev/programming-guides/encoding/) provides more |
43 | | - /// details on how `varint` works. |
44 | | - private static func parseVarint( |
45 | | - from data: Data, |
46 | | - startIndex: Int |
47 | | - ) throws -> (UInt64, Int) { |
48 | | - guard startIndex < data.count else { |
49 | | - throw VarintError.truncated |
50 | | - } |
51 | | - |
52 | | - var result: UInt64 = 0 |
53 | | - var shift = 0 |
54 | | - var bytesRead = 0 |
55 | | - var index = startIndex |
56 | | - |
57 | | - while index < data.count { |
58 | | - let byte = data[index] |
59 | | - bytesRead += 1 |
60 | | - index += 1 |
61 | | - |
62 | | - // Check for overflow (varints can be at most 10 bytes for 64-bit values) |
63 | | - if bytesRead > 10 { |
64 | | - throw VarintError.overflow |
65 | | - } |
66 | | - |
67 | | - // Extract the 7 data bits |
68 | | - let dataBits = UInt64(byte & 0x7F) |
69 | | - |
70 | | - // Check for shift overflow |
71 | | - if shift >= 64 { |
72 | | - throw VarintError.overflow |
73 | | - } |
74 | | - |
75 | | - // little-endian -> big-endian |
76 | | - result |= dataBits << shift |
77 | | - |
78 | | - // If the continuation bit (MSB) is not set, we're done |
79 | | - if (byte & 0x80) == 0 { |
80 | | - return (result, bytesRead) |
81 | | - } |
82 | | - |
83 | | - shift += 7 |
84 | | - } |
85 | 26 |
|
86 | | - // If we get here, the varint was truncated |
87 | | - throw VarintError.truncated |
| 27 | + package static func parseCqueryResult(data: Data) throws -> Analysis_CqueryResult { |
| 28 | + try Analysis_CqueryResult(serializedBytes: data) |
88 | 29 | } |
89 | | - |
90 | | - /// Parse the length prefix and return the message data |
91 | | - private static func parseDelimitedMessage( |
92 | | - from data: Data, |
93 | | - startIndex: Int = 0 |
94 | | - ) throws -> (Data, Int) { |
95 | | - let (messageLength, lengthBytes) = try parseVarint( |
96 | | - from: data, |
97 | | - startIndex: startIndex |
98 | | - ) |
99 | | - |
100 | | - let messageStart = startIndex + lengthBytes |
101 | | - let messageEnd = messageStart + Int(messageLength) |
102 | | - |
103 | | - guard messageEnd <= data.count else { |
104 | | - throw VarintError.truncated |
105 | | - } |
106 | | - |
107 | | - let messageData = data.subdata(in: messageStart..<messageEnd) |
108 | | - let totalBytesConsumed = lengthBytes + Int(messageLength) |
109 | | - |
110 | | - return (messageData, totalBytesConsumed) |
111 | | - } |
112 | | - |
113 | | - /// Parse multiple delimited messages from a data stream |
114 | | - private static func parseMultipleDelimitedMessages(from data: Data) throws -> [Data] { |
115 | | - var messages: [Data] = [] |
116 | | - var currentIndex = 0 |
117 | | - |
118 | | - while currentIndex < data.count { |
119 | | - let (messageData, bytesConsumed) = try parseDelimitedMessage( |
120 | | - from: data, |
121 | | - startIndex: currentIndex |
122 | | - ) |
123 | | - messages.append(messageData) |
124 | | - currentIndex += bytesConsumed |
125 | | - } |
126 | | - |
127 | | - return messages |
128 | | - } |
129 | | -} |
130 | | - |
131 | | -package enum VarintError: Error { |
132 | | - case truncated |
133 | | - case overflow |
134 | | - case invalidData |
135 | 30 | } |
0 commit comments