Last active
March 31, 2016 19:08
-
-
Save paulofaria/e8fab41fa9517ba82699e72853c40c6d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public typealias Byte = UInt8 | |
public struct Data { | |
public var bytes: [Byte] | |
public init(_ bytes: [Byte]) { | |
self.bytes = bytes | |
} | |
} | |
public protocol DataInitializable { | |
init(data: Data) throws | |
} | |
public protocol DataRepresentable { | |
var data: Data { get } | |
} | |
public protocol DataConvertible: DataInitializable, DataRepresentable {} | |
extension Data { | |
public init(_ string: String) { | |
self.init([Byte](string.utf8)) | |
} | |
} | |
extension Data: RangeReplaceableCollectionType {} | |
extension Data { | |
public init() { | |
self.init([]) | |
} | |
public init(count: Int, repeatedValue: Byte) { | |
self.init([Byte](count: count, repeatedValue: repeatedValue)) | |
} | |
public mutating func replaceRange<C : CollectionType where C.Generator.Element == Byte>(subRange: Range<Int>, with newElements: C) { | |
self.bytes.replaceRange(subRange, with: newElements) | |
} | |
public mutating func reserveCapacity(n: Int) { | |
self.bytes.reserveCapacity(n) | |
} | |
public init<S : SequenceType where S.Generator.Element == Byte>(_ elements: S) { | |
self.init([Byte](elements)) | |
} | |
public mutating func append(x: Byte) { | |
self.bytes.append(x) | |
} | |
public mutating func appendContentsOf<S : SequenceType where S.Generator.Element == Byte>(newElements: S) { | |
self.bytes.appendContentsOf(newElements) | |
} | |
public mutating func insert(newElement: Byte, atIndex i: Int) { | |
self.bytes.insert(newElement, atIndex: i) | |
} | |
public mutating func insertContentsOf<S : CollectionType where S.Generator.Element == Byte>(newElements: S, at i: Int) { | |
self.bytes.insertContentsOf(newElements, at: i) | |
} | |
public mutating func removeAtIndex(i: Int) -> Byte { | |
return self.bytes.removeAtIndex(i) | |
} | |
public mutating func removeFirst() -> Byte { | |
return self.bytes.removeFirst() | |
} | |
public mutating func removeFirst(n: Int) { | |
self.bytes.removeFirst(n) | |
} | |
public mutating func removeRange(bounds: Range<Int>) { | |
self.bytes.removeRange(bounds) | |
} | |
public mutating func removeAll(keepCapacity keepCapacity: Bool) { | |
self.bytes.removeAll(keepCapacity: keepCapacity) | |
} | |
} | |
extension Data: MutableCollectionType {} | |
extension Data { | |
public func generate() -> IndexingGenerator<[Byte]> { | |
return bytes.generate() | |
} | |
public var startIndex: Int { | |
return bytes.startIndex | |
} | |
public var endIndex: Int { | |
return bytes.endIndex | |
} | |
public var count: Int { | |
return bytes.count | |
} | |
public subscript(index: Int) -> Byte { | |
get { | |
return bytes[index] | |
} | |
set(value) { | |
bytes[index] = value | |
} | |
} | |
public subscript (bounds: Range<Int>) -> ArraySlice<Byte> { | |
get { | |
return bytes[bounds] | |
} | |
set(slice) { | |
bytes[bounds] = slice | |
} | |
} | |
} | |
extension Data: NilLiteralConvertible { | |
public init(nilLiteral: Void) { | |
self.init([]) | |
} | |
} | |
extension Data: ArrayLiteralConvertible { | |
public init(arrayLiteral bytes: Byte...) { | |
self.init(bytes) | |
} | |
} | |
extension Data: StringLiteralConvertible { | |
public init(stringLiteral string: String) { | |
self.init(string) | |
} | |
public init(extendedGraphemeClusterLiteral string: String){ | |
self.init(string) | |
} | |
public init(unicodeScalarLiteral string: String){ | |
self.init(string) | |
} | |
} | |
extension Data: Equatable {} | |
public func ==(lhs: Data, rhs: Data) -> Bool { | |
return lhs.bytes == rhs.bytes | |
} | |
public func +=<S : SequenceType where S.Generator.Element == Byte>(inout lhs: Data, rhs: S) { | |
return lhs.bytes += rhs | |
} | |
public func +=(inout lhs: Data, rhs: Data) { | |
return lhs.bytes += rhs.bytes | |
} | |
public func +=(inout lhs: Data, rhs: DataConvertible) { | |
return lhs += rhs.data | |
} | |
@warn_unused_result | |
public func +(lhs: Data, rhs: Data) -> Data { | |
return Data(lhs.bytes + rhs.bytes) | |
} | |
@warn_unused_result | |
public func +(lhs: Data, rhs: DataConvertible) -> Data { | |
return lhs + rhs.data | |
} | |
@warn_unused_result | |
public func +(lhs: DataConvertible, rhs: Data) -> Data { | |
return lhs.data + rhs | |
} | |
extension String: DataConvertible { | |
public init(data: Data) throws { | |
struct Error: ErrorType {} | |
var string = "" | |
var decoder = UTF8() | |
var generator = data.generate() | |
loop: while true { | |
switch decoder.decode(&generator) { | |
case .Result(let char): string.append(char) | |
case .EmptyInput: break loop | |
case .Error: throw Error() | |
} | |
} | |
self.init(string) | |
} | |
public var data: Data { | |
return Data(self) | |
} | |
} | |
extension Data { | |
public func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<Byte>) throws -> R) rethrows -> R { | |
return try bytes.withUnsafeBufferPointer(body) | |
} | |
public mutating func withUnsafeMutableBufferPointer<R>(@noescape body: (inout UnsafeMutableBufferPointer<Byte>) throws -> R) rethrows -> R { | |
return try bytes.withUnsafeMutableBufferPointer(body) | |
} | |
#if swift(>=3.0) | |
public static func bufferWithSize(size: Int) -> Data { | |
return Data([UInt8](repeating: 0, count: size)) | |
} | |
#else | |
public static func bufferWithSize(size: Int) -> Data { | |
return Data([UInt8](count: size, repeatedValue: 0)) | |
} | |
#endif | |
} | |
public protocol Stream { | |
var closed: Bool { get } | |
func close() -> Bool | |
func receive() throws -> Data | |
func send(data: Data) throws | |
func flush() throws | |
} | |
public enum StreamError: ErrorType { | |
case closedStream(data: Data) | |
} | |
public final class Drain: DataRepresentable, Stream { | |
var buffer: Data | |
public var closed = false | |
public var data: Data { | |
if !closed { | |
return buffer | |
} | |
return Data([]) | |
} | |
public convenience init() { | |
self.init(Data([])) | |
} | |
public init(_ stream: Stream) { | |
var buffer = Data([]) | |
if stream.closed { | |
self.closed = true | |
} | |
while !stream.closed { | |
if let chunk = try? stream.receive() { | |
buffer.bytes += chunk.bytes | |
} else { | |
break | |
} | |
} | |
self.buffer = buffer | |
} | |
public init(_ buffer: Data) { | |
self.buffer = buffer | |
if buffer.bytes.isEmpty { | |
close() | |
} | |
} | |
public convenience init(_ buffer: DataRepresentable) { | |
self.init(buffer.data) | |
} | |
public func close() -> Bool { | |
if closed { | |
return false | |
} | |
closed = true | |
return true | |
} | |
public func receive() throws -> Data { | |
let data = self.data | |
close() | |
return data | |
} | |
public func send(data: Data) throws { | |
buffer.appendContentsOf(data) | |
} | |
public func flush() throws {} | |
} | |
public final class EchoStream: Stream { | |
public var closed = false | |
public func close() -> Bool { | |
if closed { | |
return false | |
} | |
closed = true | |
return true | |
} | |
public func receive() throws -> Data { | |
return nil | |
} | |
public func send(data: Data) throws { | |
print(data) | |
} | |
public func flush() throws {} | |
} | |
public enum Body { | |
case buffer(Data) | |
case receiver(Stream) | |
case sender(Stream throws -> Void) | |
} | |
extension Body { | |
public var buffer: Data { | |
mutating get { | |
switch self { | |
case .buffer(let data): | |
return data | |
case .receiver(let receiver): | |
let data = Drain(receiver).data | |
self = .buffer(data) | |
return data | |
case .sender(let sender): | |
let drain = Drain() | |
do { | |
drain.closed = false | |
try sender(drain) | |
return drain.data | |
} catch { | |
return nil | |
} | |
} | |
} | |
set(data) { | |
self = .buffer(data) | |
} | |
} | |
public var isBuffer: Bool { | |
switch self { | |
case .buffer: return true | |
default: return false | |
} | |
} | |
public var receiver: Stream { | |
mutating get { | |
switch self { | |
case .receiver(let receiver): | |
return receiver | |
case .buffer(let data): | |
let stream = Drain(data) | |
self = .receiver(stream) | |
return stream | |
case .sender(let sender): | |
let drain = Drain() | |
do { | |
drain.closed = false | |
try sender(drain) | |
} catch { | |
return Drain() | |
} | |
return drain | |
} | |
} | |
set(stream) { | |
self = .receiver(stream) | |
} | |
} | |
public var isReceiver: Bool { | |
switch self { | |
case .receiver: return true | |
default: return false | |
} | |
} | |
public var sender: (Stream throws -> Void) { | |
mutating get { | |
switch self { | |
case .buffer(let data): | |
return { sender in | |
try sender.send(data) | |
} | |
case .receiver(let receiver): | |
return { sender in | |
let data = Drain(receiver).data | |
try sender.send(data) | |
} | |
case .sender(let sender): | |
return sender | |
} | |
} | |
set(sender) { | |
self = .sender(sender) | |
} | |
} | |
public var isSender: Bool { | |
switch self { | |
case .sender: return true | |
default: return false | |
} | |
} | |
} | |
//let echoStream = EchoStream() | |
// | |
//var body = Body.buffer("hello") | |
//var receiver = body.receiver | |
//var data = try receiver.receive() | |
//print(data) | |
// | |
//body = Body.buffer("hello") | |
//var sender = body.sender | |
//try sender(echoStream) | |
var body = Body.sender { stream in | |
try stream.send("yoo") | |
} | |
var buffer = body.buffer | |
print(buffer) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment