Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Sources/Encoder/CodableCBOREncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,5 @@ extension _CBOREncoder: Encoder {
protocol CBOREncodingContainer: AnyObject {
var data: Data { get }
}

extension _CBOREncoder: CBOREncodingContainer {}
14 changes: 12 additions & 2 deletions Sources/Encoder/KeyedEncodingContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,21 @@ extension _CBOREncoder.KeyedContainer: KeyedEncodingContainerProtocol {
}

func superEncoder() -> Encoder {
fatalError("Unimplemented") // FIXME
// Use a special "super" key for encoding class hierarchies
let superKey = AnyCodingKey(stringValue: "super")
let encoder = _CBOREncoder(options: self.options)
encoder.codingPath = self.codingPath + [superKey]
encoder.userInfo = self.userInfo
self.storage[superKey] = encoder
return encoder
}

func superEncoder(forKey key: Key) -> Encoder {
fatalError("Unimplemented") // FIXME
let encoder = _CBOREncoder(options: self.options)
encoder.codingPath = self.nestedCodingPath(forKey: key)
encoder.userInfo = self.userInfo
self.storage[anyCodingKeyForKey(key)] = encoder
return encoder
}
}

Expand Down
6 changes: 5 additions & 1 deletion Sources/Encoder/UnkeyedEncodingContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ extension _CBOREncoder.UnkeyedContainer: UnkeyedEncodingContainer {
}

func superEncoder() -> Encoder {
fatalError("Unimplemented") // FIXME
let encoder = _CBOREncoder(options: self.options)
encoder.codingPath = self.nestedCodingPath
encoder.userInfo = self.userInfo
self.storage.append(encoder)
return encoder
}
}

Expand Down
114 changes: 114 additions & 0 deletions Tests/CodableCBOREncoderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,120 @@ class CodableCBOREncoderTests: XCTestCase {
|| encoded == [0xa2, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x63, 0x48, 0x61, 0x6d, 0x63, 0x61, 0x67, 0x65, 0x18, 0x1b]
)
}

/// Test that superEncoder() works in KeyedEncodingContainer
func testSuperEncoderInKeyedContainer() throws {
// Create a simple class hierarchy to test super encoding
class Base: Encodable {
let baseValue: Int

init(baseValue: Int) {
self.baseValue = baseValue
}
}

class Derived: Base {
let derivedValue: String

init(baseValue: Int, derivedValue: String) {
self.derivedValue = derivedValue
super.init(baseValue: baseValue)
}

enum CodingKeys: String, CodingKey {
case derivedValue
}

override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(derivedValue, forKey: .derivedValue)
// Use superEncoder to encode the base class
try super.encode(to: container.superEncoder())
}
}

let derived = Derived(baseValue: 42, derivedValue: "test")
let encoded = try CodableCBOREncoder().encode(derived)

// Should be encodable and decodable
XCTAssertNotNil(encoded)
XCTAssertGreaterThan(encoded.count, 0)

// Decode to verify structure
let decoded = try CBOR.decode([UInt8](encoded))
XCTAssertNotNil(decoded)
}

/// Test that superEncoder() works in UnkeyedEncodingContainer
func testSuperEncoderInUnkeyedContainer() throws {
struct TestStruct: Encodable {
let value: Int

func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(value)
// Use superEncoder in an array context
let superEncoder = container.superEncoder()
var nestedContainer = superEncoder.singleValueContainer()
try nestedContainer.encode("nested")
}
}

let test = TestStruct(value: 123)
let encoded = try CodableCBOREncoder().encode(test)

// Should encode successfully
XCTAssertNotNil(encoded)
XCTAssertGreaterThan(encoded.count, 0)

// Verify it's a valid CBOR array with 2 elements
let decoded = try CBOR.decode([UInt8](encoded))
if case let .array(arr) = decoded {
XCTAssertEqual(arr.count, 2)
XCTAssertEqual(arr[0], CBOR.unsignedInt(123))
XCTAssertEqual(arr[1], CBOR.utf8String("nested"))
} else {
XCTFail("Expected array, got \(decoded)")
}
}

/// Test that superEncoder(forKey:) works correctly
func testSuperEncoderForKey() throws {
struct TestStruct: Encodable {
let value1: Int
let value2: String

enum CodingKeys: String, CodingKey {
case value1
case customSuper
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(value1, forKey: .value1)

// Use superEncoder with a custom key
let superEncoder = container.superEncoder(forKey: .customSuper)
var nestedContainer = superEncoder.singleValueContainer()
try nestedContainer.encode(value2)
}
}

let test = TestStruct(value1: 42, value2: "hello")
let encoded = try CodableCBOREncoder().encode(test)

XCTAssertNotNil(encoded)
XCTAssertGreaterThan(encoded.count, 0)

// Verify structure
let decoded = try CBOR.decode([UInt8](encoded))
if case let .map(dict) = decoded {
XCTAssertEqual(dict[CBOR.utf8String("value1")], CBOR.unsignedInt(42))
XCTAssertEqual(dict[CBOR.utf8String("customSuper")], CBOR.utf8String("hello"))
} else {
XCTFail("Expected map, got \(decoded)")
}
}
}

extension Array {
Expand Down