diff --git a/Sources/Extensions/SingleValueDecodingContainer+.swift b/Sources/Extensions/SingleValueDecodingContainer+.swift index 8566685..717bf6b 100644 --- a/Sources/Extensions/SingleValueDecodingContainer+.swift +++ b/Sources/Extensions/SingleValueDecodingContainer+.swift @@ -8,8 +8,15 @@ import Foundation +enum MessagePackableDecodingError: Error { + case notMessagePackDecoder +} + extension SingleValueDecodingContainer { func decode(as type: T.Type) throws -> T where T.T == T { - return try (self as! MessagePackDecoder.SingleValueContainer).decode(as: type) + guard let messagePackContainer = self as? MessagePackDecoder.SingleValueContainer else { + throw MessagePackableDecodingError.notMessagePackDecoder + } + return try messagePackContainer.decode(as: type) } } diff --git a/Sources/Extensions/SingleValueEncodingContainer+.swift b/Sources/Extensions/SingleValueEncodingContainer+.swift index 68d3574..b2120d5 100644 --- a/Sources/Extensions/SingleValueEncodingContainer+.swift +++ b/Sources/Extensions/SingleValueEncodingContainer+.swift @@ -8,8 +8,15 @@ import Foundation +enum MessagePackableEncodingError: Error { + case notMessagePackEncoder +} + extension SingleValueEncodingContainer { func encode(_ value: T) throws { - try (self as! MessagePackEncoder.SingleValueContainer).encode(from: value) + guard let messagePackContainer = self as? MessagePackEncoder.SingleValueContainer else { + throw MessagePackableEncodingError.notMessagePackEncoder + } + try messagePackContainer.encode(from: value) } } diff --git a/Sources/MessagePackTimestamp.swift b/Sources/MessagePackTimestamp.swift index 94f2e7b..559d2a0 100644 --- a/Sources/MessagePackTimestamp.swift +++ b/Sources/MessagePackTimestamp.swift @@ -47,12 +47,33 @@ extension MessagePackTimestamp { } extension MessagePackTimestamp: Codable { + enum CodingKeys: String, CodingKey { + case seconds + case nanoseconds + } + public func encode(to encoder: Encoder) throws { - try encoder.singleValueContainer().encode(self) + do { + // First, try encoding as a `MessagePackable`, which requires a `MessagePackEncoder`. + try encoder.singleValueContainer().encode(self) + } catch let error as MessagePackableEncodingError where error == .notMessagePackEncoder { + // If the caller is not using a `MessagePackEncoder`, then fall back to standard, non-MessagePack behavior. + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(seconds, forKey: .seconds) + try container.encode(nanoseconds, forKey: .nanoseconds) + } } public init(from decoder: Decoder) throws { - self = try decoder.singleValueContainer().decode(as: MessagePackTimestamp.self) + do { + // First, try decoding as a `MessagePackable`, which requires a `MessagePackDecoder`. + self = try decoder.singleValueContainer().decode(as: MessagePackTimestamp.self) + } catch let error as MessagePackableDecodingError where error == .notMessagePackDecoder { + // If the caller is not using a `MessagePackDecoder`, then fall back to standard, non-MessagePack behavior. + let container = try decoder.container(keyedBy: CodingKeys.self) + self.seconds = try container.decode(Int64.self, forKey: .seconds) + self.nanoseconds = try container.decode(Int64.self, forKey: .nanoseconds) + } } } diff --git a/Tests/MessagePackerTests/TimestampPackedTests.swift b/Tests/MessagePackerTests/TimestampPackedTests.swift index cd60305..bcc3d3a 100644 --- a/Tests/MessagePackerTests/TimestampPackedTests.swift +++ b/Tests/MessagePackerTests/TimestampPackedTests.swift @@ -37,4 +37,19 @@ class TimestampPackedTests: XCTestCase { let output = Data([199, 12, 255, 25, 69, 229, 222, 0, 0, 0, 14, 211, 132, 20, 74]) XCTAssertEqual(try encoder.encode(input), output) } + + func testSupportsNonMessagePackEncoder() { + let input = MessagePackTimestamp(seconds: 1542592042, nanoseconds: 209741115) + + let jsonEncoder = JSONEncoder() + jsonEncoder.outputFormatting = [.prettyPrinted, .sortedKeys] + + let output = """ + { + "nanoseconds" : 209741115, + "seconds" : 1542592042 + } + """.data(using: .utf8)! + XCTAssertEqual(try jsonEncoder.encode(input), output) + } } diff --git a/Tests/MessagePackerTests/TimestampUnpackedTests.swift b/Tests/MessagePackerTests/TimestampUnpackedTests.swift index bac61c6..0122d84 100644 --- a/Tests/MessagePackerTests/TimestampUnpackedTests.swift +++ b/Tests/MessagePackerTests/TimestampUnpackedTests.swift @@ -69,4 +69,18 @@ class TimestampUnpackedTests: XCTestCase { XCTAssertEqual(try decoder.decode(Vehicle.self, from: input), output) } + + func testSupportsNonMessagePackDecoder() { + let input = """ + { + "nanoseconds" : 209741115, + "seconds" : 1542592042 + } + """.data(using: .utf8)! + + let jsonDecoder = JSONDecoder() + + let output = MessagePackTimestamp(seconds: 1542592042, nanoseconds: 209741115) + XCTAssertEqual(try jsonDecoder.decode(MessagePackTimestamp.self, from: input), output) + } }