| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 1 | /* | 
|  | 2 | * Licensed to the Apache Software Foundation (ASF) under one | 
|  | 3 | * or more contributor license agreements. See the NOTICE file | 
|  | 4 | * distributed with this work for additional information | 
|  | 5 | * regarding copyright ownership. The ASF licenses this file | 
|  | 6 | * to you under the Apache License, Version 2.0 (the | 
|  | 7 | * "License"); you may not use this file except in compliance | 
|  | 8 | * with the License. You may obtain a copy of the License at | 
|  | 9 | * | 
|  | 10 | *   http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 11 | * | 
|  | 12 | * Unless required by applicable law or agreed to in writing, | 
|  | 13 | * software distributed under the License is distributed on an | 
|  | 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | 15 | * KIND, either express or implied. See the License for the | 
|  | 16 | * specific language governing permissions and limitations | 
|  | 17 | * under the License. | 
|  | 18 | */ | 
|  | 19 |  | 
|  | 20 | import Foundation | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 21 |  | 
|  | 22 | public enum TMessageType: Int32 { | 
|  | 23 | case call = 1 | 
|  | 24 | case reply = 2 | 
|  | 25 | case exception = 3 | 
|  | 26 | case oneway = 4 | 
|  | 27 | } | 
|  | 28 |  | 
|  | 29 | public enum TType: Int32 { | 
|  | 30 | case stop     = 0 | 
|  | 31 | case void     = 1 | 
|  | 32 | case bool     = 2 | 
|  | 33 | case i8       = 3 | 
|  | 34 | case double   = 4 | 
|  | 35 | case i16      = 6 | 
|  | 36 | case i32      = 8 | 
|  | 37 | case i64      = 10 | 
|  | 38 | case string   = 11 | 
|  | 39 | case `struct` = 12 | 
|  | 40 | case map      = 13 | 
|  | 41 | case set      = 14 | 
|  | 42 | case list     = 15 | 
|  | 43 | case utf8     = 16 | 
| Kino Roy | a9da9eb | 2022-10-07 23:13:01 -0700 | [diff] [blame^] | 44 | //case utf16    = 17 | 
|  | 45 | case uuid     = 17 | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 46 | } | 
|  | 47 |  | 
|  | 48 | public protocol TProtocol { | 
|  | 49 | var transport: TTransport { get set } | 
|  | 50 | init(on transport: TTransport) | 
|  | 51 | // Reading Methods | 
|  | 52 |  | 
|  | 53 | func readMessageBegin() throws -> (String, TMessageType, Int32) | 
|  | 54 | func readMessageEnd() throws | 
|  | 55 | func readStructBegin() throws -> String | 
|  | 56 | func readStructEnd() throws | 
|  | 57 | func readFieldBegin() throws -> (String, TType, Int32) | 
|  | 58 | func readFieldEnd() throws | 
|  | 59 | func readMapBegin() throws -> (TType, TType, Int32) | 
|  | 60 | func readMapEnd() throws | 
|  | 61 | func readSetBegin() throws -> (TType, Int32) | 
|  | 62 | func readSetEnd() throws | 
|  | 63 | func readListBegin() throws -> (TType, Int32) | 
|  | 64 | func readListEnd() throws | 
|  | 65 |  | 
|  | 66 | func read() throws -> String | 
|  | 67 | func read() throws -> Bool | 
|  | 68 | func read() throws -> UInt8 | 
| Kino Roy | a9da9eb | 2022-10-07 23:13:01 -0700 | [diff] [blame^] | 69 | func read() throws -> Int8 | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 70 | func read() throws -> Int16 | 
|  | 71 | func read() throws -> Int32 | 
|  | 72 | func read() throws -> Int64 | 
|  | 73 | func read() throws -> Double | 
|  | 74 | func read() throws -> Data | 
| Kino Roy | a9da9eb | 2022-10-07 23:13:01 -0700 | [diff] [blame^] | 75 | func read() throws -> UUID | 
|  | 76 |  | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 77 | // Writing methods | 
|  | 78 |  | 
|  | 79 | func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws | 
|  | 80 | func writeMessageEnd() throws | 
|  | 81 | func writeStructBegin(name: String) throws | 
|  | 82 | func writeStructEnd() throws | 
|  | 83 | func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws | 
|  | 84 | func writeFieldStop() throws | 
|  | 85 | func writeFieldEnd() throws | 
|  | 86 | func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws | 
|  | 87 | func writeMapEnd() throws | 
|  | 88 | func writeSetBegin(elementType: TType, size: Int32) throws | 
|  | 89 | func writeSetEnd() throws | 
|  | 90 | func writeListBegin(elementType: TType, size: Int32) throws | 
|  | 91 | func writeListEnd() throws | 
|  | 92 |  | 
|  | 93 | func write(_ value: String) throws | 
|  | 94 | func write(_ value: Bool) throws | 
|  | 95 | func write(_ value: UInt8) throws | 
| Kino Roy | a9da9eb | 2022-10-07 23:13:01 -0700 | [diff] [blame^] | 96 | func write(_ value: Int8) throws | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 97 | func write(_ value: Int16) throws | 
|  | 98 | func write(_ value: Int32) throws | 
|  | 99 | func write(_ value: Int64) throws | 
|  | 100 | func write(_ value: Double) throws | 
|  | 101 | func write(_ value: Data) throws | 
| Kino Roy | a9da9eb | 2022-10-07 23:13:01 -0700 | [diff] [blame^] | 102 | func write(_ value: UUID) throws | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 103 | } | 
|  | 104 |  | 
|  | 105 | public extension TProtocol { | 
| Antoine Cœur | 08a6eb6 | 2019-07-08 18:42:09 +0800 | [diff] [blame] | 106 | func writeFieldValue(_ value: TSerializable, name: String, type: TType, id: Int32) throws { | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 107 | try writeFieldBegin(name: name, type: type, fieldID: id) | 
|  | 108 | try value.write(to: self) | 
|  | 109 | try writeFieldEnd() | 
|  | 110 | } | 
|  | 111 |  | 
| Antoine Cœur | 08a6eb6 | 2019-07-08 18:42:09 +0800 | [diff] [blame] | 112 | func validateValue(_ value: Any?, named name: String) throws { | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 113 | if value == nil { | 
|  | 114 | throw TProtocolError(error: .unknown, message: "Missing required value for field: \(name)") | 
|  | 115 | } | 
|  | 116 | } | 
|  | 117 |  | 
| Antoine Cœur | 08a6eb6 | 2019-07-08 18:42:09 +0800 | [diff] [blame] | 118 | func readResultMessageBegin() throws { | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 119 | let (_, type, _) = try readMessageBegin(); | 
|  | 120 | if type == .exception { | 
|  | 121 | let x = try readException() | 
|  | 122 | throw x | 
|  | 123 | } | 
|  | 124 | return | 
|  | 125 | } | 
|  | 126 |  | 
| Antoine Cœur | 08a6eb6 | 2019-07-08 18:42:09 +0800 | [diff] [blame] | 127 | func readException() throws -> TApplicationError { | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 128 | return try TApplicationError.read(from: self) | 
|  | 129 | } | 
|  | 130 |  | 
| Antoine Cœur | 08a6eb6 | 2019-07-08 18:42:09 +0800 | [diff] [blame] | 131 | func writeException(messageName name: String, sequenceID: Int32, ex: TApplicationError) throws { | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 132 | try writeMessageBegin(name: name, type: .exception, sequenceID: sequenceID) | 
|  | 133 | try ex.write(to: self) | 
|  | 134 | try writeMessageEnd() | 
|  | 135 | } | 
|  | 136 |  | 
| Antoine Cœur | 08a6eb6 | 2019-07-08 18:42:09 +0800 | [diff] [blame] | 137 | func skip(type: TType) throws { | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 138 | switch type { | 
|  | 139 | case .bool:   _ = try read() as Bool | 
| Kino Roy | a9da9eb | 2022-10-07 23:13:01 -0700 | [diff] [blame^] | 140 | case .i8:   _ = try read() as Int8 | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 141 | case .i16:    _ = try read() as Int16 | 
|  | 142 | case .i32:    _ = try read() as Int32 | 
|  | 143 | case .i64:    _ = try read() as Int64 | 
|  | 144 | case .double: _ = try read() as Double | 
|  | 145 | case .string: _ = try read() as String | 
| Kino Roy | a9da9eb | 2022-10-07 23:13:01 -0700 | [diff] [blame^] | 146 | case .uuid: _ = try read() as UUID | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 147 |  | 
|  | 148 | case .struct: | 
|  | 149 | _ = try readStructBegin() | 
|  | 150 | while true { | 
|  | 151 | let (_, fieldType, _) = try readFieldBegin() | 
|  | 152 | if fieldType == .stop { | 
|  | 153 | break | 
|  | 154 | } | 
|  | 155 | try skip(type: fieldType) | 
|  | 156 | try readFieldEnd() | 
|  | 157 | } | 
|  | 158 | try readStructEnd() | 
|  | 159 |  | 
|  | 160 |  | 
|  | 161 | case .map: | 
|  | 162 | let (keyType, valueType, size) = try readMapBegin() | 
|  | 163 | for _ in 0..<size { | 
|  | 164 | try skip(type: keyType) | 
|  | 165 | try skip(type: valueType) | 
|  | 166 | } | 
|  | 167 | try readMapEnd() | 
|  | 168 |  | 
|  | 169 |  | 
|  | 170 | case .set: | 
|  | 171 | let (elemType, size) = try readSetBegin() | 
|  | 172 | for _ in 0..<size { | 
|  | 173 | try skip(type: elemType) | 
|  | 174 | } | 
|  | 175 | try readSetEnd() | 
|  | 176 |  | 
|  | 177 | case .list: | 
|  | 178 | let (elemType, size) = try readListBegin() | 
|  | 179 | for _ in 0..<size { | 
|  | 180 | try skip(type: elemType) | 
|  | 181 | } | 
|  | 182 | try readListEnd() | 
| James E. King III | dbc1f8d | 2019-02-14 16:46:38 -0500 | [diff] [blame] | 183 |  | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 184 | default: | 
| James E. King III | dbc1f8d | 2019-02-14 16:46:38 -0500 | [diff] [blame] | 185 | throw TProtocolError(error: .invalidData, message: "Invalid data") | 
| Chris Simpson | a9b6c70 | 2018-04-08 07:11:37 -0400 | [diff] [blame] | 186 | } | 
|  | 187 | } | 
|  | 188 | } |