Skip to content

Commit 84f4881

Browse files
committed
working encoder
1 parent 9144e0d commit 84f4881

File tree

7 files changed

+342
-99
lines changed

7 files changed

+342
-99
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import Bits
2+
3+
/// A frontend or backend PostgreSQL message.
4+
protocol PostgreSQLMessage: Codable {
5+
/// The first byte of a message identifies the message type
6+
static var identifier: Byte? { get }
7+
}
8+
9+
/// First message sent from the frontend during startup.
10+
struct PostgreSQLStartupMessage: PostgreSQLMessage {
11+
/// The protocol version number. The most significant 16 bits are the major
12+
/// version number (3 for the protocol described here). The least significant
13+
/// 16 bits are the minor version number (0 for the protocol described here).
14+
var protocolVersion: Int32
15+
16+
/// The protocol version number is followed by one or more pairs of parameter
17+
/// name and value strings. A zero byte is required as a terminator after
18+
/// the last name/value pair. Parameters can appear in any order. user is required,
19+
/// others are optional. Each parameter is specified as:
20+
var parameters: PostgreSQLParameters
21+
22+
/// Creates a new `PostgreSQLStartupMessage`.
23+
init(protocolVersion: Int32, parameters: PostgreSQLParameters) {
24+
self.protocolVersion = protocolVersion
25+
self.parameters = parameters
26+
}
27+
28+
/// Creates a `PostgreSQLStartupMessage` with "3.0" as the protocol version.
29+
static func versionThree(parameters: PostgreSQLParameters) -> PostgreSQLStartupMessage {
30+
return .init(protocolVersion: 196608, parameters: parameters)
31+
}
32+
33+
/// See `PostgreSQLMessage.identifier`
34+
static let identifier: Byte? = nil
35+
}
36+
37+
/// Represents [String: String] parameters encoded
38+
/// as a list of strings separated by null terminators
39+
/// and finished by a single null terminator.
40+
struct PostgreSQLParameters: Codable, ExpressibleByDictionaryLiteral {
41+
/// The internal parameter storage.
42+
var storage: [String: String]
43+
44+
/// See Encodable.encode
45+
public func encode(to encoder: Encoder) throws {
46+
var container = encoder.singleValueContainer()
47+
for (key, val) in storage {
48+
try container.encode(key)
49+
try container.encode(val)
50+
}
51+
try container.encode("")
52+
}
53+
54+
/// See ExpressibleByDictionaryLiteral.init
55+
init(dictionaryLiteral elements: (String, String)...) {
56+
var storage = [String: String]()
57+
for (key, val) in elements {
58+
storage[key] = val
59+
}
60+
self.storage = storage
61+
}
62+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import Foundation
2+
3+
/// Non-encoder wrapper for `_PostgreSQLMessageEncoder`.
4+
final class PostgreSQLMessageEncoder {
5+
/// Create a new `PostgreSQLMessageEncoder`
6+
init() {}
7+
8+
/// Encodes a `PostgreSQLMessage` to `Data`.
9+
func encode<Message>(_ message: Message) throws -> Data where Message: PostgreSQLMessage {
10+
let encoder = _PostgreSQLMessageEncoder()
11+
try message.encode(to: encoder)
12+
encoder.updateSize()
13+
if let identifier = Message.identifier {
14+
return [identifier] + encoder.data
15+
} else {
16+
return encoder.data
17+
}
18+
}
19+
}
20+
21+
// MARK: Encoder / Single
22+
23+
internal final class _PostgreSQLMessageEncoder: Encoder, SingleValueEncodingContainer {
24+
var codingPath: [CodingKey]
25+
var userInfo: [CodingUserInfoKey: Any]
26+
var data: Data
27+
28+
init() {
29+
self.codingPath = []
30+
self.userInfo = [:]
31+
self.data = Data([0, 0, 0, 0])
32+
}
33+
34+
func updateSize() {
35+
let size = numericCast(data.count - 4) as Int32
36+
data.withUnsafeMutableBytes { (pointer: UnsafeMutablePointer<Int32>) in
37+
pointer.pointee = size.bigEndian
38+
}
39+
}
40+
41+
func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey {
42+
let container = PostgreSQLMessageKeyedEncodingContainer<Key>(encoder: self)
43+
return KeyedEncodingContainer(container)
44+
}
45+
46+
func unkeyedContainer() -> UnkeyedEncodingContainer {
47+
return PostgreSQLMessageUnkeyedEncodingContainer(encoder: self)
48+
}
49+
50+
func singleValueContainer() -> SingleValueEncodingContainer {
51+
return self
52+
}
53+
54+
func encode(_ value: String) throws {
55+
// kafka style string
56+
// let stringData = Data(value.utf8)
57+
//
58+
// guard stringData.count < numericCast(Int16.max) else {
59+
// throw UnsupportedStringLength()
60+
// }
61+
//
62+
// try encode(numericCast(stringData.count) as Int16)
63+
// self.data.append(stringData)
64+
// c style string
65+
let stringData = Data(value.utf8)
66+
self.data.append(stringData + [0])
67+
}
68+
69+
func encode(_ value: Int8) throws {
70+
self.data.append(numericCast(value))
71+
}
72+
73+
func encode(_ value: Int16) throws {
74+
var value = value.bigEndian
75+
withUnsafeBytes(of: &value) { buffer in
76+
let buffer = buffer.baseAddress!.assumingMemoryBound(to: UInt8.self)
77+
self.data.append(buffer, count: 2)
78+
}
79+
}
80+
81+
func encode(_ value: Int32) throws {
82+
var value = value.bigEndian
83+
withUnsafeBytes(of: &value) { buffer in
84+
let buffer = buffer.baseAddress!.assumingMemoryBound(to: UInt8.self)
85+
self.data.append(buffer, count: 4)
86+
}
87+
}
88+
89+
func encode(_ value: Int64) throws {
90+
var value = value.bigEndian
91+
withUnsafeBytes(of: &value) { buffer in
92+
let buffer = buffer.baseAddress!.assumingMemoryBound(to: UInt8.self)
93+
self.data.append(buffer, count: 8)
94+
}
95+
}
96+
97+
func encode<T>(_ value: T) throws where T : Encodable {
98+
try value.encode(to: self)
99+
}
100+
101+
// Unsupported
102+
103+
func encode(_ value: Int) throws { fatalError("Unsupported type: \(type(of: value))") }
104+
func encode(_ value: UInt) throws { fatalError("Unsupported type: \(type(of: value))") }
105+
func encode(_ value: UInt8) throws { fatalError("Unsupported type: \(type(of: value))") }
106+
func encode(_ value: UInt16) throws { fatalError("Unsupported type: \(type(of: value))") }
107+
func encode(_ value: UInt32) throws { fatalError("Unsupported type: \(type(of: value))") }
108+
func encode(_ value: UInt64) throws { fatalError("Unsupported type: \(type(of: value))") }
109+
func encode(_ value: Float) throws { fatalError("Unsupported type: \(type(of: value))") }
110+
func encode(_ value: Double) throws { fatalError("Unsupported type: \(type(of: value))") }
111+
func encode(_ value: Bool) throws { fatalError("Unsupported type: \(type(of: value))") }
112+
func encodeNil() throws { fatalError("Unsupported type: nil") }
113+
}
114+
115+
// MARK: Keyed
116+
117+
internal struct PostgreSQLMessageKeyedEncodingContainer<K>: KeyedEncodingContainerProtocol where K: CodingKey {
118+
var count = 0
119+
typealias Key = K
120+
121+
var codingPath: [CodingKey]
122+
let encoder: _PostgreSQLMessageEncoder
123+
124+
init(encoder: _PostgreSQLMessageEncoder) {
125+
self.encoder = encoder
126+
self.codingPath = []
127+
}
128+
129+
mutating func encode(_ value: Int, forKey key: K) throws { try encoder.encode(value) }
130+
mutating func encode(_ value: Int8, forKey key: K) throws { try encoder.encode(value) }
131+
mutating func encode(_ value: Int16, forKey key: K) throws { try encoder.encode(value) }
132+
mutating func encode(_ value: Int32, forKey key: K) throws { try encoder.encode(value) }
133+
mutating func encode(_ value: Int64, forKey key: K) throws { try encoder.encode(value) }
134+
mutating func encode(_ value: UInt, forKey key: K) throws { try encoder.encode(value) }
135+
mutating func encode(_ value: UInt8, forKey key: K) throws { try encoder.encode(value) }
136+
mutating func encode(_ value: UInt16, forKey key: K) throws { try encoder.encode(value) }
137+
mutating func encode(_ value: UInt32, forKey key: K) throws { try encoder.encode(value) }
138+
mutating func encode(_ value: UInt64, forKey key: K) throws { try encoder.encode(value) }
139+
mutating func encode(_ value: Float, forKey key: K) throws { try encoder.encode(value) }
140+
mutating func encode(_ value: Double, forKey key: K) throws { try encoder.encode(value) }
141+
mutating func encode(_ value: String, forKey key: K) throws { try encoder.encode(value) }
142+
mutating func encode<T>(_ value: T, forKey key: K) throws where T : Encodable { try value.encode(to: encoder)}
143+
mutating func encode(_ value: Bool, forKey key: K) throws { try encoder.encode(value) }
144+
mutating func encodeNil(forKey key: K) throws { try encoder.encodeNil() }
145+
mutating func superEncoder() -> Encoder { return encoder }
146+
mutating func superEncoder(forKey key: K) -> Encoder { return encoder }
147+
148+
mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: K) -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
149+
let container = PostgreSQLMessageKeyedEncodingContainer<NestedKey>(encoder: encoder)
150+
return KeyedEncodingContainer(container)
151+
}
152+
153+
mutating func nestedUnkeyedContainer(forKey key: K) -> UnkeyedEncodingContainer {
154+
return PostgreSQLMessageUnkeyedEncodingContainer(encoder: encoder)
155+
}
156+
}
157+
158+
// MARK: Unkeyed
159+
160+
internal struct PostgreSQLMessageUnkeyedEncodingContainer: UnkeyedEncodingContainer {
161+
var codingPath: [CodingKey]
162+
var count: Int
163+
let encoder: _PostgreSQLMessageEncoder
164+
165+
init(encoder: _PostgreSQLMessageEncoder) {
166+
self.encoder = encoder
167+
self.codingPath = []
168+
self.count = 0
169+
}
170+
171+
mutating func encode(_ value: Int) throws { try encoder.encode(value) }
172+
mutating func encode(_ value: Int8) throws { try encoder.encode(value) }
173+
mutating func encode(_ value: Int16) throws { try encoder.encode(value) }
174+
mutating func encode(_ value: Int32) throws { try encoder.encode(value) }
175+
mutating func encode(_ value: Int64) throws { try encoder.encode(value) }
176+
mutating func encode(_ value: UInt) throws { try encoder.encode(value) }
177+
mutating func encode(_ value: UInt8) throws { try encoder.encode(value) }
178+
mutating func encode(_ value: UInt16) throws { try encoder.encode(value) }
179+
mutating func encode(_ value: UInt32) throws { try encoder.encode(value) }
180+
mutating func encode(_ value: UInt64) throws { try encoder.encode(value) }
181+
mutating func encode(_ value: Float) throws { try encoder.encode(value) }
182+
mutating func encode(_ value: Double) throws { try encoder.encode(value) }
183+
mutating func encode(_ value: String) throws { try encoder.encode(value) }
184+
mutating func encode<T>(_ value: T) throws where T : Encodable { try value.encode(to: encoder)}
185+
mutating func encode(_ value: Bool) throws { try encoder.encode(value) }
186+
mutating func encodeNil() throws { try encoder.encodeNil() }
187+
mutating func superEncoder() -> Encoder { return encoder }
188+
mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { return self }
189+
190+
mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey {
191+
let container = PostgreSQLMessageKeyedEncodingContainer<NestedKey>(encoder: encoder)
192+
return KeyedEncodingContainer(container)
193+
}
194+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//import Async
2+
//import Bits
3+
//import Foundation
4+
//
5+
//struct PostgresSerializerState {
6+
// var remaining: Data
7+
//}
8+
//
9+
//final class PostgresSerializer: ByteSerializer {
10+
// var state: ByteSerializerState<PostgresSerializer>
11+
//
12+
// typealias Input = PostgresMessage
13+
// typealias Output = ByteBuffer
14+
//
15+
// let buffer: MutableByteBuffer
16+
//
17+
// init() {
18+
// buffer = MutableByteBuffer(start: .allocate(capacity: 4096), count: 4096)
19+
// state = .init()
20+
// }
21+
//
22+
// func serialize(
23+
// _ message: PostgresMessage,
24+
// state: PostgresSerializerState?
25+
// ) throws -> ByteSerializerResult<PostgresSerializer> {
26+
// if let state = state {
27+
// return serialize(data: state.remaining)
28+
// }
29+
//
30+
// switch message {
31+
// case .startupMessage(let protocolVersion, let parameters):
32+
// var data = Data([0, 0, 0, 0])
33+
// for word in protocolVersion.words {
34+
// data.append(Byte(word))
35+
// }
36+
// for (key, val) in parameters {
37+
// data.append(contentsOf: key.data(using: .ascii)!)
38+
// data.append(contentsOf: [0])
39+
// data.append(contentsOf: val.data(using: .ascii)!)
40+
// data.append(contentsOf: [0])
41+
// }
42+
// data.append(contentsOf: [0])
43+
// return serialize(data: data)
44+
// }
45+
// }
46+
//
47+
// func serialize(data: Data) -> ByteSerializerResult<PostgresSerializer> {
48+
// let count = data.copyBytes(to: buffer)
49+
// let view = ByteBuffer(start: buffer.baseAddress, count: count)
50+
// if data.count > count {
51+
// return .incomplete(view, state: .init(remaining: data[count..<data.count]))
52+
// } else {
53+
// return .complete(view)
54+
// }
55+
// }
56+
//
57+
// deinit {
58+
// buffer.baseAddress?.deallocate(capacity: buffer.count)
59+
// }
60+
//}
61+

Sources/postgresql/PostgresMessage.swift

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)