* Changing default timeout for start maintenance. * Upgrading dependencies to gorealis v2 and thrift 0.12.0 * Refactored to update to gorealis v2.
100 lines
3.5 KiB
Swift
100 lines
3.5 KiB
Swift
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you 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
|
|
*
|
|
* http://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.
|
|
*/
|
|
|
|
|
|
/// Protocol for Generated Structs to conform to
|
|
/// Dictionary maps field names to internal IDs and uses Reflection
|
|
/// to iterate through all fields.
|
|
/// `writeFieldValue(_:name:type:id:)` calls `TSerializable.write(to:)` internally
|
|
/// giving a nice recursive behavior for nested TStructs, TLists, TMaps, and TSets
|
|
public protocol TStruct : TSerializable {
|
|
static var fieldIds: [String: Int32] { get }
|
|
static var structName: String { get }
|
|
}
|
|
|
|
public extension TStruct {
|
|
public static var fieldIds: [String: (id: Int32, type: TType)] { return [:] }
|
|
public static var thriftType: TType { return .struct }
|
|
|
|
public func write(to proto: TProtocol) throws {
|
|
// Write struct name first
|
|
try proto.writeStructBegin(name: Self.structName)
|
|
|
|
try self.forEach { name, value, id in
|
|
// Write to protocol
|
|
try proto.writeFieldValue(value, name: name,
|
|
type: value.thriftType, id: id)
|
|
}
|
|
try proto.writeFieldStop()
|
|
try proto.writeStructEnd()
|
|
}
|
|
|
|
public var hashValue: Int {
|
|
let prime = 31
|
|
var result = 1
|
|
self.forEach { _, value, _ in
|
|
result = prime &* result &+ (value.hashValue)
|
|
}
|
|
return result
|
|
}
|
|
|
|
/// Provides a block for handling each (available) thrift property using reflection
|
|
/// Caveat: Skips over optional values
|
|
|
|
|
|
/// Provides a block for handling each (available) thrift property using reflection
|
|
///
|
|
/// - parameter block: block for handling property
|
|
///
|
|
/// - throws: rethrows any Error thrown in block
|
|
private func forEach(_ block: (_ name: String, _ value: TSerializable, _ id: Int32) throws -> Void) rethrows {
|
|
// Mirror the object, getting (name: String?, value: Any) for every property
|
|
let mirror = Mirror(reflecting: self)
|
|
|
|
// Iterate through all children, ignore empty property names
|
|
for (propName, propValue) in mirror.children {
|
|
guard let propName = propName else { continue }
|
|
|
|
if let tval = unwrap(any: propValue) as? TSerializable, let id = Self.fieldIds[propName] {
|
|
try block(propName, tval, id)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// Any can mysteriously be an Optional<Any> at the same time,
|
|
/// this checks and always returns Optional<Any> without double wrapping
|
|
/// we then try to bind value as TSerializable to ignore any extension properties
|
|
/// and the like and verify the property exists and grab the Thrift
|
|
/// property ID at the same time
|
|
///
|
|
/// - parameter any: Any instance to attempt to unwrap
|
|
///
|
|
/// - returns: Unwrapped Any as Optional<Any>
|
|
private func unwrap(any: Any) -> Any? {
|
|
let mi = Mirror(reflecting: any)
|
|
|
|
if mi.displayStyle != .optional { return any }
|
|
if mi.children.count == 0 { return nil }
|
|
|
|
let (_, some) = mi.children.first!
|
|
return some
|
|
}
|
|
}
|
|
|