Skip to content

Commit d159792

Browse files
committed
adds tests and splits files
1 parent 1e9ef94 commit d159792

File tree

4 files changed

+436
-236
lines changed

4 files changed

+436
-236
lines changed

Sources/AWSLambdaEvents/Utils/DateWrappers.swift

Lines changed: 1 addition & 236 deletions
Original file line numberDiff line numberDiff line change
@@ -129,240 +129,5 @@ public struct RFC5322DateTimeCoding: Decodable, Sendable {
129129
)
130130
}
131131
}
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-
]
360132

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

Comments
 (0)