├── .gitignore ├── .swift-version ├── .travis.yml ├── C7.podspec ├── LICENSE ├── Package.swift ├── README.md ├── Sources ├── AsyncConnection.swift ├── AsyncDrain.swift ├── AsyncHost.swift ├── AsyncStream.swift ├── AsyncURIConnection.swift ├── Byte.swift ├── C7.swift ├── CaseInsensitiveString.swift ├── Closable.swift ├── Connection.swift ├── CustomDataStore.swift ├── Data.swift ├── Drain.swift ├── Host.swift ├── JSON.swift ├── Number.swift ├── Stream.swift ├── StreamError.swift ├── StreamSequence.swift ├── StructuredData.swift ├── Time.swift ├── URI.swift └── URIConnection.swift ├── Tests ├── C7Tests │ └── ExampleTests.swift └── LinuxMain.swift └── swiftenv-install.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | Xcode 5 | xcuserdata 6 | *.xcodeproj 7 | Build 8 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | DEVELOPMENT-SNAPSHOT-2016-08-04-a 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | - osx 4 | language: generic 5 | sudo: required 6 | dist: trusty 7 | osx_image: xcode8 8 | install: 9 | - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/02090c7ede5a637b76e6df1710e83cd0bbe7dcdf/swiftenv-install.sh)" 10 | script: 11 | - swift build 12 | - swift build --configuration release 13 | - swift test -------------------------------------------------------------------------------- /C7.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'C7' 3 | s.version = '0.1.12' 4 | s.license = 'MIT' 5 | s.homepage = 'https://github.com/SwiftX/C7' 6 | s.authors = { 'Logan Wright' => 'logan.william.wright@gmail.com', 7 | 'Paulo Faria' => 'paulo.faria.rl@gmail.com' } 8 | s.summary = 'Core standards for Swift.' 9 | s.source = { :git => 'https://github.com/SwiftX/C7.git', :tag => s.version } 10 | 11 | s.ios.deployment_target = '8.0' 12 | s.osx.deployment_target = '10.9' 13 | s.tvos.deployment_target = '9.0' 14 | s.watchos.deployment_target = '2.0' 15 | 16 | s.source_files = 'Sources/*.swift' 17 | end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Swift X 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // Package.swift 2 | // 3 | // The MIT License (MIT) 4 | // 5 | // Copyright (c) 2015 SwiftX 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all 15 | // copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | // SOFTWARE. 24 | 25 | import PackageDescription 26 | 27 | let package = Package( 28 | name: "C7" 29 | ) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C7 - Core 2 | 3 | [![Slack][slack-badge]][slack-url] 4 | 5 | Core standards for Swift. 6 | 7 | ## Installation 8 | 9 | - Add `C7` to your `Package.swift` 10 | 11 | ```swift 12 | import PackageDescription 13 | 14 | let package = Package( 15 | dependencies: [ 16 | .Package(url: "https://github.com/open-swift/C7.git", majorVersion: 0, minor: 10) 17 | ] 18 | ) 19 | ``` 20 | 21 | License 22 | ------- 23 | 24 | **C7** is released under the MIT license. See LICENSE for details. 25 | 26 | [slack-badge]: http://slack.swiftx.io/badge.svg 27 | [slack-url]: http://slack.swiftx.io 28 | -------------------------------------------------------------------------------- /Sources/AsyncConnection.swift: -------------------------------------------------------------------------------- 1 | public protocol AsyncConnection: AsyncStream { 2 | func open(timingOut deadline: Double, completion: @escaping ((Void) throws -> AsyncConnection) -> Void) throws 3 | } 4 | 5 | extension AsyncConnection { 6 | public func open(completion: @escaping ((Void) throws -> AsyncConnection) -> Void) throws { 7 | try open(timingOut: .never, completion: completion) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/AsyncDrain.swift: -------------------------------------------------------------------------------- 1 | public final class AsyncDrain: DataRepresentable, AsyncStream { 2 | 3 | var buffer: Data = [] 4 | public var closed = false 5 | 6 | public var data: Data { 7 | if !closed { 8 | return buffer 9 | } 10 | return [] 11 | } 12 | 13 | public convenience init() { 14 | self.init(for: []) 15 | } 16 | 17 | public init(for stream: AsyncReceivingStream, timingOut deadline: Double = .never, completion: @escaping ((Void) throws -> AsyncDrain) -> Void) { 18 | var buffer: Data = [] 19 | 20 | if stream.closed { 21 | self.closed = true 22 | completion { 23 | self 24 | } 25 | return 26 | } 27 | 28 | stream.receive(upTo: 1024, timingOut: deadline) { [unowned self] getData in 29 | do { 30 | let chunk = try getData() 31 | buffer.bytes += chunk.bytes 32 | } catch { 33 | completion { 34 | throw error 35 | } 36 | } 37 | 38 | if stream.closed { 39 | self.buffer = buffer 40 | completion { 41 | self 42 | } 43 | } 44 | } 45 | } 46 | 47 | public init(for buffer: Data) { 48 | self.buffer = buffer 49 | } 50 | 51 | public convenience init(for buffer: DataRepresentable) { 52 | self.init(for: buffer.data) 53 | } 54 | 55 | public func close() throws { 56 | guard !closed else { 57 | throw ClosableError.alreadyClosed 58 | } 59 | closed = true 60 | } 61 | 62 | public func receive(upTo byteCount: Int, timingOut deadline: Double = .never, completion: @escaping ((Void) throws -> Data) -> Void) { 63 | if byteCount >= buffer.count { 64 | completion { [unowned self] in 65 | try self.close() 66 | return self.buffer 67 | } 68 | return 69 | } 70 | 71 | let data = buffer[0.. Void) -> Void) { 80 | buffer += data.bytes 81 | completion {} 82 | } 83 | 84 | public func flush(timingOut deadline: Double = .never, completion: @escaping ((Void) throws -> Void) -> Void) { 85 | buffer = [] 86 | completion {} 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Sources/AsyncHost.swift: -------------------------------------------------------------------------------- 1 | public protocol AsyncHost { 2 | func accept(timingOut deadline: Double, completion: @escaping ((Void) throws -> AsyncStream) -> Void) 3 | } 4 | 5 | extension AsyncHost { 6 | public func accept(completion: @escaping ((Void) throws -> AsyncStream) -> Void) { 7 | accept(timingOut: .never, completion: completion) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/AsyncStream.swift: -------------------------------------------------------------------------------- 1 | public protocol AsyncSending { 2 | func send(_ data: Data, timingOut deadline: Double, completion: @escaping ((Void) throws -> Void) -> Void) 3 | func flush(timingOut deadline: Double, completion: @escaping ((Void) throws -> Void) -> Void) 4 | } 5 | 6 | public protocol AsyncReceiving { 7 | func receive(upTo byteCount: Int, timingOut deadline: Double, completion: @escaping ((Void) throws -> Data) -> Void) 8 | } 9 | 10 | public protocol AsyncSendingStream: Closable, AsyncSending {} 11 | public protocol AsyncReceivingStream: Closable, AsyncReceiving {} 12 | public protocol AsyncStream: AsyncSendingStream, AsyncReceivingStream {} 13 | 14 | extension AsyncSending { 15 | public func send(_ data: Data, completion: @escaping ((Void) throws -> Void) -> Void) { 16 | send(data, timingOut: .never, completion: completion) 17 | } 18 | public func flush(completion: @escaping ((Void) throws -> Void) -> Void) { 19 | flush(timingOut: .never, completion: completion) 20 | } 21 | } 22 | 23 | extension AsyncReceiving { 24 | public func receive(upTo byteCount: Int, completion: @escaping ((Void) throws -> Data) -> Void) { 25 | receive(upTo: byteCount, timingOut: .never, completion: completion) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/AsyncURIConnection.swift: -------------------------------------------------------------------------------- 1 | public protocol AsyncURIConnection: AsyncConnection { 2 | init(to uri: URI) throws 3 | var uri: URI { get } 4 | } 5 | -------------------------------------------------------------------------------- /Sources/Byte.swift: -------------------------------------------------------------------------------- 1 | public typealias Byte = UInt8 2 | -------------------------------------------------------------------------------- /Sources/C7.swift: -------------------------------------------------------------------------------- 1 | #if swift(>=3.0) 2 | #else 3 | public typealias ErrorProtocol = ErrorType 4 | public typealias RangeReplaceableCollection = RangeReplaceableCollectionType 5 | public typealias MutableCollection = MutableCollectionType 6 | public typealias Sequence = SequenceType 7 | #endif 8 | -------------------------------------------------------------------------------- /Sources/CaseInsensitiveString.swift: -------------------------------------------------------------------------------- 1 | public struct CaseInsensitiveString { 2 | public let string: String 3 | 4 | public init(_ string: String) { 5 | self.string = string 6 | } 7 | } 8 | 9 | extension CaseInsensitiveString: Hashable { 10 | #if swift(>=3.0) 11 | public var hashValue: Int { 12 | return string.lowercased().hashValue 13 | } 14 | #else 15 | public var hashValue: Int { 16 | return string.lowercaseString.hashValue 17 | } 18 | #endif 19 | } 20 | 21 | #if swift(>=3.0) 22 | public func == (lhs: CaseInsensitiveString, rhs: CaseInsensitiveString) -> Bool { 23 | return lhs.string.lowercased() == rhs.string.lowercased() 24 | } 25 | #else 26 | public func == (lhs: CaseInsensitiveString, rhs: CaseInsensitiveString) -> Bool { 27 | return lhs.string.lowercaseString == rhs.string.lowercaseString 28 | } 29 | #endif 30 | 31 | extension CaseInsensitiveString: ExpressibleByStringLiteral { 32 | public init(stringLiteral string: String) { 33 | self.init(string) 34 | } 35 | 36 | public init(extendedGraphemeClusterLiteral string: String){ 37 | self.init(string) 38 | } 39 | 40 | public init(unicodeScalarLiteral string: String){ 41 | self.init(string) 42 | } 43 | } 44 | 45 | extension CaseInsensitiveString: CustomStringConvertible { 46 | public var description: String { 47 | return string 48 | } 49 | } 50 | 51 | extension String { 52 | var caseInsensitive: CaseInsensitiveString { 53 | return CaseInsensitiveString(self) 54 | } 55 | } 56 | 57 | public protocol CaseInsensitiveStringRepresentable { 58 | var caseInsensitiveString: CaseInsensitiveString { get } 59 | } 60 | 61 | extension String: CaseInsensitiveStringRepresentable { 62 | public var caseInsensitiveString: CaseInsensitiveString { 63 | return CaseInsensitiveString(self) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sources/Closable.swift: -------------------------------------------------------------------------------- 1 | public protocol Closable { 2 | var closed: Bool { get } 3 | func close() throws 4 | } 5 | 6 | public enum ClosableError: Error { 7 | case alreadyClosed 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Connection.swift: -------------------------------------------------------------------------------- 1 | public protocol Connection: Stream { 2 | func open(timingOut deadline: Double) throws 3 | } 4 | 5 | extension Connection { 6 | public func open() throws { 7 | try open(timingOut: .never) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/CustomDataStore.swift: -------------------------------------------------------------------------------- 1 | public protocol CustomDataStore { 2 | var storage: [String: Any] { get set } 3 | } 4 | -------------------------------------------------------------------------------- /Sources/Data.swift: -------------------------------------------------------------------------------- 1 | public struct Data { 2 | public var bytes: [Byte] 3 | 4 | public init(_ bytes: [Byte]) { 5 | self.bytes = bytes 6 | } 7 | } 8 | 9 | public protocol DataInitializable { 10 | init(data: Data) throws 11 | } 12 | 13 | public protocol DataRepresentable { 14 | var data: Data { get } 15 | } 16 | 17 | public protocol DataConvertible: DataInitializable, DataRepresentable {} 18 | 19 | extension Data { 20 | public init(_ string: String) { 21 | self.init([Byte](string.utf8)) 22 | } 23 | } 24 | 25 | extension Data { 26 | public init(_ slice: ArraySlice) { 27 | self.init(Array(slice)) 28 | } 29 | } 30 | 31 | extension Data: RangeReplaceableCollection, MutableCollection { 32 | public init() { 33 | self.init([]) 34 | } 35 | 36 | #if swift(>=3.0) 37 | public init(_ elements: S) where S.Iterator.Element == Byte { 38 | self.init(Array(elements)) 39 | } 40 | #else 41 | public init(_ elements: S) { 42 | self.init(Array(elements)) 43 | } 44 | #endif 45 | 46 | #if swift(>=3.0) 47 | public mutating func replaceSubrange(_ subRange: Range, with newElements: C) where C.Iterator.Element == Byte { 48 | self.bytes.replaceSubrange(subRange, with: newElements) 49 | } 50 | #else 51 | public mutating func replaceRange(subRange: Range, with newElements: C) { 52 | self.bytes.replaceRange(subRange, with: newElements) 53 | } 54 | #endif 55 | 56 | #if swift(>=3.0) 57 | public func makeIterator() -> IndexingIterator<[Byte]> { 58 | return bytes.makeIterator() 59 | } 60 | #else 61 | public func generate() -> IndexingGenerator<[Byte]> { 62 | return bytes.generate() 63 | } 64 | #endif 65 | 66 | public var startIndex: Int { 67 | return bytes.startIndex 68 | } 69 | 70 | public var endIndex: Int { 71 | return bytes.endIndex 72 | } 73 | 74 | public func index(after i: Int) -> Int { 75 | return i + 1 76 | } 77 | 78 | public subscript(index: Int) -> Byte { 79 | get { 80 | return bytes[index] 81 | } 82 | 83 | set(value) { 84 | bytes[index] = value 85 | } 86 | } 87 | 88 | public subscript(bounds: Range) -> ArraySlice { 89 | get { 90 | return bytes[bounds] 91 | } 92 | 93 | set(slice) { 94 | bytes[bounds] = slice 95 | } 96 | } 97 | } 98 | 99 | extension Data: ExpressibleByArrayLiteral { 100 | public init(arrayLiteral bytes: Byte...) { 101 | self.init(bytes) 102 | } 103 | } 104 | 105 | extension Data: ExpressibleByStringLiteral { 106 | public init(stringLiteral string: String) { 107 | self.init(string) 108 | } 109 | 110 | public init(extendedGraphemeClusterLiteral string: String){ 111 | self.init(string) 112 | } 113 | 114 | public init(unicodeScalarLiteral string: String){ 115 | self.init(string) 116 | } 117 | } 118 | 119 | extension Data: Equatable {} 120 | 121 | public func == (lhs: Data, rhs: Data) -> Bool { 122 | return lhs.bytes == rhs.bytes 123 | } 124 | 125 | #if swift(>=3.0) 126 | public func += (lhs: inout Data, rhs: S) where S.Iterator.Element == Byte { 127 | return lhs.bytes += rhs 128 | } 129 | #else 130 | public func += (inout lhs: Data, rhs: S) { 131 | return lhs.bytes += rhs 132 | } 133 | #endif 134 | 135 | #if swift(>=3.0) 136 | public func += (lhs: inout Data, rhs: Data) { 137 | return lhs.bytes += rhs.bytes 138 | } 139 | #else 140 | public func += (inout lhs: Data, rhs: Data) { 141 | return lhs.bytes += rhs.bytes 142 | } 143 | #endif 144 | 145 | #if swift(>=3.0) 146 | public func += (lhs: inout Data, rhs: DataRepresentable) { 147 | return lhs += rhs.data 148 | } 149 | #else 150 | public func += (inout lhs: Data, rhs: DataRepresentable) { 151 | return lhs += rhs.data 152 | } 153 | #endif 154 | 155 | public func + (lhs: Data, rhs: Data) -> Data { 156 | return Data(lhs.bytes + rhs.bytes) 157 | } 158 | 159 | public func + (lhs: Data, rhs: DataRepresentable) -> Data { 160 | return lhs + rhs.data 161 | } 162 | 163 | public func + (lhs: DataRepresentable, rhs: Data) -> Data { 164 | return lhs.data + rhs 165 | } 166 | 167 | extension String: DataConvertible { 168 | #if swift(>=3.0) 169 | public init(data: Data) throws { 170 | struct StringError: Error {} 171 | var string = "" 172 | var decoder = UTF8() 173 | var generator = data.makeIterator() 174 | 175 | loop: while true { 176 | switch decoder.decode(&generator) { 177 | case .scalarValue(let char): string.unicodeScalars.append(char) 178 | case .emptyInput: break loop 179 | case .error: throw StringError() 180 | } 181 | } 182 | 183 | self = string 184 | } 185 | #else 186 | public init(data: Data) throws { 187 | struct Error: ErrorProtocol {} 188 | var string = "" 189 | var decoder = UTF8() 190 | var generator = data.generate() 191 | 192 | loop: while true { 193 | switch decoder.decode(&generator) { 194 | case .Result(let char): string.append(char) 195 | case .EmptyInput: break loop 196 | case .Error: throw Error() 197 | } 198 | } 199 | 200 | self.init(string) 201 | } 202 | #endif 203 | 204 | public var data: Data { 205 | return Data(self) 206 | } 207 | } 208 | 209 | extension Data { 210 | public func withUnsafeBufferPointer(body: (UnsafeBufferPointer) throws -> R) rethrows -> R { 211 | return try bytes.withUnsafeBufferPointer(body) 212 | } 213 | 214 | public mutating func withUnsafeMutableBufferPointer(body: (inout UnsafeMutableBufferPointer) throws -> R) rethrows -> R { 215 | return try bytes.withUnsafeMutableBufferPointer(body) 216 | } 217 | 218 | #if swift(>=3.0) 219 | public static func buffer(with size: Int) -> Data { 220 | return Data([UInt8](repeating: 0, count: size)) 221 | } 222 | #else 223 | public static func buffer(with size: Int) -> Data { 224 | return Data([UInt8](count: size, repeatedValue: 0)) 225 | } 226 | #endif 227 | } 228 | 229 | extension Data { 230 | #if swift(>=3.0) 231 | public func hexadecimalString(inGroupsOf characterCount: Int = 0) -> String { 232 | var string = "" 233 | for (index, value) in self.enumerated() { 234 | if characterCount != 0 && index > 0 && index % characterCount == 0 { 235 | string += " " 236 | } 237 | string += (value < 16 ? "0" : "") + String(value, radix: 16) 238 | } 239 | return string 240 | } 241 | #else 242 | public func hexadecimalString(inGroupsOf characterCount: Int = 0) -> String { 243 | var string = "" 244 | for (index, value) in self.enumerate() { 245 | if characterCount != 0 && index > 0 && index % characterCount == 0 { 246 | string += " " 247 | } 248 | string += (value < 16 ? "0" : "") + String(value, radix: 16) 249 | } 250 | return string 251 | } 252 | #endif 253 | 254 | public var hexadecimalDescription: String { 255 | return hexadecimalString(inGroupsOf: 2) 256 | } 257 | } 258 | 259 | extension Data: CustomStringConvertible { 260 | public var description: String { 261 | if let string = try? String(data: self) { 262 | return string 263 | } 264 | 265 | return debugDescription 266 | } 267 | } 268 | 269 | extension Data: CustomDebugStringConvertible { 270 | public var debugDescription: String { 271 | return hexadecimalDescription 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /Sources/Drain.swift: -------------------------------------------------------------------------------- 1 | public final class Drain: DataRepresentable, Stream { 2 | var buffer: Data 3 | public var closed = false 4 | 5 | public var data: Data { 6 | if !closed { 7 | return buffer 8 | } 9 | return [] 10 | } 11 | 12 | public convenience init() { 13 | self.init(for: []) 14 | } 15 | 16 | public init(for stream: ReceivingStream, timingOut deadline: Double = .never) { 17 | var buffer: Data = [] 18 | 19 | if stream.closed { 20 | self.closed = true 21 | } 22 | 23 | while !stream.closed { 24 | if let chunk = try? stream.receive(upTo: 1024, timingOut: deadline) { 25 | buffer.bytes += chunk.bytes 26 | } else { 27 | break 28 | } 29 | } 30 | 31 | self.buffer = buffer 32 | } 33 | 34 | public init(for buffer: Data) { 35 | self.buffer = buffer 36 | } 37 | 38 | public convenience init(for buffer: DataRepresentable) { 39 | self.init(for: buffer.data) 40 | } 41 | 42 | public func close() throws { 43 | guard !closed else { 44 | throw ClosableError.alreadyClosed 45 | } 46 | closed = true 47 | } 48 | 49 | public func receive(upTo byteCount: Int, timingOut deadline: Double = .never) throws -> Data { 50 | if byteCount >= buffer.count { 51 | try close() 52 | return buffer 53 | } 54 | 55 | let data = buffer[0.. Stream 3 | } 4 | 5 | extension Host { 6 | func accept() throws -> Stream { 7 | return try accept(timingOut: .never) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/JSON.swift: -------------------------------------------------------------------------------- 1 | public enum JSON { 2 | public enum Number { 3 | case integer(Int) 4 | case unsignedInteger(UInt) 5 | case double(Double) 6 | } 7 | case object([String: JSON]) 8 | case array([JSON]) 9 | case number(JSON.Number) 10 | case string(String) 11 | case boolean(Bool) 12 | case null 13 | } 14 | 15 | // 16 | // TODO: refactor with 17 | // https://github.com/apple/swift-evolution/blob/master/proposals/0080-failable-numeric-initializers.md 18 | // 19 | 20 | extension Int { 21 | public init?(_ number: JSON.Number) { 22 | switch number { 23 | case let .integer(value) : self.init(value) 24 | case let .unsignedInteger(value) where value <= UInt(Int.max) : self.init(value) 25 | case let .double(value) where value <= Double(Int32.max): self.init(value) 26 | default: return nil 27 | } 28 | } 29 | } 30 | 31 | extension UInt { 32 | public init?(_ number: JSON.Number) { 33 | switch number { 34 | case let .integer(value) where value > 0 : self.init(value) 35 | case let .unsignedInteger(value) : self.init(value) 36 | case let .double(value) where value <= Double(UInt32.max): self.init(value) 37 | default: return nil 38 | } 39 | } 40 | } 41 | 42 | extension Double { 43 | public init(_ number: JSON.Number) { 44 | switch number { 45 | case let .integer(value) : self.init(value) 46 | case let .unsignedInteger(value): self.init(value) 47 | case let .double(value) : self.init(value) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/Number.swift: -------------------------------------------------------------------------------- 1 | public enum Number { 2 | case int(Int) 3 | case int8(Int8) 4 | case int16(Int16) 5 | case int32(Int32) 6 | case int64(Int64) 7 | 8 | case uint(UInt) 9 | case uint8(UInt8) 10 | case uint16(UInt16) 11 | case uint32(UInt32) 12 | case uint64(UInt64) 13 | 14 | case float(Float) 15 | case double(Double) 16 | } 17 | 18 | extension Number { 19 | init(_ value: Int) { 20 | self = .int(value) 21 | } 22 | 23 | init(_ value: Int8) { 24 | self = .int8(value) 25 | } 26 | 27 | init(_ value: Int16) { 28 | self = .int16(value) 29 | } 30 | 31 | init(_ value: Int32) { 32 | self = .int32(value) 33 | } 34 | 35 | init(_ value: Int64) { 36 | self = .int64(value) 37 | } 38 | 39 | init(_ value: UInt) { 40 | self = .uint(value) 41 | } 42 | 43 | init(_ value: UInt8) { 44 | self = .uint8(value) 45 | } 46 | 47 | init(_ value: UInt16) { 48 | self = .uint16(value) 49 | } 50 | 51 | init(_ value: UInt32) { 52 | self = .uint32(value) 53 | } 54 | 55 | init(_ value: UInt64) { 56 | self = .uint64(value) 57 | } 58 | 59 | init(_ value: Float) { 60 | self = .float(value) 61 | } 62 | 63 | init(_ value: Double) { 64 | self = .double(value) 65 | } 66 | } 67 | 68 | // 69 | // Waiting for: 70 | // https://github.com/apple/swift-evolution/blob/master/proposals/0080-failable-numeric-initializers.md 71 | // 72 | 73 | extension Int { 74 | init?(_ number: Number) { 75 | switch number { 76 | case let .int(value) : self.init(value) 77 | case let .int8(value) : self.init(value) 78 | case let .int16(value) : self.init(value) 79 | case let .int32(value) : self.init(value) 80 | case let .int64(value) where value <= Int64(Int.max) : self.init(value) 81 | case let .uint(value) where value <= UInt(Int.max) : self.init(value) 82 | case let .uint8(value) : self.init(value) 83 | case let .uint16(value) : self.init(value) 84 | case let .uint32(value) where UInt64(value) <= UInt64(Int.max) : self.init(value) 85 | case let .uint64(value) where value <= UInt64(Int.max) : self.init(value) 86 | // TODO: review 87 | case let .float(value) where value <= Float(Int16.max) : self.init(value) 88 | case let .double(value) where value <= Double(Int32.max) : self.init(value) 89 | default: return nil 90 | } 91 | } 92 | } 93 | 94 | extension Int8 { 95 | init?(_ number: Number) { 96 | switch number { 97 | case let .int(value) where value <= Int(Int8.max) : self.init(value) 98 | case let .int8(value) : self.init(value) 99 | case let .int16(value) where value <= Int16(Int8.max) : self.init(value) 100 | case let .int32(value) where value <= Int32(Int8.max) : self.init(value) 101 | case let .int64(value) where value <= Int64(Int8.max) : self.init(value) 102 | case let .uint(value) where value <= UInt(Int8.max) : self.init(value) 103 | case let .uint8(value) : self.init(value) 104 | case let .uint16(value) where value <= UInt16(Int8.max): self.init(value) 105 | case let .uint32(value) where value <= UInt32(Int8.max): self.init(value) 106 | case let .uint64(value) where value <= UInt64(Int8.max): self.init(value) 107 | // TODO: review 108 | case let .float(value) where value <= Float(Int8.max) : self.init(value) 109 | case let .double(value) where value <= Double(Int8.max): self.init(value) 110 | default: return nil 111 | } 112 | } 113 | } 114 | 115 | extension Int16 { 116 | public init?(_ number: Number) { 117 | switch number { 118 | case let .int(value) where value <= Int(Int16.max) : self.init(value) 119 | case let .int8(value) : self.init(value) 120 | case let .int16(value) : self.init(value) 121 | case let .int32(value) where value <= Int32(Int16.max) : self.init(value) 122 | case let .int64(value) where value <= Int64(Int16.max) : self.init(value) 123 | case let .uint(value) where value <= UInt(Int16.max) : self.init(value) 124 | case let .uint8(value) : self.init(value) 125 | case let .uint16(value) : self.init(value) 126 | case let .uint32(value) where value <= UInt32(Int16.max) : self.init(value) 127 | case let .uint64(value) where value <= UInt64(Int16.max) : self.init(value) 128 | // TODO: review 129 | case let .float(value) where value <= Float(Int16.max) : self.init(value) 130 | case let .double(value) where value <= Double(Int16.max) : self.init(value) 131 | default: return nil 132 | } 133 | } 134 | } 135 | 136 | extension Int32 { 137 | init?(_ number: Number) { 138 | switch number { 139 | case let .int(value) where value <= Int(Int32.max) : self.init(value) 140 | case let .int8(value) : self.init(value) 141 | case let .int16(value) : self.init(value) 142 | case let .int32(value) : self.init(value) 143 | case let .int64(value) where value <= Int64(Int32.max) : self.init(value) 144 | case let .uint(value) where value <= UInt(Int32.max) : self.init(value) 145 | case let .uint8(value) : self.init(value) 146 | case let .uint16(value) : self.init(value) 147 | case let .uint32(value) : self.init(value) 148 | case let .uint64(value) where value <= UInt64(Int32.max) : self.init(value) 149 | // TODO: review 150 | case let .float(value) where value <= Float(Int16.max) : self.init(value) 151 | case let .double(value) where value <= Double(Int32.max) : self.init(value) 152 | default: return nil 153 | } 154 | } 155 | } 156 | 157 | extension Int64 { 158 | init?(_ number: Number) { 159 | switch number { 160 | case let .int(value) : self.init(value) 161 | case let .int8(value) : self.init(value) 162 | case let .int16(value) : self.init(value) 163 | case let .int32(value) : self.init(value) 164 | case let .int64(value) : self.init(value) 165 | case let .uint(value) where UInt64(value) <= UInt64(Int64.max) : self.init(value) 166 | case let .uint8(value) : self.init(value) 167 | case let .uint16(value) : self.init(value) 168 | case let .uint32(value) : self.init(value) 169 | case let .uint64(value) where value <= UInt64(Int64.max) : self.init(value) 170 | // TODO: review 171 | case let .float(value) where Double(value) <= Double(Int32.max) : self.init(value) 172 | case let .double(value) where value <= Double(Int32.max) : self.init(value) 173 | default: return nil 174 | } 175 | } 176 | } 177 | 178 | extension UInt { 179 | init?(_ number: Number) { 180 | switch number { 181 | case let .int(value) where value >= 0 : self.init(value) 182 | case let .int8(value) where value >= 0 : self.init(value) 183 | case let .int16(value) where value >= 0 : self.init(value) 184 | case let .int32(value) where value >= 0 : self.init(value) 185 | case let .int64(value) where value >= 0 && UInt64(value) <= UInt64(UInt.max) : self.init(value) 186 | case let .uint(value) : self.init(value) 187 | case let .uint8(value) : self.init(value) 188 | case let .uint16(value) : self.init(value) 189 | case let .uint32(value) : self.init(value) 190 | case let .uint64(value) where value <= UInt64(UInt.max) : self.init(value) 191 | // TODO: review 192 | case let .float(value) where value <= Float(UInt16.max) : self.init(value) 193 | case let .double(value) where value <= Double(UInt32.max) : self.init(value) 194 | default: return nil 195 | } 196 | } 197 | } 198 | 199 | extension UInt8 { 200 | init?(_ number: Number) { 201 | switch number { 202 | case let .int(value) where value >= 0 && UInt(value) <= UInt(UInt8.max) : self.init(value) 203 | case let .int8(value) where value >= 0 : self.init(value) 204 | case let .int16(value) where value >= 0 && value <= Int16(UInt8.max) : self.init(value) 205 | case let .int32(value) where value >= 0 && value <= Int32(UInt8.max) : self.init(value) 206 | case let .int64(value) where value >= 0 && value <= Int64(UInt8.max) : self.init(value) 207 | case let .uint(value) where value <= UInt(UInt8.max) : self.init(value) 208 | case let .uint8(value) : self.init(value) 209 | case let .uint16(value) where value <= UInt16(UInt8.max) : self.init(value) 210 | case let .uint32(value) where value <= UInt32(UInt8.max) : self.init(value) 211 | case let .uint64(value) where value <= UInt64(UInt8.max) : self.init(value) 212 | // TODO: review 213 | case let .float(value) where value <= Float(UInt8.max) : self.init(value) 214 | case let .double(value) where value <= Double(UInt8.max) : self.init(value) 215 | default: return nil 216 | } 217 | } 218 | } 219 | 220 | extension UInt16 { 221 | init?(_ number: Number) { 222 | switch number { 223 | case let .int(value) where value >= 0 && UInt(value) <= UInt(UInt16.max) : self.init(value) 224 | case let .int8(value) where value >= 0 : self.init(value) 225 | case let .int16(value) where value >= 0 : self.init(value) 226 | case let .int32(value) where value >= 0 && value <= Int32(UInt16.max) : self.init(value) 227 | case let .int64(value) where value >= 0 && value <= Int64(UInt16.max) : self.init(value) 228 | case let .uint(value) where value <= UInt(UInt16.max) : self.init(value) 229 | case let .uint8(value) : self.init(value) 230 | case let .uint16(value) : self.init(value) 231 | case let .uint32(value) where value <= UInt32(UInt16.max) : self.init(value) 232 | case let .uint64(value) where value <= UInt64(UInt16.max) : self.init(value) 233 | // TODO: review 234 | case let .float(value) where value <= Float(UInt16.max) : self.init(value) 235 | case let .double(value) where value <= Double(UInt16.max) : self.init(value) 236 | default: return nil 237 | } 238 | } 239 | } 240 | 241 | extension UInt32 { 242 | init?(_ number: Number) { 243 | switch number { 244 | case let .int(value) where value >= 0 && UInt(value) <= UInt(UInt32.max) : self.init(value) 245 | case let .int8(value) where value >= 0 : self.init(value) 246 | case let .int16(value) where value >= 0 : self.init(value) 247 | case let .int32(value) where value >= 0 : self.init(value) 248 | case let .int64(value) where value >= 0 && value <= Int64(UInt32.max) : self.init(value) 249 | case let .uint(value) where value <= UInt(UInt32.max) : self.init(value) 250 | case let .uint8(value) : self.init(value) 251 | case let .uint16(value) : self.init(value) 252 | case let .uint32(value) : self.init(value) 253 | case let .uint64(value) where value <= UInt64(UInt32.max) : self.init(value) 254 | // TODO: review 255 | case let .float(value) where value <= Float(UInt16.max) : self.init(value) 256 | case let .double(value) where value <= Double(UInt32.max) : self.init(value) 257 | default: return nil 258 | } 259 | } 260 | } 261 | 262 | extension UInt64 { 263 | init?(_ number: Number) { 264 | switch number { 265 | case let .int(value) where value >= 0 : self.init(value) 266 | case let .int8(value) where value >= 0 : self.init(value) 267 | case let .int16(value) where value >= 0 : self.init(value) 268 | case let .int32(value) where value >= 0 : self.init(value) 269 | case let .int64(value) where value >= 0 : self.init(value) 270 | case let .uint(value) : self.init(value) 271 | case let .uint8(value) : self.init(value) 272 | case let .uint16(value) : self.init(value) 273 | case let .uint32(value) : self.init(value) 274 | case let .uint64(value) : self.init(value) 275 | // TODO: review 276 | case let .float(value) where Double(value) <= Double(Int32.max) : self.init(value) 277 | case let .double(value) where value <= Double(Int32.max) : self.init(value) 278 | default: return nil 279 | } 280 | } 281 | } 282 | 283 | extension Float { 284 | init(_ number: Number) { 285 | switch number { 286 | case let .int(value) : self.init(value) 287 | case let .int8(value) : self.init(value) 288 | case let .int16(value) : self.init(value) 289 | case let .int32(value) : self.init(value) 290 | case let .int64(value) : self.init(value) 291 | case let .uint(value) : self.init(value) 292 | case let .uint8(value) : self.init(value) 293 | case let .uint16(value) : self.init(value) 294 | case let .uint32(value) : self.init(value) 295 | case let .uint64(value) : self.init(value) 296 | // TODO: review 297 | case let .float(value) : self.init(value) 298 | case let .double(value) : self.init(value) 299 | } 300 | } 301 | } 302 | 303 | extension Double { 304 | init(_ number: Number) { 305 | switch number { 306 | case let .int(value) : self.init(value) 307 | case let .int8(value) : self.init(value) 308 | case let .int16(value) : self.init(value) 309 | case let .int32(value) : self.init(value) 310 | case let .int64(value) : self.init(value) 311 | case let .uint(value) : self.init(value) 312 | case let .uint8(value) : self.init(value) 313 | case let .uint16(value) : self.init(value) 314 | case let .uint32(value) : self.init(value) 315 | case let .uint64(value) : self.init(value) 316 | // TODO: review 317 | case let .float(value) : self.init(value) 318 | case let .double(value) : self.init(value) 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /Sources/Stream.swift: -------------------------------------------------------------------------------- 1 | public protocol Sending: AsyncSending { 2 | func send(_ data: Data, timingOut deadline: Double) throws 3 | func flush(timingOut deadline: Double) throws 4 | } 5 | 6 | public protocol Receiving: AsyncReceiving { 7 | func receive(upTo byteCount: Int, timingOut deadline: Double) throws -> Data 8 | } 9 | 10 | public protocol SendingStream: Closable, Sending {} 11 | public protocol ReceivingStream: Closable, Receiving {} 12 | public protocol Stream: SendingStream, ReceivingStream {} 13 | 14 | extension Sending { 15 | public func send(_ data: Data, timingOut deadline: Double, completion: @escaping ((Void) throws -> Void) -> Void) { 16 | completion { try self.send(data, timingOut: deadline) } 17 | } 18 | 19 | public func flush(timingOut deadline: Double, completion: @escaping ((Void) throws -> Void) -> Void) { 20 | completion { try self.flush(timingOut: deadline) } 21 | } 22 | } 23 | 24 | extension Sending { 25 | public func send(_ data: Data) throws { 26 | try send(data, timingOut: .never) 27 | } 28 | 29 | public func flush() throws { 30 | try flush(timingOut: .never) 31 | } 32 | } 33 | 34 | extension Receiving { 35 | public func receive(upTo byteCount: Int, timingOut deadline: Double, completion: @escaping ((Void) throws -> Data) -> Void) { 36 | completion { try self.receive(upTo: byteCount, timingOut: deadline) } 37 | } 38 | } 39 | 40 | extension Receiving { 41 | public func receive(upTo byteCount: Int) throws -> Data { 42 | return try receive(upTo: byteCount, timingOut: .never) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/StreamError.swift: -------------------------------------------------------------------------------- 1 | public enum StreamError: Error { 2 | case closedStream(data: Data) 3 | case timeout(data: Data) 4 | } 5 | -------------------------------------------------------------------------------- /Sources/StreamSequence.swift: -------------------------------------------------------------------------------- 1 | #if swift(>=3.0) 2 | public final class StreamSequence: Sequence { 3 | public let stream: Stream 4 | public let deadline: Double 5 | 6 | public init(for stream: Stream, timingOut deadline: Double = .never) { 7 | self.stream = stream 8 | self.deadline = deadline 9 | } 10 | 11 | public func makeIterator() -> AnyIterator { 12 | return AnyIterator { 13 | if self.stream.closed { 14 | return nil 15 | } 16 | return try? self.stream.receive(upTo: 1024, timingOut: self.deadline) 17 | } 18 | } 19 | } 20 | #else 21 | public final class StreamSequence: SequenceType { 22 | public let stream: Stream 23 | public let deadline: Double 24 | 25 | public init(for stream: Stream, timingOut deadline: Double = .never) { 26 | self.stream = stream 27 | self.deadline = deadline 28 | } 29 | 30 | public func generate() -> AnyGenerator { 31 | return AnyGenerator { 32 | if self.stream.closed { 33 | return nil 34 | } 35 | return try? self.stream.receive(upTo: 1024, timingOut: self.deadline) 36 | } 37 | } 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /Sources/StructuredData.swift: -------------------------------------------------------------------------------- 1 | public protocol StructuredDataInitializable { 2 | init(structuredData: StructuredData) throws 3 | } 4 | 5 | public protocol StructuredDataRepresentable: StructuredDataFallibleRepresentable { 6 | var structuredData: StructuredData { get } 7 | } 8 | 9 | public protocol StructuredDataFallibleRepresentable { 10 | func asStructuredData() throws -> StructuredData 11 | } 12 | 13 | extension StructuredDataRepresentable { 14 | public func asStructuredData() throws -> StructuredData { 15 | return structuredData 16 | } 17 | } 18 | 19 | public protocol StructuredDataConvertible: StructuredDataInitializable, StructuredDataRepresentable {} 20 | 21 | public enum StructuredData { 22 | case null 23 | case bool(Bool) 24 | case double(Double) 25 | case int(Int) 26 | case string(String) 27 | case data(Data) 28 | case array([StructuredData]) 29 | case dictionary([String: StructuredData]) 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Time.swift: -------------------------------------------------------------------------------- 1 | #if os(Linux) 2 | import Glibc 3 | var ts = timespec() 4 | #else 5 | import Darwin.C 6 | var factor: Double = { 7 | var mtid = mach_timebase_info_data_t() 8 | mach_timebase_info(&mtid) 9 | return Double(mtid.numer) / Double(mtid.denom) / 1E9 10 | }() 11 | #endif 12 | 13 | /// Absolute time in seconds 14 | public func now() -> Double { 15 | #if os(Linux) 16 | clock_gettime(CLOCK_MONOTONIC, &ts) 17 | return Double(ts.tv_sec) + Double(ts.tv_nsec) / 1E9 18 | #else 19 | return Double(mach_absolute_time()) * factor 20 | #endif 21 | } 22 | 23 | extension Double { 24 | /// Interval of `self` from now. 25 | public func fromNow() -> Double { 26 | return now() + self 27 | } 28 | } 29 | 30 | public protocol TimeUnitRepresentable { 31 | var seconds: Double { get } 32 | } 33 | 34 | extension TimeUnitRepresentable { 35 | public var milliseconds: Double { 36 | if self.seconds == .never { 37 | return .never 38 | } 39 | return self.seconds / 1000 40 | } 41 | public var millisecond: Double { 42 | return self.milliseconds 43 | } 44 | public var second: Double { 45 | return self.seconds 46 | } 47 | public var minutes: Double { 48 | if self.seconds == .never { 49 | return .never 50 | } 51 | return self.seconds * 60 52 | } 53 | public var minute: Double { 54 | return self.minutes 55 | } 56 | public var hours: Double { 57 | if self.seconds == .never { 58 | return .never 59 | } 60 | return self.minutes * 60 61 | } 62 | public var hour: Double { 63 | return self.hours 64 | } 65 | } 66 | 67 | extension Double: TimeUnitRepresentable { 68 | public var seconds: Double { 69 | return self 70 | } 71 | } 72 | 73 | extension Int: TimeUnitRepresentable { 74 | public var seconds: Double { 75 | return Double(self) 76 | } 77 | } 78 | 79 | extension Double { 80 | public static var never: Double { 81 | return -1 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Sources/URI.swift: -------------------------------------------------------------------------------- 1 | /* 2 | https://tools.ietf.org/html/rfc3986#section-1 3 | 4 | 3. Syntax Components 5 | 6 | The generic URI syntax consists of a hierarchical sequence of 7 | components referred to as the scheme, authority, path, query, and 8 | fragment. 9 | 10 | URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] 11 | 12 | hier-part = "//" authority path-abempty 13 | / path-absolute 14 | / path-rootless 15 | / path-empty 16 | 17 | The scheme and path components are required, though the path may be 18 | empty (no characters). When authority is present, the path must 19 | either be empty or begin with a slash ("/") character. When 20 | authority is not present, the path cannot begin with two slash 21 | characters ("//"). These restrictions result in five different ABNF 22 | rules for a path (Section 3.3), only one of which will match any 23 | given URI reference. 24 | 25 | The following are two example URIs and their component parts: 26 | 27 | foo://example.com:8042/over/there?name=ferret#nose 28 | \_/ \______________/\_________/ \_________/ \__/ 29 | | | | | | 30 | scheme authority path query fragment 31 | | _____________________|__ 32 | / \ / \ 33 | urn:example:animal:ferret:nose 34 | */ 35 | public struct URI { 36 | public struct UserInfo { 37 | public var username: String 38 | public var password: String 39 | 40 | public init(username: String, password: String) { 41 | self.username = username 42 | self.password = password 43 | } 44 | } 45 | 46 | public var scheme: String? 47 | public var userInfo: UserInfo? 48 | public var host: String? 49 | public var port: Int? 50 | public var path: String? 51 | public var query: String? 52 | public var fragment: String? 53 | 54 | public init(scheme: String? = nil, 55 | userInfo: UserInfo? = nil, 56 | host: String? = nil, 57 | port: Int? = nil, 58 | path: String? = nil, 59 | query: String? = nil, 60 | fragment: String? = nil) { 61 | self.scheme = scheme 62 | self.userInfo = userInfo 63 | self.host = host 64 | self.port = port 65 | self.path = path 66 | self.query = query 67 | self.fragment = fragment 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Sources/URIConnection.swift: -------------------------------------------------------------------------------- 1 | public protocol URIConnection: Connection { 2 | init(to uri: URI) throws 3 | var uri: URI { get } 4 | } 5 | -------------------------------------------------------------------------------- /Tests/C7Tests/ExampleTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import C7 3 | 4 | class ExampleTests: XCTestCase { 5 | static var allTests : [(String, (ExampleTests) -> () throws -> Void)] { 6 | return [ 7 | ("testReality", testReality), 8 | ] 9 | } 10 | 11 | func testReality() { 12 | XCTAssert(2 + 2 == 4, "Something is severely wrong here.") 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | #if os(Linux) 2 | 3 | import XCTest 4 | @testable import C7Tests 5 | 6 | XCTMain([ 7 | testCase(ExampleTests.allTests) 8 | ]) 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /swiftenv-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Automatically installs swiftenv and run's swiftenv install. 3 | # This script was designed for usage in CI systems. 4 | 5 | git clone --depth 1 https://github.com/kylef/swiftenv.git ~/.swiftenv 6 | export SWIFTENV_ROOT="$HOME/.swiftenv" 7 | export PATH="$SWIFTENV_ROOT/bin:$SWIFTENV_ROOT/shims:$PATH" 8 | 9 | if [ -f ".swift-version" ] || [ -n "$SWIFT_VERSION" ]; then 10 | swiftenv install 11 | else 12 | swiftenv rehash 13 | fi --------------------------------------------------------------------------------