Merge pull request #6 from yaslab/swift-3.0

Swift 3.0 support
This commit is contained in:
Yasuhiro Hatta 2016-09-25 01:32:58 +09:00 committed by GitHub
commit cdeb78d3c0
15 changed files with 164 additions and 141 deletions

View File

@ -1,5 +1,5 @@
language: objective-c language: objective-c
osx_image: xcode7.3 osx_image: xcode8
env: env:
- LC_CTYPE=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8
git: git:

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'CSV.swift' s.name = 'CSV.swift'
s.version = '0.3.1' s.version = '1.0.0'
s.license = 'MIT' s.license = 'MIT'
s.summary = 'CSV reading library written in Swift.' s.summary = 'CSV reading library written in Swift.'
s.homepage = 'https://github.com/yaslab/CSV.swift' s.homepage = 'https://github.com/yaslab/CSV.swift'

View File

@ -396,12 +396,15 @@
TargetAttributes = { TargetAttributes = {
0E7E8C801D0BC7BB0057A1C1 = { 0E7E8C801D0BC7BB0057A1C1 = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
}; };
0E7E8C8A1D0BC7BB0057A1C1 = { 0E7E8C8A1D0BC7BB0057A1C1 = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
}; };
0E7E8CB41D0BC98B0057A1C1 = { 0E7E8CB41D0BC98B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
}; };
0E7E8CC51D0BCA2A0057A1C1 = { 0E7E8CC51D0BCA2A0057A1C1 = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
@ -413,9 +416,11 @@
}; };
0E7E8CE71D0BCD0B0057A1C1 = { 0E7E8CE71D0BCD0B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
}; };
0E7E8CF01D0BCD0B0057A1C1 = { 0E7E8CF01D0BCD0B0057A1C1 = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0800;
}; };
}; };
}; };
@ -650,7 +655,6 @@
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 2.3;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = ""; VERSION_INFO_PREFIX = "";
@ -693,7 +697,6 @@
MACOSX_DEPLOYMENT_TARGET = 10.9; MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_VERSION = 2.3;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
@ -715,6 +718,7 @@
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV; PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
PRODUCT_NAME = CSV; PRODUCT_NAME = CSV;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -733,6 +737,7 @@
PRODUCT_NAME = CSV; PRODUCT_NAME = CSV;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };
@ -743,6 +748,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS"; PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -754,6 +760,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS"; PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };
@ -772,6 +779,7 @@
PRODUCT_NAME = CSV; PRODUCT_NAME = CSV;
SDKROOT = watchos; SDKROOT = watchos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 4; TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 2.0; WATCHOS_DEPLOYMENT_TARGET = 2.0;
}; };
@ -793,6 +801,7 @@
SDKROOT = watchos; SDKROOT = watchos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 4; TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 2.0; WATCHOS_DEPLOYMENT_TARGET = 2.0;
}; };
@ -816,6 +825,7 @@
PRODUCT_NAME = CSV; PRODUCT_NAME = CSV;
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -838,6 +848,7 @@
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };
@ -852,6 +863,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-OSX"; PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-OSX";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_VERSION = 3.0;
}; };
name = Debug; name = Debug;
}; };
@ -867,6 +879,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
}; };
name = Release; name = Release;
}; };
@ -884,6 +897,7 @@
PRODUCT_NAME = CSV; PRODUCT_NAME = CSV;
SDKROOT = appletvos; SDKROOT = appletvos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 3; TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0; TVOS_DEPLOYMENT_TARGET = 9.0;
}; };
@ -904,6 +918,7 @@
SDKROOT = appletvos; SDKROOT = appletvos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 3; TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0; TVOS_DEPLOYMENT_TARGET = 9.0;
}; };
@ -917,6 +932,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-tvOS"; PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-tvOS";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos; SDKROOT = appletvos;
SWIFT_VERSION = 3.0;
TVOS_DEPLOYMENT_TARGET = 9.2; TVOS_DEPLOYMENT_TARGET = 9.2;
}; };
name = Debug; name = Debug;
@ -930,6 +946,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos; SDKROOT = appletvos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TVOS_DEPLOYMENT_TARGET = 9.2; TVOS_DEPLOYMENT_TARGET = 9.2;
}; };
name = Release; name = Release;

View File

@ -75,13 +75,13 @@ let csv = try! CSV(
### CocoaPods ### CocoaPods
```ruby ```ruby
pod 'CSV.swift', '~> 0.3' pod 'CSV.swift', '~> 1.0'
``` ```
### Carthage ### Carthage
``` ```
github "yaslab/CSV.swift" ~> 0.3 github "yaslab/CSV.swift" ~> 1.0
``` ```
### Swift Package Manager ### Swift Package Manager
@ -92,7 +92,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "PackageName", name: "PackageName",
dependencies: [ dependencies: [
.Package(url: "https://github.com/yaslab/CSV.swift", majorVersion: 0, minor: 3) .Package(url: "https://github.com/yaslab/CSV.swift", majorVersion: 1, minor: 0)
] ]
) )
``` ```

View File

@ -6,11 +6,11 @@
// Copyright © 2016 yaslab. All rights reserved. // Copyright © 2016 yaslab. All rights reserved.
// //
internal struct AnyIterator<T>: GeneratorType { internal struct AnyIterator<T>: IteratorProtocol {
private var _base_next: (() -> T?) private var _base_next: (() -> T?)
internal init<U: GeneratorType where U.Element == T>(base: U) { internal init<U: IteratorProtocol>(base: U) where U.Element == T {
var base = base var base = base
_base_next = { base.next() } _base_next = { base.next() }
} }

View File

@ -14,26 +14,26 @@ internal let utf16LittleEndianBOM: [UInt8] = [0xff, 0xfe]
internal let utf32BigEndianBOM: [UInt8] = [0x00, 0x00, 0xfe, 0xff] internal let utf32BigEndianBOM: [UInt8] = [0x00, 0x00, 0xfe, 0xff]
internal let utf32LittleEndianBOM: [UInt8] = [0xff, 0xfe, 0x00, 0x00] internal let utf32LittleEndianBOM: [UInt8] = [0xff, 0xfe, 0x00, 0x00]
private func readBOM(buffer buffer: UnsafePointer<UInt8>, length: Int) -> (Endian, Int)? { private func readBOM(buffer: UnsafePointer<UInt8>, length: Int) -> (Endian, Int)? {
if length >= 4 { if length >= 4 {
if memcmp(buffer, utf32BigEndianBOM, 4) == 0 { if memcmp(buffer, utf32BigEndianBOM, 4) == 0 {
return (.Big, 4) return (.big, 4)
} }
if memcmp(buffer, utf32LittleEndianBOM, 4) == 0 { if memcmp(buffer, utf32LittleEndianBOM, 4) == 0 {
return (.Little, 4) return (.little, 4)
} }
} }
if length >= 3 { if length >= 3 {
if memcmp(buffer, utf8BOM, 3) == 0 { if memcmp(buffer, utf8BOM, 3) == 0 {
return (.Unknown, 3) return (.unknown, 3)
} }
} }
if length >= 2 { if length >= 2 {
if memcmp(buffer, utf16BigEndianBOM, 2) == 0 { if memcmp(buffer, utf16BigEndianBOM, 2) == 0 {
return (.Big, 2) return (.big, 2)
} }
if memcmp(buffer, utf16LittleEndianBOM, 2) == 0 { if memcmp(buffer, utf16LittleEndianBOM, 2) == 0 {
return (.Little, 2) return (.little, 2)
} }
} }
return nil return nil
@ -41,30 +41,30 @@ private func readBOM(buffer buffer: UnsafePointer<UInt8>, length: Int) -> (Endia
internal class BinaryReader { internal class BinaryReader {
private let stream: NSInputStream private let stream: InputStream
private let endian: Endian private let endian: Endian
private let closeOnDeinit: Bool private let closeOnDeinit: Bool
private var buffer = [UInt8](count: 4, repeatedValue: 0) private var buffer = [UInt8](repeating: 0, count: 4)
private var tempBuffer = [UInt8](count: 4, repeatedValue: 0) private var tempBuffer = [UInt8](repeating: 0, count: 4)
private let tempBufferSize = 4 private let tempBufferSize = 4
private var tempBufferOffset = 0 private var tempBufferOffset = 0
internal init(stream: NSInputStream, endian: Endian = .Unknown, closeOnDeinit: Bool = true) throws { internal init(stream: InputStream, endian: Endian = .unknown, closeOnDeinit: Bool = true) throws {
var endian = endian var endian = endian
if stream.streamStatus == .NotOpen { if stream.streamStatus == .notOpen {
stream.open() stream.open()
} }
if stream.streamStatus != .Open { if stream.streamStatus != .open {
throw CSVError.CannotOpenFile throw CSVError.cannotOpenFile
} }
let readCount = stream.read(&tempBuffer, maxLength: tempBufferSize) let readCount = stream.read(&tempBuffer, maxLength: tempBufferSize)
if let (e, l) = readBOM(buffer: &tempBuffer, length: readCount) { if let (e, l) = readBOM(buffer: &tempBuffer, length: readCount) {
if endian != .Unknown && endian != e { if endian != .unknown && endian != e {
throw CSVError.StringEndianMismatch throw CSVError.stringEndianMismatch
} }
endian = e endian = e
tempBufferOffset = l tempBufferOffset = l
@ -76,7 +76,7 @@ internal class BinaryReader {
} }
deinit { deinit {
if closeOnDeinit && stream.streamStatus != .Closed { if closeOnDeinit && stream.streamStatus != .closed {
stream.close() stream.close()
} }
} }
@ -85,9 +85,9 @@ internal class BinaryReader {
return stream.hasBytesAvailable return stream.hasBytesAvailable
} }
private func readStream(buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) throws -> Int { private func readStream(_ buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) throws -> Int {
if stream.streamStatus != .Open { if stream.streamStatus != .open {
throw CSVError.CannotReadFile throw CSVError.cannotReadFile
} }
var i = 0 var i = 0
@ -106,10 +106,10 @@ internal class BinaryReader {
let bufferSize = 1 let bufferSize = 1
let length = try readStream(&buffer, maxLength: bufferSize) let length = try readStream(&buffer, maxLength: bufferSize)
if length < 0 { if length < 0 {
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!) throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
} }
if length != bufferSize { if length != bufferSize {
throw CSVError.CannotReadFile throw CSVError.cannotReadFile
} }
return buffer[0] return buffer[0]
} }
@ -118,19 +118,20 @@ internal class BinaryReader {
let bufferSize = 2 let bufferSize = 2
let length = try readStream(&buffer, maxLength: bufferSize) let length = try readStream(&buffer, maxLength: bufferSize)
if length < 0 { if length < 0 {
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!) throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
} }
if length != bufferSize { if length != bufferSize {
throw CSVError.StringEncodingMismatch throw CSVError.stringEncodingMismatch
} }
let tmp = UnsafeMutablePointer<UInt16>(buffer) return try UnsafePointer(buffer).withMemoryRebound(to: UInt16.self, capacity: 1) {
switch endian { switch endian {
case .Big: case .big:
return CFSwapInt16BigToHost(tmp[0]) return CFSwapInt16BigToHost($0[0])
case .Little: case .little:
return CFSwapInt16LittleToHost(tmp[0]) return CFSwapInt16LittleToHost($0[0])
default: default:
throw CSVError.StringEndianMismatch throw CSVError.stringEndianMismatch
}
} }
} }
@ -138,19 +139,20 @@ internal class BinaryReader {
let bufferSize = 4 let bufferSize = 4
let length = try readStream(&buffer, maxLength: bufferSize) let length = try readStream(&buffer, maxLength: bufferSize)
if length < 0 { if length < 0 {
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!) throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
} }
if length != 4 { if length != 4 {
throw CSVError.StringEncodingMismatch throw CSVError.stringEncodingMismatch
} }
let tmp = UnsafeMutablePointer<UInt32>(buffer) return try UnsafePointer(buffer).withMemoryRebound(to: UInt32.self, capacity: 1) {
switch endian { switch endian {
case .Big: case .big:
return CFSwapInt32BigToHost(tmp[0]) return CFSwapInt32BigToHost($0[0])
case .Little: case .little:
return CFSwapInt32LittleToHost(tmp[0]) return CFSwapInt32LittleToHost($0[0])
default: default:
throw CSVError.StringEndianMismatch throw CSVError.stringEndianMismatch
}
} }
} }
@ -158,11 +160,11 @@ internal class BinaryReader {
extension BinaryReader { extension BinaryReader {
internal struct UInt8Iterator: SequenceType, GeneratorType { internal struct UInt8Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader private let reader: BinaryReader
private init(reader: BinaryReader) { fileprivate init(reader: BinaryReader) {
self.reader = reader self.reader = reader
} }
@ -188,11 +190,11 @@ extension BinaryReader {
extension BinaryReader { extension BinaryReader {
internal struct UInt16Iterator: SequenceType, GeneratorType { internal struct UInt16Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader private let reader: BinaryReader
private init(reader: BinaryReader) { fileprivate init(reader: BinaryReader) {
self.reader = reader self.reader = reader
} }
@ -218,11 +220,11 @@ extension BinaryReader {
extension BinaryReader { extension BinaryReader {
internal struct UInt32Iterator: SequenceType, GeneratorType { internal struct UInt32Iterator: Sequence, IteratorProtocol {
private let reader: BinaryReader private let reader: BinaryReader
private init(reader: BinaryReader) { fileprivate init(reader: BinaryReader) {
self.reader = reader self.reader = reader
} }

View File

@ -11,7 +11,7 @@ import Foundation
extension CSV { extension CSV {
public init( public init(
stream: NSInputStream, stream: InputStream,
hasHeaderRow: Bool = defaultHasHeaderRow, hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter) delimiter: UnicodeScalar = defaultDelimiter)
throws throws
@ -29,7 +29,7 @@ extension CSV {
delimiter: UnicodeScalar = defaultDelimiter) delimiter: UnicodeScalar = defaultDelimiter)
throws throws
{ {
let iterator = string.unicodeScalars.generate() let iterator = string.unicodeScalars.makeIterator()
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter) try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
} }

View File

@ -13,7 +13,7 @@ extension CSV {
guard let headerRow = headerRow, let currentRow = currentRow else { guard let headerRow = headerRow, let currentRow = currentRow else {
return nil return nil
} }
guard let index = headerRow.indexOf(key) else { guard let index = headerRow.index(of: key) else {
return nil return nil
} }
if index >= currentRow.count { if index >= currentRow.count {

View File

@ -8,14 +8,14 @@
import Foundation import Foundation
private let LF = "\n".unicodeScalars.first! private let LF = UnicodeScalar("\n")!
private let CR = "\r".unicodeScalars.first! private let CR = UnicodeScalar("\r")!
private let DQUOTE = "\"".unicodeScalars.first! private let DQUOTE = UnicodeScalar("\"")!
internal let defaultHasHeaderRow = false internal let defaultHasHeaderRow = false
internal let defaultDelimiter = ",".unicodeScalars.first! internal let defaultDelimiter = UnicodeScalar(",")!
public struct CSV: GeneratorType, SequenceType { public struct CSV: IteratorProtocol, Sequence {
private var iterator: AnyIterator<UnicodeScalar> private var iterator: AnyIterator<UnicodeScalar>
private let delimiter: UnicodeScalar private let delimiter: UnicodeScalar
@ -28,18 +28,18 @@ public struct CSV: GeneratorType, SequenceType {
public var headerRow: [String]? { return _headerRow } public var headerRow: [String]? { return _headerRow }
private var _headerRow: [String]? = nil private var _headerRow: [String]? = nil
internal init<T: GeneratorType where T.Element == UnicodeScalar>( internal init<T: IteratorProtocol>(
iterator: T, iterator: T,
hasHeaderRow: Bool, hasHeaderRow: Bool,
delimiter: UnicodeScalar) delimiter: UnicodeScalar)
throws throws where T.Element == UnicodeScalar
{ {
self.iterator = AnyIterator(base: iterator) self.iterator = AnyIterator(base: iterator)
self.delimiter = delimiter self.delimiter = delimiter
if hasHeaderRow { if hasHeaderRow {
guard let headerRow = next() else { guard let headerRow = next() else {
throw CSVError.CannotReadHeaderRow throw CSVError.cannotReadHeaderRow
} }
_headerRow = headerRow _headerRow = headerRow
} }
@ -51,14 +51,15 @@ public struct CSV: GeneratorType, SequenceType {
/// - parameter codecType: A `UnicodeCodec` type for `stream`. /// - parameter codecType: A `UnicodeCodec` type for `stream`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`. /// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`. /// - parameter delimiter: Default: `","`.
public init<T: UnicodeCodecType where T.CodeUnit == UInt8>( public init<T: UnicodeCodec>(
stream: NSInputStream, stream: InputStream,
codecType: T.Type, codecType: T.Type,
hasHeaderRow: Bool = defaultHasHeaderRow, hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter) delimiter: UnicodeScalar = defaultDelimiter)
throws throws
where T.CodeUnit == UInt8
{ {
let reader = try BinaryReader(stream: stream, endian: .Unknown, closeOnDeinit: true) let reader = try BinaryReader(stream: stream, endian: .unknown, closeOnDeinit: true)
let iterator = UnicodeIterator(input: reader.makeUInt8Iterator(), inputEncodingType: codecType) let iterator = UnicodeIterator(input: reader.makeUInt8Iterator(), inputEncodingType: codecType)
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter) try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
} }
@ -70,13 +71,14 @@ public struct CSV: GeneratorType, SequenceType {
/// - parameter endian: Endian to use when reading a stream. Default: `.big`. /// - parameter endian: Endian to use when reading a stream. Default: `.big`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`. /// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`. /// - parameter delimiter: Default: `","`.
public init<T: UnicodeCodecType where T.CodeUnit == UInt16>( public init<T: UnicodeCodec>(
stream: NSInputStream, stream: InputStream,
codecType: T.Type, codecType: T.Type,
endian: Endian = .Big, endian: Endian = .big,
hasHeaderRow: Bool = defaultHasHeaderRow, hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter) delimiter: UnicodeScalar = defaultDelimiter)
throws throws
where T.CodeUnit == UInt16
{ {
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true) let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
let iterator = UnicodeIterator(input: reader.makeUInt16Iterator(), inputEncodingType: codecType) let iterator = UnicodeIterator(input: reader.makeUInt16Iterator(), inputEncodingType: codecType)
@ -90,13 +92,14 @@ public struct CSV: GeneratorType, SequenceType {
/// - parameter endian: Endian to use when reading a stream. Default: `.big`. /// - parameter endian: Endian to use when reading a stream. Default: `.big`.
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`. /// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
/// - parameter delimiter: Default: `","`. /// - parameter delimiter: Default: `","`.
public init<T: UnicodeCodecType where T.CodeUnit == UInt32>( public init<T: UnicodeCodec>(
stream: NSInputStream, stream: InputStream,
codecType: T.Type, codecType: T.Type,
endian: Endian = .Big, endian: Endian = .big,
hasHeaderRow: Bool = defaultHasHeaderRow, hasHeaderRow: Bool = defaultHasHeaderRow,
delimiter: UnicodeScalar = defaultDelimiter) delimiter: UnicodeScalar = defaultDelimiter)
throws throws
where T.CodeUnit == UInt32
{ {
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true) let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
let iterator = UnicodeIterator(input: reader.makeUInt32Iterator(), inputEncodingType: codecType) let iterator = UnicodeIterator(input: reader.makeUInt32Iterator(), inputEncodingType: codecType)
@ -178,7 +181,7 @@ public struct CSV: GeneratorType, SequenceType {
return row return row
} }
internal mutating func readField(quoted quoted: Bool) -> (String, Bool) { internal mutating func readField(quoted: Bool) -> (String, Bool) {
var field = "" var field = ""
var next = moveNext() var next = moveNext()
@ -202,15 +205,15 @@ public struct CSV: GeneratorType, SequenceType {
} }
else if cNext == DQUOTE { else if cNext == DQUOTE {
// ESC // ESC
field.append(DQUOTE) field.append(String(DQUOTE))
} }
else { else {
// ERROR?? // ERROR??
field.append(c) field.append(String(c))
} }
} }
else { else {
field.append(c) field.append(String(c))
} }
} }
else { else {
@ -229,7 +232,7 @@ public struct CSV: GeneratorType, SequenceType {
return (field, false) return (field, false)
} }
else { else {
field.append(c) field.append(String(c))
} }
} }

View File

@ -8,11 +8,11 @@
import Foundation import Foundation
public enum CSVError: ErrorType { public enum CSVError: Error {
case CannotOpenFile case cannotOpenFile
case CannotReadFile case cannotReadFile
case StreamErrorHasOccurred(error: NSError) case streamErrorHasOccurred(error: Error)
case CannotReadHeaderRow case cannotReadHeaderRow
case StringEncodingMismatch case stringEncodingMismatch
case StringEndianMismatch case stringEndianMismatch
} }

View File

@ -7,7 +7,7 @@
// //
public enum Endian { public enum Endian {
case Big case big
case Little case little
case Unknown case unknown
} }

View File

@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.3.1</string> <string>1.0.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>

View File

@ -7,10 +7,10 @@
// //
internal struct UnicodeIterator< internal struct UnicodeIterator<
Input: GeneratorType, Input: IteratorProtocol,
InputEncoding: UnicodeCodecType InputEncoding: UnicodeCodec>
where InputEncoding.CodeUnit == Input.Element> : IteratorProtocol
: GeneratorType { where InputEncoding.CodeUnit == Input.Element {
private var input: Input private var input: Input
private var inputEncoding: InputEncoding private var inputEncoding: InputEncoding
@ -22,9 +22,9 @@ internal struct UnicodeIterator<
internal mutating func next() -> UnicodeScalar? { internal mutating func next() -> UnicodeScalar? {
switch inputEncoding.decode(&input) { switch inputEncoding.decode(&input) {
case .Result(let c): return c case .scalarValue(let c): return c
case .EmptyInput: return nil case .emptyInput: return nil
case .Error: return nil case .error: return nil
} }
} }

View File

@ -6,6 +6,7 @@
// //
// //
import Foundation
import XCTest import XCTest
@testable import CSV @testable import CSV
@ -161,11 +162,11 @@ class CSVReaderTests: XCTestCase {
func testUTF8WithBOM() { func testUTF8WithBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\"," let csvString = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF8StringEncoding let encoding = String.Encoding.utf8
var mutableData = NSMutableData() var mutableData = Data()
mutableData.appendBytes(utf8BOM, length: utf8BOM.count) mutableData.append(utf8BOM, count: utf8BOM.count)
mutableData.appendData(csvString.dataUsingEncoding(encoding)!) mutableData.append(csvString.data(using: encoding)!)
let stream = NSInputStream(data: mutableData) let stream = InputStream(data: mutableData)
let csv = try! CSV(stream: stream, codecType: UTF8.self) let csv = try! CSV(stream: stream, codecType: UTF8.self)
let records = getRecords(csv: csv) let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"]) XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
@ -174,11 +175,11 @@ class CSVReaderTests: XCTestCase {
func testUTF16WithNativeEndianBOM() { func testUTF16WithNativeEndianBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv,😆asdf,\"qw\"\"er\"," let csvString = "abab,,cdcd,efef\r\nzxcv,😆asdf,\"qw\"\"er\","
let encoding = NSUTF16StringEncoding let encoding = String.Encoding.utf16
var mutableData = NSMutableData() var mutableData = Data()
mutableData.appendData(csvString.dataUsingEncoding(encoding)!) mutableData.append(csvString.data(using: encoding)!)
let stream = NSInputStream(data: mutableData) let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .Unknown) let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .unknown)
let records = getRecords(csv: csv) let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"]) XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "😆asdf", "qw\"er", ""]) XCTAssertEqual(records[1], ["zxcv", "😆asdf", "qw\"er", ""])
@ -186,12 +187,12 @@ class CSVReaderTests: XCTestCase {
func testUTF16WithBigEndianBOM() { func testUTF16WithBigEndianBOM() {
let csvString = "abab,,cdcd,efef\r\n😆zxcv,asdf,\"qw\"\"er\"," let csvString = "abab,,cdcd,efef\r\n😆zxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF16BigEndianStringEncoding let encoding = String.Encoding.utf16BigEndian
var mutableData = NSMutableData() var mutableData = Data()
mutableData.appendBytes(utf16BigEndianBOM, length: utf16BigEndianBOM.count) mutableData.append(utf16BigEndianBOM, count: utf16BigEndianBOM.count)
mutableData.appendData(csvString.dataUsingEncoding(encoding)!) mutableData.append(csvString.data(using: encoding)!)
let stream = NSInputStream(data: mutableData) let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .Big) let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .big)
let records = getRecords(csv: csv) let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"]) XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["😆zxcv", "asdf", "qw\"er", ""]) XCTAssertEqual(records[1], ["😆zxcv", "asdf", "qw\"er", ""])
@ -199,12 +200,12 @@ class CSVReaderTests: XCTestCase {
func testUTF16WithLittleEndianBOM() { func testUTF16WithLittleEndianBOM() {
let csvString = "abab,,cdcd,efef\r\nzxcv😆,asdf,\"qw\"\"er\"," let csvString = "abab,,cdcd,efef\r\nzxcv😆,asdf,\"qw\"\"er\","
let encoding = NSUTF16LittleEndianStringEncoding let encoding = String.Encoding.utf16LittleEndian
var mutableData = NSMutableData() var mutableData = Data()
mutableData.appendBytes(utf16LittleEndianBOM, length: utf16LittleEndianBOM.count) mutableData.append(utf16LittleEndianBOM, count: utf16LittleEndianBOM.count)
mutableData.appendData(csvString.dataUsingEncoding(encoding)!) mutableData.append(csvString.data(using: encoding)!)
let stream = NSInputStream(data: mutableData) let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .Little) let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .little)
let records = getRecords(csv: csv) let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"]) XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv😆", "asdf", "qw\"er", ""]) XCTAssertEqual(records[1], ["zxcv😆", "asdf", "qw\"er", ""])
@ -212,11 +213,11 @@ class CSVReaderTests: XCTestCase {
func testUTF32WithNativeEndianBOM() { func testUTF32WithNativeEndianBOM() {
let csvString = "😆abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\"," let csvString = "😆abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF32StringEncoding let encoding = String.Encoding.utf32
var mutableData = NSMutableData() var mutableData = Data()
mutableData.appendData(csvString.dataUsingEncoding(encoding)!) mutableData.append(csvString.data(using: encoding)!)
let stream = NSInputStream(data: mutableData) let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .Unknown) let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .unknown)
let records = getRecords(csv: csv) let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["😆abab", "", "cdcd", "efef"]) XCTAssertEqual(records[0], ["😆abab", "", "cdcd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""]) XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
@ -224,12 +225,12 @@ class CSVReaderTests: XCTestCase {
func testUTF32WithBigEndianBOM() { func testUTF32WithBigEndianBOM() {
let csvString = "abab,,cd😆cd,efef\r\nzxcv,asdf,\"qw\"\"er\"," let csvString = "abab,,cd😆cd,efef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF32BigEndianStringEncoding let encoding = String.Encoding.utf32BigEndian
var mutableData = NSMutableData() var mutableData = Data()
mutableData.appendBytes(utf32BigEndianBOM, length: utf32BigEndianBOM.count) mutableData.append(utf32BigEndianBOM, count: utf32BigEndianBOM.count)
mutableData.appendData(csvString.dataUsingEncoding(encoding)!) mutableData.append(csvString.data(using: encoding)!)
let stream = NSInputStream(data: mutableData) let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .Big) let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .big)
let records = getRecords(csv: csv) let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cd😆cd", "efef"]) XCTAssertEqual(records[0], ["abab", "", "cd😆cd", "efef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""]) XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
@ -237,12 +238,12 @@ class CSVReaderTests: XCTestCase {
func testUTF32WithLittleEndianBOM() { func testUTF32WithLittleEndianBOM() {
let csvString = "abab,,cdcd,ef😆ef\r\nzxcv,asdf,\"qw\"\"er\"," let csvString = "abab,,cdcd,ef😆ef\r\nzxcv,asdf,\"qw\"\"er\","
let encoding = NSUTF32LittleEndianStringEncoding let encoding = String.Encoding.utf32LittleEndian
var mutableData = NSMutableData() var mutableData = Data()
mutableData.appendBytes(utf32LittleEndianBOM, length: utf32LittleEndianBOM.count) mutableData.append(utf32LittleEndianBOM, count: utf32LittleEndianBOM.count)
mutableData.appendData(csvString.dataUsingEncoding(encoding)!) mutableData.append(csvString.data(using: encoding)!)
let stream = NSInputStream(data: mutableData) let stream = InputStream(data: mutableData as Data)
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .Little) let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .little)
let records = getRecords(csv: csv) let records = getRecords(csv: csv)
XCTAssertEqual(records[0], ["abab", "", "cdcd", "ef😆ef"]) XCTAssertEqual(records[0], ["abab", "", "cdcd", "ef😆ef"])
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""]) XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
@ -262,7 +263,7 @@ class CSVReaderTests: XCTestCase {
// ] // ]
// } // }
func parse(csv csv: String) -> [[String]] { func parse(csv: String) -> [[String]] {
let reader = try! CSV(string: csv) let reader = try! CSV(string: csv)
var records = [[String]]() var records = [[String]]()
for row in reader { for row in reader {
@ -271,7 +272,7 @@ class CSVReaderTests: XCTestCase {
return records return records
} }
func getRecords(csv csv: CSV) -> [[String]] { func getRecords(csv: CSV) -> [[String]] {
var records = [[String]]() var records = [[String]]()
for row in csv { for row in csv {
records.append(row) records.append(row)

View File

@ -162,7 +162,7 @@ class CSVTests: XCTestCase {
} }
func testCSVState1() { func testCSVState1() {
let it = "あ,い1,\"\",えお\n,,x,".unicodeScalars.generate() let it = "あ,い1,\"\",えお\n,,x,".unicodeScalars.makeIterator()
var csv = try! CSV(iterator: it, hasHeaderRow: defaultHasHeaderRow, delimiter: defaultDelimiter) var csv = try! CSV(iterator: it, hasHeaderRow: defaultHasHeaderRow, delimiter: defaultDelimiter)
var rows = [[String]]() var rows = [[String]]()