Skip to content

Commit e01cdf5

Browse files
committed
Clarify and make public RESPEncoder
1 parent 26e3ac2 commit e01cdf5

File tree

2 files changed

+34
-25
lines changed

2 files changed

+34
-25
lines changed
Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import Foundation
22
import NIO
33

4-
/// Handles outgoing `RESPValue` on the wire by encoding it to the Redis RESP protocol.
4+
/// Translates `RedisValue` into raw bytes, formatted according to the Redis Serialization Protocol (RESP).
55
///
66
/// See: https://redis.io/topics/protocol
7-
internal final class RESPEncoder: MessageToByteEncoder {
8-
/// See `MessageToByteEncoder.OutboundIn`
9-
typealias OutboundIn = RESPValue
10-
11-
/// See `RESPEncoder.encode(ctx:data:out:)`
12-
func encode(ctx: ChannelHandlerContext, data: RESPValue, out: inout ByteBuffer) throws {
13-
out.write(bytes: _encode(data: data))
14-
}
15-
16-
func _encode(data: RESPValue) -> Data {
17-
switch data {
7+
public final class RESPEncoder {
8+
/// Encodes the `RedisValue` to bytes, following the RESP specification.
9+
///
10+
/// See https://redis.io/topics/protocol
11+
/// - Parameter value: The `RESPValue` to encode.
12+
/// - Returns: The encoded value as a collection of bytes.
13+
public func encode(_ value: RESPValue) -> Data {
14+
switch value {
1815
case .simpleString(let string):
1916
return "+\(string)\r\n".convertedToData()
2017

@@ -31,8 +28,20 @@ internal final class RESPEncoder: MessageToByteEncoder {
3128
return "-\(error.description)\r\n".convertedToData()
3229

3330
case .array(let array):
34-
let encodedArray = array.map { _encode(data: $0) }.joined()
31+
let encodedArray = array.map(encode).joined()
3532
return "*\(array.count)\r\n".convertedToData() + encodedArray
3633
}
3734
}
3835
}
36+
37+
// MARK: MessageToByteEncoder
38+
39+
extension RESPEncoder: MessageToByteEncoder {
40+
/// See `MessageToByteEncoder.OutboundIn`
41+
public typealias OutboundIn = RESPValue
42+
43+
/// See `RESPEncoder.encode(ctx:data:out:)`
44+
public func encode(ctx: ChannelHandlerContext, data: RESPValue, out: inout ByteBuffer) throws {
45+
out.write(bytes: encode(data))
46+
}
47+
}

Tests/NIORedisTests/ChannelHandlers/RESPEncoder+ParsingTests.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,52 +8,52 @@ final class RESPEncoderParsingTests: XCTestCase {
88

99
func testSimpleStrings() {
1010
XCTAssertEqual(
11-
encoder._encode(data: .simpleString("Test1")),
11+
encoder.encode(.simpleString("Test1")),
1212
"+Test1\r\n".convertedToData()
1313
)
1414
XCTAssertEqual(
15-
encoder._encode(data: .simpleString("®in§³¾")),
15+
encoder.encode(.simpleString("®in§³¾")),
1616
"+®in§³¾\r\n".convertedToData()
1717
)
1818
}
1919

2020
func testBulkStrings() {
2121
let t1 = Data(bytes: [0x01, 0x02, 0x0a, 0x1b, 0xaa])
2222
XCTAssertEqual(
23-
encoder._encode(data: .bulkString(t1)),
23+
encoder.encode(.bulkString(t1)),
2424
"$5\r\n".convertedToData() + t1 + "\r\n".convertedToData()
2525
)
2626
let t2 = "®in§³¾".convertedToData()
2727
XCTAssertEqual(
28-
encoder._encode(data: .bulkString(t2)),
28+
encoder.encode(.bulkString(t2)),
2929
"$10\r\n".convertedToData() + t2 + "\r\n".convertedToData()
3030
)
3131
let t3 = "".convertedToData()
3232
XCTAssertEqual(
33-
encoder._encode(data: .bulkString(t3)),
33+
encoder.encode(.bulkString(t3)),
3434
"$0\r\n\r\n".convertedToData()
3535
)
3636
}
3737

3838
func testIntegers() {
3939
XCTAssertEqual(
40-
encoder._encode(data: .integer(Int.min)),
40+
encoder.encode(.integer(Int.min)),
4141
":\(Int.min)\r\n".convertedToData()
4242
)
4343
XCTAssertEqual(
44-
encoder._encode(data: .integer(0)),
44+
encoder.encode(.integer(0)),
4545
":0\r\n".convertedToData()
4646
)
4747
}
4848

4949
func testArrays() {
5050
XCTAssertEqual(
51-
encoder._encode(data: .array([])),
51+
encoder.encode(.array([])),
5252
"*0\r\n".convertedToData()
5353
)
5454
let a1: RESPValue = .array([.integer(3), .simpleString("foo")])
5555
XCTAssertEqual(
56-
encoder._encode(data: a1),
56+
encoder.encode(a1),
5757
"*2\r\n:3\r\n+foo\r\n".convertedToData()
5858
)
5959
let bytes = Data(bytes: [ 0x0a, 0x1a, 0x1b, 0xff ])
@@ -62,19 +62,19 @@ final class RESPEncoderParsingTests: XCTestCase {
6262
.bulkString(bytes)
6363
])])
6464
XCTAssertEqual(
65-
encoder._encode(data: a2),
65+
encoder.encode(a2),
6666
"*1\r\n*2\r\n:3\r\n$4\r\n".convertedToData() + bytes + "\r\n".convertedToData()
6767
)
6868
}
6969

7070
func testError() {
7171
let error = RedisError(identifier: "testError", reason: "Manual error")
72-
let result = encoder._encode(data: .error(error))
72+
let result = encoder.encode(.error(error))
7373
XCTAssertEqual(result, "-\(error.description)\r\n".convertedToData())
7474
}
7575

7676
func testNull() {
77-
XCTAssertEqual(encoder._encode(data: .null), "$-1\r\n".convertedToData())
77+
XCTAssertEqual(encoder.encode(.null), "$-1\r\n".convertedToData())
7878
}
7979
}
8080

0 commit comments

Comments
 (0)