Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[swift] Provide a default value for sub fields and common types as per proto spec #2650

Merged
merged 1 commit into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ plugin*.xml

# SPM
.build
.swiftpm

# Special Mkdocs files
docs/3.x
Expand Down
99 changes: 44 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -571,43 +571,25 @@ public struct Dinosaur {
/**
* Common name of this dinosaur, like "Stegosaurus".
*/
@ProtoDefaulted
public var name: String?
/**
* URLs with images of this dinosaur.
*/
public var picture_urls: [String] = []
@ProtoDefaulted
public var length_meters: Double?
@ProtoDefaulted
public var mass_kilograms: Double?
public var period: Period?
public var unknownFields: Foundation.Data = .init()

public init(configure: (inout Self) -> Void = { _ in }) {
public init(configure: (inout Self) -> Swift.Void = { _ in }) {
configure(&self)
}

}

#if WIRE_INCLUDE_MEMBERWISE_INITIALIZER
extension Dinosaur {

@_disfavoredOverload
public init(
name: String? = nil,
picture_urls: [String] = [],
length_meters: Double? = nil,
mass_kilograms: Double? = nil,
period: Period? = nil
) {
self.name = name
self.picture_urls = picture_urls
self.length_meters = length_meters
self.mass_kilograms = mass_kilograms
self.period = period
}

}
#endif

#if !WIRE_REMOVE_EQUATABLE
extension Dinosaur : Equatable {
}
Expand All @@ -623,68 +605,75 @@ extension Dinosaur : Sendable {
}
#endif

extension Dinosaur : ProtoDefaultedValue {

public static var defaultedValue: Dinosaur {
Dinosaur()
}
}

extension Dinosaur : ProtoMessage {

public static func protoMessageTypeURL() -> String {
public static func protoMessageTypeURL() -> Swift.String {
return "type.googleapis.com/squareup.dinosaurs.Dinosaur"
}

}

extension Dinosaur : Proto2Codable {

public init(from reader: ProtoReader) throws {
var name: String? = nil
var picture_urls: [String] = []
var length_meters: Double? = nil
var mass_kilograms: Double? = nil
public init(from protoReader: Wire.ProtoReader) throws {
var name: Swift.String? = nil
var picture_urls: [Swift.String] = []
var length_meters: Swift.Double? = nil
var mass_kilograms: Swift.Double? = nil
var period: Period? = nil

let token = try reader.beginMessage()
while let tag = try reader.nextTag(token: token) {
let token = try protoReader.beginMessage()
while let tag = try protoReader.nextTag(token: token) {
switch tag {
case 1: name = try reader.decode(String.self)
case 2: try reader.decode(into: &picture_urls)
case 3: length_meters = try reader.decode(Double.self)
case 4: mass_kilograms = try reader.decode(Double.self)
case 5: period = try reader.decode(Period.self)
default: try reader.readUnknownField(tag: tag)
case 1: name = try protoReader.decode(Swift.String.self)
case 2: try protoReader.decode(into: &picture_urls)
case 3: length_meters = try protoReader.decode(Swift.Double.self)
case 4: mass_kilograms = try protoReader.decode(Swift.Double.self)
case 5: period = try protoReader.decode(Period.self)
default: try protoReader.readUnknownField(tag: tag)
}
}
self.unknownFields = try reader.endMessage(token: token)
self.unknownFields = try protoReader.endMessage(token: token)

self.name = name
self._name.wrappedValue = name
self.picture_urls = picture_urls
self.length_meters = length_meters
self.mass_kilograms = mass_kilograms
self._length_meters.wrappedValue = length_meters
self._mass_kilograms.wrappedValue = mass_kilograms
self.period = period
}

public func encode(to writer: ProtoWriter) throws {
try writer.encode(tag: 1, value: self.name)
try writer.encode(tag: 2, value: self.picture_urls)
try writer.encode(tag: 3, value: self.length_meters)
try writer.encode(tag: 4, value: self.mass_kilograms)
try writer.encode(tag: 5, value: self.period)
try writer.writeUnknownFields(unknownFields)
public func encode(to protoWriter: Wire.ProtoWriter) throws {
try protoWriter.encode(tag: 1, value: self.name)
try protoWriter.encode(tag: 2, value: self.picture_urls)
try protoWriter.encode(tag: 3, value: self.length_meters)
try protoWriter.encode(tag: 4, value: self.mass_kilograms)
try protoWriter.encode(tag: 5, value: self.period)
try protoWriter.writeUnknownFields(unknownFields)
}

}

#if !WIRE_REMOVE_CODABLE
extension Dinosaur : Codable {

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringLiteralCodingKeys.self)
self.name = try container.decodeIfPresent(String.self, forKey: "name")
self.picture_urls = try container.decodeProtoArray(String.self, firstOfKeys: "pictureUrls", "picture_urls")
self.length_meters = try container.decodeIfPresent(Double.self, firstOfKeys: "lengthMeters", "length_meters")
self.mass_kilograms = try container.decodeIfPresent(Double.self, firstOfKeys: "massKilograms", "mass_kilograms")
public init(from decoder: Swift.Decoder) throws {
let container = try decoder.container(keyedBy: Wire.StringLiteralCodingKeys.self)
self._name.wrappedValue = try container.decodeIfPresent(Swift.String.self, forKey: "name")
self.picture_urls = try container.decodeProtoArray(Swift.String.self, firstOfKeys: "pictureUrls", "picture_urls")
self._length_meters.wrappedValue = try container.decodeIfPresent(Swift.Double.self, firstOfKeys: "lengthMeters", "length_meters")
self._mass_kilograms.wrappedValue = try container.decodeIfPresent(Swift.Double.self, firstOfKeys: "massKilograms", "mass_kilograms")
self.period = try container.decodeIfPresent(Period.self, forKey: "period")
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringLiteralCodingKeys.self)
public func encode(to encoder: Swift.Encoder) throws {
var container = encoder.container(keyedBy: Wire.StringLiteralCodingKeys.self)
let preferCamelCase = encoder.protoKeyNameEncodingStrategy == .camelCase
let includeDefaults = encoder.protoDefaultValuesEncodingStrategy == .include

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ import Foundation

// MARK: -

extension Bool : ProtoCodable {
extension Bool : ProtoCodable, ProtoDefaultedValue {

// MARK: - ProtoDefaultedValue

public static var defaultedValue: Bool {
false
}

// MARK: - ProtoDecodable

Expand All @@ -40,7 +46,13 @@ extension Bool : ProtoCodable {

// MARK: -

extension Data : ProtoCodable {
extension Data : ProtoCodable, ProtoDefaultedValue {

// MARK: - ProtoDefaultedValue

public static var defaultedValue: Data {
Data()
}

// MARK: - ProtoDecodable

Expand All @@ -61,7 +73,7 @@ extension Data : ProtoCodable {

// MARK: -

extension Double : ProtoCodable {
extension Double : ProtoCodable, ProtoDefaultedValue {

// MARK: - ProtoDecodable

Expand All @@ -84,7 +96,7 @@ extension Double : ProtoCodable {

// MARK: -

extension Float : ProtoCodable {
extension Float : ProtoCodable, ProtoDefaultedValue {

// MARK: - ProtoDecodable

Expand All @@ -107,7 +119,13 @@ extension Float : ProtoCodable {

// MARK: -

extension String : ProtoCodable {
extension String : ProtoCodable, ProtoDefaultedValue {

// MARK: - ProtoDefaultedValue

public static var defaultedValue: String {
""
}

// MARK: - ProtoDecodable

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Foundation

// MARK: -

extension Int32: ProtoIntCodable {
extension Int32: ProtoIntCodable, ProtoDefaultedValue {

// MARK: - ProtoIntDecodable

Expand Down Expand Up @@ -56,7 +56,7 @@ extension Int32: ProtoIntCodable {

// MARK: -

extension UInt32: ProtoIntCodable {
extension UInt32: ProtoIntCodable, ProtoDefaultedValue {

// MARK: - ProtoIntDecodable

Expand Down Expand Up @@ -93,7 +93,7 @@ extension UInt32: ProtoIntCodable {

// MARK: -

extension Int64: ProtoIntCodable {
extension Int64: ProtoIntCodable, ProtoDefaultedValue {

// MARK: - ProtoIntDecodable

Expand Down Expand Up @@ -132,7 +132,7 @@ extension Int64: ProtoIntCodable {

// MARK: -

extension UInt64: ProtoIntCodable {
extension UInt64: ProtoIntCodable, ProtoDefaultedValue {

// MARK: - ProtoIntDecodable

Expand Down
12 changes: 8 additions & 4 deletions wire-runtime-swift/src/main/swift/Redactable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,20 @@ extension Redactable {
guard let label = label else {
return "\(value)"
}
if RedactedKeys(rawValue: label) != nil {
var strippedLabel = label
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is an existing bug today. If a custom default value was specified due to applying @Defaulted the internal property is renamed with a _ in front. This fails this check.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test caught this now because we emit @Defaulted identity types for many properties which now as an empty string exacerbated this issue which is now fixed and the test passes.

if (label.hasPrefix("_")) {
strippedLabel = String(label.dropFirst(1))
}
if RedactedKeys(rawValue: strippedLabel) != nil {
// This is a redacted field, but if it's nil then that's ok to print
if "\(value)" != "nil" {
return "\(label): <redacted>"
return "\(strippedLabel): <redacted>"
}
}
if value is String {
return "\(label): \"\(value)\""
return "\(strippedLabel): \"\(value)\""
}
return "\(label): \(value)"
return "\(strippedLabel): \(value)"
}

if fields.count > 0 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
*/
import Foundation

@available(*, deprecated, message: "Replace with CustomDefaulted")
public typealias Defaulted = CustomDefaulted

/**
When applied to field a projected value is provided for accessing the real value
or the default value set.
*/
@propertyWrapper
public struct Defaulted<Value> {
public struct CustomDefaulted<Value> {

public var wrappedValue: Value?
let defaultValue: Value
Expand All @@ -34,15 +37,15 @@ public struct Defaulted<Value> {
}
}

extension Defaulted : Equatable where Value : Equatable {
extension CustomDefaulted : Equatable where Value : Equatable {
}

extension Defaulted : Hashable where Value : Hashable {
extension CustomDefaulted : Hashable where Value : Hashable {
}

#if swift(>=5.5)

extension Defaulted : Sendable where Value : Sendable {
extension CustomDefaulted : Sendable where Value : Sendable {
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2023 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public protocol ProtoDefaultedValue {
static var defaultedValue: Self { get }
}

// MARK: - ProtoDefaultedValue

extension Numeric where Self: ProtoDefaultedValue {
public static var defaultedValue: Self {
.zero
}
}

// MARK: - ProtoDefaulted

@propertyWrapper
public struct ProtoDefaulted<Value: ProtoDefaultedValue> {
public var wrappedValue: Value?

public init() {
}

public var projectedValue: Value {
wrappedValue ?? Value.defaultedValue
}
}

extension ProtoDefaulted : Equatable where Value : Equatable {
}

extension ProtoDefaulted : Hashable where Value : Hashable {
}

#if swift(>=5.5)

extension ProtoDefaulted : Sendable where Value : Sendable {
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ extension OneofOptions : Sendable {
}
#endif

extension OneofOptions : ProtoDefaultedValue {

public static var defaultedValue: OneofOptions {
OneofOptions()
}
}

extension OneofOptions : ProtoMessage {

public static func protoMessageTypeURL() -> Swift.String {
Expand Down
Loading
Loading