Skip to content

Commit 8352d11

Browse files
committed
Fix #34 Throwing on ill formed headers/rows
1 parent 86ad6b6 commit 8352d11

File tree

12 files changed

+65
-19
lines changed

12 files changed

+65
-19
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Steps to reproduce the behavior:
1919
A clear and concise description of what you expected to happen.
2020

2121
## System
22-
- OS: [e.g. macOS 11, iOS 14, Ubuntu 20.04]
23-
- CodableCSV: [e.g. 0.6.5]
22+
- OS: [e.g. macOS 11.2, iOS 14.4, Ubuntu 20.04]
23+
- CodableCSV: [e.g. 0.6.6]
2424
You can check this in your SPM `Package.swift` file (or `Package.resolved` file). Alternatively, go to Xcode's Source Control Navigator (`⌘+2`) and click on `CodableCSV`.
2525

2626
## Additional context

.github/ISSUE_TEMPLATE/question.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ Add any other context about the question here (or delete this section if it is u
1515

1616
## System
1717
Delete section if not applicable
18-
- OS: [e.g. macOS 11, iOS 14, Ubuntu 20.04]
19-
- CodableCSV: [e.g. 0.6.5]
18+
- OS: [e.g. macOS 11.2, iOS 14.4, Ubuntu 20.04]
19+
- CodableCSV: [e.g. 0.6.6]
2020
You can check this in your SPM `Package.swift` file (or `Package.resolved` file). Alternatively, go to Xcode's Source Control Navigator (`⌘+2`) and click on `CodableCSV`.

CodableCSV.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "CodableCSV"
3-
s.version = "0.6.5"
3+
s.version = "0.6.6"
44
s.summary = "Read and write CSV files row-by-row or through Swift's Codable interface."
55
s.description = <<-DESC
66
CodableCSV offers imperative and declarative ways to read and write CSV files. It is extensively configurable and is capable of reading multiple types of entries and write to many outputs.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ You can choose to add the library through SPM or Cocoapods:
3737
let package = Package(
3838
/* Your package name, supported platforms, and generated products go here */
3939
dependencies: [
40-
.package(url: "https://github.com/dehesa/CodableCSV.git", from: "0.6.5")
40+
.package(url: "https://github.com/dehesa/CodableCSV.git", from: "0.6.6")
4141
],
4242
targets: [
4343
.target(name: /* Your target name here */, dependencies: ["CodableCSV"])
@@ -48,7 +48,7 @@ You can choose to add the library through SPM or Cocoapods:
4848
- [Cocoapods](https://cocoapods.org).
4949

5050
```
51-
pod 'CodableCSV', '~> 0.6.5'
51+
pod 'CodableCSV', '~> 0.6.6'
5252
```
5353

5454
</p></details>

sources/declarative/decodable/DecoderLazy.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ extension CSVDecoder {
3535
}
3636

3737
/// Ignores the subsequent row.
38-
public func ignoreRow() {
39-
guard !self._source.isRowAtEnd(index: self._currentIndex) else { return }
38+
public func ignoreRow() throws {
39+
guard try !self._source.isRowAtEnd(index: self._currentIndex) else { return }
4040
self._currentIndex += 1
4141
}
4242
}
@@ -45,7 +45,8 @@ extension CSVDecoder {
4545
extension CSVDecoder.Lazy {
4646
/// Advances to the next row and returns a `LazyDecoder.Row`, or `nil` if no next row exists.
4747
public func next() -> CSVDecoder.Lazy.Row? {
48-
guard !self._source.isRowAtEnd(index: self._currentIndex) else { return nil }
48+
let isAtEnd = (try? self._source.isRowAtEnd(index: self._currentIndex)) ?? false
49+
guard !isAtEnd else { return nil }
4950

5051
defer { self._currentIndex += 1 }
5152
let decoder = ShadowDecoder(source: .passUnretained(self._source), codingPath: [IndexKey(self._currentIndex)])

sources/declarative/decodable/containers/KeyedDecodingContainer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ private extension ShadowDecoder.KeyedContainer {
281281

282282
switch self._focus {
283283
case .row(let rowIndex):
284-
index = (rowIndex, try self._decoder.source._withUnsafeGuaranteedRef({ try $0.fieldIndex(forKey: key, codingPath: self.codingPath) }))
284+
index = (rowIndex, try self._decoder.source._withUnsafeGuaranteedRef { try $0.fieldIndex(forKey: key, codingPath: self.codingPath) })
285285
case .file:
286286
guard let rowIndex = key.intValue else { throw CSVDecoder.Error._invalidRowKey(forKey: key, codingPath: codingPath) }
287287
// Values are only allowed to be decoded directly from a nested container in "file level" if the CSV rows have a single column.

sources/declarative/decodable/containers/SingleValueDecodingContainer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ private extension ShadowDecoder.SingleValueContainer {
265265
return try transform(string) ?> CSVDecoder.Error._invalid(type: T.self, string: string, codingPath: self.codingPath + [IndexKey(0)])
266266
case .file:
267267
// Values are only allowed to be decoded directly from a single value container in "file level" if the CSV file has a single row with a single column.
268-
if $0.isRowAtEnd(index: 1), $0.numExpectedFields == 1 {
268+
if try $0.isRowAtEnd(index: 1), $0.numExpectedFields == 1 {
269269
let string = try $0.field(0, 0)
270270
return try transform(string) ?> CSVDecoder.Error._invalid(type: T.self, string: string, codingPath: self.codingPath + [IndexKey(0), IndexKey(0)])
271271
} else {

sources/declarative/decodable/containers/UnkeyedDecodingContainer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ extension ShadowDecoder {
5757
var isAtEnd: Bool {
5858
self._decoder.source._withUnsafeGuaranteedRef {
5959
switch self._focus {
60-
case .file: return $0.isRowAtEnd(index: self.currentIndex)
60+
case .file: return (try? $0.isRowAtEnd(index: self.currentIndex)) ?? false
6161
case .row: return $0.isFieldAtEnd(index: self.currentIndex)
6262
}
6363
}

sources/declarative/decodable/internal/Source.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,13 @@ extension ShadowDecoder.Source {
100100

101101
/// Boolean indicating whether the given row index is out of bounds (i.e. there are no more elements left to be decoded in the file).
102102
/// - parameter index: The row index being checked.
103-
func isRowAtEnd(index: Int) -> Bool {
103+
func isRowAtEnd(index: Int) throws -> Bool {
104104
var nextIndex = self._reader.rowIndex
105105
guard index >= nextIndex else { return false }
106106

107107
var counter = index - (nextIndex - 1)
108108
while counter > 0 {
109-
guard let row = try? self._reader.readRow() else { return true }
109+
guard let row = try self._reader.readRow() else { return true }
110110
self._buffer.store(row, at: nextIndex)
111111
nextIndex += 1
112112
counter -= 1
@@ -164,9 +164,10 @@ extension ShadowDecoder.Source {
164164
if let index = key.intValue { return index }
165165

166166
let name = key.stringValue
167+
// If the header lookup is empty, build it for next times.
167168
if self._headerLookup.isEmpty {
168169
guard !self.headers.isEmpty else { throw CSVDecoder.Error._emptyHeader(forKey: key, codingPath: codingPath) }
169-
self._headerLookup = try self.headers.lookupDictionary(onCollision: { CSVDecoder.Error._invalidHashableHeader() })
170+
self._headerLookup = try self.headers.lookupDictionary(onCollision: CSVDecoder.Error._invalidHashableHeader)
170171
}
171172

172173
guard let index = self._headerLookup[name.hashValue] else {

sources/declarative/encodable/internal/Sink.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ extension ShadowEncoder.Sink {
159159
// 3. Get the header lookup dictionary (building it if it is the first time accessing it).
160160
if self._headerLookup.isEmpty {
161161
guard !self.configuration.headers.isEmpty else { throw CSVEncoder.Error._emptyHeader(forKey: key, codingPath: codingPath) }
162-
self._headerLookup = try self.configuration.headers.lookupDictionary(onCollision: { CSVEncoder.Error._invalidHashableHeader() })
162+
self._headerLookup = try self.configuration.headers.lookupDictionary(onCollision: CSVEncoder.Error._invalidHashableHeader)
163163
}
164164
// 4. Get the index from the header lookup up and the header name.
165165
guard let index = self._headerLookup[name.hashValue] else {

0 commit comments

Comments
 (0)