diff --git a/packages/core/ios/Sources/AnyEncodable.swift b/packages/core/ios/Sources/AnyEncodable.swift index 7fac7bb3b..ddbf1c5f5 100644 --- a/packages/core/ios/Sources/AnyEncodable.swift +++ b/packages/core/ios/Sources/AnyEncodable.swift @@ -4,6 +4,7 @@ * Copyright 2019-2020 Datadog, Inc. */ +import DatadogInternal import Foundation internal func castAttributesToSwift(_ attributes: NSDictionary) -> [String: Encodable] { @@ -29,39 +30,39 @@ internal func castValueToSwift(_ value: Any) -> Encodable { // Otherwise, cast by preserving its encoded value (and loosing type information) casted = castByPreservingEncodedValue(attributeValue: value) } - + return casted } /// Casts `Any` value to `Encodable` by preserving its type information. private func castByPreservingTypeInformation(attributeValue: Any) -> Encodable? { switch attributeValue { - case let string as String: // unpacking `NSTaggedPointerString` - return string // cast to String - case let number as NSNumber: // unpacking `__NSCFNumber` + case let string as String: // unpacking `NSTaggedPointerString` + return string // cast to String + case let number as NSNumber: // unpacking `__NSCFNumber` switch CFNumberGetType(number) { case .charType: - return number.boolValue // cast to Bool + return number.boolValue // cast to Bool case .sInt8Type: - return number.int8Value // cast to Int8 + return number.int8Value // cast to Int8 case .sInt16Type: - return number.int16Value // cast to Int16 + return number.int16Value // cast to Int16 case .sInt32Type: - return number.int32Value // cast to Int32 + return number.int32Value // cast to Int32 case .sInt64Type: - return number.int64Value // cast to Int64 + return number.int64Value // cast to Int64 case .shortType: - return number.uint16Value // cast to UInt 16 + return number.uint16Value // cast to UInt 16 case .longType: - return number.uint32Value // cast to UInt32 + return number.uint32Value // cast to UInt32 case .longLongType: - return number.uint64Value // cast to UInt64 + return number.uint64Value // cast to UInt64 case .intType, .nsIntegerType, .cfIndexType: - return number.intValue // cast to Int + return number.intValue // cast to Int case .floatType, .float32Type: - return number.floatValue // cast to Float + return number.floatValue // cast to Float case .doubleType, .float64Type, .cgFloatType: - return number.doubleValue // cast to Double + return number.doubleValue // cast to Double @unknown default: return nil } @@ -75,71 +76,3 @@ private func castByPreservingTypeInformation(attributeValue: Any) -> Encodable? private func castByPreservingEncodedValue(attributeValue: Any) -> Encodable { return AnyEncodable(attributeValue) } - -/// Type erasing `Encodable` wrapper to bridge Objective-C's `Any` to Swift `Encodable`. -/// -/// Inspired by `AnyCodable` by Flight-School (MIT): -/// https://github.com/Flight-School/AnyCodable/blob/master/Sources/AnyCodable/AnyEncodable.swift -internal class AnyEncodable: Encodable { - internal let value: Any - - init(_ value: Any) { - self.value = value - } - - func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - - switch value { - case let number as NSNumber: - try encodeNSNumber(number, into: &container) - case is NSNull, is Void: - try container.encodeNil() - case let string as String: - try container.encode(string) - case let date as Date: - try container.encode(date) - case let url as URL: - try container.encode(url) - case let array as [Any]: - try container.encode(array.map { AnyEncodable($0) }) - case let dictionary as [String: Any]: - try container.encode(dictionary.mapValues { AnyEncodable($0) }) - default: - let context = EncodingError.Context( - codingPath: container.codingPath, - debugDescription: "Value \(value) cannot be encoded - \(type(of: value)) is not supported by `AnyEncodable`." - ) - throw EncodingError.invalidValue(value, context) - } - } -} - -private func encodeNSNumber(_ nsnumber: NSNumber, into container: inout SingleValueEncodingContainer) throws { - switch CFNumberGetType(nsnumber) { - case .charType: - try container.encode(nsnumber.boolValue) - case .sInt8Type: - try container.encode(nsnumber.int8Value) - case .sInt16Type: - try container.encode(nsnumber.int16Value) - case .sInt32Type: - try container.encode(nsnumber.int32Value) - case .sInt64Type: - try container.encode(nsnumber.int64Value) - case .shortType: - try container.encode(nsnumber.uint16Value) - case .longType: - try container.encode(nsnumber.uint32Value) - case .longLongType: - try container.encode(nsnumber.uint64Value) - case .intType, .nsIntegerType, .cfIndexType: - try container.encode(nsnumber.intValue) - case .floatType, .float32Type: - try container.encode(nsnumber.floatValue) - case .doubleType, .float64Type, .cgFloatType: - try container.encode(nsnumber.doubleValue) - @unknown default: - return - } -} diff --git a/packages/core/ios/Tests/AnyEncodableTests.swift b/packages/core/ios/Tests/AnyEncodableTests.swift index 4f15a591e..ef20db530 100644 --- a/packages/core/ios/Tests/AnyEncodableTests.swift +++ b/packages/core/ios/Tests/AnyEncodableTests.swift @@ -6,6 +6,7 @@ import XCTest @testable import DatadogSDKReactNative +@testable import DatadogInternal internal class AnyEncodableTests: XCTestCase { // MARK: - Casting attributes diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index d5c65b9ef..b092229c9 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -601,7 +601,7 @@ class DdSdkTests: XCTestCase { XCTAssertEqual(userInfo.extraInfo["extra-info-3"] as? Bool, true) if let extraInfo4Encodable = userInfo.extraInfo["extra-info-4"] - as? DatadogSDKReactNative.AnyEncodable, + as? AnyEncodable, let extraInfo4Dict = extraInfo4Encodable.value as? [String: Int] { XCTAssertEqual(extraInfo4Dict, ["nested-extra-info-1": 456]) @@ -664,7 +664,7 @@ class DdSdkTests: XCTestCase { XCTAssertEqual(userInfo.extraInfo["extra-info-3"] as? Bool, true) if let extraInfo4Encodable = userInfo.extraInfo["extra-info-4"] - as? DatadogSDKReactNative.AnyEncodable, + as? AnyEncodable, let extraInfo4Dict = extraInfo4Encodable.value as? [String: Int] { XCTAssertEqual(extraInfo4Dict, ["nested-extra-info-1": 456]) @@ -718,7 +718,7 @@ class DdSdkTests: XCTestCase { XCTAssertEqual(userInfo.extraInfo["extra-info-3"] as? Bool, true) if let extraInfo4Encodable = userInfo.extraInfo["extra-info-4"] - as? DatadogSDKReactNative.AnyEncodable, + as? AnyEncodable, let extraInfo4Dict = extraInfo4Encodable.value as? [String: Int] { XCTAssertEqual(extraInfo4Dict, ["nested-extra-info-1": 456])