Skip to content

Commit

Permalink
renamed Value to AnyValue. Added subscripts
Browse files Browse the repository at this point in the history
  • Loading branch information
ypopovych committed Aug 30, 2023
1 parent 5da9e27 commit a3d3c4f
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 173 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ import Serializable

let json = """
{
"message": "Hello, World!"
"message": { "text": "Hello, World!" }
}
""".data(using: .utf8)!

let value = try! JSONDecoder().decode(Value.self, from: json)
let value = try! JSONDecoder().decode(AnyValue.self, from: json)

print("Message:", value.object!["message"].string!)
print("Message:", value["message.text"]!.string!)
```

## Author
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Value.swift
// AnyValue.swift
// Serializable
//
// Created by Yehor Popovych on 3/28/19.
Expand All @@ -20,7 +20,7 @@

import Foundation

public enum Value: Codable, Equatable, Hashable {
public enum AnyValue: Codable, Equatable, Hashable {
case `nil`
case bool(Bool)
case int(Int64)
Expand All @@ -31,16 +31,16 @@ public enum Value: Codable, Equatable, Hashable {
case array(Array<Self>)
case object(Dictionary<String, Self>)

public init(_ value: ValueConvertible) {
self = value.serializable
public init(_ value: AnyValueConvertible) {
self = value.anyValue
}

public init(_ array: Array<ValueConvertible>) {
self = .array(array.map { $0.serializable })
public init(_ array: Array<AnyValueConvertible>) {
self = .array(array.map { $0.anyValue })
}

public init(_ dict: Dictionary<String, ValueConvertible>) {
self = .object(dict.mapValues{ $0.serializable })
public init(_ dict: Dictionary<String, AnyValueConvertible>) {
self = .object(dict.mapValues{ $0.anyValue })
}

public init(from decoder: Decoder) throws {
Expand Down Expand Up @@ -88,46 +88,51 @@ public enum Value: Codable, Equatable, Hashable {
}
}

public enum Error: Swift.Error {
case notInitializable(Value)
public struct NotInitializable: Error {
public let type: String
public let from: AnyValue
public init(type: String, from: AnyValue) {
self.type = type
self.from = from
}
}

public struct DataDecodingStrategy {
public let decode: (ValueConvertible) throws -> Data
public let decode: (AnyValueConvertible) throws -> Data

public init(decode: @escaping (ValueConvertible) throws -> Data) {
public init(decode: @escaping (AnyValueConvertible) throws -> Data) {
self.decode = decode
}
}

public struct DateDecodingStrategy {
public let decode: (ValueConvertible) throws -> Date
public let decode: (AnyValueConvertible) throws -> Date

public init(decode: @escaping (ValueConvertible) throws -> Date) {
public init(decode: @escaping (AnyValueConvertible) throws -> Date) {
self.decode = decode
}
}
}

extension Value: ValueRepresentable {
public init(serializable: Serializable.Value) throws {
self = serializable
extension AnyValue: AnyValueRepresentable {
public init(anyValue: AnyValue) throws {
self = anyValue
}

public var serializable: Serializable.Value { self }
public var anyValue: AnyValue { self }
}

extension Value: CustomDebugStringConvertible {
extension AnyValue: CustomDebugStringConvertible {
public var debugDescription: String {
switch self {
case .nil: return "null"
case .int(let int): return "\(int)"
case .float(let num): return "\(num)"
case .bool(let bool): return bool ? "true" : "false"
case .date(let date): return "\"\(DateFormatter.iso8601millis.string(from: date))\""
case .date(let date): return "\"\(DateFormatter.sz_iso8601millis.string(from: date))\""
case .string(let str): return "\"\(str)\""
case .bytes(let data):
return "\"\(JSONEncoder.DataEncodingStrategy.srv_encodeHex(data: data, prefix: false))\""
return "\"\(JSONEncoder.DataEncodingStrategy.sz_encodeHex(data: data, prefix: false))\""
case .array(let arr):
return "[\(arr.map{String(describing: $0)}.joined(separator: ", "))]"
case .object(let obj):
Expand Down
26 changes: 13 additions & 13 deletions Sources/Serializable/DataDecodingStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,31 @@

import Foundation

extension Value.DataDecodingStrategy {
extension AnyValue.DataDecodingStrategy {
public static let deferredToData = Self { input in
return try Data(serializable: input.serializable)
return try Data(anyValue: input.anyValue)
}

public static let base64 = Self { input in
let serializable = input.serializable
if case .bytes(let data) = serializable { return data }
guard case .string(let string) = serializable else {
throw Value.Error.notInitializable(serializable)
let value = input.anyValue
if case .bytes(let data) = value { return data }
guard case .string(let string) = value else {
throw AnyValue.NotInitializable(type: "Data", from: value)
}
guard let data = Data(base64Encoded: string) else {
throw Value.Error.notInitializable(serializable)
throw AnyValue.NotInitializable(type: "Data", from: value)
}
return data
}

public static let hex = Self { input in
let serializable = input.serializable
if case .bytes(let data) = serializable { return data }
guard case .string(let string) = serializable else {
throw Value.Error.notInitializable(serializable)
let value = input.anyValue
if case .bytes(let data) = value { return data }
guard case .string(let string) = value else {
throw AnyValue.NotInitializable(type: "Data", from: value)
}
guard let data = string.data(using: .ascii), data.count % 2 == 0 else {
throw Value.Error.notInitializable(serializable)
throw AnyValue.NotInitializable(type: "Data", from: value)
}
let prefix = string.hasPrefix("0x") ? 2 : 0
let parsed: Data = try data.withUnsafeBytes() { hex in
Expand All @@ -58,7 +58,7 @@ extension Value.DataDecodingStrategy {
case let c where c >= 65 && c <= 70: v = c - 55
case let c where c >= 97: v = c - 87
default:
throw Value.Error.notInitializable(serializable)
throw AnyValue.NotInitializable(type: "Data", from: value)
}
if let val = current {
result.append(val << 4 | v)
Expand Down
20 changes: 10 additions & 10 deletions Sources/Serializable/DateDecodingStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,45 @@

import Foundation

extension Value.DateDecodingStrategy {
extension AnyValue.DateDecodingStrategy {
/// Return Date only if parser can parse it.
public static let deferredToDate = Self { input in
return try Date(serializable: input.serializable)
return try Date(anyValue: input.anyValue)
}

/// Decode the `Date` as a ISO8601 string with milliseconds.
public static let iso8601millis = Self { input in
switch input.serializable {
switch input.anyValue {
case .date(let date): return date
case .string(let str):
guard let date = DateFormatter.iso8601millis.date(from: str) else {
throw Value.Error.notInitializable(input.serializable)
guard let date = DateFormatter.sz_iso8601millis.date(from: str) else {
throw AnyValue.NotInitializable(type: "Date", from: input.anyValue)
}
return date
default:
throw Value.Error.notInitializable(input.serializable)
throw AnyValue.NotInitializable(type: "Date", from: input.anyValue)
}
}

/// Decode the `Date` as a UNIX timestamp from a JSON number.
public static let secondsSince1970 = Self { input in
switch input.serializable {
switch input.anyValue {
case .date(let date): return date
case .int(let int): return Date(timeIntervalSince1970: TimeInterval(int))
case .float(let float): return Date(timeIntervalSince1970: TimeInterval(float))
default:
throw Value.Error.notInitializable(input.serializable)
throw AnyValue.NotInitializable(type: "Date", from: input.anyValue)
}
}

/// Decode the `Date` as UNIX millisecond timestamp from a JSON number.
public static let millisecondsSince1970 = Self { input in
switch input.serializable {
switch input.anyValue {
case .date(let date): return date
case .int(let int): return Date(timeIntervalSince1970: TimeInterval(int) / 1000.0)
case .float(let float): return Date(timeIntervalSince1970: TimeInterval(float) / 1000.0)
default:
throw Value.Error.notInitializable(input.serializable)
throw AnyValue.NotInitializable(type: "Date", from: input.anyValue)
}
}
}
Loading

0 comments on commit a3d3c4f

Please sign in to comment.