@@ -129,240 +129,5 @@ public struct RFC5322DateTimeCoding: Decodable, Sendable {
129
129
)
130
130
}
131
131
}
132
- }
133
-
134
- struct RFC5322DateParsingError : Error { }
135
-
136
- struct RFC5322DateParseStrategy {
137
- func parse( _ input: String ) throws -> Date {
138
- guard let components = self . components ( from: input) else {
139
- throw RFC5322DateParsingError ( )
140
- }
141
- guard let date = components. date else {
142
- throw RFC5322DateParsingError ( )
143
- }
144
- return date
145
- }
146
-
147
- func components( from input: String ) -> DateComponents ? {
148
- var endIndex = input. endIndex
149
- // If the date string has a timezone in brackets, we need to remove it before parsing.
150
- if let bracket = input. firstIndex ( of: " ( " ) {
151
- endIndex = bracket
152
- }
153
- var s = input [ input. startIndex..< endIndex]
154
-
155
- let asciiDigits = UInt8 ( ascii: " 0 " ) ... UInt8 ( ascii: " 9 " )
156
-
157
- return s. withUTF8 { buffer -> DateComponents ? in
158
- func parseDay( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> Int ? {
159
- let first = it. next ( )
160
- let second = it. next ( )
161
- guard let first = first, let second = second else { return nil }
162
-
163
- guard asciiDigits. contains ( first) else { return nil }
164
-
165
- if asciiDigits. contains ( second) {
166
- return Int ( first - UInt8( ascii: " 0 " ) ) * 10 + Int( second - UInt8( ascii: " 0 " ) )
167
- } else {
168
- return Int ( first - UInt8( ascii: " 0 " ) )
169
- }
170
- }
171
-
172
- func skipWhitespace( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> UInt8 ? {
173
- while let c = it. next ( ) {
174
- if c != UInt8 ( ascii: " " ) {
175
- return c
176
- }
177
- }
178
- return nil
179
- }
180
-
181
- func parseMonth( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> Int ? {
182
- let first = it. nextAsciiLetter ( skippingWhitespace: true )
183
- let second = it. nextAsciiLetter ( )
184
- let third = it. nextAsciiLetter ( )
185
- guard let first = first, let second = second, let third = third else { return nil }
186
- guard first. isAsciiLetter else { return nil }
187
- return monthMap [ [ first, second, third] ]
188
- }
189
-
190
- func parseYear( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> Int ? {
191
- let first = it. nextAsciiDigit ( skippingWhitespace: true )
192
- let second = it. nextAsciiDigit ( )
193
- let third = it. nextAsciiDigit ( )
194
- let fourth = it. nextAsciiDigit ( )
195
- guard let first = first,
196
- let second = second,
197
- let third = third,
198
- let fourth = fourth
199
- else { return nil }
200
- return Int ( first - UInt8( ascii: " 0 " ) ) * 1000
201
- + Int( second - UInt8( ascii: " 0 " ) ) * 100
202
- + Int( third - UInt8( ascii: " 0 " ) ) * 10
203
- + Int( fourth - UInt8( ascii: " 0 " ) )
204
- }
205
-
206
- func parseHour( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> Int ? {
207
- let first = it. nextAsciiDigit ( skippingWhitespace: true )
208
- let second = it. nextAsciiDigit ( )
209
- guard let first = first, let second = second else { return nil }
210
- return Int ( first - UInt8( ascii: " 0 " ) ) * 10 + Int( second - UInt8( ascii: " 0 " ) )
211
- }
212
-
213
- func parseMinute( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> Int ? {
214
- let first = it. nextAsciiDigit ( skippingWhitespace: true )
215
- let second = it. nextAsciiDigit ( )
216
- guard let first = first, let second = second else { return nil }
217
- return Int ( first - UInt8( ascii: " 0 " ) ) * 10 + Int( second - UInt8( ascii: " 0 " ) )
218
- }
219
-
220
- func parseSecond( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> Int ? {
221
- let first = it. nextAsciiDigit ( skippingWhitespace: true )
222
- let second = it. nextAsciiDigit ( )
223
- guard let first = first, let second = second else { return nil }
224
- return Int ( first - UInt8( ascii: " 0 " ) ) * 10 + Int( second - UInt8( ascii: " 0 " ) )
225
- }
226
-
227
- func parseTimezone( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> Int ? {
228
- let plusMinus = it. nextSkippingWhitespace ( )
229
- if let plusMinus, plusMinus == UInt8 ( ascii: " + " ) || plusMinus == UInt8 ( ascii: " - " ) {
230
- let hour = parseHour ( & it)
231
- let minute = parseMinute ( & it)
232
- guard let hour = hour, let minute = minute else { return nil }
233
- return ( hour * 60 + minute) * ( plusMinus == UInt8 ( ascii: " + " ) ? 1 : - 1 )
234
- } else if let first = plusMinus {
235
- let second = it. nextAsciiLetter ( )
236
- let third = it. nextAsciiLetter ( )
237
-
238
- guard let second = second, let third = third else { return nil }
239
- let abbr = [ first, second, third]
240
- return timezoneOffsetMap [ abbr]
241
- }
242
-
243
- return nil
244
- }
245
-
246
- var it = buffer. makeIterator ( )
247
-
248
- // if the 4th character is a comma, then we have a day of the week
249
- guard buffer. count > 5 else { return nil }
250
-
251
- if buffer [ 3 ] == UInt8 ( ascii: " , " ) {
252
- for _ in 0 ..< 5 {
253
- _ = it. next ( )
254
- }
255
- }
256
-
257
- guard let day = parseDay ( & it) else { return nil }
258
- guard let month = parseMonth ( & it) else { return nil }
259
- guard let year = parseYear ( & it) else { return nil }
260
-
261
- guard let hour = parseHour ( & it) else { return nil }
262
- guard it. expect ( UInt8 ( ascii: " : " ) ) else { return nil }
263
- guard let minute = parseMinute ( & it) else { return nil }
264
- guard it. expect ( UInt8 ( ascii: " : " ) ) else { return nil }
265
- guard let second = parseSecond ( & it) else { return nil }
266
-
267
- guard let timezoneOffsetMinutes = parseTimezone ( & it) else { return nil }
268
-
269
- return DateComponents (
270
- calendar: Calendar ( identifier: . gregorian) ,
271
- timeZone: TimeZone ( secondsFromGMT: timezoneOffsetMinutes * 60 ) ,
272
- year: year,
273
- month: month,
274
- day: day,
275
- hour: hour,
276
- minute: minute,
277
- second: second
278
- )
279
- }
280
- }
281
- }
282
-
283
- @available ( macOS 12 . 0 , * )
284
- extension RFC5322DateParseStrategy : ParseStrategy { }
285
-
286
- extension IteratorProtocol where Self. Element == UInt8 {
287
- mutating func expect( _ expected: UInt8 ) -> Bool {
288
- guard self . next ( ) == expected else { return false }
289
- return true
290
- }
291
-
292
- mutating func nextSkippingWhitespace( ) -> UInt8 ? {
293
- while let c = self . next ( ) {
294
- if c != UInt8 ( ascii: " " ) {
295
- return c
296
- }
297
- }
298
- return nil
299
- }
300
-
301
- mutating func nextAsciiDigit( skippingWhitespace: Bool = false ) -> UInt8 ? {
302
- while let c = self . next ( ) {
303
- if skippingWhitespace {
304
- if c == UInt8 ( ascii: " " ) {
305
- continue
306
- }
307
- }
308
- switch c {
309
- case UInt8 ( ascii: " 0 " ) ... UInt8 ( ascii: " 9 " ) : return c
310
- default : return nil
311
- }
312
- }
313
- return nil
314
- }
315
-
316
- mutating func nextAsciiLetter( skippingWhitespace: Bool = false ) -> UInt8 ? {
317
- while let c = self . next ( ) {
318
- if skippingWhitespace {
319
- if c == UInt8 ( ascii: " " ) {
320
- continue
321
- }
322
- }
323
-
324
- switch c {
325
- case UInt8 ( ascii: " A " ) ... UInt8 ( ascii: " Z " ) ,
326
- UInt8 ( ascii: " a " ) ... UInt8 ( ascii: " z " ) :
327
- return c
328
- default : return nil
329
- }
330
- }
331
- return nil
332
- }
333
- }
334
-
335
- extension UInt8 {
336
- var isAsciiLetter : Bool {
337
- switch self {
338
- case UInt8 ( ascii: " A " ) ... UInt8 ( ascii: " Z " ) ,
339
- UInt8 ( ascii: " a " ) ... UInt8 ( ascii: " z " ) :
340
- return true
341
- default : return false
342
- }
343
- }
344
- }
345
-
346
- let monthMap : [ [ UInt8 ] : Int ] = [
347
- Array ( " Jan " . utf8) : 1 ,
348
- Array ( " Feb " . utf8) : 2 ,
349
- Array ( " Mar " . utf8) : 3 ,
350
- Array ( " Apr " . utf8) : 4 ,
351
- Array ( " May " . utf8) : 5 ,
352
- Array ( " Jun " . utf8) : 6 ,
353
- Array ( " Jul " . utf8) : 7 ,
354
- Array ( " Aug " . utf8) : 8 ,
355
- Array ( " Sep " . utf8) : 9 ,
356
- Array ( " Oct " . utf8) : 10 ,
357
- Array ( " Nov " . utf8) : 11 ,
358
- Array ( " Dec " . utf8) : 12 ,
359
- ]
360
132
361
- let timezoneOffsetMap : [ [ UInt8 ] : Int ] = [
362
- Array ( " UTC " . utf8) : 0 ,
363
- Array ( " GMT " . utf8) : 0 ,
364
- Array ( " EDT " . utf8) : - 4 * 60 ,
365
- Array ( " CDT " . utf8) : - 5 * 60 ,
366
- Array ( " MDT " . utf8) : - 6 * 60 ,
367
- Array ( " PDT " . utf8) : - 7 * 60 ,
368
- ]
133
+ }
0 commit comments