Skip to content

Commit e756177

Browse files
authored
Merge pull request #16 from josh/decode-sequence
Lazy Sequence Decoder
2 parents ff4cd63 + 1b1e945 commit e756177

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

sources/declarative/decodable/Decoder.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,22 @@ extension CSVDecoder {
6060
let source = ShadowDecoder.Source(reader: reader, configuration: self.configuration, userInfo: self.userInfo)
6161
return try T(from: ShadowDecoder(source: source, codingPath: []))
6262
}
63+
64+
/// Returns a sequence for decoding each row from a CSV file (given as a `Data` blob).
65+
/// - parameter data: The data blob representing a CSV file.
66+
/// - throws: `CSVError<CSVReader>` exclusively.
67+
open func lazy(from data: Data) throws -> LazySequence {
68+
let reader = try CSVReader(input: data, configuration: self.configuration.readerConfiguration)
69+
let source = ShadowDecoder.Source(reader: reader, configuration: self.configuration, userInfo: self.userInfo)
70+
return LazySequence(source: source)
71+
}
72+
73+
/// Returns a sequence for decoding each row from a CSV file (being pointed by `url`).
74+
/// - parameter url: The URL pointing to the file to decode.
75+
/// - throws: `CSVError<CSVReader>` exclusively.
76+
open func lazy(from url: URL) throws -> LazySequence {
77+
let reader = try CSVReader(input: url, configuration: self.configuration.readerConfiguration)
78+
let source = ShadowDecoder.Source(reader: reader, configuration: self.configuration, userInfo: self.userInfo)
79+
return LazySequence(source: source)
80+
}
6381
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
extension CSVDecoder {
2+
public struct LazySequence: IteratorProtocol, Sequence {
3+
private let source: ShadowDecoder.Source
4+
private var currentIndex: Int = 0
5+
6+
init(source: ShadowDecoder.Source) {
7+
self.source = source
8+
}
9+
10+
/// Advances to the next row and returns a `LazySequence.Row`, or `nil` if no next row exists.
11+
public mutating func next() -> Row? {
12+
guard !self.source.isRowAtEnd(index: self.currentIndex) else {
13+
return nil
14+
}
15+
16+
defer { self.currentIndex += 1 }
17+
let decoder = ShadowDecoder(source: source, codingPath: [IndexKey(self.currentIndex)])
18+
return Row(decoder: decoder)
19+
}
20+
21+
public struct Row {
22+
/// The representation of the decoding process point-in-time.
23+
private let decoder: ShadowDecoder
24+
25+
fileprivate init(decoder: ShadowDecoder) {
26+
self.decoder = decoder
27+
}
28+
29+
/// Returns a value of the type you specify, decoded from CSV row.
30+
/// - parameter type: The type of the value to decode from the supplied file.
31+
/// - throws: `DecodingError`, or `CSVError<CSVReader>`, or the error raised by your custom types.
32+
public func decode<T:Decodable>(_ type: T.Type) throws -> T {
33+
return try T(from: decoder)
34+
}
35+
}
36+
}
37+
}

tests/CodableTests/DecodingRegularUsageTests.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ extension DecodingRegularUsageTests {
9191
XCTAssertEqual(pet.gender?.rawValue ?? "", testPet[3])
9292
XCTAssertEqual(pet.animal, testPet[4])
9393
}
94+
95+
for (index, row) in try decoder.lazy(from: input).enumerated() {
96+
let pet = try row.decode(Pet.self)
97+
let testPet = TestData.content[index]
98+
XCTAssertEqual(pet.sequence, Int(testPet[0])!)
99+
XCTAssertEqual(pet.name, testPet[1])
100+
XCTAssertEqual(pet.age, Double(testPet[2])!)
101+
XCTAssertEqual(pet.gender?.rawValue ?? "", testPet[3])
102+
XCTAssertEqual(pet.animal, testPet[4])
103+
}
94104
}
95105
}
96106

0 commit comments

Comments
 (0)