Skip to content

Commit 4672c49

Browse files
committed
Make RESPChannelHandler work as a base-class
... so that we subclass it. Intention: workaround NIOAny wrapping overhead.
1 parent 8e12a8a commit 4672c49

File tree

1 file changed

+48
-105
lines changed

1 file changed

+48
-105
lines changed

Sources/NIORedis/RESPChannelHandler.swift

Lines changed: 48 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -14,48 +14,47 @@
1414

1515
import NIO
1616

17-
final class RedisChannelHandler : ChannelInboundHandler,
18-
ChannelOutboundHandler
17+
open class RedisChannelHandler : ChannelInboundHandler,
18+
ChannelOutboundHandler
1919
{
2020

21-
typealias InboundErr = RESPParserError
21+
public typealias InboundErr = RESPParserError
2222

23-
typealias InboundIn = ByteBuffer
24-
typealias InboundOut = RESPValue
23+
public typealias InboundIn = ByteBuffer
24+
public typealias InboundOut = RESPValue
2525

26-
typealias OutboundIn = RESPEncodable
27-
typealias OutboundOut = ByteBuffer
26+
public typealias OutboundIn = RESPEncodable
27+
public typealias OutboundOut = ByteBuffer
2828

29-
let nilStringBuffer = ConstantBuffers.nilStringBuffer
30-
let nilArrayBuffer = ConstantBuffers.nilArrayBuffer
29+
private final let nilStringBuffer = ConstantBuffers.nilStringBuffer
30+
private final let nilArrayBuffer = ConstantBuffers.nilArrayBuffer
3131

32-
private final var parser = RESPParser()
32+
public final var parser = RESPParser()
3333

3434
// MARK: - Channel Open/Close
3535

36-
func channelActive(ctx: ChannelHandlerContext) {
36+
public func channelActive(ctx: ChannelHandlerContext) {
3737
ctx.fireChannelActive()
3838
}
39-
func channelInactive(ctx: ChannelHandlerContext) {
40-
switch state {
41-
case .protocolError, .start: break // all good
42-
default:
43-
ctx.fireErrorCaught(InboundErr.ProtocolError)
44-
}
45-
46-
overflowBuffer = nil
47-
39+
public func channelInactive(ctx: ChannelHandlerContext) {
40+
#if false // this doesn't gain us anything?
41+
switch parser.state {
42+
case .protocolError, .start: break // all good
43+
default:
44+
ctx.fireErrorCaught(InboundErr.ProtocolError)
45+
}
46+
#endif
4847
ctx.fireChannelInactive()
4948
}
50-
49+
5150

5251
// MARK: - Reading
5352

5453
public func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
5554
do {
5655
let buffer = self.unwrapInboundIn(data)
5756
try parser.feed(buffer) { respValue in
58-
ctx.fireChannelRead(self.wrapInboundOut(respValue))
57+
self.channelRead(ctx: ctx, value: respValue)
5958
}
6059
}
6160
catch {
@@ -64,84 +63,28 @@ final class RedisChannelHandler : ChannelInboundHandler,
6463
return
6564
}
6665
}
67-
66+
67+
open func channelRead(ctx: ChannelHandlerContext, value: RESPValue) {
68+
ctx.fireChannelRead(self.wrapInboundOut(value))
69+
}
70+
6871
public func errorCaught(ctx: ChannelHandlerContext, error: Error) {
6972
ctx.fireErrorCaught(InboundErr.TransportError(error))
7073
}
7174

7275

73-
// MARK: - Parsing
76+
// MARK: - Writing
7477

75-
private enum ParserState {
76-
case protocolError
77-
case start
78-
case error
79-
case integer
80-
case bulkStringLen
81-
case bulkStringValue
82-
case simpleString
83-
case arrayCount
84-
case telnet
85-
}
86-
87-
@inline(__always)
88-
private func makeArrayParseContext(_ parent: ArrayParseContext? = nil,
89-
_ count: Int) -> ArrayParseContext
78+
public func write(ctx: ChannelHandlerContext, data: NIOAny,
79+
promise: EventLoopPromise<Void>?)
9080
{
91-
if parent == nil && cachedParseContext != nil {
92-
let ctx = cachedParseContext!
93-
cachedParseContext = nil
94-
ctx.count = count
95-
ctx.values.reserveCapacity(count)
96-
return ctx
97-
}
98-
else {
99-
return ArrayParseContext(parent, count)
100-
}
101-
}
102-
private final var cachedParseContext : ArrayParseContext? = nil
103-
104-
final private class ArrayParseContext {
105-
106-
let parent : ArrayParseContext?
107-
var values = ContiguousArray<RESPValue>()
108-
var count : Int
109-
110-
init(_ parent: ArrayParseContext?, _ count: Int) {
111-
self.parent = parent
112-
self.count = count
113-
}
114-
115-
var isDone : Bool { return count <= values.count }
116-
var isNested : Bool { return parent != nil }
117-
118-
@inline(__always)
119-
func append(value v: InboundOut) -> Bool {
120-
assert(!isNested || !isDone,
121-
"attempt to add to a context which is not TL or done")
122-
values.append(v)
123-
return isDone
124-
}
81+
let data : RESPEncodable = self.unwrapOutboundIn(data)
82+
write(ctx: ctx, value: data.toRESPValue(), promise: promise)
12583
}
12684

127-
private var state = ParserState.start
128-
private var overflowSkipNL = false
129-
private var hadMinus = false
130-
131-
private var countValue = 0
132-
private var overflowBuffer : ByteBuffer?
133-
134-
private var arrayContext : ArrayParseContext?
135-
136-
137-
// MARK: - Writing
138-
139-
func write(ctx: ChannelHandlerContext, data: NIOAny,
140-
promise: EventLoopPromise<Void>?)
85+
public final func write(ctx: ChannelHandlerContext, value: RESPValue,
86+
promise: EventLoopPromise<Void>?)
14187
{
142-
let data : RESPEncodable = self.unwrapOutboundIn(data)
143-
let value = data.toRESPValue()
144-
14588
var out : ByteBuffer
14689
switch value {
14790
case .simpleString(var s): // +
@@ -190,8 +133,8 @@ final class RedisChannelHandler : ChannelInboundHandler,
190133
}
191134

192135
@inline(__always)
193-
func encode<S: ContiguousCollection>(simpleString bytes: S,
194-
out: inout ByteBuffer)
136+
final func encode<S: ContiguousCollection>(simpleString bytes: S,
137+
out: inout ByteBuffer)
195138
where S.Element == UInt8
196139
{
197140
out.write(integer : UInt8(43)) // +
@@ -200,15 +143,15 @@ final class RedisChannelHandler : ChannelInboundHandler,
200143
}
201144

202145
@inline(__always)
203-
func encode(simpleString bytes: ByteBuffer, out: inout ByteBuffer) {
146+
final func encode(simpleString bytes: ByteBuffer, out: inout ByteBuffer) {
204147
var s = bytes
205148
out.write(integer : UInt8(43)) // +
206149
out.write(buffer : &s)
207150
out.write(bytes : eol)
208151
}
209152

210153
@inline(__always)
211-
func encode(bulkString bytes: ByteBuffer?, out: inout ByteBuffer) {
154+
final func encode(bulkString bytes: ByteBuffer?, out: inout ByteBuffer) {
212155
if var s = bytes {
213156
out.write(integer : UInt8(36)) // $
214157
out.write(integerAsString : s.readableBytes)
@@ -222,8 +165,8 @@ final class RedisChannelHandler : ChannelInboundHandler,
222165
}
223166

224167
@inline(__always)
225-
func encode<S: ContiguousCollection>(bulkString bytes: S?,
226-
out: inout ByteBuffer)
168+
final func encode<S: ContiguousCollection>(bulkString bytes: S?,
169+
out: inout ByteBuffer)
227170
where S.Element == UInt8
228171
{
229172
if let s = bytes {
@@ -239,32 +182,32 @@ final class RedisChannelHandler : ChannelInboundHandler,
239182
}
240183

241184
@inline(__always)
242-
func encode(integer i: Int, out: inout ByteBuffer) {
185+
final func encode(integer i: Int, out: inout ByteBuffer) {
243186
out.write(integer : UInt8(58)) // :
244187
out.write(integerAsString : i)
245188
out.write(bytes : eol)
246189
}
247190

248191
@inline(__always)
249-
func encode(error: RESPError, out: inout ByteBuffer) {
192+
final func encode(error: RESPError, out: inout ByteBuffer) {
250193
out.write(integer : UInt8(45)) // -
251194
out.write(string : error.code)
252195
out.write(integer : UInt8(32)) // ' '
253196
out.write(string : error.message)
254197
out.write(bytes : eol)
255198
}
256199

257-
func encode(ctx : ChannelHandlerContext,
258-
data : RESPValue,
259-
out : inout ByteBuffer)
200+
final func encode(ctx : ChannelHandlerContext,
201+
data : RESPValue,
202+
out : inout ByteBuffer)
260203
{
261204
encode(ctx: ctx, data: data, level: 0, out: &out)
262205
}
263206

264-
func encode(ctx : ChannelHandlerContext,
265-
data : RESPValue,
266-
level : Int,
267-
out : inout ByteBuffer)
207+
final func encode(ctx : ChannelHandlerContext,
208+
data : RESPValue,
209+
level : Int,
210+
out : inout ByteBuffer)
268211
{
269212
// FIXME: Creating a String for an Int is expensive, there is something
270213
// something better in the HTTP-API async imp.

0 commit comments

Comments
 (0)