@@ -77,14 +77,23 @@ public struct KeyValueEncoder: Sendable {
7777 /// Encodes dates by directly casting to Any.
7878 case date
7979
80- /// Encodes dates from ISO8601 strings.
81- case iso8601( options: ISO8601DateFormatter . Options = [ . withInternetDateTime] )
82-
8380 /// Encodes dates to Int in terms of milliseconds since midnight UTC on January 1, 1970.
8481 case millisecondsSince1970
8582
8683 /// Encodes dates to Int in terms of seconds since midnight UTC on January 1, 1970.
8784 case secondsSince1970
85+
86+ /// Encodes dates to Any using a closure
87+ case custom( @Sendable ( Date) throws -> Any )
88+
89+ /// Encodes dates to ISO8601 strings.
90+ static func iso8601( options: ISO8601DateFormatter . Options = [ . withInternetDateTime] ) -> Self {
91+ . custom {
92+ let formatter = ISO8601DateFormatter ( )
93+ formatter. formatOptions = options
94+ return formatter. string ( from: $0)
95+ }
96+ }
8897 }
8998}
9099
@@ -238,7 +247,7 @@ private extension KeyValueEncoder {
238247 }
239248
240249 func encodeToValue< T> ( _ value: T ) throws -> EncodedValue where T: Encodable {
241- guard let encoded = EncodedValue . makeValue ( for: value, using: strategy) else {
250+ guard let encoded = try EncodedValue . makeValue ( for: value, at : codingPath , using: strategy) else {
242251 try value. encode ( to: self )
243252 return try getEncodedValue ( )
244253 }
@@ -338,7 +347,7 @@ private extension KeyValueEncoder {
338347 }
339348
340349 func encode< T: Encodable > ( _ value: T , forKey key: Key ) throws {
341- if let val = EncodedValue . makeValue ( for: value, using: strategy) {
350+ if let val = try EncodedValue . makeValue ( for: value, at : codingPath , using: strategy) {
342351 setValue ( val, forKey: key)
343352 return
344353 }
@@ -468,7 +477,7 @@ private extension KeyValueEncoder {
468477 }
469478
470479 func encode< T: Encodable > ( _ value: T ) throws {
471- if let val = EncodedValue . makeValue ( for: value, using: strategy) {
480+ if let val = try EncodedValue . makeValue ( for: value, at : codingPath . appending ( index : count ) , using: strategy) {
472481 appendValue ( val)
473482 return
474483 }
@@ -587,7 +596,7 @@ private extension KeyValueEncoder {
587596 }
588597
589598 func encode< T> ( _ value: T ) throws where T: Encodable {
590- if let encoded = EncodedValue . makeValue ( for: value, using: strategy) {
599+ if let encoded = try EncodedValue . makeValue ( for: value, at : codingPath , using: strategy) {
591600 self . value = encoded
592601 return
593602 }
@@ -708,11 +717,25 @@ struct AnyCodingKey: CodingKey {
708717
709718extension KeyValueEncoder . EncodedValue {
710719
711- static func makeValue( for value: Any , using strategy: KeyValueEncoder . EncodingStrategy ) -> Self ? {
720+ static func makeValue( for value: Any , at codingPath: [ any CodingKey ] , using strategy: KeyValueEncoder . EncodingStrategy ) throws -> Self ? {
721+ do {
722+ return try makeValue ( for: value, using: strategy)
723+ } catch {
724+ let valueDescription = strategy. optionals. isNull ( value) ? " nil " : String ( describing: type ( of: value) )
725+ let context = EncodingError . Context (
726+ codingPath: codingPath,
727+ debugDescription: " \( valueDescription) at \( codingPath. makeKeyPath ( ) ) cannot be encoded. \( error. localizedDescription) " ,
728+ underlyingError: error
729+ )
730+ throw EncodingError . invalidValue ( value, context)
731+ }
732+ }
733+
734+ static func makeValue( for value: Any , using strategy: KeyValueEncoder . EncodingStrategy ) throws -> Self ? {
712735 if let dataValue = value as? Data {
713736 return . value( dataValue)
714737 } else if let dateValue = value as? Date {
715- return makeValue ( for: dateValue, using: strategy. dates)
738+ return try makeValue ( for: dateValue, using: strategy. dates)
716739 } else if let urlValue = value as? URL {
717740 return . value( urlValue)
718741 } else if let decimalValue = value as? Decimal {
@@ -722,14 +745,12 @@ extension KeyValueEncoder.EncodedValue {
722745 }
723746 }
724747
725- static func makeValue( for date: Date , using strategy: KeyValueEncoder . DateEncodingStrategy ) -> Self ? {
748+ static func makeValue( for date: Date , using strategy: KeyValueEncoder . DateEncodingStrategy ) throws -> Self ? {
726749 switch strategy {
727750 case . date:
728751 return . value( date)
729- case . iso8601( options: let options) :
730- let f = ISO8601DateFormatter ( )
731- f. formatOptions = options
732- return . value( f. string ( from: date) )
752+ case . custom( let transform) :
753+ return try . value( transform ( date) )
733754 case . millisecondsSince1970:
734755 return . value( Int ( date. timeIntervalSince1970 * 1000 ) )
735756 case . secondsSince1970:
0 commit comments