Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Codable support #66

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions MessagePack.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions Sources/MessagePack/Decoder/MessagePackDecoder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// MessagePackDecoder.swift
// MessagePack
//
// Created by Andrew Eng on 20/2/18.
//

import Foundation

open class MessagePackDecoder {
public init() {}

open func decode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T {
let messagePack = try decodeToMessagePack(from: data)
return try decodeMessagePack(type, from: messagePack)
}

open func decodeToMessagePack(from data: Data) throws -> MessagePackValue {
return try unpackFirst(data)
}

open func decodeMessagePack<T: Decodable>(_ type: T.Type, from messagePack: MessagePackValue) throws -> T {
let decoder = _MessagePackDecoder(value: messagePack)
return try T(from: decoder)
}
}

// MARK: - _MessagePackDecoder

final class _MessagePackDecoder {

fileprivate let value: MessagePackValue

init(value: MessagePackValue) {
self.value = value
}
}

// MARK: Decoder
extension _MessagePackDecoder: Decoder {

// TODO: Implement Me!
var codingPath: [CodingKey] { return [] }

// TODO: Implement Me!
var userInfo: [CodingUserInfoKey : Any] { return [:] }

func container<Key: CodingKey>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> {

guard case let .map(map) = value else {
let msg = "Cannot decode map from \(value)"
let context = DecodingError.Context(codingPath: [], debugDescription: msg)
throw DecodingError.typeMismatch([MessagePackValue: MessagePackValue].self, context)
}

let container = MessagePackKeyedDecodingContainer<Key>(map: map)
return KeyedDecodingContainer(container)
}

func unkeyedContainer() throws -> UnkeyedDecodingContainer {

guard case let .array(array) = value else {
let msg = "Cannot decode array from \(value)"
let context = DecodingError.Context(codingPath: [], debugDescription: msg)
throw DecodingError.typeMismatch([MessagePackValue].self, context)
}

return MessagePackUnkeyedDecodingContainer(array: array)
}

func singleValueContainer() throws -> SingleValueDecodingContainer {
return MessagePackSingleValueDecodingContainer(value: value)
}
}
215 changes: 215 additions & 0 deletions Sources/MessagePack/Decoder/MessagePackKeyedDecodingContainer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
//
// MessagePackKeyedDecodingContainer.swift
// MessagePack
//
// Created by Andrew Eng on 20/2/18.
//

import Foundation

final class MessagePackKeyedDecodingContainer<K: CodingKey> {

let map: [MessagePackValue: MessagePackValue]

init(map: [MessagePackValue: MessagePackValue]) {
self.map = map
}
}

// MARK: - Helper
extension MessagePackKeyedDecodingContainer {

fileprivate func _decode<T: MessagePackRepresentable>(_ type: T.Type, forKey key: Key) throws -> T {
let value = try valueForKey(key)
return try _decode(value, type: type)
}

fileprivate func _decode<T: MessagePackRepresentable>(_ value: MessagePackValue, type: T.Type) throws -> T {

guard let decoded = T(messagePack: value) else {
let msg = "Cannot decode \(type) from \(value)"
let context = DecodingError.Context(codingPath: [], debugDescription: msg)
throw DecodingError.typeMismatch(type, context)
}
return decoded
}

fileprivate func _decodeIfPresent<T: MessagePackRepresentable>(_ type: T.Type, forKey key: Key) throws -> T? {

guard let value = map[.string(key.stringValue)] else {
return nil
}

if case .`nil` = value {
return nil
} else {
return try _decode(value, type: type)
}
}

fileprivate func _decodeDecodable<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
let value = try valueForKey(key)
return try _decodeDecodable(value, type: type)
}

fileprivate func _decodeDecodable<T: Decodable>(_ value: MessagePackValue, type: T.Type) throws -> T {
let decoder = _MessagePackDecoder(value: value)
return try T(from: decoder)
}

fileprivate func _decodeDecodableIfPresent<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T? {

guard let value = map[.string(key.stringValue)] else {
return nil
}

if case .`nil` = value {
return nil
} else {
return try _decodeDecodable(value, type: type)
}
}

fileprivate func valueForKey(_ key: Key) throws -> MessagePackValue {

guard let value = map[.string(key.stringValue)] else {
let msg = "Key not found : \(key)"
let context = DecodingError.Context(codingPath: [], debugDescription: msg)
throw DecodingError.keyNotFound(key, context)
}
return value
}
}

// MARK: - KeyedDecodingContainerProtocol
extension MessagePackKeyedDecodingContainer: KeyedDecodingContainerProtocol {
typealias Key = K

// TODO: Implement Me!
var codingPath: [CodingKey] { return [] }

var allKeys: [Key] {
return map.keys.flatMap() {
guard let stringValue = $0.stringValue else { return nil }
return Key(stringValue: stringValue)
}
}

func contains(_ key: Key) -> Bool {
return map[.string(key.stringValue)] != nil
}

func decodeNil(forKey key: Key) throws -> Bool {
let value = try valueForKey(key)
return (value == .`nil`)
}

func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { return try _decode(type, forKey: key) }
func decode(_ type: Int.Type, forKey key: Key) throws -> Int { return try _decode(type, forKey: key) }
func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { return try _decode(type, forKey: key) }
func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { return try _decode(type, forKey: key) }
func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { return try _decode(type, forKey: key) }
func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { return try _decode(type, forKey: key) }
func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { return try _decode(type, forKey: key) }
func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { return try _decode(type, forKey: key) }
func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { return try _decode(type, forKey: key) }
func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { return try _decode(type, forKey: key) }
func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { return try _decode(type, forKey: key) }
func decode(_ type: Float.Type, forKey key: Key) throws -> Float { return try _decode(type, forKey: key) }
func decode(_ type: Double.Type, forKey key: Key) throws -> Double { return try _decode(type, forKey: key) }
func decode(_ type: String.Type, forKey key: Key) throws -> String { return try _decode(type, forKey: key) }

func decode<T: Decodable>(_ type: T.Type, forKey key: Key) throws -> T {

if T.self == Data.self || T.self == NSData.self {
return try _decode(Data.self, forKey: key) as! T
} else {
return try _decodeDecodable(type, forKey: key)
}
}

func decodeIfPresent(_ type: Bool.Type, forKey key: Key) throws -> Bool? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: Int.Type, forKey key: Key) throws -> Int? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: Int8.Type, forKey key: Key) throws -> Int8? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: Int16.Type, forKey key: Key) throws -> Int16? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: Int32.Type, forKey key: Key) throws -> Int32? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: Int64.Type, forKey key: Key) throws -> Int64? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: UInt.Type, forKey key: Key) throws -> UInt? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: UInt8.Type, forKey key: Key) throws -> UInt8? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: UInt16.Type, forKey key: Key) throws -> UInt16? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: UInt32.Type, forKey key: Key) throws -> UInt32? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: UInt64.Type, forKey key: Key) throws -> UInt64? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: Float.Type, forKey key: Key) throws -> Float? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: Double.Type, forKey key: Key) throws -> Double? {
return try _decodeIfPresent(type, forKey: key)
}
func decodeIfPresent(_ type: String.Type, forKey key: Key) throws -> String? {
return try _decodeIfPresent(type, forKey: key)
}

func decodeIfPresent<T : Decodable>(_ type: T.Type, forKey key: K) throws -> T? {

if T.self == Data.self || T.self == NSData.self {
return try _decodeIfPresent(Data.self, forKey: key) as! T?
} else {
return try _decodeDecodableIfPresent(type, forKey: key)
}
}

func nestedContainer<NestedKey: CodingKey>(keyedBy type: NestedKey.Type, forKey key: Key)
throws -> KeyedDecodingContainer<NestedKey>
{
let value = try valueForKey(key)

guard case let .map(map) = value else {
let msg = "Cannot decode map from \(value)"
let context = DecodingError.Context(codingPath: [], debugDescription: msg)
throw DecodingError.typeMismatch([MessagePackValue: MessagePackValue].self, context)
}

let container = MessagePackKeyedDecodingContainer<NestedKey>(map: map)
return KeyedDecodingContainer(container)
}

func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
let value = try valueForKey(key)

guard case let .array(array) = value else {
let msg = "Cannot decode array from \(value)"
let context = DecodingError.Context(codingPath: [], debugDescription: msg)
throw DecodingError.typeMismatch([MessagePackValue].self, context)
}

return MessagePackUnkeyedDecodingContainer(array: array)
}

// TODO: Implement Me!
func superDecoder() throws -> Decoder { abort() }

// TODO: Implement Me!
func superDecoder(forKey key: Key) throws -> Decoder { abort() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// MessagePackSingleValueDecodingContainer.swift
// MessagePack
//
// Created by Andrew Eng on 20/2/18.
//

import Foundation

final class MessagePackSingleValueDecodingContainer {

let value: MessagePackValue

init(value: MessagePackValue) {
self.value = value
}
}

// MARK: - Helper
extension MessagePackSingleValueDecodingContainer {

fileprivate func _decode<T: MessagePackRepresentable>(_ type: T.Type) throws -> T {

guard let value = T(messagePack: self.value) else {
let msg = "Cannot decode \(type) from \(self.value)"
let context = DecodingError.Context(codingPath: [], debugDescription: msg)
throw DecodingError.typeMismatch(type, context)
}

return value
}

fileprivate func _decodeDecodable<T: Decodable>(_ type: T.Type) throws -> T {

let decoder = _MessagePackDecoder(value: value)
return try T(from: decoder)
}
}

// MARK: - SingleValueDecodingContainer
extension MessagePackSingleValueDecodingContainer: SingleValueDecodingContainer {

// TODO: Implement Me!
var codingPath: [CodingKey] { return [] }

func decodeNil() -> Bool { return value == .`nil` }
func decode(_ type: Bool.Type) throws -> Bool { return try _decode(type) }
func decode(_ type: Int.Type) throws -> Int { return try _decode(type) }
func decode(_ type: Int8.Type) throws -> Int8 { return try _decode(type) }
func decode(_ type: Int16.Type) throws -> Int16 { return try _decode(type) }
func decode(_ type: Int32.Type) throws -> Int32 { return try _decode(type) }
func decode(_ type: Int64.Type) throws -> Int64 { return try _decode(type) }
func decode(_ type: UInt.Type) throws -> UInt { return try _decode(type) }
func decode(_ type: UInt8.Type) throws -> UInt8 { return try _decode(type) }
func decode(_ type: UInt16.Type) throws -> UInt16 { return try _decode(type) }
func decode(_ type: UInt32.Type) throws -> UInt32 { return try _decode(type) }
func decode(_ type: UInt64.Type) throws -> UInt64 { return try _decode(type) }
func decode(_ type: Float.Type) throws -> Float { return try _decode(type) }
func decode(_ type: Double.Type) throws -> Double { return try _decode(type) }
func decode(_ type: String.Type) throws -> String { return try _decode(type) }

func decode<T: Decodable>(_ type: T.Type) throws -> T {

if T.self == Data.self || T.self == NSData.self {
return try _decode(Data.self) as! T
} else {
return try _decodeDecodable(type)
}
}
}
Loading