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
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 uuid     = 16
44 }
45 
46 public protocol TProtocol {
47   var transport: TTransport { get set }
48   init(on transport: TTransport)
49   // Reading Methods
50 
readMessageBeginnull51   func readMessageBegin() throws -> (String, TMessageType, Int32)
52   func readMessageEnd() throws
53   func readStructBegin() throws -> String
54   func readStructEnd() throws
55   func readFieldBegin() throws -> (String, TType, Int32)
56   func readFieldEnd() throws
57   func readMapBegin() throws -> (TType, TType, Int32)
58   func readMapEnd() throws
59   func readSetBegin() throws -> (TType, Int32)
60   func readSetEnd() throws
61   func readListBegin() throws -> (TType, Int32)
62   func readListEnd() throws
63 
64   func read() throws -> String
65   func read() throws -> Bool
66   func read() throws -> UInt8
67   func read() throws -> Int8
68   func read() throws -> Int16
69   func read() throws -> Int32
70   func read() throws -> Int64
71   func read() throws -> Double
72   func read() throws -> Data
73   func read() throws -> UUID
74 
75   // Writing methods
76 
77   func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws
78   func writeMessageEnd() throws
79   func writeStructBegin(name: String) throws
80   func writeStructEnd() throws
81   func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws
82   func writeFieldStop() throws
83   func writeFieldEnd() throws
84   func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws
85   func writeMapEnd() throws
86   func writeSetBegin(elementType: TType, size: Int32) throws
87   func writeSetEnd() throws
88   func writeListBegin(elementType: TType, size: Int32) throws
89   func writeListEnd() throws
90 
91   func write(_ value: String) throws
92   func write(_ value: Bool) throws
93   func write(_ value: UInt8) throws
94   func write(_ value: Int8) throws
95   func write(_ value: Int16) throws
96   func write(_ value: Int32) throws
97   func write(_ value: Int64) throws
98   func write(_ value: Double) throws
99   func write(_ value: Data) throws
100   func write(_ value: UUID) throws
101 }
102 
103 public extension TProtocol {
104   func writeFieldValue(_ value: TSerializable, name: String, type: TType, id: Int32) throws {
105     try writeFieldBegin(name: name, type: type, fieldID: id)
106     try value.write(to: self)
107     try writeFieldEnd()
108   }
109 
110   func validateValue(_ value: Any?, named name: String) throws {
111     if value == nil {
112       throw TProtocolError(error: .unknown, message: "Missing required value for field: \(name)")
113     }
114   }
115 
116   func readResultMessageBegin() throws {
117     let (_, type, _) = try readMessageBegin();
118     if type == .exception {
119       let x = try readException()
120       throw x
121     }
122     return
123   }
124 
125   func readException() throws -> TApplicationError {
126     return try TApplicationError.read(from: self)
127   }
128 
129   func writeException(messageName name: String, sequenceID: Int32, ex: TApplicationError) throws {
130     try writeMessageBegin(name: name, type: .exception, sequenceID: sequenceID)
131     try ex.write(to: self)
132     try writeMessageEnd()
133   }
134 
135   func skip(type: TType) throws {
136     switch type {
137     case .bool:   _ = try read() as Bool
138     case .i8:   _ = try read() as Int8
139     case .i16:    _ = try read() as Int16
140     case .i32:    _ = try read() as Int32
141     case .i64:    _ = try read() as Int64
142     case .double: _ = try read() as Double
143     case .string: _ = try read() as String
144     case .uuid: _ = try read() as UUID
145 
146     case .struct:
147       _ = try readStructBegin()
148       while true {
149         let (_, fieldType, _) = try readFieldBegin()
150         if fieldType == .stop {
151           break
152         }
153         try skip(type: fieldType)
154         try readFieldEnd()
155       }
156       try readStructEnd()
157 
158 
159     case .map:
160       let (keyType, valueType, size) = try readMapBegin()
161       for _ in 0..<size {
162         try skip(type: keyType)
163         try skip(type: valueType)
164       }
165       try readMapEnd()
166 
167 
168     case .set:
169       let (elemType, size) = try readSetBegin()
170       for _ in 0..<size {
171         try skip(type: elemType)
172       }
173       try readSetEnd()
174 
175     case .list:
176       let (elemType, size) = try readListBegin()
177       for _ in 0..<size {
178         try skip(type: elemType)
179       }
180       try readListEnd()
181 
182     default:
183       throw TProtocolError(error: .invalidData, message: "Invalid data")
184     }
185   }
186 }
187