Skip to content

Commit

Permalink
Fix a bug where the codingPath isn't correctly updated throughout nes…
Browse files Browse the repository at this point in the history
…ted generic decoding steps
  • Loading branch information
Joannis committed Jan 6, 2023
1 parent 5fb64b7 commit 07e5de4
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct User: Codable {
let name: String
}

let data = Data()
let data: Data = ...
var decoder = IkigaJSONDecoder()
let user = try decoder.decode(User.self, from: data)
```
Expand Down
19 changes: 12 additions & 7 deletions Sources/IkigaJSON/Codable/JSONDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public final class IkigaJSONDecoder {
var parser = JSONParser(pointer: pointer, count: buffer.count)
try parser.scanValue()

let decoder = _JSONDecoder(description: parser.description, pointer: pointer, settings: settings)
let decoder = _JSONDecoder(description: parser.description, codingPath: [], pointer: pointer, settings: settings)
let type = try D(from: decoder)
return type
}
Expand All @@ -99,6 +99,7 @@ public final class IkigaJSONDecoder {
return try object.jsonBuffer.withUnsafeReadableBytes { buffer in
let decoder = _JSONDecoder(
description: object.description,
codingPath: [],
pointer: buffer.baseAddress!.bindMemory(to: UInt8.self, capacity: buffer.count),
settings: settings
)
Expand All @@ -112,6 +113,7 @@ public final class IkigaJSONDecoder {
return try array.jsonBuffer.withUnsafeReadableBytes { buffer in
let decoder = _JSONDecoder(
description: array.description,
codingPath: [],
pointer: buffer.baseAddress!.bindMemory(to: UInt8.self, capacity: buffer.count),
settings: settings
)
Expand Down Expand Up @@ -158,7 +160,7 @@ public final class IkigaJSONDecoder {
var parser = JSONParser(pointer: pointer, count: buffer.count)
try parser.scanValue()

let decoder = _JSONDecoder(description: parser.description, pointer: pointer, settings: settings)
let decoder = _JSONDecoder(description: parser.description, codingPath: [], pointer: pointer, settings: settings)
let type = try D(from: decoder)
return (parser.currentOffset, type)
}
Expand All @@ -170,7 +172,7 @@ public final class IkigaJSONDecoder {
parser: JSONParser,
settings: JSONDecoderSettings = JSONDecoderSettings()
) throws -> D {
let decoder = _JSONDecoder(description: parser.description, pointer: buffer.baseAddress!, settings: settings)
let decoder = _JSONDecoder(description: parser.description, codingPath: [], pointer: buffer.baseAddress!, settings: settings)
return try D(from: decoder)
}
}
Expand All @@ -181,7 +183,7 @@ fileprivate struct _JSONDecoder: Decoder {
let settings: JSONDecoderSettings
var snakeCasing: Bool

var codingPath = [CodingKey]()
var codingPath: [CodingKey]
var userInfo: [CodingUserInfoKey : Any] {
return settings.userInfo
}
Expand Down Expand Up @@ -215,9 +217,10 @@ fileprivate struct _JSONDecoder: Decoder {
return SingleValueJSONDecodingContainer(decoder: self)
}

init(description: JSONDescription, pointer: UnsafePointer<UInt8>, settings: JSONDecoderSettings) {
init(description: JSONDescription, codingPath: [CodingKey], pointer: UnsafePointer<UInt8>, settings: JSONDecoderSettings) {
self.description = description
self.pointer = pointer
self.codingPath = codingPath
self.settings = settings

if case .convertFromSnakeCase = settings.keyDecodingStrategy {
Expand All @@ -229,7 +232,7 @@ fileprivate struct _JSONDecoder: Decoder {

func subDecoder(offsetBy offset: Int) -> _JSONDecoder {
let subDescription = self.description.subDescription(offset: offset)
return _JSONDecoder(description: subDescription, pointer: pointer, settings: settings)
return _JSONDecoder(description: subDescription, codingPath: codingPath, pointer: pointer, settings: settings)
}

func decode<D: Decodable>(_ type: D.Type) throws -> D {
Expand Down Expand Up @@ -441,7 +444,9 @@ fileprivate struct KeyedJSONDecodingContainer<Key: CodingKey>: KeyedDecodingCont
) else {
throw failureError
}
return self.decoder.subDecoder(offsetBy: offset)
var subDecoder = self.decoder.subDecoder(offsetBy: offset)
subDecoder.codingPath.append(key)
return subDecoder
}

func decode<T>(_: T.Type, forKey key: Key) throws -> T where T : Decodable {
Expand Down
5 changes: 5 additions & 0 deletions Sources/IkigaJSON/Codable/JSONEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ public struct IkigaJSONEncoder {
return data
}

/// Encodes the provided value as JSON into the given buffer.
public func encodeAndWrite<E: Encodable>(_ value: E, into buffer: inout ByteBuffer) throws {
let encoder = _JSONEncoder(userInfo: userInfo, settings: settings)
try value.encode(to: encoder)
Expand All @@ -229,6 +230,8 @@ public struct IkigaJSONEncoder {
encoder.cleanUp()
}

/// Encodes the provided value as JSON and returns a JSON Object.
/// If the value is not a JSON Object, an error is thrown.
public func encodeJSONObject<E: Encodable>(from value: E) throws -> JSONObject {
let encoder = _JSONEncoder(userInfo: userInfo, settings: settings)
try value.encode(to: encoder)
Expand All @@ -239,6 +242,8 @@ public struct IkigaJSONEncoder {
return object
}

/// Encodes the provided value as JSON and returns a JSON Array.
/// If the value is not a JSON Array, an error is thrown.
public func encodeJSONArray<E: Encodable>(from value: E) throws -> JSONArray {
let encoder = _JSONEncoder(userInfo: userInfo, settings: settings)
try value.encode(to: encoder)
Expand Down

0 comments on commit 07e5de4

Please sign in to comment.