diff --git a/Sources/SwiftyRedis/FromRedisValue.swift b/Sources/SwiftyRedis/FromRedisValue.swift index a4493d05..24536586 100644 --- a/Sources/SwiftyRedis/FromRedisValue.swift +++ b/Sources/SwiftyRedis/FromRedisValue.swift @@ -39,7 +39,12 @@ extension FromRedisValue { extension String: FromRedisValue { public init(_ value: RedisValue) throws { switch value { - case let .SimpleString(string), let .BulkString(string): + case let .SimpleString(string): + self = string + case let .BulkString(data): + guard let string = String(data: data, encoding: .utf8) else { + throw RedisError.InvalidUTF8 + } self = string case let .Int(int): self = "\(int)" @@ -52,7 +57,13 @@ extension String: FromRedisValue { extension Float64: FromRedisValue { public init(_ value: RedisValue) throws { switch value { - case let .BulkString(string), let .SimpleString(string): + case let .BulkString(data): + if let string = String(data: data, encoding: .utf8) { + self = try Self.init(RedisValue.SimpleString(string)) + } else { + throw RedisError.make_invalid_type_error(detail: "Could not convert non UTF-8 String to Float64") + } + case let .SimpleString(string): if let float = Float64(string) { self = float } else { @@ -69,7 +80,13 @@ extension Float64: FromRedisValue { extension Float32: FromRedisValue { public init(_ value: RedisValue) throws { switch value { - case let .BulkString(string), let .SimpleString(string): + case let .BulkString(data): + if let string = String(data: data, encoding: .utf8) { + self = try Self.init(RedisValue.SimpleString(string)) + } else { + throw RedisError.make_invalid_type_error(detail: "Could not convert non UTF-8 String to Float32") + } + case let .SimpleString(string): if let float = Float(string) { self = float } else { @@ -98,7 +115,13 @@ extension Float32: FromRedisValue { extension Int64: FromRedisValue { public init(_ value: RedisValue) throws { switch value { - case let .BulkString(string), let .SimpleString(string): + case let .BulkString(data): + if let string = String(data: data, encoding: .utf8) { + self = try Self.init(RedisValue.SimpleString(string)) + } else { + throw RedisError.make_invalid_type_error(detail: "Could not convert non UTF-8 String to Int64") + } + case let .SimpleString(string): if let int = Int64(string) { self = int } else { @@ -187,7 +210,13 @@ extension Bool: FromRedisValue { switch value { case let .Int(int): self = int != 0 - case let .BulkString(string), let .SimpleString(string): + case let .BulkString(data): + if let string = String(data: data, encoding: .utf8) { + self = try Self.init(RedisValue.SimpleString(string)) + } else { + throw RedisError.make_invalid_type_error(detail: "Could not convert non UTF-8 String to Bool") + } + case let .SimpleString(string): if string == "1" { self = true } else if string == "0" { diff --git a/Sources/SwiftyRedis/JSONValue.swift b/Sources/SwiftyRedis/JSONValue.swift index f31fedfc..3ce5e687 100644 --- a/Sources/SwiftyRedis/JSONValue.swift +++ b/Sources/SwiftyRedis/JSONValue.swift @@ -39,9 +39,9 @@ extension JSONValue: FromRedisValue where T: Decodable { */ public init(_ value: RedisValue) throws { switch value { - case let .BulkString(string): + case let .BulkString(data): let decoder = JSONDecoder() - self.value = try decoder.decode(T.self, from: string.data(using: .utf8)!) + self.value = try decoder.decode(T.self, from: data) default: throw RedisError.make_invalid_type_error(detail: "Response type (\(value)), is not JSON compatible") } diff --git a/Sources/SwiftyRedis/ResponseValueParser.swift b/Sources/SwiftyRedis/ResponseValueParser.swift index 3a05a600..e879f404 100644 --- a/Sources/SwiftyRedis/ResponseValueParser.swift +++ b/Sources/SwiftyRedis/ResponseValueParser.swift @@ -86,12 +86,11 @@ class ResponseValueParser { if length < 0 { return .Nil } else { - if let value = try String(data: await stream.next(n: Int(length)), encoding: .utf8) { - try await disgard_crlf_token() - return .BulkString(value) - } else { - throw RedisError.InvalidUTF8 - } + let value = Data(try await stream.next(n: Int(length))) + + try await disgard_crlf_token() + + return .BulkString(value) } } else { unreachable() diff --git a/Sources/SwiftyRedis/Stream.swift b/Sources/SwiftyRedis/Stream.swift index baa99904..71b55bb3 100644 --- a/Sources/SwiftyRedis/Stream.swift +++ b/Sources/SwiftyRedis/Stream.swift @@ -17,15 +17,12 @@ public struct RedisStreamElement: FromRedisValue where T: FromRedisValue { public init(_ value: RedisValue) throws { if case var .Array(array) = value { array = array.reversed() - switch array.popLast() { - case let .BulkString(id), let .SimpleString(id): + if let id = try? String(array.popLast()) { self.id = id if let data = array.popLast() { self.data = try T(data) return } - default: - break } } throw RedisError.make_invalid_type_error(detail: "Response type not convertible to RedisStreamElement.") @@ -39,15 +36,12 @@ public struct RedisStream: FromRedisValue where T: FromRedisValue { public init(_ value: RedisValue) throws { if case var .Array(array) = value { array = array.reversed() - switch array.popLast() { - case let .BulkString(name), let .SimpleString(name): + if let name = try? String(array.popLast()) { self.name = name if case let .Array(elements) = array.popLast() { self.elements = try elements.map { value in try RedisStreamElement(value) } return } - default: - break } } throw RedisError.make_invalid_type_error(detail: "Response type not convertible to RedisStream.") diff --git a/Sources/SwiftyRedis/Value.swift b/Sources/SwiftyRedis/Value.swift index ba05adb8..e748cc7b 100644 --- a/Sources/SwiftyRedis/Value.swift +++ b/Sources/SwiftyRedis/Value.swift @@ -18,9 +18,13 @@ public indirect enum RedisValue: Equatable { /// Represents integer responses from the server. The returned integer is guaranteed to be within the range of a signed 64-bit integer. case Int(Int64) /// Represents a single binary-safe string up to 512 MB in length. - case BulkString(String) + case BulkString(Data) /// Represents the absence of a value. case Nil /// Represents an array of RedisValues, commonly used for commands that return collections of elements. case Array([RedisValue]) + + static func BulkString(_ string: String) -> Self { + return .BulkString(string.data(using: .utf8)!) + } } diff --git a/Tests/SwiftyRedisTests/ConnectionTests.swift b/Tests/SwiftyRedisTests/ConnectionTests.swift index 0bf112c8..8a457a70 100644 --- a/Tests/SwiftyRedisTests/ConnectionTests.swift +++ b/Tests/SwiftyRedisTests/ConnectionTests.swift @@ -42,7 +42,7 @@ final class ConnectionTests: XCTestCase { try await connection2.xadd("stream1", nil, .AUTO_ID, .init("field1", "Hello, World!")) } - let value: RedisValue = try await connection.xread(nil, 0, .init("stream1", id: "$")) + let value: XreadResponse = try await connection.xread(nil, 0, .init("stream1", id: "$")) print(value) }