Skip to content

Commit

Permalink
Merge pull request #1663 from mkruskal-google/delimited-fix
Browse files Browse the repository at this point in the history
Fix handling of map fields inheriting delimited encoding
  • Loading branch information
tbkka authored Jun 12, 2024
2 parents 3ecce91 + 4d7fb41 commit 0595151
Show file tree
Hide file tree
Showing 7 changed files with 666 additions and 154 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ regenerate-fuzz-protos: build ${PROTOC_GEN_SWIFT}
SWIFT_PLUGINLIB_DESCRIPTOR_TEST_PROTOS= \
Protos/SwiftProtobufPluginLibraryTests/pluginlib_descriptor_test.proto \
Protos/SwiftProtobufPluginLibraryTests/pluginlib_descriptor_test2.proto \
Protos/SwiftProtobufPluginLibraryTests/pluginlib_descriptor_delimited.proto \
Protos/SwiftProtobufPluginLibraryTests/google/protobuf/unittest_delimited.proto \
Protos/SwiftProtobufPluginLibraryTests/google/protobuf/unittest_delimited_import.proto \
Protos/SwiftProtobufPluginLibrary/google/protobuf/compiler/plugin.proto \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Protos/pluginlib_descriptor_test.proto - test proto
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
// -----------------------------------------------------------------------------
///
/// Test proto for Tests/SwiftProtobufPluginLibraryTests/Test_Descriptor.swift
///
// -----------------------------------------------------------------------------

edition = "2023";

package swift_descriptor_test;

option features.message_encoding = DELIMITED;

message EditionsMessageForDelimited {
int32 scalar_field = 1;
map<int32, string> map_field = 2;
map<int32, EditionsMessageForDelimited> message_map_field = 3;
EditionsMessageForDelimited delimited_field = 4;
EditionsMessageForDelimited length_prefixed_field = 5 [
features.message_encoding = LENGTH_PREFIXED
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: pluginlib_descriptor_delimited.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/

// Protos/pluginlib_descriptor_test.proto - test proto
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
// -----------------------------------------------------------------------------
///
/// Test proto for Tests/SwiftProtobufPluginLibraryTests/Test_Descriptor.swift
///
// -----------------------------------------------------------------------------

import Foundation
import SwiftProtobuf

// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}

struct SwiftDescriptorTest_EditionsMessageForDelimited: @unchecked Sendable {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.

var scalarField: Int32 {
get {return _storage._scalarField ?? 0}
set {_uniqueStorage()._scalarField = newValue}
}
/// Returns true if `scalarField` has been explicitly set.
var hasScalarField: Bool {return _storage._scalarField != nil}
/// Clears the value of `scalarField`. Subsequent reads from it will return its default value.
mutating func clearScalarField() {_uniqueStorage()._scalarField = nil}

var mapField: Dictionary<Int32,String> {
get {return _storage._mapField}
set {_uniqueStorage()._mapField = newValue}
}

var messageMapField: Dictionary<Int32,SwiftDescriptorTest_EditionsMessageForDelimited> {
get {return _storage._messageMapField}
set {_uniqueStorage()._messageMapField = newValue}
}

var delimitedField: SwiftDescriptorTest_EditionsMessageForDelimited {
get {return _storage._delimitedField ?? SwiftDescriptorTest_EditionsMessageForDelimited()}
set {_uniqueStorage()._delimitedField = newValue}
}
/// Returns true if `delimitedField` has been explicitly set.
var hasDelimitedField: Bool {return _storage._delimitedField != nil}
/// Clears the value of `delimitedField`. Subsequent reads from it will return its default value.
mutating func clearDelimitedField() {_uniqueStorage()._delimitedField = nil}

var lengthPrefixedField: SwiftDescriptorTest_EditionsMessageForDelimited {
get {return _storage._lengthPrefixedField ?? SwiftDescriptorTest_EditionsMessageForDelimited()}
set {_uniqueStorage()._lengthPrefixedField = newValue}
}
/// Returns true if `lengthPrefixedField` has been explicitly set.
var hasLengthPrefixedField: Bool {return _storage._lengthPrefixedField != nil}
/// Clears the value of `lengthPrefixedField`. Subsequent reads from it will return its default value.
mutating func clearLengthPrefixedField() {_uniqueStorage()._lengthPrefixedField = nil}

var unknownFields = SwiftProtobuf.UnknownStorage()

init() {}

fileprivate var _storage = _StorageClass.defaultInstance
}

// MARK: - Code below here is support for the SwiftProtobuf runtime.

fileprivate let _protobuf_package = "swift_descriptor_test"

extension SwiftDescriptorTest_EditionsMessageForDelimited: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".EditionsMessageForDelimited"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "scalar_field"),
2: .standard(proto: "map_field"),
3: .standard(proto: "message_map_field"),
4: .standard(proto: "delimited_field"),
5: .standard(proto: "length_prefixed_field"),
]

fileprivate class _StorageClass {
var _scalarField: Int32? = nil
var _mapField: Dictionary<Int32,String> = [:]
var _messageMapField: Dictionary<Int32,SwiftDescriptorTest_EditionsMessageForDelimited> = [:]
var _delimitedField: SwiftDescriptorTest_EditionsMessageForDelimited? = nil
var _lengthPrefixedField: SwiftDescriptorTest_EditionsMessageForDelimited? = nil

#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif

private init() {}

init(copying source: _StorageClass) {
_scalarField = source._scalarField
_mapField = source._mapField
_messageMapField = source._messageMapField
_delimitedField = source._delimitedField
_lengthPrefixedField = source._lengthPrefixedField
}
}

fileprivate mutating func _uniqueStorage() -> _StorageClass {
if !isKnownUniquelyReferenced(&_storage) {
_storage = _StorageClass(copying: _storage)
}
return _storage
}

mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
_ = _uniqueStorage()
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt32Field(value: &_storage._scalarField) }()
case 2: try { try decoder.decodeMapField(fieldType: SwiftProtobuf._ProtobufMap<SwiftProtobuf.ProtobufInt32,SwiftProtobuf.ProtobufString>.self, value: &_storage._mapField) }()
case 3: try { try decoder.decodeMapField(fieldType: SwiftProtobuf._ProtobufMessageMap<SwiftProtobuf.ProtobufInt32,SwiftDescriptorTest_EditionsMessageForDelimited>.self, value: &_storage._messageMapField) }()
case 4: try { try decoder.decodeSingularGroupField(value: &_storage._delimitedField) }()
case 5: try { try decoder.decodeSingularMessageField(value: &_storage._lengthPrefixedField) }()
default: break
}
}
}
}

func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = _storage._scalarField {
try visitor.visitSingularInt32Field(value: v, fieldNumber: 1)
} }()
if !_storage._mapField.isEmpty {
try visitor.visitMapField(fieldType: SwiftProtobuf._ProtobufMap<SwiftProtobuf.ProtobufInt32,SwiftProtobuf.ProtobufString>.self, value: _storage._mapField, fieldNumber: 2)
}
if !_storage._messageMapField.isEmpty {
try visitor.visitMapField(fieldType: SwiftProtobuf._ProtobufMessageMap<SwiftProtobuf.ProtobufInt32,SwiftDescriptorTest_EditionsMessageForDelimited>.self, value: _storage._messageMapField, fieldNumber: 3)
}
try { if let v = _storage._delimitedField {
try visitor.visitSingularGroupField(value: v, fieldNumber: 4)
} }()
try { if let v = _storage._lengthPrefixedField {
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
} }()
}
try unknownFields.traverse(visitor: &visitor)
}

static func ==(lhs: SwiftDescriptorTest_EditionsMessageForDelimited, rhs: SwiftDescriptorTest_EditionsMessageForDelimited) -> Bool {
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0
let rhs_storage = _args.1
if _storage._scalarField != rhs_storage._scalarField {return false}
if _storage._mapField != rhs_storage._mapField {return false}
if _storage._messageMapField != rhs_storage._messageMapField {return false}
if _storage._delimitedField != rhs_storage._delimitedField {return false}
if _storage._lengthPrefixedField != rhs_storage._lengthPrefixedField {return false}
return true
}
if !storagesAreEqual {return false}
}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
12 changes: 10 additions & 2 deletions Sources/SwiftProtobufPluginLibrary/Descriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,8 @@ public final class FieldDescriptor {
static let kLastReservedNumber: Int = 19999

/// Declared type of this field.
public let type: Google_Protobuf_FieldDescriptorProto.TypeEnum
public private(set) var type: Google_Protobuf_FieldDescriptorProto.TypeEnum

/// optional/required/repeated
public let label: Google_Protobuf_FieldDescriptorProto.Label

Expand Down Expand Up @@ -1046,7 +1047,14 @@ public final class FieldDescriptor {
if type == .enum {
_fieldTypeStorage = .enum(UnownedBox(value: registry.enumDescriptor(named: typeName)!))
} else {
_fieldTypeStorage = .message(UnownedBox(value: registry.descriptor(named: typeName)!))
let msgtype = registry.descriptor(named: typeName)!
_fieldTypeStorage = .message(UnownedBox(value: msgtype))
if type == .group && (
msgtype.options.mapEntry ||
(_containingType != nil && _containingType!.options.mapEntry)
) {
type = .message
}
}
}
}
Expand Down
Loading

0 comments on commit 0595151

Please sign in to comment.