A fast, safe, and efficient CBOR serialization library for Swift on any platform. swiftpackageindex.com/thecoolwinter/CBOR/1.1.1/documentation/cbor
atproto swift cbor

Relax Requirements for Decoding Dates

+27 -17
+27 -17
Sources/CBOR/Decoder/Containers/SingleValueCBORDecodingContainer.swift
··· 129 129 return string 130 130 } 131 131 132 + // Attempt first to decode a tagged date value, then move on and try decoding any of the following as a date: 133 + // - Int 134 + // - Float/Double/Float16 135 + // - ISO String 132 136 private func _decode(_: Date.Type) throws -> Date { 133 - let argument = try checkType(.tagged, arguments: 0, 1, as: Date.self) 134 - if argument == 0 { 135 - // String 136 - return try decodeStringDate() 137 - } else { 138 - return try decodeEpochDate() 137 + if let argument = try? checkType(.tagged, arguments: 0, 1, as: Date.self) { 138 + let taggedData = context.results.loadTagData(tagMapIndex: data.mapOffset) 139 + if argument == 0 { 140 + // String 141 + return try decodeStringDate(data: taggedData) 142 + } else { 143 + return try decodeEpochDate(data: taggedData) 144 + } 139 145 } 146 + 147 + let region = context.results.load(at: data.mapOffset) 148 + guard let date = (try? decodeStringDate(data: region)) ?? (try? decodeEpochDate(data: region)) else { 149 + throw DecodingError.typeMismatch(Date.self, context.error("Failed to decode a valid `Date` value.")) 150 + } 151 + return date 140 152 } 141 153 142 - private func decodeStringDate() throws -> Date { 143 - let taggedData = context.results.loadTagData(tagMapIndex: data.mapOffset) 144 - let string = try SingleValueCBORDecodingContainer(context: context, data: taggedData).decode(String.self) 154 + private func decodeStringDate(data: DataRegion) throws -> Date { 155 + let string = try SingleValueCBORDecodingContainer(context: context, data: data).decode(String.self) 145 156 #if canImport(FoundationEssentials) 146 157 guard let date = try? Date.ISO8601FormatStyle().parse(string) else { 147 158 throw DecodingError.dataCorrupted(context.error("Failed to decode date from \"\(string)\"")) ··· 154 165 return date 155 166 } 156 167 157 - private func decodeEpochDate() throws -> Date { 168 + private func decodeEpochDate(data: DataRegion) throws -> Date { 158 169 // Epoch Timestamp, can be a floating point or positive/negative integer value 159 - let taggedData = context.results.loadTagData(tagMapIndex: data.mapOffset) 160 - switch (taggedData.type, taggedData.argument) { 170 + switch (data.type, data.argument) { 161 171 case (.uint, _): 162 - let int = try taggedData.readInt(as: Int.self) 172 + let int = try data.readInt(as: Int.self) 163 173 return Date(timeIntervalSince1970: Double(int)) 164 174 case (.nint, _): 165 - let int = -1 - (try taggedData.readInt(as: Int.self)) 175 + let int = -1 - (try data.readInt(as: Int.self)) 166 176 return Date(timeIntervalSince1970: Double(int)) 167 177 case (.simple, 25), (.simple, 26): 168 178 // Float 169 - let float = try SingleValueCBORDecodingContainer(context: context, data: taggedData).decode(Float.self) 179 + let float = try SingleValueCBORDecodingContainer(context: context, data: data).decode(Float.self) 170 180 return Date(timeIntervalSince1970: Double(float)) 171 181 case (.simple, 27): 172 182 // Double 173 - let double = try SingleValueCBORDecodingContainer(context: context, data: taggedData).decode(Double.self) 183 + let double = try SingleValueCBORDecodingContainer(context: context, data: data).decode(Double.self) 174 184 return Date(timeIntervalSince1970: double) 175 185 default: 176 186 throw DecodingError.typeMismatch( 177 187 Date.self, 178 - context.error("Invalid type found for epoch date: \(taggedData.type) at \(taggedData.globalIndex)") 188 + context.error("Invalid type found for epoch date: \(data.type) at \(data.globalIndex)") 179 189 ) 180 190 } 181 191 }