Skip to content

Commit 49d0d5b

Browse files
committed
[libSyntax] Make the ByteTree protocol version consist of a major and minor component
1 parent 11bddb4 commit 49d0d5b

File tree

6 files changed

+39
-14
lines changed

6 files changed

+39
-14
lines changed

Diff for: docs/ByteTree.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Arrays are modelled as objects whose fields are all of the same type and whose l
2121

2222
## Versioning
2323

24-
The ByteTree format is prepended by a 4-byte protocol version number that describes the version of the object tree that was serialized. Its exact semantics are up to each specific application, but it is encouraged to interpret it as a two-comentent number where the first component, consisting of the first three bytes, is incremented for breaking changes and the last byte is incremented for backwards-compatible changes.
24+
The ByteTree format is prepended by a 4-byte protocol version number that describes the version of the object tree that was serialized. Its exact semantics are up to each specific application, but it is encouraged to interpret it as a two-comentent number where the first component, consisting of the three most significant bytes, is incremented for breaking changes and the last byte is incremented for backwards-compatible changes.
2525

2626
## Forward compatilibity
2727

Diff for: include/swift/Syntax/Serialization/SyntaxSerialization.h

+14
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,20 @@ struct NullableTraits<RC<syntax::RawSyntax>> {
203203

204204
namespace byteTree {
205205

206+
/// Increase the major version for every change that is not just adding a new
207+
/// field at the end of an object. Older swiftSyntax clients will no longer be
208+
/// able to deserialize the format.
209+
const uint16_t SYNTAX_TREE_VERSION_MAJOR = 1; // Last change: initial version
210+
/// Increase the minor version if only new field has been added at the end of
211+
/// an object. Older swiftSyntax clients will still be able to deserialize the
212+
/// format.
213+
const uint8_t SYNTAX_TREE_VERSION_MINOR = 0; // Last change: initial version
214+
215+
// Combine the major and minor version into one. The first three bytes
216+
// represent the major version, the last byte the minor version.
217+
const uint32_t SYNTAX_TREE_VERSION =
218+
SYNTAX_TREE_VERSION_MAJOR << 8 | SYNTAX_TREE_VERSION_MINOR;
219+
206220
/// The key for a ByteTree serializion user info of type
207221
/// `std::unordered_set<unsigned> *`. Specifies the IDs of syntax nodes that
208222
/// shall be omitted when the syntax tree gets serialized.

Diff for: tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -2448,7 +2448,8 @@ void serializeSyntaxTreeAsByteTree(
24482448
Stream.reserve(32 * 1024);
24492449
std::map<void *, void *> UserInfo;
24502450
UserInfo[swift::byteTree::UserInfoKeyReusedNodeIds] = &ReusedNodeIds;
2451-
swift::byteTree::ByteTreeWriter::write(Stream, /*ProtocolVersion=*/1,
2451+
swift::byteTree::ByteTreeWriter::write(Stream,
2452+
swift::byteTree::SYNTAX_TREE_VERSION,
24522453
*SyntaxTree.getRaw(), UserInfo);
24532454

24542455
std::unique_ptr<llvm::WritableMemoryBuffer> Buf =

Diff for: tools/SwiftSyntax/ByteTreeDeserialization.swift

+18-9
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,15 @@ struct ByteTreeObjectReader {
129129
}
130130
}
131131

132+
struct ByteTreeProtocolVersion {
133+
let major: Int
134+
let minor: Int
135+
}
136+
132137
/// Reader for reading the ByteTree format into Swift objects
133138
struct ByteTreeReader {
134139
enum DeserializationError: Error, CustomStringConvertible {
135-
case versionValidationFailed(ByteTreeReader.ProtocolVersion)
140+
case versionValidationFailed(ByteTreeProtocolVersion)
136141

137142
public var description: String {
138143
switch self {
@@ -143,9 +148,6 @@ struct ByteTreeReader {
143148
}
144149
}
145150

146-
/// The type as which the protocol version is encoded in ByteTree
147-
typealias ProtocolVersion = UInt32
148-
149151
/// A pointer pointing to the next byte of serialized data to be read
150152
private var pointer: UnsafeRawPointer
151153

@@ -173,7 +175,7 @@ struct ByteTreeReader {
173175
static func read<T: ByteTreeObjectDecodable>(
174176
_ rootObjectType: T.Type, from pointer: UnsafeRawPointer,
175177
userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]>,
176-
protocolVersionValidation: (ProtocolVersion) -> Bool
178+
protocolVersionValidation: (ByteTreeProtocolVersion) -> Bool
177179
) throws -> T {
178180
var reader = ByteTreeReader(pointer: pointer, userInfo: userInfo)
179181
try reader.readAndValidateProtocolVersion(protocolVersionValidation)
@@ -193,7 +195,7 @@ struct ByteTreeReader {
193195
static func read<T: ByteTreeObjectDecodable>(
194196
_ rootObjectType: T.Type, from data: Data,
195197
userInfo: UnsafePointer<[ByteTreeUserInfoKey: Any]>,
196-
protocolVersionValidation versionValidate: (ProtocolVersion) -> Bool
198+
protocolVersionValidation versionValidate: (ByteTreeProtocolVersion) -> Bool
197199
) throws -> T {
198200
return try data.withUnsafeBytes { (pointer: UnsafePointer<UInt8>) in
199201
let rawPointer = UnsafeRawPointer(pointer)
@@ -249,10 +251,17 @@ struct ByteTreeReader {
249251
/// - Parameter validationCallback: A callback that determines if the given
250252
/// protocol version can be read
251253
private mutating func readAndValidateProtocolVersion(
252-
_ validationCallback: (ProtocolVersion) -> Bool
254+
_ validationCallback: (ByteTreeProtocolVersion) -> Bool
253255
) throws {
254-
let protocolVersion = ProtocolVersion(littleEndian:
255-
readRaw(ProtocolVersion.self))
256+
// The first three bytes of the four byte version number make up the major
257+
// version
258+
let version = UInt32(littleEndian: readRaw(UInt32.self))
259+
// The most significant three bytes make up the major version
260+
let majorVersion = Int(version >> 8)
261+
// The least significant byte constitutes the minor version
262+
let minorVersion = Int(version & 0xff)
263+
let protocolVersion = ByteTreeProtocolVersion(major: majorVersion,
264+
minor: minorVersion)
256265
let result = validationCallback(protocolVersion)
257266
if !result {
258267
throw DeserializationError.versionValidationFailed(protocolVersion)

Diff for: tools/SwiftSyntax/SwiftSyntax.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ public final class SyntaxTreeDeserializer {
8080
userInfo[.omittedNodeLookupFunction] = self.lookupNode
8181
return try ByteTreeReader.read(RawSyntax.self, from: data,
8282
userInfo: &userInfo) {
83-
(version: ByteTreeReader.ProtocolVersion) in
84-
return version == 1
83+
(version: ByteTreeProtocolVersion) in
84+
return version.major == 1
8585
}
8686
}
8787

Diff for: tools/swift-syntax-test/swift-syntax-test.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,8 @@ int doSerializeRawTree(const char *MainExecutablePath,
737737
if (options::AddByteTreeFields) {
738738
UserInfo[swift::byteTree::UserInfoKeyAddInvalidFields] = (void *)true;
739739
}
740-
swift::byteTree::ByteTreeWriter::write(Stream, /*ProtocolVersion=*/1,
740+
swift::byteTree::ByteTreeWriter::write(Stream,
741+
byteTree::SYNTAX_TREE_VERSION,
741742
*Root, UserInfo);
742743
auto OutputBufferOrError = llvm::FileOutputBuffer::create(
743744
options::OutputFilename, Stream.data().size());

0 commit comments

Comments
 (0)