Sources/Confidence/ConfidenceValue.swift (209 lines of code) (raw):

import Foundation public typealias ConfidenceStruct = [String: ConfidenceValue] public class ConfidenceValue: Equatable, Codable, CustomStringConvertible { private let value: ConfidenceValueInternal public var description: String { return value.description } init(from networkValue: NetworkValue) { switch networkValue { case .boolean(let value): self.value = .boolean(value) case .string(let value): self.value = .string(value) case .number(let value): self.value = .double(value) case .list(let values): self.value = .list(values.map { value in ConfidenceValue(from: value).value }) case .structure(let map): self.value = .structure(map.fields.mapValues { entryValue in ConfidenceValue(from: entryValue).value }) case .null: self.value = .null } } public required init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() self.value = try container.decode(ConfidenceValueInternal.self) } public init(boolean: Bool) { self.value = .boolean(boolean) } public init(string: String) { self.value = .string(string) } public init(integer: Int) { self.value = .integer(integer) } public init(double: Double) { self.value = .double(double) } /// `date` should have at least precision to the "day". /// If a custom TimeZone is set for the input DateComponents, the internal serializers /// will convert the input to the local TimeZone before extracting the calendar day. public init(date: DateComponents) { self.value = .date(date) } /// If a custom TimeZone is set for the input Date, the internal serializers will convert /// the input to the local TimeZone (i.e. the local offset information is maintained /// rather than the one customly set in Date). public init(timestamp: Date) { self.value = .timestamp(timestamp) } public init(booleanList: [Bool]) { self.value = .list(booleanList.map { .boolean($0) }) } public init(stringList: [String]) { self.value = .list(stringList.map { .string($0) }) } internal init(list: [ConfidenceValue]) { self.value = .list(list.map { $0.value }) } public init(integerList: [Int]) { self.value = .list(integerList.map { .integer($0) }) } public init(doubleList: [Double]) { self.value = .list(doubleList.map { .double($0) }) } public init(nullList: [()]) { self.value = .list(nullList.map { .null }) } public init(dateList: [DateComponents]) { self.value = .list(dateList.map { .date($0) }) } public init(timestampList: [Date]) { self.value = .list(timestampList.map { .timestamp($0) }) } public init(structure: [String: ConfidenceValue]) { self.value = .structure(structure.mapValues { $0.value }) } public init(null: ()) { self.value = .null } private init(valueInternal: ConfidenceValueInternal) { self.value = valueInternal } public func asBoolean() -> Bool? { if case let .boolean(bool) = value { return bool } return nil } public func asString() -> String? { if case let .string(string) = value { return string } return nil } public func asInteger() -> Int? { if case let .integer(int) = value { return int } return nil } public func asDouble() -> Double? { if case let .double(double) = value { return double } return nil } public func asDateComponents() -> DateComponents? { if case let .date(dateComponents) = value { return dateComponents } return nil } public func asDate() -> Date? { if case let .timestamp(date) = value { return date } return nil } public func asList() -> [ConfidenceValue]? { if case let .list(values) = value { return values.map { i in ConfidenceValue(valueInternal: i) } } return nil } public func asStructure() -> [String: ConfidenceValue]? { if case let .structure(values) = value { return values.mapValues { ConfidenceValue(valueInternal: $0) } } return nil } public func isNull() -> Bool { if case .null = value { return true } return false } public func type() -> ConfidenceValueType { switch value { case .boolean: return .boolean case .string: return .string case .integer: return .integer case .double: return .double case .date: return .date case .timestamp: return .timestamp case .list: return .list case .structure: return .structure case .null: return .null } } public static func == (lhs: ConfidenceValue, rhs: ConfidenceValue) -> Bool { lhs.value == rhs.value } } extension ConfidenceValue { public func encode(to encoder: Encoder) throws { try value.encode(to: encoder) } } public enum ConfidenceValueType: CaseIterable { case boolean case string case integer case double case date case timestamp case list case structure case null } /// Serializable data structure meant for event sending via Confidence private enum ConfidenceValueInternal: Equatable, Codable { case boolean(Bool) case string(String) case integer(Int) case double(Double) case date(DateComponents) case timestamp(Date) case list([ConfidenceValueInternal]) case structure([String: ConfidenceValueInternal]) case null } extension ConfidenceValueInternal: CustomStringConvertible { public var description: String { switch self { case .boolean(let value): return "\(value)" case .string(let value): return value case .integer(let value): return "\(value)" case .double(let value): return "\(value)" case .date(let value): return "\(value)" case .timestamp(let value): return "\(value)" case .list(value: let values): return "\(values.map { value in value.description })" case .structure(value: let values): return "\(values.mapValues { value in value.description })" case .null: return "null" } } }