diff --git a/Sources/JavaScriptPersistence/Array (ext).swift b/Sources/JavaScriptPersistence/Array (ext).swift index 953d3ef..d44d6db 100644 --- a/Sources/JavaScriptPersistence/Array (ext).swift +++ b/Sources/JavaScriptPersistence/Array (ext).swift @@ -5,7 +5,7 @@ extension Array: ConvertibleToJSValue where Element: ConvertibleToJSValue { } extension Array: ConstructibleFromJSValue where Element: ConstructibleFromJSValue { @inlinable public static func construct(from value: JSValue) -> [Element]? { - guard case .object(let object) = value, object.isArray else { + guard case .object(let object) = value.storage, object.isArray else { return nil } diff --git a/Sources/JavaScriptPersistence/BinaryFloatingPoint (ext).swift b/Sources/JavaScriptPersistence/BinaryFloatingPoint (ext).swift index c581859..8c3c1d9 100644 --- a/Sources/JavaScriptPersistence/BinaryFloatingPoint (ext).swift +++ b/Sources/JavaScriptPersistence/BinaryFloatingPoint (ext).swift @@ -1,6 +1,6 @@ extension BinaryFloatingPoint where Self: ConstructibleFromJSValue { @inlinable public static func construct(from value: JSValue) -> Self? { - switch value { + switch value.storage { case .number(let value): return Self.init(value) case .bigInt(let value): diff --git a/Sources/JavaScriptPersistence/ConstructibleFromJSValue.swift b/Sources/JavaScriptPersistence/ConstructibleFromJSValue.swift index 3b43dd5..5603f28 100644 --- a/Sources/JavaScriptPersistence/ConstructibleFromJSValue.swift +++ b/Sources/JavaScriptPersistence/ConstructibleFromJSValue.swift @@ -3,7 +3,7 @@ public protocol ConstructibleFromJSValue { } extension ConstructibleFromJSValue where Self: SignedInteger { @inlinable public static func construct(from value: JSValue) -> Self? { - switch value { + switch value.storage { case .number(let value): .init(exactly: value) case .bigInt(let value): .init(exactly: value.int128) default: nil @@ -12,7 +12,7 @@ extension ConstructibleFromJSValue where Self: SignedInteger { } extension ConstructibleFromJSValue where Self: UnsignedInteger { @inlinable public static func construct(from value: JSValue) -> Self? { - switch value { + switch value.storage { case .number(let number): Self.init(exactly: number) case .bigInt(let bigInt): Self.init(exactly: bigInt.int128) default: nil diff --git a/Sources/JavaScriptPersistence/JSString.swift b/Sources/JavaScriptPersistence/JSString.swift index 1607e06..331dd53 100644 --- a/Sources/JavaScriptPersistence/JSString.swift +++ b/Sources/JavaScriptPersistence/JSString.swift @@ -18,7 +18,7 @@ extension JSString: ConvertibleToJSValue { } extension JSString: ConstructibleFromJSValue { @inlinable public static func construct(from value: JSValue) -> JSString? { - guard case .string(let string) = value else { + guard case .string(let string) = value.storage else { return nil } return string diff --git a/Sources/JavaScriptPersistence/JSValue.Storage.swift b/Sources/JavaScriptPersistence/JSValue.Storage.swift new file mode 100644 index 0000000..cf94a17 --- /dev/null +++ b/Sources/JavaScriptPersistence/JSValue.Storage.swift @@ -0,0 +1,12 @@ +extension JSValue { + @frozen @usableFromInline enum Storage { + case boolean(Bool) + case string(JSString) + case number(Double) + case object(JSObject) + case null + case undefined + case symbol(JSSymbol) + case bigInt(JSBigInt) + } +} diff --git a/Sources/JavaScriptPersistence/JSValue.swift b/Sources/JavaScriptPersistence/JSValue.swift index 756609c..117efab 100644 --- a/Sources/JavaScriptPersistence/JSValue.swift +++ b/Sources/JavaScriptPersistence/JSValue.swift @@ -1,18 +1,40 @@ import JSON -@frozen public enum JSValue { - case boolean(Bool) - case string(JSString) - case number(Double) - case object(JSObject) - case null - case undefined - case symbol(JSSymbol) - case bigInt(JSBigInt) +@frozen public struct JSValue { + @usableFromInline let storage: Storage + @inlinable init(storage: Storage) { + self.storage = storage + } +} +extension JSValue { + @inlinable public static func boolean(_ value: Bool) -> Self { + .init(storage: .boolean(value)) + } + @inlinable public static func string(_ value: JSString) -> Self { + .init(storage: .string(value)) + } + @inlinable public static func number(_ value: Double) -> Self { + .init(storage: .number(value)) + } + @inlinable public static func object(_ value: JSObject) -> Self { + .init(storage: .object(value)) + } + @inlinable public static var null: Self { + .init(storage: .null) + } + @inlinable public static var undefined: Self { + .init(storage: .undefined) + } + @inlinable public static func symbol(_ value: JSSymbol) -> Self { + .init(storage: .symbol(value)) + } + @inlinable public static func bigInt(_ value: JSBigInt) -> Self { + .init(storage: .bigInt(value)) + } } extension JSValue: JSONEncodable { public func encode(to json: inout JSON) { - switch self { + switch self.storage { case .null: (nil as Never?).encode(to: &json) case .boolean(let js): @@ -108,21 +130,23 @@ extension JSValue: ConvertibleToJSValue { @inlinable public var jsValue: JSValue { self } } extension JSValue { - @available( - *, unavailable, - message: "code that expects a numeric value should check for 'BigInt' as well" - ) @inlinable public var number: Double? { - guard case .number(let value) = self else { + @inlinable public var number: Double? { + guard case .number(let value) = self.storage else { return nil } return value } - @available( - *, unavailable, - message: "code that expects a numeric value should check for 'Double' as well" - ) @inlinable public var bigInt: JSBigInt? { - guard case .bigInt(let value) = self else { + @inlinable public var bigInt: JSBigInt? { + guard case .bigInt(let value) = self.storage else { + return nil + } + return value + } +} +extension JSValue { + @inlinable public var jsString: JSString? { + guard case .string(let value) = self.storage else { return nil } return value @@ -130,42 +154,42 @@ extension JSValue { } extension JSValue { @inlinable public var boolean: Bool? { - guard case .boolean(let value) = self else { + guard case .boolean(let value) = self.storage else { return nil } return value } @inlinable public var string: String? { - guard case .string(let value) = self else { + guard case .string(let value) = self.storage else { return nil } return value.string } @inlinable public var object: JSObject? { - guard case .object(let value) = self else { + guard case .object(let value) = self.storage else { return nil } return value } @inlinable public var symbol: JSSymbol? { - guard case .symbol(let value) = self else { + guard case .symbol(let value) = self.storage else { return nil } return value } @inlinable public var isNull: Bool { - guard case .null = self else { + guard case .null = self.storage else { return false } return true } @inlinable public var isUndefined: Bool { - guard case .undefined = self else { + guard case .undefined = self.storage else { return false } return true diff --git a/Sources/JavaScriptPersistence/Optional (ext).swift b/Sources/JavaScriptPersistence/Optional (ext).swift index 422ecfb..74aa5a4 100644 --- a/Sources/JavaScriptPersistence/Optional (ext).swift +++ b/Sources/JavaScriptPersistence/Optional (ext).swift @@ -1,6 +1,6 @@ extension Optional: ConstructibleFromJSValue where Wrapped: ConstructibleFromJSValue { @inlinable public static func construct(from value: JSValue) -> Self? { - switch value { + switch value.storage { case .null, .undefined: return .some(nil) default: