Skip to content

Commit

Permalink
Fix diect encoding/decoding of AnyValue.AnyDictionary
Browse files Browse the repository at this point in the history
Ensures that when direcly encoding an `AnyValue.AnyDictionary` (not wrapped in an `AnyValue`) the a map or objet is used.
  • Loading branch information
kdubb committed Jun 26, 2023
1 parent d37225d commit f7f183f
Show file tree
Hide file tree
Showing 16 changed files with 177 additions and 0 deletions.
13 changes: 13 additions & 0 deletions Sources/PotentASN1/ASN1Decoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public struct ASN1DecoderTransform: InternalDecoderTransform, InternalValueDeser
BigInt.self,
BigUInt.self,
AnyValue.self,
AnyValue.AnyDictionary.self,
]

public static func intercepts(_ type: Decodable.Type) -> Bool {
Expand Down Expand Up @@ -179,6 +180,9 @@ public struct ASN1DecoderTransform: InternalDecoderTransform, InternalValueDeser
else if interceptedType == AnyValue.self {
return try unbox(value, as: AnyValue.self, decoder: decoder)
}
else if interceptedType == AnyValue.AnyDictionary.self {
return try unbox(value, as: AnyValue.AnyDictionary.self, decoder: decoder)
}
else {
fatalError("type not valid for intercept")
}
Expand Down Expand Up @@ -610,6 +614,15 @@ public struct ASN1DecoderTransform: InternalDecoderTransform, InternalValueDeser
}
}

public static func unbox(_ value: ASN1, as type: AnyValue.AnyDictionary.Type, decoder: IVD) throws -> AnyValue.AnyDictionary? {
guard let keyedValues = try valueToKeyedValues(value, decoder: decoder) else {
return nil
}
return AnyValue.AnyDictionary(
uniqueKeysWithValues: try keyedValues.map { (.string($0), try unbox($1, as: AnyValue.self, decoder: decoder)) }
)
}

public static func valueToUnkeyedValues(_ value: ASN1, decoder: IVD) throws -> UnkeyedValues? {

guard let decoded = try decode(value, decoder: decoder) else { return nil }
Expand Down
4 changes: 4 additions & 0 deletions Sources/PotentASN1/ASN1Encoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public struct ASN1EncoderTransform: InternalEncoderTransform, InternalValueSeria
BigInt.self,
BigUInt.self,
AnyValue.self,
AnyValue.AnyDictionary.self,
]

public static func intercepts(_ type: Encodable.Type) -> Bool {
Expand All @@ -135,6 +136,9 @@ public struct ASN1EncoderTransform: InternalEncoderTransform, InternalValueSeria
if let anyValue = value as? AnyValue {
return try box(anyValue, encoder: encoder)
}
if let value = value as? AnyValue.AnyDictionary {
return try box(.dictionary(value), encoder: encoder)
}
if let uuid = value as? UUID {
value = uuid.uuidString
}
Expand Down
19 changes: 19 additions & 0 deletions Sources/PotentCBOR/CBORDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser
BigInt.self,
BigUInt.self,
AnyValue.self,
AnyValue.AnyDictionary.self,
]

public static func intercepts(_ type: Decodable.Type) -> Bool {
Expand Down Expand Up @@ -113,6 +114,9 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser
else if interceptedType == AnyValue.self {
return try unbox(value, as: AnyValue.self, decoder: decoder)
}
else if interceptedType == AnyValue.AnyDictionary.self {
return try unbox(value, as: AnyValue.AnyDictionary.self, decoder: decoder)
}
fatalError("type not valid for intercept")
}

Expand Down Expand Up @@ -535,6 +539,21 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser
}
}

public static func unbox(
_ value: CBOR,
as type: AnyValue.AnyDictionary.Type,
decoder: IVD
) throws -> AnyValue.AnyDictionary {
guard case .map(let map) = value else {
throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value)
}
return AnyValue.AnyDictionary(uniqueKeysWithValues: try map.map { key, value in
let key = try unbox(key, as: AnyValue.self, decoder: decoder)
let value = try unbox(value, as: AnyValue.self, decoder: decoder)
return (key, value)
})
}

public static func valueToUnkeyedValues(_ value: CBOR, decoder: IVD) throws -> UnkeyedValues? {
guard case .array(let array) = value else { return nil }
return array
Expand Down
4 changes: 4 additions & 0 deletions Sources/PotentCBOR/CBOREncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public struct CBOREncoderTransform: InternalEncoderTransform, InternalValueSeria
BigInt.self,
BigUInt.self,
AnyValue.self,
AnyValue.AnyDictionary.self,
]

public static func intercepts(_ type: Encodable.Type) -> Bool {
Expand Down Expand Up @@ -127,6 +128,9 @@ public struct CBOREncoderTransform: InternalEncoderTransform, InternalValueSeria
else if let value = value as? AnyValue {
return try box(value, encoder: encoder)
}
else if let value = value as? AnyValue.AnyDictionary {
return try box(.dictionary(value), encoder: encoder)
}
fatalError("type not valid for intercept")
}

Expand Down
17 changes: 17 additions & 0 deletions Sources/PotentJSON/JSONDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public struct JSONDecoderTransform: InternalDecoderTransform, InternalValueDeser
BigInt.self,
BigUInt.self,
AnyValue.self,
AnyValue.AnyDictionary.self,
]

public static func intercepts(_ type: Decodable.Type) -> Bool {
Expand Down Expand Up @@ -151,6 +152,9 @@ public struct JSONDecoderTransform: InternalDecoderTransform, InternalValueDeser
else if interceptedType == AnyValue.self {
return try unbox(value, as: AnyValue.self, decoder: decoder)
}
else if interceptedType == AnyValue.AnyDictionary.self {
return try unbox(value, as: AnyValue.AnyDictionary.self, decoder: decoder)
}
fatalError("type not valid for intercept")
}

Expand Down Expand Up @@ -515,6 +519,19 @@ public struct JSONDecoderTransform: InternalDecoderTransform, InternalValueDeser
}
}

public static func unbox(
_ value: JSON,
as type: AnyValue.AnyDictionary.Type,
decoder: IVD
) throws -> AnyValue.AnyDictionary {
guard case .object(let object) = value else {
throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value)
}
return AnyValue.AnyDictionary(uniqueKeysWithValues: try object.map { key, value in
(.string(key), try unbox(value, as: AnyValue.self, decoder: decoder))
})
}

public static func valueToUnkeyedValues(_ value: JSON, decoder: IVD) throws -> UnkeyedValues? {
guard case .array(let array) = value else { return nil }
return array
Expand Down
4 changes: 4 additions & 0 deletions Sources/PotentJSON/JSONEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ public struct JSONEncoderTransform: InternalEncoderTransform, InternalValueSeria
BigInt.self,
BigUInt.self,
AnyValue.self,
AnyValue.AnyDictionary.self,
]

public static func intercepts(_ type: Encodable.Type) -> Bool {
Expand Down Expand Up @@ -187,6 +188,9 @@ public struct JSONEncoderTransform: InternalEncoderTransform, InternalValueSeria
else if let value = value as? AnyValue {
return try box(value, encoder: encoder)
}
else if let value = value as? AnyValue.AnyDictionary {
return try box(.dictionary(value), encoder: encoder)
}
fatalError("type not valid for intercept")
}

Expand Down
18 changes: 18 additions & 0 deletions Sources/PotentYAML/YAMLDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser
BigInt.self,
BigUInt.self,
AnyValue.self,
AnyValue.AnyDictionary.self,
]

public static func intercepts(_ type: Decodable.Type) -> Bool {
Expand Down Expand Up @@ -146,6 +147,9 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser
else if interceptedType == AnyValue.self {
return try unbox(value, as: AnyValue.self, decoder: decoder)
}
else if interceptedType == AnyValue.AnyDictionary.self {
return try unbox(value, as: AnyValue.AnyDictionary.self, decoder: decoder)
}
fatalError("type not valid for intercept")
}

Expand Down Expand Up @@ -538,6 +542,20 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser
throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value)
}

public static func unbox(
_ value: YAML,
as type: AnyValue.AnyDictionary.Type,
decoder: IVD
) throws -> AnyValue.AnyDictionary {
guard case .mapping(let mapping, _, _, _) = value else {
throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value)
}
return AnyValue.AnyDictionary(uniqueKeysWithValues: try mapping.map { entry in
(try unbox(entry.key, as: AnyValue.self, decoder: decoder),
try unbox(entry.value, as: AnyValue.self, decoder: decoder))
})
}

public static func valueToUnkeyedValues(_ value: YAML, decoder: IVD) throws -> UnkeyedValues? {
guard case .sequence(let sequence, _, _, _) = value else { return nil }
return sequence
Expand Down
4 changes: 4 additions & 0 deletions Sources/PotentYAML/YAMLEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public struct YAMLEncoderTransform: InternalEncoderTransform, InternalValueSeria
BigInt.self,
BigUInt.self,
AnyValue.self,
AnyValue.AnyDictionary.self,
]

public static func intercepts(_ type: Encodable.Type) -> Bool {
Expand Down Expand Up @@ -166,6 +167,9 @@ public struct YAMLEncoderTransform: InternalEncoderTransform, InternalValueSeria
else if let value = value as? AnyValue {
return try box(value, encoder: encoder)
}
else if let value = value as? AnyValue.AnyDictionary {
return try box(.dictionary(value), encoder: encoder)
}
fatalError("type not valid for intercept")
}

Expand Down
13 changes: 13 additions & 0 deletions Tests/ASN1DecoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1189,4 +1189,17 @@ class ASN1DecoderTests: XCTestCase {
)
}

func testDecodeAnyDictionary() throws {

let asn1 = Data(hexEncoded: "300c020101020102020103020104")

let value = try ASN1.Decoder(schema: .sequence(["b": .integer(),
"z": .integer(),
"n": .integer(),
"f": .integer()]))
.decode(AnyValue.AnyDictionary.self, from: asn1)

XCTAssertEqual(value, ["b": .integer(1), "z": .integer(2), "n": .integer(3), "f": .integer(4)])
}

}
11 changes: 11 additions & 0 deletions Tests/ASN1EncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,15 @@ class ASN1EncoderTests: XCTestCase {
)
}

func testEncodeAnyDictionary() throws {

let dict: AnyValue.AnyDictionary = ["b": 1, "z": 2, "n": 3, "f": 4]

let testASN1 = try ASN1.Encoder(schema: .sequence(["b": .integer(),
"z": .integer(),
"n": .integer(),
"f": .integer()])).encode(dict)
XCTAssertEqual(testASN1.hexEncodedString(), "300c020101020102020103020104")
}

}
8 changes: 8 additions & 0 deletions Tests/CBORDecoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1435,4 +1435,12 @@ class CBORDecoderTests: XCTestCase {
}
}

func testDecodeAnyDictionary() throws {

XCTAssertEqual(try CBOR.Decoder.default.decode(AnyValue.AnyDictionary.self,
from: Data([0xA4, 0x61, 0x62, 0x01, 0x61, 0x7A, 0x02,
0x61, 0x6E, 0x03, 0x61, 0x66, 0x04])),
["b": 1, "z": 2, "n": 3, "f": 4])
}

}
8 changes: 8 additions & 0 deletions Tests/CBOREncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,14 @@ class CBOREncoderTests: XCTestCase {
XCTAssertEqual(try encode(BigUInt(1234567)),
[0xC2, 0x43, 0x12, 0xD6, 0x87])
}

func testEncodeAnyDictionary() throws {

let dict: AnyValue.AnyDictionary = ["b": 1, "z": 2, "n": 3, "f": 4]

XCTAssertEqual(try encode(dict),
[0xA4, 0x61, 0x62, 0x01, 0x61, 0x7A, 0x02, 0x61, 0x6E, 0x03, 0x61, 0x66, 0x04])
}
}

extension Array {
Expand Down
8 changes: 8 additions & 0 deletions Tests/JSONDecoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2298,4 +2298,12 @@ class JSONDecoderTests: XCTestCase {
}
}

func testDecodeAnyDictionaryFromObject() throws {

let json = #"{"b":1,"z":2,"n":3,"f":4}"#

let testValue = try JSON.Decoder.default.decode(AnyValue.AnyDictionary.self, from: json)
XCTAssertEqual(testValue, ["b": 1, "z": 2, "n": 3, "f": 4])
}

}
8 changes: 8 additions & 0 deletions Tests/JSONEncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,14 @@ class JSONEncoderTests: XCTestCase {
XCTAssertEqual(testJSON, json)
}

func testEncodeAnyDictionary() throws {

let dict: AnyValue.AnyDictionary = ["b": 1, "z": 2, "n": 3, "f": 4]

let testJSON = try JSON.Encoder.default.encodeString(dict)
XCTAssertEqual(testJSON, #"{"b":1,"z":2,"n":3,"f":4}"#)
}

func testEncodeNonStringKeyedDictionary() throws {

struct TestValue: Codable {
Expand Down
19 changes: 19 additions & 0 deletions Tests/YAMLDecoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3020,4 +3020,23 @@ class YAMLDecoderTests: XCTestCase {
}
}

func testDecodeAnyDictionary() throws {

let yaml =
"""
---
b: 1
z: 2
n: 3
f: 4
...
"""

XCTAssertEqual(
try YAML.Decoder.default.decode(AnyValue.AnyDictionary.self, from: yaml),
["b": 1, "z": 2, "n": 3, "f": 4]
)
}

}
19 changes: 19 additions & 0 deletions Tests/YAMLEncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,25 @@ class YAMLEncoderTests: XCTestCase {
XCTAssertEqual(testYAML, yaml)
}

func testEncodeAnyDictionary() throws {

let dict: AnyValue.AnyDictionary = ["b": 1, "z": 2, "n": 3, "f": 4]

let yaml =
"""
---
b: 1
z: 2
n: 3
f: 4
...
"""

let testYAML = try YAML.Encoder.default.encodeString(dict)
XCTAssertEqual(testYAML, yaml)
}

func testEncodeNonStringKeyedDictionary() throws {

struct TestValue: Codable {
Expand Down

0 comments on commit f7f183f

Please sign in to comment.