Merge pull request #30 from Mordil/29-replace-data

Replace `Foundation.Data` with `[UInt8]` type everywhere
This commit is contained in:
Nathan Harris
2019-04-01 09:25:06 -07:00
committed by GitHub
17 changed files with 82 additions and 100 deletions
@@ -1,4 +1,4 @@
import Foundation
import struct Foundation.UUID
import Logging
import NIO
@@ -1,4 +1,3 @@
import Foundation
import NIO
extension RedisClient {
@@ -1,4 +1,3 @@
import Foundation
import NIO
// MARK: General
@@ -1,4 +1,3 @@
import Foundation
import NIO
extension ClientBootstrap {
+4 -5
View File
@@ -1,4 +1,3 @@
import Foundation
import NIO
extension UInt8 {
@@ -143,7 +142,7 @@ extension RESPDecoder {
guard size > 0 else {
// Move the tip of the message position
position += 2
return .parsed(.bulkString(Data()))
return .parsed(.bulkString([]))
}
guard let bytes = buffer.copyBytes(at: position, length: expectedRemainingMessageSize) else {
@@ -154,9 +153,9 @@ extension RESPDecoder {
// of the bulk string content
position += expectedRemainingMessageSize
return .parsed(
.bulkString(Data(bytes[ ..<size ]))
)
return .parsed(.bulkString(
.init(bytes[..<size])
))
}
/// See [https://redis.io/topics/protocol#resp-arrays](https://redis.io/topics/protocol#resp-arrays)
+10 -10
View File
@@ -1,26 +1,26 @@
import Foundation
/// A representation of a Redis Serialization Protocol (RESP) primitive value.
///
/// See: [https://redis.io/topics/protocol](https://redis.io/topics/protocol)
public enum RESPValue {
case null
case simpleString(String)
case bulkString(Data)
case bulkString([UInt8])
case error(RedisError)
case integer(Int)
case array([RESPValue])
/// Initializes a `bulkString` by converting the provided string input.
public init(bulk: String) {
self = .bulkString(Data(bulk.utf8))
let bytes = [UInt8](bulk.utf8)
self = .bulkString(bytes)
}
}
extension RESPValue: ExpressibleByStringLiteral {
/// Initializes a bulk string from a String literal
public init(stringLiteral value: String) {
self = .bulkString(Data(value.utf8))
let bytes = [UInt8](value.utf8)
self = .bulkString(bytes)
}
}
@@ -51,15 +51,15 @@ extension RESPValue {
public var string: String? {
switch self {
case .simpleString(let string): return string
case .bulkString(let data): return String(bytes: data, encoding: .utf8)
case .bulkString(let bytes): return String(bytes: bytes, encoding: .utf8)
default: return nil
}
}
/// Extracted binary data from `bulkString` representations.
public var data: Data? {
guard case .bulkString(let data) = self else { return nil }
return data
/// Extracted byte representation from `bulkString` values.
public var bytes: [UInt8]? {
guard case let .bulkString(bytes) = self else { return nil }
return bytes
}
/// Extracted container of data elements from `array` representations.
@@ -1,5 +1,3 @@
import Foundation
/// Capable of converting to / from `RESPValue`.
public protocol RESPValueConvertible {
init?(_ value: RESPValue)
@@ -39,7 +37,7 @@ extension String: RESPValueConvertible {
/// See `RESPValueConvertible.convertedToRESPValue()`
public func convertedToRESPValue() -> RESPValue {
return .bulkString(Data(self.utf8))
return .bulkString(.init(self.utf8))
}
}
@@ -56,7 +54,7 @@ extension FixedWidthInteger {
/// See `RESPValueConvertible.convertedToRESPValue()`
public func convertedToRESPValue() -> RESPValue {
return .bulkString(Data(self.description.utf8))
return .bulkString(.init(self.description.utf8))
}
}
@@ -80,7 +78,7 @@ extension Double: RESPValueConvertible {
/// See `RESPValueConvertible.convertedToRESPValue()`
public func convertedToRESPValue() -> RESPValue {
return .bulkString(Data(self.description.utf8))
return .bulkString(.init(self.description.utf8))
}
}
@@ -93,19 +91,7 @@ extension Float: RESPValueConvertible {
/// See `RESPValueConvertible.convertedToRESPValue()`
public func convertedToRESPValue() -> RESPValue {
return .bulkString(Data(self.description.utf8))
}
}
extension Data: RESPValueConvertible {
public init?(_ value: RESPValue) {
guard let data = value.data else { return nil }
self = data
}
/// See `RESPValueConvertible.convertedToRESPValue()`
public func convertedToRESPValue() -> RESPValue {
return .bulkString(self)
return .bulkString(.init(self.description.utf8))
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
import struct Foundation.UUID
import Logging
import Foundation
import NIO
import NIOConcurrencyHelpers
+2 -1
View File
@@ -1,4 +1,5 @@
import Foundation
import protocol Foundation.LocalizedError
import class Foundation.Thread
/// Errors thrown while working with Redis.
public struct RedisError: CustomDebugStringConvertible, CustomStringConvertible, LocalizedError {
+1 -1
View File
@@ -1,4 +1,4 @@
import Foundation
import struct Foundation.UUID
import Logging
/// An object that provides a mechanism to "pipeline" multiple Redis commands in sequence,
@@ -39,8 +39,7 @@ final class RESPDecoderByteToMessageDecoderTests: XCTestCase {
func testDecoding_complete_movesReaderIndex() throws {
for message in RESPDecoderByteToMessageDecoderTests.completeMessages {
let messageByteSize = message.convertedToData()
XCTAssertEqual(try decodeTest(message).1, messageByteSize.count)
XCTAssertEqual(try decodeTest(message).1, message.bytes.count)
}
}
@@ -43,35 +43,35 @@ final class RESPDecoderParsingTests: XCTestCase {
XCTAssertEqual(parseTest_singleValue(input: "$0\r\n\r\n")?.string, "")
XCTAssertEqual(parseTest_singleValue(input: "$1\r\n!\r\n")?.string, "!")
XCTAssertEqual(
parseTest_singleValue(input: "$1\r\n".convertedToData() + Data([0xa3]) + "\r\n".convertedToData())?.data,
Data([0xa3])
parseTest_singleValue(input: "$1\r\n".bytes + [0xa3] + "\r\n".bytes)?.bytes,
[0xa3]
)
XCTAssertEqual(
parseTest_singleValue(input: "$1\r\n".convertedToData() + Data([0xba]) + "\r\n".convertedToData())?.data,
Data([0xba])
parseTest_singleValue(input: "$1\r\n".bytes + [0xba] + "\r\n".bytes)?.bytes,
[0xba]
)
}
func testParsing_with_bulkString_multiple() throws {
let t1 = try parseTest_twoValues(withChunks: ["$3\r", "\naaa\r\n$", "4\r\nnio!\r\n"])
XCTAssertTrue(t1.0?.data?.count == 3)
XCTAssertTrue(t1.1?.data?.count == 4)
XCTAssertTrue(t1.0?.bytes?.count == 3)
XCTAssertTrue(t1.1?.bytes?.count == 4)
let chunks: [Data] = [
"$3\r".convertedToData(),
"\n".convertedToData() + Data([0xAA, 0xA3, 0xFF]) + "\r\n$".convertedToData(),
"4\r\n".convertedToData() + Data([0xbb, 0x3a, 0xba, 0xFF]) + "\r\n".convertedToData()
let chunks: [[UInt8]] = [
"$3\r".bytes,
"\n".bytes + [0xAA, 0xA3, 0xFF] + "\r\n$".bytes,
"4\r\n".bytes + [0xbb, 0x3a, 0xba, 0xFF] + "\r\n".bytes
]
let t2 = try parseTest_twoValues(withChunks: chunks)
XCTAssertTrue(t2.0?.data?.count == 3)
XCTAssertTrue(t2.1?.data?.count == 4)
XCTAssertTrue(t2.0?.bytes?.count == 3)
XCTAssertTrue(t2.1?.bytes?.count == 4)
}
func testParsing_with_arrays() {
XCTAssertEqual(parseTest_singleValue(input: "*1\r\n+!\r\n")?.array?.count, 1)
XCTAssertEqual(parseTest_singleValue(input: "*2\r\n*1\r\n:1\r\n:3\r\n")?.array?.count, 2)
XCTAssertEqual(parseTest_singleValue(input: "*0\r\n".convertedToData())?.array?.count, 0)
XCTAssertNil(parseTest_singleValue(input: "*-1\r\n".convertedToData())?.array)
XCTAssertEqual(parseTest_singleValue(input: "*0\r\n".bytes)?.array?.count, 0)
XCTAssertNil(parseTest_singleValue(input: "*-1\r\n".bytes)?.array)
}
func testParsing_with_arrays_multiple() throws {
@@ -80,10 +80,10 @@ final class RESPDecoderParsingTests: XCTestCase {
XCTAssertTrue(t1.1?.array?.count == 0)
let t2 = try parseTest_twoValues(withChunks: [
"*-1\r".convertedToData(),
"\n".convertedToData(),
"*1\r".convertedToData(),
"\n\r\n".convertedToData()
"*-1\r".bytes,
"\n".bytes,
"*1\r".bytes,
"\n\r\n".bytes
])
XCTAssertTrue(t2.0?.array == nil)
XCTAssertTrue(t2.1?.array?.count == 1)
@@ -120,11 +120,11 @@ final class RESPDecoderParsingTests: XCTestCase {
/// See parse_Test_singleValue(input:) String
private func parseTest_singleValue(input: String) -> RESPValue? {
return parseTest_singleValue(input: input.convertedToData())
return parseTest_singleValue(input: input.bytes)
}
/// Takes a collection of bytes representing a complete message and returns the data
private func parseTest_singleValue(input: Data) -> RESPValue? {
private func parseTest_singleValue(input: [UInt8]) -> RESPValue? {
return runParse(offset: 0) { decoder, position, buffer in
buffer.writeBytes(input)
guard case .parsed(let result)? = try? decoder.parse(at: &position, from: &buffer) else { return nil }
@@ -134,13 +134,13 @@ final class RESPDecoderParsingTests: XCTestCase {
/// See parseTest_recursive(withCunks:) [Data]
private func parseTest_twoValues(withChunks messageChunks: [String]) throws -> (RESPValue?, RESPValue?) {
return try parseTest_twoValues(withChunks: messageChunks.map({ $0.convertedToData() }))
return try parseTest_twoValues(withChunks: messageChunks.map({ $0.bytes }))
}
/// Takes a collection of incomplete byte messages that produce exactly two decoded RESPValue.
/// The expected pattern of messages should be [incomplete, remaining, incomplete, remaining]
/// - Returns: The first and second decoded data
private func parseTest_twoValues(withChunks messageChunks: [Data]) throws -> (RESPValue?, RESPValue?) {
private func parseTest_twoValues(withChunks messageChunks: [[UInt8]]) throws -> (RESPValue?, RESPValue?) {
let decoder = RESPDecoder()
var buffer = allocator.buffer(capacity: messageChunks.joined().count)
@@ -263,12 +263,12 @@ extension RESPDecoderParsingTests {
func testParsing_bulkString_withNoSize_returnsEmpty() throws {
let result = parseTestBulkString("$0\r\n\r\n")
XCTAssertEqual(result?.data?.count, 0)
XCTAssertEqual(result?.bytes?.count, 0)
}
func testParsing_bulkString_withSize_returnsContent() throws {
let result = parseTestBulkString("$1\r\n1\r\n")
XCTAssertEqual(result?.data?.count, 1)
XCTAssertEqual(result?.bytes?.count, 1)
}
func testParsing_bulkString_withNull_returnsNil() throws {
@@ -278,18 +278,18 @@ extension RESPDecoderParsingTests {
func testParsing_bulkString_handlesRawBytes() throws {
let bytes: [UInt8] = [0x00, 0x01, 0x02, 0x03, 0x0A, 0xFF]
let data = "$\(bytes.count)\r\n".convertedToData() + Data(bytes) + "\r\n".convertedToData()
let allBytes = "$\(bytes.count)\r\n".bytes + bytes + "\r\n".bytes
let result = parseTestBulkString(data)
let result = parseTestBulkString(allBytes)
XCTAssertEqual(result?.data?.count, bytes.count)
XCTAssertEqual(result?.bytes?.count, bytes.count)
}
private func parseTestBulkString(_ input: String) -> RESPValue? {
return parseTestBulkString(input.convertedToData())
return parseTestBulkString(input.bytes)
}
private func parseTestBulkString(_ input: Data) -> RESPValue? {
private func parseTestBulkString(_ input: [UInt8]) -> RESPValue? {
return runParse { decoder, position, buffer in
buffer.writeBytes(input)
guard case .parsed(let result) = try decoder._parseBulkString(at: &position, from: &buffer) else {
@@ -318,7 +318,7 @@ extension RESPDecoderParsingTests {
XCTAssertEqual(result?.count, 3)
XCTAssertEqual(result?[0].int, 3)
XCTAssertEqual(result?[1].string, "OK")
XCTAssertEqual(result?[2].data?.count, 1)
XCTAssertEqual(result?[2].bytes?.count, 1)
}
func testParsing_array_handlesNullElements() {
@@ -340,10 +340,10 @@ extension RESPDecoderParsingTests {
}
private func parseTestArray(_ input: String) -> RESPValue? {
return parseTestArray(input.convertedToData())
return parseTestArray(input.bytes)
}
private func parseTestArray(_ input: Data) -> RESPValue? {
private func parseTestArray(_ input: [UInt8]) -> RESPValue? {
return runParse { decoder, position, buffer in
buffer.writeBytes(input)
guard case .parsed(let result) = try decoder._parseArray(at: &position, from: &buffer) else { return nil }
@@ -58,18 +58,18 @@ final class RESPDecoderTests: XCTestCase {
XCTAssertEqual(try runTest("$3\r\n\r\n")?.string, "")
let str = "κόσμε"
let strBytes = str.convertedToData()
let strBytes = str.bytes
let strInput = "$\(strBytes.count)\r\n\(str)\r\n"
XCTAssertEqual(try runTest(strInput)?.string, str)
XCTAssertEqual(try runTest(strInput)?.data, strBytes)
XCTAssertEqual(try runTest(strInput)?.bytes, strBytes)
let multiBulkString: (RESPValue?, RESPValue?) = try runTest("$-1\r\n$3\r\n\r\n")
XCTAssertEqual(multiBulkString.0?.isNull, true)
XCTAssertEqual(multiBulkString.1?.string, "")
let rawBytes = Data([0x00, 0x01, 0x02, 0x03, 0x0A, 0xff])
let rawByteInput = "$\(rawBytes.count)\r\n".convertedToData() + rawBytes + "\r\n".convertedToData()
XCTAssertEqual(try runTest(rawByteInput)?.data, rawBytes)
let rawBytes: [UInt8] = [0x00, 0x01, 0x02, 0x03, 0x0A, 0xff]
let rawByteInput = "$\(rawBytes.count)\r\n".bytes + rawBytes + "\r\n".bytes
XCTAssertEqual(try runTest(rawByteInput)?.bytes, rawBytes)
}
func test_array() throws {
@@ -82,11 +82,11 @@ final class RESPDecoderTests: XCTestCase {
XCTAssertEqual(try runArrayTest("*0\r\n")?.count, 0)
XCTAssertTrue(arraysAreEqual(
try runArrayTest("*1\r\n$3\r\nfoo\r\n"),
expected: [.bulkString("foo".convertedToData())]
expected: [.bulkString("foo".bytes)]
))
XCTAssertTrue(arraysAreEqual(
try runArrayTest("*3\r\n+foo\r\n$3\r\nbar\r\n:3\r\n"),
expected: [.simpleString("foo"), .bulkString("bar".convertedToData()), .integer(3)]
expected: [.simpleString("foo"), .bulkString("bar".bytes), .integer(3)]
))
XCTAssertTrue(arraysAreEqual(
try runArrayTest("*1\r\n*2\r\n+OK\r\n:1\r\n"),
@@ -95,18 +95,18 @@ final class RESPDecoderTests: XCTestCase {
}
private func runTest(_ input: String) throws -> RESPValue? {
return try runTest(input.convertedToData())
return try runTest(input.bytes)
}
private func runTest(_ input: Data) throws -> RESPValue? {
private func runTest(_ input: [UInt8]) throws -> RESPValue? {
return try runTest(input).0
}
private func runTest(_ input: String) throws -> (RESPValue?, RESPValue?) {
return try runTest(input.convertedToData())
return try runTest(input.bytes)
}
private func runTest(_ input: Data) throws -> (RESPValue?, RESPValue?) {
private func runTest(_ input: [UInt8]) throws -> (RESPValue?, RESPValue?) {
let embeddedChannel = EmbeddedChannel()
defer { _ = try? embeddedChannel.finish() }
let handler = ByteToMessageHandler(decoder)
@@ -191,11 +191,11 @@ extension RESPDecoderTests {
XCTAssertEqual(results[2]?.error?.description.contains(AllData.expectedError), true)
XCTAssertEqual(results[3]?.string, AllData.expectedBulkString)
XCTAssertEqual(results[3]?.data, AllData.expectedBulkString.convertedToData())
XCTAssertEqual(results[3]?.bytes, AllData.expectedBulkString.bytes)
XCTAssertEqual(results[4]?.isNull, true)
XCTAssertEqual(results[5]?.data?.count, 0)
XCTAssertEqual(results[5]?.bytes?.count, 0)
XCTAssertEqual(results[5]?.string, "")
XCTAssertEqual(results[6]?.array?.count, 3)
@@ -203,7 +203,7 @@ extension RESPDecoderTests {
results[6]?.array,
expected: [
.simpleString(AllData.expectedString),
.bulkString(AllData.expectedBulkString.convertedToData()),
.bulkString(AllData.expectedBulkString.bytes),
.integer(AllData.expectedInteger)
]
))
@@ -12,8 +12,8 @@ final class RESPEncoderParsingTests: XCTestCase {
}
func testBulkStrings() {
let bytes = Data([0x01, 0x02, 0x0a, 0x1b, 0xaa])
XCTAssertTrue(testPass(input: .bulkString(bytes), expected: Data("$5\r\n".utf8) + bytes + Data("\r\n".utf8)))
let bytes: [UInt8] = [0x01, 0x02, 0x0a, 0x1b, 0xaa]
XCTAssertTrue(testPass(input: .bulkString(bytes), expected: "$5\r\n".bytes + bytes + "\r\n".bytes))
XCTAssertTrue(testPass(input: .init(bulk: "®in§³¾"), expected: "$10\r\n®in§³¾\r\n"))
XCTAssertTrue(testPass(input: .init(bulk: ""), expected: "$0\r\n\r\n"))
}
@@ -29,10 +29,10 @@ final class RESPEncoderParsingTests: XCTestCase {
input: .array([ .integer(3), .simpleString("foo") ]),
expected: "*2\r\n:3\r\n+foo\r\n"
))
let bytes = Data([ 0x0a, 0x1a, 0x1b, 0xff ])
let bytes: [UInt8] = [ 0x0a, 0x1a, 0x1b, 0xff ]
XCTAssertTrue(testPass(
input: .array([ .array([ .integer(10), .bulkString(bytes) ]) ]),
expected: Data("*1\r\n*2\r\n:10\r\n$4\r\n".utf8) + bytes + Data("\r\n".utf8)
expected: "*1\r\n*2\r\n:10\r\n$4\r\n".bytes + bytes + "\r\n".bytes
))
}
@@ -45,7 +45,7 @@ final class RESPEncoderParsingTests: XCTestCase {
XCTAssertTrue(testPass(input: .null, expected: "$-1\r\n"))
}
private func testPass(input: RESPValue, expected: Data) -> Bool {
private func testPass(input: RESPValue, expected: [UInt8]) -> Bool {
let allocator = ByteBufferAllocator()
var comparisonBuffer = allocator.buffer(capacity: expected.count)
@@ -33,15 +33,15 @@ final class RESPEncoderTests: XCTestCase {
}
func testBulkStrings() throws {
let bs1 = RESPValue.bulkString(Data([0x01, 0x02, 0x0a, 0x1b, 0xaa]))
let bs1 = RESPValue.bulkString([0x01, 0x02, 0x0a, 0x1b, 0xaa])
try runEncodePass(with: bs1) { XCTAssertEqual($0.readableBytes, 11) }
XCTAssertNoThrow(try channel.writeOutbound(bs1))
let bs2 = RESPValue.bulkString("®in§³¾".convertedToData())
let bs2 = RESPValue.bulkString("®in§³¾".bytes)
try runEncodePass(with: bs2) { XCTAssertEqual($0.readableBytes, 17) }
XCTAssertNoThrow(try channel.writeOutbound(bs2))
let bs3 = RESPValue.bulkString("".convertedToData())
let bs3 = RESPValue.bulkString("".bytes)
try runEncodePass(with: bs3) { XCTAssertEqual($0.readableBytes, 6) }
XCTAssertNoThrow(try channel.writeOutbound(bs3))
}
@@ -65,7 +65,7 @@ final class RESPEncoderTests: XCTestCase {
try runEncodePass(with: a2) { XCTAssertEqual($0.readableBytes, 14) }
XCTAssertNoThrow(try channel.writeOutbound(a2))
let bytes = Data([ 0x0a, 0x1a, 0x1b, 0xff ])
let bytes: [UInt8] = [ 0x0a, 0x1a, 0x1b, 0xff ]
let a3: RESPValue = .array([.array([
.integer(3),
.bulkString(bytes)
@@ -78,7 +78,7 @@ final class RESPEncoderTests: XCTestCase {
let error = RedisError(identifier: "testError", reason: "Manual error")
let data = RESPValue.error(error)
try runEncodePass(with: data) {
XCTAssertEqual($0.readableBytes, "-\(error.description)\r\n".convertedToData().count)
XCTAssertEqual($0.readableBytes, "-\(error.description)\r\n".bytes.count)
}
XCTAssertNoThrow(try channel.writeOutbound(data))
}
+1 -1
View File
@@ -55,7 +55,7 @@ final class RedisPipelineTests: XCTestCase {
XCTAssertEqual(results[0].string, "PONG")
XCTAssertEqual(results[1].string, "OK")
XCTAssertEqual(results[2].data, "3".convertedToData())
XCTAssertEqual(results[2].bytes, "3".bytes)
}
func test_executeIsOrdered() throws {
+1 -1
View File
@@ -2,5 +2,5 @@ import Foundation
extension String {
/// Converts this String to a byte representation.
func convertedToData() -> Data { return Data(utf8) }
var bytes: [UInt8] { return .init(self.utf8) }
}