@@ -79,12 +79,8 @@ public struct RFC5322DateTimeCoding: Decodable, Sendable {
79
79
80
80
public init ( from decoder: Decoder ) throws {
81
81
let container = try decoder. singleValueContainer ( )
82
- var string = try container. decode ( String . self)
83
- // RFC5322 dates sometimes have the alphabetic version of the timezone in brackets after the numeric version. The date formatter
84
- // fails to parse this so we need to remove this before parsing.
85
- if let bracket = string. firstIndex ( of: " ( " ) {
86
- string = String ( string [ string. startIndex..< bracket] . _timming ( while: { $0. isWhitespace } ) )
87
- }
82
+ let string = try container. decode ( String . self)
83
+
88
84
do {
89
85
self . wrappedValue = try Date ( string, strategy: RFC5322DateStrategy ( ) )
90
86
} catch {
@@ -95,44 +91,6 @@ public struct RFC5322DateTimeCoding: Decodable, Sendable {
95
91
)
96
92
}
97
93
}
98
-
99
- /*private static var dateFormatters: [DateFormatter] {
100
- // rfc5322 dates received in SES mails sometimes do not include the day, so need two dateformatters
101
- // one with a day and one without
102
- let formatterWithDay = DateFormatter()
103
- formatterWithDay.dateFormat = "EEE, d MMM yyy HH:mm:ss z"
104
- formatterWithDay.locale = Locale(identifier: "en_US_POSIX")
105
- let formatterWithoutDay = DateFormatter()
106
- formatterWithoutDay.dateFormat = "d MMM yyy HH:mm:ss z"
107
- formatterWithoutDay.locale = Locale(identifier: "en_US_POSIX")
108
- return [formatterWithDay, formatterWithoutDay]
109
- }*/
110
- }
111
-
112
- extension RangeReplaceableCollection {
113
- func _timming( while predicate: ( Element ) -> Bool ) -> SubSequence {
114
- var idx = startIndex
115
- while idx < endIndex && predicate ( self [ idx] ) {
116
- formIndex ( after: & idx)
117
- }
118
-
119
- let startOfNonTrimmedRange = idx // Points at the first char not in the set
120
- guard startOfNonTrimmedRange != endIndex else {
121
- return self [ endIndex... ]
122
- }
123
-
124
- let beforeEnd = index ( endIndex, offsetBy: - 1 )
125
- guard startOfNonTrimmedRange < beforeEnd else {
126
- return self [ startOfNonTrimmedRange ..< endIndex]
127
- }
128
-
129
- var backIdx = beforeEnd
130
- // No need to bound-check because we've already trimmed from the beginning, so we'd definitely break off of this loop before `backIdx` rewinds before `startIndex`
131
- while predicate ( self [ backIdx] ) {
132
- formIndex ( & backIdx, offsetBy: - 1 )
133
- }
134
- return self [ startOfNonTrimmedRange ... backIdx]
135
- }
136
94
}
137
95
138
96
struct RFC5322DateError : Error { }
@@ -149,23 +107,24 @@ struct RFC5322DateStrategy: ParseStrategy {
149
107
}
150
108
151
109
func components( from input: String ) -> DateComponents ? {
152
- var s = input [ ... ]
153
- return s . withUTF8 { buffer -> DateComponents ? in
154
- // if the 4th character is a comma, then we have a day of the week
155
- guard buffer . count > 5 else { return nil }
156
- var offset = 0
157
- if buffer [ 3 ] == UInt8 ( ascii : " , " ) {
158
- offset = 5
159
- }
110
+ var endIndex = input. endIndex
111
+ // If the date string has a timezone in brackets, we need to remove it before parsing.
112
+ if let bracket = input . firstIndex ( of : " ( " ) {
113
+ endIndex = bracket
114
+ }
115
+ var s = input [ input . startIndex ..< endIndex ]
116
+
117
+ let asciiNumbers = UInt8 ( ascii : " 0 " ) ... UInt8 ( ascii : " 9 " )
160
118
119
+ return s. withUTF8 { buffer -> DateComponents ? in
161
120
func parseDay( _ it: inout UnsafeBufferPointer < UInt8 > . Iterator ) -> Int ? {
162
121
let first = it. next ( )
163
122
let second = it. next ( )
164
123
guard let first = first, let second = second else { return nil }
165
124
166
- guard first >= UInt8 ( ascii : " 0 " ) && first <= UInt8 ( ascii : " 9 " ) else { return nil }
125
+ guard asciiNumbers . contains ( first) else { return nil }
167
126
168
- if second >= UInt8 ( ascii : " 0 " ) && second <= UInt8 ( ascii : " 9 " ) {
127
+ if asciiNumbers . contains ( second) {
169
128
return Int ( first - UInt8( ascii: " 0 " ) ) * 10 + Int( second - UInt8( ascii: " 0 " ) )
170
129
} else {
171
130
return Int ( first - UInt8( ascii: " 0 " ) )
@@ -241,10 +200,15 @@ struct RFC5322DateStrategy: ParseStrategy {
241
200
242
201
var it = buffer. makeIterator ( )
243
202
244
- for _ in 0 ..< offset {
245
- _ = it. next ( )
246
- }
203
+ // if the 4th character is a comma, then we have a day of the week
204
+ guard buffer. count > 5 else { return nil }
247
205
206
+ if buffer [ 3 ] == UInt8 ( ascii: " , " ) {
207
+ for _ in 0 ..< 5 {
208
+ _ = it. next ( )
209
+ }
210
+ }
211
+
248
212
guard let day = parseDay ( & it) else { return nil }
249
213
guard let month = parseMonth ( & it) else { return nil }
250
214
guard let year = parseYear ( & it) else { return nil }
@@ -293,10 +257,9 @@ extension IteratorProtocol where Self.Element == UInt8 {
293
257
continue
294
258
}
295
259
}
296
- if c >= UInt8 ( ascii: " 0 " ) && c <= UInt8 ( ascii: " 9 " ) {
297
- return c
298
- } else {
299
- return nil
260
+ switch c {
261
+ case UInt8 ( ascii: " 0 " ) ... UInt8 ( ascii: " 9 " ) : return c
262
+ default : return nil
300
263
}
301
264
}
302
265
return nil
@@ -309,10 +272,11 @@ extension IteratorProtocol where Self.Element == UInt8 {
309
272
continue
310
273
}
311
274
}
312
- if c >= UInt8 ( ascii: " A " ) && c <= UInt8 ( ascii: " Z " ) || c >= UInt8 ( ascii: " a " ) && c <= UInt8 ( ascii: " z " ) {
313
- return c
314
- } else {
315
- return nil
275
+
276
+ switch c {
277
+ case UInt8 ( ascii: " A " ) ... UInt8 ( ascii: " Z " ) ,
278
+ UInt8 ( ascii: " a " ) ... UInt8 ( ascii: " z " ) : return c
279
+ default : return nil
316
280
}
317
281
}
318
282
return nil
@@ -321,7 +285,11 @@ extension IteratorProtocol where Self.Element == UInt8 {
321
285
322
286
extension UInt8 {
323
287
var isAsciiLetter : Bool {
324
- return self >= UInt8 ( ascii: " A " ) && self <= UInt8 ( ascii: " Z " ) || self >= UInt8 ( ascii: " a " ) && self <= UInt8 ( ascii: " z " )
288
+ switch self {
289
+ case UInt8 ( ascii: " A " ) ... UInt8 ( ascii: " Z " ) ,
290
+ UInt8 ( ascii: " a " ) ... UInt8 ( ascii: " z " ) : return true
291
+ default : return false
292
+ }
325
293
}
326
294
}
327
295
@@ -331,5 +299,11 @@ let monthMap : [Array<UInt8> : Int ] = [
331
299
]
332
300
333
301
let timezoneOffsetMap : [ Array < UInt8 > : Int ] = [
334
- Array ( " UTC " . utf8) : 0 , Array ( " GMT " . utf8) : 0 , Array ( " EDT " . utf8) : - 4 * 60 , Array ( " CDT " . utf8) : - 5 * 60 , Array ( " MDT " . utf8) : - 6 * 60 , Array ( " PDT " . utf8) : - 7 * 60
302
+ Array ( " UTC " . utf8) : 0 ,
303
+ Array ( " GMT " . utf8) : 0 ,
304
+ Array ( " EDT " . utf8) : - 4 * 60 ,
305
+ Array ( " CDT " . utf8) : - 5 * 60 ,
306
+ Array ( " MDT " . utf8) : - 6 * 60 ,
307
+ Array ( " PDT " . utf8) : - 7 * 60 ,
308
+
335
309
]
0 commit comments