├── docs ├── favicon.ico ├── metadata.json ├── img │ ├── deprecated-icon.015b4f17.svg │ ├── added-icon.d6f7e47d.svg │ └── modified-icon.f496e73d.svg ├── js │ ├── highlight-js-shell.dd7f411f.js │ ├── highlight-js-json.471128d2.js │ ├── highlight-js-diff.62d66733.js │ ├── highlight-js-http.163e45b6.js │ ├── highlight-js-xml.9c3688c7.js │ ├── highlight-js-markdown.90077643.js │ ├── highlight-js-java.8326d9d8.js │ ├── highlight-js-llvm.6100b125.js │ ├── highlight-js-objectivec.bcdf5156.js │ ├── highlight-js-bash.1b52852f.js │ ├── highlight-js-custom-markdown.7cffc4b3.js │ ├── highlight-js-python.c214ed92.js │ ├── highlight-js-ruby.f889d392.js │ ├── highlight-js-c.d1db3f17.js │ ├── highlight-js-php.cc8d6c27.js │ └── highlight-js-perl.757d7b6f.js ├── theme-settings.json ├── favicon.svg ├── data │ ├── documentation │ │ └── packetprocessor │ │ │ ├── packethandleridentifier.json │ │ │ ├── gettingstarted.json │ │ │ ├── packetcollectiontype │ │ │ ├── init().json │ │ │ └── count.json │ │ │ ├── packetsearchresult │ │ │ └── packet.json │ │ │ └── packetprocessor │ │ │ └── init().json │ └── tutorials │ │ └── tutorial-toc.json ├── index.html ├── tutorials │ ├── tutorial-toc │ │ └── index.html │ └── packetprocessor │ │ ├── datapacket-utf8 │ │ └── index.html │ │ ├── stringpacket-json │ │ └── index.html │ │ └── stringpacket-logfile │ │ └── index.html └── documentation │ └── packetprocessor │ ├── index.html │ ├── packet │ ├── index.html │ └── collectiontype │ │ └── index.html │ ├── anypacket │ └── index.html │ ├── datapacket │ └── index.html │ ├── stringpacket │ └── index.html │ ├── gettingstarted │ └── index.html │ ├── packetprocessor │ ├── index.html │ └── end() │ │ └── index.html │ ├── packetsearchresult │ └── index.html │ ├── packetcollectiontype │ └── index.html │ ├── packethandlercontext │ └── index.html │ └── packethandleridentifier │ └── index.html ├── Sources └── PacketProcessor │ ├── Packet Types │ ├── PacketHandlerIdentifier.swift │ ├── DataPacket.swift │ ├── StringPacket.swift │ └── PacketProtocols.swift │ ├── PacketProcessor.docc │ ├── Resources │ │ └── code-files │ │ │ ├── stringpacket-json-01-01.json │ │ │ ├── stringpacket-logfile-01-01.swift │ │ │ ├── stringpacket-logfile-02-01.swift │ │ │ ├── stringpacket-logfile-02-02.swift │ │ │ ├── datapacket-utf8-01-01.swift │ │ │ ├── stringpacket-logfile-01-02.swift │ │ │ ├── stringpacket-logfile-02-03.swift │ │ │ ├── stringpacket-json-01-02.swift │ │ │ ├── stringpacket-logfile-02-04.swift │ │ │ ├── datapacket-utf8-01-02.swift │ │ │ ├── stringpacket-logfile-01-03.swift │ │ │ ├── stringpacket-logfile-02-05.swift │ │ │ ├── stringpacket-json-01-03.swift │ │ │ ├── stringpacket-json-01-04.swift │ │ │ ├── stringpacket-logfile-02-06.swift │ │ │ ├── datapacket-utf8-02-01.swift │ │ │ ├── datapacket-utf8-02-02.swift │ │ │ ├── stringpacket-json-02-01.swift │ │ │ ├── stringpacket-json-02-02.swift │ │ │ └── stringpacket-json-02-03.swift │ ├── Extensions │ │ └── PacketProcessorClass.md │ ├── GettingStarted.md │ ├── PacketProcessor.md │ └── Tutorials │ │ ├── Tutorial-TOC.tutorial │ │ ├── StringPacket-JSON.tutorial │ │ └── DataPacket-utf8.tutorial │ ├── Internal │ ├── HandlerWrapper.swift │ └── PacketTypeWrapper.swift │ ├── PacketHandlerContext.swift │ ├── PacketSearchResult.swift │ └── PacketCollectionType.swift ├── doc-gen.sh ├── Package.swift ├── README.md ├── Tests └── PacketProcessorTests │ ├── SwiftPacketProcessorForStringTests.swift │ ├── SerialTaskOperation.swift │ ├── PartialStringPacketProcessorTests.swift │ └── DataPacketProcessorTests.swift └── .gitignore /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannys42/SwiftPacketProcessor/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /docs/metadata.json: -------------------------------------------------------------------------------- 1 | {"bundleDisplayName":"PacketProcessor","bundleIdentifier":"PacketProcessor","schemaVersion":{"major":0,"minor":1,"patch":0}} -------------------------------------------------------------------------------- /Sources/PacketProcessor/Packet Types/PacketHandlerIdentifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketHandlerIdentifier.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/25/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | public typealias PacketHandlerIdentifier = UUID 11 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-json-01-01.json: -------------------------------------------------------------------------------- 1 | { 2 | "playerId": 1, 3 | "move": { 4 | "x" : 3, 5 | "y" : 2 6 | } 7 | 8 | { 9 | "playerId": 1, 10 | "attack": { 11 | "x" : 7, 12 | "y" : 9 13 | }, 14 | "weapon": "cannon" 15 | } 16 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-01-01.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct NewlinePacket { 13 | var text: String 14 | } 15 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-02-01.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | 11 | import Foundation 12 | import PacketProcessor 13 | 14 | let packetProcessor = PacketProcessor() 15 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Extensions/PacketProcessorClass.md: -------------------------------------------------------------------------------- 1 | # ``PacketProcessor/PacketProcessor`` 2 | 3 | ## Topics 4 | 5 | ### Initializing 6 | 7 | - ``init()`` 8 | 9 | ### Adding Packet Handlers 10 | - ``addHandler(_:_:)-86o7r`` 11 | - ``addHandler(_:_:)-8hqd3`` 12 | 13 | ### Data from the data stream 14 | - ``push(_:)`` 15 | - ``end()`` 16 | 17 | ## Removing Packet Handlers 18 | - ``remove(handlerId:)`` 19 | 20 | ## See Also 21 | 22 | - ``PacketProcessor`` 23 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-02-02.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | 11 | import Foundation 12 | import PacketProcessor 13 | 14 | let packetProcessor = PacketProcessor() 15 | 16 | packetProcessor.addHandler(NewlinePacket.self) { packet in 17 | print("Found a full line: \(packet.text)") 18 | } 19 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/Internal/HandlerWrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HandlerWrapper.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/20/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | internal struct HandlerWrapper: Identifiable { 11 | var id: PacketHandlerIdentifier 12 | var handler: (PacketHandlerIdentifier, AnyPacket) ->Void 13 | 14 | init(_ handler: @escaping (PacketHandlerIdentifier, AnyPacket) ->Void) { 15 | self.id = UUID() 16 | self.handler = handler 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/GettingStarted.md: -------------------------------------------------------------------------------- 1 | # Getting Started with PacketProcessor 2 | 3 | Easily handle packetized data-streams. 4 | 5 | ## Overview 6 | 7 | ``PacketProcessor`` simplifies the task of converting data streams into type-safe packetized data. 8 | 9 | ``PacketProcessor`` has the following features: 10 | * Takes care of buffer management for you 11 | * Allows you to register multiple handlers of the same type 12 | * Has a simple interface for defining packets of fixed or variable length 13 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/datapacket-utf8-01-01.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple UTF-8 decoder 6 | 7 | Created by Danny Sung on 05/05/2022. 8 | */ 9 | 10 | 11 | import Foundation 12 | 13 | struct UTF8ToString: DataPacket { 14 | var string: String 15 | 16 | static func findFirstPacket(context: PacketHandlerContext, data: Data) -> PacketSearchResult? { 17 | // TBD 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-01-02.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | import Foundation 11 | import PacketProcessor 12 | 13 | struct NewlinePacket: StringPacket { 14 | var text: String 15 | 16 | static func findFirstPacket(context: PacketContext, data: String) -> PacketSearchResult? { 17 | // TBD 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /docs/img/deprecated-icon.015b4f17.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-02-03.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | 11 | import Foundation 12 | import PacketProcessor 13 | 14 | let packetProcessor = PacketProcessor() 15 | 16 | packetProcessor.addHandler(NewlinePacket.self) { packet in 17 | print("Found a full line: \(packet.text)") 18 | } 19 | 20 | while let newText = getNewTextFromSomewhere() { 21 | self.packetProcessor.push(text) 22 | } 23 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-json-01-02.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A JSON packet processor, supporting multiple types of JSON packets. 6 | 7 | Created by Danny Sung on 05/07/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct Coordinates: Codable { 13 | let x: Int 14 | let y: Int 15 | } 16 | 17 | struct PlayerMove: Codable { 18 | let playerId: Int 19 | let move: Coordinates 20 | } 21 | 22 | struct PlayerAttack: Codable { 23 | let playerId: Int 24 | let attack: Coordinates 25 | let weapon: String 26 | } 27 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-02-04.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | 11 | import Foundation 12 | import PacketProcessor 13 | 14 | let packetProcessor = PacketProcessor() 15 | 16 | packetProcessor.addHandler(NewlinePacket.self) { packet in 17 | print("Found a full line: \(packet.text)") 18 | } 19 | 20 | while let newText = getNewTextFromSomewhere() { 21 | self.packetProcessor.push(text) 22 | } 23 | 24 | self.packetProcessor.end() 25 | -------------------------------------------------------------------------------- /docs/img/added-icon.d6f7e47d.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/js/highlight-js-shell.dd7f411f.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-shell"],{b65b:function(s,n){function e(s){return{name:"Shell Session",aliases:["console","shellsession"],contains:[{className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}}s.exports=e}}]); -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketHandlerContext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketHandlerContext.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/15/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Used by packet handlers to get more details about the state of the data stream. Typically used in ``Packet/findFirstPacket(context:data:)``. 11 | public class PacketHandlerContext { 12 | /// `true` if input handling has ended on a ``PacketProcessor``. 13 | /// 14 | /// This is intended for ``Packet/findFirstPacket(context:data:)`` to determine how to handle potentially incomplete packets. 15 | public private(set) var isEnded: Bool 16 | 17 | internal init(isEnded: Bool = false) { 18 | self.isEnded = isEnded 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/datapacket-utf8-01-02.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple UTF-8 decoder 6 | 7 | Created by Danny Sung on 05/05/2022. 8 | */ 9 | 10 | 11 | import Foundation 12 | 13 | struct UTF8ToString: DataPacket { 14 | var string: String 15 | 16 | static func findFirstPacket(context: PacketHandlerContext, data: Data) -> PacketSearchResult? { 17 | guard let string = String(data: data, encoding: .utf8) else { 18 | return nil 19 | } 20 | let packet = UTF8ToString(string: string) 21 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: data.count) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/js/highlight-js-json.471128d2.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-json"],{"5ad2":function(n,e){function a(n){const e={className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},a={match:/[{}[\],:]/,className:"punctuation",relevance:0},s={beginKeywords:["true","false","null"].join(" ")};return{name:"JSON",contains:[e,a,n.QUOTE_STRING_MODE,s,n.C_NUMBER_MODE,n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],illegal:"\\S"}}n.exports=a}}]); -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-01-03.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | import Foundation 11 | import PacketProcessor 12 | 13 | struct NewlinePacket: StringPacket { 14 | var text: String 15 | 16 | static func findFirstPacket(context: PacketContext, data: String) -> PacketSearchResult? { 17 | guard let newlineIndex = data.firstIndex(of: "\n") else { 18 | return nil 19 | } 20 | 21 | let payload = data.prefix(upTo: newlineIndex) 22 | let packet = NewlinePacket(text: String(payload)) 23 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: payload.count+1) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-02-05.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | import Foundation 11 | import PacketProcessor 12 | 13 | struct NewlinePacket: StringPacket { 14 | var text: String 15 | 16 | static func findFirstPacket(context: PacketContext, data: String) -> PacketSearchResult? { 17 | guard let newlineIndex = data.firstIndex(of: "\n") else { 18 | return nil 19 | } 20 | 21 | let payload = data.prefix(upTo: newlineIndex) 22 | let packet = NewlinePacket(text: String(payload)) 23 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: payload.count+1) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /doc-gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ref: https://apple.github.io/swift-docc-plugin/documentation/swiftdoccplugin/publishing-to-github-pages/ 3 | # ref: https://apple.github.io/swift-docc-plugin/documentation/swiftdoccplugin/generating-documentation-for-hosting-online 4 | 5 | DERIVED_DATA_DIR=/tmp/derived_data 6 | DOARCHIVE=${DERIVED_DATA_DIR}/Build/Products/Debug/PacketProcessor.doccarchive 7 | OUTPUT_DIR="docs" 8 | BASE_URL="SwiftPacketProcessor/" 9 | BUILD_TARGET="PacketProcessor" 10 | 11 | 12 | swift package --allow-writing-to-directory "${OUTPUT_DIR}" \ 13 | generate-documentation --target "${BUILD_TARGET}" \ 14 | --disable-indexing \ 15 | --transform-for-static-hosting \ 16 | --hosting-base-path "${BASE_URL}" \ 17 | --output-path "${OUTPUT_DIR}" 18 | 19 | 20 | mv docs/index.html ${DERIVED_DATA_DIR}/index.html 21 | cat ${DERIVED_DATA_DIR}/index.html | sed 's/"\//"\/SwiftPacketProcessor\//g' > docs/index.html 22 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-json-01-03.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A JSON packet processor, supporting multiple types of JSON packets. 6 | 7 | Created by Danny Sung on 05/07/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct Coordinates: Codable { 13 | let x: Int 14 | let y: Int 15 | } 16 | 17 | struct PlayerMove: Codable { 18 | let playerId: Int 19 | let move: Coordinates 20 | } 21 | 22 | struct PlayerAttack: Codable { 23 | let playerId: Int 24 | let attack: Coordinates 25 | let weapon: String 26 | } 27 | 28 | func handleNewData(packetData: Data) { 29 | if let playerMove = try? jsonDecoder.decode(PlayerMove.self, from: packetData) { 30 | // handle move 31 | } else if let playerAttack = try? jsonDecoder.decode(PlayerAttack.self, from: packetData) { 32 | // handle attack 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/js/highlight-js-diff.62d66733.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-diff"],{"48b8":function(e,n){function a(e){const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)},{className:"comment",variants:[{begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}}e.exports=a}}]); -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-json-01-04.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A JSON packet processor, supporting multiple types of JSON packets. 6 | 7 | Created by Danny Sung on 05/07/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct Coordinates: Codable { 13 | let x: Int 14 | let y: Int 15 | } 16 | 17 | struct PlayerMove: Codable { 18 | let playerId: Int 19 | let move: Coordinates 20 | } 21 | 22 | struct PlayerAttack: Codable { 23 | let playerId: Int 24 | let attack: Coordinates 25 | let weapon: String 26 | } 27 | 28 | // Setup 29 | let packetProcessor = PacketProcessor() 30 | 31 | packetProcessor.addHandler(PlayerMovePacket.self) { packet in 32 | playerMove = packet 33 | } 34 | packetProcessor.addHandler(PlayerAttackPacket.self) { packet in 35 | playerAttack = packet 36 | } 37 | 38 | // Read new packets 39 | let newData = ... 40 | packetProcessor.push(newData) 41 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketSearchResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketSearchResult.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/24/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct PacketSearchResult { 11 | /// The ``Packet`` found 12 | public let packet: P 13 | /// The number of data elements consumed (from ``Packet/findFirstPacket(context:data:)``) by the packet 14 | public let numberOfElementsConsumedByPacket: Int 15 | 16 | /// Declare a packet that has been found by ``Packet/findFirstPacket(context:data:)`` 17 | /// - Parameters: 18 | /// - packet: The ``Packet`` that was found. 19 | /// - numberOfElementsConsumedByPacket: The number of elements of data (from ``Packet/findFirstPacket(context:data:)``) that was used to construct the ``Packet``. 20 | public init(packet: P, numberOfElementsConsumedByPacket: Int) { 21 | self.packet = packet 22 | self.numberOfElementsConsumedByPacket = numberOfElementsConsumedByPacket 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/Internal/PacketTypeWrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketTypeWrapper.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/20/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | internal struct PacketTypeWrapper: Hashable { 11 | static func == (lhs: PacketTypeWrapper, rhs: PacketTypeWrapper) -> Bool { 12 | lhs.packetType == rhs.packetType 13 | } 14 | func hash(into hasher: inout Hasher) { 15 | hasher.combine("\(self.packetType)") 16 | hasher.combine(ObjectIdentifier(self.packetType)) 17 | } 18 | 19 | let packetType: AnyPacket.Type 20 | let packetGenerator: (_ context: PacketHandlerContext, _ data: CollectionType)->(packet: AnyPacket, count: Int)? 21 | init(_ packetType: AnyPacket.Type, packetGenerator: @escaping (_ context: PacketHandlerContext, _ data: CollectionType)->(packet: AnyPacket, count: Int)? ) { 22 | self.packetType = packetType 23 | self.packetGenerator = packetGenerator 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketCollectionType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketCollectionType.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/13/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Protocol used to declare data collection types that can be used by ``PacketProcessor``. 11 | /// 12 | /// This is primarily used to initialize a ``PacketProcessor``. You will do so by specifying either `PacketProcessor` or `PacketProcessor`. 13 | /// 14 | /// Most users can ignore this protocol. 15 | public protocol PacketCollectionType { 16 | 17 | init() 18 | 19 | /// Number of elements in the collection. 20 | var count: Int { get } 21 | 22 | /// Called when adding more data to the buffer. 23 | /// - Parameter other: Additional data to add. 24 | mutating func _packetProcessor_packetAppend(_ other: Self) 25 | 26 | /// Called when removing data from the buffer. 27 | /// - Parameter count: Number of elements to remove. (bytes for Data; characters for String) 28 | mutating func _packetProcessor_packetRemoveFirst(_ count: Int) 29 | } 30 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/PacketProcessor.md: -------------------------------------------------------------------------------- 1 | # ``PacketProcessor`` 2 | 3 | ``PacketProcessor`` takes care of buffer management when processing packetized data within streams. 4 | 5 | ## Intro 6 | 7 | ``PacketProcessor`` allows you to process any type of packet (whether variable or fixed length, binary, or string) by writing simple definitions for your ``PacketProcessor/Packet``s. 8 | 9 | In addition, ``PacketProcessor`` is able to aid you in handling any packet type when reading chunked data, e.g. from a very large file to be more memory efficient or from a network socket where there may be latency between chunks. 10 | 11 | 12 | ## Topics 13 | 14 | ### Essentials 15 | 16 | - 17 | - 18 | 19 | 20 | 21 | ### Initializing a Packet Processor 22 | 23 | - ``PacketProcessor/PacketProcessor`` 24 | 25 | ### Defining & Handling Packets 26 | - ``DataPacket`` 27 | - ``StringPacket`` 28 | - ``PacketHandlerContext`` 29 | 30 | ### Internals 31 | 32 | - ``AnyPacket`` 33 | - ``Packet`` 34 | - ``PacketCollectionType`` 35 | 36 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Tutorials/Tutorial-TOC.tutorial: -------------------------------------------------------------------------------- 1 | @Tutorials(name: "Tutorials") { 2 | @Intro(title: "Examples Packets") { 3 | ``PacketProcessor`` can help you to easily convert a stream of characters to structured data packets. 4 | 5 | 6 | } 7 | 8 | @Chapter(name: "Reading log files") { 9 | This example demonstrates how we might read from a log file. 10 | 11 | 12 | 13 | @TutorialReference(tutorial: "doc:StringPacket-Logfile") 14 | } 15 | 16 | @Chapter(name: "Processing messages from sockets") { 17 | This example demonstrates how we might handle JSON messages from web sockets. 18 | 19 | @TutorialReference(tutorial: "doc:StringPacket-JSON") 20 | } 21 | 22 | @Chapter(name: "Converting UTF-8 byte streams to Strings") { 23 | An example working with variable length byte streams. 24 | 25 | @TutorialReference(tutorial: "doc:DataPacket-utf8") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/img/modified-icon.f496e73d.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-logfile-02-06.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple log file processor 6 | 7 | Created by Danny Sung on 04/29/2022. 8 | */ 9 | 10 | import Foundation 11 | import PacketProcessor 12 | 13 | struct NewlinePacket: StringPacket { 14 | var text: String 15 | 16 | static func findFirstPacket(context: PacketContext, data: String) -> PacketSearchResult? { 17 | 18 | let endOfLineIndex: String.Index 19 | let newlineCount: Int 20 | 21 | if let newlineIndex = data.firstIndex(of: "\n") { 22 | endOfLineIndex = newlineIndex 23 | newlineCount = 1 24 | } else if context.isEnded { 25 | endOfLineIndex = data.endIndex 26 | newlineCount = 0 27 | } else { 28 | return nil 29 | } 30 | 31 | let payload = data.prefix(upTo: endOfLineIndex) 32 | let packet = NewlinePacket(text: String(payload)) 33 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: payload.count+newlineCount) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /docs/js/highlight-js-http.163e45b6.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-http"],{c01d:function(e,n){function a(e){const n=e.regex,a="HTTP/(2|1\\.[01])",s=/[A-Za-z][A-Za-z0-9-]*/,t={className:"attribute",begin:n.concat("^",s,"(?=\\:\\s)"),starts:{contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$",relevance:0}}]}},i=[t,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{begin:"^(?="+a+" \\d{3})",end:/$/,contains:[{className:"meta",begin:a},{className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/,contains:i}},{begin:"(?=^[A-Z]+ (.*?) "+a+"$)",end:/$/,contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{className:"meta",begin:a},{className:"keyword",begin:"[A-Z]+"}],starts:{end:/\b\B/,illegal:/\S/,contains:i}},e.inherit(t,{relevance:0})]}}e.exports=a}}]); -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.5 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "PacketProcessor", 8 | platforms: [.macOS(.v10_10), .iOS(.v13), .watchOS(.v2), .tvOS(.v13)], 9 | products: [ 10 | // Products define the executables and libraries a package produces, and make them visible to other packages. 11 | .library( 12 | name: "PacketProcessor", 13 | targets: ["PacketProcessor"]), 14 | ], 15 | dependencies: [ 16 | // Dependencies declare other packages that this package depends on. 17 | // .package(url: /* package url */, from: "1.0.0"), 18 | .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), 19 | ], 20 | targets: [ 21 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 22 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 23 | .target( 24 | name: "PacketProcessor", 25 | dependencies: []), 26 | .testTarget( 27 | name: "PacketProcessorTests", 28 | dependencies: ["PacketProcessor"]), 29 | ] 30 | ) 31 | -------------------------------------------------------------------------------- /docs/theme-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta": {}, 3 | "theme": { 4 | "colors": { 5 | "text": "", 6 | "text-background": "", 7 | "grid": "", 8 | "article-background": "", 9 | "generic-modal-background": "", 10 | "secondary-label": "", 11 | "header-text": "", 12 | "not-found": { 13 | "input-border": "" 14 | }, 15 | "runtime-preview": { 16 | "text": "" 17 | }, 18 | "tabnav-item": { 19 | "border-color": "" 20 | }, 21 | "svg-icon": { 22 | "fill-light": "", 23 | "fill-dark": "" 24 | }, 25 | "loading-placeholder": { 26 | "background": "" 27 | }, 28 | "button": { 29 | "text": "", 30 | "light": { 31 | "background": "", 32 | "backgroundHover": "", 33 | "backgroundActive": "" 34 | }, 35 | "dark": { 36 | "background": "", 37 | "backgroundHover": "", 38 | "backgroundActive": "" 39 | } 40 | }, 41 | "link": null 42 | }, 43 | "style": { 44 | "button": { 45 | "borderRadius": null 46 | } 47 | }, 48 | "typography": { 49 | "html-font": "" 50 | } 51 | }, 52 | "features": { 53 | "docs": { 54 | "summary": { 55 | "hide": false 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/Packet Types/DataPacket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataPacket.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/21/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Byte-oriented packets should conform to `DataPacket`. 11 | /// Examples of this include IP, TCP, and UDP. 12 | /// 13 | /// See ``Packet`` for full conformance. 14 | public protocol DataPacket: Packet where CollectionType == Data { 15 | /// Implement this method to find the first occurance of a valid packet within the data supplied. 16 | /// - Parameters: 17 | /// - context: ``PacketHandlerContext/isEnded`` can be used to determine if the `data` passed is the last to be processed. Useful for handling incomplete packets (such as due to end of file or close of socket). 18 | /// - data: The data to search. The packet must start at the beginning of `data`. 19 | /// - Returns: ``PacketSearchResult`` containing this ``Packet`` if a valid packet is found at the beginning of `data`. Otherwise returns `nil`. 20 | static func findFirstPacket(context: PacketHandlerContext, data: Data) -> PacketSearchResult? 21 | } 22 | 23 | /// Declare `Data` is a valid `PacketCollectionType` 24 | extension Data: PacketCollectionType { 25 | 26 | mutating public func _packetProcessor_packetAppend(_ other: Self) { 27 | self.append(other) 28 | } 29 | mutating public func _packetProcessor_packetRemoveFirst(_ count: Int) { 30 | self.removeFirst(count) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/Packet Types/StringPacket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringPacket.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/21/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | /// String-oriented packets should conform to `StringPacket`. 11 | /// Examples include SMTP, IRC, XMPP. 12 | /// 13 | /// See ``Packet`` for full conformance. 14 | public protocol StringPacket: Packet where CollectionType == String { 15 | /// Implement this method to find the first occurance of a valid packet within the data supplied. 16 | /// - Parameters: 17 | /// - context: ``PacketHandlerContext/isEnded`` can be used to determine if the `data` passed is the last to be processed. Useful for handling incomplete packets (such as due to end of file or close of socket). 18 | /// - data: The data to search. The packet must start at the beginning of `data`. 19 | /// - Returns: ``PacketSearchResult`` containing this ``Packet`` if a valid packet is found at the beginning of `data`. Otherwise returns `nil`. 20 | static func findFirstPacket(context: PacketHandlerContext, data: String) -> PacketSearchResult? 21 | } 22 | 23 | /// Declare `String` is a valid `PacketCollectionType` 24 | extension String: PacketCollectionType { 25 | mutating public func _packetProcessor_packetAppend(_ other: String) { 26 | self.append(other) 27 | } 28 | mutating public func _packetProcessor_packetRemoveFirst(_ count: Int) { 29 | self.removeFirst(count) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /docs/favicon.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/Packet Types/PacketProtocols.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketProtocols.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/20/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | /// A type-erased `Packet`. 11 | /// - Note: Primarily used internally; most callers can ignore this. 12 | public protocol AnyPacket { 13 | } 14 | 15 | /// A generic `Packet` type that allows the choice between different `CollectionType`s (either `Data` or `String`) 16 | /// 17 | /// - Note: Primarily used internally; most callers can ignore this. 18 | public protocol Packet: AnyPacket { 19 | /// Must be either `String` or `Data`. You usually do not need to specify this as it will be inferred from your declaration of ``findFirstPacket(context:data:)``. 20 | associatedtype CollectionType 21 | 22 | /// Implement this method to find the first occurance of a valid packet within the data supplied. 23 | /// - Parameters: 24 | /// - context: ``PacketHandlerContext/isEnded`` can be used to determine if the `data` passed is the last to be processed. Useful for handling incomplete packets (such as due to end of file or close of socket). 25 | /// - data: The data to search. The packet must start at the beginning of `data`. Either `String` or `Data` must be used in place of ``CollectionType``. 26 | /// - Returns: ``PacketSearchResult`` containing this ``Packet`` if a valid packet is found at the beginning of `data`. Otherwise returns `nil`. 27 | static func findFirstPacket(context: PacketHandlerContext, data: CollectionType) -> PacketSearchResult? 28 | } 29 | 30 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/datapacket-utf8-02-01.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple UTF-8 decoder 6 | 7 | Created by Danny Sung on 05/05/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct UTF8ToString: DataPacket { 13 | var string: String 14 | 15 | static func findFirstPacket(context: PacketHandlerContext, data: Data) -> PacketSearchResult? { 16 | /// A buffer to append valid converted `String`s until we're ready to return 17 | var string = "" 18 | 19 | /// The last `Data.Index` that was converted to string 20 | var lastConsumedIndex: Data.Index! 21 | 22 | /// Invalid bytes found will generate a UTF-8 Replacement character 23 | let invalidCharacter = "�" 24 | 25 | /// A container to keep track of a range of indexes into `Data` 26 | struct Range { 27 | let startIndex: Data.Index 28 | let endIndex: Data.Index 29 | 30 | init(startIndex: Data.Index, endIndex: Data.Index) { 31 | self.startIndex = startIndex 32 | self.endIndex = endIndex 33 | } 34 | 35 | init(index: Data.Index) { 36 | self.startIndex = index 37 | self.endIndex = index 38 | } 39 | 40 | func incrementEnd() -> Range { 41 | return Range(startIndex: self.startIndex, endIndex: self.endIndex+1) 42 | } 43 | } 44 | 45 | /// TBD 46 | return nil 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | Apache 2 5 |

6 | 7 | # PacketProcessor 8 | 9 | The Swift `PacketProcessor` provides a simple, type-safe way of handling structured packets given a data stream. 10 | 11 | `PacketProcessor` handles the details of buffer management when reading a data stream. Callers need only push newly received data to the `PacketProcessor`. The correct handlers for the appropriately typed packet will be called when appropriate. 12 | 13 | Packet definitions must include rules for validating the packet and returning the number of data elements consumed by the packet. See `DataPacket` and `StringPacket`. 14 | 15 | Streams can have a base collection type of `String` or `Data` by initializing as `PacketProcessor` or `PacketProcessor`. 16 | 17 | 18 | ## Installation 19 | 20 | ### Swift Package Manager 21 | Add the `PacketProcessor ` package to the dependencies within your application's `Package.swift` file. Substitute "x.y.z" with the [latest PacketProcessor release](https://github.com/dannys42/SwiftPacketProcessor/releases). 22 | 23 | ```swift 24 | .package(url: "https://github.com/dannys42/SwiftPacketProcessor", from: "x.y.z") 25 | ``` 26 | 27 | Add `PacketProcessor` to your target's dependencies: 28 | 29 | ```swift 30 | .target(name: "example", dependencies: ["PacketProcessor"]), 31 | ``` 32 | -------------------------------------------------------------------------------- /Tests/PacketProcessorTests/SwiftPacketProcessorForStringTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftPacketProcessorForStringTests.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/16/2022. 6 | // 7 | 8 | import Foundation 9 | import XCTest 10 | @testable import PacketProcessor 11 | 12 | /* 13 | class SwiftPacketProcessorForStringTests: XCTestCase { 14 | struct NewlinePacket: SwiftStringPacket { 15 | static func findFirstPacket(context: PacketHandlerContext, data: String) -> (packet: NewlinePacket, countInPacket: Int)? { 16 | guard let newlineIndex = data.firstIndex(of: "\n") else { 17 | return nil 18 | } 19 | 20 | let payload = data.prefix(upTo: newlineIndex) 21 | let packet = NewlinePacket(payload: String(payload)) 22 | return (packet, payload.count+1) 23 | } 24 | 25 | var payload: String 26 | } 27 | var stringProcessor = SwiftPacketProcessor() 28 | 29 | override func setUpWithError() throws { 30 | self.stringProcessor = SwiftPacketProcessor() 31 | // Put setup code here. This method is called before the invocation of each test method in the class. 32 | } 33 | 34 | override func tearDownWithError() throws { 35 | // Put teardown code here. This method is called after the invocation of each test method in the class. 36 | } 37 | 38 | func testThat_ThereIsOnePacket_WhenNewline() throws { 39 | let expectation = self.expectation(description: "Find a newline.") 40 | let expectedValue = "Hello world!" 41 | var observedValue: String? 42 | 43 | stringProcessor.addHandler(NewlinePacket.self) { p in 44 | observedValue = p.payload 45 | expectation.fulfill() 46 | } 47 | stringProcessor.push("Hello") 48 | stringProcessor.push(" world!\n") 49 | 50 | self.wait(for: [expectation], timeout: Timeouts.successTimeout.rawValue) 51 | XCTAssertEqual(observedValue, expectedValue) 52 | } 53 | 54 | } 55 | 56 | */ 57 | -------------------------------------------------------------------------------- /Tests/PacketProcessorTests/SerialTaskOperation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/28/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | #if false 11 | class SerialTask { 12 | private let opQ: OperationQueue 13 | private let serialTaskOp: SerialTaskOp 14 | typealias AsyncBlock = () async -> Void 15 | 16 | init() { 17 | self.opQ = OperationQueue() 18 | self.opQ.maxConcurrentOperationCount = 1 19 | self.serialTaskOp = SerialTaskOp() 20 | self.opQ.addOperation(self.serialTaskOp) 21 | } 22 | 23 | func addTask(_ handler: @escaping AsyncBlock ) { 24 | serialTaskOp.addTask(handler) 25 | } 26 | 27 | } 28 | 29 | class SerialTaskOp: Operation { 30 | private var handlers: [SerialTask.AsyncBlock] = [] 31 | private let syncQ: DispatchQueue 32 | private let semaphore: DispatchSemaphore 33 | 34 | override init() { 35 | self.syncQ = DispatchQueue(label: "SerialTaskQueue: handler sync queue") 36 | self.semaphore = DispatchSemaphore(value: 0) 37 | super.init() 38 | } 39 | 40 | 41 | override func main() { 42 | while( !self.isCancelled ) { 43 | self.semaphore.wait() 44 | 45 | self.syncQ.sync { 46 | let g = DispatchGroup() 47 | g.enter() 48 | _ = Task { 49 | defer { g.leave() } 50 | 51 | var numHandlersExecuted = 0 52 | for handler in self.handlers { 53 | if self.isCancelled { 54 | break 55 | } 56 | await handler() 57 | numHandlersExecuted += 1 58 | } 59 | self.handlers.removeFirst(numHandlersExecuted) 60 | } 61 | g.wait() 62 | } 63 | } 64 | } 65 | 66 | func addTask(_ handler: @escaping SerialTask.AsyncBlock ) { 67 | self.syncQ.async { 68 | self.handlers.append(handler) 69 | self.semaphore.signal() 70 | } 71 | } 72 | } 73 | #endif 74 | 75 | -------------------------------------------------------------------------------- /docs/js/highlight-js-xml.9c3688c7.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-xml"],{"8dcb":function(e,n){function a(e){const n=e.regex,a=n.concat(/[A-Z_]/,n.optional(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),s=/[A-Za-z0-9._:-]+/,t={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/,contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},c=e.inherit(i,{begin:/\(/,end:/\)/}),l=e.inherit(e.APOS_STRING_MODE,{className:"string"}),r=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),g={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,r,l,c,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[i,c,r,l]}]}]},e.COMMENT(//,{relevance:10}),{begin://,relevance:10},t,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[g],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[g],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:n.concat(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:a,relevance:0,starts:g}]},{className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(a,/>/))),contains:[{className:"name",begin:a,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/data/documentation/packetprocessor/packethandleridentifier.json: -------------------------------------------------------------------------------- 1 | {"primaryContentSections":[{"kind":"declarations","declarations":[{"tokens":[{"kind":"keyword","text":"typealias"},{"kind":"text","text":" "},{"kind":"identifier","text":"PacketHandlerIdentifier"},{"kind":"text","text":" = "},{"kind":"typeIdentifier","text":"UUID","preciseIdentifier":"s:10Foundation4UUIDV"}],"languages":["swift"],"platforms":["macOS"]}]}],"schemaVersion":{"major":0,"minor":2,"patch":0},"sections":[],"variants":[{"paths":["\/documentation\/packetprocessor\/packethandleridentifier"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketHandlerIdentifier","interfaceLanguage":"swift"},"abstract":[{"type":"text","text":"No overview available."}],"kind":"symbol","metadata":{"fragments":[{"kind":"keyword","text":"typealias"},{"kind":"text","text":" "},{"kind":"identifier","text":"PacketHandlerIdentifier"}],"title":"PacketHandlerIdentifier","roleHeading":"Type Alias","role":"symbol","symbolKind":"typealias","externalID":"s:15PacketProcessor0A17HandlerIdentifiera","modules":[{"name":"PacketProcessor"}],"navigatorTitle":[{"kind":"identifier","text":"PacketHandlerIdentifier"}]},"hierarchy":{"paths":[["doc:\/\/PacketProcessor\/documentation\/PacketProcessor"]]},"references":{"doc://PacketProcessor/documentation/PacketProcessor":{"role":"collection","title":"PacketProcessor","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" takes care of buffer management when processing packetized data within streams."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor"},"doc://PacketProcessor/documentation/PacketProcessor/PacketHandlerIdentifier":{"role":"symbol","title":"PacketHandlerIdentifier","fragments":[{"kind":"keyword","text":"typealias"},{"kind":"text","text":" "},{"kind":"identifier","text":"PacketHandlerIdentifier"}],"abstract":[],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketHandlerIdentifier","kind":"symbol","type":"topic","navigatorTitle":[{"kind":"identifier","text":"PacketHandlerIdentifier"}],"url":"\/documentation\/packetprocessor\/packethandleridentifier"}}} -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/datapacket-utf8-02-02.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A simple UTF-8 decoder 6 | 7 | Created by Danny Sung on 05/05/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct UTF8ToString: DataPacket { 13 | var string: String 14 | 15 | static func findFirstPacket(context: PacketHandlerContext, data: Data) -> PacketSearchResult? { 16 | /// A buffer to append valid converted `String`s until we're ready to return 17 | var string = "" 18 | 19 | /// The last `Data.Index` that was converted to string 20 | var lastConsumedIndex: Data.Index! 21 | 22 | /// Invalid bytes found will generate a UTF-8 Replacement character 23 | let invalidCharacter = "�" 24 | 25 | /// A container to keep track of a range of indexes into `Data` 26 | struct Range { 27 | let startIndex: Data.Index 28 | let endIndex: Data.Index 29 | 30 | init(startIndex: Data.Index, endIndex: Data.Index) { 31 | self.startIndex = startIndex 32 | self.endIndex = endIndex 33 | } 34 | 35 | init(index: Data.Index) { 36 | self.startIndex = index 37 | self.endIndex = index 38 | } 39 | 40 | func incrementEnd() -> Range { 41 | return Range(startIndex: self.startIndex, endIndex: self.endIndex+1) 42 | } 43 | } 44 | 45 | enum State { 46 | /// range keeps track of a run of "good" bytes that can be converted and appended to ``string`` 47 | case good(range: Range) 48 | 49 | /// goodRange is the last "good" range that has not yet been appended to ``string``. 50 | /// partialRange keeps track of the start and current index of a multi-byte character 51 | case partial(goodRange: Range, partialRange: Range, count: Int) 52 | 53 | /// an exit condition if we were expecting more bytes in a multi-byte character, but ran out 54 | case incomplete(lastGoodIndex: Data.Index) 55 | 56 | /// an exit condition when everything has been properly converted 57 | case done(lastGoodIndex: Data.Index) 58 | } 59 | 60 | /// TBD 61 | return nil 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/js/highlight-js-markdown.90077643.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-markdown"],{"04b0":function(n,e){function a(n){const e=n.regex,a={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},i={begin:"^[-\\*]{3,}",end:"$"},s={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},c={className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},t={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},g=/[A-Za-z][A-Za-z0-9+.-]*/,d={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:e.concat(/\[.+?\]\(/,g,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},l={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},o={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};l.contains.push(o),o.contains.push(l);let b=[a,d];l.contains=l.contains.concat(b),o.contains=o.contains.concat(b),b=b.concat(l,o);const r={className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:b},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:b}]}]},m={className:"quote",begin:"^>\\s+",contains:b,end:"$"};return{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[r,a,c,l,o,m,s,i,d,t]}}n.exports=a}}]); -------------------------------------------------------------------------------- /Tests/PacketProcessorTests/PartialStringPacketProcessorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PartialStringPacketProcessorTests.swift 3 | // 4 | // 5 | // Created by Danny Sung on 04/29/2022. 6 | // 7 | 8 | import XCTest 9 | @testable import PacketProcessor 10 | 11 | class PartialStringPacketProcessorTests: XCTestCase { 12 | 13 | struct NewlinePacket: StringPacket { 14 | var text: String 15 | 16 | static func findFirstPacket(context: PacketHandlerContext, data: String) -> PacketSearchResult? { 17 | let endOfLineIndex: String.Index 18 | let newlineCount: Int 19 | 20 | if let newlineIndex = data.firstIndex(of: "\n") { 21 | endOfLineIndex = newlineIndex 22 | newlineCount = 1 23 | } else if context.isEnded { 24 | endOfLineIndex = data.endIndex 25 | newlineCount = 0 26 | } else { 27 | return nil 28 | } 29 | 30 | let payload = data.prefix(upTo: endOfLineIndex) 31 | let packet = NewlinePacket(text: String(payload)) 32 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: payload.count+newlineCount) 33 | } 34 | 35 | } 36 | var stringProcessor = PacketProcessor() 37 | 38 | override func setUpWithError() throws { 39 | self.stringProcessor = PacketProcessor() 40 | // Put setup code here. This method is called before the invocation of each test method in the class. 41 | } 42 | 43 | override func tearDownWithError() throws { 44 | // Put teardown code here. This method is called after the invocation of each test method in the class. 45 | } 46 | 47 | func testThat_ThereIsNoPacket_WhenNoNewline_AndNoEnd() throws { 48 | let expectedValue = 0 49 | var count = 0 50 | 51 | stringProcessor.addHandler(NewlinePacket.self) { p in 52 | count += 1 53 | } 54 | stringProcessor.push("Hello") 55 | stringProcessor.push(" world!") 56 | 57 | let observedValue = count 58 | XCTAssertEqual(expectedValue, observedValue) 59 | } 60 | 61 | func testThat_ThereIsOnePacket_WhenNoNewline() throws { 62 | let expectedValue = 1 63 | var count = 0 64 | 65 | stringProcessor.addHandler(NewlinePacket.self) { p in 66 | count += 1 67 | } 68 | stringProcessor.push("Hello") 69 | stringProcessor.push(" world!") 70 | stringProcessor.end() 71 | 72 | let observedValue = count 73 | XCTAssertEqual(expectedValue, observedValue) 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /docs/data/documentation/packetprocessor/gettingstarted.json: -------------------------------------------------------------------------------- 1 | {"primaryContentSections":[{"kind":"content","content":[{"anchor":"Overview","level":2,"type":"heading","text":"Overview"},{"type":"paragraph","inlineContent":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" simplifies the task of converting data streams into type-safe packetized data."}]},{"type":"paragraph","inlineContent":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" has the following features:"}]},{"type":"unorderedList","items":[{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Takes care of buffer management for you"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Allows you to register multiple handlers of the same type"}]}]},{"content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"Has a simple interface for defining packets of fixed or variable length"}]}]}]}]}],"schemaVersion":{"major":0,"minor":2,"patch":0},"sections":[],"variants":[{"paths":["\/documentation\/packetprocessor\/gettingstarted"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/GettingStarted","interfaceLanguage":"swift"},"abstract":[{"type":"text","text":"Easily handle packetized data-streams."}],"kind":"article","metadata":{"roleHeading":"Article","title":"Getting Started with PacketProcessor","role":"article","modules":[{"name":"PacketProcessor"}]},"hierarchy":{"paths":[["doc:\/\/PacketProcessor\/documentation\/PacketProcessor"]]},"seeAlsoSections":[{"title":"Essentials","identifiers":["doc:\/\/PacketProcessor\/tutorials\/Tutorial-TOC"],"generated":true}],"references":{"doc://PacketProcessor/documentation/PacketProcessor":{"role":"collection","title":"PacketProcessor","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" takes care of buffer management when processing packetized data within streams."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor"},"doc://PacketProcessor/tutorials/Tutorial-TOC":{"role":"overview","title":"Examples Packets","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" can help you to easily convert a stream of characters to structured data packets."}],"identifier":"doc:\/\/PacketProcessor\/tutorials\/Tutorial-TOC","kind":"overview","type":"topic","url":"\/tutorials\/tutorial-toc"}}} -------------------------------------------------------------------------------- /docs/data/documentation/packetprocessor/packetcollectiontype/init().json: -------------------------------------------------------------------------------- 1 | {"primaryContentSections":[{"kind":"declarations","declarations":[{"tokens":[{"kind":"keyword","text":"init"},{"kind":"text","text":"()"}],"languages":["swift"],"platforms":["macOS"]}]}],"schemaVersion":{"major":0,"minor":2,"patch":0},"sections":[],"variants":[{"paths":["\/documentation\/packetprocessor\/packetcollectiontype\/init()"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketCollectionType\/init()","interfaceLanguage":"swift"},"abstract":[{"type":"text","text":"No overview available."}],"kind":"symbol","metadata":{"role":"symbol","title":"init()","roleHeading":"Initializer","fragments":[{"kind":"identifier","text":"init"},{"kind":"text","text":"()"}],"symbolKind":"init","externalID":"s:15PacketProcessor0A14CollectionTypePxycfc","required":true,"modules":[{"name":"PacketProcessor"}]},"hierarchy":{"paths":[["doc:\/\/PacketProcessor\/documentation\/PacketProcessor","doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketCollectionType"]]},"references":{"doc://PacketProcessor/documentation/PacketProcessor/PacketCollectionType":{"role":"symbol","title":"PacketCollectionType","fragments":[{"kind":"keyword","text":"protocol"},{"kind":"text","text":" "},{"kind":"identifier","text":"PacketCollectionType"}],"abstract":[{"type":"text","text":"Protocol used to declare data collection types that can be used by "},{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":"."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketCollectionType","kind":"symbol","type":"topic","navigatorTitle":[{"kind":"identifier","text":"PacketCollectionType"}],"url":"\/documentation\/packetprocessor\/packetcollectiontype"},"doc://PacketProcessor/documentation/PacketProcessor":{"role":"collection","title":"PacketProcessor","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" takes care of buffer management when processing packetized data within streams."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor"},"doc://PacketProcessor/documentation/PacketProcessor/PacketCollectionType/init()":{"role":"symbol","title":"init()","fragments":[{"kind":"identifier","text":"init"},{"kind":"text","text":"()"}],"abstract":[],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketCollectionType\/init()","kind":"symbol","required":true,"type":"topic","url":"\/documentation\/packetprocessor\/packetcollectiontype\/init()"}}} -------------------------------------------------------------------------------- /Tests/PacketProcessorTests/DataPacketProcessorTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | @testable import PacketProcessor 4 | 5 | final class DataPacketProcessorTests: XCTestCase { 6 | var dataProcessor = PacketProcessor() 7 | 8 | // A test of "typical" network byte protocols 9 | override func setUpWithError() throws { 10 | self.dataProcessor = PacketProcessor() 11 | // Put setup code here. This method is called before the invocation of each test method in the class. 12 | } 13 | 14 | override func tearDownWithError() throws { 15 | // Put teardown code here. This method is called after the invocation of each test method in the class. 16 | } 17 | 18 | func testThat_DifferentPacketTypes_Are_Different() throws { 19 | let movementId = ObjectIdentifier(PlayerMovement.self) 20 | let attackid = ObjectIdentifier(PlayerAttack.self) 21 | XCTAssertNotEqual(movementId, attackid) 22 | } 23 | 24 | func testThat_PacketId_Is_Static() throws { 25 | let packetId1 = ObjectIdentifier(PlayerMovement.self) 26 | let packetId2 = ObjectIdentifier(PlayerMovement.self) 27 | 28 | XCTAssertEqual(packetId1, packetId2) 29 | } 30 | 31 | func testThat_DifferentPacketsWithSameName_Are_Different() throws { 32 | class Container { 33 | struct PlayerMovement: DataPacket { 34 | static func findFirstPacket(context: PacketHandlerContext, data: Data) -> PacketSearchResult? { 35 | return nil 36 | } 37 | } 38 | } 39 | 40 | let packetId1 = ObjectIdentifier(PlayerMovement.self) 41 | let packetId2 = ObjectIdentifier(Container.PlayerMovement.self) 42 | 43 | XCTAssertNotEqual(packetId1, packetId2) 44 | } 45 | 46 | func testThat_GeneratedMovement_isEqualTo_ParsedMovement() throws { 47 | let inputValue = PlayerMovement(playerId: 0x23, direction: .East) 48 | let expectedValue = inputValue 49 | 50 | let packetData = inputValue.toData() 51 | guard let processedMovement = PlayerMovement.findFirstPacket(context: PacketHandlerContext(), data: packetData) else { 52 | XCTFail("Did not find a valid packet!") 53 | return 54 | } 55 | let observedValue = processedMovement.packet 56 | 57 | XCTAssertEqual(expectedValue, observedValue) 58 | } 59 | 60 | func testExample() throws { 61 | self.dataProcessor.addHandler(PlayerMovement.self) { packet in 62 | print("got movement packet: \(packet)") 63 | } 64 | } 65 | } 66 | 67 | fileprivate extension Data { 68 | func indexOf(character: String) -> Int? { 69 | return self.firstIndex(of: Character("\n").asciiValue!) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-json-02-01.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A JSON packet processor, supporting multiple types of JSON packets. 6 | 7 | Created by Danny Sung on 05/07/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct JSONPacket: StringPacket { 13 | var value: String 14 | 15 | static func findFirstPacket(context: PacketHandlerContext, data: String) -> PacketSearchResult? { 16 | 17 | var objectLevel = 0 18 | enum State { 19 | case unquoted 20 | case quoted 21 | case quotedEscape 22 | } 23 | var state = State.unquoted 24 | var numberOfCharactersConsumed: Int? 25 | 26 | for (index,character) in data.enumerated() { 27 | if numberOfCharactersConsumed != nil { 28 | break 29 | } 30 | if character.isWhitespace { // ignore whitespace 31 | continue 32 | } 33 | var nextState: State 34 | switch state { 35 | case .unquoted: 36 | // Try to find out where the object boundary is 37 | switch character { 38 | case "{": 39 | objectLevel += 1 40 | nextState = state 41 | case "}": 42 | objectLevel -= 1 43 | if objectLevel == 0 { 44 | numberOfCharactersConsumed = index + 1 45 | } 46 | nextState = state 47 | case "\"": 48 | nextState = .quoted 49 | default: 50 | nextState = state 51 | } 52 | case .quoted: 53 | // Once we're inside double-quotes, just keep going until we're no longer quoted, paying attention to escape characters. 54 | switch character { 55 | case "\"": 56 | nextState = .unquoted 57 | case "\\": 58 | nextState = .quotedEscape 59 | default: 60 | nextState = state 61 | } 62 | case .quotedEscape: 63 | // It actually doesn't matter what this character is. We'll simply go back to the quoted state. 64 | nextState = .quoted 65 | } 66 | state = nextState 67 | } 68 | 69 | if let numberOfCharactersConsumed = numberOfCharactersConsumed { 70 | let packet = JSONPacket(value: String(data.prefix(numberOfCharactersConsumed))) 71 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: numberOfCharactersConsumed) 72 | } 73 | return nil 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | 92 | # Custom 93 | # 94 | .DS_Store 95 | /.build 96 | /Packages 97 | /*.xcodeproj 98 | xcuserdata/ 99 | DerivedData/ 100 | .swiftpm/config/registries.json 101 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 102 | .netrc 103 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Tutorials/StringPacket-JSON.tutorial: -------------------------------------------------------------------------------- 1 | @Tutorial(time: 10) { 2 | @Intro(title: "Reading JSON packets from a socket") { 3 | This example demonstrates how we can use ``PacketProcessor`` to manage different JSON packets read from a WebSocket or raw socket. 4 | 5 | } 6 | 7 | @Section(title: "WebSocket") { 8 | @ContentAndMedia { 9 | Since WebSockets are gauranteed to include the entire message upon read, very little is needed to support them. 10 | } 11 | 12 | @Steps { 13 | @Step { 14 | Suppose we have the following JSON objects coming in from a streasm 15 | 16 | @Code(name: "packets.json", file: "stringpacket-json-01-01") 17 | } 18 | 19 | @Step { 20 | We start out defining our structs. 21 | 22 | @Code(name: "jsonpacket.swift", file: "stringpacket-json-01-02") 23 | } 24 | 25 | @Step { 26 | In the case of WebSockets, we can make due without ``PacketProcessor`` by simply attempting to decode our packets in turn. 27 | 28 | @Code(name: "jsonpacket.swift", file: "stringpacket-json-01-03") 29 | } 30 | 31 | @Step { 32 | Alternatively we could use ``PacketProcessor``. 33 | 34 | @Code(name: "jsonpacket.swift", file: "stringpacket-json-01-04") 35 | } 36 | 37 | } 38 | } 39 | 40 | @Section(title: "Raw sockets") { 41 | @ContentAndMedia { 42 | Raw sockets can be a little trickier to work with since messages can be split anywhere. This is where ``PacketProcessor`` can help simplify things a little. 43 | } 44 | 45 | @Steps { 46 | @Step { 47 | First we need a way to buffer and split messages at the JSON message boundary. This is a simple state machine that does just that. It assumes every message is a dictionary. 48 | 49 | @Code(name: "jsonpacket.swift", file: "stringpacket-json-02-01") 50 | } 51 | 52 | @Step { 53 | Once we have that, we're back in a similar situation as the WebSocket. We can decode the JSON messages directly. 54 | 55 | @Code(name: "jsonpacket.swift", file: "stringpacket-json-02-02") 56 | } 57 | 58 | @Step { 59 | Or we can define each JSON object as their own ``DataPacket`` and handle it with a two-stage ``PacketProcessor/PacketProcessor``. 60 | 61 | @Code(name: "jsonpacket.swift", file: "stringpacket-json-02-03") 62 | } 63 | 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /docs/js/highlight-js-java.8326d9d8.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-java"],{"332f":function(e,a){var n="[0-9](_*[0-9])*",s=`\\.(${n})`,i="[0-9a-fA-F](_*[0-9a-fA-F])*",t={className:"number",variants:[{begin:`(\\b(${n})((${s})|\\.)?|(${s}))[eE][+-]?(${n})[fFdD]?\\b`},{begin:`\\b(${n})((${s})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${s})[fFdD]?\\b`},{begin:`\\b(${n})[fFdD]\\b`},{begin:`\\b0[xX]((${i})\\.?|(${i})?\\.(${i}))[pP][+-]?(${n})[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${i})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};function r(e,a,n){return-1===n?"":e.replace(a,s=>r(e,a,n-1))}function c(e){e.regex;const a="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",n=a+r("(?:<"+a+"~~~(?:\\s*,\\s*"+a+"~~~)*>)?",/~~~/g,2),s=["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do"],i=["super","this"],c=["false","true","null"],l=["char","boolean","long","float","int","byte","short","double"],o={keyword:s,literal:c,type:l,built_in:i},b={className:"meta",begin:"@"+a,contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},_={className:"params",begin:/\(/,end:/\)/,keywords:o,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0};return{name:"Java",aliases:["jsp"],keywords:o,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{begin:/import java\.[a-z]+\./,keywords:"import",relevance:2},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/,className:"string",contains:[e.BACKSLASH_ESCAPE]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,a],className:{1:"keyword",3:"title.class"}},{begin:[a,/\s+/,a,/\s+/,/=/],className:{1:"type",3:"variable",5:"operator"}},{begin:[/record/,/\s+/,a],className:{1:"keyword",3:"title.class"},contains:[_,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"new throw return else",relevance:0},{begin:["(?:"+n+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{2:"title.function"},keywords:o,contains:[{className:"params",begin:/\(/,end:/\)/,keywords:o,relevance:0,contains:[b,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,t,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},t,b]}}e.exports=c}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-llvm.6100b125.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-llvm"],{"7c30":function(e,n){function a(e){const n=e.regex,a=/([-a-zA-Z$._][\w$.-]*)/,t={className:"type",begin:/\bi\d+(?=\s|\b)/},i={className:"operator",relevance:0,begin:/=/},c={className:"punctuation",relevance:0,begin:/,/},l={className:"number",variants:[{begin:/0[xX][a-fA-F0-9]+/},{begin:/-?\d+(?:[.]\d+)?(?:[eE][-+]?\d+(?:[.]\d+)?)?/}],relevance:0},r={className:"symbol",variants:[{begin:/^\s*[a-z]+:/}],relevance:0},s={className:"variable",variants:[{begin:n.concat(/%/,a)},{begin:/%\d+/},{begin:/#\d+/}]},o={className:"title",variants:[{begin:n.concat(/@/,a)},{begin:/@\d+/},{begin:n.concat(/!/,a)},{begin:n.concat(/!\d+/,a)},{begin:/!\d+/}]};return{name:"LLVM IR",keywords:"begin end true false declare define global constant private linker_private internal available_externally linkonce linkonce_odr weak weak_odr appending dllimport dllexport common default hidden protected extern_weak external thread_local zeroinitializer undef null to tail target triple datalayout volatile nuw nsw nnan ninf nsz arcp fast exact inbounds align addrspace section alias module asm sideeffect gc dbg linker_private_weak attributes blockaddress initialexec localdynamic localexec prefix unnamed_addr ccc fastcc coldcc x86_stdcallcc x86_fastcallcc arm_apcscc arm_aapcscc arm_aapcs_vfpcc ptx_device ptx_kernel intel_ocl_bicc msp430_intrcc spir_func spir_kernel x86_64_sysvcc x86_64_win64cc x86_thiscallcc cc c signext zeroext inreg sret nounwind noreturn noalias nocapture byval nest readnone readonly inlinehint noinline alwaysinline optsize ssp sspreq noredzone noimplicitfloat naked builtin cold nobuiltin noduplicate nonlazybind optnone returns_twice sanitize_address sanitize_memory sanitize_thread sspstrong uwtable returned type opaque eq ne slt sgt sle sge ult ugt ule uge oeq one olt ogt ole oge ord uno ueq une x acq_rel acquire alignstack atomic catch cleanup filter inteldialect max min monotonic nand personality release seq_cst singlethread umax umin unordered xchg add fadd sub fsub mul fmul udiv sdiv fdiv urem srem frem shl lshr ashr and or xor icmp fcmp phi call trunc zext sext fptrunc fpext uitofp sitofp fptoui fptosi inttoptr ptrtoint bitcast addrspacecast select va_arg ret br switch invoke unwind unreachable indirectbr landingpad resume malloc alloca free load store getelementptr extractelement insertelement shufflevector getresult extractvalue insertvalue atomicrmw cmpxchg fence argmemonly double",contains:[t,e.COMMENT(/;\s*$/,null,{relevance:0}),e.COMMENT(/;/,/$/),e.QUOTE_STRING_MODE,{className:"string",variants:[{begin:/"/,end:/[^\\]"/}]},o,c,i,s,r,l]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-objectivec.bcdf5156.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-objectivec"],{"9bf2":function(e,n){function _(e){const n={className:"built_in",begin:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"},_=/[a-zA-Z@][a-zA-Z0-9_]*/,i=["int","float","while","char","export","sizeof","typedef","const","struct","for","union","unsigned","long","volatile","static","bool","mutable","if","do","return","goto","void","enum","else","break","extern","asm","case","short","default","double","register","explicit","signed","typename","this","switch","continue","wchar_t","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","super","unichar","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],t=["false","true","FALSE","TRUE","nil","YES","NO","NULL"],a=["BOOL","dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"],o={$pattern:_,keyword:i,literal:t,built_in:a},s={$pattern:_,keyword:["@interface","@class","@protocol","@implementation"]};return{name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],keywords:o,illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+s.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:s,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}e.exports=_}}]); -------------------------------------------------------------------------------- /docs/data/documentation/packetprocessor/packetcollectiontype/count.json: -------------------------------------------------------------------------------- 1 | {"primaryContentSections":[{"kind":"declarations","declarations":[{"tokens":[{"kind":"keyword","text":"var"},{"kind":"text","text":" "},{"kind":"identifier","text":"count"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"Int","preciseIdentifier":"s:Si"},{"kind":"text","text":" { "},{"kind":"keyword","text":"get"},{"kind":"text","text":" }"}],"languages":["swift"],"platforms":["macOS"]}]}],"schemaVersion":{"major":0,"minor":2,"patch":0},"sections":[],"variants":[{"paths":["\/documentation\/packetprocessor\/packetcollectiontype\/count"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketCollectionType\/count","interfaceLanguage":"swift"},"abstract":[{"type":"text","text":"Number of elements in the collection."}],"kind":"symbol","metadata":{"role":"symbol","title":"count","roleHeading":"Instance Property","fragments":[{"kind":"keyword","text":"var"},{"kind":"text","text":" "},{"kind":"identifier","text":"count"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"Int","preciseIdentifier":"s:Si"}],"symbolKind":"property","externalID":"s:15PacketProcessor0A14CollectionTypeP5countSivp","required":true,"modules":[{"name":"PacketProcessor"}]},"hierarchy":{"paths":[["doc:\/\/PacketProcessor\/documentation\/PacketProcessor","doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketCollectionType"]]},"references":{"doc://PacketProcessor/documentation/PacketProcessor/PacketCollectionType/count":{"role":"symbol","title":"count","fragments":[{"kind":"keyword","text":"var"},{"kind":"text","text":" "},{"kind":"identifier","text":"count"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"Int","preciseIdentifier":"s:Si"}],"abstract":[{"type":"text","text":"Number of elements in the collection."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketCollectionType\/count","kind":"symbol","required":true,"type":"topic","url":"\/documentation\/packetprocessor\/packetcollectiontype\/count"},"doc://PacketProcessor/documentation/PacketProcessor":{"role":"collection","title":"PacketProcessor","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" takes care of buffer management when processing packetized data within streams."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor"},"doc://PacketProcessor/documentation/PacketProcessor/PacketCollectionType":{"role":"symbol","title":"PacketCollectionType","fragments":[{"kind":"keyword","text":"protocol"},{"kind":"text","text":" "},{"kind":"identifier","text":"PacketCollectionType"}],"abstract":[{"type":"text","text":"Protocol used to declare data collection types that can be used by "},{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":"."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketCollectionType","kind":"symbol","type":"topic","navigatorTitle":[{"kind":"identifier","text":"PacketCollectionType"}],"url":"\/documentation\/packetprocessor\/packetcollectiontype"}}} -------------------------------------------------------------------------------- /docs/js/highlight-js-bash.1b52852f.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-bash"],{f0f8:function(e,s){function t(e){const s=e.regex,t={},n={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]};Object.assign(t,{className:"variable",variants:[{begin:s.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},n]});const a={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},c={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,t,a]};a.contains.push(c);const o={className:"",begin:/\\"/},r={className:"string",begin:/'/,end:/'/},l={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]},p=["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"],d=e.SHEBANG({binary:`(${p.join("|")})`,relevance:10}),h={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0},m=["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"],u=["true","false"],b={match:/(\/[a-z._-]+)+/},g=["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset"],f=["alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias"],w=["autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp"],k=["chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"];return{name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z._-]+\b/,keyword:m,literal:u,built_in:[...g,...f,"set","shopt",...w,...k]},contains:[d,e.SHEBANG(),h,l,e.HASH_COMMENT_MODE,i,b,c,o,r,t]}}e.exports=t}}]); -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-json-02-02.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A JSON packet processor, supporting multiple types of JSON packets. 6 | 7 | Created by Danny Sung on 05/07/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct JSONPacket: StringPacket { 13 | var value: String 14 | 15 | static func findFirstPacket(context: PacketHandlerContext, data: String) -> PacketSearchResult? { 16 | 17 | var objectLevel = 0 18 | enum State { 19 | case unquoted 20 | case quoted 21 | case quotedEscape 22 | } 23 | var state = State.unquoted 24 | var numberOfCharactersConsumed: Int? 25 | 26 | for (index,character) in data.enumerated() { 27 | if numberOfCharactersConsumed != nil { 28 | break 29 | } 30 | if character.isWhitespace { // ignore whitespace 31 | continue 32 | } 33 | var nextState: State 34 | switch state { 35 | case .unquoted: 36 | // Try to find out where the object boundary is 37 | switch character { 38 | case "{": 39 | objectLevel += 1 40 | nextState = state 41 | case "}": 42 | objectLevel -= 1 43 | if objectLevel == 0 { 44 | numberOfCharactersConsumed = index + 1 45 | } 46 | nextState = state 47 | case "\"": 48 | nextState = .quoted 49 | default: 50 | nextState = state 51 | } 52 | case .quoted: 53 | // Once we're inside double-quotes, just keep going until we're no longer quoted, paying attention to escape characters. 54 | switch character { 55 | case "\"": 56 | nextState = .unquoted 57 | case "\\": 58 | nextState = .quotedEscape 59 | default: 60 | nextState = state 61 | } 62 | case .quotedEscape: 63 | // It actually doesn't matter what this character is. We'll simply go back to the quoted state. 64 | nextState = .quoted 65 | } 66 | state = nextState 67 | } 68 | 69 | if let numberOfCharactersConsumed = numberOfCharactersConsumed { 70 | let packet = JSONPacket(value: String(data.prefix(numberOfCharactersConsumed))) 71 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: numberOfCharactersConsumed) 72 | } 73 | return nil 74 | } 75 | } 76 | 77 | struct PlayerMove: Codable { 78 | let playerId: Int 79 | let move: Coordinates 80 | } 81 | 82 | struct PlayerAttack: Codable { 83 | let playerId: Int 84 | let attack: Coordinates 85 | let weapon: String 86 | } 87 | 88 | let jsonProcessor = PacketProcessor() 89 | 90 | jsonProcessor.addHandler(JSONPacket.self) { packet in 91 | let packetData = packet.value.data(using: .utf8)! 92 | if let playerMove = try? jsonDecoder.decode(PlayerMove.self, from: packetData) { 93 | // handle move 94 | } else if let playerAttack = try? jsonDecoder.decode(PlayerAttack.self, from: packetData) { 95 | // handle attack 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Tutorials/DataPacket-utf8.tutorial: -------------------------------------------------------------------------------- 1 | @Tutorial(time: 15) { 2 | @Intro(title: "UTF-8 to String Converter") { 3 | The standard approach to UTF-8 conversion is to load all UTF-8 data into a `Data()` object, then convert to a `String` using `String(data:utf8)`. While this works, it can be problematic in a couple areas: 4 | 5 | * High Memory - If loading from a very large file, this could take a lot of memory and time before being able to render anything on-screen. 6 | * Latency - If reading a stream of bytes from a network socket, there may be occasions where you want to render partial data to the screen without having to wait until the full content is loaded. 7 | 8 | While we'll still rely on Swift's built-in `String(data:utf8)` function, using the packet processor will resolve these issues by allowing us to convert any valid data we have to strings and render it on-the-fly with much lower memory and latency. 9 | } 10 | 11 | @Section(title: "The naive way") { 12 | @ContentAndMedia { 13 | 14 | } 15 | 16 | @Steps { 17 | @Step { 18 | We start out by defining `UTF8ToString` as a ``PacketProcessor/DataPacket``, since we are expecting to push blocks of `Data` into the ``PacketProcessor/PacketProcessor``. 19 | 20 | @Code(name: "UTF8ToString.swift", file: "datapacket-utf8-01-01") 21 | } 22 | @Step { 23 | Simply passing the `Data` into `String(data:utf8)` does not work since UTF-8 has variable-length characters. If `Data` has split any of the characters, then `String(data:utf8)` will return nil and no conversion will happen. 24 | 25 | Clearly we need to do more in order to properly process UTF-8. 26 | 27 | @Code(name: "UTF8ToString.swift", file: "datapacket-utf8-01-02") 28 | } 29 | 30 | } 31 | } 32 | 33 | @Section(title: "Processing a stream") { 34 | @ContentAndMedia { 35 | A more complete implementation. We'll still rely on `String(data:utf8)` to do the heavy lifting of actually converting UTF-8 to Strings, however we need to do some bookkeeping to ensure we handle partial data appropriately. 36 | } 37 | @Steps { 38 | @Step { 39 | We start by creating some book keeping variables. `Range` will be used to keep track of range of `Data.Index`es. 40 | 41 | @Code(name: "UTF8ToString.swift", file: "datapacket-utf8-02-01") 42 | } 43 | 44 | @Step { 45 | We'll be creating a state machine, so let's define a few states. 46 | 47 | @Code(name: "UTF8ToString.swift", file: "datapacket-utf8-02-02") 48 | } 49 | 50 | @Step { 51 | Create the state machine. 52 | 53 | @Code(name: "UTF8ToString.swift", file: "datapacket-utf8-02-03") 54 | } 55 | 56 | @Step { 57 | Next we must ensure we properly handle "end" conditions correctly if we're expecting more information. 58 | 59 | @Code(name: "UTF8ToString.swift", file: "datapacket-utf8-02-04") 60 | } 61 | 62 | @Step { 63 | Finally we return the packet as well as the number of bytes consumed. 64 | 65 | @Code(name: "UTF8ToString.swift", file: "datapacket-utf8-02-05") 66 | } 67 | 68 | } 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /docs/js/highlight-js-custom-markdown.7cffc4b3.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-custom-markdown","highlight-js-markdown"],{"04b0":function(n,e){function a(n){const e=n.regex,a={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},i={begin:"^[-\\*]{3,}",end:"$"},s={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},t={className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},c={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},d=/[A-Za-z][A-Za-z0-9+.-]*/,l={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:e.concat(/\[.+?\]\(/,d,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},g={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},o={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};g.contains.push(o),o.contains.push(g);let r=[a,l];g.contains=g.contains.concat(r),o.contains=o.contains.concat(r),r=r.concat(g,o);const b={className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:r},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:r}]}]},u={className:"quote",begin:"^>\\s+",contains:r,end:"$"};return{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[b,a,t,g,o,u,s,i,l,c]}}n.exports=a},"84cb":function(n,e,a){"use strict";a.r(e);var i=a("04b0"),s=a.n(i);const t={begin:"",returnBegin:!0,contains:[{className:"link",begin:"doc:",end:">",excludeEnd:!0}]},c={className:"link",begin:/`{2}(?!`)/,end:/`{2}(?!`)/,excludeBegin:!0,excludeEnd:!0},d={begin:"^>\\s+[Note:|Tip:|Important:|Experiment:|Warning:]",end:"$",returnBegin:!0,contains:[{className:"quote",begin:"^>",end:"\\s+"},{className:"type",begin:"Note|Tip|Important|Experiment|Warning",end:":"},{className:"quote",begin:".*",end:"$",endsParent:!0}]},l={begin:"@",end:"[{\\)\\s]",returnBegin:!0,contains:[{className:"title",begin:"@",end:"[\\s+(]",excludeEnd:!0},{begin:":",end:"[,\\)\n\t]",excludeBegin:!0,keywords:{literal:"true false null undefined"},contains:[{className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",endsWithParent:!0,excludeEnd:!0},{className:"string",variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}],endsParent:!0},{className:"link",begin:"http|https",endsWithParent:!0,excludeEnd:!0}]}]};e["default"]=function(n){const e=s()(n),a=e.contains.find(({className:n})=>"code"===n);a.variants=a.variants.filter(({begin:n})=>!n.includes("( {4}|\\t)"));const i=[...e.contains.filter(({className:n})=>"code"!==n),a];return{...e,contains:[c,t,d,l,...i]}}}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-python.c214ed92.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-python"],{9510:function(e,n){function a(e){const n=e.regex,a=/[\p{XID_Start}_]\p{XID_Continue}*/u,i=["and","as","assert","async","await","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],s=["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],t=["__debug__","Ellipsis","False","None","NotImplemented","True"],r=["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"],l={$pattern:/[A-Za-z]\w+|__\w+__/,keyword:i,built_in:s,literal:t,type:r},o={className:"meta",begin:/^(>>>|\.\.\.) /},b={className:"subst",begin:/\{/,end:/\}/,keywords:l,illegal:/#/},c={begin:/\{\{/,relevance:0},d={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,o],relevance:10},{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,o],relevance:10},{begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,o,c,b]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,o,c,b]},{begin:/([uU]|[rR])'/,end:/'/,relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,c,b]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,c,b]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},p="[0-9](_?[0-9])*",g=`(\\b(${p}))?\\.(${p})|\\b(${p})\\.`,m={className:"number",relevance:0,variants:[{begin:`(\\b(${p})|(${g}))[eE][+-]?(${p})[jJ]?\\b`},{begin:`(${g})[jJ]?`},{begin:"\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?\\b"},{begin:"\\b0[bB](_?[01])+[lL]?\\b"},{begin:"\\b0[oO](_?[0-7])+[lL]?\\b"},{begin:"\\b0[xX](_?[0-9a-fA-F])+[lL]?\\b"},{begin:`\\b(${p})[jJ]\\b`}]},_={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:l,contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},u={className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:["self",o,m,d,e.HASH_COMMENT_MODE]}]};return b.contains=[d,m,o],{name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:l,illegal:/(<\/|->|\?)|=>/,contains:[o,m,{begin:/\bself\b/},{beginKeywords:"if",relevance:0},d,_,e.HASH_COMMENT_MODE,{match:[/def/,/\s+/,a],scope:{1:"keyword",3:"title.function"},contains:[u]},{variants:[{match:[/class/,/\s+/,a,/\s*/,/\(\s*/,a,/\s*\)/]},{match:[/class/,/\s+/,a]}],scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[m,u,d]}]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/data/documentation/packetprocessor/packetsearchresult/packet.json: -------------------------------------------------------------------------------- 1 | {"primaryContentSections":[{"kind":"declarations","declarations":[{"tokens":[{"kind":"keyword","text":"let"},{"kind":"text","text":" "},{"kind":"identifier","text":"packet"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"P"}],"languages":["swift"],"platforms":["macOS"]}]}],"schemaVersion":{"major":0,"minor":2,"patch":0},"sections":[],"variants":[{"paths":["\/documentation\/packetprocessor\/packetsearchresult\/packet"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketSearchResult\/packet","interfaceLanguage":"swift"},"abstract":[{"type":"text","text":"The "},{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/Packet"},{"type":"text","text":" found"}],"kind":"symbol","metadata":{"fragments":[{"kind":"keyword","text":"let"},{"kind":"text","text":" "},{"kind":"identifier","text":"packet"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"P"}],"title":"packet","roleHeading":"Instance Property","role":"symbol","symbolKind":"property","externalID":"s:15PacketProcessor0A12SearchResultV6packetxvp","modules":[{"name":"PacketProcessor"}]},"hierarchy":{"paths":[["doc:\/\/PacketProcessor\/documentation\/PacketProcessor","doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketSearchResult"]]},"references":{"doc://PacketProcessor/documentation/PacketProcessor":{"role":"collection","title":"PacketProcessor","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" takes care of buffer management when processing packetized data within streams."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor"},"doc://PacketProcessor/documentation/PacketProcessor/PacketSearchResult":{"role":"symbol","title":"PacketSearchResult","fragments":[{"kind":"keyword","text":"struct"},{"kind":"text","text":" "},{"kind":"identifier","text":"PacketSearchResult"}],"abstract":[],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketSearchResult","kind":"symbol","type":"topic","navigatorTitle":[{"kind":"identifier","text":"PacketSearchResult"}],"url":"\/documentation\/packetprocessor\/packetsearchresult"},"doc://PacketProcessor/documentation/PacketProcessor/PacketSearchResult/packet":{"role":"symbol","title":"packet","fragments":[{"kind":"keyword","text":"let"},{"kind":"text","text":" "},{"kind":"identifier","text":"packet"},{"kind":"text","text":": "},{"kind":"typeIdentifier","text":"P"}],"abstract":[{"type":"text","text":"The "},{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/Packet"},{"type":"text","text":" found"}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketSearchResult\/packet","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor\/packetsearchresult\/packet"},"doc://PacketProcessor/documentation/PacketProcessor/Packet":{"role":"symbol","title":"Packet","fragments":[{"kind":"keyword","text":"protocol"},{"kind":"text","text":" "},{"kind":"identifier","text":"Packet"}],"abstract":[{"type":"text","text":"A generic "},{"type":"codeVoice","code":"Packet"},{"type":"text","text":" type that allows the choice between different "},{"type":"codeVoice","code":"CollectionType"},{"type":"text","text":"s (either "},{"type":"codeVoice","code":"Data"},{"type":"text","text":" or "},{"type":"codeVoice","code":"String"},{"type":"text","text":")"}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/Packet","kind":"symbol","type":"topic","navigatorTitle":[{"kind":"identifier","text":"Packet"}],"url":"\/documentation\/packetprocessor\/packet"}}} -------------------------------------------------------------------------------- /docs/js/highlight-js-ruby.f889d392.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-ruby"],{"82cb":function(e,n){function a(e){const n=e.regex,a="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",i={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__",built_in:"proc lambda",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},b={begin:"#<",end:">"},c=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],r={className:"subst",begin:/#\{/,end:/\}/,keywords:i},d={className:"string",contains:[e.BACKSLASH_ESCAPE,r],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,r]})]}]},t="[1-9](_?[0-9])*|0",o="[0-9](_?[0-9])*",g={className:"number",relevance:0,variants:[{begin:`\\b(${t})(\\.(${o}))?([eE][+-]?(${o})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},l={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:i},_=[d,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE,relevance:0}]}].concat(c)},{className:"function",begin:n.concat(/def\s+/,n.lookahead(a+"\\s*(\\(|;|$)")),relevance:0,keywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:a}),l].concat(c)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[d,{begin:a}],relevance:0},g,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:i},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,r],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(b,c),relevance:0}].concat(b,c);r.contains=_,l.contains=_;const w="[>?]>",E="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>",N=[{begin:/^\s*=>/,starts:{end:"$",contains:_}},{className:"meta",begin:"^("+w+"|"+E+"|"+u+")(?=[ ])",starts:{end:"$",contains:_}}];return c.unshift(b),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:i,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(N).concat(c).concat(_)}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/js/highlight-js-c.d1db3f17.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-c"],{"1fe5":function(e,n){function s(e){const n=e.regex,s=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]}),t="decltype\\(auto\\)",a="[a-zA-Z_]\\w*::",i="<[^<>]+>",r="("+t+"|"+n.optional(a)+"[a-zA-Z_]\\w*"+n.optional(i)+")",l={className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{match:/\batomic_[a-z]{3,6}\b/}]},o="\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)",c={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'("+o+"|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},d={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},u={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(c,{className:"string"}),{className:"string",begin:/<.*?>/},s,e.C_BLOCK_COMMENT_MODE]},g={className:"title",begin:n.optional(a)+e.IDENT_RE,relevance:0},p=n.optional(a)+e.IDENT_RE+"\\s*\\(",m=["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],_=["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"],f={keyword:m,type:_,literal:"true false NULL",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"},b=[u,l,s,e.C_BLOCK_COMMENT_MODE,d,c],w={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:f,contains:b.concat([{begin:/\(/,end:/\)/,keywords:f,contains:b.concat(["self"]),relevance:0}]),relevance:0},h={begin:"("+r+"[\\*&\\s]+)+"+p,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:f,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:t,keywords:f,relevance:0},{begin:p,returnBegin:!0,contains:[e.inherit(g,{className:"title.function"})],relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:f,relevance:0,contains:[s,e.C_BLOCK_COMMENT_MODE,c,d,l,{begin:/\(/,end:/\)/,keywords:f,relevance:0,contains:["self",s,e.C_BLOCK_COMMENT_MODE,c,d,l]}]},l,s,e.C_BLOCK_COMMENT_MODE,u]};return{name:"C",aliases:["h"],keywords:f,disableAutodetect:!0,illegal:"=]/,contains:[{beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:u,strings:c,keywords:f}}}e.exports=s}}]); -------------------------------------------------------------------------------- /docs/data/documentation/packetprocessor/packetprocessor/init().json: -------------------------------------------------------------------------------- 1 | {"primaryContentSections":[{"kind":"declarations","declarations":[{"tokens":[{"kind":"keyword","text":"init"},{"kind":"text","text":"()"}],"languages":["swift"],"platforms":["macOS"]}]}],"schemaVersion":{"major":0,"minor":2,"patch":0},"sections":[],"variants":[{"paths":["\/documentation\/packetprocessor\/packetprocessor\/init()"],"traits":[{"interfaceLanguage":"swift"}]}],"identifier":{"url":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketProcessor\/init()","interfaceLanguage":"swift"},"abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" should be initializd as "},{"type":"codeVoice","code":"PacketProcessor"},{"type":"text","text":" or "},{"type":"codeVoice","code":"PacketProcessor"},{"type":"text","text":" depending on whehter you will be "},{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketProcessor\/push(_:)"},{"type":"text","text":"ing "},{"type":"codeVoice","code":"String"},{"type":"text","text":" or "},{"type":"codeVoice","code":"Data"},{"type":"text","text":" elements, respectively."}],"kind":"symbol","metadata":{"fragments":[{"kind":"identifier","text":"init"},{"kind":"text","text":"()"}],"title":"init()","roleHeading":"Initializer","role":"symbol","symbolKind":"init","externalID":"s:15PacketProcessorAACAByxGycfc","modules":[{"name":"PacketProcessor"}]},"hierarchy":{"paths":[["doc:\/\/PacketProcessor\/documentation\/PacketProcessor","doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketProcessor"]]},"references":{"doc://PacketProcessor/documentation/PacketProcessor/PacketProcessor/push(_:)":{"role":"symbol","title":"push(_:)","fragments":[{"kind":"keyword","text":"func"},{"kind":"text","text":" "},{"kind":"identifier","text":"push"},{"kind":"text","text":"("},{"kind":"typeIdentifier","text":"CollectionType"},{"kind":"text","text":")"}],"abstract":[{"type":"text","text":"Call when more data in the stream is received."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketProcessor\/push(_:)","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor\/packetprocessor\/push(_:)"},"doc://PacketProcessor/documentation/PacketProcessor/PacketProcessor/init()":{"role":"symbol","title":"init()","fragments":[{"kind":"identifier","text":"init"},{"kind":"text","text":"()"}],"abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" should be initializd as "},{"type":"codeVoice","code":"PacketProcessor"},{"type":"text","text":" or "},{"type":"codeVoice","code":"PacketProcessor"},{"type":"text","text":" depending on whehter you will be "},{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketProcessor\/push(_:)"},{"type":"text","text":"ing "},{"type":"codeVoice","code":"String"},{"type":"text","text":" or "},{"type":"codeVoice","code":"Data"},{"type":"text","text":" elements, respectively."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketProcessor\/init()","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor\/packetprocessor\/init()"},"doc://PacketProcessor/documentation/PacketProcessor":{"role":"collection","title":"PacketProcessor","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" takes care of buffer management when processing packetized data within streams."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor"},"doc://PacketProcessor/documentation/PacketProcessor/PacketProcessor":{"role":"symbol","title":"PacketProcessor","fragments":[{"kind":"keyword","text":"class"},{"kind":"text","text":" "},{"kind":"identifier","text":"PacketProcessor"}],"abstract":[{"type":"text","text":"Provides a simple, type-safe way of handling structured packets given a data stream."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor\/PacketProcessor","kind":"symbol","type":"topic","navigatorTitle":[{"kind":"identifier","text":"PacketProcessor"}],"url":"\/documentation\/packetprocessor\/packetprocessor"}}} -------------------------------------------------------------------------------- /docs/js/highlight-js-php.cc8d6c27.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-php"],{2907:function(e,r){function t(e){const r={className:"variable",begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*(?![A-Za-z0-9])(?![$])"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]},n=e.inherit(e.APOS_STRING_MODE,{illegal:null}),i=e.inherit(e.QUOTE_STRING_MODE,{illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(a)}),o=e.END_SAME_AS_BEGIN({begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/,contains:e.QUOTE_STRING_MODE.contains.concat(a)}),l={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[e.inherit(n,{begin:"b'",end:"'"}),e.inherit(i,{begin:'b"',end:'"'}),i,n,o]},c={className:"number",variants:[{begin:"\\b0b[01]+(?:_[01]+)*\\b"},{begin:"\\b0o[0-7]+(?:_[0-7]+)*\\b"},{begin:"\\b0x[\\da-f]+(?:_[\\da-f]+)*\\b"},{begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:e[+-]?\\d+)?"}],relevance:0},s={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match|0 mixed new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException UnhandledMatchError ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable WeakReference WeakMap Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{case_insensitive:!0,keywords:s,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use"},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:s,contains:["self",r,e.C_BLOCK_COMMENT_MODE,l,c]}]},{className:"class",variants:[{beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",relevance:0,end:";",contains:[e.UNDERSCORE_TITLE_MODE]},l,c]}}e.exports=t}}]); -------------------------------------------------------------------------------- /docs/data/tutorials/tutorial-toc.json: -------------------------------------------------------------------------------- 1 | {"metadata":{"role":"overview","title":"Examples Packets","categoryPathComponent":"Tutorial-TOC","category":"Tutorials","estimatedTime":"30min"},"hierarchy":{"paths":[],"reference":"doc:\/\/PacketProcessor\/tutorials\/Tutorial-TOC"},"schemaVersion":{"major":0,"minor":2,"patch":0},"kind":"overview","identifier":{"url":"doc:\/\/PacketProcessor\/tutorials\/Tutorial-TOC","interfaceLanguage":"swift"},"sections":[{"kind":"hero","title":"Examples Packets","content":[{"type":"paragraph","inlineContent":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" can help you to easily convert a stream of characters to structured data packets."}]}],"action":{"overridingTitleInlineContent":[{"type":"text","text":"Get started"}],"isActive":true,"type":"reference","identifier":"doc:\/\/PacketProcessor\/tutorials\/PacketProcessor\/StringPacket-Logfile","overridingTitle":"Get started"}},{"kind":"volume","content":[],"name":null,"image":null,"chapters":[{"name":"Reading log files","content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"This example demonstrates how we might read from a log file."}]}],"tutorials":["doc:\/\/PacketProcessor\/tutorials\/PacketProcessor\/StringPacket-Logfile"]},{"name":"Processing messages from sockets","content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"This example demonstrates how we might handle JSON messages from web sockets."}]}],"tutorials":["doc:\/\/PacketProcessor\/tutorials\/PacketProcessor\/StringPacket-JSON"]},{"name":"Converting UTF-8 byte streams to Strings","content":[{"type":"paragraph","inlineContent":[{"type":"text","text":"An example working with variable length byte streams."}]}],"tutorials":["doc:\/\/PacketProcessor\/tutorials\/PacketProcessor\/DataPacket-utf8"]}]}],"references":{"doc://PacketProcessor/tutorials/PacketProcessor/StringPacket-JSON":{"role":"project","title":"Reading JSON packets from a socket","estimatedTime":"10min","abstract":[{"type":"text","text":"This example demonstrates how we can use "},{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" to manage different JSON packets read from a WebSocket or raw socket."}],"identifier":"doc:\/\/PacketProcessor\/tutorials\/PacketProcessor\/StringPacket-JSON","kind":"project","type":"topic","url":"\/tutorials\/packetprocessor\/stringpacket-json"},"doc://PacketProcessor/tutorials/PacketProcessor/StringPacket-Logfile":{"role":"project","title":"Line oriented String Packets","estimatedTime":"5min","abstract":[{"type":"text","text":"A simple variable-length packet for reading lines of text (e.g. from log files)."}],"identifier":"doc:\/\/PacketProcessor\/tutorials\/PacketProcessor\/StringPacket-Logfile","kind":"project","type":"topic","url":"\/tutorials\/packetprocessor\/stringpacket-logfile"},"doc://PacketProcessor/documentation/PacketProcessor":{"role":"collection","title":"PacketProcessor","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" takes care of buffer management when processing packetized data within streams."}],"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor","kind":"symbol","type":"topic","url":"\/documentation\/packetprocessor"},"doc://PacketProcessor/tutorials/Tutorial-TOC":{"role":"overview","title":"Examples Packets","abstract":[{"type":"reference","isActive":true,"identifier":"doc:\/\/PacketProcessor\/documentation\/PacketProcessor"},{"type":"text","text":" can help you to easily convert a stream of characters to structured data packets."}],"identifier":"doc:\/\/PacketProcessor\/tutorials\/Tutorial-TOC","kind":"overview","type":"topic","url":"\/tutorials\/tutorial-toc"},"doc://PacketProcessor/tutorials/PacketProcessor/DataPacket-utf8":{"role":"project","title":"UTF-8 to String Converter","estimatedTime":"15min","abstract":[{"type":"text","text":"The standard approach to UTF-8 conversion is to load all UTF-8 data into a "},{"type":"codeVoice","code":"Data()"},{"type":"text","text":" object, then convert to a "},{"type":"codeVoice","code":"String"},{"type":"text","text":" using "},{"type":"codeVoice","code":"String(data:utf8)"},{"type":"text","text":". While this works, it can be problematic in a couple areas:"}],"identifier":"doc:\/\/PacketProcessor\/tutorials\/PacketProcessor\/DataPacket-utf8","kind":"project","type":"topic","url":"\/tutorials\/packetprocessor\/datapacket-utf8"}}} -------------------------------------------------------------------------------- /Sources/PacketProcessor/PacketProcessor.docc/Resources/code-files/stringpacket-json-02-03.swift: -------------------------------------------------------------------------------- 1 | /* 2 | See LICENSE file for this sample’s licensing information. 3 | 4 | Abstract: 5 | A JSON packet processor, supporting multiple types of JSON packets. 6 | 7 | Created by Danny Sung on 05/07/2022. 8 | */ 9 | 10 | import Foundation 11 | 12 | struct JSONPacket: StringPacket { 13 | var value: String 14 | 15 | static func findFirstPacket(context: PacketHandlerContext, data: String) -> PacketSearchResult? { 16 | 17 | var objectLevel = 0 18 | enum State { 19 | case unquoted 20 | case quoted 21 | case quotedEscape 22 | } 23 | var state = State.unquoted 24 | var numberOfCharactersConsumed: Int? 25 | 26 | for (index,character) in data.enumerated() { 27 | if numberOfCharactersConsumed != nil { 28 | break 29 | } 30 | if character.isWhitespace { // ignore whitespace 31 | continue 32 | } 33 | var nextState: State 34 | switch state { 35 | case .unquoted: 36 | // Try to find out where the object boundary is 37 | switch character { 38 | case "{": 39 | objectLevel += 1 40 | nextState = state 41 | case "}": 42 | objectLevel -= 1 43 | if objectLevel == 0 { 44 | numberOfCharactersConsumed = index + 1 45 | } 46 | nextState = state 47 | case "\"": 48 | nextState = .quoted 49 | default: 50 | nextState = state 51 | } 52 | case .quoted: 53 | // Once we're inside double-quotes, just keep going until we're no longer quoted, paying attention to escape characters. 54 | switch character { 55 | case "\"": 56 | nextState = .unquoted 57 | case "\\": 58 | nextState = .quotedEscape 59 | default: 60 | nextState = state 61 | } 62 | case .quotedEscape: 63 | // It actually doesn't matter what this character is. We'll simply go back to the quoted state. 64 | nextState = .quoted 65 | } 66 | state = nextState 67 | } 68 | 69 | if let numberOfCharactersConsumed = numberOfCharactersConsumed { 70 | let packet = JSONPacket(value: String(data.prefix(numberOfCharactersConsumed))) 71 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: numberOfCharactersConsumed) 72 | } 73 | return nil 74 | } 75 | } 76 | 77 | struct PlayerMove: Codable, DataPacket { 78 | let playerId: Int 79 | let move: Coordinates 80 | 81 | static func findFirstPacket(context: PacketHandlerContext, data: Data) -> PacketSearchResult? { 82 | 83 | let decoder = JSONDecoder() 84 | if let packet = try? decoder.decode(PlayerMovePacket.self, from: data) { 85 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: data.count) 86 | } 87 | 88 | return nil 89 | } 90 | } 91 | 92 | struct PlayerAttack: Codable, DataPacket { 93 | let playerId: Int 94 | let attack: Coordinates 95 | let weapon: String 96 | 97 | static func findFirstPacket(context: PacketHandlerContext, data: Data) -> PacketSearchResult? { 98 | 99 | let decoder = JSONDecoder() 100 | if let packet = try? decoder.decode(PlayerAttackPacket.self, from: data) { 101 | return PacketSearchResult(packet: packet, numberOfElementsConsumedByPacket: data.count) 102 | } 103 | 104 | return nil 105 | } 106 | } 107 | 108 | 109 | let jsonProcessor = PacketProcessor() 110 | let packetProcessor = PacketProcessor() 111 | 112 | jsonProcessor.addHandler(JSONPacket.self) { packet in 113 | let packetData = packet.value.data(using: .utf8)! 114 | packetProcessor.push(packetData) 115 | } 116 | 117 | packetProcessor.addHandler(PlayerMove.self) { packet in 118 | // Handle move 119 | } 120 | 121 | packetProcessor.addHandler(PlayerAttack.self) { packet in 122 | // Handle attack 123 | } 124 | -------------------------------------------------------------------------------- /docs/js/highlight-js-perl.757d7b6f.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-perl"],{"6a51":function(e,n){function t(e){const n=e.regex,t=["abs","accept","alarm","and","atan2","bind","binmode","bless","break","caller","chdir","chmod","chomp","chop","chown","chr","chroot","close","closedir","connect","continue","cos","crypt","dbmclose","dbmopen","defined","delete","die","do","dump","each","else","elsif","endgrent","endhostent","endnetent","endprotoent","endpwent","endservent","eof","eval","exec","exists","exit","exp","fcntl","fileno","flock","for","foreach","fork","format","formline","getc","getgrent","getgrgid","getgrnam","gethostbyaddr","gethostbyname","gethostent","getlogin","getnetbyaddr","getnetbyname","getnetent","getpeername","getpgrp","getpriority","getprotobyname","getprotobynumber","getprotoent","getpwent","getpwnam","getpwuid","getservbyname","getservbyport","getservent","getsockname","getsockopt","given","glob","gmtime","goto","grep","gt","hex","if","index","int","ioctl","join","keys","kill","last","lc","lcfirst","length","link","listen","local","localtime","log","lstat","lt","ma","map","mkdir","msgctl","msgget","msgrcv","msgsnd","my","ne","next","no","not","oct","open","opendir","or","ord","our","pack","package","pipe","pop","pos","print","printf","prototype","push","q|0","qq","quotemeta","qw","qx","rand","read","readdir","readline","readlink","readpipe","recv","redo","ref","rename","require","reset","return","reverse","rewinddir","rindex","rmdir","say","scalar","seek","seekdir","select","semctl","semget","semop","send","setgrent","sethostent","setnetent","setpgrp","setpriority","setprotoent","setpwent","setservent","setsockopt","shift","shmctl","shmget","shmread","shmwrite","shutdown","sin","sleep","socket","socketpair","sort","splice","split","sprintf","sqrt","srand","stat","state","study","sub","substr","symlink","syscall","sysopen","sysread","sysseek","system","syswrite","tell","telldir","tie","tied","time","times","tr","truncate","uc","ucfirst","umask","undef","unless","unlink","unpack","unshift","untie","until","use","utime","values","vec","wait","waitpid","wantarray","warn","when","while","write","x|0","xor","y|0"],s=/[dualxmsipngr]{0,12}/,r={$pattern:/[\w.]+/,keyword:t.join(" ")},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:r},a={begin:/->\{/,end:/\}/},o={variants:[{begin:/\$\d/},{begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])")},{begin:/[$%@][^\s\w{]/,relevance:0}]},c=[e.BACKSLASH_ESCAPE,i,o],g=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],l=(e,t,r="\\1")=>{const i="\\1"===r?r:n.concat(r,t);return n.concat(n.concat("(?:",e,")"),t,/(?:\\.|[^\\\/])*?/,i,/(?:\\.|[^\\\/])*?/,r,s)},d=(e,t,r)=>n.concat(n.concat("(?:",e,")"),t,/(?:\\.|[^\\\/])*?/,r,s),p=[o,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{endsWithParent:!0}),a,{className:"string",contains:c,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{begin:l("s|tr|y",n.either(...g,{capture:!0}))},{begin:l("s|tr|y","\\(","\\)")},{begin:l("s|tr|y","\\[","\\]")},{begin:l("s|tr|y","\\{","\\}")}],relevance:2},{className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...g,{capture:!0}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return i.contains=p,a.contains=p,{name:"Perl",aliases:["pl","pm"],keywords:r,contains:p}}e.exports=t}}]); -------------------------------------------------------------------------------- /docs/tutorials/tutorial-toc/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/packet/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/anypacket/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/datapacket/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/stringpacket/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/tutorials/packetprocessor/datapacket-utf8/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/tutorials/packetprocessor/stringpacket-json/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/gettingstarted/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/packetprocessor/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/packetsearchresult/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/tutorials/packetprocessor/stringpacket-logfile/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/packet/collectiontype/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/packetcollectiontype/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/packethandlercontext/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/packethandleridentifier/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/packetprocessor/packetprocessor/end()/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Documentation
--------------------------------------------------------------------------------