-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnonymousJSONSupport.swift
More file actions
149 lines (114 loc) · 4.66 KB
/
AnonymousJSONSupport.swift
File metadata and controls
149 lines (114 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import Foundation
public typealias AnonymousJSONObject = [String:AnonymousJSONValue]
public typealias AnonymousJSONArray = [AnonymousJSONValue]
public typealias AnonymousJSONProperty = (String, AnonymousJSONValue)
public extension AnonymousJSONObject {
func getJsonData() throws -> Data {
return try JSONEncoder().encode(self)
}
func transcode<T:Decodable>(as _:T.Type) throws -> T {
let jsonData = try getJsonData()
return try JSONDecoder().decode(T.self, from:jsonData)
}
}
public enum AnonymousJSONValue: Codable, Equatable {
public enum Errors : Error {
case decodingError(String)
}
case `nil`
case boolean(Bool)
case integer(Int)
case double(Double)
case string(String)
case array(AnonymousJSONArray)
case object(AnonymousJSONObject)
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() { self = .nil }
else if let value = try? container.decode(Bool.self) { self = .boolean(value) }
else if let value = try? container.decode(Int.self) { self = .integer(value) }
else if let value = try? container.decode(Double.self) { self = .double(value) }
else if let value = try? container.decode(String.self) { self = .string(value) }
else if let value = try? container.decode(AnonymousJSONArray.self) { self = .array(value) }
else if let value = try? container.decode(AnonymousJSONObject.self) { self = .object(value) }
else {
throw Errors.decodingError("could not decode a valid JSONValue")
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .nil : try container.encodeNil()
case .boolean(let value) : try container.encode(value)
case .integer(let value) : try container.encode(value)
case .double (let value) : try container.encode(value)
case .string (let value) : try container.encode(value)
case .array (let value) : try container.encode(value)
case .object (let value) : try container.encode(value)
}
}
}
// Convenience methods
public extension AnonymousJSONValue {
var isNil:Bool {
return self == .nil
}
var asBoolean:Bool {
guard case let .boolean(value) = self else { preconditionFailure("Not a boolean") }
return value
}
var asInteger:Int {
guard case let .integer(value) = self else { preconditionFailure("Not an integer") }
return value
}
var asDouble:Double {
switch self {
case let .double(value) : return value
case let .integer(value) : return Double(value)
default : preconditionFailure("Not a double")
}
}
var asString:String {
guard case let .string(value) = self else { preconditionFailure("Not a string") }
return value
}
var asArray:AnonymousJSONArray {
guard case let .array(value) = self else { preconditionFailure("Not an array") }
return value
}
subscript(index:Int) -> AnonymousJSONValue {
return asArray[index]
}
var asObject:AnonymousJSONObject {
guard case let .object(value) = self else { preconditionFailure("Not an object") }
return value
}
subscript(key:String) -> AnonymousJSONValue {
guard let value = asObject[key] else { preconditionFailure("key not found") }
return value
}
func transcode<T:Decodable>(to _:T.Type) throws -> T {
return try asObject.transcode(as:T.self)
}
}
// Literal Conversions
extension AnonymousJSONValue: ExpressibleByBooleanLiteral {
public init(booleanLiteral value: Bool) { self = .boolean(value) }
}
extension AnonymousJSONValue: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) { self = .integer(value) }
}
extension AnonymousJSONValue: ExpressibleByFloatLiteral {
public init(floatLiteral value: Double) { self = .double(value) }
}
extension AnonymousJSONValue: ExpressibleByStringLiteral {
public init(stringLiteral value: String) { self = .string(value) }
}
extension AnonymousJSONValue: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: AnonymousJSONValue...) { self = .array(elements) }
}
extension AnonymousJSONValue: ExpressibleByDictionaryLiteral {
public init(dictionaryLiteral keyValuePairs: AnonymousJSONProperty...) {
self = .object(Dictionary.init(uniqueKeysWithValues: keyValuePairs))
}
}