@@ -0,0 +1,1619 @@
1+//
2+// JSONError.swift
3+// PMJSON
4+//
5+// Created by Kevin Ballard on 11/9/15.
6+// Copyright © 2016 Postmates.
7+//
8+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
9+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
10+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
11+// option. This file may not be copied, modified, or distributed
12+// except according to those terms.
13+//
14+
15+// MARK: JSONError
16+
17+/// Errors thrown by the JSON `get*` or `to*` accessor families.
18+public enum JSONError: Error, CustomStringConvertible {
19+ /// Thrown when a given path is missing or has the wrong type.
20+ /// - Parameter path: The path of the key that caused the error.
21+ /// - Parameter expected: The type that was expected at this path.
22+ /// - Parameter actual: The type of the value found at the path, or `nil` if there was no value.
23+ case missingOrInvalidType(path: String?, expected: ExpectedType, actual: JSONType?)
24+ /// Thrown when an integral value is coerced to a smaller type (e.g. `Int64` to `Int`) and the
25+ /// value doesn't fit in the smaller type.
26+ /// - Parameter path: The path of the value that cuased the error.
27+ /// - Parameter value: The actual value at that path.
28+ /// - Parameter expected: The type that the value doesn't fit in, e.g. `Int.self`.
29+ case outOfRangeInt64(path: String?, value: Int64, expected: Any.Type)
30+ /// Thrown when a floating-point value is coerced to a smaller type (e.g. `Double` to `Int`)
31+ /// and the value doesn't fit in the smaller type.
32+ /// - Parameter path: The path of the value that cuased the error.
33+ /// - Parameter value: The actual value at that path.
34+ /// - Parameter expected: The type that the value doesn't fit in, e.g. `Int.self`.
35+ case outOfRangeDouble(path: String?, value: Double, expected: Any.Type)
36+
37+ public var description: String {
38+ switch self {
39+ case let .missingOrInvalidType(path, expected, actual): return "\(path.map({"\($0): "}) ?? "")expected \(expected), found \(actual?.description ?? "missing value")"
40+ case let .outOfRangeInt64(path, value, expected): return "\(path.map({"\($0): "}) ?? "")value \(value) cannot be coerced to type \(expected)"
41+ case let .outOfRangeDouble(path, value, expected): return "\(path.map({"\($0): "}) ?? "")value \(value) cannot be coerced to type \(expected)"
42+ }
43+ }
44+
45+ fileprivate func withPrefix(_ prefix: String) -> JSONError {
46+ func prefixPath(_ path: String?, with prefix: String) -> String {
47+ guard let path = path, !path.isEmpty else { return prefix }
48+ if path.unicodeScalars.first == "[" {
49+ return prefix + path
50+ } else {
51+ return "\(prefix).\(path)"
52+ }
53+ }
54+ switch self {
55+ case let .missingOrInvalidType(path, expected, actual):
56+ return .missingOrInvalidType(path: prefixPath(path, with: prefix), expected: expected, actual: actual)
57+ case let .outOfRangeInt64(path, value, expected):
58+ return .outOfRangeInt64(path: prefixPath(path, with: prefix), value: value, expected: expected)
59+ case let .outOfRangeDouble(path, value, expected):
60+ return .outOfRangeDouble(path: prefixPath(path, with: prefix), value: value, expected: expected)
61+ }
62+ }
63+
64+ public enum ExpectedType: CustomStringConvertible {
65+ case required(JSONType)
66+ case optional(JSONType)
67+
68+ public var description: String {
69+ switch self {
70+ case .required(let type): return type.description
71+ case .optional(let type): return "\(type) or null"
72+ }
73+ }
74+ }
75+
76+ public enum JSONType: String, CustomStringConvertible {
77+ case null = "null"
78+ case bool = "bool"
79+ case string = "string"
80+ case number = "number"
81+ case object = "object"
82+ case array = "array"
83+
84+ internal static func forValue(_ value: JSON) -> JSONType {
85+ switch value {
86+ case .null: return .null
87+ case .bool: return .bool
88+ case .string: return .string
89+ case .int64, .double: return .number
90+ case .object: return .object
91+ case .array: return .array
92+ }
93+ }
94+
95+ public var description: String {
96+ return rawValue
97+ }
98+ }
99+}
100+
101+// MARK: - Basic accessors
102+public extension JSON {
103+ /// Returns the bool value if the receiver is a bool.
104+ /// - Returns: A `Bool` value.
105+ /// - Throws: `JSONError` if the receiver is the wrong type.
106+ func getBool() throws -> Bool {
107+ guard let b = self.bool else { throw JSONError.missingOrInvalidType(path: nil, expected: .required(.bool), actual: .forValue(self)) }
108+ return b
109+ }
110+
111+ /// Returns the bool value if the receiver is a bool.
112+ /// - Returns: A `Bool` value, or `nil` if the receiver is `null`.
113+ /// - Throws: `JSONError` if the receiver is the wrong type.
114+ func getBoolOrNil() throws -> Bool? {
115+ if let b = self.bool { return b }
116+ else if isNull { return nil }
117+ else { throw JSONError.missingOrInvalidType(path: nil, expected: .optional(.bool), actual: .forValue(self)) }
118+ }
119+
120+ /// Returns the string value if the receiver is a string.
121+ /// - Returns: A `String` value.
122+ /// - Throws: `JSONError` if the receiver is the wrong type.
123+ func getString() throws -> String {
124+ guard let str = self.string else { throw JSONError.missingOrInvalidType(path: nil, expected: .required(.string), actual: .forValue(self)) }
125+ return str
126+ }
127+
128+ /// Returns the string value if the receiver is a string.
129+ /// - Returns: A `String` value, or `nil` if the receiver is `null`.
130+ /// - Throws: `JSONError` if the receiver is the wrong type.
131+ func getStringOrNil() throws -> String? {
132+ if let str = self.string { return str }
133+ else if isNull { return nil }
134+ else { throw JSONError.missingOrInvalidType(path: nil, expected: .optional(.string), actual: .forValue(self)) }
135+ }
136+
137+ /// Returns the 64-bit integral value if the receiver is a number.
138+ /// - Returns: An `Int64` value.
139+ /// - Throws: `JSONError` if the receiver is the wrong type.
140+ func getInt64() throws -> Int64 {
141+ guard let val = self.int64 else { throw JSONError.missingOrInvalidType(path: nil, expected: .required(.number), actual: .forValue(self)) }
142+ return val
143+ }
144+
145+ /// Returns the 64-bit integral value value if the receiver is a number.
146+ /// - Returns: An `Int64` value, or `nil` if the receiver is `null`.
147+ /// - Throws: `JSONError` if the receiver is the wrong type.
148+ func getInt64OrNil() throws -> Int64? {
149+ if let val = self.int64 { return val }
150+ else if isNull { return nil }
151+ else { throw JSONError.missingOrInvalidType(path: nil, expected: .optional(.number), actual: .forValue(self)) }
152+ }
153+
154+ /// Returns the integral value if the receiver is a number.
155+ /// - Returns: An `Int` value.
156+ /// - Throws: `JSONError` if the receiver is the wrong type, or if the 64-bit integral value
157+ /// is too large to fit in an `Int`.
158+ func getInt() throws -> Int {
159+ guard let val = self.int64 else { throw JSONError.missingOrInvalidType(path: nil, expected: .required(.number), actual: .forValue(self)) }
160+ let truncated = Int(truncatingBitPattern: val)
161+ guard Int64(truncated) == val else { throw JSONError.outOfRangeInt64(path: nil, value: val, expected: Int.self) }
162+ return truncated
163+ }
164+
165+ /// Returns the integral value if the receiver is a number.
166+ /// - Returns: An `Int` value, or `nil` if the receiver is `null`.
167+ /// - Throws: `JSONError` if the receiver is the wrong type, or if the 64-bit integral value
168+ /// is too large to fit in an `Int`.
169+ func getIntOrNil() throws -> Int? {
170+ if let val = self.int64 {
171+ let truncated = Int(truncatingBitPattern: val)
172+ guard Int64(truncated) == val else { throw JSONError.outOfRangeInt64(path: nil, value: val, expected: Int.self) }
173+ return truncated
174+ } else if isNull { return nil }
175+ else { throw JSONError.missingOrInvalidType(path: nil, expected: .optional(.number), actual: .forValue(self)) }
176+ }
177+
178+ /// Returns the double value if the receiver is a number.
179+ /// - Returns: A `Double` value.
180+ /// - Throws: `JSONError` if the receiver is the wrong type.
181+ func getDouble() throws -> Double {
182+ guard let val = self.double else { throw JSONError.missingOrInvalidType(path: nil, expected: .required(.number), actual: .forValue(self)) }
183+ return val
184+ }
185+
186+ /// Returns the double value if the receiver is a number.
187+ /// - Returns: A `Double` value, or `nil` if the receiver is `null`.
188+ /// - Throws: `JSONError` if the receiver is the wrong type.
189+ func getDoubleOrNil() throws -> Double? {
190+ if let val = self.double { return val }
191+ else if isNull { return nil }
192+ else { throw JSONError.missingOrInvalidType(path: nil, expected: .optional(.number), actual: .forValue(self)) }
193+ }
194+
195+ /// Returns the object value if the receiver is an object.
196+ /// - Returns: An object value.
197+ /// - Throws: `JSONError` if the receiver is the wrong type.
198+ func getObject() throws -> JSONObject {
199+ guard let dict = self.object else { throw JSONError.missingOrInvalidType(path: nil, expected: .required(.object), actual: .forValue(self)) }
200+ return dict
201+ }
202+
203+ /// Returns the object value if the receiver is an object.
204+ /// - Returns: An object value, or `nil` if the receiver is `null`.
205+ /// - Throws: `JSONError` if the receiver is the wrong type.
206+ func getObjectOrNil() throws -> JSONObject? {
207+ if let dict = self.object { return dict }
208+ else if isNull { return nil }
209+ else { throw JSONError.missingOrInvalidType(path: nil, expected: .optional(.object), actual: .forValue(self)) }
210+ }
211+
212+ /// Returns the array value if the receiver is an array.
213+ /// - Returns: An array value.
214+ /// - Throws: `JSONError` if the receiver is the wrong type.
215+ func getArray() throws -> JSONArray {
216+ guard let ary = self.array else { throw JSONError.missingOrInvalidType(path: nil, expected: .required(.array), actual: .forValue(self)) }
217+ return ary
218+ }
219+
220+ /// Returns the array value if the receiver is an array.
221+ /// - Returns: An array value, or `nil` if the receiver is `null`.
222+ /// - Throws: `JSONError` if the receiver is the wrong type.
223+ func getArrayOrNil() throws -> JSONArray? {
224+ if let ary = self.array { return ary }
225+ else if isNull { return nil }
226+ else { throw JSONError.missingOrInvalidType(path: nil, expected: .optional(.array), actual: .forValue(self)) }
227+ }
228+}
229+
230+public extension JSON {
231+ /// Returns the receiver coerced to a string value.
232+ /// - Returns: A `String` value.
233+ /// - Throws: `JSONError` if the receiver is an object or array.
234+ func toString() throws -> String {
235+ return try toStringMaybeNil(.required(.string)) ?? "null"
236+ }
237+
238+ /// Returns the receiver coerced to a string value.
239+ /// - Returns: A `String` value, or `nil` if the receiver is `null`.
240+ /// - Throws: `JSONError` if the receiver is an object or array.
241+ func toStringOrNil() throws -> String? {
242+ return try toStringMaybeNil(.optional(.string))
243+ }
244+
245+ private func toStringMaybeNil(_ expected: JSONError.ExpectedType) throws -> String? {
246+ switch self {
247+ case .string(let s): return s
248+ case .null: return nil
249+ case .bool(let b): return String(b)
250+ case .int64(let i): return String(i)
251+ case .double(let d): return String(d)
252+ default: throw JSONError.missingOrInvalidType(path: nil, expected: expected, actual: .forValue(self))
253+ }
254+ }
255+
256+ /// Returns the receiver coerced to a 64-bit integral value.
257+ /// If the receiver is a floating-point value, the value will be truncated
258+ /// to an integer.
259+ /// - Returns: An `Int64` value`.
260+ /// - Throws: `JSONError` if the receiver is `null`, a boolean, an object,
261+ /// an array, a string that cannot be coerced to a 64-bit integral value,
262+ /// or a floating-point value that does not fit in 64 bits.
263+ func toInt64() throws -> Int64 {
264+ guard let val = try toInt64MaybeNil(.required(.number)) else {
265+ throw JSONError.missingOrInvalidType(path: nil, expected: .required(.number), actual: .null)
266+ }
267+ return val
268+ }
269+
270+ /// Returns the receiver coerced to a 64-bit integral value.
271+ /// If the receiver is a floating-point value, the value will be truncated
272+ /// to an integer.
273+ /// - Returns: An `Int64` value`, or `nil` if the receiver is `null`.
274+ /// - Throws: `JSONError` if the receiver is a boolean, an object, an array,
275+ /// a string that cannot be coerced to a 64-bit integral value,
276+ /// or a floating-point value that does not fit in 64 bits.
277+ func toInt64OrNil() throws -> Int64? {
278+ return try toInt64MaybeNil(.optional(.number))
279+ }
280+
281+ private func toInt64MaybeNil(_ expected: JSONError.ExpectedType) throws -> Int64? {
282+ switch self {
283+ case .int64(let i):
284+ return i
285+ case .double(let d):
286+ guard let val = convertDoubleToInt64(d) else {
287+ throw JSONError.outOfRangeDouble(path: nil, value: d, expected: Int64.self)
288+ }
289+ return val
290+ case .string(let s):
291+ if let i = Int64(s, radix: 10) {
292+ return i
293+ } else if let d = Double(s) {
294+ guard let val = convertDoubleToInt64(d) else {
295+ throw JSONError.outOfRangeDouble(path: nil, value: d, expected: Int64.self)
296+ }
297+ return val
298+ }
299+ case .null:
300+ return nil
301+ default:
302+ break
303+ }
304+ throw JSONError.missingOrInvalidType(path: nil, expected: expected, actual: .forValue(self))
305+ }
306+
307+ /// Returns the receiver coerced to an integral value.
308+ /// If the receiver is a floating-point value, the value will be truncated
309+ /// to an integer.
310+ /// - Returns: An `Int` value`.
311+ /// - Throws: `JSONError` if the receiver is `null`, a boolean, an object,
312+ /// an array, a string that cannot be coerced to an integral value,
313+ /// or a floating-point value that does not fit in an `Int`.
314+ func toInt() throws -> Int {
315+ let val = try toInt64()
316+ let truncated = Int(truncatingBitPattern: val)
317+ guard Int64(truncated) == val else { throw JSONError.outOfRangeInt64(path: nil, value: val, expected: Int.self) }
318+ return truncated
319+ }
320+
321+ /// Returns the receiver coerced to an integral value.
322+ /// If the receiver is a floating-point value, the value will be truncated
323+ /// to an integer.
324+ /// - Returns: An `Int` value`, or `nil` if the receiver is `null`.
325+ /// - Throws: `JSONError` if the receiver is a boolean, an object,
326+ /// an array, a string that cannot be coerced to an integral value,
327+ /// or a floating-point value that does not fit in an `Int`.
328+ func toIntOrNil() throws -> Int? {
329+ guard let val = try toInt64OrNil() else { return nil }
330+ let truncated = Int(truncatingBitPattern: val)
331+ guard Int64(truncated) == val else { throw JSONError.outOfRangeInt64(path: nil, value: val, expected: Int.self) }
332+ return truncated
333+ }
334+
335+ /// Returns the receiver coerced to a `Double`.
336+ /// - Returns: A `Double` value.
337+ /// - Throws: `JSONError` if the receiver is `null`, a boolean, an object, an array,
338+ /// or a string that cannot be coerced to a floating-point value.
339+ func toDouble() throws -> Double {
340+ guard let val = try toDoubleMaybeNil(.required(.number)) else {
341+ throw JSONError.missingOrInvalidType(path: nil, expected: .required(.number), actual: .null)
342+ }
343+ return val
344+ }
345+
346+ /// Returns the receiver coerced to a `Double`.
347+ /// - Returns: A `Double` value, or `nil` if the receiver is `null`.
348+ /// - Throws: `JSONError` if the receiver is a boolean, an object, an array,
349+ /// or a string that cannot be coerced to a floating-point value.
350+ func toDoubleOrNil() throws -> Double? {
351+ return try toDoubleMaybeNil(.optional(.number))
352+ }
353+
354+ private func toDoubleMaybeNil(_ expected: JSONError.ExpectedType) throws -> Double? {
355+ switch self {
356+ case .int64(let i): return Double(i)
357+ case .double(let d): return d
358+ case .string(let s): return Double(s)
359+ case .null: return nil
360+ default: throw JSONError.missingOrInvalidType(path: nil, expected: expected, actual: .forValue(self))
361+ }
362+ }
363+}
364+
365+// MARK: - Keyed accessors
366+public extension JSON {
367+ /// Subscripts the receiver with `key` and returns the result.
368+ /// - Parameter key: The key that's used to subscript the receiver.
369+ /// - Returns: A `Bool` value.
370+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or if
371+ /// the receiver is not an object.
372+ func getBool(_ key: String) throws -> Bool {
373+ let dict = try getObject()
374+ let value = try getRequired(dict, key: key, type: .string)
375+ return try scoped(key) { try value.getBool() }
376+ }
377+
378+ /// Subscripts the receiver with `key` and returns the result.
379+ /// - Parameter key: The key that's used to subscript the receiver.
380+ /// - Returns: A `Bool` value, or `nil` if the key doesn't exist or the value is `null`.
381+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an object.
382+ func getBoolOrNil(_ key: String) throws -> Bool? {
383+ let dict = try getObject()
384+ guard let value = dict[key] else { return nil }
385+ return try scoped(key) { try value.getBoolOrNil() }
386+ }
387+
388+ /// Subscripts the receiver with `key` and returns the result.
389+ /// - Parameter key: The key that's used to subscript the receiver.
390+ /// - Returns: A `String` value.
391+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or if
392+ /// the receiver is not an object.
393+ func getString(_ key: String) throws -> String {
394+ let dict = try getObject()
395+ let value = try getRequired(dict, key: key, type: .string)
396+ return try scoped(key) { try value.getString() }
397+ }
398+
399+ /// Subscripts the receiver with `key` and returns the result.
400+ /// - Parameter key: The key that's used to subscript the receiver.
401+ /// - Returns: A `String` value, or `nil` if the key doesn't exist or the value is `null`.
402+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an object.
403+ func getStringOrNil(_ key: String) throws -> String? {
404+ let dict = try getObject()
405+ guard let value = dict[key] else { return nil }
406+ return try scoped(key) { try value.getStringOrNil() }
407+ }
408+
409+ /// Subscripts the receiver with `key` and returns the result.
410+ /// - Parameter key: The key that's used to subscript the receiver.
411+ /// - Returns: An `Int64` value.
412+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or if
413+ /// the receiver is not an object.
414+ func getInt64(_ key: String) throws -> Int64 {
415+ let dict = try getObject()
416+ let value = try getRequired(dict, key: key, type: .number)
417+ return try scoped(key) { try value.getInt64() }
418+ }
419+
420+ /// Subscripts the receiver with `key` and returns the result.
421+ /// - Parameter key: The key that's used to subscript the receiver.
422+ /// - Returns: An `Int64` value, or `nil` if the key doesn't exist or the value is `null`.
423+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an object.
424+ func getInt64OrNil(_ key: String) throws -> Int64? {
425+ let dict = try getObject()
426+ guard let value = dict[key] else { return nil }
427+ return try scoped(key) { try value.getInt64OrNil() }
428+ }
429+
430+ /// Subscripts the receiver with `key` and returns the result.
431+ /// - Parameter key: The key that's used to subscript the receiver.
432+ /// - Returns: An `Int` value.
433+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type,
434+ /// or if the 64-bit integral value is too large to fit in an `Int`, or if
435+ /// the receiver is not an object.
436+ func getInt(_ key: String) throws -> Int {
437+ let dict = try getObject()
438+ let value = try getRequired(dict, key: key, type: .number)
439+ return try scoped(key) { try value.getInt() }
440+ }
441+
442+ /// Subscripts the receiver with `key` and returns the result.
443+ /// - Parameter key: The key that's used to subscript the receiver.
444+ /// - Returns: An `Int` value, or `nil` if the key doesn't exist or the value is `null`.
445+ /// - Throws: `JSONError` if the value has the wrong type, or if the 64-bit integral
446+ /// value is too large to fit in an `Int`, or if the receiver is not an object.
447+ func getIntOrNil(_ key: String) throws -> Int? {
448+ let dict = try getObject()
449+ guard let value = dict[key] else { return nil }
450+ return try scoped(key) { try value.getIntOrNil() }
451+ }
452+
453+ /// Subscripts the receiver with `key` and returns the result.
454+ /// - Parameter key: The key that's used to subscript the receiver.
455+ /// - Returns: A `Double` value.
456+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or if
457+ /// the receiver is not an object.
458+ func getDouble(_ key: String) throws -> Double {
459+ let dict = try getObject()
460+ let value = try getRequired(dict, key: key, type: .number)
461+ return try scoped(key) { try value.getDouble() }
462+ }
463+
464+ /// Subscripts the receiver with `key` and returns the result.
465+ /// - Parameter key: The key that's used to subscript the receiver.
466+ /// - Returns: A `Double` value, or `nil` if the key doesn't exist or the value is `null`.
467+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an object.
468+ func getDoubleOrNil(_ key: String) throws -> Double? {
469+ let dict = try getObject()
470+ guard let value = dict[key] else { return nil }
471+ return try scoped(key) { try value.getDoubleOrNil() }
472+ }
473+
474+ /// Subscripts the receiver with `key` and returns the result.
475+ /// - Note: Use `getObject(_:_:)` when using throwing accessors on the resulting
476+ /// object value to produce better errors.
477+ /// - Parameter key: The key that's used to subscript the receiver.
478+ /// - Returns: An object value.
479+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or if
480+ /// the receiver is not an object.
481+ /// - SeeAlso: `getObject(_:_:)`
482+ func getObject(_ key: String) throws -> JSONObject {
483+ return try getObject(key, { $0 })
484+ }
485+
486+ /// Subscripts the receiver with `key` and returns the result.
487+ /// - Note: Use `getObjectOrNil(_:_:)` when using throwing accessors on the resulting
488+ /// object value to produce better errors.
489+ /// - Parameter key: The key that's used to subscript the receiver.
490+ /// - Returns: An object value, or `nil` if the key doesn't exist or the value is `null`.
491+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an object.
492+ /// - SeeAlso: `getObjectOrNil(_:_:)`
493+ func getObjectOrNil(_ key: String) throws -> JSONObject? {
494+ return try getObjectOrNil(key, { $0 })
495+ }
496+
497+ /// Subscripts the receiver with `key` and passes the result to the given block.
498+ /// - Parameter key: The key that's used to subscript the receiver.
499+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `key`.
500+ /// - Returns: The result of calling the given block.
501+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or if
502+ /// the receiver is not an object, or any error thrown by `transform`.
503+ func getObject<T>(_ key: String, _ transform: (JSONObject) throws -> T) throws -> T {
504+ return try getObject().getObject(key, transform)
505+ }
506+
507+ /// Subscripts the receiver with `key` and passes the result to the given block.
508+ /// - Parameter key: The key that's used to subscript the receiver.
509+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `key`.
510+ /// - Returns: The result of calling the given block, or `nil` if the key doesn't exist or the value is `null`.
511+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an object,
512+ /// or any error thrown by `transform`.
513+ func getObjectOrNil<T>(_ key: String, _ transform: (JSONObject) throws -> T?) throws -> T? {
514+ return try getObject().getObjectOrNil(key, transform)
515+ }
516+
517+ /// Subscripts the receiver with `key` and returns the result.
518+ /// - Note: Use `getArray(_:_:)` when using throwing accessors on the resulting
519+ /// array value to produce better errors.
520+ /// - Parameter key: The key that's used to subscript the receiver.
521+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or if
522+ /// the receiver is not an object.
523+ /// - SeeAlso: `getArray(_:_:)`
524+ func getArray(_ key: String) throws -> JSONArray {
525+ return try getArray(key, { $0 })
526+ }
527+
528+ /// Subscripts the receiver with `key` and returns the result.
529+ /// - Note: Use `getArrayOrNil(_:_:)` when using throwing accessors on the resulting
530+ /// array value to produce better errors.
531+ /// - Parameter key: The key that's used to subscript the receiver.
532+ /// - Returns: An array value, or `nil` if the key doesn't exist or the value is `null`.
533+ /// - Throws: `JSONError` if the value has the wrong type.
534+ /// - SeeAlso: `getArrayOrNil(_:_:)`
535+ func getArrayOrNil(_ key: String) throws -> JSONArray? {
536+ return try getArrayOrNil(key, { $0 })
537+ }
538+
539+ /// Subscripts the receiver with `key` and passes the result to the given block.
540+ /// - Parameter key: The key that's used to subscript the receiver.
541+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `key`.
542+ /// - Returns: The result of calling the given block.
543+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or if
544+ /// the receiver is not an object, or any error thrown by `transform`.
545+ func getArray<T>(_ key: String, _ transform: (JSONArray) throws -> T) throws -> T {
546+ let dict = try getObject()
547+ let value = try getRequired(dict, key: key, type: .array)
548+ return try scoped(key) { try transform(value.getArray()) }
549+ }
550+
551+ /// Subscripts the receiver with `key` and passes the result to the given block.
552+ /// - Parameter key: The key that's used to subscript the receiver.
553+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `key`.
554+ /// - Returns: The result of calling the given block, or `nil` if the key doesn't exist or the value is `null`.
555+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an object,
556+ /// or any error thrown by `transform`.
557+ func getArrayOrNil<T>(_ key: String, _ transform: (JSONArray) throws -> T?) throws -> T? {
558+ let dict = try getObject()
559+ guard let value = dict[key] else { return nil }
560+ return try scoped(key) { try value.getArrayOrNil().flatMap(transform) }
561+ }
562+}
563+
564+public extension JSON {
565+ /// Subscripts the receiver with `key` and returns the result coerced to a `String`.
566+ /// - Parameter key: The key that's used to subscript the receiver.
567+ /// - Returns: A `String` value.
568+ /// - Throws: `JSONError` if the key doesn't exist, the value is an object or an array,
569+ /// or if the receiver is not an object.
570+ /// - SeeAlso: `toString()`.
571+ func toString(_ key: String) throws -> String {
572+ let dict = try getObject()
573+ let value = try getRequired(dict, key: key, type: .string)
574+ return try scoped(key) { try value.toString() }
575+ }
576+
577+ /// Subscripts the receiver with `key` and returns the result coerced to a `String`.
578+ /// - Parameter key: The key that's used to subscript the receiver.
579+ /// - Returns: A `String` value, or `nil` if the key doesn't exist or the value is `null`.
580+ /// - Throws: `JSONError` if the value is an object or an array, or if the receiver is not an object.
581+ /// - SeeAlso: `toStringOrNil()`.
582+ func toStringOrNil(_ key: String) throws -> String? {
583+ let dict = try getObject()
584+ guard let value = dict[key] else { return nil }
585+ return try scoped(key) { try value.toStringOrNil() }
586+ }
587+
588+ /// Subscripts the receiver with `key` and returns the result coerced to an `Int64`.
589+ /// - Parameter key: The key that's used to subscript the receiver.
590+ /// - Returns: An `Int64` value.
591+ /// - Throws: `JSONError` if the key doesn't exist or the value is `null`, a boolean, an object,
592+ /// an array, a string that cannot be coerced to a 64-bit integral value, or a floating-point
593+ /// value that does not fit in 64 bits, or if the receiver is not an object.
594+ func toInt64(_ key: String) throws -> Int64 {
595+ let dict = try getObject()
596+ let value = try getRequired(dict, key: key, type: .number)
597+ return try scoped(key) { try value.toInt64() }
598+ }
599+
600+ /// Subscripts the receiver with `key` and returns the result coerced to an `Int64`.
601+ /// - Parameter key: The key that's used to subscript the receiver.
602+ /// - Returns: An `Int64` value, or `nil` if the key doesn't exist or the value is `null`.
603+ /// - Throws: `JSONError` if the the value is a boolean, an object, an array, a string
604+ /// that cannot be coerced to a 64-bit integral value, or a floating-point value
605+ /// that does not fit in 64 bits, or if the receiver is not an object.
606+ func toInt64OrNil(_ key: String) throws -> Int64? {
607+ let dict = try getObject()
608+ guard let value = dict[key] else { return nil }
609+ return try scoped(key) { try value.toInt64OrNil() }
610+ }
611+
612+ /// Subscripts the receiver with `key` and returns the result coerced to an `Int`.
613+ /// - Parameter key: The key that's used to subscript the receiver.
614+ /// - Returns: An `Int` value.
615+ /// - Throws: `JSONError` if the key doesn't exist or the value is `null`, a boolean, an object,
616+ /// an array, a string that cannot be coerced to an integral value, or a floating-point
617+ /// value that does not fit in an `Int`, or if the receiver is not an object.
618+ func toInt(_ key: String) throws -> Int {
619+ let dict = try getObject()
620+ let value = try getRequired(dict, key: key, type: .number)
621+ return try scoped(key) { try value.toInt() }
622+ }
623+
624+ /// Subscripts the receiver with `key` and returns the result coerced to an `Int`.
625+ /// - Parameter key: The key that's used to subscript the receiver.
626+ /// - Returns: An `Int` value, or `nil` if the key doesn't exist or the value is `null`.
627+ /// - Throws: `JSONError` if the the value is a boolean, an object, an array, a string
628+ /// that cannot be coerced to an integral value, or a floating-point value
629+ /// that does not fit in an `Int`, or if the receiver is not an object.
630+ func toIntOrNil(_ key: String) throws -> Int? {
631+ let dict = try getObject()
632+ guard let value = dict[key] else { return nil }
633+ return try scoped(key) { try value.toIntOrNil() }
634+ }
635+
636+ /// Subscripts the receiver with `key` and returns the result coerced to a `Double`.
637+ /// - Parameter key: The key that's used to subscript the receiver.
638+ /// - Returns: A `Double` value.
639+ /// - Throws: `JSONError` if the key doesn't exist or the value is `null`, a boolean,
640+ /// an object, an array, or a string that cannot be coerced to a floating-point value,
641+ /// or if the receiver is not an object.
642+ func toDouble(_ key: String) throws -> Double {
643+ let dict = try getObject()
644+ let value = try getRequired(dict, key: key, type: .number)
645+ return try scoped(key) { try value.toDouble() }
646+ }
647+
648+ /// Subscripts the receiver with `key` and returns the result coerced to a `Double`.
649+ /// - Parameter key: The key that's used to subscript the receiver.
650+ /// - Returns: A `Double` value, or `nil` if the key doesn't exist or the value is `null`.
651+ /// - Throws: `JSONError` if the value is a boolean, an object, an array, or a string that
652+ /// cannot be coerced to a floating-point value, or if the receiver is not an object.
653+ func toDoubleOrNil(_ key: String) throws -> Double? {
654+ let dict = try getObject()
655+ guard let value = dict[key] else { return nil }
656+ return try scoped(key) { try value.toDoubleOrNil() }
657+ }
658+}
659+
660+// MARK: - Indexed accessors
661+public extension JSON {
662+ /// Subscripts the receiver with `index` and returns the result.
663+ /// - Parameter index: The index that's used to subscript the receiver.
664+ /// - Returns: A `Bool` value.
665+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
666+ /// or if the receiver is not an array.
667+ func getBool(_ index: Int) throws -> Bool {
668+ let ary = try getArray()
669+ let value = try getRequired(ary, index: index, type: .bool)
670+ return try scoped(index) { try value.getBool() }
671+ }
672+
673+ /// Subscripts the receiver with `index` and returns the result.
674+ /// - Parameter index: The index that's used to subscript the receiver.
675+ /// - Returns: A `Bool` value, or `nil` if the index is out of bounds or the value is `null`.
676+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an array.
677+ func getBoolOrNil(_ index: Int) throws -> Bool? {
678+ let ary = try getArray()
679+ guard let value = ary[safe: index] else { return nil }
680+ return try scoped(index) { try value.getBoolOrNil() }
681+ }
682+
683+ /// Subscripts the receiver with `index` and returns the result.
684+ /// - Parameter index: The index that's used to subscript the receiver.
685+ /// - Returns: A `String` value.
686+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
687+ /// or if the receiver is not an array.
688+ func getString(_ index: Int) throws -> String {
689+ let ary = try getArray()
690+ let value = try getRequired(ary, index: index, type: .string)
691+ return try scoped(index) { try value.getString() }
692+ }
693+
694+ /// Subscripts the receiver with `index` and returns the result.
695+ /// - Parameter index: The index that's used to subscript the receiver.
696+ /// - Returns: A `String` value, or `nil` if the index is out of bounds or the value is `null`.
697+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an array.
698+ func getStringOrNil(_ index: Int) throws -> String? {
699+ let ary = try getArray()
700+ guard let value = ary[safe: index] else { return nil }
701+ return try scoped(index) { try value.getStringOrNil() }
702+ }
703+
704+ /// Subscripts the receiver with `index` and returns the result.
705+ /// - Parameter index: The index that's used to subscript the receiver.
706+ /// - Returns: An `Int64` value.
707+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
708+ /// or if the receiver is not an array.
709+ func getInt64(_ index: Int) throws -> Int64 {
710+ let ary = try getArray()
711+ let value = try getRequired(ary, index: index, type: .number)
712+ return try scoped(index) { try value.getInt64() }
713+ }
714+
715+ /// Subscripts the receiver with `index` and returns the result.
716+ /// - Parameter index: The index that's used to subscript the receiver.
717+ /// - Returns: An `Int64` value, or `nil` if the index is out of bounds or the value is `null`.
718+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an array.
719+ func getInt64OrNil(_ index: Int) throws -> Int64? {
720+ let ary = try getArray()
721+ guard let value = ary[safe: index] else { return nil }
722+ return try scoped(index) { try value.getInt64OrNil() }
723+ }
724+
725+ /// Subscripts the receiver with `index` and returns the result.
726+ /// - Parameter index: The index that's used to subscript the receiver.
727+ /// - Returns: An `Int` value.
728+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
729+ /// or if the 64-bit integral value is too large to fit in an `Int`, or if
730+ /// the receiver is not an array.
731+ func getInt(_ index: Int) throws -> Int {
732+ let ary = try getArray()
733+ let value = try getRequired(ary, index: index, type: .number)
734+ return try scoped(index) { try value.getInt() }
735+ }
736+
737+ /// Subscripts the receiver with `index` and returns the result.
738+ /// - Parameter index: The index that's used to subscript the receiver.
739+ /// - Returns: An `Int` value, or `nil` if the index is out of bounds or the value is `null`.
740+ /// - Throws: `JSONError` if the value has the wrong type, or if the 64-bit integral value
741+ /// is too large to fit in an `Int`, or if the receiver is not an array.
742+ func getIntOrNil(_ index: Int) throws -> Int? {
743+ let ary = try getArray()
744+ guard let value = ary[safe: index] else { return nil }
745+ return try scoped(index) { try value.getIntOrNil() }
746+ }
747+
748+ /// Subscripts the receiver with `index` and returns the result.
749+ /// - Parameter index: The index that's used to subscript the receiver.
750+ /// - Returns: A `Double` value.
751+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
752+ /// or if the receiver is not an array.
753+ func getDouble(_ index: Int) throws -> Double {
754+ let ary = try getArray()
755+ let value = try getRequired(ary, index: index, type: .number)
756+ return try scoped(index) { try value.getDouble() }
757+ }
758+
759+ /// Subscripts the receiver with `index` and returns the result.
760+ /// - Parameter index: The index that's used to subscript the receiver.
761+ /// - Returns: A `Double` value, or `nil` if the index is out of bounds or the value is `null`.
762+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an array.
763+ func getDoubleOrNil(_ index: Int) throws -> Double? {
764+ let ary = try getArray()
765+ guard let value = ary[safe: index] else { return nil }
766+ return try scoped(index) { try value.getDoubleOrNil() }
767+ }
768+
769+ /// Subscripts the receiver with `index` and returns the result.
770+ /// - Note: Use `getObject(_:_:)` when using throwing accessors on the resulting
771+ /// object value to produce better errors.
772+ /// - Parameter index: The index that's used to subscript the receiver.
773+ /// - Returns: An object value.
774+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
775+ /// or if the receiver is not an array.
776+ /// - SeeAlso: `getObject(_:_:)`
777+ func getObject(_ index: Int) throws -> JSONObject {
778+ return try getObject(index, { $0 })
779+ }
780+
781+ /// Subscripts the receiver with `index` and returns the result.
782+ /// - Note: Use `getObjectOrNil(_:_:)` when using throwing accessors on the resulting
783+ /// object value to produce better errors.
784+ /// - Parameter index: The index that's used to subscript the receiver.
785+ /// - Returns: An object value, or `nil` if the index is out of bounds or the value is `null`.
786+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an array.
787+ /// - SeeAlso: `getObjectOrNil(_:_:)`
788+ func getObjectOrNil(_ index: Int) throws -> JSONObject? {
789+ return try getObjectOrNil(index, { $0 })
790+ }
791+
792+ /// Subscripts the receiver with `index` and passes the result to the given block.
793+ /// - Parameter index: The index that's used to subscript the receiver.
794+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `index`.
795+ /// - Returns: The result of calling the given block.
796+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
797+ /// or if the receiver is not an array, or any error thrown by `transform`.
798+ func getObject<T>(_ index: Int, _ f: (JSONObject) throws -> T) throws -> T {
799+ let ary = try getArray()
800+ let value = try getRequired(ary, index: index, type: .object)
801+ return try scoped(index) { try f(value.getObject()) }
802+ }
803+
804+ /// Subscripts the receiver with `index` and passes the result to the given block.
805+ /// - Parameter index: The index that's used to subscript the receiver.
806+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `index`.
807+ /// - Returns: The result of calling the given block, or `nil` if the index is out of bounds or the value is `null`.
808+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an array,
809+ //// or any error thrown by `transform`.
810+ func getObjectOrNil<T>(_ index: Int, _ f: (JSONObject) throws -> T?) throws -> T? {
811+ let ary = try getArray()
812+ guard let value = ary[safe: index] else { return nil }
813+ return try scoped(index) { try value.getObjectOrNil().flatMap(f) }
814+ }
815+
816+ /// Subscripts the receiver with `index` and returns the result.
817+ /// - Note: Use `getArray(_:_:)` when using throwing accessors on the resulting
818+ /// array value to produce better errors.
819+ /// - Parameter index: The index that's used to subscript the receiver.
820+ /// - Returns: An array value.
821+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
822+ /// or if the receiver is not an array.
823+ /// - SeeAlso: `getArray(_:_:)`
824+ func getArray(_ index: Int) throws -> JSONArray {
825+ return try getArray(index, { $0 })
826+ }
827+
828+ /// Subscripts the receiver with `index` and returns the result.
829+ /// - Note: Use `getArrayOrNil(_:_:)` when using throwing accessors on the resulting
830+ /// array value to produce better errors.
831+ /// - Parameter index: The index that's used to subscript the receiver.
832+ /// - Returns: An array value, or `nil` if the index is out of bounds or the value is `null`.
833+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an array.
834+ /// - SeeAlso: `getArrayOrNil(_:_:)`
835+ func getArrayOrNil(_ index: Int) throws -> JSONArray? {
836+ return try getArrayOrNil(index, { $0 })
837+ }
838+
839+ /// Subscripts the receiver with `index` and passes the result to the given block.
840+ /// - Parameter index: The index that's used to subscript the receiver.
841+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `index`.
842+ /// - Returns: The result of calling the given block.
843+ /// - Throws: `JSONError` if the index is out of bounds or the value is the wrong type,
844+ /// or if the receiver is not an array, or any error thrown by `transform`.
845+ func getArray<T>(_ index: Int, _ f: (JSONArray) throws -> T) throws -> T {
846+ let ary = try getArray()
847+ let value = try getRequired(ary, index: index, type: .array)
848+ return try scoped(index) { try f(value.getArray()) }
849+ }
850+
851+ /// Subscripts the receiver with `index` and passes the result to the given block.
852+ /// - Parameter index: The index that's used to subscript the receiver.
853+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `index`.
854+ /// - Returns: The result of calling the given block, or `nil` if the index is out of bounds or the value is `null`.
855+ /// - Throws: `JSONError` if the value has the wrong type, or if the receiver is not an array,
856+ /// or any error thrown by `transform`.
857+ func getArrayOrNil<T>(_ index: Int, _ f: (JSONArray) throws -> T?) throws -> T? {
858+ let ary = try getArray()
859+ guard let value = ary[safe: index] else { return nil }
860+ return try scoped(index) { try value.getArrayOrNil().flatMap(f) }
861+ }
862+}
863+
864+public extension JSON {
865+ /// Subscripts the receiver with `index` and returns the result coerced to a `String`.
866+ /// - Parameter index: The index that's used to subscript the receiver.
867+ /// - Returns: A `String` value.
868+ /// - Throws: `JSONError` if the index is out of bounds or the value is an object or an array,
869+ /// or if the receiver is not an array.
870+ /// - SeeAlso: `toString()`.
871+ func toString(_ index: Int) throws -> String {
872+ let ary = try getArray()
873+ let value = try getRequired(ary, index: index, type: .string)
874+ return try scoped(index) { try value.toString() }
875+ }
876+
877+ /// Subscripts the receiver with `index` and returns the result coerced to a `String`.
878+ /// - Parameter index: The index that's used to subscript the receiver.
879+ /// - Returns: A `String` value, or `nil` if the index is out of bounds or the value is `null`.
880+ /// - Throws: `JSONError` if the value is an object or an array, or if the receiver is not an array.
881+ /// - SeeAlso: `toStringOrNil()`.
882+ func toStringOrNil(_ index: Int) throws -> String? {
883+ let ary = try getArray()
884+ guard let value = ary[safe: index] else { return nil }
885+ return try scoped(index) { try value.toStringOrNil() }
886+ }
887+
888+ /// Subscripts the receiver with `index` and returns the result coerced to an `Int64`.
889+ /// - Parameter index: The index that's used to subscript the receiver.
890+ /// - Returns: An `Int64` value.
891+ /// - Throws: `JSONError` if the index is out of bounds or the value is `null`, a boolean,
892+ /// an object, an array, a string that cannot be coerced to a 64-bit integral value, or a
893+ /// floating-point value that does not fit in 64 bits, or if the receiver is not an array.
894+ /// - SeeAlso: `toInt64()`.
895+ func toInt64(_ index: Int) throws -> Int64 {
896+ let ary = try getArray()
897+ let value = try getRequired(ary, index: index, type: .number)
898+ return try scoped(index) { try value.toInt64() }
899+ }
900+
901+ /// Subscripts the receiver with `index` and returns the result coerced to an `Int64`.
902+ /// - Parameter index: The index that's used to subscript the receiver.
903+ /// - Returns: An `Int64` value, or `nil` if the index is out of bounds or the value is `null`.
904+ /// - Throws: `JSONError` if the the value is a boolean, an object, an array, a string
905+ /// that cannot be coerced to a 64-bit integral value, or a floating-point value
906+ /// that does not fit in 64 bits, or if the receiver is not an array.
907+ /// - SeeAlso: `toInt64OrNil()`.
908+ func toInt64OrNil(_ index: Int) throws -> Int64? {
909+ let ary = try getArray()
910+ guard let value = ary[safe: index] else { return nil }
911+ return try scoped(index) { try value.toInt64OrNil() }
912+ }
913+
914+ /// Subscripts the receiver with `index` and returns the result coerced to an `Int`.
915+ /// - Parameter index: The index that's used to subscript the receiver.
916+ /// - Returns: An `Int` value.
917+ /// - Throws: `JSONError` if the index is out of bounds or the value is `null`, a boolean,
918+ /// an object, an array, a string that cannot be coerced to an integral value, or a
919+ /// floating-point value that does not fit in an `Int`, or if the receiver is not an array.
920+ /// - SeeAlso: `toInt()`.
921+ func toInt(_ index: Int) throws -> Int {
922+ let ary = try getArray()
923+ let value = try getRequired(ary, index: index, type: .number)
924+ return try scoped(index) { try value.toInt() }
925+ }
926+
927+ /// Subscripts the receiver with `index` and returns the result coerced to an `Int`.
928+ /// - Parameter index: The index that's used to subscript the receiver.
929+ /// - Returns: An `Int` value, or `nil` if the index is out of bounds or the value is `null`.
930+ /// - Throws: `JSONError` if the the value is a boolean, an object, an array, a string
931+ /// that cannot be coerced to an integral value, or a floating-point value
932+ /// that does not fit in an `Int`, or if the receiver is not an array.
933+ /// - SeeAlso: `toIntOrNil()`.
934+ func toIntOrNil(_ index: Int) throws -> Int? {
935+ let ary = try getArray()
936+ guard let value = ary[safe: index] else { return nil }
937+ return try scoped(index) { try value.toIntOrNil() }
938+ }
939+
940+ /// Subscripts the receiver with `index` and returns the result coerced to a `Double`.
941+ /// - Parameter index: The index that's used to subscript the receiver.
942+ /// - Returns: A `Double` value.
943+ /// - Throws: `JSONError` if the index is out of bounds or the value is `null`, a boolean,
944+ /// an object, an array, or a string that cannot be coerced to a floating-point value,
945+ /// or if the receiver is not an array.
946+ /// - SeeAlso: `toDouble()`.
947+ func toDouble(_ index: Int) throws -> Double {
948+ let ary = try getArray()
949+ let value = try getRequired(ary, index: index, type: .number)
950+ return try scoped(index) { try value.toDouble() }
951+ }
952+
953+ /// Subscripts the receiver with `index` and returns the result coerced to a `Double`.
954+ /// - Parameter index: The index that's used to subscript the receiver.
955+ /// - Returns: A `Double` value, or `nil` if the index is out of bounds or the value is `null`.
956+ /// - Throws: `JSONError` if the value is a boolean, an object, an array, or a string that
957+ /// cannot be coerced to a floating-point value, or if the receiver is not an array.
958+ /// - SeeAlso: `toDouble()`.
959+ func toDoubleOrNil(_ index: Int) throws -> Double? {
960+ let ary = try getArray()
961+ guard let value = ary[safe: index] else { return nil }
962+ return try scoped(index) { try value.toDoubleOrNil() }
963+ }
964+}
965+
966+// MARK: -
967+
968+public extension JSONObject {
969+ /// Subscripts the receiver with `key` and returns the result.
970+ /// - Parameter key: The key that's used to subscript the receiver.
971+ /// - Returns: A `Bool` value.
972+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type.
973+ func getBool(_ key: String) throws -> Bool {
974+ let value = try getRequired(self, key: key, type: .string)
975+ return try scoped(key) { try value.getBool() }
976+ }
977+
978+ /// Subscripts the receiver with `key` and returns the result.
979+ /// - Parameter key: The key that's used to subscript the receiver.
980+ /// - Returns: A `Bool` value, or `nil` if the key doesn't exist or the value is `null`.
981+ /// - Throws: `JSONError` if the value has the wrong type.
982+ func getBoolOrNil(_ key: String) throws -> Bool? {
983+ guard let value = self[key] else { return nil }
984+ return try scoped(key) { try value.getBoolOrNil() }
985+ }
986+
987+ /// Subscripts the receiver with `key` and returns the result.
988+ /// - Parameter key: The key that's used to subscript the receiver.
989+ /// - Returns: A `String` value.
990+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type.
991+ func getString(_ key: String) throws -> String {
992+ let value = try getRequired(self, key: key, type: .string)
993+ return try scoped(key) { try value.getString() }
994+ }
995+
996+ /// Subscripts the receiver with `key` and returns the result.
997+ /// - Parameter key: The key that's used to subscript the receiver.
998+ /// - Returns: A `String` value, or `nil` if the key doesn't exist or the value is `null`.
999+ /// - Throws: `JSONError` if the value has the wrong type.
1000+ func getStringOrNil(_ key: String) throws -> String? {
1001+ guard let value = self[key] else { return nil }
1002+ return try scoped(key) { try value.getStringOrNil() }
1003+ }
1004+
1005+ /// Subscripts the receiver with `key` and returns the result.
1006+ /// - Parameter key: The key that's used to subscript the receiver.
1007+ /// - Returns: An `Int64` value.
1008+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type.
1009+ func getInt64(_ key: String) throws -> Int64 {
1010+ let value = try getRequired(self, key: key, type: .number)
1011+ return try scoped(key) { try value.getInt64() }
1012+ }
1013+
1014+ /// Subscripts the receiver with `key` and returns the result.
1015+ /// - Parameter key: The key that's used to subscript the receiver.
1016+ /// - Returns: An `Int64` value, or `nil` if the key doesn't exist or the value is `null`.
1017+ /// - Throws: `JSONError` if the value has the wrong type.
1018+ func getInt64OrNil(_ key: String) throws -> Int64? {
1019+ guard let value = self[key] else { return nil }
1020+ return try scoped(key) { try value.getInt64OrNil() }
1021+ }
1022+
1023+ /// Subscripts the receiver with `key` and returns the result.
1024+ /// - Parameter key: The key that's used to subscript the receiver.
1025+ /// - Returns: An `Int` value.
1026+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type,
1027+ /// or if the 64-bit integral value is too large to fit in an `Int`.
1028+ func getInt(_ key: String) throws -> Int {
1029+ let value = try getRequired(self, key: key, type: .number)
1030+ return try scoped(key) { try value.getInt() }
1031+ }
1032+
1033+ /// Subscripts the receiver with `key` and returns the result.
1034+ /// - Parameter key: The key that's used to subscript the receiver.
1035+ /// - Returns: An `Int` value, or `nil` if the key doesn't exist or the value is `null`.
1036+ /// - Throws: `JSONError` if the value has the wrong type, or if the 64-bit integral
1037+ /// value is too large to fit in an `Int`.
1038+ func getIntOrNil(_ key: String) throws -> Int? {
1039+ guard let value = self[key] else { return nil }
1040+ return try scoped(key) { try value.getIntOrNil() }
1041+ }
1042+
1043+ /// Subscripts the receiver with `key` and returns the result.
1044+ /// - Parameter key: The key that's used to subscript the receiver.
1045+ /// - Returns: A `Double` value.
1046+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type.
1047+ func getDouble(_ key: String) throws -> Double {
1048+ let value = try getRequired(self, key: key, type: .number)
1049+ return try scoped(key) { try value.getDouble() }
1050+ }
1051+
1052+ /// Subscripts the receiver with `key` and returns the result.
1053+ /// - Parameter key: The key that's used to subscript the receiver.
1054+ /// - Returns: A `Double` value, or `nil` if the key doesn't exist or the value is `null`.
1055+ /// - Throws: `JSONError` if the value has the wrong type.
1056+ func getDoubleOrNil(_ key: String) throws -> Double? {
1057+ guard let value = self[key] else { return nil }
1058+ return try scoped(key) { try value.getDoubleOrNil() }
1059+ }
1060+
1061+ /// Subscripts the receiver with `key` and returns the result.
1062+ /// - Note: Use `getObject(_:_:)` when using throwing accessors on the resulting
1063+ /// object value to produce better errors.
1064+ /// - Parameter key: The key that's used to subscript the receiver.
1065+ /// - Returns: An object value.
1066+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type.
1067+ /// - SeeAlso: `getObject(_:_:)`
1068+ func getObject(_ key: String) throws -> JSONObject {
1069+ return try getObject(key, { $0 })
1070+ }
1071+
1072+ /// Subscripts the receiver with `key` and returns the result.
1073+ /// - Note: Use `getObjectOrNil(_:_:)` when using throwing accessors on the resulting
1074+ /// object value to produce better errors.
1075+ /// - Parameter key: The key that's used to subscript the receiver.
1076+ /// - Returns: An object value, or `nil` if the key doesn't exist or the value is `null`.
1077+ /// - Throws: `JSONError` if the value has the wrong type.
1078+ /// - SeeAlso: `getObjectOrNil(_:_:)`
1079+ func getObjectOrNil(_ key: String) throws -> JSONObject? {
1080+ return try getObjectOrNil(key, { $0 })
1081+ }
1082+
1083+ /// Subscripts the receiver with `key` and passes the result to the given block.
1084+ /// - Parameter key: The key that's used to subscript the receiver.
1085+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `key`.
1086+ /// - Returns: The result of calling the given block.
1087+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or any
1088+ /// error thrown by `transform`.
1089+ func getObject<T>(_ key: String, _ f: (JSONObject) throws -> T) throws -> T {
1090+ let value = try getRequired(self, key: key, type: .object)
1091+ return try scoped(key) { try f(value.getObject()) }
1092+ }
1093+
1094+ /// Subscripts the receiver with `key` and passes the result to the given block.
1095+ /// - Parameter key: The key that's used to subscript the receiver.
1096+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `key`.
1097+ /// - Returns: The result of calling the given block, or `nil` if the key doesn't exist or the value is `null`.
1098+ /// - Throws: `JSONError` if the value has the wrong type, or any error thrown by `transform`.
1099+ func getObjectOrNil<T>(_ key: String, _ f: (JSONObject) throws -> T?) throws -> T? {
1100+ guard let value = self[key] else { return nil }
1101+ return try scoped(key) { try value.getObjectOrNil().flatMap(f) }
1102+ }
1103+
1104+ /// Subscripts the receiver with `key` and returns the result.
1105+ /// - Note: Use `getArray(_:_:)` when using throwing accessors on the resulting
1106+ /// array value to produce better errors.
1107+ /// - Parameter key: The key that's used to subscript the receiver.
1108+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type.
1109+ /// - SeeAlso: `getArray(_:_:)`
1110+ func getArray(_ key: String) throws -> JSONArray {
1111+ return try getArray(key, { $0 })
1112+ }
1113+
1114+ /// Subscripts the receiver with `key` and returns the result.
1115+ /// - Note: Use `getArrayOrNil(_:_:)` when using throwing accessors on the resulting
1116+ /// array value to produce better errors.
1117+ /// - Parameter key: The key that's used to subscript the receiver.
1118+ /// - Returns: An array value, or `nil` if the key doesn't exist or the value is `null`.
1119+ /// - Throws: `JSONError` if the value has the wrong type.
1120+ /// - SeeAlso: `getArrayOrNil(_:_:)`
1121+ func getArrayOrNil(_ key: String) throws -> JSONArray? {
1122+ return try getArrayOrNil(key, { $0 })
1123+ }
1124+
1125+ /// Subscripts the receiver with `key` and passes the result to the given block.
1126+ /// - Parameter key: The key that's used to subscript the receiver.
1127+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `key`.
1128+ /// - Returns: The result of calling the given block.
1129+ /// - Throws: `JSONError` if the key doesn't exist or the value is the wrong type, or any
1130+ /// error thrown by `transform`.
1131+ func getArray<T>(_ key: String, _ f: (JSONArray) throws -> T) throws -> T {
1132+ let value = try getRequired(self, key: key, type: .array)
1133+ return try scoped(key) { try f(value.getArray()) }
1134+ }
1135+
1136+ /// Subscripts the receiver with `key` and passes the result to the given block.
1137+ /// - Parameter key: The key that's used to subscript the receiver.
1138+ /// - Parameter transform: A block that's called with the result of subscripting the receiver with `key`.
1139+ /// - Returns: The result of calling the given block, or `nil` if the key doesn't exist or the value is `null`.
1140+ /// - Throws: `JSONError` if the value has the wrong type, or any error thrown by `transform`.
1141+ func getArrayOrNil<T>(_ key: String, _ f: (JSONArray) throws -> T?) throws -> T? {
1142+ guard let value = self[key] else { return nil }
1143+ return try scoped(key) { try value.getArrayOrNil().flatMap(f) }
1144+ }
1145+}
1146+
1147+public extension JSONObject {
1148+ /// Subscripts the receiver with `key` and returns the result coerced to a `String`.
1149+ /// - Parameter key: The key that's used to subscript the receiver.
1150+ /// - Returns: A `String` value.
1151+ /// - Throws: `JSONError` if the key doesn't exist, the value is an object or an array,
1152+ /// or if the receiver is not an object.
1153+ /// - SeeAlso: `toString()`.
1154+ func toString(_ key: String) throws -> String {
1155+ let value = try getRequired(self, key: key, type: .string)
1156+ return try scoped(key) { try value.toString() }
1157+ }
1158+
1159+ /// Subscripts the receiver with `key` and returns the result coerced to a `String`.
1160+ /// - Parameter key: The key that's used to subscript the receiver.
1161+ /// - Returns: A `String` value, or `nil` if the key doesn't exist or the value is `null`.
1162+ /// - Throws: `JSONError` if the value is an object or an array, or if the receiver is not an object.
1163+ /// - SeeAlso: `toStringOrNil()`.
1164+ func toStringOrNil(_ key: String) throws -> String? {
1165+ guard let value = self[key] else { return nil }
1166+ return try scoped(key) { try value.toStringOrNil() }
1167+ }
1168+
1169+ /// Subscripts the receiver with `key` and returns the result coerced to an `Int64`.
1170+ /// - Parameter key: The key that's used to subscript the receiver.
1171+ /// - Returns: An `Int64` value.
1172+ /// - Throws: `JSONError` if the key doesn't exist or the value is `null`, a boolean, an object,
1173+ /// an array, a string that cannot be coerced to a 64-bit integral value, or a floating-point
1174+ /// value that does not fit in 64 bits, or if the receiver is not an object.
1175+ func toInt64(_ key: String) throws -> Int64 {
1176+ let value = try getRequired(self, key: key, type: .number)
1177+ return try scoped(key) { try value.toInt64() }
1178+ }
1179+
1180+ /// Subscripts the receiver with `key` and returns the result coerced to an `Int64`.
1181+ /// - Parameter key: The key that's used to subscript the receiver.
1182+ /// - Returns: An `Int64` value, or `nil` if the key doesn't exist or the value is `null`.
1183+ /// - Throws: `JSONError` if the the value is a boolean, an object, an array, a string
1184+ /// that cannot be coerced to a 64-bit integral value, or a floating-point value
1185+ /// that does not fit in 64 bits, or if the receiver is not an object.
1186+ func toInt64OrNil(_ key: String) throws -> Int64? {
1187+ guard let value = self[key] else { return nil }
1188+ return try scoped(key) { try value.toInt64OrNil() }
1189+ }
1190+
1191+ /// Subscripts the receiver with `key` and returns the result coerced to an `Int`.
1192+ /// - Parameter key: The key that's used to subscript the receiver.
1193+ /// - Returns: An `Int` value.
1194+ /// - Throws: `JSONError` if the key doesn't exist or the value is `null`, a boolean, an object,
1195+ /// an array, a string that cannot be coerced to an integral value, or a floating-point
1196+ /// value that does not fit in an `Int`, or if the receiver is not an object.
1197+ func toInt(_ key: String) throws -> Int {
1198+ let value = try getRequired(self, key: key, type: .number)
1199+ return try scoped(key) { try value.toInt() }
1200+ }
1201+
1202+ /// Subscripts the receiver with `key` and returns the result coerced to an `Int`.
1203+ /// - Parameter key: The key that's used to subscript the receiver.
1204+ /// - Returns: An `Int` value, or `nil` if the key doesn't exist or the value is `null`.
1205+ /// - Throws: `JSONError` if the the value is a boolean, an object, an array, a string
1206+ /// that cannot be coerced to an integral value, or a floating-point value
1207+ /// that does not fit in an `Int`, or if the receiver is not an object.
1208+ func toIntOrNil(_ key: String) throws -> Int? {
1209+ guard let value = self[key] else { return nil }
1210+ return try scoped(key) { try value.toIntOrNil() }
1211+ }
1212+
1213+ /// Subscripts the receiver with `key` and returns the result coerced to a `Double`.
1214+ /// - Parameter key: The key that's used to subscript the receiver.
1215+ /// - Returns: A `Double` value.
1216+ /// - Throws: `JSONError` if the key doesn't exist or the value is `null`, a boolean,
1217+ /// an object, an array, or a string that cannot be coerced to a floating-point value,
1218+ /// or if the receiver is not an object.
1219+ func toDouble(_ key: String) throws -> Double {
1220+ let value = try getRequired(self, key: key, type: .number)
1221+ return try scoped(key) { try value.toDouble() }
1222+ }
1223+
1224+ /// Subscripts the receiver with `key` and returns the result coerced to a `Double`.
1225+ /// - Parameter key: The key that's used to subscript the receiver.
1226+ /// - Returns: A `Double` value, or `nil` if the key doesn't exist or the value is `null`.
1227+ /// - Throws: `JSONError` if the value is a boolean, an object, an array, or a string that
1228+ /// cannot be coerced to a floating-point value, or if the receiver is not an object.
1229+ func toDoubleOrNil(_ key: String) throws -> Double? {
1230+ guard let value = self[key] else { return nil }
1231+ return try scoped(key) { try value.toDoubleOrNil() }
1232+ }
1233+}
1234+
1235+// MARK: - JSONArray helpers
1236+
1237+public extension JSON {
1238+ /// Returns an `Array` containing the results of mapping `transform` over `array`.
1239+ ///
1240+ /// If `transform` throws a `JSONError`, the error will be modified to include the index
1241+ /// of the element that caused the error.
1242+ ///
1243+ /// - Parameter array: The `JSONArray` to map over.
1244+ /// - Parameter transform: A block that is called once for each element of `array`.
1245+ /// - Returns: An array with the results of mapping `transform` over `array`.
1246+ /// - Throws: Rethrows any error thrown by `transform`.
1247+ /// - Complexity: O(*N*).
1248+ static func map<T>(_ array: JSONArray, _ transform: (JSON) throws -> T) rethrows -> [T] {
1249+ return try array.enumerated().map({ i, elt in try scoped(i, { try transform(elt) }) })
1250+ }
1251+
1252+ /// Returns an `Array` containing the non-`nil` results of mapping `transform` over `array`.
1253+ ///
1254+ /// If `transform` throws a `JSONError`, the error will be modified to include the index
1255+ /// of the element that caused the error.
1256+ ///
1257+ /// - Parameter array: The `JSONArray` to map over.
1258+ /// - Parameter transform: A block that is called once for each element of `array`.
1259+ /// - Returns: An array with the non-`nil` results of mapping `transform` over `array`.
1260+ /// - Throws: Rethrows any error thrown by `transform`.
1261+ /// - Complexity: O(*N*).
1262+ static func flatMap<T>(_ array: JSONArray, _ transform: (JSON) throws -> T?) rethrows -> [T] {
1263+ return try array.enumerated().flatMap({ i, elt in try scoped(i, { try transform(elt) }) })
1264+ }
1265+
1266+ /// Returns an `Array` containing the concatenated results of mapping `transform` over `array`.
1267+ ///
1268+ /// If `transform` throws a `JSONError`, the error will be modified to include the index
1269+ /// of the element that caused the error.
1270+ ///
1271+ /// - Parameter array: The `JSONArray` to map over.
1272+ /// - Parameter transform: A block that is called once for each element of `array`.
1273+ /// - Returns: An array with the concatenated results of mapping `transform` over `array`.
1274+ /// - Throws: Rethrows any error thrown by `transform`.
1275+ /// - Complexity: O(*M* + *N*) where *M* is the length of `array` and *N* is the length of the result.
1276+ static func flatMap<S: Sequence>(_ array: JSONArray, _ transform: (JSON) throws -> S) rethrows -> [S.Iterator.Element] {
1277+ return try array.enumerated().flatMap({ (i, elt) in
1278+ return try scoped(i, { try transform(elt) })
1279+ })
1280+ }
1281+}
1282+
1283+public extension JSON {
1284+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1285+ /// containing the results of mapping `transform` over the value.
1286+ ///
1287+ /// - Note: This method is equivalent to `getArray(key, { try JSON.map($0, transform) })`.
1288+ ///
1289+ /// - Parameter key: The key to subscript the receiver with.
1290+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1291+ /// - Returns: An array with the results of mapping `transform` over the array.
1292+ /// - Throws: `JSONError` if the receiver is not an object, `key` does not exist, or the value
1293+ /// is not an array. Also rethrows any error thrown by `transform`.
1294+ /// - Complexity: O(*N*).
1295+ func mapArray<T>(_ key: String, _ transform: (JSON) throws -> T) throws -> [T] {
1296+ return try getArray(key, { try JSON.map($0, transform) })
1297+ }
1298+
1299+ /// Subscripts the receiver with `index`, converts the value to an array, and returns an `Array`
1300+ /// containing the results of mapping `transform` over the value.
1301+ ///
1302+ /// - Note: This method is equivalent to `getArray(index, { try JSON.map($0, transform) })`.
1303+ ///
1304+ /// - Parameter index: The index to subscript the receiver with.
1305+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1306+ /// - Returns: An array with the results of mapping `transform` over the array.
1307+ /// - Throws: `JSONError` if the receiver is not an array, `index` is out of bounds, or the
1308+ /// value is not an array. Also rethrows any error thrown by `transform`.
1309+ /// - Complexity: O(*N*).
1310+ func mapArray<T>(_ index: Int, _ transform: (JSON) throws -> T) throws -> [T] {
1311+ return try getArray(index, { try JSON.map($0, transform) })
1312+ }
1313+
1314+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1315+ /// containing the results of mapping `transform` over the value.
1316+ ///
1317+ /// Returns `nil` if `key` doesn't exist or the value is `null`.
1318+ ///
1319+ /// - Note: This method is equivalent to `getArrayOrNil(key, { try JSON.map($0, transform) })`.
1320+ ///
1321+ /// - Parameter key: The key to subscript the receiver with.
1322+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1323+ /// - Returns: An array with the results of mapping `transform` over the array, or `nil` if
1324+ /// `key` does not exist or the value is `null`.
1325+ /// - Throws: `JSONError` if the receiver is not an object or `key` exists but the value is not
1326+ /// an array or `null`. Also rethrows any error thrown by `transform`.
1327+ /// - Complexity: O(*N*).
1328+ func mapArrayOrNil<T>(_ key: String, _ transform: (JSON) throws -> T) throws -> [T]? {
1329+ return try getArrayOrNil(key, { try JSON.map($0, transform) })
1330+ }
1331+
1332+ /// Subscripts the receiver with `index`, converts the value to an array, and returns an `Array`
1333+ /// containing the results of mapping `transform` over the value.
1334+ ///
1335+ /// Returns `nil` if `index` is out of bounds or the value is `null`.
1336+ ///
1337+ /// - Note: This method is equivalent to `getArrayOrNil(index, { try JSON.map($0, transform) })`.
1338+ ///
1339+ /// - Parameter index: The index to subscript the receiver with.
1340+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1341+ /// - Returns: An array with the results of mapping `transform` over the array, or `nil` if
1342+ /// `index` is out of bounds or the value is `null`.
1343+ /// - Throws: `JSONError` if the receiver is not an object or the subscript value is not an
1344+ /// array or `null`. Also rethrows any error thrown by `transform`.
1345+ /// - Complexity: O(*N*).
1346+ func mapArrayOrNil<T>(_ index: Int, _ transform: (JSON) throws -> T) throws -> [T]? {
1347+ return try getArrayOrNil(index, { try JSON.map($0, transform) })
1348+ }
1349+
1350+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1351+ /// containing the non-`nil` results of mapping `transform` over the value.
1352+ ///
1353+ /// - Note: This method is equivalent to `getArray(key, { try JSON.flatMap($0, transform) })`.
1354+ ///
1355+ /// - Parameter key: The key to subscript the receiver with.
1356+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1357+ /// - Returns: An array with the non-`nil` results of mapping `transform` over the array.
1358+ /// - Throws: `JSONError` if the receiver is not an object, `key` does not exist, or the value
1359+ /// is not an array. Also rethrows any error thrown by `transform`.
1360+ /// - Complexity: O(*N*).
1361+ func flatMapArray<T>(_ key: String, _ transform: (JSON) throws -> T?) throws -> [T] {
1362+ return try getArray(key, { try JSON.flatMap($0, transform) })
1363+ }
1364+
1365+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1366+ /// containing the concatenated results of mapping `transform` over the value.
1367+ ///
1368+ /// - Note: This method is equivalent to `getArray(key, { try JSON.flatMap($0, transform) })`.
1369+ ///
1370+ /// - Parameter key: The key to subscript the receiver with.
1371+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1372+ /// - Returns: An array with the concatenated results of mapping `transform` over the array.
1373+ /// - Throws: `JSONError` if the receiver is not an object, `key` does not exist, or the value
1374+ /// is not an array. Also rethrows any error thrown by `transform`.
1375+ /// - Complexity: O(*M* + *N*) where *M* is the length of `array` and *N* is the length of the result.
1376+ func flatMapArray<S: Sequence>(_ key: String, _ transform: (JSON) throws -> S) throws -> [S.Iterator.Element] {
1377+ return try getArray(key, { try JSON.flatMap($0, transform) })
1378+ }
1379+
1380+ /// Subscripts the receiver with `index`, converts the value to an array, and returns an `Array`
1381+ /// containing the non-`nil` results of mapping `transform` over the value.
1382+ ///
1383+ /// - Note: This method is equivalent to `getArray(index, { try JSON.flatMap($0, transform) })`.
1384+ ///
1385+ /// - Parameter index: The index to subscript the receiver with.
1386+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1387+ /// - Returns: An array with the non-`nil` results of mapping `transform` over the array.
1388+ /// - Throws: `JSONError` if the receiver is not an array, `index` is out of bounds, or the
1389+ /// value is not an array. Also rethrows any error thrown by `transform`.
1390+ /// - Complexity: O(*N*).
1391+ func flatMapArray<T>(_ index: Int, _ transform: (JSON) throws -> T?) throws -> [T] {
1392+ return try getArray(index, { try JSON.flatMap($0, transform) })
1393+ }
1394+
1395+ /// Subscripts the receiver with `index`, converts the value to an array, and returns an `Array`
1396+ /// containing the concatenated results of mapping `transform` over the value.
1397+ ///
1398+ /// - Note: This method is equivalent to `getArray(index, { try JSON.flatMap($0, transform) })`.
1399+ ///
1400+ /// - Parameter index: The index to subscript the receiver with.
1401+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1402+ /// - Returns: An array with the concatenated results of mapping `transform` over the array.
1403+ /// - Throws: `JSONError` if the receiver is not an array, `index` is out of bounds, or the
1404+ /// value is not an array. Also rethrows any error thrown by `transform`.
1405+ /// - Complexity: O(*M* + *N*) where *M* is the length of `array` and *N* is the length of the result.
1406+ func flatMapArray<S: Sequence>(_ index: Int, _ transform: (JSON) throws -> S) throws -> [S.Iterator.Element] {
1407+ return try getArray(index, { try JSON.flatMap($0, transform) })
1408+ }
1409+
1410+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1411+ /// containing the non-`nil` results of mapping `transform` over the value.
1412+ ///
1413+ /// Returns `nil` if `key` doesn't exist or the value is `null`.
1414+ ///
1415+ /// - Note: This method is equivalent to `getArrayOrNil(key, { try JSON.flatMap($0, transform) })`.
1416+ ///
1417+ /// - Parameter key: The key to subscript the receiver with.
1418+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1419+ /// - Returns: An array with the non-`nil` results of mapping `transform` over the array, or
1420+ /// `nil` if `key` does not exist or the value is `null`.
1421+ /// - Throws: `JSONError` if the receiver is not an object or the value is not an array or
1422+ /// `null`. Also rethrows any error thrown by `transform`.
1423+ /// - Complexity: O(*N*).
1424+ func flatMapArrayOrNil<T>(_ key: String, _ transform: (JSON) throws -> T?) throws -> [T]? {
1425+ return try getArrayOrNil(key, { try JSON.flatMap($0, transform) })
1426+ }
1427+
1428+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1429+ /// containing the concatenated results of mapping `transform` over the value.
1430+ ///
1431+ /// Returns `nil` if `key` doesn't exist or the value is `null`.
1432+ ///
1433+ /// - Note: This method is equivalent to `getArrayOrNil(key, { try JSON.flatMap($0, transform) })`.
1434+ ///
1435+ /// - Parameter key: The key to subscript the receiver with.
1436+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1437+ /// - Returns: An array with the concatenated results of mapping `transform` over the array,
1438+ /// or `nil` if `key` does not exist or the value is `null`.
1439+ /// - Throws: `JSONError` if the receiver is not an object or the value is not an array or
1440+ /// `null`. Also rethrows any error thrown by `transform`.
1441+ /// - Complexity: O(*M* + *N*) where *M* is the length of `array` and *N* is the length of the result.
1442+ func flatMapArrayOrNil<S: Sequence>(_ key: String, _ transform: (JSON) throws -> S) throws -> [S.Iterator.Element]? {
1443+ return try getArrayOrNil(key, { try JSON.flatMap($0, transform) })
1444+ }
1445+
1446+ /// Subscripts the receiver with `index`, converts the value to an array, and returns an `Array`
1447+ /// containing the non-`nil` results of mapping `transform` over the value.
1448+ ///
1449+ /// Returns `nil` if `index` is out of bounds or the value is `null`.
1450+ ///
1451+ /// - Note: This method is equivalent to `getArrayOrNil(index, { try JSON.flatMap($0, transform) })`.
1452+ ///
1453+ /// - Parameter index: The index to subscript the receiver with.
1454+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1455+ /// - Returns: An array with the non-`nil` results of mapping `transform` over the array, or
1456+ /// `nil` if `index` is out of bounds or the value is `null`.
1457+ /// - Throws: `JSONError` if the receiver is not an array or the value is not an array or
1458+ /// `null`. Also rethrows any error thrown by `transform`.
1459+ /// - Complexity: O(*N*).
1460+ func flatMapArrayOrNil<T>(_ index: Int, _ transform: (JSON) throws -> T?) throws -> [T]? {
1461+ return try getArrayOrNil(index, { try JSON.flatMap($0, transform) })
1462+ }
1463+
1464+ /// Subscripts the receiver with `index`, converts the value to an array, and returns an `Array`
1465+ /// containing the concatenated results of mapping `transform` over the value.
1466+ ///
1467+ /// Returns `nil` if `index` is out of bounds or the value is `null`.
1468+ ///
1469+ /// - Note: This method is equivalent to `getArrayOrNil(index, { try JSON.flatMap($0, transform) })`.
1470+ ///
1471+ /// - Parameter index: The index to subscript the receiver with.
1472+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1473+ /// - Returns: An array with the concatenated results of mapping `transform` over the array,
1474+ /// or `nil` if `index` is out of bounds or the value is `null`.
1475+ /// - Throws: `JSONError` if the receiver is not an array or the value is not an array or
1476+ /// `null`. Also rethrows any error thrown by `transform`.
1477+ /// - Complexity: O(*M* + *N*) where *M* is the length of `array` and *N* is the length of the result.
1478+ func flatMapArrayOrNil<S: Sequence>(_ index: Int, _ transform: (JSON) throws -> S) throws -> [S.Iterator.Element]? {
1479+ return try getArrayOrNil(index, { try JSON.flatMap($0, transform) })
1480+ }
1481+}
1482+
1483+public extension JSONObject {
1484+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1485+ /// containing the results of mapping `transform` over the value.
1486+ ///
1487+ /// - Note: This method is equivalent to `getArray(key, { try JSON.map($0, transform) })`.
1488+ ///
1489+ /// - Parameter key: The key to subscript the receiver with.
1490+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1491+ /// - Returns: An array with the results of mapping `transform` over the array.
1492+ /// - Throws: `JSONError` if `key` does not exist or the value is not an array.
1493+ /// Also rethrows any error thrown by `transform`.
1494+ /// - Complexity: O(*N*).
1495+ func mapArray<T>(_ key: String, _ transform: (JSON) throws -> T) throws -> [T] {
1496+ return try getArray(key, { try JSON.map($0, transform) })
1497+ }
1498+
1499+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1500+ /// containing the results of mapping `transform` over the value.
1501+ ///
1502+ /// Returns `nil` if `key` doesn't exist or the value is `null`.
1503+ ///
1504+ /// - Note: This method is equivalent to `getArrayOrNil(key, { try JSON.map($0, transform) })`.
1505+ ///
1506+ /// - Parameter key: The key to subscript the receiver with.
1507+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1508+ /// - Returns: An array with the results of mapping `transform` over the array, or `nil` if
1509+ /// `key` does not exist or the value is `null`.
1510+ /// - Throws: `JSONError` if `key` exists but the value is not an array or `null`.
1511+ /// Also rethrows any error thrown by `transform`.
1512+ /// - Complexity: O(*N*).
1513+ func mapArrayOrNil<T>(_ key: String, _ transform: (JSON) throws -> T) throws -> [T]? {
1514+ return try getArrayOrNil(key, { try JSON.map($0, transform) })
1515+ }
1516+
1517+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1518+ /// containing the non-`nil` results of mapping `transform` over the value.
1519+ ///
1520+ /// - Note: This method is equivalent to `getArray(key, { try JSON.flatMap($0, transform) })`.
1521+ ///
1522+ /// - Parameter key: The key to subscript the receiver with.
1523+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1524+ /// - Returns: An array with the non-`nil` results of mapping `transform` over the array.
1525+ /// - Throws: `JSONError` if `key` does not exist or the value is not an array.
1526+ /// Also rethrows any error thrown by `transform`.
1527+ /// - Complexity: O(*N*).
1528+ func flatMapArray<T>(_ key: String, _ transform: (JSON) throws -> T?) throws -> [T] {
1529+ return try getArray(key, { try JSON.flatMap($0, transform) })
1530+ }
1531+
1532+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1533+ /// containing the concatenated results of mapping `transform` over the value.
1534+ ///
1535+ /// - Note: This method is equivalent to `getArray(key, { try JSON.flatMap($0, transform) })`.
1536+ ///
1537+ /// - Parameter key: The key to subscript the receiver with.
1538+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1539+ /// - Returns: An array with the concatenated results of mapping `transform` over the array.
1540+ /// - Throws: `JSONError` if `key` does not exist or the value is not an array.
1541+ /// Also rethrows any error thrown by `transform`.
1542+ /// - Complexity: O(*M* + *N*) where *M* is the length of `array` and *N* is the length of the result.
1543+ func flatMapArray<S: Sequence>(_ key: String, _ transform: (JSON) throws -> S) throws -> [S.Iterator.Element] {
1544+ return try getArray(key, { try JSON.flatMap($0, transform) })
1545+ }
1546+
1547+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1548+ /// containing the non-`nil` results of mapping `transform` over the value.
1549+ ///
1550+ /// Returns `nil` if `key` doesn't exist or the value is `null`.
1551+ ///
1552+ /// - Note: This method is equivalent to `getArrayOrNil(key, { try JSON.flatMap($0, transform) })`.
1553+ ///
1554+ /// - Parameter key: The key to subscript the receiver with.
1555+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1556+ /// - Returns: An array with the non-`nil` results of mapping `transform` over the array, or
1557+ /// `nil` if `key` does not exist or the value is `null`.
1558+ /// - Throws: `JSONError` if `key` exists but the value is not an array or `null`.
1559+ /// Also rethrows any error thrown by `transform`.
1560+ /// - Complexity: O(*N*).
1561+ func flatMapArrayOrNil<T>(_ key: String, _ transform: (JSON) throws -> T?) throws -> [T]? {
1562+ return try getArrayOrNil(key, { try JSON.flatMap($0, transform) })
1563+ }
1564+
1565+ /// Subscripts the receiver with `key`, converts the value to an array, and returns an `Array`
1566+ /// containing the concatenated results of mapping `transform` over the value.
1567+ ///
1568+ /// Returns `nil` if `key` doesn't exist or the value is `null`.
1569+ ///
1570+ /// - Note: This method is equivalent to `getArrayOrNil(key, { try JSON.flatMap($0, transform) })`.
1571+ ///
1572+ /// - Parameter key: The key to subscript the receiver with.
1573+ /// - Parameter transform: A block that is called once for each element of the resulting array.
1574+ /// - Returns: An array with the concatenated results of mapping `transform` over the array,
1575+ /// or `nil` if `key` does not exist or the value is `null`.
1576+ /// - Throws: `JSONError` if `key` exists but the value is not an array or `null`.
1577+ /// Also rethrows any error thrown by `transform`.
1578+ /// - Complexity: O(*M* + *N*) where *M* is the length of `array` and *N* is the length of the result.
1579+ func flatMapArrayOrNil<S: Sequence>(_ key: String, _ transform: (JSON) throws -> S) throws -> [S.Iterator.Element]? {
1580+ return try getArrayOrNil(key, { try JSON.flatMap($0, transform) })
1581+ }
1582+}
1583+
1584+// MARK: -
1585+
1586+internal func getRequired(_ dict: JSONObject, key: String, type: JSONError.JSONType) throws -> JSON {
1587+ guard let value = dict[key] else { throw JSONError.missingOrInvalidType(path: key, expected: .required(type), actual: nil) }
1588+ return value
1589+}
1590+
1591+internal func getRequired(_ ary: JSONArray, index: Int, type: JSONError.JSONType) throws -> JSON {
1592+ guard let value = ary[safe: index] else { throw JSONError.missingOrInvalidType(path: "[\(index)]", expected: .required(type), actual: nil) }
1593+ return value
1594+}
1595+
1596+@inline(__always)
1597+internal func scoped<T>(_ key: String, _ f: () throws -> T) rethrows -> T {
1598+ do {
1599+ return try f()
1600+ } catch let error as JSONError {
1601+ throw error.withPrefix(key)
1602+ }
1603+}
1604+
1605+@inline(__always)
1606+internal func scoped<T>(_ index: Int, _ f: () throws -> T) rethrows -> T {
1607+ do {
1608+ return try f()
1609+ } catch let error as JSONError {
1610+ throw error.withPrefix("[\(index)]")
1611+ }
1612+}
1613+
1614+internal extension ContiguousArray {
1615+ subscript(safe index: Int) -> Element? {
1616+ guard index >= startIndex && index < endIndex else { return nil }
1617+ return self[index]
1618+ }
1619+}