diff --git a/README.md b/README.md index 921b651..8557d59 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted * Split `JSON.Encoder.encodeAs*` and `JSON.Decoder.decode` methods into overload pairs where one takes `options:` and the other doesn't. This makes it easier to replace function references to `JSONEncoder`/`JSONDecoder` methods with the equivalents from PMJSON. * Add conformance to Combine's `TopLevelEncoder` and `TopLevelDecoder`, using `Data` as the input/output type. This means that `JSON.Encoder.encode(_:)` is now marked as deprecated instead of unavailable. * Rename `JSON.flatMap*` and `JSONObject.flatMap*` methods to `.compactMap*` instead when the transformation returns an optional. ([#28][]) +* Mark a lot of methods as `@inlinable`. [#25]: https://github.com/postmates/PMJSON/issues/25 "GitHub: JSONObject.ns should return [String: Any]" [#28]: https://github.com/postmates/PMJSON/issues/28 "GitHub: Rename JSON.flatMap to JSON.compactMap" diff --git a/Sources/Accessors.swift b/Sources/Accessors.swift index 25bd11c..c725340 100644 --- a/Sources/Accessors.swift +++ b/Sources/Accessors.swift @@ -17,6 +17,7 @@ import struct Foundation.Decimal public extension JSON { /// Returns `true` iff the receiver is `.null`. + @inlinable var isNull: Bool { switch self { case .null: return true @@ -25,6 +26,7 @@ public extension JSON { } /// Returns `true` iff the receiver is `.bool`. + @inlinable var isBool: Bool { switch self { case .bool: return true @@ -33,6 +35,7 @@ public extension JSON { } /// Returns `true` iff the receiver is `.string`. + @inlinable var isString: Bool { switch self { case .string: return true @@ -41,6 +44,7 @@ public extension JSON { } /// Returns `true` iff the receiver is `.int64`. + @inlinable var isInt64: Bool { switch self { case .int64: return true @@ -49,6 +53,7 @@ public extension JSON { } /// Returns `true` iff the receiver is `.double`. + @inlinable var isDouble: Bool { switch self { case .double: return true @@ -57,6 +62,7 @@ public extension JSON { } /// Returns `true` iff the receiver is a `.decimal`. + @inlinable var isDecimal: Bool { switch self { case .decimal: return true @@ -65,6 +71,7 @@ public extension JSON { } /// Returns `true` iff the receiver is `.int64`, `.double`, or `.decimal`. + @inlinable var isNumber: Bool { switch self { case .int64, .double, .decimal: return true @@ -73,6 +80,7 @@ public extension JSON { } /// Returns `true` iff the receiver is `.object`. + @inlinable var isObject: Bool { switch self { case .object: return true @@ -81,6 +89,7 @@ public extension JSON { } /// Returns `true` iff the receiver is `.array`. + @inlinable var isArray: Bool { switch self { case .array: return true @@ -94,6 +103,7 @@ public extension JSON { /// /// When setting, replaces the receiver with the given boolean value, or with /// null if the value is `nil`. + @inlinable var bool: Bool? { get { switch self { @@ -110,6 +120,7 @@ public extension JSON { /// /// When setting, replaces the receiver with the given string value, or with /// null if the value is `nil`. + @inlinable var string: String? { get { switch self { @@ -129,6 +140,7 @@ public extension JSON { /// /// When setting, replaces the receiver with the given integral value, or with /// null if the value is `nil`. + @inlinable var int64: Int64? { get { switch self { @@ -150,6 +162,7 @@ public extension JSON { /// /// When setting, replaces the receiver with the given integral value, or with /// null if the value is `nil`. + @inlinable var int: Int? { get { guard let value = self.int64 else { return nil} @@ -167,6 +180,7 @@ public extension JSON { /// /// When setting, replaces the receiver with the given double value, or with /// null if the value is `nil`. + @inlinable var double: Double? { get { switch self { @@ -187,6 +201,7 @@ public extension JSON { /// /// When setting, replaces the receiver with the given object value, or with /// null if the value is `nil`. + @inlinable var object: JSONObject? { get { switch self { @@ -203,6 +218,7 @@ public extension JSON { /// /// When setting, replaces the receiver with the given array value, or with /// null if the value is `nil`. + @inlinable var array: JSONArray? { get { switch self { @@ -219,6 +235,7 @@ public extension JSON { public extension JSON { /// Returns the string value if the receiver is `.string`, coerces the value to a string if /// the receiver is `.bool`, `.null`, `.int64`, `.double`, or `.decimal, or otherwise returns `nil`. + @inlinable var asString: String? { return try? toString() } @@ -230,6 +247,7 @@ public extension JSON { /// in 64 bits, `nil` is returned. /// If the receiver is `.string`, it must parse fully as an integral or floating-point number. /// If it parses as a floating-point number, it is truncated. If it does not fit in 64 bits, `nil` is returned. + @inlinable var asInt64: Int64? { return try? toInt64() } @@ -241,6 +259,7 @@ public extension JSON { /// in an `Int`, `nil` is returned. /// If the receiver is `.string`, it must parse fully as an integral or floating-point number. /// If it parses as a floating-point number, it is truncated. If it does not fit in an `Int`, `nil` is returned. + @inlinable var asInt: Int? { return try? toInt() } @@ -248,6 +267,7 @@ public extension JSON { /// Returns the double value if the receiver is `.int64`, `.double`, or `.decimal`, coerces the value /// if the receiver is `.string`, otherwise returns `nil`. /// If the receiver is `.string`, it must parse fully as a floating-point number. + @inlinable var asDouble: Double? { return try? toDouble() } @@ -256,12 +276,14 @@ public extension JSON { public extension JSON { /// If the receiver is `.object`, returns the result of subscripting the object. /// Otherwise, returns `nil`. + @inlinable subscript(key: String) -> JSON? { return self.object?[key] } /// If the receiver is `.array` and the index is in range of the array, returns the result of subscripting the array. /// Otherwise returns `nil`. + @inlinable subscript(index: Int) -> JSON? { guard let ary = self.array else { return nil } guard index >= ary.startIndex && index < ary.endIndex else { return nil } @@ -269,6 +291,7 @@ public extension JSON { } } +@usableFromInline internal func convertDoubleToInt64(_ d: Double) -> Int64? { // Int64(Double(Int64.max)) asserts because it interprets it as out of bounds. // Int64(Double(Int64.min)) works just fine. @@ -278,6 +301,7 @@ internal func convertDoubleToInt64(_ d: Double) -> Int64? { return Int64(d) } +@usableFromInline internal func convertDecimalToInt64(_ d: Decimal) -> Int64? { if d > Int64.maxDecimal || d < Int64.minDecimal { return nil @@ -286,6 +310,7 @@ internal func convertDecimalToInt64(_ d: Decimal) -> Int64? { return NSDecimalNumber(decimal: d).int64Value } +@usableFromInline internal func convertDecimalToUInt64(_ d: Decimal) -> UInt64? { if d > UInt64.maxDecimal || d < UInt64.minDecimal { return nil diff --git a/Sources/DecimalNumber.swift b/Sources/DecimalNumber.swift index d366efe..1e3ac44 100644 --- a/Sources/DecimalNumber.swift +++ b/Sources/DecimalNumber.swift @@ -466,6 +466,7 @@ internal extension UInt64 { internal extension Decimal { // NB: As of Swift 3.0.1, Decimal(_: Double) can produce incorrect results (SR-3130) + @usableFromInline init(workaround value: Double) { self = NSNumber(value: value).decimalValue } diff --git a/Sources/JSON.swift b/Sources/JSON.swift index d70dc6d..957af7e 100644 --- a/Sources/JSON.swift +++ b/Sources/JSON.swift @@ -38,29 +38,37 @@ public enum JSON { case array(JSONArray) /// Initializes `self` as a boolean with the value `bool`. + @inlinable public init(_ bool: Bool) { self = .bool(bool) } /// Initializes `self` as a string with the value `str`. + @inlinable public init(_ str: String) { self = .string(str) } /// Initializes `self` as a 64-bit integer with the value `i`. + @inlinable public init(_ i: Int64) { self = .int64(i) } /// Initializes `self` as a double with the value `d`. + @inlinable public init(_ d: Double) { self = .double(d) } + /// Initializes `self` as a decimal with the value `d`. + @inlinable public init(_ d: Decimal) { self = .decimal(d) } /// Initializes `self` as an object with the value `obj`. + @inlinable public init(_ obj: JSONObject) { self = .object(obj) } /// Initializes `self` as an array with the value `ary`. + @inlinable public init(_ ary: JSONArray) { self = .array(ary) } @@ -69,26 +77,31 @@ public enum JSON { // Convenience conversions. extension JSON { /// Returns a `JSON.int64` with the given value. + @inlinable public static func int(_ value: Int) -> JSON { return .int64(Int64(value)) } /// Initializes `self` as a 64-bit integer with the value `i`. + @inlinable public init(_ i: Int) { self = .int64(Int64(i)) } /// Initializes `self` as an array with the contents of the sequence `seq`. + @inlinable public init(_ seq: S) where S.Iterator.Element == JSON { self = .array(JSONArray(seq)) } /// Initializes `self` as an array with the contents of the sequence `seq`. + @inlinable public init(_ seq: S) where S.Iterator.Element == JSONObject { self = .array(JSONArray(seq.lazy.map(JSON.init))) } /// Initializes `self` as an array with the contents of the sequence `seq`. + @inlinable public init(_ seq: S) where S.Iterator.Element == JSONArray { self = .array(JSONArray(seq.lazy.map(JSON.init))) } @@ -97,6 +110,7 @@ extension JSON { public typealias JSONArray = ContiguousArray extension JSON: Equatable { + @inlinable public static func ==(lhs: JSON, rhs: JSON) -> Bool { switch (lhs, rhs) { case (.null, .null): return true @@ -119,10 +133,12 @@ extension JSON: Equatable { } extension JSON: TextOutputStreamable, CustomStringConvertible, CustomDebugStringConvertible { + @inlinable public func write(to target: inout Target) { JSON.encode(self, to: &target) } + @inlinable public var description: String { return JSON.encodeAsString(self) } @@ -139,42 +155,51 @@ extension JSON: TextOutputStreamable, CustomStringConvertible, CustomDebugString } extension JSON: ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral, ExpressibleByBooleanLiteral, ExpressibleByNilLiteral { + @inlinable public init(integerLiteral value: Int64) { self = .int64(value) } + @inlinable public init(floatLiteral value: Double) { self = .double(value) } + @inlinable public init(booleanLiteral value: Bool) { self = .bool(value) } + @inlinable public init(nilLiteral: ()) { self = .null } } extension JSON: ExpressibleByStringLiteral { + @inlinable public init(stringLiteral value: String) { self = .string(value) } + @inlinable public init(extendedGraphemeClusterLiteral value: String) { self = .string(value) } + @inlinable public init(unicodeScalarLiteral value: String) { self = .string(value) } } extension JSON: ExpressibleByArrayLiteral, ExpressibleByDictionaryLiteral { + @inlinable public init(arrayLiteral elements: JSON...) { self = .array(JSONArray(elements)) } + @inlinable public init(dictionaryLiteral elements: (String, JSON)...) { self = .object(JSONObject(elements)) } diff --git a/Sources/JSONObject.swift b/Sources/JSONObject.swift index 1423c39..f0a4ba1 100644 --- a/Sources/JSONObject.swift +++ b/Sources/JSONObject.swift @@ -43,6 +43,7 @@ public struct JSONObject { public fileprivate(set) var dictionary: [String: JSON] public subscript(key: String) -> JSON? { + @inlinable @inline(__always) get { return dictionary[key] } @@ -69,11 +70,13 @@ extension JSONObject: Collection { } /// Returns `true` iff `self` is empty. + @inlinable public var isEmpty: Bool { return dictionary.isEmpty } /// The number of entries in the object. + @inlinable public var count: Int { return dictionary.count } @@ -132,6 +135,7 @@ extension JSONObject { /// /// Keys appear in the same order as they occur as the `.0` member of key-value pairs in `self`. /// Each key in the result has a unique value. + @inlinable public var keys: LazyMapCollection { return lazy.map({ $0.0 }) } @@ -139,6 +143,7 @@ extension JSONObject { /// A collection containing just the values of `self`. /// /// Values appear in the same order as they occur as the `.1` member of key-value pairs in `self`. + @inlinable public var values: LazyMapCollection { return lazy.map({ $0.1 }) } @@ -189,16 +194,19 @@ extension JSONObject: ExpressibleByDictionaryLiteral { } /// Creates an object initialized with `elements`. + @inlinable public init(dictionaryLiteral elements: (String, JSON)...) { self.init(elements) } } extension JSONObject: TextOutputStreamable, CustomStringConvertible, CustomDebugStringConvertible { + @inlinable public func write(to target: inout Target) { JSON.encode(JSON(self), to: &target) } + @inlinable public var description: String { return JSON.encodeAsString(JSON(self)) } @@ -210,6 +218,7 @@ extension JSONObject: TextOutputStreamable, CustomStringConvertible, CustomDebug } extension JSONObject: Equatable { + @inlinable public static func ==(lhs: JSONObject, rhs: JSONObject) -> Bool { return lhs.dictionary == rhs.dictionary }