Skip to content

Commit

Permalink
[swift] Provide a default value for sub fields and common types as pe…
Browse files Browse the repository at this point in the history
…r proto spec
  • Loading branch information
Dimitris+Adam authored and dnkoutso committed Oct 13, 2023
1 parent b9f6835 commit dd5aafe
Show file tree
Hide file tree
Showing 43 changed files with 937 additions and 353 deletions.
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
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
@@ -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
5 changes: 5 additions & 0 deletions wire-runtime-swift/src/test/swift/DefaultedTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import Wire
import XCTest

final class DefaultedTests: XCTestCase {
func testMessageIdentityValue() throws {
let d: D = D()
XCTAssertNotNil(d.$a)
}

func testProjectedValueIsDefaultValue() throws {
let phoneNumber = Person.PhoneNumber(number: "1234567890")
XCTAssertNil(phoneNumber.type)
Expand Down
Loading

0 comments on commit dd5aafe

Please sign in to comment.