├── .gitignore ├── .jazzy.yaml ├── .swift-version ├── .swiftformat ├── .tailor.yml ├── .travis.yml ├── CHANGELOG.md ├── Finite.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace │ └── contents.xcworkspacedata └── timeline.xctimeline ├── Finite.podspec ├── Finite.xcodeproj ├── FiniteTests_Info.plist ├── Finite_Info.plist ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── xcshareddata │ └── xcschemes │ └── Finite-Package.xcscheme ├── Finite.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── LinuxMain.swift ├── Package.resolved ├── Package.swift ├── README.md ├── Scripts └── docs-head.html ├── Sources ├── Ref.swift ├── StateFlow.swift ├── StateMachine.swift └── Transition.swift ├── Tests ├── FiniteTests │ ├── StateFlowTests.swift │ ├── StateMachine.swift │ ├── SwiftShim.swift │ └── TransitionTests.swift └── XCTestManifests.swift ├── codecov.yml └── docs ├── Enums.html ├── Enums └── TransitionError.html ├── Protocols.html ├── Protocols └── ReferenceDisposable.html ├── Structs.html ├── Structs ├── StateFlow.html ├── StateMachine.html └── Transition.html ├── Typealiases.html ├── badge.svg ├── css ├── highlight.css └── jazzy.css ├── docsets ├── Finite.docset │ └── Contents │ │ ├── Info.plist │ │ └── Resources │ │ ├── Documents │ │ ├── Enums.html │ │ ├── Enums │ │ │ └── TransitionError.html │ │ ├── Protocols.html │ │ ├── Protocols │ │ │ └── ReferenceDisposable.html │ │ ├── Structs.html │ │ ├── Structs │ │ │ ├── StateFlow.html │ │ │ ├── StateMachine.html │ │ │ └── Transition.html │ │ ├── Typealiases.html │ │ ├── badge.svg │ │ ├── css │ │ │ ├── highlight.css │ │ │ └── jazzy.css │ │ ├── img │ │ │ ├── carat.png │ │ │ ├── dash.png │ │ │ ├── gh.png │ │ │ └── spinner.gif │ │ ├── index.html │ │ ├── js │ │ │ ├── jazzy.js │ │ │ ├── jazzy.search.js │ │ │ ├── jquery.min.js │ │ │ ├── lunr.min.js │ │ │ └── typeahead.jquery.js │ │ ├── search.json │ │ └── undocumented.json │ │ └── docSet.dsidx ├── Finite.tgz └── Finite.xml ├── img ├── carat.png ├── dash.png ├── gh.png └── spinner.gif ├── index.html ├── js ├── jazzy.js ├── jazzy.search.js ├── jquery.min.js ├── lunr.min.js └── typeahead.jquery.js ├── search.json └── undocumented.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac 2 | .DS_Store 3 | ._* 4 | 5 | # VS Code 6 | ## Settings 7 | .vscode 8 | 9 | # Xcode 10 | ## Build generated 11 | .build/ 12 | .swiftpm/ 13 | build/ 14 | DerivedData 15 | 16 | ## Various settings 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | xcuserdata 26 | 27 | ## Other 28 | *.xccheckout 29 | *.moved-aside 30 | *.xcuserstate 31 | *.xcscmblueprint 32 | 33 | ## Docs 34 | # docs/ 35 | -------------------------------------------------------------------------------- /.jazzy.yaml: -------------------------------------------------------------------------------- 1 | author: Valentin Knabel 2 | author_url: https://twitter.com/vknabel 3 | github_url: https://github.com/vknabel/Finite 4 | module: Finite 5 | module_version: 4.0.0 6 | root_url: https://vknabel.github.io/Finite/ 7 | readme: README.md 8 | output: docs/ 9 | theme: fullwidth 10 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.3.1 2 | -------------------------------------------------------------------------------- /.swiftformat: -------------------------------------------------------------------------------- 1 | --disable redundantSelf # ambiguous wait(for:timeout:) 2 | --tabwidth 4 -------------------------------------------------------------------------------- /.tailor.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - Sources 3 | - Tests 4 | - Package.swift 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | sudo: required 3 | dist: trusty 4 | notifications: 5 | email: false 6 | os: linux 7 | matrix: 8 | include: 9 | - os: linux 10 | env: 11 | - SWIFT_VERSION=5.0.1 12 | install: 13 | - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" 14 | - swift package resolve 15 | script: 16 | - swift build 17 | - swift test 18 | - os: linux 19 | env: 20 | - SWIFT_VERSION=5.3.1 21 | install: 22 | - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" 23 | - swift package resolve 24 | script: 25 | - swift build 26 | - swift test 27 | - os: osx 28 | osx_image: xcode10.2 29 | env: 30 | - SWIFT_VERSION=system 31 | install: 32 | - swift package resolve 33 | script: 34 | - xcodebuild -scheme Finite -enableCodeCoverage YES test | xcpretty 35 | after_success: 36 | - bash <(curl -s https://codecov.io/bash) 37 | - os: osx 38 | osx_image: xcode12.2 39 | env: 40 | - SWIFT_VERSION=system 41 | install: 42 | - swift package resolve 43 | script: 44 | - xcodebuild -scheme Finite -enableCodeCoverage YES test | xcpretty 45 | after_success: 46 | - bash <(curl -s https://codecov.io/bash) 47 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 4.0.0 4 | 5 | The new Finite offers you two new features: temporarily subscribing transitions and observing any transitions at once. 6 | 7 | Use the new `onTransitions(perform:)` or `subscribeTransitions(perform:)` methods to observe all transitions. 8 | Temporarily `subscribeTransitions` of your State Machines and bind the callbacks to the lifetime of your View Controllers. Just don't forget to store the subscription to bind `self` as `weak` or `unowned`. 9 | 10 | ### Breaking Changes 11 | 12 | - Requires Swift 5 13 | - Previously passing `Transition.nilTransition` to `StateMachine.onTransitions(like:perform:)` did never trigger the `perform` handler and was therefore useless. Now it will always be triggered. 14 | 15 | ### Additions 16 | 17 | - Deprecated `StateMachine.onTransitions(transition:perform:)` in favor of `StateMachine.onTransitions(like:perform:)`. 18 | - The `StateMachine.onTransitions(perform:)` overload for `StateMachine.onTransitions(perform:)`. 19 | - Adds temporary observation of transitions `subscribeTransitions(like:perform:)`, `subscribeTransitions(perform:)`, `subscribeTransitions(from:perform:)`, `subscribeTransitions(to:perform:)`, `subscribeTransitions(from:to:perform:)`. All return a `ReferenceDisposable` which needs to be stored as a strong reference. On deinit, the handler will be freed. 20 | 21 | ### Upgrading to 4.0.0 22 | 23 | First bump your dependency version of Finite to `4.0.0`. 24 | When you compile your project, you won't experience compile errors. Instead you will receive compiler warnings whenever you used `StateMachine.onTransitions(transition:perform:)`. If there are no warnings, you already finished the upgrade. 25 | 26 | In case you passed `.nilTransition`: this did never work. Your `perform` operation has never been called! 27 | Starting from 4.0.0, `.nilTransition` operations will always be called. 28 | 29 | In case you did not pass a `.nilTransition`, apply the fix-it and use `onTransitions(like:perform:)` instead. 30 | 31 | ## 3.1.1 32 | 33 | ### Fixes 34 | 35 | - Avoid assertion failure by combining hash values instead of summing them up - @iLuke93 @snofla 36 | 37 | ## 3.1.0 38 | 39 | ### Additions 40 | 41 | - Introduced graphviz compatible descriptions - @snofla 42 | 43 | ## 3.0.3 44 | 45 | *Released: 2017-10-06* 46 | 47 | ### Other Changes 48 | 49 | - Readme updates - @vknabel 50 | - Proven Swift 4.0 support - @vknabel 51 | 52 | ## 3.0.2 53 | 54 | *Released: 2016-09-26* 55 | 56 | ### Other Changes 57 | 58 | - Fixes Testing error - @vknabel 59 | 60 | ## 3.0.1 61 | 62 | *Released: 2016-09-26* 63 | 64 | ### Other Changes 65 | 66 | - Added support for Travis builds - @vknabel 67 | - Added test support for Linux - @vknabel 68 | - Updated docs - @vknabel 69 | 70 | ## 3.0.0 71 | 72 | *Released: 2016-09-08* 73 | 74 | ### Breaking Changes 75 | 76 | - Dropped Swift 2.2 and 2.3 support - @vknabel 77 | 78 | ## 2.0.0 79 | *Released: 2016-08-22* 80 | 81 | ### Breaking Changes 82 | 83 | - Renamed Project from `StateMachine` to `Finite` - @vknabel 84 | - Renamed `StateMachine.triggerTransition(to:)` to `StateMachine.transition(to:)` - @vknabel 85 | - `StateMachine.transition(to:)` throws `TransitionError` and rethrows - @vknabel 86 | 87 | ### API Additions 88 | 89 | - `Operation`s may now throw - @vknabel 90 | - Added `TransitionError` - @vknabel 91 | - Added Swift 3.0 Support - @vknabel 92 | - Added generated Docs - @vknabel 93 | 94 | ### Other Changes 95 | 96 | - Added `CocoaPods` and `Swift Package Manager` support - @vknabel 97 | - Started this `CHANGELOG`. 98 | 99 | -------------------------------------------------------------------------------- /Finite.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // Playground - noun: a place where people can play 2 | 3 | import Finite 4 | 5 | enum Test: Int { 6 | case Saving, Fetching, Deleting 7 | case Ready, Fail 8 | } 9 | 10 | var machine = StateMachine(initial: .Ready) { c in 11 | c.allow(from: [.Saving, .Fetching, .Deleting], to: [.Ready, .Fail]) 12 | c.allow(from: .Ready, to: [.Saving, .Fetching, .Deleting]) 13 | } 14 | 15 | machine.onTransitions(from: .Ready) { 16 | print("From Ready: show activity indicator") 17 | } 18 | 19 | machine.onTransitions(to: .Ready) { 20 | print("To Ready: hide activity indicator") 21 | } 22 | 23 | machine.onTransitions(to: .Saving) { 24 | print("To: save") 25 | } 26 | 27 | try machine.transition(to: .Saving) { 28 | print("Triggered: save") 29 | } 30 | 31 | machine.state 32 | 33 | enum State: Hashable { 34 | case Ready 35 | case Error 36 | case Busy(T) 37 | 38 | var hashValue: Int { 39 | switch self { 40 | case .Ready: 41 | return 0 42 | case .Error: 43 | return 1 44 | case let .Busy(b): 45 | return 2 + b.hashValue 46 | } 47 | } 48 | 49 | var isBusy: Bool { 50 | switch self { 51 | case .Busy: 52 | return true 53 | default: 54 | return false 55 | } 56 | } 57 | } 58 | 59 | func == (lhs: State, rhs: State) -> Bool { 60 | switch (lhs, rhs) { 61 | case (.Ready, .Ready): 62 | return true 63 | case (.Error, .Error): 64 | return true 65 | case let (.Busy(lhb), .Busy(rhb)): 66 | return lhb == rhb 67 | default: 68 | return false 69 | } 70 | } 71 | 72 | enum Process { 73 | case Saving, Fetching, Deleting 74 | } 75 | 76 | var scnd = StateMachine>(initial: .Ready) { flow in 77 | // allow transitions from busy 78 | flow.allow(to: [.Ready, .Error]) { transition in 79 | transition.from?.isBusy ?? false 80 | } 81 | // allow transitions from ready to busy 82 | flow.allow(from: .Ready) { t in 83 | t.to?.isBusy ?? false 84 | } 85 | flow.allow(transition: Transition(from: nil, to: .Busy(.Deleting))) 86 | } 87 | 88 | do { 89 | try scnd.transition(to: State.Busy(.Deleting)) 90 | } catch { 91 | print(error) 92 | } 93 | -------------------------------------------------------------------------------- /Finite.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Finite.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Finite.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Finite.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Finite' 3 | s.version = '4.0.0' 4 | s.summary = 'A simple state machine written in Swift.' 5 | s.description = <<-DESC 6 | Finite is a simple, pure Swift finite state machine. 7 | DESC 8 | s.social_media_url = "https://twitter.com/vknabel" 9 | s.homepage = 'https://github.com/vknabel/Finite' 10 | s.license = { :type => 'MIT', :file => 'LICENSE' } 11 | s.author = { 'Valentin Knabel' => 'dev@vknabel.com' } 12 | s.source = { :git => 'https://github.com/vknabel/Finite.git', :tag => s.version.to_s } 13 | s.ios.deployment_target = '8.0' 14 | s.osx.deployment_target = '10.9' 15 | s.watchos.deployment_target = "2.0" 16 | s.tvos.deployment_target = "9.0" 17 | s.source_files = 'Sources/*.swift' 18 | end 19 | -------------------------------------------------------------------------------- /Finite.xcodeproj/FiniteTests_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Finite.xcodeproj/Finite_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | FMWK 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Finite.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /Finite.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Finite.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | -------------------------------------------------------------------------------- /Finite.xcodeproj/xcshareddata/xcschemes/Finite-Package.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Finite.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Finite.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Finite.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | 2 | gem "cocoapods" 3 | gem "jazzy" 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | specs: 3 | CFPropertyList (3.0.2) 4 | activesupport (5.2.4.4) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 0.7, < 2) 7 | minitest (~> 5.1) 8 | tzinfo (~> 1.1) 9 | addressable (2.7.0) 10 | public_suffix (>= 2.0.2, < 5.0) 11 | algoliasearch (1.27.5) 12 | httpclient (~> 2.8, >= 2.8.3) 13 | json (>= 1.5.1) 14 | atomos (0.1.3) 15 | claide (1.0.3) 16 | cocoapods (1.10.0) 17 | addressable (~> 2.6) 18 | claide (>= 1.0.2, < 2.0) 19 | cocoapods-core (= 1.10.0) 20 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 21 | cocoapods-downloader (>= 1.4.0, < 2.0) 22 | cocoapods-plugins (>= 1.0.0, < 2.0) 23 | cocoapods-search (>= 1.0.0, < 2.0) 24 | cocoapods-trunk (>= 1.4.0, < 2.0) 25 | cocoapods-try (>= 1.1.0, < 2.0) 26 | colored2 (~> 3.1) 27 | escape (~> 0.0.4) 28 | fourflusher (>= 2.3.0, < 3.0) 29 | gh_inspector (~> 1.0) 30 | molinillo (~> 0.6.6) 31 | nap (~> 1.0) 32 | ruby-macho (~> 1.4) 33 | xcodeproj (>= 1.19.0, < 2.0) 34 | cocoapods-core (1.10.0) 35 | activesupport (> 5.0, < 6) 36 | addressable (~> 2.6) 37 | algoliasearch (~> 1.0) 38 | concurrent-ruby (~> 1.1) 39 | fuzzy_match (~> 2.0.4) 40 | nap (~> 1.0) 41 | netrc (~> 0.11) 42 | public_suffix 43 | typhoeus (~> 1.0) 44 | cocoapods-deintegrate (1.0.4) 45 | cocoapods-downloader (1.4.0) 46 | cocoapods-plugins (1.0.0) 47 | nap 48 | cocoapods-search (1.0.0) 49 | cocoapods-trunk (1.5.0) 50 | nap (>= 0.8, < 2.0) 51 | netrc (~> 0.11) 52 | cocoapods-try (1.2.0) 53 | colored2 (3.1.2) 54 | concurrent-ruby (1.1.7) 55 | escape (0.0.4) 56 | ethon (0.12.0) 57 | ffi (>= 1.3.0) 58 | ffi (1.13.1) 59 | fourflusher (2.3.1) 60 | fuzzy_match (2.0.4) 61 | gh_inspector (1.1.3) 62 | httpclient (2.8.3) 63 | i18n (1.8.5) 64 | concurrent-ruby (~> 1.0) 65 | jazzy (0.13.5) 66 | cocoapods (~> 1.5) 67 | mustache (~> 1.1) 68 | open4 69 | redcarpet (~> 3.4) 70 | rouge (>= 2.0.6, < 4.0) 71 | sassc (~> 2.1) 72 | sqlite3 (~> 1.3) 73 | xcinvoke (~> 0.3.0) 74 | json (2.3.1) 75 | liferaft (0.0.6) 76 | minitest (5.14.2) 77 | molinillo (0.6.6) 78 | mustache (1.1.1) 79 | nanaimo (0.3.0) 80 | nap (1.1.0) 81 | netrc (0.11.0) 82 | open4 (1.3.4) 83 | public_suffix (4.0.6) 84 | redcarpet (3.5.0) 85 | rouge (3.23.0) 86 | ruby-macho (1.4.0) 87 | sassc (2.4.0) 88 | ffi (~> 1.9) 89 | sqlite3 (1.4.2) 90 | thread_safe (0.3.6) 91 | typhoeus (1.4.0) 92 | ethon (>= 0.9.0) 93 | tzinfo (1.2.8) 94 | thread_safe (~> 0.1) 95 | xcinvoke (0.3.0) 96 | liferaft (~> 0.0.6) 97 | xcodeproj (1.19.0) 98 | CFPropertyList (>= 2.3.3, < 4.0) 99 | atomos (~> 0.1.3) 100 | claide (>= 1.0.2, < 2.0) 101 | colored2 (~> 3.1) 102 | nanaimo (~> 0.3.0) 103 | 104 | PLATFORMS 105 | ruby 106 | 107 | DEPENDENCIES 108 | cocoapods 109 | jazzy 110 | 111 | BUNDLED WITH 112 | 1.17.3 113 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Valentin Knabel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import FiniteTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += FiniteTests.__allTests() 7 | 8 | XCTMain(tests) 9 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Komondor", 6 | "repositoryURL": "https://github.com/shibapm/Komondor.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "3cd6d76887816ead5931ddbfb249c2935f518e17", 10 | "version": "1.0.4" 11 | } 12 | }, 13 | { 14 | "package": "Logger", 15 | "repositoryURL": "https://github.com/shibapm/Logger", 16 | "state": { 17 | "branch": null, 18 | "revision": "53c3ecca5abe8cf46697e33901ee774236d94cce", 19 | "version": "0.2.3" 20 | } 21 | }, 22 | { 23 | "package": "PackageConfig", 24 | "repositoryURL": "https://github.com/shibapm/PackageConfig.git", 25 | "state": { 26 | "branch": null, 27 | "revision": "bf90dc69fa0792894b08a0b74cf34029694ae486", 28 | "version": "0.13.0" 29 | } 30 | }, 31 | { 32 | "package": "Rocket", 33 | "repositoryURL": "https://github.com/f-meloni/Rocket.git", 34 | "state": { 35 | "branch": null, 36 | "revision": "623cb4ccf55d708d082516ccd5cfea3dac8f9032", 37 | "version": "1.0.0" 38 | } 39 | }, 40 | { 41 | "package": "ShellOut", 42 | "repositoryURL": "https://github.com/JohnSundell/ShellOut.git", 43 | "state": { 44 | "branch": null, 45 | "revision": "e1577acf2b6e90086d01a6d5e2b8efdaae033568", 46 | "version": "2.3.0" 47 | } 48 | }, 49 | { 50 | "package": "SwiftFormat", 51 | "repositoryURL": "https://github.com/nicklockwood/SwiftFormat.git", 52 | "state": { 53 | "branch": null, 54 | "revision": "d9b7cf39e06e89428004a767d97006fb6d293c53", 55 | "version": "0.43.5" 56 | } 57 | }, 58 | { 59 | "package": "SwiftShell", 60 | "repositoryURL": "https://github.com/kareman/SwiftShell", 61 | "state": { 62 | "branch": null, 63 | "revision": "fb7fc2c9ad8811caf324431a508fb79e3fb74f99", 64 | "version": "5.0.1" 65 | } 66 | }, 67 | { 68 | "package": "Yams", 69 | "repositoryURL": "https://github.com/jpsim/Yams", 70 | "state": { 71 | "branch": null, 72 | "revision": "c947a306d2e80ecb2c0859047b35c73b8e1ca27f", 73 | "version": "2.0.0" 74 | } 75 | } 76 | ] 77 | }, 78 | "version": 1 79 | } 80 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "Finite", 6 | products: [ 7 | .library( 8 | name: "Finite", 9 | targets: ["Finite"] 10 | ), 11 | ], 12 | dependencies: [ 13 | .package(url: "https://github.com/shibapm/Komondor.git", from: "1.0.4"), // dev 14 | .package(url: "https://github.com/nicklockwood/SwiftFormat.git", from: "0.43.5"), // dev 15 | .package(url: "https://github.com/f-meloni/Rocket.git", from: "1.0.0"), // dev 16 | ], 17 | targets: [ 18 | .target(name: "Finite", path: "Sources"), 19 | .testTarget(name: "FiniteTests", dependencies: ["Finite"], path: "Tests"), 20 | ] 21 | ) 22 | 23 | #if canImport(PackageConfig) 24 | import PackageConfig 25 | 26 | let config = PackageConfiguration([ 27 | "komondor": [ 28 | "pre-push": "swift test", 29 | "pre-commit": [ 30 | "swift package generate-xcodeproj --enable-code-coverage || true", 31 | "swift test --generate-linuxmain || true", 32 | "swift test", 33 | "swift run swiftformat Sources *.swift Tests", 34 | "git add .", 35 | ], 36 | ], 37 | "rocket": ["steps": [ 38 | "jazzy --head \"$(cat Scripts/docs-head.html)\" --module-version $VERSION || true", 39 | ["script": ["content": "echo Release $VERSION"]], 40 | "hide_dev_dependencies", 41 | ["git_add": ["paths": ["Package.swift", "docs"]]], 42 | ["commit": ["no_verify": true]], 43 | "tag", 44 | "unhide_dev_dependencies", 45 | ["git_add": ["paths": ["Package.swift", "docs"]]], 46 | ["commit": ["no_verify": true, "message": "Unhide dev dependencies"]], 47 | "push", 48 | ]], 49 | ]).write() 50 | #endif 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CocoaPods](https://img.shields.io/cocoapods/v/Finite.svg?maxAge=2592000?style=flat-square)]() 2 | [![CocoaPods](https://img.shields.io/cocoapods/p/Finite.svg?maxAge=2592000?style=flat-square)]() 3 | [![Install](https://img.shields.io/badge/install-SwiftPM%20%7C%20Carthage%20%7C%20Cocoapods-lightgrey.svg?style=flat-square)]() 4 | [![License](https://img.shields.io/cocoapods/l/Finite.svg?maxAge=2592000?style=flat-square)]() 5 | 6 | # Finite 7 | 8 | Finite is a simple, pure Swift finite state machine. Only exlicitly allowed transitions between states are allowed, otherwise an error will be thrown. 9 | 10 | | **Finite** | **Swift** | 11 | | ---------- | -------------------- | 12 | | `2.0.0` | `2.2` and `3.0 Beta` | 13 | | `3.x.x` | `3.0` and `4.0` | 14 | | `4.x.x` | `5.0` | 15 | 16 | ## Installation 17 | 18 | Finite has no external dependencies and supports [Swift Package Manager](https://github.com/apple/swift-package-manager), [Carthage](https://github.com/Carthage/Carthage) and [CocoaPods](https://github.com/CocoaPods/CocoaPods). 19 | 20 | ### Swift Package Manager 21 | 22 | ```swift 23 | import PackageDescription 24 | 25 | let package = Package( 26 | name: "YourPackage", 27 | dependencies: [ 28 | .package(url: "https://github.com/vknabel/Finite.git", from: "4.0.0") 29 | ], 30 | targets: [ 31 | .target(name: "YourTarget", dependencies: ["Finite"]), 32 | ] 33 | ) 34 | ``` 35 | 36 | ### Carthage 37 | 38 | ```ruby 39 | github "vknabel/Finite" 40 | ``` 41 | 42 | ### CocoaPods 43 | 44 | ```ruby 45 | source 'https://github.com/CocoaPods/Specs.git' 46 | use_frameworks! 47 | 48 | pod 'Finite', '~> 4.0.0' 49 | ``` 50 | 51 | ## Introduction 52 | 53 | It operates on a given type, where each value represents an internal state of the machine. A `StateMachine` is defined by providing all allowed state transitions. 54 | 55 | ```swift 56 | enum Test: Int { 57 | case saving, fetching, deleting 58 | case ready, fail 59 | } 60 | 61 | var machine = StateMachine(initial: .ready) { c in 62 | c.allow(from: [.saving, .fetching, .deleting], to: [.ready, .fail]) 63 | c.allow(from: .ready, to: [.saving, .fetching, .deleting]) 64 | } 65 | ``` 66 | 67 | It is possible to provide callbacks, that will be called once certain transitions will happen. 68 | 69 | ```swift 70 | machine.onTransitions { 71 | println("Successfully triggered transition!") 72 | } 73 | machine.onTransitions(from: .ready) { 74 | println("From Ready: show activity indicator") 75 | } 76 | machine.onTransitions(to: .ready) { 77 | println("To Ready: hide activity indicator") 78 | } 79 | machine.onTransitions(to: .saving) { 80 | println("To: save") 81 | } 82 | 83 | let subscription = machine.subscribeTransitions(to: .saving) { 84 | println("Only triggered as long as you keep `subscription`") 85 | } 86 | ``` 87 | 88 | Once the `StateMachine` has been set up, you may trigger all transitions you have declared above. 89 | 90 | ```swift 91 | try machine.transition(to: .saving) { 92 | println("Triggered: save") 93 | } 94 | 95 | // this will throw TransitionError.denied(from: .saving, to: .fetching) 96 | try machine.transition(to: .fetching) 97 | ``` 98 | 99 | ## Author 100 | 101 | Valentin Knabel, dev@vknabel.com 102 | 103 | Special thanks to @snofla for allowing to export state machines to graphviz. 104 | 105 | ## License 106 | 107 | Finite is available under the [MIT](./LICENSE) license. 108 | -------------------------------------------------------------------------------- /Scripts/docs-head.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /Sources/Ref.swift: -------------------------------------------------------------------------------- 1 | /// A subscription reference which needs to be referenced strongly. 2 | public protocol ReferenceDisposable { 3 | /// Disposes the current subscription. Current and future operations will be canceled. 4 | func dispose() 5 | } 6 | 7 | internal class Ref { 8 | private var value: () -> T? 9 | 10 | init(dereference: @escaping () -> T?) { 11 | value = dereference 12 | } 13 | 14 | func resolve() -> T? { 15 | value() 16 | } 17 | 18 | func free() { 19 | value = { nil } 20 | } 21 | } 22 | 23 | extension Ref { 24 | static func weak(_ value: T) -> (ReferenceDisposable, Ref) { 25 | let lifetime = Box(value) 26 | let weak = Weak(value: lifetime) 27 | return ( 28 | lifetime, 29 | .init(dereference: { weak.value?.value }) 30 | ) 31 | } 32 | 33 | static func strong(_ value: T) -> Ref { 34 | .init(dereference: { value }) 35 | } 36 | 37 | private struct Weak { 38 | fileprivate weak var value: Box? 39 | } 40 | 41 | private class Box: ReferenceDisposable { 42 | var value: T? 43 | 44 | init(_ value: T?) { 45 | self.value = value 46 | } 47 | 48 | func dispose() { 49 | value = nil 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/StateFlow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StateFlow.swift 3 | // StateMachine 4 | // 5 | // Created by Valentin Knabel on 19.02.15. 6 | // Copyright (c) 2015 Valentin Knabel. All rights reserved. 7 | // 8 | 9 | /// Represents a configuration of a state machine. 10 | public struct StateFlow: CustomStringConvertible { 11 | /// Filters wether a transition is allowed to be performed. 12 | public typealias TransitionFilter = (Transition) -> Bool 13 | /// Configures the instance for immutable usage. 14 | public typealias Configurator = (inout StateFlow) -> Void 15 | 16 | /// Empty array means transition is allowed. 17 | /// Once there is a single filter, all previous unconditioned transitions are omitted. 18 | private var transitionFilters: [Transition: TransitionFilter?] = [:] 19 | 20 | /** 21 | Creates a new instance that can be mutated to be stored immutable. 22 | 23 | - parameter config: A function that mutates the constructed instance. 24 | */ 25 | public init(config: Configurator) { 26 | config(&self) 27 | } 28 | 29 | /// Creates a new instance to be used mutable. 30 | public init() {} 31 | 32 | /** 33 | Allows all less-equal general transitions to be triggered. 34 | 35 | - parameter transition: The transition allowing less-equal transitions. 36 | - parameter filter: An optional filter for transitions. 37 | */ 38 | public mutating func allow(transition: Transition, filter: TransitionFilter? = nil) { 39 | if transitionFilters[transition] == nil { 40 | transitionFilters[transition] = filter 41 | } 42 | } 43 | 44 | /** 45 | Returns wether a specific transition is allowed or not. 46 | Invokes defined transition filters until one returned true or a transition is unconditioned. 47 | 48 | - parameter transition: The transition to be tested. 49 | - returns: Returns true if a more-equal transition is allowed. 50 | */ 51 | public func allows(_ transition: Transition) -> Bool { 52 | for current in transition.generalTransitions { 53 | if let opf = transitionFilters[current] { 54 | let succ = opf?(current) ?? true 55 | if succ { 56 | return true 57 | } 58 | } 59 | } 60 | return false 61 | } 62 | 63 | /** 64 | Returns list of of transitions, sorted by the hash values of the 65 | from node 66 | */ 67 | public var description: String { 68 | let graph = transitionFilters.sorted { (lhs, rhs) -> Bool in 69 | lhs.key.hashValue < rhs.key.hashValue 70 | }.compactMap { (transform) -> String? in 71 | transform.key.description 72 | } 73 | if graph.count > 0 { 74 | return graph.joined(separator: "\n") 75 | } else { 76 | return "" 77 | } 78 | } 79 | } 80 | 81 | public extension StateFlow { 82 | /** 83 | Convinience method that allows all less-equal general absolute transitions to be triggered. 84 | 85 | - parameter from: The source state. 86 | - parameter filter: An optional filter for transitions. 87 | */ 88 | mutating func allow(from: T, filter: TransitionFilter? = nil) { 89 | allow(transition: Transition(from: from, to: nil), filter: filter) 90 | } 91 | 92 | /** 93 | Convinience method that allows all less-equal general absolute transitions to be triggered. 94 | 95 | - parameter to: The target state. 96 | - parameter filter: An optional filter for transitions. 97 | */ 98 | mutating func allow(to: T, filter: TransitionFilter? = nil) { 99 | allow(transition: Transition(from: nil, to: to), filter: filter) 100 | } 101 | 102 | /** 103 | Convinience method that allows all less-equal general absolute transitions to be triggered. 104 | 105 | - parameter from: The source state. 106 | - parameter to: The target state. 107 | - parameter filter: An optional filter for transitions. 108 | */ 109 | mutating func allow(from: T, to: T, filter: TransitionFilter? = nil) { 110 | allow(transition: Transition(from: from, to: to), filter: filter) 111 | } 112 | 113 | /** 114 | Convinience method that allows all less-equal general absolute transitions to be triggered. 115 | 116 | - parameter from: All source states. 117 | - parameter filter: An optional filter for transitions. 118 | */ 119 | mutating func allow(from: [T], filter: TransitionFilter? = nil) { 120 | for f in from { 121 | allow(transition: Transition(from: f, to: nil), filter: filter) 122 | } 123 | } 124 | 125 | /** 126 | Convinience method that allows all less-equal general absolute transitions to be triggered. 127 | 128 | - parameter from: All source states. 129 | - parameter to: The target state. 130 | - parameter filter: An optional filter for transitions. 131 | */ 132 | mutating func allow(from: [T], to: T, filter: TransitionFilter? = nil) { 133 | for f in from { 134 | allow(transition: Transition(from: f, to: to), filter: filter) 135 | } 136 | } 137 | 138 | /** 139 | Convinience method that allows all less-equal general absolute transitions to be triggered. 140 | 141 | - parameter to: All target states. 142 | - parameter filter: An optional filter for transitions. 143 | */ 144 | mutating func allow(to: [T], filter: TransitionFilter? = nil) { 145 | for t in to { 146 | allow(transition: Transition(from: nil, to: t), filter: filter) 147 | } 148 | } 149 | 150 | /** 151 | Convinience method that allows all less-equal general absolute transitions to be triggered. 152 | 153 | - parameter from: The source state. 154 | - parameter to: All target states. 155 | - parameter filter: An optional filter for transitions. 156 | */ 157 | mutating func allow(from: T, to: [T], filter: TransitionFilter? = nil) { 158 | for t in to { 159 | allow(transition: Transition(from: from, to: t), filter: filter) 160 | } 161 | } 162 | 163 | /** 164 | Convinience method that allows all less-equal general absolute transitions to be triggered. 165 | 166 | - parameter from: All source states. 167 | - parameter to: All target states. 168 | - parameter filter: An optional filter for transitions. 169 | */ 170 | mutating func allow(from: [T], to: [T], filter: TransitionFilter? = nil) { 171 | for f in from { 172 | for t in to { 173 | allow(transition: Transition(from: f, to: t), filter: filter) 174 | } 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Sources/StateMachine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StateMachine.swift 3 | // StateMachine 4 | // 5 | // Created by Valentin Knabel on 19.02.15. 6 | // Copyright (c) 2015 Valentin Knabel. All rights reserved. 7 | // 8 | 9 | /// Indicates that a transition failed. 10 | public enum TransitionError: Error { 11 | /// Represents a tried transition that is not allowed. 12 | case denied(from: T, to: T) 13 | } 14 | 15 | /// Represents a state machine. 16 | public struct StateMachine: CustomStringConvertible { 17 | /// An empty operation to be performed. 18 | public typealias Operation = () throws -> Void 19 | public typealias TransitionFilter = StateFlow.TransitionFilter 20 | 21 | /// Stores the current state. 22 | internal var currentState: T 23 | /// Stores the immutable state flow. 24 | internal let configuration: StateFlow 25 | /// Stores all transition handlers associated to transitions. 26 | internal var transitionHandlers: [Transition: [Ref]] = [:] 27 | 28 | /// The current state of the machine. 29 | public var state: T { 30 | currentState 31 | } 32 | 33 | /** 34 | Instantiates a state machine by configuring the StateFlow instance. 35 | 36 | - parameter initial: The initial state. 37 | - parameter config: A configurator for an instance of StateFlow. 38 | */ 39 | public init(initial: T, config: StateFlow.Configurator) { 40 | currentState = initial 41 | configuration = StateFlow(config: config) 42 | } 43 | 44 | /** 45 | Instantiates a state machine by passing an instance of StateFlow. 46 | 47 | - parameter initial: The initial state. 48 | - parameter stateFlow: The state flow to be used as configuration. 49 | */ 50 | public init(initial: T, stateFlow: StateFlow) { 51 | currentState = initial 52 | configuration = stateFlow 53 | } 54 | 55 | /** 56 | Triggers a transition to a given state and invokes a callback on completion. 57 | 58 | - parameter to: The targeted state. 59 | - parameter completion: An optional callback. Will be only be called on success and after all defined transition handlers were invoked. 60 | - throws: Either TransitionError or rethrows underlying errors. 61 | - returns: Wether the transition could be performed or not. 62 | */ 63 | public mutating func transition(to: T, completion: Operation? = nil) throws { 64 | let transition = self.transition(to: to) 65 | if configuration.allows(transition) { 66 | for t in transition.generalTransitions + [.nilTransition] { 67 | if let handlers = self.transitionHandlers[t] { 68 | for h in handlers { 69 | try h.resolve()?() // rethrows 70 | } 71 | } 72 | transitionHandlers[t]?.removeAll(where: { $0.resolve() == nil }) 73 | } 74 | currentState = to 75 | try completion?() 76 | } else { 77 | throw TransitionError.denied(from: currentState, to: to) 78 | } 79 | } 80 | 81 | /** 82 | Returns wether transitioning to a state is allowed. 83 | 84 | - parameter to: The targeted state. 85 | - returns: true if allowed else false. 86 | */ 87 | public func allows(to: T) -> Bool { 88 | configuration.allows(transition(to: to)) 89 | } 90 | 91 | private mutating func observeTransitions(like transition: Transition, perform opRef: Ref) { 92 | if transitionHandlers[transition] == nil { 93 | transitionHandlers[transition] = [] 94 | } 95 | transitionHandlers[transition]?.append(opRef) 96 | } 97 | 98 | /** 99 | Appends a transition handler for all more-equal general transitions. 100 | 101 | - parameter transition: The most specific transition. 102 | - parameter perform: The operation the be performed. 103 | */ 104 | public mutating func onTransitions(like transition: Transition = .nilTransition, perform op: @escaping Operation) { 105 | observeTransitions(like: transition, perform: .strong(op)) 106 | } 107 | 108 | /** 109 | Appends a transition handler for all more-equal general transitions. 110 | 111 | - parameter transition: The most specific transition. 112 | - parameter perform: The operation the be performed. 113 | */ 114 | public mutating func subscribeTransitions(like transition: Transition = .nilTransition, perform op: @escaping Operation) -> ReferenceDisposable { 115 | let (subscription, ref) = Ref.weak(op) 116 | observeTransitions(like: transition, perform: ref) 117 | return subscription 118 | } 119 | 120 | /** 121 | Returns the graph for the state machine 122 | */ 123 | public var description: String { 124 | let result = "digraph {\n" + "graph [rankdir=LR]\n" + configuration.description + "\n}\n" 125 | return result 126 | } 127 | } 128 | 129 | internal extension StateMachine { 130 | /// - returns: A transition from the current state to a given target. 131 | private func transition(to: T) -> Transition { 132 | Transition(from: currentState, to: to) 133 | } 134 | } 135 | 136 | public extension StateMachine { 137 | /** 138 | Appends a transition handler for all more-equal general transitions. 139 | 140 | - parameter from: The source state. 141 | - parameter to: The target state. 142 | - parameter perform: The operation the be performed. 143 | */ 144 | mutating func onTransitions(from: T, to: T, perform op: @escaping Operation) { 145 | let transition = Transition(from: from, to: to) 146 | onTransitions(like: transition, perform: op) 147 | } 148 | 149 | /** 150 | Appends a transition handler for all more-equal general transitions. 151 | 152 | - parameter from: The source state. 153 | - parameter to: The target state. 154 | - parameter perform: The operation the be performed. 155 | - returns: subcription which needs to be kept. 156 | */ 157 | mutating func subscribeTransitions(from: T, to: T, perform op: @escaping Operation) -> ReferenceDisposable { 158 | let transition = Transition(from: from, to: to) 159 | return subscribeTransitions(like: transition, perform: op) 160 | } 161 | 162 | /** 163 | Appends a transition handler for all more-equal general transitions. 164 | 165 | - parameter from: The source state. 166 | - parameter perform: The operation the be performed. 167 | */ 168 | mutating func onTransitions(from: T, perform op: @escaping Operation) { 169 | let transition = Transition(from: from, to: nil) 170 | onTransitions(like: transition, perform: op) 171 | } 172 | 173 | /** 174 | Appends a transition handler for all more-equal general transitions. 175 | 176 | - parameter from: The source state. 177 | - parameter perform: The operation the be performed. 178 | - returns: subcription which needs to be kept. 179 | */ 180 | mutating func subscribeTransitions(from: T, perform op: @escaping Operation) -> ReferenceDisposable { 181 | let transition = Transition(from: from, to: nil) 182 | return subscribeTransitions(like: transition, perform: op) 183 | } 184 | 185 | /** 186 | Appends a transition handler for all more-equal general transitions. 187 | 188 | - parameter to: The target state. 189 | - parameter perform: The operation the be performed. 190 | */ 191 | mutating func onTransitions(to: T, perform op: @escaping Operation) { 192 | let transition = Transition(from: nil, to: to) 193 | onTransitions(like: transition, perform: op) 194 | } 195 | 196 | /** 197 | Appends a transition handler for all more-equal general transitions. 198 | 199 | - parameter to: The target state. 200 | - parameter perform: The operation the be performed. 201 | - returns: subcription which needs to be kept. 202 | */ 203 | mutating func subscribeTransitions(to: T, perform op: @escaping Operation) -> ReferenceDisposable { 204 | let transition = Transition(from: nil, to: to) 205 | return subscribeTransitions(like: transition, perform: op) 206 | } 207 | } 208 | 209 | public extension StateMachine { 210 | /** 211 | Appends a transition handler for all more-equal general transitions. 212 | Deprecated, use `StateMachine.onTransitions(like:perform:)` instead. 213 | Operations for .nilTransition will now be performed for every transition. 214 | 215 | - parameter transition: The most specific transition. 216 | - parameter perform: The operation the be performed. 217 | */ 218 | @available(*, renamed: "onTransitions(like:perform:)", deprecated, message: "Operations for .nilTransition will now be performed for every transition") 219 | mutating func onTransitions(transition: Transition, perform op: @escaping Operation) { 220 | observeTransitions(like: transition, perform: .strong(op)) 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /Sources/Transition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transition.swift 3 | // StateMachine 4 | // 5 | // Created by Valentin Knabel on 19.02.15. 6 | // Copyright (c) 2015 Valentin Knabel. All rights reserved. 7 | // 8 | 9 | /** 10 | The Transition class represents a transition from a given state to a targeted state. 11 | There are three types of transitions: 12 | 13 | 1. Absolute Transitions have a source and a target state set. 14 | 2. Relative Transitions have only one state set. 15 | 3. Nil Transitions have none states set and will be ignored. 16 | */ 17 | public struct Transition: Hashable, CustomStringConvertible { 18 | /// Nil transitions will be ignored. 19 | public static var nilTransition: Transition { 20 | Transition(from: nil, to: nil) 21 | } 22 | 23 | /// The source state. 24 | public var from: T? 25 | /// The targeted state. 26 | public var to: T? 27 | 28 | /** 29 | Constructs an absolute, relative or nil transition. 30 | 31 | - parameter from: The source state. 32 | - parameter to: The target state. 33 | */ 34 | public init(from: T?, to: T?) { 35 | self.from = from 36 | self.to = to 37 | } 38 | 39 | /** 40 | All more general transitions include itself except the nil transition. 41 | 42 | - returns: All general transitions. 43 | 44 | - Generals of an absolute transition is itself and relative transitions. 45 | - Generals of a relative transition is only itself. 46 | - Nil transitions have no generals. 47 | */ 48 | public var generalTransitions: Set { 49 | var generals = Set([self, Transition(from: from, to: nil), Transition(from: nil, to: to)]) 50 | generals.remove(.nilTransition) 51 | return generals 52 | } 53 | 54 | public var description: String { 55 | let f = from != nil ? String(describing: from!) : "any" 56 | let t = to != nil ? String(describing: to!) : "any" 57 | return "\(f) -> \(t)" 58 | } 59 | 60 | public func hash(into hasher: inout Hasher) { 61 | hasher.combine(from) 62 | hasher.combine(to) 63 | } 64 | } 65 | 66 | /// :nodoc: 67 | public func == (lhs: Transition, rhs: Transition) -> Bool { 68 | lhs.from == rhs.from && lhs.to == rhs.to 69 | } 70 | -------------------------------------------------------------------------------- /Tests/FiniteTests/StateMachine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StateMachine.swift 3 | // FiniteTests 4 | // 5 | // Created by Valentin Knabel on 06.11.17. 6 | // 7 | 8 | import Finite 9 | import XCTest 10 | 11 | class StateMachineTests: XCTestCase { 12 | enum Test { 13 | case s0, s1 14 | } 15 | 16 | var sut: StateMachine! 17 | 18 | override func setUp() { 19 | sut = nil 20 | } 21 | 22 | func testCreatingStateMachineWillSetState() { 23 | prepare(initial: .s0, allowing: Transition(from: .s0, to: .s1)) 24 | XCTAssertEqual(sut.state, .s0) 25 | } 26 | 27 | func testAllowedTransitionsDoNotThrowAndAdjustTheState() { 28 | prepare(allowing: Transition(from: .s0, to: .s1)) 29 | XCTAssertNoThrow(try sut.transition(to: .s1)) 30 | XCTAssertEqual(sut.state, .s1) 31 | } 32 | 33 | func testNotAllowedTransitionsDoThrowAndKeepTheState() { 34 | prepare(initial: .s0, allowing: Transition(from: .s0, to: .s1)) 35 | let action = { try self.sut.transition(to: .s0) } 36 | XCTAssertThrowsError(try action()) { error in 37 | if case let .denied(from: from, to: to) = error as? TransitionError { 38 | XCTAssertEqual(from, .s0) 39 | XCTAssertEqual(to, .s0) 40 | } else { 41 | XCTFail() 42 | } 43 | } 44 | XCTAssertEqual(sut.state, .s0) 45 | } 46 | 47 | func testOnTransitionsForNilTransitionTriggered() throws { 48 | prepare(allowing: Transition(from: .s0, to: .s1)) 49 | let calledOnNilTransitions = expectation(description: "onTransitions(like:_:) called") 50 | sut.onTransitions(like: .nilTransition) { 51 | calledOnNilTransitions.fulfill() 52 | } 53 | let calledOnDefaultTransitions = expectation(description: "onTransitions(_:) called") 54 | sut.onTransitions { 55 | calledOnDefaultTransitions.fulfill() 56 | } 57 | try sut.transition(to: .s1) 58 | self.wait(for: [calledOnNilTransitions, calledOnDefaultTransitions], timeout: 0.1) 59 | } 60 | 61 | func testSubscribeTransitionsForNilTransitionTriggeredWhenHold() throws { 62 | var disposeBag = [ReferenceDisposable]() 63 | prepare(allowing: Transition(from: .s0, to: .s1)) 64 | let calledOnNilTransitions = expectation(description: "subscribeTransitions(like:_:) called") 65 | disposeBag.append(sut.subscribeTransitions(like: .nilTransition) { 66 | calledOnNilTransitions.fulfill() 67 | }) 68 | let calledOnDefaultTransitions = expectation(description: "subscribeTransitions(_:) called") 69 | disposeBag.append(sut.subscribeTransitions { 70 | calledOnDefaultTransitions.fulfill() 71 | }) 72 | try sut.transition(to: .s1) 73 | self.wait(for: [calledOnNilTransitions, calledOnDefaultTransitions], timeout: 0.1) 74 | } 75 | 76 | func testSubscribeTransitionsForNilTransitionNeverTriggeredWhenNotHold() throws { 77 | prepare(allowing: Transition(from: .s0, to: .s1)) 78 | let calledOnNilTransitions = expectation(description: "subscribeTransitions(like:_:) called") 79 | calledOnNilTransitions.isInverted = true 80 | _ = sut.subscribeTransitions(like: .nilTransition) { 81 | calledOnNilTransitions.fulfill() 82 | } 83 | let calledOnDefaultTransitions = expectation(description: "subscribeTransitions(_:) called") 84 | calledOnDefaultTransitions.isInverted = true 85 | _ = sut.subscribeTransitions { 86 | calledOnDefaultTransitions.fulfill() 87 | } 88 | try sut.transition(to: .s1) 89 | self.wait(for: [calledOnNilTransitions, calledOnDefaultTransitions], timeout: 0.1) 90 | } 91 | 92 | func testOnTransitionsTriggeredOnExactTransition() throws { 93 | prepare(allowing: Transition(from: .s0, to: .s1)) 94 | let calledOnTransitions = expectation(description: "onTransitions(like:_:) called") 95 | sut.onTransitions(like: Transition(from: .s0, to: .s1)) { 96 | calledOnTransitions.fulfill() 97 | } 98 | let calledOnTransitionsTo = expectation(description: "onTransitions(to:_:) called") 99 | sut.onTransitions(to: .s1) { 100 | calledOnTransitionsTo.fulfill() 101 | } 102 | let calledOnTransitionsFrom = expectation(description: "onTransitions(from:_:) called") 103 | sut.onTransitions(from: .s0) { 104 | calledOnTransitionsFrom.fulfill() 105 | } 106 | let calledOnTransitionsFromTo = expectation(description: "onTransitions(from:to:_:) called") 107 | sut.onTransitions(from: .s0, to: .s1) { 108 | calledOnTransitionsFromTo.fulfill() 109 | } 110 | 111 | try sut.transition(to: .s1) 112 | self.wait(for: [calledOnTransitions, calledOnTransitionsTo, calledOnTransitionsFrom, calledOnTransitionsFromTo], timeout: 1) 113 | } 114 | 115 | func testOnTransitionsNeverTriggeredOnSwappedTransition() throws { 116 | prepare(allowing: Transition(from: .s0, to: .s1)) 117 | 118 | let anyCalled = expectation(description: "any transition called") 119 | anyCalled.isInverted = true 120 | sut.onTransitions(like: Transition(from: .s1, to: .s0)) { 121 | anyCalled.fulfill() 122 | } 123 | sut.onTransitions(to: .s0) { 124 | anyCalled.fulfill() 125 | } 126 | sut.onTransitions(from: .s1) { 127 | anyCalled.fulfill() 128 | } 129 | sut.onTransitions(from: .s1, to: .s0) { 130 | anyCalled.fulfill() 131 | } 132 | 133 | try sut.transition(to: .s1) 134 | self.wait(for: [anyCalled], timeout: 0.1) 135 | } 136 | 137 | func testSubscribedTransitionsTriggeredOnExactTransitionWhenStored() throws { 138 | var disposeBag = [ReferenceDisposable]() 139 | prepare(allowing: Transition(from: .s0, to: .s1)) 140 | let calledSubscribeTransitions = expectation(description: "subscribeTransitions(like:_:) called") 141 | disposeBag.append(sut.subscribeTransitions(like: Transition(from: .s0, to: .s1)) { 142 | calledSubscribeTransitions.fulfill() 143 | }) 144 | let calledSubscribeTransitionsTo = expectation(description: "subscribeTransitions(to:_:) called") 145 | disposeBag.append(sut.subscribeTransitions(to: .s1) { 146 | calledSubscribeTransitionsTo.fulfill() 147 | }) 148 | let calledSubscribeTransitionsFrom = expectation(description: "subscribeTransitions(from:_:) called") 149 | disposeBag.append(sut.subscribeTransitions(from: .s0) { 150 | calledSubscribeTransitionsFrom.fulfill() 151 | }) 152 | let calledSubscribeTransitionsFromTo = expectation(description: "subscribeTransitions(from:to:_:) called") 153 | disposeBag.append(sut.subscribeTransitions(from: .s0, to: .s1) { 154 | calledSubscribeTransitionsFromTo.fulfill() 155 | }) 156 | 157 | try sut.transition(to: .s1) 158 | self.wait(for: [calledSubscribeTransitions, calledSubscribeTransitionsTo, calledSubscribeTransitionsFrom, calledSubscribeTransitionsFromTo], timeout: 0.1) 159 | } 160 | 161 | func testSubscribedTransitionsNeverTriggeredOnExactTransitionWhenNotStored() throws { 162 | prepare(allowing: Transition(from: .s0, to: .s1)) 163 | let anyCalled = expectation(description: "any subscribeTransitions called") 164 | anyCalled.isInverted = true 165 | 166 | _ = sut.subscribeTransitions(like: Transition(from: .s0, to: .s1)) { 167 | anyCalled.fulfill() 168 | } 169 | _ = sut.subscribeTransitions(to: .s1) { 170 | anyCalled.fulfill() 171 | } 172 | _ = sut.subscribeTransitions(from: .s0) { 173 | anyCalled.fulfill() 174 | } 175 | _ = sut.subscribeTransitions(from: .s0, to: .s1) { 176 | anyCalled.fulfill() 177 | } 178 | 179 | try sut.transition(to: .s1) 180 | self.wait(for: [anyCalled], timeout: 1) 181 | } 182 | 183 | private func prepare(initial state: Test = .s0, allowing transitions: Transition...) { 184 | sut = StateMachine(initial: state) { flow in 185 | for t in transitions { 186 | flow.allow(transition: t) 187 | } 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Tests/FiniteTests/SwiftShim.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftShim.swift 3 | // FiniteTests 4 | // 5 | // Created by Valentin Knabel on 07.11.17. 6 | // 7 | 8 | import XCTest 9 | 10 | #if !swift(>=4.0) 11 | 12 | func XCTAssertNoThrow(_ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "XCTAssertNoThrow", file: StaticString = #file, line: UInt = #line) { 13 | do { 14 | _ = try expression() 15 | } catch { 16 | XCTFail(message(), file: file, line: line) 17 | } 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /Tests/FiniteTests/TransitionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransitionTests.swift 3 | // StateMachine 4 | // 5 | // Created by Valentin Knabel on 20.02.15. 6 | // Copyright (c) 2015 Valentin Knabel. All rights reserved. 7 | // 8 | 9 | import Finite 10 | import XCTest 11 | 12 | class TransitionTests: XCTestCase { 13 | enum Test { 14 | case s0, s1 15 | } 16 | 17 | var nilt: Transition! 18 | var relft: Transition! 19 | var reltt: Transition! 20 | var abst: Transition! 21 | var abstr: Transition! 22 | var ts: [Transition]! { 23 | [nilt, relft, reltt, abst, abstr] 24 | } 25 | 26 | override func setUp() { 27 | nilt = Transition.nilTransition 28 | relft = Transition(from: Test.s0, to: nil) 29 | reltt = Transition(from: nil, to: Test.s1) 30 | abst = Transition(from: Test.s0, to: Test.s1) 31 | abstr = Transition(from: Test.s1, to: Test.s0) 32 | } 33 | 34 | func testAbsolute() { 35 | if abst.from == nil || abst.to == nil { 36 | XCTFail("Absolute Transition") 37 | } 38 | } 39 | 40 | func testRelative() { 41 | if relft.from == nil || relft.to != nil { 42 | XCTFail("Source Transition") 43 | } 44 | 45 | if reltt.from != nil || reltt.to == nil { 46 | XCTFail("Target Transition") 47 | } 48 | } 49 | 50 | func testNil() { 51 | let nilt = Transition(from: nil, to: nil) 52 | if nilt.from != nil || nilt.from != nil { 53 | XCTFail("Nil Transition") 54 | } 55 | } 56 | 57 | func testEqualty() { 58 | for li in 0 ..< ts.count { 59 | for ri in 0 ..< ts.count { 60 | XCTAssertEqual(ts[li] == ts[ri], li == ri, "Diagonal equal, else unequal") 61 | } 62 | } 63 | } 64 | 65 | func testHash() { 66 | // cannot test for unequalty => there may always be collisions 67 | for i in 0 ..< ts.count { 68 | XCTAssertEqual(ts[i].hashValue, ts[i].hashValue, "Diagonal hash equal") 69 | } 70 | } 71 | 72 | func testGeneral() { 73 | XCTAssertEqual(nilt.generalTransitions, [], "Nil transition generals") 74 | XCTAssertEqual(relft.generalTransitions, [relft], "Relative source transition generals") 75 | XCTAssertEqual(reltt.generalTransitions, [reltt], "Relative target transition generals") 76 | XCTAssertEqual(abst.generalTransitions, [abst, relft, reltt], "Absolute transition generals") 77 | } 78 | 79 | func testDescription() { 80 | XCTAssertEqual(nilt.description, "any -> any") 81 | XCTAssertEqual(relft.description, "s0 -> any") 82 | XCTAssertEqual(reltt.description, "any -> s1") 83 | XCTAssertEqual(abst.description, "s0 -> s1") 84 | XCTAssertEqual(abstr.description, "s1 -> s0") 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Tests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | #if !canImport(ObjectiveC) 2 | import XCTest 3 | 4 | extension StateFlowTests { 5 | // DO NOT MODIFY: This is autogenerated, use: 6 | // `swift test --generate-linuxmain` 7 | // to regenerate. 8 | static let __allTests__StateFlowTests = [ 9 | ("testAllowingConvenienceFromRelativeTransitionHelper", testAllowingConvenienceFromRelativeTransitionHelper), 10 | ("testAllowingConvenienceToRelativeTransitionHelper", testAllowingConvenienceToRelativeTransitionHelper), 11 | ("testAllowingEverythingMultipleConvenienceFromToAbsoluteTransitionHelperForEveryState", testAllowingEverythingMultipleConvenienceFromToAbsoluteTransitionHelperForEveryState), 12 | ("testAllowingMultipleConvenienceFromAbsoluteTransitionHelper", testAllowingMultipleConvenienceFromAbsoluteTransitionHelper), 13 | ("testAllowingMultipleConvenienceFromRelativeTransitionHelper", testAllowingMultipleConvenienceFromRelativeTransitionHelper), 14 | ("testAllowingMultipleConvenienceFromToAbsoluteTransitionHelper", testAllowingMultipleConvenienceFromToAbsoluteTransitionHelper), 15 | ("testAllowingMultipleConvenienceToAbsoluteTransitionHelper", testAllowingMultipleConvenienceToAbsoluteTransitionHelper), 16 | ("testAllowingMultipleConvenienceToRelativeTransitionHelper", testAllowingMultipleConvenienceToRelativeTransitionHelper), 17 | ("testAllowsAbsoluteTransitionsWhenAddedPreviously", testAllowsAbsoluteTransitionsWhenAddedPreviously), 18 | ("testAllowsAbsoluteTransitionsWhenAddedPreviouslyUsingEmptyInitializer", testAllowsAbsoluteTransitionsWhenAddedPreviouslyUsingEmptyInitializer), 19 | ("testAllowsAbsoluteTransitionWhenFromRelativeIsAllowed", testAllowsAbsoluteTransitionWhenFromRelativeIsAllowed), 20 | ("testAllowsAbsoluteTransitionWhenToRelativeIsAllowed", testAllowsAbsoluteTransitionWhenToRelativeIsAllowed), 21 | ("testAllowsAlwaysSucceedingFilter", testAllowsAlwaysSucceedingFilter), 22 | ("testAllowsFromRelativeTransitionsWhenAddedPreviously", testAllowsFromRelativeTransitionsWhenAddedPreviously), 23 | ("testAllowsToRelativeTransitionsWhenAddedPreviously", testAllowsToRelativeTransitionsWhenAddedPreviously), 24 | ("testDeniesAlwaysDenyingFilter", testDeniesAlwaysDenyingFilter), 25 | ("testDescriptionWithContents", testDescriptionWithContents), 26 | ("testDescriptionWithoutContents", testDescriptionWithoutContents), 27 | ("testDoesNotAllowAbsoluteTransitionsWhenAddedNilPreviously", testDoesNotAllowAbsoluteTransitionsWhenAddedNilPreviously), 28 | ("testDoesNotAllowNilTransitionsWhenAddedPreviously", testDoesNotAllowNilTransitionsWhenAddedPreviously), 29 | ("testDoesNotAllowTransitionsToSameStateByDefault", testDoesNotAllowTransitionsToSameStateByDefault), 30 | ("testDoesNotAllowUnrelatedAbsoluteTransitions", testDoesNotAllowUnrelatedAbsoluteTransitions), 31 | ("testEmptyDeniesEverything", testEmptyDeniesEverything), 32 | ("testEmptyDeniesEverythingForConfig", testEmptyDeniesEverythingForConfig), 33 | ] 34 | } 35 | 36 | extension StateMachineTests { 37 | // DO NOT MODIFY: This is autogenerated, use: 38 | // `swift test --generate-linuxmain` 39 | // to regenerate. 40 | static let __allTests__StateMachineTests = [ 41 | ("testAllowedTransitionsDoNotThrowAndAdjustTheState", testAllowedTransitionsDoNotThrowAndAdjustTheState), 42 | ("testCreatingStateMachineWillSetState", testCreatingStateMachineWillSetState), 43 | ("testNotAllowedTransitionsDoThrowAndKeepTheState", testNotAllowedTransitionsDoThrowAndKeepTheState), 44 | ("testOnTransitionsForNilTransitionTriggered", testOnTransitionsForNilTransitionTriggered), 45 | ("testOnTransitionsNeverTriggeredOnSwappedTransition", testOnTransitionsNeverTriggeredOnSwappedTransition), 46 | ("testOnTransitionsTriggeredOnExactTransition", testOnTransitionsTriggeredOnExactTransition), 47 | ("testSubscribedTransitionsNeverTriggeredOnExactTransitionWhenNotStored", testSubscribedTransitionsNeverTriggeredOnExactTransitionWhenNotStored), 48 | ("testSubscribedTransitionsTriggeredOnExactTransitionWhenStored", testSubscribedTransitionsTriggeredOnExactTransitionWhenStored), 49 | ("testSubscribeTransitionsForNilTransitionNeverTriggeredWhenNotHold", testSubscribeTransitionsForNilTransitionNeverTriggeredWhenNotHold), 50 | ("testSubscribeTransitionsForNilTransitionTriggeredWhenHold", testSubscribeTransitionsForNilTransitionTriggeredWhenHold), 51 | ] 52 | } 53 | 54 | extension TransitionTests { 55 | // DO NOT MODIFY: This is autogenerated, use: 56 | // `swift test --generate-linuxmain` 57 | // to regenerate. 58 | static let __allTests__TransitionTests = [ 59 | ("testAbsolute", testAbsolute), 60 | ("testDescription", testDescription), 61 | ("testEqualty", testEqualty), 62 | ("testGeneral", testGeneral), 63 | ("testHash", testHash), 64 | ("testNil", testNil), 65 | ("testRelative", testRelative), 66 | ] 67 | } 68 | 69 | public func __allTests() -> [XCTestCaseEntry] { 70 | [ 71 | testCase(StateFlowTests.__allTests__StateFlowTests), 72 | testCase(StateMachineTests.__allTests__StateMachineTests), 73 | testCase(TransitionTests.__allTests__TransitionTests), 74 | ] 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: "header, diff" 3 | behavior: default 4 | -------------------------------------------------------------------------------- /docs/Enums.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Enumerations Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

Enumerations

96 |

The following enumerations are available globally.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | TransitionError 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    Indicates that a transition failed.

    119 | 120 | See more 121 |
    122 |
    123 |

    Declaration

    124 |
    125 |

    Swift

    126 |
    public enum TransitionError<T> : Error where T : Hashable
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
134 |
135 |
136 |
137 | 138 |
139 |
140 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /docs/Enums/TransitionError.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TransitionError Enumeration Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

TransitionError

96 |
97 |
98 | 99 |
public enum TransitionError<T> : Error where T : Hashable
100 | 101 |
102 |
103 |

Indicates that a transition failed.

104 | 105 |
106 |
107 | 108 |
109 |
110 |
111 |
    112 |
  • 113 |
    114 | 115 | 116 | 117 | denied(from:to:) 118 | 119 |
    120 |
    121 |
    122 |
    123 |
    124 |
    125 |

    Represents a tried transition that is not allowed.

    126 | 127 |
    128 |
    129 |

    Declaration

    130 |
    131 |

    Swift

    132 |
    case denied(from: T, to: T)
    133 | 134 |
    135 |
    136 |
    137 |
    138 |
  • 139 |
140 |
141 |
142 |
143 | 144 |
145 |
146 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /docs/Protocols.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Protocols Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

Protocols

96 |

The following protocols are available globally.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | ReferenceDisposable 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    A subsription reference which needs to be referenced strongly.

    119 | 120 | See more 121 |
    122 |
    123 |

    Declaration

    124 |
    125 |

    Swift

    126 |
    public protocol ReferenceDisposable
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
134 |
135 |
136 |
137 | 138 |
139 |
140 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /docs/Protocols/ReferenceDisposable.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ReferenceDisposable Protocol Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

ReferenceDisposable

96 |
97 |
98 | 99 |
public protocol ReferenceDisposable
100 | 101 |
102 |
103 |

A subsription reference which needs to be referenced strongly.

104 | 105 |
106 |
107 | 108 |
109 |
110 |
111 |
    112 |
  • 113 |
    114 | 115 | 116 | 117 | dispose() 118 | 119 |
    120 |
    121 |
    122 |
    123 |
    124 |
    125 |

    Disposes the current subscription. Current and future operations will be canceled.

    126 | 127 |
    128 |
    129 |

    Declaration

    130 |
    131 |

    Swift

    132 |
    func dispose()
    133 | 134 |
    135 |
    136 |
    137 |
    138 |
  • 139 |
140 |
141 |
142 |
143 | 144 |
145 |
146 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /docs/Structs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Structures Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

Structures

96 |

The following structures are available globally.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | StateFlow 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    Represents a configuration of a state machine.

    119 | 120 | See more 121 |
    122 |
    123 |

    Declaration

    124 |
    125 |

    Swift

    126 |
    public struct StateFlow<T> : CustomStringConvertible where T : Hashable
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
  • 134 |
    135 | 136 | 137 | 138 | StateMachine 139 | 140 |
    141 |
    142 |
    143 |
    144 |
    145 |
    146 |

    Represents a state machine.

    147 | 148 | See more 149 |
    150 |
    151 |

    Declaration

    152 |
    153 |

    Swift

    154 |
    public struct StateMachine<T> : CustomStringConvertible where T : Hashable
    155 | 156 |
    157 |
    158 |
    159 |
    160 |
  • 161 |
  • 162 |
    163 | 164 | 165 | 166 | Transition 167 | 168 |
    169 |
    170 |
    171 |
    172 |
    173 |
    174 |

    The Transition class represents a transition from a given state to a targeted state. 175 | There are three types of transitions:

    176 | 177 |
      178 |
    1. Absolute Transitions have a source and a target state set.
    2. 179 |
    3. Relative Transitions have only one state set.
    4. 180 |
    5. Nil Transitions have none states set and will be ignored.
    6. 181 |
    182 | 183 | See more 184 |
    185 |
    186 |

    Declaration

    187 |
    188 |

    Swift

    189 |
    public struct Transition<T> : Hashable, CustomStringConvertible where T : Hashable
    190 | 191 |
    192 |
    193 |
    194 |
    195 |
  • 196 |
197 |
198 |
199 |
200 | 201 |
202 |
203 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /docs/Typealiases.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Type Aliases Reference 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |

28 | 29 | Finite 4.0.0 Docs 30 | 31 | (97% documented) 32 |

33 | 34 |

35 |

36 | 37 |
38 |

39 | 40 |

41 | 42 | 43 | View on GitHub 44 | 45 |

46 | 47 |

48 | 49 | 50 | Install in Dash 51 | 52 |

53 |
54 | 55 | 60 | 61 |
62 | 104 |
105 | 106 |
107 |
108 |

Type Aliases

109 |

The following type aliases are available globally.

110 | 111 |
112 |
113 | 114 |
115 |
116 |
117 |
    118 |
  • 119 |
    120 | 121 | 122 | 123 | Error 124 | 125 |
    126 |
    127 |
    128 |
    129 |
    130 |
    131 |

    A shim for Swift 3.0’s Error protocol

    132 | 133 |
    134 |
    135 |
    136 |
  • 137 |
138 |
139 |
140 |
141 | 142 |
143 |
144 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 97% 23 | 24 | 25 | 97% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/css/jazzy.css: -------------------------------------------------------------------------------- 1 | *, *:before, *:after { 2 | box-sizing: inherit; } 3 | 4 | body { 5 | margin: 0; 6 | background: #fff; 7 | color: #333; 8 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | letter-spacing: .2px; 10 | -webkit-font-smoothing: antialiased; 11 | box-sizing: border-box; } 12 | 13 | h1 { 14 | font-size: 2rem; 15 | font-weight: 700; 16 | margin: 1.275em 0 0.6em; } 17 | 18 | h2 { 19 | font-size: 1.75rem; 20 | font-weight: 700; 21 | margin: 1.275em 0 0.3em; } 22 | 23 | h3 { 24 | font-size: 1.5rem; 25 | font-weight: 700; 26 | margin: 1em 0 0.3em; } 27 | 28 | h4 { 29 | font-size: 1.25rem; 30 | font-weight: 700; 31 | margin: 1.275em 0 0.85em; } 32 | 33 | h5 { 34 | font-size: 1rem; 35 | font-weight: 700; 36 | margin: 1.275em 0 0.85em; } 37 | 38 | h6 { 39 | font-size: 1rem; 40 | font-weight: 700; 41 | margin: 1.275em 0 0.85em; 42 | color: #777; } 43 | 44 | p { 45 | margin: 0 0 1em; } 46 | 47 | ul, ol { 48 | padding: 0 0 0 2em; 49 | margin: 0 0 0.85em; } 50 | 51 | blockquote { 52 | margin: 0 0 0.85em; 53 | padding: 0 15px; 54 | color: #858585; 55 | border-left: 4px solid #e5e5e5; } 56 | 57 | img { 58 | max-width: 100%; } 59 | 60 | a { 61 | color: #4183c4; 62 | text-decoration: none; } 63 | a:hover, a:focus { 64 | outline: 0; 65 | text-decoration: underline; } 66 | a.discouraged { 67 | text-decoration: line-through; } 68 | a.discouraged:hover, a.discouraged:focus { 69 | text-decoration: underline line-through; } 70 | 71 | table { 72 | background: #fff; 73 | width: 100%; 74 | border-collapse: collapse; 75 | border-spacing: 0; 76 | overflow: auto; 77 | margin: 0 0 0.85em; } 78 | 79 | tr:nth-child(2n) { 80 | background-color: #fbfbfb; } 81 | 82 | th, td { 83 | padding: 6px 13px; 84 | border: 1px solid #ddd; } 85 | 86 | pre { 87 | margin: 0 0 1.275em; 88 | padding: .85em 1em; 89 | overflow: auto; 90 | background: #f7f7f7; 91 | font-size: .85em; 92 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } 93 | 94 | code { 95 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } 96 | 97 | .item-container p > code, .item-container li > code, .top-matter p > code, .top-matter li > code { 98 | background: #f7f7f7; 99 | padding: .2em; } 100 | .item-container p > code:before, .item-container p > code:after, .item-container li > code:before, .item-container li > code:after, .top-matter p > code:before, .top-matter p > code:after, .top-matter li > code:before, .top-matter li > code:after { 101 | letter-spacing: -.2em; 102 | content: "\00a0"; } 103 | 104 | pre code { 105 | padding: 0; 106 | white-space: pre; } 107 | 108 | .content-wrapper { 109 | display: flex; 110 | flex-direction: column; } 111 | @media (min-width: 768px) { 112 | .content-wrapper { 113 | flex-direction: row; } } 114 | .header { 115 | display: flex; 116 | padding: 8px; 117 | font-size: 0.875em; 118 | background: #444; 119 | color: #999; } 120 | 121 | .header-col { 122 | margin: 0; 123 | padding: 0 8px; } 124 | 125 | .header-col--primary { 126 | flex: 1; } 127 | 128 | .header-link { 129 | color: #fff; } 130 | 131 | .header-icon { 132 | padding-right: 6px; 133 | vertical-align: -4px; 134 | height: 16px; } 135 | 136 | .breadcrumbs { 137 | font-size: 0.875em; 138 | padding: 8px 16px; 139 | margin: 0; 140 | background: #fbfbfb; 141 | border-bottom: 1px solid #ddd; } 142 | 143 | .carat { 144 | height: 10px; 145 | margin: 0 5px; } 146 | 147 | .navigation { 148 | order: 2; } 149 | @media (min-width: 768px) { 150 | .navigation { 151 | order: 1; 152 | width: 25%; 153 | max-width: 300px; 154 | padding-bottom: 64px; 155 | overflow: hidden; 156 | word-wrap: normal; 157 | background: #fbfbfb; 158 | border-right: 1px solid #ddd; } } 159 | .nav-groups { 160 | list-style-type: none; 161 | padding-left: 0; } 162 | 163 | .nav-group-name { 164 | border-bottom: 1px solid #ddd; 165 | padding: 8px 0 8px 16px; } 166 | 167 | .nav-group-name-link { 168 | color: #333; } 169 | 170 | .nav-group-tasks { 171 | margin: 8px 0; 172 | padding: 0 0 0 8px; } 173 | 174 | .nav-group-task { 175 | font-size: 1em; 176 | list-style-type: none; 177 | white-space: nowrap; } 178 | 179 | .nav-group-task-link { 180 | color: #808080; } 181 | 182 | .main-content { 183 | order: 1; } 184 | @media (min-width: 768px) { 185 | .main-content { 186 | order: 2; 187 | flex: 1; 188 | padding-bottom: 60px; } } 189 | .section { 190 | padding: 0 32px; 191 | border-bottom: 1px solid #ddd; } 192 | 193 | .section-content { 194 | max-width: 834px; 195 | margin: 0 auto; 196 | padding: 16px 0; } 197 | 198 | .section-name { 199 | color: #666; 200 | display: block; } 201 | .section-name p { 202 | margin-bottom: inherit; } 203 | 204 | .declaration .highlight { 205 | overflow-x: initial; 206 | padding: 8px 0; 207 | margin: 0; 208 | background-color: transparent; 209 | border: none; } 210 | 211 | .task-group-section { 212 | border-top: 1px solid #ddd; } 213 | 214 | .task-group { 215 | padding-top: 0px; } 216 | 217 | .task-name-container a[name]:before { 218 | content: ""; 219 | display: block; } 220 | 221 | .section-name-container { 222 | position: relative; } 223 | .section-name-container .section-name-link { 224 | position: absolute; 225 | top: 0; 226 | left: 0; 227 | bottom: 0; 228 | right: 0; 229 | margin-bottom: 0; } 230 | .section-name-container .section-name { 231 | position: relative; 232 | pointer-events: none; 233 | z-index: 1; } 234 | .section-name-container .section-name a { 235 | pointer-events: auto; } 236 | 237 | .item-container { 238 | padding: 0; } 239 | 240 | .item { 241 | padding-top: 8px; 242 | width: 100%; 243 | list-style-type: none; } 244 | .item a[name]:before { 245 | content: ""; 246 | display: block; } 247 | .item .token, .item .direct-link { 248 | display: inline-block; 249 | text-indent: -20px; 250 | padding-left: 3px; 251 | margin-left: 20px; 252 | font-size: 1rem; } 253 | .item .declaration-note { 254 | font-size: .85em; 255 | color: #808080; 256 | font-style: italic; } 257 | 258 | .pointer-container { 259 | border-bottom: 1px solid #ddd; 260 | left: -23px; 261 | padding-bottom: 13px; 262 | position: relative; 263 | width: 110%; } 264 | 265 | .pointer { 266 | left: 21px; 267 | top: 7px; 268 | display: block; 269 | position: absolute; 270 | width: 12px; 271 | height: 12px; 272 | border-left: 1px solid #ddd; 273 | border-top: 1px solid #ddd; 274 | background: #fff; 275 | transform: rotate(45deg); } 276 | 277 | .height-container { 278 | display: none; 279 | position: relative; 280 | width: 100%; 281 | overflow: hidden; } 282 | .height-container .section { 283 | background: #fff; 284 | border: 1px solid #ddd; 285 | border-top-width: 0; 286 | padding-top: 10px; 287 | padding-bottom: 5px; 288 | padding: 8px 16px; } 289 | 290 | .aside, .language { 291 | padding: 6px 12px; 292 | margin: 12px 0; 293 | border-left: 5px solid #dddddd; 294 | overflow-y: hidden; } 295 | .aside .aside-title, .language .aside-title { 296 | font-size: 9px; 297 | letter-spacing: 2px; 298 | text-transform: uppercase; 299 | padding-bottom: 0; 300 | margin: 0; 301 | color: #aaa; 302 | -webkit-user-select: none; } 303 | .aside p:last-child, .language p:last-child { 304 | margin-bottom: 0; } 305 | 306 | .language { 307 | border-left: 5px solid #cde9f4; } 308 | .language .aside-title { 309 | color: #4183c4; } 310 | 311 | .aside-warning, .aside-deprecated, .aside-unavailable { 312 | border-left: 5px solid #ff6666; } 313 | .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { 314 | color: #ff0000; } 315 | 316 | .graybox { 317 | border-collapse: collapse; 318 | width: 100%; } 319 | .graybox p { 320 | margin: 0; 321 | word-break: break-word; 322 | min-width: 50px; } 323 | .graybox td { 324 | border: 1px solid #ddd; 325 | padding: 5px 25px 5px 10px; 326 | vertical-align: middle; } 327 | .graybox tr td:first-of-type { 328 | text-align: right; 329 | padding: 7px; 330 | vertical-align: top; 331 | word-break: normal; 332 | width: 40px; } 333 | 334 | .slightly-smaller { 335 | font-size: 0.9em; } 336 | 337 | .footer { 338 | padding: 8px 16px; 339 | background: #444; 340 | color: #ddd; 341 | font-size: 0.8em; } 342 | .footer p { 343 | margin: 8px 0; } 344 | .footer a { 345 | color: #fff; } 346 | 347 | html.dash .header, html.dash .breadcrumbs, html.dash .navigation { 348 | display: none; } 349 | 350 | html.dash .height-container { 351 | display: block; } 352 | 353 | form[role=search] input { 354 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 355 | font-size: 14px; 356 | line-height: 24px; 357 | padding: 0 10px; 358 | margin: 0; 359 | border: none; 360 | border-radius: 1em; } 361 | .loading form[role=search] input { 362 | background: white url(../img/spinner.gif) center right 4px no-repeat; } 363 | 364 | form[role=search] .tt-menu { 365 | margin: 0; 366 | min-width: 300px; 367 | background: #fbfbfb; 368 | color: #333; 369 | border: 1px solid #ddd; } 370 | 371 | form[role=search] .tt-highlight { 372 | font-weight: bold; } 373 | 374 | form[role=search] .tt-suggestion { 375 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 376 | padding: 0 8px; } 377 | form[role=search] .tt-suggestion span { 378 | display: table-cell; 379 | white-space: nowrap; } 380 | form[role=search] .tt-suggestion .doc-parent-name { 381 | width: 100%; 382 | text-align: right; 383 | font-weight: normal; 384 | font-size: 0.9em; 385 | padding-left: 16px; } 386 | 387 | form[role=search] .tt-suggestion:hover, 388 | form[role=search] .tt-suggestion.tt-cursor { 389 | cursor: pointer; 390 | background-color: #4183c4; 391 | color: #fff; } 392 | 393 | form[role=search] .tt-suggestion:hover .doc-parent-name, 394 | form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { 395 | color: #fff; } 396 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.finite 7 | CFBundleName 8 | Finite 9 | DocSetPlatformFamily 10 | finite 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | DashDocSetFallbackURL 20 | https://vknabel.github.io/Finite/ 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/Enums.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Enumerations Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

Enumerations

96 |

The following enumerations are available globally.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | TransitionError 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    Indicates that a transition failed.

    119 | 120 | See more 121 |
    122 |
    123 |

    Declaration

    124 |
    125 |

    Swift

    126 |
    public enum TransitionError<T> : Error where T : Hashable
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
134 |
135 |
136 |
137 | 138 |
139 |
140 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/Enums/TransitionError.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TransitionError Enumeration Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

TransitionError

96 |
97 |
98 | 99 |
public enum TransitionError<T> : Error where T : Hashable
100 | 101 |
102 |
103 |

Indicates that a transition failed.

104 | 105 |
106 |
107 | 108 |
109 |
110 |
111 |
    112 |
  • 113 |
    114 | 115 | 116 | 117 | denied(from:to:) 118 | 119 |
    120 |
    121 |
    122 |
    123 |
    124 |
    125 |

    Represents a tried transition that is not allowed.

    126 | 127 |
    128 |
    129 |

    Declaration

    130 |
    131 |

    Swift

    132 |
    case denied(from: T, to: T)
    133 | 134 |
    135 |
    136 |
    137 |
    138 |
  • 139 |
140 |
141 |
142 |
143 | 144 |
145 |
146 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/Protocols.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Protocols Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

Protocols

96 |

The following protocols are available globally.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | ReferenceDisposable 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    A subsription reference which needs to be referenced strongly.

    119 | 120 | See more 121 |
    122 |
    123 |

    Declaration

    124 |
    125 |

    Swift

    126 |
    public protocol ReferenceDisposable
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
134 |
135 |
136 |
137 | 138 |
139 |
140 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/Protocols/ReferenceDisposable.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ReferenceDisposable Protocol Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

ReferenceDisposable

96 |
97 |
98 | 99 |
public protocol ReferenceDisposable
100 | 101 |
102 |
103 |

A subsription reference which needs to be referenced strongly.

104 | 105 |
106 |
107 | 108 |
109 |
110 |
111 |
    112 |
  • 113 |
    114 | 115 | 116 | 117 | dispose() 118 | 119 |
    120 |
    121 |
    122 |
    123 |
    124 |
    125 |

    Disposes the current subscription. Current and future operations will be canceled.

    126 | 127 |
    128 |
    129 |

    Declaration

    130 |
    131 |

    Swift

    132 |
    func dispose()
    133 | 134 |
    135 |
    136 |
    137 |
    138 |
  • 139 |
140 |
141 |
142 |
143 | 144 |
145 |
146 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/Structs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Structures Reference 5 | 6 | 7 | 8 | 9 | 10 | " 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |

23 | 24 | Finite 4.0.0 Docs 25 | 26 | (97% documented) 27 |

28 | 29 |

30 |

31 | 32 |
33 |

34 | 35 |

36 | 37 | 38 | View on GitHub 39 | 40 |

41 | 42 |

43 | 44 | 45 | Install in Dash 46 | 47 |

48 |
49 | 50 | 55 | 56 |
57 | 91 |
92 | 93 |
94 |
95 |

Structures

96 |

The following structures are available globally.

97 | 98 |
99 |
100 | 101 |
102 |
103 |
104 |
    105 |
  • 106 |
    107 | 108 | 109 | 110 | StateFlow 111 | 112 |
    113 |
    114 |
    115 |
    116 |
    117 |
    118 |

    Represents a configuration of a state machine.

    119 | 120 | See more 121 |
    122 |
    123 |

    Declaration

    124 |
    125 |

    Swift

    126 |
    public struct StateFlow<T> : CustomStringConvertible where T : Hashable
    127 | 128 |
    129 |
    130 |
    131 |
    132 |
  • 133 |
  • 134 |
    135 | 136 | 137 | 138 | StateMachine 139 | 140 |
    141 |
    142 |
    143 |
    144 |
    145 |
    146 |

    Represents a state machine.

    147 | 148 | See more 149 |
    150 |
    151 |

    Declaration

    152 |
    153 |

    Swift

    154 |
    public struct StateMachine<T> : CustomStringConvertible where T : Hashable
    155 | 156 |
    157 |
    158 |
    159 |
    160 |
  • 161 |
  • 162 |
    163 | 164 | 165 | 166 | Transition 167 | 168 |
    169 |
    170 |
    171 |
    172 |
    173 |
    174 |

    The Transition class represents a transition from a given state to a targeted state. 175 | There are three types of transitions:

    176 | 177 |
      178 |
    1. Absolute Transitions have a source and a target state set.
    2. 179 |
    3. Relative Transitions have only one state set.
    4. 180 |
    5. Nil Transitions have none states set and will be ignored.
    6. 181 |
    182 | 183 | See more 184 |
    185 |
    186 |

    Declaration

    187 |
    188 |

    Swift

    189 |
    public struct Transition<T> : Hashable, CustomStringConvertible where T : Hashable
    190 | 191 |
    192 |
    193 |
    194 |
    195 |
  • 196 |
197 |
198 |
199 |
200 | 201 |
202 |
203 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/Typealiases.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Type Aliases Reference 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |

28 | 29 | Finite 4.0.0 Docs 30 | 31 | (97% documented) 32 |

33 | 34 |

35 |

36 | 37 |
38 |

39 | 40 |

41 | 42 | 43 | View on GitHub 44 | 45 |

46 | 47 |

48 | 49 | 50 | Install in Dash 51 | 52 |

53 |
54 | 55 | 60 | 61 |
62 | 104 |
105 | 106 |
107 |
108 |

Type Aliases

109 |

The following type aliases are available globally.

110 | 111 |
112 |
113 | 114 |
115 |
116 |
117 |
    118 |
  • 119 |
    120 | 121 | 122 | 123 | Error 124 | 125 |
    126 |
    127 |
    128 |
    129 |
    130 |
    131 |

    A shim for Swift 3.0’s Error protocol

    132 | 133 |
    134 |
    135 |
    136 |
  • 137 |
138 |
139 |
140 |
141 | 142 |
143 |
144 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 97% 23 | 24 | 25 | 97% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/css/jazzy.css: -------------------------------------------------------------------------------- 1 | *, *:before, *:after { 2 | box-sizing: inherit; } 3 | 4 | body { 5 | margin: 0; 6 | background: #fff; 7 | color: #333; 8 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | letter-spacing: .2px; 10 | -webkit-font-smoothing: antialiased; 11 | box-sizing: border-box; } 12 | 13 | h1 { 14 | font-size: 2rem; 15 | font-weight: 700; 16 | margin: 1.275em 0 0.6em; } 17 | 18 | h2 { 19 | font-size: 1.75rem; 20 | font-weight: 700; 21 | margin: 1.275em 0 0.3em; } 22 | 23 | h3 { 24 | font-size: 1.5rem; 25 | font-weight: 700; 26 | margin: 1em 0 0.3em; } 27 | 28 | h4 { 29 | font-size: 1.25rem; 30 | font-weight: 700; 31 | margin: 1.275em 0 0.85em; } 32 | 33 | h5 { 34 | font-size: 1rem; 35 | font-weight: 700; 36 | margin: 1.275em 0 0.85em; } 37 | 38 | h6 { 39 | font-size: 1rem; 40 | font-weight: 700; 41 | margin: 1.275em 0 0.85em; 42 | color: #777; } 43 | 44 | p { 45 | margin: 0 0 1em; } 46 | 47 | ul, ol { 48 | padding: 0 0 0 2em; 49 | margin: 0 0 0.85em; } 50 | 51 | blockquote { 52 | margin: 0 0 0.85em; 53 | padding: 0 15px; 54 | color: #858585; 55 | border-left: 4px solid #e5e5e5; } 56 | 57 | img { 58 | max-width: 100%; } 59 | 60 | a { 61 | color: #4183c4; 62 | text-decoration: none; } 63 | a:hover, a:focus { 64 | outline: 0; 65 | text-decoration: underline; } 66 | a.discouraged { 67 | text-decoration: line-through; } 68 | a.discouraged:hover, a.discouraged:focus { 69 | text-decoration: underline line-through; } 70 | 71 | table { 72 | background: #fff; 73 | width: 100%; 74 | border-collapse: collapse; 75 | border-spacing: 0; 76 | overflow: auto; 77 | margin: 0 0 0.85em; } 78 | 79 | tr:nth-child(2n) { 80 | background-color: #fbfbfb; } 81 | 82 | th, td { 83 | padding: 6px 13px; 84 | border: 1px solid #ddd; } 85 | 86 | pre { 87 | margin: 0 0 1.275em; 88 | padding: .85em 1em; 89 | overflow: auto; 90 | background: #f7f7f7; 91 | font-size: .85em; 92 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } 93 | 94 | code { 95 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } 96 | 97 | .item-container p > code, .item-container li > code, .top-matter p > code, .top-matter li > code { 98 | background: #f7f7f7; 99 | padding: .2em; } 100 | .item-container p > code:before, .item-container p > code:after, .item-container li > code:before, .item-container li > code:after, .top-matter p > code:before, .top-matter p > code:after, .top-matter li > code:before, .top-matter li > code:after { 101 | letter-spacing: -.2em; 102 | content: "\00a0"; } 103 | 104 | pre code { 105 | padding: 0; 106 | white-space: pre; } 107 | 108 | .content-wrapper { 109 | display: flex; 110 | flex-direction: column; } 111 | @media (min-width: 768px) { 112 | .content-wrapper { 113 | flex-direction: row; } } 114 | .header { 115 | display: flex; 116 | padding: 8px; 117 | font-size: 0.875em; 118 | background: #444; 119 | color: #999; } 120 | 121 | .header-col { 122 | margin: 0; 123 | padding: 0 8px; } 124 | 125 | .header-col--primary { 126 | flex: 1; } 127 | 128 | .header-link { 129 | color: #fff; } 130 | 131 | .header-icon { 132 | padding-right: 6px; 133 | vertical-align: -4px; 134 | height: 16px; } 135 | 136 | .breadcrumbs { 137 | font-size: 0.875em; 138 | padding: 8px 16px; 139 | margin: 0; 140 | background: #fbfbfb; 141 | border-bottom: 1px solid #ddd; } 142 | 143 | .carat { 144 | height: 10px; 145 | margin: 0 5px; } 146 | 147 | .navigation { 148 | order: 2; } 149 | @media (min-width: 768px) { 150 | .navigation { 151 | order: 1; 152 | width: 25%; 153 | max-width: 300px; 154 | padding-bottom: 64px; 155 | overflow: hidden; 156 | word-wrap: normal; 157 | background: #fbfbfb; 158 | border-right: 1px solid #ddd; } } 159 | .nav-groups { 160 | list-style-type: none; 161 | padding-left: 0; } 162 | 163 | .nav-group-name { 164 | border-bottom: 1px solid #ddd; 165 | padding: 8px 0 8px 16px; } 166 | 167 | .nav-group-name-link { 168 | color: #333; } 169 | 170 | .nav-group-tasks { 171 | margin: 8px 0; 172 | padding: 0 0 0 8px; } 173 | 174 | .nav-group-task { 175 | font-size: 1em; 176 | list-style-type: none; 177 | white-space: nowrap; } 178 | 179 | .nav-group-task-link { 180 | color: #808080; } 181 | 182 | .main-content { 183 | order: 1; } 184 | @media (min-width: 768px) { 185 | .main-content { 186 | order: 2; 187 | flex: 1; 188 | padding-bottom: 60px; } } 189 | .section { 190 | padding: 0 32px; 191 | border-bottom: 1px solid #ddd; } 192 | 193 | .section-content { 194 | max-width: 834px; 195 | margin: 0 auto; 196 | padding: 16px 0; } 197 | 198 | .section-name { 199 | color: #666; 200 | display: block; } 201 | .section-name p { 202 | margin-bottom: inherit; } 203 | 204 | .declaration .highlight { 205 | overflow-x: initial; 206 | padding: 8px 0; 207 | margin: 0; 208 | background-color: transparent; 209 | border: none; } 210 | 211 | .task-group-section { 212 | border-top: 1px solid #ddd; } 213 | 214 | .task-group { 215 | padding-top: 0px; } 216 | 217 | .task-name-container a[name]:before { 218 | content: ""; 219 | display: block; } 220 | 221 | .section-name-container { 222 | position: relative; } 223 | .section-name-container .section-name-link { 224 | position: absolute; 225 | top: 0; 226 | left: 0; 227 | bottom: 0; 228 | right: 0; 229 | margin-bottom: 0; } 230 | .section-name-container .section-name { 231 | position: relative; 232 | pointer-events: none; 233 | z-index: 1; } 234 | .section-name-container .section-name a { 235 | pointer-events: auto; } 236 | 237 | .item-container { 238 | padding: 0; } 239 | 240 | .item { 241 | padding-top: 8px; 242 | width: 100%; 243 | list-style-type: none; } 244 | .item a[name]:before { 245 | content: ""; 246 | display: block; } 247 | .item .token, .item .direct-link { 248 | display: inline-block; 249 | text-indent: -20px; 250 | padding-left: 3px; 251 | margin-left: 20px; 252 | font-size: 1rem; } 253 | .item .declaration-note { 254 | font-size: .85em; 255 | color: #808080; 256 | font-style: italic; } 257 | 258 | .pointer-container { 259 | border-bottom: 1px solid #ddd; 260 | left: -23px; 261 | padding-bottom: 13px; 262 | position: relative; 263 | width: 110%; } 264 | 265 | .pointer { 266 | left: 21px; 267 | top: 7px; 268 | display: block; 269 | position: absolute; 270 | width: 12px; 271 | height: 12px; 272 | border-left: 1px solid #ddd; 273 | border-top: 1px solid #ddd; 274 | background: #fff; 275 | transform: rotate(45deg); } 276 | 277 | .height-container { 278 | display: none; 279 | position: relative; 280 | width: 100%; 281 | overflow: hidden; } 282 | .height-container .section { 283 | background: #fff; 284 | border: 1px solid #ddd; 285 | border-top-width: 0; 286 | padding-top: 10px; 287 | padding-bottom: 5px; 288 | padding: 8px 16px; } 289 | 290 | .aside, .language { 291 | padding: 6px 12px; 292 | margin: 12px 0; 293 | border-left: 5px solid #dddddd; 294 | overflow-y: hidden; } 295 | .aside .aside-title, .language .aside-title { 296 | font-size: 9px; 297 | letter-spacing: 2px; 298 | text-transform: uppercase; 299 | padding-bottom: 0; 300 | margin: 0; 301 | color: #aaa; 302 | -webkit-user-select: none; } 303 | .aside p:last-child, .language p:last-child { 304 | margin-bottom: 0; } 305 | 306 | .language { 307 | border-left: 5px solid #cde9f4; } 308 | .language .aside-title { 309 | color: #4183c4; } 310 | 311 | .aside-warning, .aside-deprecated, .aside-unavailable { 312 | border-left: 5px solid #ff6666; } 313 | .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { 314 | color: #ff0000; } 315 | 316 | .graybox { 317 | border-collapse: collapse; 318 | width: 100%; } 319 | .graybox p { 320 | margin: 0; 321 | word-break: break-word; 322 | min-width: 50px; } 323 | .graybox td { 324 | border: 1px solid #ddd; 325 | padding: 5px 25px 5px 10px; 326 | vertical-align: middle; } 327 | .graybox tr td:first-of-type { 328 | text-align: right; 329 | padding: 7px; 330 | vertical-align: top; 331 | word-break: normal; 332 | width: 40px; } 333 | 334 | .slightly-smaller { 335 | font-size: 0.9em; } 336 | 337 | .footer { 338 | padding: 8px 16px; 339 | background: #444; 340 | color: #ddd; 341 | font-size: 0.8em; } 342 | .footer p { 343 | margin: 8px 0; } 344 | .footer a { 345 | color: #fff; } 346 | 347 | html.dash .header, html.dash .breadcrumbs, html.dash .navigation { 348 | display: none; } 349 | 350 | html.dash .height-container { 351 | display: block; } 352 | 353 | form[role=search] input { 354 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 355 | font-size: 14px; 356 | line-height: 24px; 357 | padding: 0 10px; 358 | margin: 0; 359 | border: none; 360 | border-radius: 1em; } 361 | .loading form[role=search] input { 362 | background: white url(../img/spinner.gif) center right 4px no-repeat; } 363 | 364 | form[role=search] .tt-menu { 365 | margin: 0; 366 | min-width: 300px; 367 | background: #fbfbfb; 368 | color: #333; 369 | border: 1px solid #ddd; } 370 | 371 | form[role=search] .tt-highlight { 372 | font-weight: bold; } 373 | 374 | form[role=search] .tt-suggestion { 375 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; 376 | padding: 0 8px; } 377 | form[role=search] .tt-suggestion span { 378 | display: table-cell; 379 | white-space: nowrap; } 380 | form[role=search] .tt-suggestion .doc-parent-name { 381 | width: 100%; 382 | text-align: right; 383 | font-weight: normal; 384 | font-size: 0.9em; 385 | padding-left: 16px; } 386 | 387 | form[role=search] .tt-suggestion:hover, 388 | form[role=search] .tt-suggestion.tt-cursor { 389 | cursor: pointer; 390 | background-color: #4183c4; 391 | color: #fff; } 392 | 393 | form[role=search] .tt-suggestion:hover .doc-parent-name, 394 | form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { 395 | color: #fff; } 396 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/docsets/Finite.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/docsets/Finite.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/docsets/Finite.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/docsets/Finite.docset/Contents/Resources/Documents/img/spinner.gif -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | function toggleItem($link, $content) { 12 | var animationDuration = 300; 13 | $link.toggleClass('token-open'); 14 | $content.slideToggle(animationDuration); 15 | } 16 | 17 | function itemLinkToContent($link) { 18 | return $link.parent().parent().next(); 19 | } 20 | 21 | // On doc load + hash-change, open any targetted item 22 | function openCurrentItemIfClosed() { 23 | if (window.jazzy.docset) { 24 | return; 25 | } 26 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); 27 | $content = itemLinkToContent($link); 28 | if ($content.is(':hidden')) { 29 | toggleItem($link, $content); 30 | } 31 | } 32 | 33 | $(openCurrentItemIfClosed); 34 | $(window).on('hashchange', openCurrentItemIfClosed); 35 | 36 | // On item link ('token') click, toggle its discussion 37 | $('.token').on('click', function(event) { 38 | if (window.jazzy.docset) { 39 | return; 40 | } 41 | var $link = $(this); 42 | toggleItem($link, itemLinkToContent($link)); 43 | 44 | // Keeps the document from jumping to the hash. 45 | var href = $link.attr('href'); 46 | if (history.pushState) { 47 | history.pushState({}, '', href); 48 | } else { 49 | location.hash = href; 50 | } 51 | event.preventDefault(); 52 | }); 53 | 54 | // Clicks on links to the current, closed, item need to open the item 55 | $("a:not('.token')").on('click', function() { 56 | if (location == this.href) { 57 | openCurrentItemIfClosed(); 58 | } 59 | }); 60 | 61 | // KaTeX rendering 62 | if ("katex" in window) { 63 | $($('.math').each( (_, element) => { 64 | katex.render(element.textContent, element, { 65 | displayMode: $(element).hasClass('m-block'), 66 | throwOnError: false, 67 | trust: true 68 | }); 69 | })) 70 | } 71 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/js/jazzy.search.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | var $typeahead = $('[data-typeahead]'); 3 | var $form = $typeahead.parents('form'); 4 | var searchURL = $form.attr('action'); 5 | 6 | function displayTemplate(result) { 7 | return result.name; 8 | } 9 | 10 | function suggestionTemplate(result) { 11 | var t = '
'; 12 | t += '' + result.name + ''; 13 | if (result.parent_name) { 14 | t += '' + result.parent_name + ''; 15 | } 16 | t += '
'; 17 | return t; 18 | } 19 | 20 | $typeahead.one('focus', function() { 21 | $form.addClass('loading'); 22 | 23 | $.getJSON(searchURL).then(function(searchData) { 24 | const searchIndex = lunr(function() { 25 | this.ref('url'); 26 | this.field('name'); 27 | this.field('abstract'); 28 | for (const [url, doc] of Object.entries(searchData)) { 29 | this.add({url: url, name: doc.name, abstract: doc.abstract}); 30 | } 31 | }); 32 | 33 | $typeahead.typeahead( 34 | { 35 | highlight: true, 36 | minLength: 3, 37 | autoselect: true 38 | }, 39 | { 40 | limit: 10, 41 | display: displayTemplate, 42 | templates: { suggestion: suggestionTemplate }, 43 | source: function(query, sync) { 44 | const lcSearch = query.toLowerCase(); 45 | const results = searchIndex.query(function(q) { 46 | q.term(lcSearch, { boost: 100 }); 47 | q.term(lcSearch, { 48 | boost: 10, 49 | wildcard: lunr.Query.wildcard.TRAILING 50 | }); 51 | }).map(function(result) { 52 | var doc = searchData[result.ref]; 53 | doc.url = result.ref; 54 | return doc; 55 | }); 56 | sync(results); 57 | } 58 | } 59 | ); 60 | $form.removeClass('loading'); 61 | $typeahead.trigger('focus'); 62 | }); 63 | }); 64 | 65 | var baseURL = searchURL.slice(0, -"search.json".length); 66 | 67 | $typeahead.on('typeahead:select', function(e, result) { 68 | window.location = baseURL + result.url; 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/search.json: -------------------------------------------------------------------------------- 1 | {"Structs/Transition.html#/s:6Finite10TransitionV03nilB0ACyxGvpZ":{"name":"nilTransition","abstract":"

Nil transitions will be ignored.

","parent_name":"Transition"},"Structs/Transition.html#/s:6Finite10TransitionV4fromxSgvp":{"name":"from","abstract":"

The source state.

","parent_name":"Transition"},"Structs/Transition.html#/s:6Finite10TransitionV2toxSgvp":{"name":"to","abstract":"

The targeted state.

","parent_name":"Transition"},"Structs/Transition.html#/s:6Finite10TransitionV4from2toACyxGxSg_AGtcfc":{"name":"init(from:to:)","abstract":"

Constructs an absolute, relative or nil transition.

","parent_name":"Transition"},"Structs/Transition.html#/s:6Finite10TransitionV18generalTransitionsShyACyxGGvp":{"name":"generalTransitions","abstract":"

All more general transitions include itself except the nil transition.

","parent_name":"Transition"},"Structs/Transition.html#/s:s23CustomStringConvertibleP11descriptionSSvp":{"name":"description","parent_name":"Transition"},"Structs/Transition.html#/s:SH4hash4intoys6HasherVz_tF":{"name":"hash(into:)","parent_name":"Transition"},"Structs/StateMachine.html#/s:6Finite12StateMachineV9Operationa":{"name":"Operation","abstract":"

An empty operation to be performed.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV16TransitionFiltera":{"name":"TransitionFilter","abstract":"

Undocumented

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV5statexvp":{"name":"state","abstract":"

The current state of the machine.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV7initial6configACyxGx_yAA0B4FlowVyxGzXEtcfc":{"name":"init(initial:config:)","abstract":"

Instantiates a state machine by configuring the StateFlow instance.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV7initial9stateFlowACyxGx_AA0bF0VyxGtcfc":{"name":"init(initial:stateFlow:)","abstract":"

Instantiates a state machine by passing an instance of StateFlow.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV10transition2to10completionyx_yyKcSgtKF":{"name":"transition(to:completion:)","abstract":"

Triggers a transition to a given state and invokes a callback on completion.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV6allows2toSbx_tF":{"name":"allows(to:)","abstract":"

Returns wether transitioning to a state is allowed.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions4like7performyAA10TransitionVyxG_yyKctF":{"name":"onTransitions(like:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV20subscribeTransitions4like7performAA19ReferenceDisposable_pAA10TransitionVyxG_yyKctF":{"name":"subscribeTransitions(like:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV11descriptionSSvp":{"name":"description","abstract":"

Returns the graph for the state machine

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions4from2to7performyx_xyyKctF":{"name":"onTransitions(from:to:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV20subscribeTransitions4from2to7performAA19ReferenceDisposable_px_xyyKctF":{"name":"subscribeTransitions(from:to:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions4from7performyx_yyKctF":{"name":"onTransitions(from:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV20subscribeTransitions4from7performAA19ReferenceDisposable_px_yyKctF":{"name":"subscribeTransitions(from:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions2to7performyx_yyKctF":{"name":"onTransitions(to:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV20subscribeTransitions2to7performAA19ReferenceDisposable_px_yyKctF":{"name":"subscribeTransitions(to:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions10transition7performyAA10TransitionVyxG_yyKctF":{"name":"onTransitions(transition:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.","parent_name":"StateMachine"},"Structs/StateFlow.html#/s:6Finite9StateFlowV16TransitionFiltera":{"name":"TransitionFilter","abstract":"

Filters wether a transition is allowed to be performed.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV12Configuratora":{"name":"Configurator","abstract":"

Configures the instance for immutable usage.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV6configACyxGyAEzXE_tcfc":{"name":"init(config:)","abstract":"

Creates a new instance that can be mutated to be stored immutable.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowVACyxGycfc":{"name":"init()","abstract":"

Creates a new instance to be used mutable.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow10transition6filteryAA10TransitionVyxG_SbAIcSgtF":{"name":"allow(transition:filter:)","abstract":"

Allows all less-equal general transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV6allowsySbAA10TransitionVyxGF":{"name":"allows(_:)","abstract":"

Returns wether a specific transition is allowed or not.","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV11descriptionSSvp":{"name":"description","abstract":"

Returns list of of transitions, sorted by the hash values of the","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from6filteryx_SbAA10TransitionVyxGcSgtF":{"name":"allow(from:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow2to6filteryx_SbAA10TransitionVyxGcSgtF":{"name":"allow(to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from2to6filteryx_xSbAA10TransitionVyxGcSgtF":{"name":"allow(from:to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from6filterySayxG_SbAA10TransitionVyxGcSgtF":{"name":"allow(from:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from2to6filterySayxG_xSbAA10TransitionVyxGcSgtF":{"name":"allow(from:to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow2to6filterySayxG_SbAA10TransitionVyxGcSgtF":{"name":"allow(to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from2to6filteryx_SayxGSbAA10TransitionVyxGcSgtF":{"name":"allow(from:to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from2to6filterySayxG_AHSbAA10TransitionVyxGcSgtF":{"name":"allow(from:to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html":{"name":"StateFlow","abstract":"

Represents a configuration of a state machine.

"},"Structs/StateMachine.html":{"name":"StateMachine","abstract":"

Represents a state machine.

"},"Structs/Transition.html":{"name":"Transition","abstract":"

The Transition class represents a transition from a given state to a targeted state."},"Protocols/ReferenceDisposable.html#/s:6Finite19ReferenceDisposableP7disposeyyF":{"name":"dispose()","abstract":"

Disposes the current subscription. Current and future operations will be canceled.

","parent_name":"ReferenceDisposable"},"Protocols/ReferenceDisposable.html":{"name":"ReferenceDisposable","abstract":"

A subsription reference which needs to be referenced strongly.

"},"Enums/TransitionError.html#/s:6Finite15TransitionErrorO6deniedyACyxGx_xtcAEmSHRzlF":{"name":"denied(from:to:)","abstract":"

Represents a tried transition that is not allowed.

","parent_name":"TransitionError"},"Enums/TransitionError.html":{"name":"TransitionError","abstract":"

Indicates that a transition failed.

"},"Enums.html":{"name":"Enumerations","abstract":"

The following enumerations are available globally.

"},"Protocols.html":{"name":"Protocols","abstract":"

The following protocols are available globally.

"},"Structs.html":{"name":"Structures","abstract":"

The following structures are available globally.

"}} -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/Documents/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | { 4 | "file": "/Users/vknabel/Developer/vknabel/Finite/Sources/StateMachine.swift", 5 | "line": 24, 6 | "symbol": "StateMachine.TransitionFilter", 7 | "symbol_kind": "source.lang.swift.decl.typealias", 8 | "warning": "undocumented" 9 | } 10 | ], 11 | "source_directory": "/Users/vknabel/Developer/vknabel/Finite" 12 | } -------------------------------------------------------------------------------- /docs/docsets/Finite.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/docsets/Finite.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/Finite.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/docsets/Finite.tgz -------------------------------------------------------------------------------- /docs/docsets/Finite.xml: -------------------------------------------------------------------------------- 1 | 4.0.0https://vknabel.github.io/Finite/docsets/Finite.tgz 2 | -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/img/carat.png -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/img/gh.png -------------------------------------------------------------------------------- /docs/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vknabel/Finite/cbd5de6ebbabfb39a730d1357c1c3659f4301c45/docs/img/spinner.gif -------------------------------------------------------------------------------- /docs/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | function toggleItem($link, $content) { 12 | var animationDuration = 300; 13 | $link.toggleClass('token-open'); 14 | $content.slideToggle(animationDuration); 15 | } 16 | 17 | function itemLinkToContent($link) { 18 | return $link.parent().parent().next(); 19 | } 20 | 21 | // On doc load + hash-change, open any targetted item 22 | function openCurrentItemIfClosed() { 23 | if (window.jazzy.docset) { 24 | return; 25 | } 26 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); 27 | $content = itemLinkToContent($link); 28 | if ($content.is(':hidden')) { 29 | toggleItem($link, $content); 30 | } 31 | } 32 | 33 | $(openCurrentItemIfClosed); 34 | $(window).on('hashchange', openCurrentItemIfClosed); 35 | 36 | // On item link ('token') click, toggle its discussion 37 | $('.token').on('click', function(event) { 38 | if (window.jazzy.docset) { 39 | return; 40 | } 41 | var $link = $(this); 42 | toggleItem($link, itemLinkToContent($link)); 43 | 44 | // Keeps the document from jumping to the hash. 45 | var href = $link.attr('href'); 46 | if (history.pushState) { 47 | history.pushState({}, '', href); 48 | } else { 49 | location.hash = href; 50 | } 51 | event.preventDefault(); 52 | }); 53 | 54 | // Clicks on links to the current, closed, item need to open the item 55 | $("a:not('.token')").on('click', function() { 56 | if (location == this.href) { 57 | openCurrentItemIfClosed(); 58 | } 59 | }); 60 | 61 | // KaTeX rendering 62 | if ("katex" in window) { 63 | $($('.math').each( (_, element) => { 64 | katex.render(element.textContent, element, { 65 | displayMode: $(element).hasClass('m-block'), 66 | throwOnError: false, 67 | trust: true 68 | }); 69 | })) 70 | } 71 | -------------------------------------------------------------------------------- /docs/js/jazzy.search.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | var $typeahead = $('[data-typeahead]'); 3 | var $form = $typeahead.parents('form'); 4 | var searchURL = $form.attr('action'); 5 | 6 | function displayTemplate(result) { 7 | return result.name; 8 | } 9 | 10 | function suggestionTemplate(result) { 11 | var t = '
'; 12 | t += '' + result.name + ''; 13 | if (result.parent_name) { 14 | t += '' + result.parent_name + ''; 15 | } 16 | t += '
'; 17 | return t; 18 | } 19 | 20 | $typeahead.one('focus', function() { 21 | $form.addClass('loading'); 22 | 23 | $.getJSON(searchURL).then(function(searchData) { 24 | const searchIndex = lunr(function() { 25 | this.ref('url'); 26 | this.field('name'); 27 | this.field('abstract'); 28 | for (const [url, doc] of Object.entries(searchData)) { 29 | this.add({url: url, name: doc.name, abstract: doc.abstract}); 30 | } 31 | }); 32 | 33 | $typeahead.typeahead( 34 | { 35 | highlight: true, 36 | minLength: 3, 37 | autoselect: true 38 | }, 39 | { 40 | limit: 10, 41 | display: displayTemplate, 42 | templates: { suggestion: suggestionTemplate }, 43 | source: function(query, sync) { 44 | const lcSearch = query.toLowerCase(); 45 | const results = searchIndex.query(function(q) { 46 | q.term(lcSearch, { boost: 100 }); 47 | q.term(lcSearch, { 48 | boost: 10, 49 | wildcard: lunr.Query.wildcard.TRAILING 50 | }); 51 | }).map(function(result) { 52 | var doc = searchData[result.ref]; 53 | doc.url = result.ref; 54 | return doc; 55 | }); 56 | sync(results); 57 | } 58 | } 59 | ); 60 | $form.removeClass('loading'); 61 | $typeahead.trigger('focus'); 62 | }); 63 | }); 64 | 65 | var baseURL = searchURL.slice(0, -"search.json".length); 66 | 67 | $typeahead.on('typeahead:select', function(e, result) { 68 | window.location = baseURL + result.url; 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /docs/search.json: -------------------------------------------------------------------------------- 1 | {"Structs/Transition.html#/s:6Finite10TransitionV03nilB0ACyxGvpZ":{"name":"nilTransition","abstract":"

Nil transitions will be ignored.

","parent_name":"Transition"},"Structs/Transition.html#/s:6Finite10TransitionV4fromxSgvp":{"name":"from","abstract":"

The source state.

","parent_name":"Transition"},"Structs/Transition.html#/s:6Finite10TransitionV2toxSgvp":{"name":"to","abstract":"

The targeted state.

","parent_name":"Transition"},"Structs/Transition.html#/s:6Finite10TransitionV4from2toACyxGxSg_AGtcfc":{"name":"init(from:to:)","abstract":"

Constructs an absolute, relative or nil transition.

","parent_name":"Transition"},"Structs/Transition.html#/s:6Finite10TransitionV18generalTransitionsShyACyxGGvp":{"name":"generalTransitions","abstract":"

All more general transitions include itself except the nil transition.

","parent_name":"Transition"},"Structs/Transition.html#/s:s23CustomStringConvertibleP11descriptionSSvp":{"name":"description","parent_name":"Transition"},"Structs/Transition.html#/s:SH4hash4intoys6HasherVz_tF":{"name":"hash(into:)","parent_name":"Transition"},"Structs/StateMachine.html#/s:6Finite12StateMachineV9Operationa":{"name":"Operation","abstract":"

An empty operation to be performed.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV16TransitionFiltera":{"name":"TransitionFilter","abstract":"

Undocumented

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV5statexvp":{"name":"state","abstract":"

The current state of the machine.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV7initial6configACyxGx_yAA0B4FlowVyxGzXEtcfc":{"name":"init(initial:config:)","abstract":"

Instantiates a state machine by configuring the StateFlow instance.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV7initial9stateFlowACyxGx_AA0bF0VyxGtcfc":{"name":"init(initial:stateFlow:)","abstract":"

Instantiates a state machine by passing an instance of StateFlow.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV10transition2to10completionyx_yyKcSgtKF":{"name":"transition(to:completion:)","abstract":"

Triggers a transition to a given state and invokes a callback on completion.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV6allows2toSbx_tF":{"name":"allows(to:)","abstract":"

Returns wether transitioning to a state is allowed.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions4like7performyAA10TransitionVyxG_yyKctF":{"name":"onTransitions(like:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV20subscribeTransitions4like7performAA19ReferenceDisposable_pAA10TransitionVyxG_yyKctF":{"name":"subscribeTransitions(like:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV11descriptionSSvp":{"name":"description","abstract":"

Returns the graph for the state machine

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions4from2to7performyx_xyyKctF":{"name":"onTransitions(from:to:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV20subscribeTransitions4from2to7performAA19ReferenceDisposable_px_xyyKctF":{"name":"subscribeTransitions(from:to:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions4from7performyx_yyKctF":{"name":"onTransitions(from:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV20subscribeTransitions4from7performAA19ReferenceDisposable_px_yyKctF":{"name":"subscribeTransitions(from:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions2to7performyx_yyKctF":{"name":"onTransitions(to:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV20subscribeTransitions2to7performAA19ReferenceDisposable_px_yyKctF":{"name":"subscribeTransitions(to:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.

","parent_name":"StateMachine"},"Structs/StateMachine.html#/s:6Finite12StateMachineV13onTransitions10transition7performyAA10TransitionVyxG_yyKctF":{"name":"onTransitions(transition:perform:)","abstract":"

Appends a transition handler for all more-equal general transitions.","parent_name":"StateMachine"},"Structs/StateFlow.html#/s:6Finite9StateFlowV16TransitionFiltera":{"name":"TransitionFilter","abstract":"

Filters wether a transition is allowed to be performed.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV12Configuratora":{"name":"Configurator","abstract":"

Configures the instance for immutable usage.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV6configACyxGyAEzXE_tcfc":{"name":"init(config:)","abstract":"

Creates a new instance that can be mutated to be stored immutable.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowVACyxGycfc":{"name":"init()","abstract":"

Creates a new instance to be used mutable.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow10transition6filteryAA10TransitionVyxG_SbAIcSgtF":{"name":"allow(transition:filter:)","abstract":"

Allows all less-equal general transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV6allowsySbAA10TransitionVyxGF":{"name":"allows(_:)","abstract":"

Returns wether a specific transition is allowed or not.","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV11descriptionSSvp":{"name":"description","abstract":"

Returns list of of transitions, sorted by the hash values of the","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from6filteryx_SbAA10TransitionVyxGcSgtF":{"name":"allow(from:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow2to6filteryx_SbAA10TransitionVyxGcSgtF":{"name":"allow(to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from2to6filteryx_xSbAA10TransitionVyxGcSgtF":{"name":"allow(from:to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from6filterySayxG_SbAA10TransitionVyxGcSgtF":{"name":"allow(from:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from2to6filterySayxG_xSbAA10TransitionVyxGcSgtF":{"name":"allow(from:to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow2to6filterySayxG_SbAA10TransitionVyxGcSgtF":{"name":"allow(to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from2to6filteryx_SayxGSbAA10TransitionVyxGcSgtF":{"name":"allow(from:to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html#/s:6Finite9StateFlowV5allow4from2to6filterySayxG_AHSbAA10TransitionVyxGcSgtF":{"name":"allow(from:to:filter:)","abstract":"

Convinience method that allows all less-equal general absolute transitions to be triggered.

","parent_name":"StateFlow"},"Structs/StateFlow.html":{"name":"StateFlow","abstract":"

Represents a configuration of a state machine.

"},"Structs/StateMachine.html":{"name":"StateMachine","abstract":"

Represents a state machine.

"},"Structs/Transition.html":{"name":"Transition","abstract":"

The Transition class represents a transition from a given state to a targeted state."},"Protocols/ReferenceDisposable.html#/s:6Finite19ReferenceDisposableP7disposeyyF":{"name":"dispose()","abstract":"

Disposes the current subscription. Current and future operations will be canceled.

","parent_name":"ReferenceDisposable"},"Protocols/ReferenceDisposable.html":{"name":"ReferenceDisposable","abstract":"

A subsription reference which needs to be referenced strongly.

"},"Enums/TransitionError.html#/s:6Finite15TransitionErrorO6deniedyACyxGx_xtcAEmSHRzlF":{"name":"denied(from:to:)","abstract":"

Represents a tried transition that is not allowed.

","parent_name":"TransitionError"},"Enums/TransitionError.html":{"name":"TransitionError","abstract":"

Indicates that a transition failed.

"},"Enums.html":{"name":"Enumerations","abstract":"

The following enumerations are available globally.

"},"Protocols.html":{"name":"Protocols","abstract":"

The following protocols are available globally.

"},"Structs.html":{"name":"Structures","abstract":"

The following structures are available globally.

"}} -------------------------------------------------------------------------------- /docs/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | { 4 | "file": "/Users/vknabel/dev/Finite/Sources/StateMachine.swift", 5 | "line": 19, 6 | "symbol": "StateMachine.TransitionFilter", 7 | "symbol_kind": "source.lang.swift.decl.typealias", 8 | "warning": "undocumented" 9 | } 10 | ], 11 | "source_directory": "/Users/vknabel/dev/Finite" 12 | } --------------------------------------------------------------------------------