Skip to content

Instantly share code, notes, and snippets.

@tanner0101
Forked from paulofaria/Body.swift
Last active March 31, 2016 19:03
Show Gist options
  • Save tanner0101/50783cded5c0da9668d4d00835b4810e to your computer and use it in GitHub Desktop.
Save tanner0101/50783cded5c0da9668d4d00835b4810e to your computer and use it in GitHub Desktop.
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 stream = Drain()
do {
stream.closed = false
try sender(stream)
return stream.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 {
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