├── .dockerignore
├── .github
└── workflows
│ ├── ci.yml
│ └── release.yml
├── .gitignore
├── .jazzy.yml
├── .swiftformat
├── .swiftlint.yml
├── Dockerfile
├── LICENSE
├── Makefile
├── Package.swift
├── README.md
├── Scripts
├── ensure-pristine.sh
├── gyb.py
└── make-docs.sh
├── Sources
├── Futures
│ ├── Cancellable.swift
│ ├── Channel.swift
│ ├── Channel
│ │ ├── ChannelImpl.swift
│ │ ├── ChannelMPSCBufferBounded.swift
│ │ ├── ChannelMPSCBufferUnbounded.swift
│ │ ├── ChannelMPSCPark.swift
│ │ ├── ChannelSPSCBufferBounded.swift
│ │ ├── ChannelSPSCBufferUnbounded.swift
│ │ ├── ChannelSPSCPark.swift
│ │ ├── ChannelSlotBounded.swift
│ │ └── ChannelSlotUnbounded.swift
│ ├── Context.swift
│ ├── Either.swift
│ ├── Executor.swift
│ ├── Executor
│ │ ├── QueueExecutor.swift
│ │ ├── RunLoopExecutor.swift
│ │ └── ThreadExecutor.swift
│ ├── Extensions.swift
│ ├── Future.swift
│ ├── Future
│ │ ├── AbortFuture.swift
│ │ ├── AssertNoErrorFuture.swift
│ │ ├── BreakpointFuture.swift
│ │ ├── CatchErrorFuture.swift
│ │ ├── FlatMapFuture.swift
│ │ ├── FlattenFuture.swift
│ │ ├── FlattenResultFuture.swift
│ │ ├── FutureStream.swift
│ │ ├── HandleEventsFuture.swift
│ │ ├── IgnoreOutputFuture.swift
│ │ ├── JoinAllFuture.swift
│ │ ├── JoinFuture.swift
│ │ ├── LazyFuture.swift
│ │ ├── MapFuture.swift
│ │ ├── MapKeyPathFuture.swift
│ │ ├── MapResultFuture.swift
│ │ ├── MatchEitherFuture.swift
│ │ ├── MatchOptionalFuture.swift
│ │ ├── MatchResultFuture.swift
│ │ ├── NeverFuture.swift
│ │ ├── PeekFuture.swift
│ │ ├── PollOnFuture.swift
│ │ ├── PrintFuture.swift
│ │ ├── ReadyFuture.swift
│ │ ├── ReferenceFuture.swift
│ │ ├── ReplaceErrorFuture.swift
│ │ ├── ReplaceOutputFuture.swift
│ │ ├── SelectAnyFuture.swift
│ │ ├── SelectFuture.swift
│ │ ├── SetFailureTypeFuture.swift
│ │ ├── ThenFuture.swift
│ │ ├── TryLazyFuture.swift
│ │ └── TryMapFuture.swift
│ ├── Internal
│ │ ├── AdaptiveQueue.swift
│ │ ├── CircularBuffer.swift
│ │ ├── Private.swift
│ │ ├── TaskRunner.swift
│ │ └── TaskScheduler.swift
│ ├── Poll.swift
│ ├── Promise.swift
│ ├── Result.swift
│ ├── Sink.swift
│ ├── Sink
│ │ ├── AssertNoErrorSink.swift
│ │ ├── BlockingSink.swift
│ │ ├── BufferSink.swift
│ │ ├── CollectSink.swift
│ │ ├── FlatMapInputSink.swift
│ │ ├── MapErrorSink.swift
│ │ ├── MapInputSink.swift
│ │ ├── SetFailureTypeSink.swift
│ │ ├── SinkCloseFuture.swift
│ │ ├── SinkFlushFuture.swift
│ │ ├── SinkSendAllFuture.swift
│ │ └── SinkSendFuture.swift
│ ├── Stream.swift
│ ├── Stream
│ │ ├── AbortStream.swift
│ │ ├── AssertNoErrorStream.swift
│ │ ├── BreakpointStream.swift
│ │ ├── BufferStream.swift
│ │ ├── CatchErrorStream.swift
│ │ ├── CompactMapStream.swift
│ │ ├── CompleteOnErrorStream.swift
│ │ ├── ConcatenateStream.swift
│ │ ├── DropStream.swift
│ │ ├── DropUntilOutputStream.swift
│ │ ├── DropWhileStream.swift
│ │ ├── EmptyStream.swift
│ │ ├── EnumerateStream.swift
│ │ ├── FilterStream.swift
│ │ ├── FlatMapStream.swift
│ │ ├── FlattenResultStream.swift
│ │ ├── FlattenStream.swift
│ │ ├── ForEachStream.swift
│ │ ├── GenerateStream.swift
│ │ ├── HandleEventsStream.swift
│ │ ├── JoinStream.swift
│ │ ├── JustStream.swift
│ │ ├── LatestStream.swift
│ │ ├── LazyStream.swift
│ │ ├── MapKeyPathStream.swift
│ │ ├── MapResultStream.swift
│ │ ├── MapStream.swift
│ │ ├── MatchEitherStream.swift
│ │ ├── MatchOptionalStream.swift
│ │ ├── MatchResultStream.swift
│ │ ├── MergeAllStream.swift
│ │ ├── MergeStream.swift
│ │ ├── MulticastStream.swift
│ │ ├── NeverStream.swift
│ │ ├── OptionalStream.swift
│ │ ├── OutputStream.swift
│ │ ├── PollOnStream.swift
│ │ ├── PrefixStream.swift
│ │ ├── PrefixUntilOutputStream.swift
│ │ ├── PrefixWhileStream.swift
│ │ ├── PrintStream.swift
│ │ ├── ReferenceStream.swift
│ │ ├── RemoveDuplicatesStream.swift
│ │ ├── RepeatStream.swift
│ │ ├── ReplaceEmptyStream.swift
│ │ ├── ReplaceErrorStream.swift
│ │ ├── ScanStream.swift
│ │ ├── SequenceStream.swift
│ │ ├── SetFailureTypeStream.swift
│ │ ├── ShareStream.swift
│ │ ├── StreamAllSatisfyFuture.swift
│ │ ├── StreamContainsFuture.swift
│ │ ├── StreamContainsWhereFuture.swift
│ │ ├── StreamFirstFuture.swift
│ │ ├── StreamFirstWhereFuture.swift
│ │ ├── StreamForwardFuture.swift
│ │ ├── StreamFuture.swift
│ │ ├── StreamIgnoreOutputFuture.swift
│ │ ├── StreamLastFuture.swift
│ │ ├── StreamLastWhereFuture.swift
│ │ ├── StreamReduceFuture.swift
│ │ ├── StreamReduceIntoFuture.swift
│ │ ├── StreamReplayBuffer.swift
│ │ ├── SwitchToLatestStream.swift
│ │ ├── TryMapStream.swift
│ │ ├── UnfoldStream.swift
│ │ ├── YieldStream.swift
│ │ └── ZipStream.swift
│ ├── Task.swift
│ └── Waker.swift
├── FuturesPrivate
│ ├── Private.c
│ └── include
│ │ ├── CAtomic.h
│ │ └── FuturesPrivate.h
├── FuturesSync
│ ├── Atomic.swift
│ ├── Atomic
│ │ ├── AtomicBitset.swift
│ │ ├── AtomicBitset.swift.gyb
│ │ ├── AtomicEnum.swift
│ │ ├── AtomicEnum.swift.gyb
│ │ ├── AtomicPointer.swift
│ │ ├── AtomicPointer.swift.gyb
│ │ ├── AtomicReference.swift
│ │ ├── AtomicValue.swift
│ │ └── AtomicValue.swift.gyb
│ ├── AtomicQueue.swift
│ ├── AtomicQueue
│ │ ├── AtomicBuffer.swift
│ │ ├── AtomicList.swift
│ │ ├── AtomicMPMCQueue.swift
│ │ ├── AtomicMPSCQueue.swift
│ │ ├── AtomicSPMCQueue.swift
│ │ ├── AtomicSPSCQueue.swift
│ │ ├── AtomicUnboundedMPSCQueue.swift
│ │ └── AtomicUnboundedSPSCQueue.swift
│ ├── Backoff.swift
│ ├── Locking.swift
│ ├── Locking
│ │ ├── PosixConditionLock.swift
│ │ ├── PosixLock.swift
│ │ ├── SpinLock.swift
│ │ └── UnfairLock.swift
│ ├── Mutex.swift
│ ├── Private.swift
│ └── Thread.swift
└── FuturesTestSupport
│ ├── Assert.swift
│ ├── Future.swift
│ ├── Module.swift
│ ├── Stream.swift
│ ├── TestCase.swift
│ └── TestError.swift
└── Tests
├── FuturesSyncTests
├── AtomicQueueTests.swift
├── AtomicReferenceTests.swift
├── AtomicValueTests.swift
├── AtomicValueTests.swift.gyb
└── LockingTests.swift
└── FuturesTests
├── CancellableTests.swift
├── ChannelTests.swift
├── ExecutorTests.swift
├── FutureTests.swift
├── ReadmeTests.swift
└── StreamTests.swift
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | .DS_Store
3 | /.build
4 | /.digests
5 | /.swiftpm
6 | /build
7 | /Carthage
8 | /DerivedData
9 | /docs
10 | /Packages
11 | /xcuserdata
12 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - master
8 | - next
9 |
10 | jobs:
11 | pretest:
12 | name: Check commit
13 | runs-on: macos-latest
14 | steps:
15 | - uses: actions/checkout@v2
16 | - run: brew install swiftformat
17 | - run: brew install swiftlint
18 | - run: make pretest
19 |
20 | xcode:
21 | name: Xcode ${{ matrix.xcode }} / Swift ${{ matrix.swift }}
22 | needs: pretest
23 | runs-on: macos-latest
24 | strategy:
25 | fail-fast: false
26 | matrix:
27 | xcode: ['11.3', '11.4']
28 | include:
29 | - xcode: '11.3'
30 | swift: '5.1'
31 | - xcode: '11.4'
32 | swift: '5.2'
33 | steps:
34 | - uses: actions/checkout@v2
35 | - run: sudo xcode-select -s '/Applications/Xcode_${{ matrix.xcode }}.app'
36 | - run: swift --version
37 | - run: make test
38 |
39 | ubuntu:
40 | name: Ubuntu ${{ matrix.os_version }} / Swift ${{ matrix.swift }}
41 | needs: pretest
42 | runs-on: ubuntu-latest
43 | strategy:
44 | fail-fast: false
45 | matrix:
46 | os: [xenial, bionic]
47 | swift: ['5.1', '5.2']
48 | include:
49 | - os: xenial
50 | os_version: '16.04'
51 | - os: bionic
52 | os_version: '18.04'
53 | - swift: '5.1'
54 | image: 'swift:'
55 | - swift: '5.2'
56 | image: 'swiftlang/swift:nightly-'
57 | container:
58 | image: ${{ matrix.image }}${{ matrix.swift }}-${{ matrix.os }}
59 | steps:
60 | - uses: actions/checkout@v2
61 | - run: swift --version
62 | - run: make test
63 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | release:
5 | types: published
6 |
7 | jobs:
8 | docs:
9 | name: Documentation
10 | runs-on: macos-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | with:
14 | token: ${{ secrets.PUSH_TOKEN }}
15 | - run: sudo gem install --no-document jazzy
16 | - run: make docs
17 | env:
18 | CI: 'true'
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /*.xcodeproj
3 | /.build
4 | /.digests
5 | /.swiftpm
6 | /build
7 | /Carthage
8 | /DerivedData
9 | /docs
10 | /Packages
11 | /xcuserdata
12 |
--------------------------------------------------------------------------------
/.swiftformat:
--------------------------------------------------------------------------------
1 | --swiftversion 5.0
2 | --allman false
3 | --decimalgrouping 3,4
4 | --exclude Package.swift
5 | --ifdef no-indent
6 | --indent 4
7 | --patternlet inline
8 | --nospaceoperators
9 | --self remove
10 | --selfrequired
11 | --wraparguments before-first
12 | --wrapcollections before-first
13 | --header \n {file}\n Futures\n\n Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.\n
14 | --rules andOperator,anyObjectProtocol,blankLinesAroundMark,blankLinesAtEndOfScope,blankLinesAtStartOfScope,blankLinesBetweenScopes,braces,consecutiveBlankLines,consecutiveSpaces,duplicateImports,elseOnSameLine,emptyBraces,fileHeader,hoistPatternLet,indent,leadingDelimiters,linebreakAtEndOfFile,linebreaks,numberFormatting,redundantBreak,redundantExtensionACL,redundantFileprivate,redundantGet,redundantInit,redundantLet,redundantLetError,redundantNilInit,redundantObjc,redundantParens,redundantPattern,redundantRawValues,redundantSelf,redundantVoidReturnType,semicolons,sortedImports,spaceAroundBraces,spaceAroundBrackets,spaceAroundComments,spaceAroundGenerics,spaceAroundParens,spaceInsideBraces,spaceInsideBrackets,spaceInsideComments,spaceInsideGenerics,spaceInsideParens,strongOutlets,strongifiedSelf,todos,trailingClosures,trailingCommas,trailingSpace,typeSugar,unusedArguments,void,wrapArguments,yodaConditions
15 |
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | excluded:
2 | - .build/
3 | - Tests/LinuxMain.swift
4 |
5 | disabled_rules:
6 | - empty_count
7 | - file_length
8 | - function_body_length
9 | - identifier_name
10 | - line_length
11 | - todo
12 | - type_body_length
13 |
14 | opt_in_rules:
15 | - anyobject_protocol
16 | - closure_end_indentation
17 | - closure_spacing
18 | - collection_alignment
19 | - contains_over_first_not_nil
20 | - convenience_type
21 | - empty_string
22 | - empty_xctest_method
23 | - explicit_init
24 | - fallthrough
25 | - fatal_error_message
26 | - first_where
27 | - force_unwrapping
28 | - identical_operands
29 | - implicitly_unwrapped_optional
30 | - joined_default_parameter
31 | - let_var_whitespace
32 | - last_where
33 | - literal_expression_end_indentation
34 | - modifier_order
35 | - multiline_function_chains
36 | - multiline_literal_brackets
37 | - multiline_parameters
38 | - multiline_parameters_brackets
39 | - nimble_operator
40 | - number_separator
41 | - object_literal
42 | - operator_usage_whitespace
43 | - overridden_super_call
44 | - override_in_extension
45 | - private_action
46 | - private_outlet
47 | - prohibited_interface_builder
48 | - prohibited_super_call
49 | - quick_discouraged_call
50 | - quick_discouraged_focused_test
51 | - quick_discouraged_pending_test
52 | - redundant_nil_coalescing
53 | - redundant_type_annotation
54 | - sorted_first_last
55 | - sorted_imports
56 | - static_operator
57 | - switch_case_on_newline
58 | - unavailable_function
59 | - unneeded_parentheses_in_closure_argument
60 | - untyped_error_in_catch
61 | - unused_declaration
62 | - unused_import
63 | - vertical_whitespace_closing_braces
64 | - vertical_whitespace_opening_braces
65 | - xct_specific_matcher
66 | - yoda_condition # sic
67 |
68 | cyclomatic_complexity:
69 | ignores_case_statements: true
70 |
71 | large_tuple:
72 | warning: 4
73 | error: 5
74 |
75 | modifier_order:
76 | preferred_modifier_order: [
77 | acl, setterACL, final, override, dynamic, mutators, lazy, required, convenience, typeMethods, owned
78 | ]
79 |
80 | nesting:
81 | type_level: 3
82 |
83 | trailing_comma:
84 | mandatory_comma: true
85 |
86 | type_name:
87 | min_length: 1
88 | validates_start_with_lowercase: false
89 | allowed_symbols:
90 | - '_'
91 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG TOOLCHAIN
2 | FROM $TOOLCHAIN
3 | VOLUME ["/src"]
4 | WORKDIR /src
5 | RUN /usr/bin/swift --version
6 | ENTRYPOINT ["/usr/bin/swift"]
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019, Akis Kesoglou
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a
4 | copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included
12 | in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "Futures",
7 | platforms: [
8 | .macOS(.v10_12),
9 | .iOS(.v10),
10 | .tvOS(.v10),
11 | .watchOS(.v3),
12 | ],
13 | products: [
14 | // Primitives for asynchronous programming; futures, streams, channels.
15 | .library(name: "Futures", targets: ["Futures"]),
16 |
17 | // Primitives for thread synchronization; atomics, queues, locks.
18 | .library(name: "FuturesSync", targets: ["FuturesSync"]),
19 | ],
20 | targets: [
21 | .target(
22 | name: "Futures",
23 | dependencies: [
24 | "FuturesSync",
25 | ]
26 | ),
27 | .target(
28 | name: "FuturesSync",
29 | dependencies: [
30 | "FuturesPrivate",
31 | ]
32 | ),
33 | .target(
34 | name: "FuturesPrivate",
35 | dependencies: []
36 | ),
37 | .target(
38 | name: "FuturesTestSupport",
39 | dependencies: [
40 | "Futures",
41 | "FuturesSync",
42 | ]
43 | ),
44 |
45 | .testTarget(
46 | name: "FuturesTests",
47 | dependencies: [
48 | "Futures",
49 | "FuturesTestSupport",
50 | ]
51 | ),
52 | .testTarget(
53 | name: "FuturesSyncTests",
54 | dependencies: [
55 | "FuturesSync",
56 | "FuturesTestSupport",
57 | ]
58 | ),
59 | ]
60 | )
61 |
--------------------------------------------------------------------------------
/Scripts/ensure-pristine.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | set -e
4 |
5 | if test -n "$(git status -z --porcelain)"; then
6 | echo 'ERROR: Found uncommitted changes and/or untracked files.'
7 | echo ' Run `make precommit` in your working directory, commit'
8 | echo ' the changes and push again.'
9 | echo ''
10 | git status -s
11 | exit 1
12 | fi
13 |
--------------------------------------------------------------------------------
/Scripts/make-docs.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | # Much of this is an adaptation of the corresponding script in swift-nio:
4 | # https://github.com/apple/swift-nio
5 | # ============================================================================
6 |
7 | set -e
8 |
9 | MODULES=(Futures FuturesSync)
10 |
11 | REPO_SLUG=dfunckt/swift-futures
12 | REPO_URL=https://github.com/${REPO_SLUG}
13 | BASE_URL=https://dfunckt.github.io/swift-futures
14 | OUTPUT_DIR="docs/"
15 |
16 | VERSION=$(git describe --exact-match --abbrev=0 --tags || git rev-parse --abbrev-ref HEAD)
17 | echo "Building docs for version '${VERSION}'"
18 |
19 | JAZZY_ARGS=(
20 | --config .jazzy.yml
21 | --github_url "${REPO_URL}"
22 | --github-file-prefix "${REPO_URL}/tree/${VERSION}"
23 | --xcodebuild-arguments USE_SWIFT_RESPONSE_FILE=NO
24 | )
25 |
26 | make_module_readme() {
27 | local readme_path="$1"
28 | cat > "${readme_path}" <<"EOF"
29 | # Futures
30 |
31 | Futures comprises several modules:
32 |
33 | EOF
34 | for m in "${MODULES[@]}"; do
35 | echo "- [${m}](../${m}/index.html)" >>"${readme_path}"
36 | done
37 | }
38 |
39 | make_module_docs() {
40 | local module="$1"
41 | local module_readme="$2"
42 | args=(
43 | "${JAZZY_ARGS[@]}"
44 | --module "${module}"
45 | --module-version "${VERSION}"
46 | --title "${module} Reference (${VERSION})"
47 | --readme "${module_readme}"
48 | --root-url "${BASE_URL}/${OUTPUT_DIR}${VERSION}/${module}"
49 | --output "${OUTPUT_DIR}${VERSION}/${module}/"
50 | )
51 | jazzy "${args[@]}"
52 | }
53 |
54 | publish() {
55 | local branch_name=$(git rev-parse --abbrev-ref HEAD)
56 | local git_author=$(git --no-pager show -s --format='%an <%ae>' HEAD)
57 |
58 | git fetch --depth=1 origin +gh-pages:gh-pages
59 | git checkout gh-pages
60 |
61 | rm -rf "${OUTPUT_DIR}latest"
62 | cp -r "${OUTPUT_DIR}${VERSION}" "${OUTPUT_DIR}latest"
63 |
64 | git add --all "${OUTPUT_DIR}"
65 |
66 | local latest_url="${OUTPUT_DIR}${VERSION}/Futures/index.html"
67 | echo '
' >index.html
68 | git add index.html
69 |
70 | touch .nojekyll
71 | git add .nojekyll
72 |
73 | local changes=$(git diff-index --name-only HEAD)
74 | if test -n "$changes"; then
75 | git commit --author="${git_author}" -m "Publish API reference for ${VERSION}"
76 | git push origin gh-pages
77 | else
78 | echo "no changes detected"
79 | fi
80 |
81 | git checkout -f "${branch_name}"
82 | }
83 |
84 | mkdir -p "${OUTPUT_DIR}${VERSION}"
85 |
86 | for module in "${MODULES[@]}"; do
87 | readme="${OUTPUT_DIR}${VERSION}/${module}.md"
88 | make_module_readme "$readme"
89 | make_module_docs "$module" "$readme"
90 | done
91 |
92 | if test $CI = true; then
93 | publish
94 | fi
95 |
--------------------------------------------------------------------------------
/Sources/Futures/Channel/ChannelMPSCBufferBounded.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelMPSCBufferBounded.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | import FuturesSync
9 |
10 | extension Channel._Private {
11 | public struct MPSCBufferBounded- : _ChannelBufferImplProtocol {
12 | @usableFromInline let _buffer: AtomicMPSCQueue
-
13 |
14 | @inlinable
15 | init(capacity: Int) {
16 | _buffer = .init(capacity: capacity)
17 | }
18 |
19 | @inlinable
20 | public static var isPassthrough: Bool {
21 | return false
22 | }
23 |
24 | @inlinable
25 | public static var isBounded: Bool {
26 | return true
27 | }
28 |
29 | @inlinable
30 | public var capacity: Int {
31 | return _buffer.capacity
32 | }
33 |
34 | @inlinable
35 | public func push(_ item: Item) {
36 | let result = _buffer.tryPush(item)
37 | assert(result, "expected push to succeed, but buffer is at capacity")
38 | }
39 |
40 | @inlinable
41 | public func pop() -> Item? {
42 | return _buffer.pop()
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/Futures/Channel/ChannelMPSCBufferUnbounded.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelMPSCBufferUnbounded.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | import FuturesSync
9 |
10 | extension Channel._Private {
11 | public struct MPSCBufferUnbounded
- : _ChannelBufferImplProtocol {
12 | @usableFromInline let _buffer = AtomicUnboundedMPSCQueue
- ()
13 |
14 | @inlinable
15 | init() {}
16 |
17 | @inlinable
18 | public static var isPassthrough: Bool {
19 | return false
20 | }
21 |
22 | @inlinable
23 | public static var isBounded: Bool {
24 | return false
25 | }
26 |
27 | @inlinable
28 | public var capacity: Int {
29 | return Int.max
30 | }
31 |
32 | @inlinable
33 | public func push(_ item: Item) {
34 | _buffer.push(item)
35 | }
36 |
37 | @inlinable
38 | public func pop() -> Item? {
39 | return _buffer.pop()
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/Futures/Channel/ChannelMPSCPark.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelMPSCPark.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | import FuturesSync
9 |
10 | extension Channel._Private {
11 | public struct MPSCPark: _ChannelParkImplProtocol {
12 | @usableFromInline let _wakers = AtomicWakerQueue()
13 | @usableFromInline let _wakersFlush = AtomicWakerQueue()
14 |
15 | @inlinable
16 | init() {}
17 |
18 | @inlinable
19 | public func park(_ waker: WakerProtocol) -> Cancellable {
20 | _wakers.push(waker)
21 | }
22 |
23 | @inlinable
24 | public func notifyOne() {
25 | _wakers.signal()
26 | }
27 |
28 | @inlinable
29 | public func notifyAll() {
30 | _wakers.broadcast()
31 | }
32 |
33 | @inlinable
34 | public func parkFlush(_ waker: WakerProtocol) -> Cancellable {
35 | _wakersFlush.push(waker)
36 | }
37 |
38 | @inlinable
39 | public func notifyFlush() {
40 | _wakersFlush.broadcast()
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/Futures/Channel/ChannelSPSCBufferBounded.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelSPSCBufferBounded.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | import FuturesSync
9 |
10 | extension Channel._Private {
11 | public struct SPSCBufferBounded
- : _ChannelBufferImplProtocol {
12 | @usableFromInline let _buffer: AtomicSPSCQueue
-
13 |
14 | @inlinable
15 | init(capacity: Int) {
16 | _buffer = .init(capacity: capacity)
17 | }
18 |
19 | @inlinable
20 | public static var isPassthrough: Bool {
21 | return false
22 | }
23 |
24 | @inlinable
25 | public static var isBounded: Bool {
26 | return true
27 | }
28 |
29 | @inlinable
30 | public var capacity: Int {
31 | return _buffer.capacity
32 | }
33 |
34 | @inlinable
35 | public func push(_ item: Item) {
36 | let result = _buffer.tryPush(item)
37 | assert(result, "expected push to succeed, but buffer is at capacity")
38 | }
39 |
40 | @inlinable
41 | public func pop() -> Item? {
42 | return _buffer.pop()
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/Futures/Channel/ChannelSPSCBufferUnbounded.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelSPSCBufferUnbounded.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | import FuturesSync
9 |
10 | extension Channel._Private {
11 | public struct SPSCBufferUnbounded
- : _ChannelBufferImplProtocol {
12 | @usableFromInline let _buffer = AtomicUnboundedSPSCQueue
- ()
13 |
14 | @inlinable
15 | init() {}
16 |
17 | @inlinable
18 | public static var isPassthrough: Bool {
19 | return false
20 | }
21 |
22 | @inlinable
23 | public static var isBounded: Bool {
24 | return false
25 | }
26 |
27 | @inlinable
28 | public var capacity: Int {
29 | return Int.max
30 | }
31 |
32 | @inlinable
33 | public func push(_ item: Item) {
34 | _buffer.push(item)
35 | }
36 |
37 | @inlinable
38 | public func pop() -> Item? {
39 | return _buffer.pop()
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/Futures/Channel/ChannelSPSCPark.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelSPSCPark.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | extension Channel._Private {
9 | public struct SPSCPark: _ChannelParkImplProtocol {
10 | @usableFromInline
11 | struct Waker {
12 | @usableFromInline let _waker: AtomicWaker
13 |
14 | @inlinable
15 | init(_ waker: AtomicWaker) {
16 | _waker = waker
17 | }
18 | }
19 |
20 | @usableFromInline let _waker = AtomicWaker()
21 |
22 | @inlinable
23 | init() {}
24 |
25 | @inlinable
26 | public func park(_ waker: WakerProtocol) -> Cancellable {
27 | _waker.register(waker)
28 | return Waker(_waker)
29 | }
30 |
31 | @inlinable
32 | public func notifyOne() {
33 | _waker.signal()
34 | }
35 |
36 | @inlinable
37 | public func notifyAll() {
38 | _waker.signal()
39 | }
40 |
41 | @inlinable
42 | public func parkFlush(_ waker: WakerProtocol) -> Cancellable {
43 | _waker.register(waker)
44 | return Waker(_waker)
45 | }
46 |
47 | @inlinable
48 | public func notifyFlush() {
49 | _waker.signal()
50 | }
51 | }
52 | }
53 |
54 | extension Channel._Private.SPSCPark.Waker: Cancellable {
55 | @inlinable
56 | func cancel() {
57 | _waker.clear()
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Sources/Futures/Channel/ChannelSlotBounded.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelSlotBounded.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | import FuturesSync
9 |
10 | extension Channel._Private {
11 | public struct SlotBounded
- : _ChannelBufferImplProtocol {
12 | @usableFromInline let _element = Mutex(Item?.none)
13 |
14 | @inlinable
15 | init() {}
16 |
17 | @inlinable
18 | public static var isPassthrough: Bool {
19 | return false
20 | }
21 |
22 | @inlinable
23 | public static var isBounded: Bool {
24 | return true
25 | }
26 |
27 | @inlinable
28 | public var capacity: Int {
29 | return 1
30 | }
31 |
32 | @inlinable
33 | public func push(_ item: Item) {
34 | _element.value = item
35 | }
36 |
37 | @inlinable
38 | public func pop() -> Item? {
39 | return _element.move()
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/Futures/Channel/ChannelSlotUnbounded.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChannelSlotUnbounded.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | import FuturesSync
9 |
10 | extension Channel._Private {
11 | public struct SlotUnbounded
- : _ChannelBufferImplProtocol {
12 | @usableFromInline let _element = Mutex(Item?.none)
13 |
14 | @inlinable
15 | init() {}
16 |
17 | @inlinable
18 | public static var isPassthrough: Bool {
19 | return true
20 | }
21 |
22 | @inlinable
23 | public static var isBounded: Bool {
24 | return false
25 | }
26 |
27 | @inlinable
28 | public var capacity: Int {
29 | return 1
30 | }
31 |
32 | @inlinable
33 | public func push(_ item: Item) {
34 | _element.value = item
35 | }
36 |
37 | @inlinable
38 | public func pop() -> Item? {
39 | return _element.move()
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/Futures/Context.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Context.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | import FuturesSync
9 |
10 | public struct Context {
11 | @usableFromInline let _runner: _TaskRunner
12 | @usableFromInline let _waker: WakerProtocol
13 |
14 | @inlinable
15 | init(runner: _TaskRunner, waker: WakerProtocol) {
16 | _runner = runner
17 | _waker = waker
18 | }
19 |
20 | @inlinable
21 | public var waker: WakerProtocol {
22 | return _waker
23 | }
24 |
25 | @inlinable
26 | public func withWaker(_ newWaker: WakerProtocol) -> Context {
27 | return .init(runner: _runner, waker: newWaker)
28 | }
29 |
30 | @inlinable
31 | public func submit(_ future: F) where F.Output == Void {
32 | _runner.schedule(future)
33 | }
34 |
35 | @inlinable
36 | public func spawn(_ future: F) -> Task {
37 | return Task.create(future: future, runner: _runner)
38 | }
39 |
40 | @inlinable
41 | public func yield() -> Poll {
42 | _waker.signal()
43 | // yielding a task is a form of spinning,
44 | // so give other threads a chance as well.
45 | Atomic.preemptionYield(0)
46 | return .pending
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Sources/Futures/Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | extension Swift.Sequence {
9 | @inlinable
10 | public func makeStream() -> Stream._Private.Sequence {
11 | return .init(sequence: self)
12 | }
13 | }
14 |
15 | extension Swift.Array: StreamConvertible {}
16 | extension Swift.ContiguousArray: StreamConvertible {}
17 | extension Swift.Set: StreamConvertible {}
18 | extension Swift.Dictionary: StreamConvertible {}
19 |
--------------------------------------------------------------------------------
/Sources/Futures/Future/AbortFuture.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AbortFuture.swift
3 | // Futures
4 | //
5 | // Copyright © 2019 Akis Kesoglou. Licensed under the MIT license.
6 | //
7 |
8 | extension Future._Private {
9 | public enum Abort where U.FutureType.Output == Void {
10 | public typealias Signal = () -> U
11 |
12 | case pending(Base, Signal)
13 | case polling(Base, U.FutureType)
14 | case done
15 |
16 | @inlinable
17 | public init(base: Base, signal: @escaping Signal) {
18 | self = .pending(base, signal)
19 | }
20 | }
21 | }
22 |
23 | extension Future._Private.Abort: FutureProtocol {
24 | public typealias Output = Base.Output?
25 |
26 | @inlinable
27 | public mutating func poll(_ context: inout Context) -> Poll