From 41e4d600948513030f72a079ca00d68e6c1fdf0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Olejni=CC=81k?= Date: Thu, 8 Aug 2019 15:36:30 +0200 Subject: [PATCH 1/4] Add ReactiveSwift tests --- Podfile | 1 + Podfile.lock | 17 +- .../Local Podspecs/ReactiveSwift.podspec.json | 33 + Pods/Manifest.lock | 17 +- Pods/Pods.xcodeproj/project.pbxproj | 1827 +++++----- .../xcschemes/Pods-SpeedTestTests.xcscheme | 58 + .../xcschemes/ReactiveSwift.xcscheme | 60 + .../xcschemes/RxSwift.xcscheme | 60 + .../xcschemes/xcschememanagement.plist | 26 + Pods/ReactiveSwift/LICENSE.md | 19 + Pods/ReactiveSwift/README.md | 157 + Pods/ReactiveSwift/Sources/Action.swift | 375 +++ Pods/ReactiveSwift/Sources/Atomic.swift | 283 ++ Pods/ReactiveSwift/Sources/Bag.swift | 99 + .../Sources/Deprecations+Removals.swift | 16 + Pods/ReactiveSwift/Sources/Disposable.swift | 380 +++ Pods/ReactiveSwift/Sources/Event.swift | 1037 ++++++ Pods/ReactiveSwift/Sources/EventLogger.swift | 174 + Pods/ReactiveSwift/Sources/Flatten.swift | 1132 +++++++ .../Sources/FoundationExtensions.swift | 136 + Pods/ReactiveSwift/Sources/Lifetime.swift | 114 + Pods/ReactiveSwift/Sources/Observer.swift | 133 + Pods/ReactiveSwift/Sources/Optional.swift | 42 + Pods/ReactiveSwift/Sources/Property.swift | 808 +++++ Pods/ReactiveSwift/Sources/Reactive.swift | 33 + .../Sources/ResultExtensions.swift | 44 + Pods/ReactiveSwift/Sources/Scheduler.swift | 613 ++++ Pods/ReactiveSwift/Sources/Signal.swift | 2279 +++++++++++++ .../Sources/SignalProducer.swift | 2956 +++++++++++++++++ .../Sources/UnidirectionalBinding.swift | 190 ++ .../Sources/UninhabitedTypeGuards.swift | 146 + .../Sources/ValidatingProperty.swift | 325 ++ ...s-SpeedTestTests-acknowledgements.markdown | 23 + ...Pods-SpeedTestTests-acknowledgements.plist | 29 + ...ts-frameworks-Debug-input-files.xcfilelist | 1 + ...s-frameworks-Debug-output-files.xcfilelist | 1 + ...-frameworks-Release-input-files.xcfilelist | 1 + ...frameworks-Release-output-files.xcfilelist | 1 + .../Pods-SpeedTestTests-frameworks.sh | 4 +- .../Pods-SpeedTestTests.debug.xcconfig | 8 +- .../Pods-SpeedTestTests.release.xcconfig | 8 +- .../ReactiveSwift/ReactiveSwift-Info.plist | 26 + .../ReactiveSwift/ReactiveSwift-dummy.m | 5 + .../ReactiveSwift/ReactiveSwift-prefix.pch | 12 + .../ReactiveSwift/ReactiveSwift-umbrella.h | 16 + .../ReactiveSwift/ReactiveSwift.modulemap | 6 + .../ReactiveSwift/ReactiveSwift.xcconfig | 10 + SpeedTest.xcodeproj/project.pbxproj | 6 +- .../xcschemes/xcschememanagement.plist | 14 + .../UserInterfaceState.xcuserstate | Bin 0 -> 19603 bytes SpeedTestTests/ReactiveSwiftTests.swift | 308 ++ 51 files changed, 13273 insertions(+), 796 deletions(-) create mode 100644 Pods/Local Podspecs/ReactiveSwift.podspec.json create mode 100644 Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/Pods-SpeedTestTests.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/ReactiveSwift.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/RxSwift.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Pods/ReactiveSwift/LICENSE.md create mode 100644 Pods/ReactiveSwift/README.md create mode 100644 Pods/ReactiveSwift/Sources/Action.swift create mode 100644 Pods/ReactiveSwift/Sources/Atomic.swift create mode 100644 Pods/ReactiveSwift/Sources/Bag.swift create mode 100644 Pods/ReactiveSwift/Sources/Deprecations+Removals.swift create mode 100644 Pods/ReactiveSwift/Sources/Disposable.swift create mode 100644 Pods/ReactiveSwift/Sources/Event.swift create mode 100644 Pods/ReactiveSwift/Sources/EventLogger.swift create mode 100644 Pods/ReactiveSwift/Sources/Flatten.swift create mode 100644 Pods/ReactiveSwift/Sources/FoundationExtensions.swift create mode 100644 Pods/ReactiveSwift/Sources/Lifetime.swift create mode 100644 Pods/ReactiveSwift/Sources/Observer.swift create mode 100644 Pods/ReactiveSwift/Sources/Optional.swift create mode 100644 Pods/ReactiveSwift/Sources/Property.swift create mode 100644 Pods/ReactiveSwift/Sources/Reactive.swift create mode 100644 Pods/ReactiveSwift/Sources/ResultExtensions.swift create mode 100644 Pods/ReactiveSwift/Sources/Scheduler.swift create mode 100644 Pods/ReactiveSwift/Sources/Signal.swift create mode 100644 Pods/ReactiveSwift/Sources/SignalProducer.swift create mode 100644 Pods/ReactiveSwift/Sources/UnidirectionalBinding.swift create mode 100644 Pods/ReactiveSwift/Sources/UninhabitedTypeGuards.swift create mode 100644 Pods/ReactiveSwift/Sources/ValidatingProperty.swift create mode 100644 Pods/Target Support Files/ReactiveSwift/ReactiveSwift-Info.plist create mode 100644 Pods/Target Support Files/ReactiveSwift/ReactiveSwift-dummy.m create mode 100644 Pods/Target Support Files/ReactiveSwift/ReactiveSwift-prefix.pch create mode 100644 Pods/Target Support Files/ReactiveSwift/ReactiveSwift-umbrella.h create mode 100644 Pods/Target Support Files/ReactiveSwift/ReactiveSwift.modulemap create mode 100644 Pods/Target Support Files/ReactiveSwift/ReactiveSwift.xcconfig create mode 100644 SpeedTest.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 SpeedTest.xcworkspace/xcuserdata/olejnjak.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 SpeedTestTests/ReactiveSwiftTests.swift diff --git a/Podfile b/Podfile index c25ac9b..bc24561 100644 --- a/Podfile +++ b/Podfile @@ -8,4 +8,5 @@ use_frameworks! target "SpeedTestTests" do project 'SpeedTest.xcodeproj' pod 'RxSwift', '~> 5.0' +pod 'ReactiveSwift', :git => "https://github.com/ReactiveCocoa/ReactiveSwift.git", :tag => "6.1.0" end diff --git a/Podfile.lock b/Podfile.lock index 6ab23f0..8ea34cf 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,16 +1,29 @@ PODS: + - ReactiveSwift (6.1.0) - RxSwift (5.0.0) DEPENDENCIES: + - ReactiveSwift (from `https://github.com/ReactiveCocoa/ReactiveSwift.git`, tag `6.1.0`) - RxSwift (~> 5.0) SPEC REPOS: https://github.com/cocoapods/specs.git: - RxSwift +EXTERNAL SOURCES: + ReactiveSwift: + :git: https://github.com/ReactiveCocoa/ReactiveSwift.git + :tag: 6.1.0 + +CHECKOUT OPTIONS: + ReactiveSwift: + :git: https://github.com/ReactiveCocoa/ReactiveSwift.git + :tag: 6.1.0 + SPEC CHECKSUMS: + ReactiveSwift: b78c7259f8ca46368238c895ae33a6a3bf9f811c RxSwift: 8b0671caa829a763bbce7271095859121cbd895f -PODFILE CHECKSUM: 5949c781af362f5f03ac55c374eace20756b40d7 +PODFILE CHECKSUM: 4f7b6d260f9fbe88c1ff1f4f9a5f081e9570610c -COCOAPODS: 1.7.0.rc.1 +COCOAPODS: 1.7.5 diff --git a/Pods/Local Podspecs/ReactiveSwift.podspec.json b/Pods/Local Podspecs/ReactiveSwift.podspec.json new file mode 100644 index 0000000..e8f0c66 --- /dev/null +++ b/Pods/Local Podspecs/ReactiveSwift.podspec.json @@ -0,0 +1,33 @@ +{ + "name": "ReactiveSwift", + "version": "6.1.0", + "summary": "Streams of values over time", + "description": "ReactiveSwift is a Swift framework inspired by Functional Reactive Programming. It provides APIs for composing and transforming streams of values over time.", + "homepage": "https://github.com/ReactiveCocoa/ReactiveSwift", + "license": { + "type": "MIT", + "file": "LICENSE.md" + }, + "authors": "ReactiveCocoa", + "platforms": { + "ios": "8.0", + "osx": "10.9", + "watchos": "2.0", + "tvos": "9.0" + }, + "source": { + "git": "https://github.com/ReactiveCocoa/ReactiveSwift.git", + "tag": "6.1.0" + }, + "source_files": "Sources/*.{swift}", + "pod_target_xcconfig": { + "OTHER_SWIFT_FLAGS[config=Release]": "$(inherited) -suppress-warnings" + }, + "cocoapods_version": ">= 1.4.0", + "swift_versions": [ + "5.0", + "5.1", + "5.1" + ], + "swift_version": "5.1" +} diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index 6ab23f0..8ea34cf 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -1,16 +1,29 @@ PODS: + - ReactiveSwift (6.1.0) - RxSwift (5.0.0) DEPENDENCIES: + - ReactiveSwift (from `https://github.com/ReactiveCocoa/ReactiveSwift.git`, tag `6.1.0`) - RxSwift (~> 5.0) SPEC REPOS: https://github.com/cocoapods/specs.git: - RxSwift +EXTERNAL SOURCES: + ReactiveSwift: + :git: https://github.com/ReactiveCocoa/ReactiveSwift.git + :tag: 6.1.0 + +CHECKOUT OPTIONS: + ReactiveSwift: + :git: https://github.com/ReactiveCocoa/ReactiveSwift.git + :tag: 6.1.0 + SPEC CHECKSUMS: + ReactiveSwift: b78c7259f8ca46368238c895ae33a6a3bf9f811c RxSwift: 8b0671caa829a763bbce7271095859121cbd895f -PODFILE CHECKSUM: 5949c781af362f5f03ac55c374eace20756b40d7 +PODFILE CHECKSUM: 4f7b6d260f9fbe88c1ff1f4f9a5f081e9570610c -COCOAPODS: 1.7.0.rc.1 +COCOAPODS: 1.7.5 diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj index da380cf..b2ea28c 100644 --- a/Pods/Pods.xcodeproj/project.pbxproj +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -7,167 +7,198 @@ objects = { /* Begin PBXBuildFile section */ - 02A949CB014B6A490CD9C0EBD8B9F3DF /* Amb.swift in Sources */ = {isa = PBXBuildFile; fileRef = E49710A6B497C193740AF6A425589D07 /* Amb.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 02FD4ADA12298BDF172AD1ED60F93522 /* ScheduledItemType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5617CC15404DAF3805EB0070B19BC157 /* ScheduledItemType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 0302AB35D61D7CC16621DE3EB9E5C4ED /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FFCE1932228F377D03BCC121EDF4434 /* SynchronizedOnType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 05D7FABB08C6666A7D63234D68E602F2 /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9757333012BF772F4247DF841ED7935 /* PrimitiveSequence+Zip+arity.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 060B98A5D2D2D7DA32D061E66D1212C5 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47D23DFB0E9DBCD27717F395BD82A96 /* Lock.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 090EC252A320ACCE2E20DBB808A7ADD0 /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9695003960CFCFCAB6973EF2930244D0 /* Disposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 0BD56F15A29CCD0E1CFCF0505CE7E19C /* Zip+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB728D69EE6493BDBE5D071062BB3C6 /* Zip+Collection.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 10D995A6A50A1F4C3D28184B934F6A35 /* AddRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2274A4FABE921F12C377C27E8F92A9F3 /* AddRef.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 169EA35AF6A61349381E0508B61F4D49 /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC501375543E136ADE66E557A92401C9 /* Repeat.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 17722BE03F7B5E5E25D440315A121439 /* ObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71C921D4C61C49477F7D45BF9F0D596A /* ObservableType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 1848D2995C8279FD8E2E6ABF5D841B98 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012D7D176B48342A29FBBF46AFBD0624 /* Zip.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 18F6681A17081BD11CD25B3F20E3C9E3 /* HistoricalScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92286F3AF1F2E2EC69A9FF583722C8D1 /* HistoricalScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 1A9CC2706D139FD5DEFF44C72C934F25 /* Never.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C1C3C1D616B940D3BA19D47FEE9B3B2 /* Never.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 1C120001157EB215BFB8D4A61973864E /* Concat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FFBC6AC68411BAC76597A4912382BC2 /* Concat.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 1C767BF644464DE62BEB5C638C35A27E /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56FF046AD8A4053530C22905A5A7C7D /* CombineLatest+arity.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 1F1988F428A13D6ABD0FE13FCBD89D72 /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F99B771E28A26E71C366754C343D1C /* Multicast.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 1F4685399CB83A36B2530D2E624AF11C /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A77F87BF09F886F0FFE5EE14CDD1BF9 /* Filter.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 20B4327C56941179B54C52A11A791423 /* Do.swift in Sources */ = {isa = PBXBuildFile; fileRef = D493DD6B080AC568B6FA0618686C3D76 /* Do.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 21CF4EA34645F13A88F5E8B95AC29B0A /* Deferred.swift in Sources */ = {isa = PBXBuildFile; fileRef = 167B521463C24DAC8198866F49CB61AD /* Deferred.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 22789593B093B489DAD1D2F8C3289203 /* Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CE9840E02A9CAC89AD1E42B4AF9C55 /* Debug.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 229E4B34FD637F75DE2482DA2CA6574A /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC859AD860BFB0BC7BF8DE756098E271 /* DispatchQueue+Extensions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 23B610152008B94B7D406A7D6BFE044C /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72D303B43AC9702530301C44D37B20E6 /* SkipWhile.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 270678DEE2C346CD4BFF2BC06C2F90FB /* Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D79FAFD822FBEB7CD95E9F70918B6F1 /* Merge.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 2948F7E90A4094D0838042BF406328C7 /* Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A3E9F59FE2E8B99CF1A7161ACD4C312 /* Delay.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 2A1501D58FAD345D7BADD8FE331C5F3B /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7AEFCBAE8882AB113116AC76B8D329 /* CompactMap.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 2B66A5B233A6D99A6872C1893F97EB86 /* InvocableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2AD331471133FE73D9A9360C4D6FD06 /* InvocableType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 2DF88FA76C9EA8D08367DFE180E639F4 /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4CDCFCAC74B4A6BB27AEC4F605B525 /* Dematerialize.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 3021A8AE5959452BD21997CA8C126CD9 /* Scan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474F10EA67A5905D2AF0EDB7D4BF60DE /* Scan.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 306799CEB9E954F70E6B04A4151FDA46 /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F6810A13B1F72B2F10E9B60A055ED2F /* InfiniteSequence.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 31AB4FBDC3146035B7F265F36CE05B61 /* SchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF509447FD82026F923DD5E1C1FB989 /* SchedulerType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 31FB64B52DE94DB2BFA1B17848B268FD /* RxSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 58746BF458A9D6B1B131E43917E1AC73 /* RxSwift-dummy.m */; }; - 3411B2340A79F2F3C098303F1F50EC9B /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C845DF990EACA316A5B424082798634 /* TakeLast.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 36BD1858768BEB09C85016AB17026C22 /* Disposables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D82409C496F92C2FEFC48A70F451BDB1 /* Disposables.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 374218DF6948B2E9514D1E148A6154EF /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7508A87DAD82D00401628ED25840498 /* Queue.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 3781BA60E511450E9A22703DEC854154 /* AsyncSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55806A569FBE99EF1D5EF177F0E55541 /* AsyncSubject.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 37E8DCDE7CA61F0C12D774BA553E9525 /* BehaviorSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5FEAF703A4D3E2E46A3F1554B8C0D5 /* BehaviorSubject.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 3BB80A2F097BFB068E0C7D35E5CD7242 /* SubscribeOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A7E7A407382AF5941B06CE4C7325DF /* SubscribeOn.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 3CFC709C2287A04B80A4B2A6E9D860B7 /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE41578A30310AC2C7F256279DEB314 /* Sequence.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 428BDE4DA26F3137965A07BCDD86CCF5 /* ImmediateSchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 069F01BC4A1392ED2E66E02E6339A8F3 /* ImmediateSchedulerType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 43B16DDB3D5918D5311750AECA0852E2 /* Pods-SpeedTestTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 71617E72E8E69DFB034385FC4AB97CE0 /* Pods-SpeedTestTests-dummy.m */; }; - 44E269AB3B1BBF2746E2CB4479982887 /* RecursiveScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33FD1981C6F35453F660B293D58E3CF7 /* RecursiveScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 4701FB27A2A5F95D589F0352FADA79C0 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = E598BBB34F3194609B47FE65035F38FF /* Event.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 4A3E884CED7CD18AB0AA40E8BE54842C /* ObservableType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E48DDFC33C9573D6329F36C2CC9EF9D3 /* ObservableType+Extensions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 4B655E78A858B92DCBE47A725AE84B60 /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5A0F66C1F84A92178BD9484D19E319A /* ConcurrentMainScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 4B9377FFE5EEC0A597B9D7E46678CF05 /* ShareReplayScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D3D54E33FF3238304C7C9913E792B28 /* ShareReplayScope.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 4E85586A71691C866DE7BBDE8E5A22E9 /* SubjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3CB1DE79E00A059411D7A8112BBA296 /* SubjectType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 4EF994316123FBA40568D0A277A58399 /* ObserveOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7551FC1EB41CFC063B934CDCB82C2E8 /* ObserveOn.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 516D5CE1DDE6304462EE46D97AD5511C /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC870E2DA4EA3A208D6CC128C774774A /* Empty.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5360507BF8FD8E1165527B76D4C3CC89 /* Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08DB7A2C782A192306FF01CCED728618 /* Timeout.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5605F5212A6EA73AB45704A8CD9372BF /* CurrentThreadScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA7DB61CF15B4BA52CBDB3F60C68DBB8 /* CurrentThreadScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5782DCD1477EFC6396F6F45C5E46C033 /* ObservableType+PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16D52A30C471E02F800ADCA71FEA34A2 /* ObservableType+PrimitiveSequence.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 59E474030FA5E9D0CA129A072FF56808 /* AsMaybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E7E771A623979EF95A322F1107FFEB8 /* AsMaybe.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5B1432EFE051CE8542DACB6C881633AF /* DefaultIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEAED7C0CE5E328FBEF2211BB04FC98 /* DefaultIfEmpty.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5C47DE456BA87393E7E4556C3F4A29B8 /* Using.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E3B6350CE7DC6A8D4CA9C97AF58633 /* Using.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5D6BB4D14A7FA4A748405FC7D1E713F7 /* SwitchIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B2B2B7EB6B462C9BAF4D02BB1596B7 /* SwitchIfEmpty.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5EF3D14AABA18971D9CBFD379DEF8342 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19B5A5B86E47172C1EBDAF854330561 /* Throttle.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5EF60FB96CDC276C589470FA1FC05C86 /* ConcurrentDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17214F0A5E8878853A63430D553B610 /* ConcurrentDispatchQueueScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 6061E9C5328EC38DE98F7A9EA26D9082 /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52AAACBB14FE9BD1C035AD7F56B7A438 /* RetryWhen.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 609408A30B183CAEC4C9D3491148FC96 /* String+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DD374AA04E414FE2AE2F74B5AFDC60 /* String+Rx.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 64DD354BAB0986E0E87D9309103F4B63 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DE89160B0C8B1120FD3BE4D5135DFAC /* Bag.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 679344A9097862B6E979AEDE43D54FAD /* SerialDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4732CAC567AB9E6FC2ED425A091B661F /* SerialDispatchQueueScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 68F27AE118E94E70FD2038F64611571E /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93F23F6F42CC3531743DFE2134556E82 /* VirtualTimeConverterType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 6F0D723277FFE043C4FEB54C0E94E3FB /* Reactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CEE237A47CB832B82BE9AB11E02E3BE /* Reactive.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 6FECE751FE85F866EC758404991012C7 /* MainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88A68DAFCA3F86B83387D36FC32E261 /* MainScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 70F573D3C1841C765353F8FED2CF0AC6 /* Sink.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66FDBB09F58822C66816A25FA954182 /* Sink.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 712FD04C67CCDE6F4CA10B6DFF53AE56 /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 878F7DAE257E28A5866FE720753AA0AC /* Cancelable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 71C71ECD882C26578FB10F663A557AA3 /* Pods-SpeedTestTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B9BA4B4DF4B788CF78C4FF5EAA77E3FB /* Pods-SpeedTestTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 73EC147D6B962F7EF427CFE13A4E9FA8 /* ObserverType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1997FB7E29CE3D6373F93A1ABF00097 /* ObserverType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 74F3A0AF31490C4E3932DFED9BE5D689 /* Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70EE902503459EFA68F4E81979BA2222 /* Catch.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 7594B7CE0F85102FA5D9F58B1EBABB71 /* Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E5C36EB3E39AF68E36D08CCDA4C653A /* Rx.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 76EF084E53C3804B1C776CCD67FEB9E3 /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD607973F7533D994C5BAF02DB65BF8E /* Timer.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 78298ADDE86F786E90A8A726473DFDD1 /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7CF663929B98F4C512EE9AE045E2B17 /* ElementAt.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 79FBCB64980B6E4A1338534572CF6D2D /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58552F09308C4BB15C6E3C993A5B03CD /* Switch.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 7D16C62A2053EE65BC360CAC50B29B85 /* DisposeBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 651B56536404EDA63606BAD39BF3AA23 /* DisposeBase.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 7DEF07041653823A4369D23636048D4F /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33497C1B69A3756EC9868E624CEECE4C /* SynchronizedDisposeType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 7EA3C3BFD7B3B35F020DF1EF50C3B00E /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A007B93A08FF145FCED1BCFF259603 /* Platform.Linux.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 7EA69DC18F902601DCD269042537DAE1 /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2BBE46A95AB6C7F71E42E35BA96CD78 /* SwiftSupport.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 834DDAC2BD2B8B5F3EE9083AF9837391 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E3E5057B9A128271581BCCBE98B7275 /* LockOwnerType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 850F7D942640C8F0E58A143E37BECC21 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB4607EFCA7C5F75397649E792E2AFCB /* Foundation.framework */; }; - 85B83B8E6B2850400F1231318FE2CBAA /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376EB75F9B880D9FD1B6F2F45131CBDF /* ConnectableObservableType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 86977C3CB6E1246F6DDE10A8FF8F306E /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7575A0C8D35E860B313DFA0AD7CF4F8 /* Optional.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 87A9A76C34551F9C6C808B11DFDA9245 /* InvocableScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9139B8639FD885639FB93B756DD9B7E8 /* InvocableScheduledItem.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 8C5780DB24F88FED0C99B2DAFCE9A9B0 /* Debounce.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC198B408CE132567385BC58F92959D /* Debounce.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 920387D4074E8839B3D102DD63B45791 /* GroupedObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C231C2128176D458FC8B7DCD727AD97C /* GroupedObservable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 94E59D1A5AF689747AB1EFA5B2A8C6BA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB4607EFCA7C5F75397649E792E2AFCB /* Foundation.framework */; }; - 95583A3AD97E369F924E039C12B58866 /* BinaryDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7B0F7B6582F69152A462C140699234A /* BinaryDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 95B50D34D42473A825CA022A0AB3E3B2 /* DisposeBag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BBDBEF351A55D2369D808A0B910D6B7 /* DisposeBag.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 962A5B803659BBF43DBC1438F5D46D30 /* PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65FC7CD4FFA07D7C5C259EF2B050391 /* PrimitiveSequence.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 96411BE4F9F5F13A1D294F834F345A8C /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A0EED0C095518127F9A305A5070650 /* Deprecated.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 965D0444A70B5EC5F44E5DE8F3526473 /* Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E4EE54B0B8056EACFF23E79FC6FA13B /* Generate.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 976115218A5FE95A07BF0FC60D460850 /* OperationQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D20C0518E27696964A5D7E0A5E2D9BD /* OperationQueueScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 9ABCA5F08F43DC5F05CD094092F75ADE /* AnonymousDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E1B998F98983D222C15C2DA33E99B61 /* AnonymousDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 9F5992C37BFF9D066E2B39990C1D4A79 /* Sample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EAB316B1E600239C78B09CE940E8F9 /* Sample.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A07A2CAFC16448BBCADEBCF3E6AE619B /* GroupBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181F7A0CAFDFC849A468C6C9C50F1C58 /* GroupBy.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A185A17C8B21436DC5BCC73F44BE99B2 /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07299265E8DC2DE35499F40E85D9F81C /* Just.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A303F4252DCDD78AEBC2B994CCB1B340 /* ObserverBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72B4B6D8E329E01070B008308A8C15EE /* ObserverBase.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A383874C9FF5FDF3C50230B7CECE23A4 /* AsSingle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72EF4AC0B5074A2E29B2428B3A7E0ADE /* AsSingle.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A3CFEEC67EEE47CF1287A80CA0EBA3FD /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F82CA826788EB21CAED9AB7A61CB7289 /* RecursiveLock.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A7B1CEE272FA065BCDE192EC13C4E288 /* RefCountDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4DE329BEF1CB87ED4F38CA6ADFD7B9F /* RefCountDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A953B4C58C9C88492C4AAB83AB80A88F /* DistinctUntilChanged.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A66A067BB487D24B58DDE50654AF46 /* DistinctUntilChanged.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - AD3772A208DAAC8FEAA29120D0975004 /* VirtualTimeScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EE4B540DCCB2925913C2EBAF3D9124C /* VirtualTimeScheduler.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - AFA6D34905BB6EC19E2732DDBC2F29C2 /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50232F56C3A7B75C934C7BC82692AF59 /* Enumerated.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B4839D44F447030944349761A03ECCCA /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC889F2478204688AA933DCF4693C636 /* PriorityQueue.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B4DC02636E7D7EC2B3EB90FCAFE646DD /* WithLatestFrom.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAEC2E787170816AAB96CBFA83740657 /* WithLatestFrom.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B4F60F4FBB05BB4651F48A356CA2E412 /* HistoricalSchedulerTimeConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA54B4558300360287F36AB44B39FE4C /* HistoricalSchedulerTimeConverter.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B5405E851BC3EE239BE984881729C5C0 /* DispatchQueueConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16A1D9EAA7F04D2D367D496695C0FCD /* DispatchQueueConfiguration.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B58B19CE594B511CB290A1E7D5F304B0 /* SingleAssignmentDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F6C870393D220B3AF7BFDFDE76E6AA /* SingleAssignmentDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B65A0A1244D1584C3DA8A84F1F4DF644 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BB96FC10EB906309699733BA4835AB6 /* Range.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B67836312A5EB1F580D76D2B22A6E906 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0563003B44EC515724F308FCD3CD8193 /* Observable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B76D304F0849BB5E7C6D46ED75F248FD /* RxMutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB98879951B60465272D8B90E39AC845 /* RxMutableBox.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B92833B4E5BBBFBFB24441D8176A4AEF /* AsyncLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 752F32A59CBBFCAA84277A6D86DCD2CD /* AsyncLock.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B92B3B3CD9A5EFB573B0708E621AECC4 /* Completable+AndThen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E209853647CCABA40FF10E958258341 /* Completable+AndThen.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B952B076B721D7A580F04C7BB0FB854C /* CombineLatest+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B0F97F33E48BB3438584F09E674E10 /* CombineLatest+Collection.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - B98F5BBBB6ABA7F14C61B2064B461D3A /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F00E9F12804718CAA29E7808208EE1 /* Window.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - BA8EC7529065111272A4FA01C11A3D64 /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 769044E4D29F65C4310FC11D40304806 /* Materialize.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - BC5FE46EE548A548B440D070DF24EB04 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E3BFCE0B1839472BF8C261911036EC /* Buffer.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - BCC6DAD730DC025E6E149E732317C59C /* PublishSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181AFF6EE7661E0BD553B973424023DC /* PublishSubject.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - BDED91D633AA1983E5A67B8128E05234 /* AnonymousObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 987D881E9A3A698D1447833FB87334FD /* AnonymousObserver.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - BE094D7ECBF3E53D8F428D0F8D676AEE /* Date+Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EA9BD9058FCE9132A39EEBF8AEF716 /* Date+Dispatch.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - BFAEB6ADC9B47FFE11453CEACE2D62EC /* TakeWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB6F7DE7EB92D46B5A113578044EB90B /* TakeWhile.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C137E2628E1FD659662AB6D16CC95033 /* ScheduledDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE36BD7E39BF9D232A5347DAD9AC32C /* ScheduledDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C23217F0F25980F861EDD5F462B35316 /* Maybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306DE0E6D87978242135F33A6C4D5A1D /* Maybe.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C23CCE94FD722E5A5C162CB200466F83 /* ObservableConvertibleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87BA7F3696D6A4CC74082CA4873A8A96 /* ObservableConvertibleType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C3F119E2B62D5E076C9F556FB70806E6 /* RxSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 07E14D5018327B9D23E609DF824E4E36 /* RxSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C40658C5DCC74AB1C91C5AADDBF4CF28 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F60E23C9CDED9D731140F98B1118425 /* Errors.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C59FC470BE2A3165194188162A71A96E /* CompositeDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48792B925801208B04C1CFF407072A42 /* CompositeDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C5AF3F7093ED5A06BFD5259F4BF86328 /* Completable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCC8DB7E83D31D79474DDEB93766B06F /* Completable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C7BB1A38A77108201F7A5071F16A9511 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9834F595A96BDB23A404BBB215DAB955 /* SkipUntil.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C9427DD70225FCCF56DE65166319A44D /* TakeUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7999131F2F79B776A2951B564923046F /* TakeUntil.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - CAE248D10EF6E99863D18FB9906ED3B6 /* ScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663E825CA6C7EADB658061705B9A6CB3 /* ScheduledItem.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - CD07FAC8B8C8650E384D95F7AD270048 /* ToArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90610A4859390D4BC2483853E6A3AE85 /* ToArray.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D219A4016E471D45195458719AEC9D3B /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA469C34D0EF836534B9EEB63B256DC4 /* SubscriptionDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D4AA3FB82F427707196ED9AF3050315F /* CombineLatest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A787BC2076D63A7ACFD626D1DE5A9EC /* CombineLatest.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D6B675670B8BD1F9E317CFA2471EE6E7 /* Single.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47069C123FA0ACB2DCBE886D7B3BC1 /* Single.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D87AFA7FF659C0FF9432929C2951CD97 /* SingleAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BB07C02339DCC64F774319E1496DA6D /* SingleAsync.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D93B3464EDF3046FAE88CD740FB41D5A /* Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C122750E8C0F3A45FD8E0DBDFDC8F9 /* Create.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D9821D4C4A8BCBAD2F381238AF1970E1 /* Take.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2278F7BA462362D40764DC52273D2382 /* Take.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D9B77BADB41468BE70DAC25803050054 /* Bag+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = E975D5A109D443919A2684C7C1A0AF76 /* Bag+Rx.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D9B90A747F561F5809B1B13398623180 /* AtomicInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A45279A2F183B85BDD344D764EBE13 /* AtomicInt.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D9BA913218F72D08C2032D489C8AC002 /* BooleanDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB28BF72935934FB28144A700AB0054 /* BooleanDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - DA77A2BE647B59AC47FF50C84E4AAE18 /* SchedulerServices+Emulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E9FB2FDCD209FC08E7D6E73BC5CE8C /* SchedulerServices+Emulation.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - DCFEE5F9795EC2120A29EA202D26699B /* Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65E171AC22F631D21200DB4EBE231AB /* Reduce.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - DDE4C3A200978199BB6DB8D72C990983 /* SerialDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D7D076BF1319E12D146579A1E3AA47 /* SerialDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - DDEAF8D022C1F849C353332547A8F5EF /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E4173F63456BB3C1FE17283F5FCBB21 /* SynchronizedUnsubscribeType.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - DE488CB06623208D0CD63FEC39E28675 /* Skip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C9640FFD356546806E100F45E8A44FB /* Skip.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - DFF994904AEC19EC8861E3233FBB1FA2 /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 594376167C7F58F7C62FAB5F552C508D /* Platform.Darwin.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - E4128B12254F47FEE2E915BC828BB680 /* AnyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F313DE547D913B19C56B7820225BA20 /* AnyObserver.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - EAA4CF152ADD14DD714C9210C4272BF7 /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3288AFCEC296C92324275DCD605E92F7 /* Producer.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - EF046775B5834F37554BCEAA84A72CD5 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC232B350290EEFAF1C80C342AC435EB /* Error.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - EF911DC502F4EBBC602D3765233C38B1 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = B07026266021D7A9212562587B8FF47D /* Map.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F037EC426CB22C61DC42C53929B58461 /* NopDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D3E1B7821FAF644D9A989EA39898832 /* NopDisposable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F059E01A6F668D4323E8AA8B829C319F /* DelaySubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E35C91B560F36745E6DDC9E2723BE1 /* DelaySubscription.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F1C701E17D204CDDDFF1BD79D2F83D24 /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29650A70429833A1243416EE598E3D43 /* Zip+arity.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F22215E45AB372FA8D48062A6E8BCC7D /* StartWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A96C066DF600D628B06989E1DA8C23 /* StartWith.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F3B782903EC34C12754EB7F302AF610A /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = 932F8FCB03BF9A7A375D9E46B79444CF /* First.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F42ECF65DB5D0D8F65E2F10DEBC09A1D /* TailRecursiveSink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0832711C1CFEAECBE58CEACA4813F3 /* TailRecursiveSink.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F7647A452BD8B9D3ABA2B27C5E281CA2 /* ReplaySubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BDADF0926AD1A5EEB6ECC2DD4AC32FC /* ReplaySubject.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 01670D708938741AB647D33821B489D2 /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11C0033F9533132D424D4B730C0F5E8 /* Enumerated.swift */; }; + 02912A00FC9AC0534AC160268C6EA5CC /* DefaultIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACE978FC15EDD537F57236BD94D063F1 /* DefaultIfEmpty.swift */; }; + 049CA7046095813FAB9CAB24E3E3C04F /* NopDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B624ACBF9E210375CB613F46F660F9 /* NopDisposable.swift */; }; + 0681EF9707D9CC4F69FE11D3C48C0659 /* FoundationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A89E0286754DC69A2D1F91523DB0495 /* FoundationExtensions.swift */; }; + 06A5235E9085439CC10A1F3BF43110D5 /* VirtualTimeScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A019FA65289E40EC9ED581F854C9D1C /* VirtualTimeScheduler.swift */; }; + 0810484E07381D9DDB7FA921D1AE5624 /* ResultExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F16D73F7D479F3BE8DB88673189FB14D /* ResultExtensions.swift */; }; + 0A2BA8C6F0199E9D7749A9566202C758 /* Sample.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBADBB25DFE793AD037F1C0D82996E78 /* Sample.swift */; }; + 0BDC3CA3A6146B13A9888F7C07BC4722 /* BinaryDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71129D9105A5E651FC2CCCE7A999E48F /* BinaryDisposable.swift */; }; + 0CE9B22B9CF1D6BAAB6818B655C3BAA8 /* AsyncLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A674F1C4A77CEB37A6FD4B0FE8BB0906 /* AsyncLock.swift */; }; + 0D42F06544FB8922A2A65009FAB3583F /* Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6B50FBF38287E14A48A3EA4D745568F /* Rx.swift */; }; + 0E095B3BB4591D548D35430EDE48C4B6 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF52C1EC5F01AAC22B7276F4363EEB40 /* SkipUntil.swift */; }; + 0FCFBD94D256BDB1E065EF3DCDCA5393 /* RxMutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D5902520E2FB22A99F6E2D48C484ECC /* RxMutableBox.swift */; }; + 10E96C8BA5EEECE3378CA40D8B01411A /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = B874CAB52B08912C053A8E98E4F6B245 /* SkipWhile.swift */; }; + 114F5668F8B2C7A328966299B99CE5BE /* Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EE7A7E598D75E301DFA1177AFF2BF15 /* Timeout.swift */; }; + 119A325E155541452F432B23FECA24E0 /* HistoricalScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70FA50883E931662880526F3DD1C230A /* HistoricalScheduler.swift */; }; + 170A43301BBF4101108638668FF34DEE /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6583D7F8E68A885F2F1E9517A44634 /* Errors.swift */; }; + 18F1C4F429EA4EE47863C59F183F6758 /* Scan.swift in Sources */ = {isa = PBXBuildFile; fileRef = F35D19B3B82D092F7F7F789F815CE5F4 /* Scan.swift */; }; + 1C2ABE3286100015AB5AD375F6C846AF /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416A696DE5B535AEA1BF453FA1E2154C /* ConnectableObservableType.swift */; }; + 1C5FCB11BDA6B695859066A82E0A3962 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAFF4A1222A4EE1E936576B5E281863F /* LockOwnerType.swift */; }; + 1EB069D5C9FB689AB1CCB587B3890DF0 /* RxSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = BCB5F4845E6E32094586D7AC473EC638 /* RxSwift-dummy.m */; }; + 2066B802CD5EE10B7EB31F45087771E7 /* AnonymousDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FFC42154BD2B0451000470877BCA75C /* AnonymousDisposable.swift */; }; + 212E37330B2EE9058E21C03B04BDC0F9 /* Deprecations+Removals.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46373391CDCBA2FF4C663E4F1263F62 /* Deprecations+Removals.swift */; }; + 2146EBC9AD0F764FB5A08C8B1F6BB604 /* GroupBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC01A9598EB317206B15721CCF44D4C5 /* GroupBy.swift */; }; + 22E362389674EB5F349D28163B8BA1CF /* Never.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CC9CE34F10A9A35653402267C9460B4 /* Never.swift */; }; + 24F634748E68CD7B8226EBBB45E3F30C /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F04DA2BBEFB1AB011376B20BA92415 /* CombineLatest+arity.swift */; }; + 25796C6EBD25AB379B015ADF82EE1EE5 /* Date+Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8180670A16C2146033A448DD77D9294C /* Date+Dispatch.swift */; }; + 2597376F5FFD083F6353D503E729A90C /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BFC42BBC0266D0109E1356451424F81 /* SwiftSupport.swift */; }; + 259BE7147C34DF767EE744B3370963A3 /* ReactiveSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = AD967D6DD7C1B506DBBD109F6EC99657 /* ReactiveSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2714A15AD83759B3639EA631D596D22A /* SingleAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 909ED74747DC5BACB9C55AEA4D0BAA23 /* SingleAsync.swift */; }; + 2885AA71C5B2AB74419A81270B1F68E3 /* Pods-SpeedTestTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 71617E72E8E69DFB034385FC4AB97CE0 /* Pods-SpeedTestTests-dummy.m */; }; + 2A4823904796E1CA89E86E0DDD180BAE /* Single.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6E4A009A9456241DE76D86AA92CE87C /* Single.swift */; }; + 2CE4C4AED40EA9755848498A687FEB16 /* Maybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23CED774E31E8B168D85D4ECCB042643 /* Maybe.swift */; }; + 30ADE54AB0A7977B017F30B52209EECC /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38A9FE71D02057E76EF25465B491DD11 /* Disposable.swift */; }; + 350E28A9E921E9F9E5B3C2E77CB3BFF2 /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10F3B2BC25A8E02655B282CE7D407EC9 /* VirtualTimeConverterType.swift */; }; + 35C8E014E23B79DD2E81F9A3CB06CBF8 /* BehaviorSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D97D3F5C1CED6E78333D1549277688 /* BehaviorSubject.swift */; }; + 36ED2437C10C08EDEC51764D2AD5E002 /* String+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCA627C08DB6947FE4A75C6CDE0A913A /* String+Rx.swift */; }; + 3A385C67DFF818E91D54F33FBD6FB7DE /* DisposeBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CCBA2716A417112FA97C9221DE72681 /* DisposeBase.swift */; }; + 3AD25AD9C8728A9A86FFE6EC25FA9BFE /* Debounce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B612D0B2C41C3A1CA70200986B23EA /* Debounce.swift */; }; + 3BEF2CF5FB56FF6949B715C255A8D316 /* SignalProducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7539FBA4DE081BA605E936BEF11D883 /* SignalProducer.swift */; }; + 3D3010B87410A0F556596DF882B103F0 /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9260027C815A321953195CEC95FA2E30 /* RetryWhen.swift */; }; + 3DB6D1DE2CF5FA22FE46BC1E6499E37A /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4ED3B844E77EC35A3422774EAF7DED2 /* Lock.swift */; }; + 3DBE3AEDC40B41E826C365D8CA247217 /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A19D802A29C857DF55899C88835D2D /* PrimitiveSequence+Zip+arity.swift */; }; + 3E256795F6BB882B6664D74AFA4F5FDF /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C1367B7E3A62B3918270152C10ED32C /* Dematerialize.swift */; }; + 4018D04EFFFB41BAFDAF771A46D17190 /* AddRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = A433E0251ADE40C48B64D32E0A65A7D8 /* AddRef.swift */; }; + 4030F2E41D3B55189558F48CDE8DECFF /* ImmediateSchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E388061D44B77E43C627EC5C2A1B5E74 /* ImmediateSchedulerType.swift */; }; + 41479B8E61A8D1F6D9BD7DDDE0A3D3FF /* BooleanDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16EB310540F44ECD13B956664981373D /* BooleanDisposable.swift */; }; + 43764C8719E0B6C43333BFE14605C54A /* HistoricalSchedulerTimeConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75DA0DA36E5BBDC292DE099BD1B06DC9 /* HistoricalSchedulerTimeConverter.swift */; }; + 43FBA3428C3C5DD96158EB605E38DC11 /* InvocableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2718EE1F40BF5A72D9410328CFC72747 /* InvocableType.swift */; }; + 48F98DADB3283A18D18095778AAF4334 /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4223D4EC521F560272A60443E84F13CE /* Materialize.swift */; }; + 498A81CFDAA604E2A6C602BB6C00575C /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A72063DAB47887233C0B02410F2A229 /* InfiniteSequence.swift */; }; + 4AC39B2213528DD3BDA4C243B14E37ED /* RefCountDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B38742F2A310BB91E002963C66EE18F9 /* RefCountDisposable.swift */; }; + 4BE5939AF4C323CB7AFF8E4186449499 /* ObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AA28D955567B852298A5D87F02C8F21 /* ObservableType.swift */; }; + 4D8B3BE5F99171A4D1205B606B69F79E /* CurrentThreadScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6935DBC6D830FA58B6F00DE6F939916 /* CurrentThreadScheduler.swift */; }; + 4EAEADDF7427C16CB82699DF48965A0F /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33B8DBF05C340F518F9850ECF1DB48AF /* Event.swift */; }; + 4F53CECC2B262774607D98C45C5F7CE8 /* Completable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CB2E417378373476655F23897B7D0F4 /* Completable.swift */; }; + 4FE2DB9FA1369193B5D4B0613C9AE5DB /* Using.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C5B9A502A600B56D05F3A37BCCB082B /* Using.swift */; }; + 51EA4D0F33C66DB2505645FFE31CD7AF /* UnidirectionalBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096A461278DBA4D9E3790AD0153012E1 /* UnidirectionalBinding.swift */; }; + 51F56A370E86EA66D4533D91CE2E088C /* OperationQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C45A27DC8EC05EAF142135B5A67834 /* OperationQueueScheduler.swift */; }; + 52959B2DBDABF67EE84B668630D99958 /* Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA2F528B005F78152AD33DED8EBE235 /* Catch.swift */; }; + 53267AC8D59401E882954F0ADD24B87F /* Flatten.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AA2345DD8FA01DA8C7F5C07DBAE80AE /* Flatten.swift */; }; + 5467DA8A0A477B4414120B9AD955FAF0 /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14490319BFBC29BB70901D29672A9AD1 /* Window.swift */; }; + 578289037D6D6B75AE26BCD55B6A64DD /* ObserveOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3E65B33B2FF09471EBD74DB3EDA751 /* ObserveOn.swift */; }; + 5A351E279F8F63E0D8BFF14BC15B8144 /* DispatchQueueConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EA8A7E536DA0583DA76D23A47117F6D /* DispatchQueueConfiguration.swift */; }; + 5A4E6C8DC64E05677CBCD58BB2877EE8 /* Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F7EC7A583D5177AAF95BAA2F69F7A4D /* Reduce.swift */; }; + 5B121DC2FDA622AC0AD34621B9628B43 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C1149F3C5794854FE51478609C957B /* DispatchQueue+Extensions.swift */; }; + 5B656B6DEFBB0EF2BECA60932689A8B7 /* RxSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AE2A60F25C513E34FABCFD5F06CEBF7 /* RxSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5BBAF6797B81F267510263D80B8197BF /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12C37CD0DFABEF2D597A81073377359 /* Range.swift */; }; + 5BE1AF801B6F3E2AF365B69F066F268E /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04977683CA90E6037B7707BE7DFB710B /* Multicast.swift */; }; + 5DBA1F21AAE770A20D3C8D8DD769013C /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881F24B385762FFB15EF37D3340405A9 /* Filter.swift */; }; + 5DC99ECACE479596E644115F745B38E6 /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = C959E1A895BC2404A85BAF49A8A3F698 /* CompactMap.swift */; }; + 5E290FC57A79D804C79FE2965828678F /* TailRecursiveSink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E26795766A973976E8862FBFF103408 /* TailRecursiveSink.swift */; }; + 5E6945651475F73AB34C1AEBE937013C /* CombineLatest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F407D14E1493E8D4AA3049C0C2B293 /* CombineLatest.swift */; }; + 60052D900CCEAEA66B2010EAC44BAA07 /* Deferred.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818CDCC1E417ACEF273725C82FB518EE /* Deferred.swift */; }; + 62AC2EE31140FD90DF4CB9E84EB1D69E /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACCDD1317DD115FE47EBE54B4E319877 /* SynchronizedUnsubscribeType.swift */; }; + 64F73958A768D74A7C45DDEFCE480654 /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CCA9B21D16565E6B165F12FCD70EAD9 /* ElementAt.swift */; }; + 65FD5D2FF0833408E12236FCB0E42C24 /* Disposables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49952D18F2FE454FC6B0BB584E3C87AE /* Disposables.swift */; }; + 67B1E0AD31FD7C44E31E241D6D97BB15 /* ToArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7438B8B58F8F6E6C0219AFA0EDF56D /* ToArray.swift */; }; + 68E40ACE329722C65A6A8D590A49CDB6 /* PublishSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 141B8F8F6CBEC21B549FDDFDA7A2DB5E /* PublishSubject.swift */; }; + 69182AEC6A4022999099278A5977494A /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41A4F32477479664F726767C4A01E7B5 /* Event.swift */; }; + 695C2D0242295C6450A7F6330471B7FC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */; }; + 69EFD659067C53680C77D8B57F1D1965 /* Sink.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0CD6E465F1DC81CE057B393DA114935 /* Sink.swift */; }; + 6A9AAA0728FF5F65038B5F7488BFF5BC /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1605D69B978CEFB408B33EBD19332CE5 /* RecursiveLock.swift */; }; + 6B3B23BA169A57B7416235BB113808F6 /* RecursiveScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F82671F5C0E6F66A1EDBAB6223A396E /* RecursiveScheduler.swift */; }; + 6C5A4DBCACAFC5842E6C0C0BB405CF8D /* Amb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1AB48B54F45F5054FEA5BBF90FFB20 /* Amb.swift */; }; + 6CBC14F3CC53081CBD6F8FED6B7B7874 /* Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FFC2FD1DCB87A14C1D7C2EF0A07D425 /* Generate.swift */; }; + 6D3C1A1EEF289BEF78464D964CAD416E /* ObservableConvertibleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEEF26419AC066446518D9D171E49E3A /* ObservableConvertibleType.swift */; }; + 6D59D8BAC5B3723B390094A96CCB060A /* ReactiveSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 358DDDE9642A15D1B039CFB3DB084775 /* ReactiveSwift-dummy.m */; }; + 734C83E2143BA00000E8FADA79B4754D /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14B6E7D3F989CC972FEEEA9E428FE9B7 /* Zip.swift */; }; + 754ADE52D9972F60BCDD9113BC452C32 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE71314BA1E364D614F9E15E41DD46E /* Atomic.swift */; }; + 75775C05191E91911C191F0986760184 /* Take.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F6E10E62C00A66FF62AD38BB7E783BD /* Take.swift */; }; + 7696B97F3023FE444D94C963CBD702AE /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8480F4C4E69A22F23F4EFE5EB810864 /* SubscriptionDisposable.swift */; }; + 786C12158AB5FD4716E8BF8296B65FA7 /* SubjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560667B676984E93B5FB59D8F8187A64 /* SubjectType.swift */; }; + 7C689B24B97556FCD447B4D32C40D0ED /* CombineLatest+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B7FD477438657A51429AB16E2B6854 /* CombineLatest+Collection.swift */; }; + 7C9EFBE6B93212C73D12DABF15FBA9EA /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = B424B118CC6D52AF47567EC0DED4AB9E /* Property.swift */; }; + 7D28D11F4FAA31632DB2CF1BC29AD441 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46021142BE4F3C15C44B2A173CE263BE /* Bag.swift */; }; + 7DEAA92B9F585386A82AACD633F00CDD /* SubscribeOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60E6FE990DF652A3EBE755640EDBDF4E /* SubscribeOn.swift */; }; + 7EDD2A215B6E80D4E2EBE92F99F6410F /* ScheduledDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED97D9D6733783480CD6EDCCD6F85E0C /* ScheduledDisposable.swift */; }; + 80FCBBEADEB4B6CB604AEDCA5C9BA34A /* MainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83355F8333C2B35BD219E79655A71C6 /* MainScheduler.swift */; }; + 816C318B7A7D7C24E6017545558780FF /* AnyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAADB332B016CC2E05DC377A4586CAA /* AnyObserver.swift */; }; + 829E7231D40238B884E2B9D8151ACCDB /* SwitchIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615F53F30FC4997851C4E179BC17969F /* SwitchIfEmpty.swift */; }; + 837EBAA86949F7E6998F2E74ECE3F424 /* Skip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9DF2C471E8F5A446BD5F3B2AF64751 /* Skip.swift */; }; + 88109443D950C6F779C61E28D56DDEC0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */; }; + 88296C90ACB3968788ED9C7D53D661A5 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD80AB0E90EE946B2DE8AF20A063BFE /* Optional.swift */; }; + 8B4CBF7AD5DDA658BCB7E8D939F1A829 /* Observer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70235626E65FBDD5D1CC30E7EE6E55FD /* Observer.swift */; }; + 8E7E2AF1C299262FEA6D473BE01BD935 /* ScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54177EB2B2D573E374DE620CD8A07E2D /* ScheduledItem.swift */; }; + 901C1FFA2B8F7E5AA667D995163682F0 /* ObserverBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C8E6A92293F2ECD8AEC67D1A3A07ACE /* ObserverBase.swift */; }; + 903F5D7445CCBE92F6F6B9AE7431A756 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9AB27F2A6CD3FB8B947176D0F228F1 /* Action.swift */; }; + 919B2EF09439DC404F918854676773FE /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E0A10482D8F901E259114C0249A1261 /* Zip+arity.swift */; }; + 92D0B5DCE541366E791E4E2D12915751 /* Reactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = E826AD57ED3060670F6A393595511FDB /* Reactive.swift */; }; + 93E81EB50E68C3C420019ACE8A4A2197 /* Deprecated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8DC00B4257C11ED799A9297843DF7F /* Deprecated.swift */; }; + 9459D3C756860382C479FADB0A0B7A7F /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F8A06E7618E1B78B5D27A2C28BD7E2 /* Throttle.swift */; }; + 953762806E37C8CDF25BD38C740FF722 /* ObserverType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DF2E79A3DF6185ED45ED3C74E62AA5 /* ObserverType.swift */; }; + 95392ACCB07214CE44543153D49EF2D7 /* SchedulerServices+Emulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCD084FB95A9B12E041CE8DC1339CC2E /* SchedulerServices+Emulation.swift */; }; + 96D58161696810A52CCD104B3C25496C /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCE221F334E6722B8B8416576482340F /* TakeLast.swift */; }; + 98007C0C6060C697C9193EFB39A8E927 /* Do.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABBAAC34E04605A6F459AC797C8D0213 /* Do.swift */; }; + 9A8362B931B67A195EEF99D1D5787C95 /* AtomicInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 222E3B261C4A898F9728230C4E6C5472 /* AtomicInt.swift */; }; + 9ADF15C6FA880CA3AEC4D7B14BC0EB7F /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA37B00D4300ADEDF8FB73363425EED4 /* Map.swift */; }; + 9C8BF8D864399F4CE1AA7511B05F5E53 /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D88A5563A68F78D8FB9E7641A78E3E6 /* Producer.swift */; }; + 9CEAF2A6B8551ECED2EA3897DAD37D61 /* AsMaybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FD23B77696683254C845D9E7270FA25 /* AsMaybe.swift */; }; + 9F2F4F0D0F959C2E06818775F0CDF0D1 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04399814E7A289CAF87D70B59DEDDB3 /* Observable.swift */; }; + A34F91EC384833CC0A348278A208992E /* CompositeDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16E1DE0980686599F47F6830A6E6529 /* CompositeDisposable.swift */; }; + A5176420651EB50AD675EF9F62E0016A /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2BD7C5430821B1797DDBB13A563C0DC /* SynchronizedOnType.swift */; }; + A70A1B109F6E624265FA027F766B0232 /* Zip+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2E65C764782E6ED7D1BAF868909BA1 /* Zip+Collection.swift */; }; + A7655A896348660BB60A8F46DC8B8CF9 /* ObservableType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124140C3CF78161EFF9502BEFB068507 /* ObservableType+Extensions.swift */; }; + A9ADF31E6D9B024261F99D9787EB1921 /* ScheduledItemType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E79C7C7361732EDC62CA930797D63904 /* ScheduledItemType.swift */; }; + AAF0DCFF1D57D2ADF8ADD5424CA5A86C /* DisposeBag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BCEDB95F6A4FB5CF35F3D125C63AF3F /* DisposeBag.swift */; }; + ABD7FB4FA4E20A445F2528C91486D9C3 /* Concat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10580DF14A779C6A0F3A26B5266A0C65 /* Concat.swift */; }; + ADB2CF20567AF529197A1091FA531B1E /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BD792020DA9F4954DB5E711B88A5C6 /* Switch.swift */; }; + B08325501BE96BAE7DEA0EDB4C3E4478 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FBCAD665FA5718C63FEB7C456EA3B63 /* Error.swift */; }; + B333454B3020CEDEC9BDBEF0E8400FFB /* Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B743B5D3AD8D6EAC35F09B4A07ED221 /* Debug.swift */; }; + B397928461945EC67D0C863EBE61899C /* Reactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FFF244A5764C5A15DB00266892650A7 /* Reactive.swift */; }; + B73FAE22FC2C65D60C28A64E77052EB4 /* Completable+AndThen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A500E1DCDAA1AEEDDED3611CAB37647 /* Completable+AndThen.swift */; }; + B8D36F26D5452163DC4BC19B6D06A28C /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2010CDEC317A362AB9FACE331E38718 /* Just.swift */; }; + BAEF9CEF2AE7BC78522CABDD33699BFF /* ValidatingProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144D91B492709EDF6F03EF19CB81501D /* ValidatingProperty.swift */; }; + BB0A800EDA70827B28B4B2E28B96C6E8 /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616B57782F104485154E1B59EEEAF26B /* Signal.swift */; }; + BCA62AF4479783CEBC1A9443D1A7FFEA /* EventLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = E44DC83C20BD673B98FD159AFE87D54D /* EventLogger.swift */; }; + BD95E4BC718104C84F7851658AA3FE29 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48142E2FA28D3DBCD712308F4F24CC0E /* Buffer.swift */; }; + BDC1C85FC295E69FEED6436CABD6B5A1 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ECA604A47966C4735B434BC6DA2A177 /* PriorityQueue.swift */; }; + C47662C1EF5D5DCDAC5C993EE18AC095 /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF43252AFDF541A39F6083C7C0410D3C /* Disposable.swift */; }; + C4E4D6818A36C89F8BA49A05E293BA5F /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B5CEE1040AA17B845C38191C8456105 /* SynchronizedDisposeType.swift */; }; + C57A6C666E9D7EB9B8B38E60A284E278 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */; }; + C667FA9B9CA2B99DC20A8D4AF10B2D68 /* DelaySubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A45F8546554D26D53520E66037989F /* DelaySubscription.swift */; }; + C6FFB5DC01D6D855057BDB7B9D3C3C7D /* ConcurrentDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1111163020378F1263875AF87327EA2B /* ConcurrentDispatchQueueScheduler.swift */; }; + CD4ADA36A7DF68D26DDE8214363856F4 /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3123C761FFF570332DAC5E7A8D5265F /* First.swift */; }; + CD694C0B16BF9542A27DD7946AB77F3A /* SingleAssignmentDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A6A401C28480D667C988A1F6BE1FB42 /* SingleAssignmentDisposable.swift */; }; + CDAD526F22D894E420C5741C700CE322 /* Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EBC60B461BE55F69A204B8D1E281A2E /* Delay.swift */; }; + CF0588B8A21F79EBDDA3A5E0AFD3B480 /* ObservableType+PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849055E8CB8F92B218DD19C216FF0EFB /* ObservableType+PrimitiveSequence.swift */; }; + D165B42B89C543C053698AE43992A772 /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADF76FE5BAD7F7167C22F55BF15B6A31 /* Timer.swift */; }; + D19C9CB44E37C7DCDFEA752129E20BD1 /* SerialDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD71EE6B56554451CC09C0D11A557E0 /* SerialDisposable.swift */; }; + D29B07F9BB89DD02DF8479E59674915A /* ReplaySubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA7EFAF3754E3204528DF074253BB8D /* ReplaySubject.swift */; }; + D88D1773D62A011C69B6EBC40C976BEB /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 136C533FBAD2065CF922C5D4178507F4 /* ConcurrentMainScheduler.swift */; }; + D9319698B5B17CDBF62256F90E991EB6 /* WithLatestFrom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615A1505F8D5DC0674E4198FBD6E7E5C /* WithLatestFrom.swift */; }; + DAEB3A87FF8A72A708FC186BE709D6BB /* Pods-SpeedTestTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B9BA4B4DF4B788CF78C4FF5EAA77E3FB /* Pods-SpeedTestTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DB3F362A380421D822B8AF97F8D80FCD /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D64E6ABAEEBF0D658153E5F00563F6 /* Queue.swift */; }; + DC1B356C82B075C5D1D2BC57B12BE44D /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038F225C8F23D07ACF31BD010CEC3FCB /* Sequence.swift */; }; + DCD250EB247CA3362A697180B0182086 /* InvocableScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86BE5495FD6250F9A47065F2E24D9B97 /* InvocableScheduledItem.swift */; }; + DD69FC6190FB0C4D8574932D64296693 /* AsSingle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D25CF4C826D65F08417B0B3906BEE080 /* AsSingle.swift */; }; + DDCA2294062DEE92F3FDC1E7CB72E840 /* DistinctUntilChanged.swift in Sources */ = {isa = PBXBuildFile; fileRef = 464ECD6DA7A1EBCAD3C85E4F28EB6AC8 /* DistinctUntilChanged.swift */; }; + DDD1698D35501DCFF3B731E906D80F18 /* UninhabitedTypeGuards.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8BDBB317A647BED7C8B9317AA9AA7EB /* UninhabitedTypeGuards.swift */; }; + DED3055847861EDDF90F925377D5D714 /* SerialDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C947A95C4B3D381C602A417EFD72787C /* SerialDispatchQueueScheduler.swift */; }; + E0308CBE21DE89A7AA62551F16578304 /* Lifetime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83600B5B0DF0A906401995187215ABE5 /* Lifetime.swift */; }; + E05C3E0B8D466582B98045FF27EC5464 /* Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C86301CD1D600AA7E068851356C388 /* Create.swift */; }; + E05DA5DB5B8295E44B101DC8072944BC /* ShareReplayScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03900D108AD7A7765B68240EB9313869 /* ShareReplayScope.swift */; }; + E060A3B61583147855DDF23368350929 /* AnonymousObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C6F5D5B3FB6C9FE9802A1F9DA2041FD /* AnonymousObserver.swift */; }; + E0A9095EBD109A44CBC85AD84D7B2819 /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = C591009344E52A280A0DF1010217A26B /* Platform.Linux.swift */; }; + E1568E4EEBD20A839AE8D485F76E94CD /* StartWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C4D2AA2FEF93131A2797A7182576B /* StartWith.swift */; }; + E1D09901E7F579D08345E3DD25E8C5E8 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2AADA46DDBDFA4BC647000AB189C5F /* Optional.swift */; }; + E4069D575BE2E2FB54C8488A93181834 /* TakeWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1977D8DBA9130EF0286977D17E0E3FB6 /* TakeWhile.swift */; }; + E4C4F3E52516A9C5E3A18CE8CFBB4E13 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E45A7C3937EA2BD7B809383A083E7570 /* Scheduler.swift */; }; + E5856E1162F623E87FBF41836214CD2B /* SchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A165B3B061C9B1D4DC8E5DAB9DDABFF /* SchedulerType.swift */; }; + E5A0C334AA8D8BDF9584A77B64F55599 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 928265E5C82E2CE242668268AB0AB7A4 /* Bag.swift */; }; + E687FA252C567B7BDEB2C01EDB4097A1 /* TakeUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A840CC90B8D3BAD9EABDD41BE16D71 /* TakeUntil.swift */; }; + E822E6FCFDEB95CF949DBC5FE59C2745 /* Bag+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9819C64B1BDB53C623124B5A3A9F6D /* Bag+Rx.swift */; }; + EF2214EBE4FEEFD5E8171F6C4E5F2BBE /* PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1A16308DDE5843D95C4F85B11025A5 /* PrimitiveSequence.swift */; }; + EFA35142E87F39D8E1B51948A1F795AD /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC2B98C06689F58B33FC5B6B75B3ECFB /* Empty.swift */; }; + F023436537FB3460AA7073BCFFD078AA /* AsyncSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943CDB8979A44F79605D7C581CC55580 /* AsyncSubject.swift */; }; + F568CDFE9189631D2C10CC527C1BD33A /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AF9C701AE2F9B64D1B7D8629BABFA2 /* Platform.Darwin.swift */; }; + F73D3DFAB783E7DBAD910C2C0AE6140C /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C79D1BC58EA7994FC6EED8B1420E21C /* Repeat.swift */; }; + F7E285B8F3BA0E3C7EF6AFA17708FBD7 /* GroupedObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D84DC35F26963DA11DAAC90A4577765 /* GroupedObservable.swift */; }; + F996F714EC4FD3EE059CCCF0E8F9E7A2 /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6416D38D72ECCD0E5291778D21F53FA4 /* Cancelable.swift */; }; + FA99DE9AD216F43B08E06A301A65BF1E /* Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B409AEC546D48C982232951729CA8103 /* Merge.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - B678F51CCA816C93D41CD33C9E258E9C /* PBXContainerItemProxy */ = { + 43D69BABC7C9123379154D61B2E9BEE0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 08B8EF1A02DE30CBEFB370FFE1C123C0; + remoteInfo = ReactiveSwift; + }; + 89968FCCBB466431C135B1DAACA0A705 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; @@ -177,198 +208,403 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 012D7D176B48342A29FBBF46AFBD0624 /* Zip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Zip.swift; path = RxSwift/Observables/Zip.swift; sourceTree = ""; }; - 01A7E7A407382AF5941B06CE4C7325DF /* SubscribeOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscribeOn.swift; path = RxSwift/Observables/SubscribeOn.swift; sourceTree = ""; }; - 0563003B44EC515724F308FCD3CD8193 /* Observable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Observable.swift; path = RxSwift/Observable.swift; sourceTree = ""; }; - 069F01BC4A1392ED2E66E02E6339A8F3 /* ImmediateSchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImmediateSchedulerType.swift; path = RxSwift/ImmediateSchedulerType.swift; sourceTree = ""; }; - 07299265E8DC2DE35499F40E85D9F81C /* Just.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Just.swift; path = RxSwift/Observables/Just.swift; sourceTree = ""; }; - 07E14D5018327B9D23E609DF824E4E36 /* RxSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-umbrella.h"; sourceTree = ""; }; - 08DB7A2C782A192306FF01CCED728618 /* Timeout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timeout.swift; path = RxSwift/Observables/Timeout.swift; sourceTree = ""; }; + 038F225C8F23D07ACF31BD010CEC3FCB /* Sequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sequence.swift; path = RxSwift/Observables/Sequence.swift; sourceTree = ""; }; + 03900D108AD7A7765B68240EB9313869 /* ShareReplayScope.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ShareReplayScope.swift; path = RxSwift/Observables/ShareReplayScope.swift; sourceTree = ""; }; + 04977683CA90E6037B7707BE7DFB710B /* Multicast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Multicast.swift; path = RxSwift/Observables/Multicast.swift; sourceTree = ""; }; + 066EA75C23239E88AFD38D843C35D737 /* RxSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxSwift-Info.plist"; sourceTree = ""; }; + 06F04DA2BBEFB1AB011376B20BA92415 /* CombineLatest+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+arity.swift"; path = "RxSwift/Observables/CombineLatest+arity.swift"; sourceTree = ""; }; + 096A461278DBA4D9E3790AD0153012E1 /* UnidirectionalBinding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UnidirectionalBinding.swift; path = Sources/UnidirectionalBinding.swift; sourceTree = ""; }; 09C540500A583CA3D8CF67548F66082E /* Pods-SpeedTestTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-SpeedTestTests.debug.xcconfig"; sourceTree = ""; }; - 0CEE237A47CB832B82BE9AB11E02E3BE /* Reactive.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reactive.swift; path = RxSwift/Reactive.swift; sourceTree = ""; }; - 0F4B8AAECAC0596375E5202E6005273B /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxSwift.framework; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0F6810A13B1F72B2F10E9B60A055ED2F /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; - 167B521463C24DAC8198866F49CB61AD /* Deferred.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deferred.swift; path = RxSwift/Observables/Deferred.swift; sourceTree = ""; }; - 16D52A30C471E02F800ADCA71FEA34A2 /* ObservableType+PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+PrimitiveSequence.swift"; path = "RxSwift/Traits/ObservableType+PrimitiveSequence.swift"; sourceTree = ""; }; - 181AFF6EE7661E0BD553B973424023DC /* PublishSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishSubject.swift; path = RxSwift/Subjects/PublishSubject.swift; sourceTree = ""; }; - 181F7A0CAFDFC849A468C6C9C50F1C58 /* GroupBy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupBy.swift; path = RxSwift/Observables/GroupBy.swift; sourceTree = ""; }; - 19B2B2B7EB6B462C9BAF4D02BB1596B7 /* SwitchIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwitchIfEmpty.swift; path = RxSwift/Observables/SwitchIfEmpty.swift; sourceTree = ""; }; - 1C1C3C1D616B940D3BA19D47FEE9B3B2 /* Never.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Never.swift; path = RxSwift/Observables/Never.swift; sourceTree = ""; }; - 1C7AEFCBAE8882AB113116AC76B8D329 /* CompactMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompactMap.swift; path = RxSwift/Observables/CompactMap.swift; sourceTree = ""; }; - 1EE4B540DCCB2925913C2EBAF3D9124C /* VirtualTimeScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeScheduler.swift; path = RxSwift/Schedulers/VirtualTimeScheduler.swift; sourceTree = ""; }; - 1FFBC6AC68411BAC76597A4912382BC2 /* Concat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Concat.swift; path = RxSwift/Observables/Concat.swift; sourceTree = ""; }; - 2274A4FABE921F12C377C27E8F92A9F3 /* AddRef.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AddRef.swift; path = RxSwift/Observables/AddRef.swift; sourceTree = ""; }; - 2278F7BA462362D40764DC52273D2382 /* Take.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Take.swift; path = RxSwift/Observables/Take.swift; sourceTree = ""; }; - 29650A70429833A1243416EE598E3D43 /* Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+arity.swift"; path = "RxSwift/Observables/Zip+arity.swift"; sourceTree = ""; }; - 2A3E9F59FE2E8B99CF1A7161ACD4C312 /* Delay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Delay.swift; path = RxSwift/Observables/Delay.swift; sourceTree = ""; }; - 2C845DF990EACA316A5B424082798634 /* TakeLast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeLast.swift; path = RxSwift/Observables/TakeLast.swift; sourceTree = ""; }; - 2D20C0518E27696964A5D7E0A5E2D9BD /* OperationQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OperationQueueScheduler.swift; path = RxSwift/Schedulers/OperationQueueScheduler.swift; sourceTree = ""; }; - 2E4173F63456BB3C1FE17283F5FCBB21 /* SynchronizedUnsubscribeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedUnsubscribeType.swift; path = RxSwift/Concurrency/SynchronizedUnsubscribeType.swift; sourceTree = ""; }; - 2F313DE547D913B19C56B7820225BA20 /* AnyObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyObserver.swift; path = RxSwift/AnyObserver.swift; sourceTree = ""; }; - 306DE0E6D87978242135F33A6C4D5A1D /* Maybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Maybe.swift; path = RxSwift/Traits/Maybe.swift; sourceTree = ""; }; - 3288AFCEC296C92324275DCD605E92F7 /* Producer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Producer.swift; path = RxSwift/Observables/Producer.swift; sourceTree = ""; }; - 33497C1B69A3756EC9868E624CEECE4C /* SynchronizedDisposeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedDisposeType.swift; path = RxSwift/Concurrency/SynchronizedDisposeType.swift; sourceTree = ""; }; - 33FD1981C6F35453F660B293D58E3CF7 /* RecursiveScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveScheduler.swift; path = RxSwift/Schedulers/RecursiveScheduler.swift; sourceTree = ""; }; - 34A007B93A08FF145FCED1BCFF259603 /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; - 34E9FB2FDCD209FC08E7D6E73BC5CE8C /* SchedulerServices+Emulation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerServices+Emulation.swift"; path = "RxSwift/Schedulers/SchedulerServices+Emulation.swift"; sourceTree = ""; }; - 376EB75F9B880D9FD1B6F2F45131CBDF /* ConnectableObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConnectableObservableType.swift; path = RxSwift/ConnectableObservableType.swift; sourceTree = ""; }; - 3BB96FC10EB906309699733BA4835AB6 /* Range.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Range.swift; path = RxSwift/Observables/Range.swift; sourceTree = ""; }; - 3BE36BD7E39BF9D232A5347DAD9AC32C /* ScheduledDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledDisposable.swift; path = RxSwift/Disposables/ScheduledDisposable.swift; sourceTree = ""; }; - 3C0832711C1CFEAECBE58CEACA4813F3 /* TailRecursiveSink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TailRecursiveSink.swift; path = RxSwift/Observers/TailRecursiveSink.swift; sourceTree = ""; }; - 3E1B998F98983D222C15C2DA33E99B61 /* AnonymousDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousDisposable.swift; path = RxSwift/Disposables/AnonymousDisposable.swift; sourceTree = ""; }; + 0A89E0286754DC69A2D1F91523DB0495 /* FoundationExtensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FoundationExtensions.swift; path = Sources/FoundationExtensions.swift; sourceTree = ""; }; + 0C1A16308DDE5843D95C4F85B11025A5 /* PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PrimitiveSequence.swift; path = RxSwift/Traits/PrimitiveSequence.swift; sourceTree = ""; }; + 0C5B9A502A600B56D05F3A37BCCB082B /* Using.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Using.swift; path = RxSwift/Observables/Using.swift; sourceTree = ""; }; + 0C79D1BC58EA7994FC6EED8B1420E21C /* Repeat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Repeat.swift; path = RxSwift/Observables/Repeat.swift; sourceTree = ""; }; + 0CCBA2716A417112FA97C9221DE72681 /* DisposeBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBase.swift; path = RxSwift/Disposables/DisposeBase.swift; sourceTree = ""; }; + 0D88A5563A68F78D8FB9E7641A78E3E6 /* Producer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Producer.swift; path = RxSwift/Observables/Producer.swift; sourceTree = ""; }; + 0E26795766A973976E8862FBFF103408 /* TailRecursiveSink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TailRecursiveSink.swift; path = RxSwift/Observers/TailRecursiveSink.swift; sourceTree = ""; }; + 0F6E10E62C00A66FF62AD38BB7E783BD /* Take.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Take.swift; path = RxSwift/Observables/Take.swift; sourceTree = ""; }; + 0FD23B77696683254C845D9E7270FA25 /* AsMaybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsMaybe.swift; path = RxSwift/Observables/AsMaybe.swift; sourceTree = ""; }; + 0FFF244A5764C5A15DB00266892650A7 /* Reactive.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reactive.swift; path = Sources/Reactive.swift; sourceTree = ""; }; + 10580DF14A779C6A0F3A26B5266A0C65 /* Concat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Concat.swift; path = RxSwift/Observables/Concat.swift; sourceTree = ""; }; + 10F3B2BC25A8E02655B282CE7D407EC9 /* VirtualTimeConverterType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeConverterType.swift; path = RxSwift/Schedulers/VirtualTimeConverterType.swift; sourceTree = ""; }; + 1111163020378F1263875AF87327EA2B /* ConcurrentDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentDispatchQueueScheduler.swift; path = RxSwift/Schedulers/ConcurrentDispatchQueueScheduler.swift; sourceTree = ""; }; + 124140C3CF78161EFF9502BEFB068507 /* ObservableType+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+Extensions.swift"; path = "RxSwift/ObservableType+Extensions.swift"; sourceTree = ""; }; + 136C533FBAD2065CF922C5D4178507F4 /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentMainScheduler.swift; path = RxSwift/Schedulers/ConcurrentMainScheduler.swift; sourceTree = ""; }; + 137A5FDBD494F2E59438C6531490ECC5 /* Pods_SpeedTestTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_SpeedTestTests.framework; path = "Pods-SpeedTestTests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 141B8F8F6CBEC21B549FDDFDA7A2DB5E /* PublishSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishSubject.swift; path = RxSwift/Subjects/PublishSubject.swift; sourceTree = ""; }; + 14490319BFBC29BB70901D29672A9AD1 /* Window.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Window.swift; path = RxSwift/Observables/Window.swift; sourceTree = ""; }; + 144D91B492709EDF6F03EF19CB81501D /* ValidatingProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ValidatingProperty.swift; path = Sources/ValidatingProperty.swift; sourceTree = ""; }; + 14B6E7D3F989CC972FEEEA9E428FE9B7 /* Zip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Zip.swift; path = RxSwift/Observables/Zip.swift; sourceTree = ""; }; + 15A840CC90B8D3BAD9EABDD41BE16D71 /* TakeUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeUntil.swift; path = RxSwift/Observables/TakeUntil.swift; sourceTree = ""; }; + 1605D69B978CEFB408B33EBD19332CE5 /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; + 16EB310540F44ECD13B956664981373D /* BooleanDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BooleanDisposable.swift; path = RxSwift/Disposables/BooleanDisposable.swift; sourceTree = ""; }; + 1977D8DBA9130EF0286977D17E0E3FB6 /* TakeWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeWhile.swift; path = RxSwift/Observables/TakeWhile.swift; sourceTree = ""; }; + 1A7438B8B58F8F6E6C0219AFA0EDF56D /* ToArray.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ToArray.swift; path = RxSwift/Observables/ToArray.swift; sourceTree = ""; }; + 1B5CEE1040AA17B845C38191C8456105 /* SynchronizedDisposeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedDisposeType.swift; path = RxSwift/Concurrency/SynchronizedDisposeType.swift; sourceTree = ""; }; + 1B743B5D3AD8D6EAC35F09B4A07ED221 /* Debug.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debug.swift; path = RxSwift/Observables/Debug.swift; sourceTree = ""; }; + 1BF49369D912E56427765EDB1A95D9A1 /* ReactiveSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ReactiveSwift-Info.plist"; sourceTree = ""; }; + 1CB2E417378373476655F23897B7D0F4 /* Completable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Completable.swift; path = RxSwift/Traits/Completable.swift; sourceTree = ""; }; + 1D5902520E2FB22A99F6E2D48C484ECC /* RxMutableBox.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxMutableBox.swift; path = RxSwift/RxMutableBox.swift; sourceTree = ""; }; + 1E1AB48B54F45F5054FEA5BBF90FFB20 /* Amb.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Amb.swift; path = RxSwift/Observables/Amb.swift; sourceTree = ""; }; + 1ECA604A47966C4735B434BC6DA2A177 /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; + 1FFC42154BD2B0451000470877BCA75C /* AnonymousDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousDisposable.swift; path = RxSwift/Disposables/AnonymousDisposable.swift; sourceTree = ""; }; + 222E3B261C4A898F9728230C4E6C5472 /* AtomicInt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AtomicInt.swift; path = Platform/AtomicInt.swift; sourceTree = ""; }; + 23CED774E31E8B168D85D4ECCB042643 /* Maybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Maybe.swift; path = RxSwift/Traits/Maybe.swift; sourceTree = ""; }; + 26F407D14E1493E8D4AA3049C0C2B293 /* CombineLatest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombineLatest.swift; path = RxSwift/Observables/CombineLatest.swift; sourceTree = ""; }; + 26F8A06E7618E1B78B5D27A2C28BD7E2 /* Throttle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Throttle.swift; path = RxSwift/Observables/Throttle.swift; sourceTree = ""; }; + 2718EE1F40BF5A72D9410328CFC72747 /* InvocableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableType.swift; path = RxSwift/Schedulers/Internal/InvocableType.swift; sourceTree = ""; }; + 2A019FA65289E40EC9ED581F854C9D1C /* VirtualTimeScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeScheduler.swift; path = RxSwift/Schedulers/VirtualTimeScheduler.swift; sourceTree = ""; }; + 2AD71EE6B56554451CC09C0D11A557E0 /* SerialDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDisposable.swift; path = RxSwift/Disposables/SerialDisposable.swift; sourceTree = ""; }; + 2BFC42BBC0266D0109E1356451424F81 /* SwiftSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftSupport.swift; path = RxSwift/SwiftSupport/SwiftSupport.swift; sourceTree = ""; }; + 2CC16A8516226A1BC69001BEFD46F978 /* RxSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-prefix.pch"; sourceTree = ""; }; + 2F7EC7A583D5177AAF95BAA2F69F7A4D /* Reduce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reduce.swift; path = RxSwift/Observables/Reduce.swift; sourceTree = ""; }; + 3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 33B8DBF05C340F518F9850ECF1DB48AF /* Event.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Event.swift; path = RxSwift/Event.swift; sourceTree = ""; }; + 358DDDE9642A15D1B039CFB3DB084775 /* ReactiveSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "ReactiveSwift-dummy.m"; sourceTree = ""; }; + 38A9FE71D02057E76EF25465B491DD11 /* Disposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposable.swift; path = RxSwift/Disposable.swift; sourceTree = ""; }; + 38D97D3F5C1CED6E78333D1549277688 /* BehaviorSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorSubject.swift; path = RxSwift/Subjects/BehaviorSubject.swift; sourceTree = ""; }; + 3A500E1DCDAA1AEEDDED3611CAB37647 /* Completable+AndThen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Completable+AndThen.swift"; path = "RxSwift/Traits/Completable+AndThen.swift"; sourceTree = ""; }; + 3AA28D955567B852298A5D87F02C8F21 /* ObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableType.swift; path = RxSwift/ObservableType.swift; sourceTree = ""; }; + 3CC9CE34F10A9A35653402267C9460B4 /* Never.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Never.swift; path = RxSwift/Observables/Never.swift; sourceTree = ""; }; + 3EE7A7E598D75E301DFA1177AFF2BF15 /* Timeout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timeout.swift; path = RxSwift/Observables/Timeout.swift; sourceTree = ""; }; + 416A696DE5B535AEA1BF453FA1E2154C /* ConnectableObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConnectableObservableType.swift; path = RxSwift/ConnectableObservableType.swift; sourceTree = ""; }; + 41A4F32477479664F726767C4A01E7B5 /* Event.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Event.swift; path = Sources/Event.swift; sourceTree = ""; }; + 4223D4EC521F560272A60443E84F13CE /* Materialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Materialize.swift; path = RxSwift/Observables/Materialize.swift; sourceTree = ""; }; + 43A45F8546554D26D53520E66037989F /* DelaySubscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelaySubscription.swift; path = RxSwift/Observables/DelaySubscription.swift; sourceTree = ""; }; + 46021142BE4F3C15C44B2A173CE263BE /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; + 464ECD6DA7A1EBCAD3C85E4F28EB6AC8 /* DistinctUntilChanged.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DistinctUntilChanged.swift; path = RxSwift/Observables/DistinctUntilChanged.swift; sourceTree = ""; }; 46B3F51D8C4340E2891CB0D82380E8D9 /* Pods-SpeedTestTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-SpeedTestTests-acknowledgements.markdown"; sourceTree = ""; }; - 4732CAC567AB9E6FC2ED425A091B661F /* SerialDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDispatchQueueScheduler.swift; path = RxSwift/Schedulers/SerialDispatchQueueScheduler.swift; sourceTree = ""; }; - 474F10EA67A5905D2AF0EDB7D4BF60DE /* Scan.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Scan.swift; path = RxSwift/Observables/Scan.swift; sourceTree = ""; }; - 48792B925801208B04C1CFF407072A42 /* CompositeDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompositeDisposable.swift; path = RxSwift/Disposables/CompositeDisposable.swift; sourceTree = ""; }; - 4A77F87BF09F886F0FFE5EE14CDD1BF9 /* Filter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = RxSwift/Observables/Filter.swift; sourceTree = ""; }; - 4E3E5057B9A128271581BCCBE98B7275 /* LockOwnerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LockOwnerType.swift; path = RxSwift/Concurrency/LockOwnerType.swift; sourceTree = ""; }; - 4E5C36EB3E39AF68E36D08CCDA4C653A /* Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Rx.swift; path = RxSwift/Rx.swift; sourceTree = ""; }; - 4EB28BF72935934FB28144A700AB0054 /* BooleanDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BooleanDisposable.swift; path = RxSwift/Disposables/BooleanDisposable.swift; sourceTree = ""; }; - 50232F56C3A7B75C934C7BC82692AF59 /* Enumerated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Enumerated.swift; path = RxSwift/Observables/Enumerated.swift; sourceTree = ""; }; - 50A45279A2F183B85BDD344D764EBE13 /* AtomicInt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AtomicInt.swift; path = Platform/AtomicInt.swift; sourceTree = ""; }; - 52AAACBB14FE9BD1C035AD7F56B7A438 /* RetryWhen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryWhen.swift; path = RxSwift/Observables/RetryWhen.swift; sourceTree = ""; }; - 55806A569FBE99EF1D5EF177F0E55541 /* AsyncSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncSubject.swift; path = RxSwift/Subjects/AsyncSubject.swift; sourceTree = ""; }; - 5617CC15404DAF3805EB0070B19BC157 /* ScheduledItemType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItemType.swift; path = RxSwift/Schedulers/Internal/ScheduledItemType.swift; sourceTree = ""; }; - 58552F09308C4BB15C6E3C993A5B03CD /* Switch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Switch.swift; path = RxSwift/Observables/Switch.swift; sourceTree = ""; }; - 58746BF458A9D6B1B131E43917E1AC73 /* RxSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxSwift-dummy.m"; sourceTree = ""; }; - 594376167C7F58F7C62FAB5F552C508D /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; - 5D3E1B7821FAF644D9A989EA39898832 /* NopDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NopDisposable.swift; path = RxSwift/Disposables/NopDisposable.swift; sourceTree = ""; }; - 5E209853647CCABA40FF10E958258341 /* Completable+AndThen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Completable+AndThen.swift"; path = "RxSwift/Traits/Completable+AndThen.swift"; sourceTree = ""; }; - 5E4EE54B0B8056EACFF23E79FC6FA13B /* Generate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Generate.swift; path = RxSwift/Observables/Generate.swift; sourceTree = ""; }; - 651B56536404EDA63606BAD39BF3AA23 /* DisposeBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBase.swift; path = RxSwift/Disposables/DisposeBase.swift; sourceTree = ""; }; - 663E825CA6C7EADB658061705B9A6CB3 /* ScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItem.swift; path = RxSwift/Schedulers/Internal/ScheduledItem.swift; sourceTree = ""; }; - 67A66A067BB487D24B58DDE50654AF46 /* DistinctUntilChanged.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DistinctUntilChanged.swift; path = RxSwift/Observables/DistinctUntilChanged.swift; sourceTree = ""; }; - 67DD374AA04E414FE2AE2F74B5AFDC60 /* String+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "String+Rx.swift"; path = "RxSwift/Extensions/String+Rx.swift"; sourceTree = ""; }; - 6BB07C02339DCC64F774319E1496DA6D /* SingleAsync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAsync.swift; path = RxSwift/Observables/SingleAsync.swift; sourceTree = ""; }; - 6BBDBEF351A55D2369D808A0B910D6B7 /* DisposeBag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBag.swift; path = RxSwift/Disposables/DisposeBag.swift; sourceTree = ""; }; - 6BDADF0926AD1A5EEB6ECC2DD4AC32FC /* ReplaySubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReplaySubject.swift; path = RxSwift/Subjects/ReplaySubject.swift; sourceTree = ""; }; - 6C9640FFD356546806E100F45E8A44FB /* Skip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Skip.swift; path = RxSwift/Observables/Skip.swift; sourceTree = ""; }; - 6D669D2B1969E2BCE4DED7161293460F /* RxSwift.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.xcconfig; sourceTree = ""; }; - 6D79FAFD822FBEB7CD95E9F70918B6F1 /* Merge.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Merge.swift; path = RxSwift/Observables/Merge.swift; sourceTree = ""; }; - 70B0F97F33E48BB3438584F09E674E10 /* CombineLatest+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+Collection.swift"; path = "RxSwift/Observables/CombineLatest+Collection.swift"; sourceTree = ""; }; - 70EE902503459EFA68F4E81979BA2222 /* Catch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Catch.swift; path = RxSwift/Observables/Catch.swift; sourceTree = ""; }; + 47C1149F3C5794854FE51478609C957B /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; + 48142E2FA28D3DBCD712308F4F24CC0E /* Buffer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Buffer.swift; path = RxSwift/Observables/Buffer.swift; sourceTree = ""; }; + 49952D18F2FE454FC6B0BB584E3C87AE /* Disposables.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposables.swift; path = RxSwift/Disposables/Disposables.swift; sourceTree = ""; }; + 4A165B3B061C9B1D4DC8E5DAB9DDABFF /* SchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SchedulerType.swift; path = RxSwift/SchedulerType.swift; sourceTree = ""; }; + 4A6A401C28480D667C988A1F6BE1FB42 /* SingleAssignmentDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAssignmentDisposable.swift; path = RxSwift/Disposables/SingleAssignmentDisposable.swift; sourceTree = ""; }; + 4C2AADA46DDBDFA4BC647000AB189C5F /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RxSwift/Observables/Optional.swift; sourceTree = ""; }; + 4C3E65B33B2FF09471EBD74DB3EDA751 /* ObserveOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserveOn.swift; path = RxSwift/Observables/ObserveOn.swift; sourceTree = ""; }; + 54177EB2B2D573E374DE620CD8A07E2D /* ScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItem.swift; path = RxSwift/Schedulers/Internal/ScheduledItem.swift; sourceTree = ""; }; + 560667B676984E93B5FB59D8F8187A64 /* SubjectType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubjectType.swift; path = RxSwift/Subjects/SubjectType.swift; sourceTree = ""; }; + 5C8E6A92293F2ECD8AEC67D1A3A07ACE /* ObserverBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverBase.swift; path = RxSwift/Observers/ObserverBase.swift; sourceTree = ""; }; + 5EBC60B461BE55F69A204B8D1E281A2E /* Delay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Delay.swift; path = RxSwift/Observables/Delay.swift; sourceTree = ""; }; + 60E6FE990DF652A3EBE755640EDBDF4E /* SubscribeOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscribeOn.swift; path = RxSwift/Observables/SubscribeOn.swift; sourceTree = ""; }; + 615A1505F8D5DC0674E4198FBD6E7E5C /* WithLatestFrom.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WithLatestFrom.swift; path = RxSwift/Observables/WithLatestFrom.swift; sourceTree = ""; }; + 615F53F30FC4997851C4E179BC17969F /* SwitchIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwitchIfEmpty.swift; path = RxSwift/Observables/SwitchIfEmpty.swift; sourceTree = ""; }; + 616B57782F104485154E1B59EEEAF26B /* Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Signal.swift; path = Sources/Signal.swift; sourceTree = ""; }; + 6416D38D72ECCD0E5291778D21F53FA4 /* Cancelable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cancelable.swift; path = RxSwift/Cancelable.swift; sourceTree = ""; }; + 64AF9C701AE2F9B64D1B7D8629BABFA2 /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; + 6BCEDB95F6A4FB5CF35F3D125C63AF3F /* DisposeBag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBag.swift; path = RxSwift/Disposables/DisposeBag.swift; sourceTree = ""; }; + 6C6F5D5B3FB6C9FE9802A1F9DA2041FD /* AnonymousObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousObserver.swift; path = RxSwift/Observers/AnonymousObserver.swift; sourceTree = ""; }; + 6D84DC35F26963DA11DAAC90A4577765 /* GroupedObservable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupedObservable.swift; path = RxSwift/GroupedObservable.swift; sourceTree = ""; }; + 6F82671F5C0E6F66A1EDBAB6223A396E /* RecursiveScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveScheduler.swift; path = RxSwift/Schedulers/RecursiveScheduler.swift; sourceTree = ""; }; + 6FBCAD665FA5718C63FEB7C456EA3B63 /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RxSwift/Observables/Error.swift; sourceTree = ""; }; + 6FFC2FD1DCB87A14C1D7C2EF0A07D425 /* Generate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Generate.swift; path = RxSwift/Observables/Generate.swift; sourceTree = ""; }; + 70235626E65FBDD5D1CC30E7EE6E55FD /* Observer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Observer.swift; path = Sources/Observer.swift; sourceTree = ""; }; + 70FA50883E931662880526F3DD1C230A /* HistoricalScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalScheduler.swift; path = RxSwift/Schedulers/HistoricalScheduler.swift; sourceTree = ""; }; + 71129D9105A5E651FC2CCCE7A999E48F /* BinaryDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BinaryDisposable.swift; path = RxSwift/Disposables/BinaryDisposable.swift; sourceTree = ""; }; 71617E72E8E69DFB034385FC4AB97CE0 /* Pods-SpeedTestTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-SpeedTestTests-dummy.m"; sourceTree = ""; }; - 71C921D4C61C49477F7D45BF9F0D596A /* ObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableType.swift; path = RxSwift/ObservableType.swift; sourceTree = ""; }; 72106231E77496C7219E619BE6438C0B /* Pods-SpeedTestTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-SpeedTestTests.modulemap"; sourceTree = ""; }; - 72B4B6D8E329E01070B008308A8C15EE /* ObserverBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverBase.swift; path = RxSwift/Observers/ObserverBase.swift; sourceTree = ""; }; - 72D303B43AC9702530301C44D37B20E6 /* SkipWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipWhile.swift; path = RxSwift/Observables/SkipWhile.swift; sourceTree = ""; }; - 72EF4AC0B5074A2E29B2428B3A7E0ADE /* AsSingle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsSingle.swift; path = RxSwift/Observables/AsSingle.swift; sourceTree = ""; }; - 752F32A59CBBFCAA84277A6D86DCD2CD /* AsyncLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncLock.swift; path = RxSwift/Concurrency/AsyncLock.swift; sourceTree = ""; }; - 75D7D076BF1319E12D146579A1E3AA47 /* SerialDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDisposable.swift; path = RxSwift/Disposables/SerialDisposable.swift; sourceTree = ""; }; - 769044E4D29F65C4310FC11D40304806 /* Materialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Materialize.swift; path = RxSwift/Observables/Materialize.swift; sourceTree = ""; }; - 7999131F2F79B776A2951B564923046F /* TakeUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeUntil.swift; path = RxSwift/Observables/TakeUntil.swift; sourceTree = ""; }; - 7A5FEAF703A4D3E2E46A3F1554B8C0D5 /* BehaviorSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorSubject.swift; path = RxSwift/Subjects/BehaviorSubject.swift; sourceTree = ""; }; - 7DE89160B0C8B1120FD3BE4D5135DFAC /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; - 80F00E9F12804718CAA29E7808208EE1 /* Window.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Window.swift; path = RxSwift/Observables/Window.swift; sourceTree = ""; }; - 85A96C066DF600D628B06989E1DA8C23 /* StartWith.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StartWith.swift; path = RxSwift/Observables/StartWith.swift; sourceTree = ""; }; - 878F7DAE257E28A5866FE720753AA0AC /* Cancelable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cancelable.swift; path = RxSwift/Cancelable.swift; sourceTree = ""; }; - 87BA7F3696D6A4CC74082CA4873A8A96 /* ObservableConvertibleType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableConvertibleType.swift; path = RxSwift/ObservableConvertibleType.swift; sourceTree = ""; }; - 89EAB316B1E600239C78B09CE940E8F9 /* Sample.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sample.swift; path = RxSwift/Observables/Sample.swift; sourceTree = ""; }; - 8D3D54E33FF3238304C7C9913E792B28 /* ShareReplayScope.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ShareReplayScope.swift; path = RxSwift/Observables/ShareReplayScope.swift; sourceTree = ""; }; - 8E7E771A623979EF95A322F1107FFEB8 /* AsMaybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsMaybe.swift; path = RxSwift/Observables/AsMaybe.swift; sourceTree = ""; }; - 8F60E23C9CDED9D731140F98B1118425 /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = RxSwift/Errors.swift; sourceTree = ""; }; - 90610A4859390D4BC2483853E6A3AE85 /* ToArray.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ToArray.swift; path = RxSwift/Observables/ToArray.swift; sourceTree = ""; }; - 9139B8639FD885639FB93B756DD9B7E8 /* InvocableScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableScheduledItem.swift; path = RxSwift/Schedulers/Internal/InvocableScheduledItem.swift; sourceTree = ""; }; - 91CE9840E02A9CAC89AD1E42B4AF9C55 /* Debug.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debug.swift; path = RxSwift/Observables/Debug.swift; sourceTree = ""; }; - 92286F3AF1F2E2EC69A9FF583722C8D1 /* HistoricalScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalScheduler.swift; path = RxSwift/Schedulers/HistoricalScheduler.swift; sourceTree = ""; }; - 932F8FCB03BF9A7A375D9E46B79444CF /* First.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = First.swift; path = RxSwift/Observables/First.swift; sourceTree = ""; }; - 93E3B6350CE7DC6A8D4CA9C97AF58633 /* Using.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Using.swift; path = RxSwift/Observables/Using.swift; sourceTree = ""; }; - 93F23F6F42CC3531743DFE2134556E82 /* VirtualTimeConverterType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeConverterType.swift; path = RxSwift/Schedulers/VirtualTimeConverterType.swift; sourceTree = ""; }; - 9695003960CFCFCAB6973EF2930244D0 /* Disposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposable.swift; path = RxSwift/Disposable.swift; sourceTree = ""; }; - 9834F595A96BDB23A404BBB215DAB955 /* SkipUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipUntil.swift; path = RxSwift/Observables/SkipUntil.swift; sourceTree = ""; }; - 987D881E9A3A698D1447833FB87334FD /* AnonymousObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousObserver.swift; path = RxSwift/Observers/AnonymousObserver.swift; sourceTree = ""; }; - 9A787BC2076D63A7ACFD626D1DE5A9EC /* CombineLatest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombineLatest.swift; path = RxSwift/Observables/CombineLatest.swift; sourceTree = ""; }; + 73CC285A0970DA08D4D96C90682B76EC /* ReactiveSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = ReactiveSwift.modulemap; sourceTree = ""; }; + 75DA0DA36E5BBDC292DE099BD1B06DC9 /* HistoricalSchedulerTimeConverter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalSchedulerTimeConverter.swift; path = RxSwift/Schedulers/HistoricalSchedulerTimeConverter.swift; sourceTree = ""; }; + 7A9AB27F2A6CD3FB8B947176D0F228F1 /* Action.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Action.swift; path = Sources/Action.swift; sourceTree = ""; }; + 7B8DC00B4257C11ED799A9297843DF7F /* Deprecated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deprecated.swift; path = RxSwift/Deprecated.swift; sourceTree = ""; }; + 7CCA9B21D16565E6B165F12FCD70EAD9 /* ElementAt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ElementAt.swift; path = RxSwift/Observables/ElementAt.swift; sourceTree = ""; }; + 7EA8A7E536DA0583DA76D23A47117F6D /* DispatchQueueConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DispatchQueueConfiguration.swift; path = RxSwift/Schedulers/Internal/DispatchQueueConfiguration.swift; sourceTree = ""; }; + 7F6583D7F8E68A885F2F1E9517A44634 /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = RxSwift/Errors.swift; sourceTree = ""; }; + 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxSwift.framework; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8180670A16C2146033A448DD77D9294C /* Date+Dispatch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Date+Dispatch.swift"; path = "RxSwift/Date+Dispatch.swift"; sourceTree = ""; }; + 818CDCC1E417ACEF273725C82FB518EE /* Deferred.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deferred.swift; path = RxSwift/Observables/Deferred.swift; sourceTree = ""; }; + 83600B5B0DF0A906401995187215ABE5 /* Lifetime.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Lifetime.swift; path = Sources/Lifetime.swift; sourceTree = ""; }; + 849055E8CB8F92B218DD19C216FF0EFB /* ObservableType+PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+PrimitiveSequence.swift"; path = "RxSwift/Traits/ObservableType+PrimitiveSequence.swift"; sourceTree = ""; }; + 85B624ACBF9E210375CB613F46F660F9 /* NopDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NopDisposable.swift; path = RxSwift/Disposables/NopDisposable.swift; sourceTree = ""; }; + 86B612D0B2C41C3A1CA70200986B23EA /* Debounce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debounce.swift; path = RxSwift/Observables/Debounce.swift; sourceTree = ""; }; + 86BE5495FD6250F9A47065F2E24D9B97 /* InvocableScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableScheduledItem.swift; path = RxSwift/Schedulers/Internal/InvocableScheduledItem.swift; sourceTree = ""; }; + 87D64E6ABAEEBF0D658153E5F00563F6 /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; + 881F24B385762FFB15EF37D3340405A9 /* Filter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = RxSwift/Observables/Filter.swift; sourceTree = ""; }; + 883AAA7A0359C1678B657C204B29628B /* RxSwift.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.xcconfig; sourceTree = ""; }; + 8AA2345DD8FA01DA8C7F5C07DBAE80AE /* Flatten.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Flatten.swift; path = Sources/Flatten.swift; sourceTree = ""; }; + 8AE2A60F25C513E34FABCFD5F06CEBF7 /* RxSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-umbrella.h"; sourceTree = ""; }; + 8AE71314BA1E364D614F9E15E41DD46E /* Atomic.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Atomic.swift; path = Sources/Atomic.swift; sourceTree = ""; }; + 909ED74747DC5BACB9C55AEA4D0BAA23 /* SingleAsync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAsync.swift; path = RxSwift/Observables/SingleAsync.swift; sourceTree = ""; }; + 9260027C815A321953195CEC95FA2E30 /* RetryWhen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryWhen.swift; path = RxSwift/Observables/RetryWhen.swift; sourceTree = ""; }; + 928265E5C82E2CE242668268AB0AB7A4 /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Sources/Bag.swift; sourceTree = ""; }; + 943CDB8979A44F79605D7C581CC55580 /* AsyncSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncSubject.swift; path = RxSwift/Subjects/AsyncSubject.swift; sourceTree = ""; }; + 9A72063DAB47887233C0B02410F2A229 /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; + 9C1367B7E3A62B3918270152C10ED32C /* Dematerialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Dematerialize.swift; path = RxSwift/Observables/Dematerialize.swift; sourceTree = ""; }; 9CBC60A34501ED8EF03B8F0E58FED465 /* Pods-SpeedTestTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-SpeedTestTests-acknowledgements.plist"; sourceTree = ""; }; 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 9EB728D69EE6493BDBE5D071062BB3C6 /* Zip+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+Collection.swift"; path = "RxSwift/Observables/Zip+Collection.swift"; sourceTree = ""; }; - 9FFCE1932228F377D03BCC121EDF4434 /* SynchronizedOnType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedOnType.swift; path = RxSwift/Concurrency/SynchronizedOnType.swift; sourceTree = ""; }; - A17214F0A5E8878853A63430D553B610 /* ConcurrentDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentDispatchQueueScheduler.swift; path = RxSwift/Schedulers/ConcurrentDispatchQueueScheduler.swift; sourceTree = ""; }; - A19B5A5B86E47172C1EBDAF854330561 /* Throttle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Throttle.swift; path = RxSwift/Observables/Throttle.swift; sourceTree = ""; }; + 9E0A10482D8F901E259114C0249A1261 /* Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+arity.swift"; path = "RxSwift/Observables/Zip+arity.swift"; sourceTree = ""; }; + 9F9DF2C471E8F5A446BD5F3B2AF64751 /* Skip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Skip.swift; path = RxSwift/Observables/Skip.swift; sourceTree = ""; }; + A16E1DE0980686599F47F6830A6E6529 /* CompositeDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompositeDisposable.swift; path = RxSwift/Disposables/CompositeDisposable.swift; sourceTree = ""; }; + A433E0251ADE40C48B64D32E0A65A7D8 /* AddRef.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AddRef.swift; path = RxSwift/Observables/AddRef.swift; sourceTree = ""; }; + A5E2483DCCA8F64A1F4B7C2742B95039 /* RxSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxSwift.modulemap; sourceTree = ""; }; + A674F1C4A77CEB37A6FD4B0FE8BB0906 /* AsyncLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncLock.swift; path = RxSwift/Concurrency/AsyncLock.swift; sourceTree = ""; }; + A6935DBC6D830FA58B6F00DE6F939916 /* CurrentThreadScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CurrentThreadScheduler.swift; path = RxSwift/Schedulers/CurrentThreadScheduler.swift; sourceTree = ""; }; + A7DA933C1F6993AD9DB4BF3D9250B705 /* ReactiveSwift.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = ReactiveSwift.xcconfig; sourceTree = ""; }; A90E43BE8DAE0A05C4499DDE5025DE8C /* Pods-SpeedTestTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-SpeedTestTests.release.xcconfig"; sourceTree = ""; }; - AA54B4558300360287F36AB44B39FE4C /* HistoricalSchedulerTimeConverter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalSchedulerTimeConverter.swift; path = RxSwift/Schedulers/HistoricalSchedulerTimeConverter.swift; sourceTree = ""; }; - AAE41578A30310AC2C7F256279DEB314 /* Sequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sequence.swift; path = RxSwift/Observables/Sequence.swift; sourceTree = ""; }; - AC232B350290EEFAF1C80C342AC435EB /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RxSwift/Observables/Error.swift; sourceTree = ""; }; - AEF509447FD82026F923DD5E1C1FB989 /* SchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SchedulerType.swift; path = RxSwift/SchedulerType.swift; sourceTree = ""; }; - AF4CDCFCAC74B4A6BB27AEC4F605B525 /* Dematerialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Dematerialize.swift; path = RxSwift/Observables/Dematerialize.swift; sourceTree = ""; }; - B07026266021D7A9212562587B8FF47D /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = RxSwift/Observables/Map.swift; sourceTree = ""; }; - B2AD331471133FE73D9A9360C4D6FD06 /* InvocableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableType.swift; path = RxSwift/Schedulers/Internal/InvocableType.swift; sourceTree = ""; }; - B37BB553F77A15D0B8A8BF3B70F5F2FC /* RxSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxSwift-Info.plist"; sourceTree = ""; }; - B65E171AC22F631D21200DB4EBE231AB /* Reduce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reduce.swift; path = RxSwift/Observables/Reduce.swift; sourceTree = ""; }; - B66FDBB09F58822C66816A25FA954182 /* Sink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sink.swift; path = RxSwift/Observables/Sink.swift; sourceTree = ""; }; - B6F99B771E28A26E71C366754C343D1C /* Multicast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Multicast.swift; path = RxSwift/Observables/Multicast.swift; sourceTree = ""; }; - B7B0F7B6582F69152A462C140699234A /* BinaryDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BinaryDisposable.swift; path = RxSwift/Disposables/BinaryDisposable.swift; sourceTree = ""; }; + AA9819C64B1BDB53C623124B5A3A9F6D /* Bag+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Bag+Rx.swift"; path = "RxSwift/Extensions/Bag+Rx.swift"; sourceTree = ""; }; + ABBAAC34E04605A6F459AC797C8D0213 /* Do.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Do.swift; path = RxSwift/Observables/Do.swift; sourceTree = ""; }; + ACCDD1317DD115FE47EBE54B4E319877 /* SynchronizedUnsubscribeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedUnsubscribeType.swift; path = RxSwift/Concurrency/SynchronizedUnsubscribeType.swift; sourceTree = ""; }; + ACE978FC15EDD537F57236BD94D063F1 /* DefaultIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultIfEmpty.swift; path = RxSwift/Observables/DefaultIfEmpty.swift; sourceTree = ""; }; + AD967D6DD7C1B506DBBD109F6EC99657 /* ReactiveSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ReactiveSwift-umbrella.h"; sourceTree = ""; }; + ADF76FE5BAD7F7167C22F55BF15B6A31 /* Timer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timer.swift; path = RxSwift/Observables/Timer.swift; sourceTree = ""; }; + AF2E65C764782E6ED7D1BAF868909BA1 /* Zip+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+Collection.swift"; path = "RxSwift/Observables/Zip+Collection.swift"; sourceTree = ""; }; + B07FF1E50CAC8390DB61819BFCA1EA82 /* ReactiveSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ReactiveSwift-prefix.pch"; sourceTree = ""; }; + B0CD6E465F1DC81CE057B393DA114935 /* Sink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sink.swift; path = RxSwift/Observables/Sink.swift; sourceTree = ""; }; + B11C0033F9533132D424D4B730C0F5E8 /* Enumerated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Enumerated.swift; path = RxSwift/Observables/Enumerated.swift; sourceTree = ""; }; + B2BD7C5430821B1797DDBB13A563C0DC /* SynchronizedOnType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedOnType.swift; path = RxSwift/Concurrency/SynchronizedOnType.swift; sourceTree = ""; }; + B3123C761FFF570332DAC5E7A8D5265F /* First.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = First.swift; path = RxSwift/Observables/First.swift; sourceTree = ""; }; + B38742F2A310BB91E002963C66EE18F9 /* RefCountDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RefCountDisposable.swift; path = RxSwift/Disposables/RefCountDisposable.swift; sourceTree = ""; }; + B409AEC546D48C982232951729CA8103 /* Merge.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Merge.swift; path = RxSwift/Observables/Merge.swift; sourceTree = ""; }; + B424B118CC6D52AF47567EC0DED4AB9E /* Property.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Property.swift; path = Sources/Property.swift; sourceTree = ""; }; + B83355F8333C2B35BD219E79655A71C6 /* MainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MainScheduler.swift; path = RxSwift/Schedulers/MainScheduler.swift; sourceTree = ""; }; + B874CAB52B08912C053A8E98E4F6B245 /* SkipWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipWhile.swift; path = RxSwift/Observables/SkipWhile.swift; sourceTree = ""; }; B9BA4B4DF4B788CF78C4FF5EAA77E3FB /* Pods-SpeedTestTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-SpeedTestTests-umbrella.h"; sourceTree = ""; }; - BC501375543E136ADE66E557A92401C9 /* Repeat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Repeat.swift; path = RxSwift/Observables/Repeat.swift; sourceTree = ""; }; - BC870E2DA4EA3A208D6CC128C774774A /* Empty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Empty.swift; path = RxSwift/Observables/Empty.swift; sourceTree = ""; }; - BC889F2478204688AA933DCF4693C636 /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; - C1997FB7E29CE3D6373F93A1ABF00097 /* ObserverType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverType.swift; path = RxSwift/ObserverType.swift; sourceTree = ""; }; - C231C2128176D458FC8B7DCD727AD97C /* GroupedObservable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupedObservable.swift; path = RxSwift/GroupedObservable.swift; sourceTree = ""; }; - C47D23DFB0E9DBCD27717F395BD82A96 /* Lock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Lock.swift; path = RxSwift/Concurrency/Lock.swift; sourceTree = ""; }; - C56FF046AD8A4053530C22905A5A7C7D /* CombineLatest+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+arity.swift"; path = "RxSwift/Observables/CombineLatest+arity.swift"; sourceTree = ""; }; - C5A0F66C1F84A92178BD9484D19E319A /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentMainScheduler.swift; path = RxSwift/Schedulers/ConcurrentMainScheduler.swift; sourceTree = ""; }; - C65FC7CD4FFA07D7C5C259EF2B050391 /* PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PrimitiveSequence.swift; path = RxSwift/Traits/PrimitiveSequence.swift; sourceTree = ""; }; + BAFF4A1222A4EE1E936576B5E281863F /* LockOwnerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LockOwnerType.swift; path = RxSwift/Concurrency/LockOwnerType.swift; sourceTree = ""; }; + BCA627C08DB6947FE4A75C6CDE0A913A /* String+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "String+Rx.swift"; path = "RxSwift/Extensions/String+Rx.swift"; sourceTree = ""; }; + BCB5F4845E6E32094586D7AC473EC638 /* RxSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxSwift-dummy.m"; sourceTree = ""; }; + BF43252AFDF541A39F6083C7C0410D3C /* Disposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposable.swift; path = Sources/Disposable.swift; sourceTree = ""; }; + BFAADB332B016CC2E05DC377A4586CAA /* AnyObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyObserver.swift; path = RxSwift/AnyObserver.swift; sourceTree = ""; }; + C2010CDEC317A362AB9FACE331E38718 /* Just.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Just.swift; path = RxSwift/Observables/Just.swift; sourceTree = ""; }; + C46373391CDCBA2FF4C663E4F1263F62 /* Deprecations+Removals.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Deprecations+Removals.swift"; path = "Sources/Deprecations+Removals.swift"; sourceTree = ""; }; + C591009344E52A280A0DF1010217A26B /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; + C6E4A009A9456241DE76D86AA92CE87C /* Single.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Single.swift; path = RxSwift/Traits/Single.swift; sourceTree = ""; }; + C8B7FD477438657A51429AB16E2B6854 /* CombineLatest+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+Collection.swift"; path = "RxSwift/Observables/CombineLatest+Collection.swift"; sourceTree = ""; }; + C947A95C4B3D381C602A417EFD72787C /* SerialDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDispatchQueueScheduler.swift; path = RxSwift/Schedulers/SerialDispatchQueueScheduler.swift; sourceTree = ""; }; + C959E1A895BC2404A85BAF49A8A3F698 /* CompactMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompactMap.swift; path = RxSwift/Observables/CompactMap.swift; sourceTree = ""; }; C9B3305EA69073D0BE455F1A2E7329AE /* Pods-SpeedTestTests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-SpeedTestTests-Info.plist"; sourceTree = ""; }; - CB4607EFCA7C5F75397649E792E2AFCB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - CCC8DB7E83D31D79474DDEB93766B06F /* Completable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Completable.swift; path = RxSwift/Traits/Completable.swift; sourceTree = ""; }; - CD607973F7533D994C5BAF02DB65BF8E /* Timer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timer.swift; path = RxSwift/Observables/Timer.swift; sourceTree = ""; }; - CDEAED7C0CE5E328FBEF2211BB04FC98 /* DefaultIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultIfEmpty.swift; path = RxSwift/Observables/DefaultIfEmpty.swift; sourceTree = ""; }; - D2BBE46A95AB6C7F71E42E35BA96CD78 /* SwiftSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftSupport.swift; path = RxSwift/SwiftSupport/SwiftSupport.swift; sourceTree = ""; }; - D493DD6B080AC568B6FA0618686C3D76 /* Do.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Do.swift; path = RxSwift/Observables/Do.swift; sourceTree = ""; }; - D6EA9BD9058FCE9132A39EEBF8AEF716 /* Date+Dispatch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Date+Dispatch.swift"; path = "RxSwift/Date+Dispatch.swift"; sourceTree = ""; }; - D7C122750E8C0F3A45FD8E0DBDFDC8F9 /* Create.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Create.swift; path = RxSwift/Observables/Create.swift; sourceTree = ""; }; - D7E3BFCE0B1839472BF8C261911036EC /* Buffer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Buffer.swift; path = RxSwift/Observables/Buffer.swift; sourceTree = ""; }; - D82409C496F92C2FEFC48A70F451BDB1 /* Disposables.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposables.swift; path = RxSwift/Disposables/Disposables.swift; sourceTree = ""; }; - DA7DB61CF15B4BA52CBDB3F60C68DBB8 /* CurrentThreadScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CurrentThreadScheduler.swift; path = RxSwift/Schedulers/CurrentThreadScheduler.swift; sourceTree = ""; }; - DAC198B408CE132567385BC58F92959D /* Debounce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debounce.swift; path = RxSwift/Observables/Debounce.swift; sourceTree = ""; }; - DD47069C123FA0ACB2DCBE886D7B3BC1 /* Single.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Single.swift; path = RxSwift/Traits/Single.swift; sourceTree = ""; }; - DE7BD84048A07F9A732906E15927E2F5 /* RxSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-prefix.pch"; sourceTree = ""; }; - E16A1D9EAA7F04D2D367D496695C0FCD /* DispatchQueueConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DispatchQueueConfiguration.swift; path = RxSwift/Schedulers/Internal/DispatchQueueConfiguration.swift; sourceTree = ""; }; - E1F6C870393D220B3AF7BFDFDE76E6AA /* SingleAssignmentDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAssignmentDisposable.swift; path = RxSwift/Disposables/SingleAssignmentDisposable.swift; sourceTree = ""; }; - E2A0EED0C095518127F9A305A5070650 /* Deprecated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deprecated.swift; path = RxSwift/Deprecated.swift; sourceTree = ""; }; - E3CB1DE79E00A059411D7A8112BBA296 /* SubjectType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubjectType.swift; path = RxSwift/Subjects/SubjectType.swift; sourceTree = ""; }; - E48DDFC33C9573D6329F36C2CC9EF9D3 /* ObservableType+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+Extensions.swift"; path = "RxSwift/ObservableType+Extensions.swift"; sourceTree = ""; }; - E49710A6B497C193740AF6A425589D07 /* Amb.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Amb.swift; path = RxSwift/Observables/Amb.swift; sourceTree = ""; }; - E4DE329BEF1CB87ED4F38CA6ADFD7B9F /* RefCountDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RefCountDisposable.swift; path = RxSwift/Disposables/RefCountDisposable.swift; sourceTree = ""; }; - E4E35C91B560F36745E6DDC9E2723BE1 /* DelaySubscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelaySubscription.swift; path = RxSwift/Observables/DelaySubscription.swift; sourceTree = ""; }; - E598BBB34F3194609B47FE65035F38FF /* Event.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Event.swift; path = RxSwift/Event.swift; sourceTree = ""; }; - E7551FC1EB41CFC063B934CDCB82C2E8 /* ObserveOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserveOn.swift; path = RxSwift/Observables/ObserveOn.swift; sourceTree = ""; }; - E7575A0C8D35E860B313DFA0AD7CF4F8 /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RxSwift/Observables/Optional.swift; sourceTree = ""; }; - E76EE1D6D327FBE42B802436B6E5DBBB /* RxSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxSwift.modulemap; sourceTree = ""; }; - E7CF663929B98F4C512EE9AE045E2B17 /* ElementAt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ElementAt.swift; path = RxSwift/Observables/ElementAt.swift; sourceTree = ""; }; - E975D5A109D443919A2684C7C1A0AF76 /* Bag+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Bag+Rx.swift"; path = "RxSwift/Extensions/Bag+Rx.swift"; sourceTree = ""; }; - EB6F7DE7EB92D46B5A113578044EB90B /* TakeWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeWhile.swift; path = RxSwift/Observables/TakeWhile.swift; sourceTree = ""; }; + CAA2F528B005F78152AD33DED8EBE235 /* Catch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Catch.swift; path = RxSwift/Observables/Catch.swift; sourceTree = ""; }; + CBADBB25DFE793AD037F1C0D82996E78 /* Sample.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sample.swift; path = RxSwift/Observables/Sample.swift; sourceTree = ""; }; + CC2B98C06689F58B33FC5B6B75B3ECFB /* Empty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Empty.swift; path = RxSwift/Observables/Empty.swift; sourceTree = ""; }; + CCD084FB95A9B12E041CE8DC1339CC2E /* SchedulerServices+Emulation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerServices+Emulation.swift"; path = "RxSwift/Schedulers/SchedulerServices+Emulation.swift"; sourceTree = ""; }; + CCE221F334E6722B8B8416576482340F /* TakeLast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeLast.swift; path = RxSwift/Observables/TakeLast.swift; sourceTree = ""; }; + CE9C4D2AA2FEF93131A2797A7182576B /* StartWith.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StartWith.swift; path = RxSwift/Observables/StartWith.swift; sourceTree = ""; }; + CF52C1EC5F01AAC22B7276F4363EEB40 /* SkipUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipUntil.swift; path = RxSwift/Observables/SkipUntil.swift; sourceTree = ""; }; + D04399814E7A289CAF87D70B59DEDDB3 /* Observable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Observable.swift; path = RxSwift/Observable.swift; sourceTree = ""; }; + D25CF4C826D65F08417B0B3906BEE080 /* AsSingle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsSingle.swift; path = RxSwift/Observables/AsSingle.swift; sourceTree = ""; }; + D4A19D802A29C857DF55899C88835D2D /* PrimitiveSequence+Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PrimitiveSequence+Zip+arity.swift"; path = "RxSwift/Traits/PrimitiveSequence+Zip+arity.swift"; sourceTree = ""; }; + D5BD792020DA9F4954DB5E711B88A5C6 /* Switch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Switch.swift; path = RxSwift/Observables/Switch.swift; sourceTree = ""; }; + D6DF2E79A3DF6185ED45ED3C74E62AA5 /* ObserverType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverType.swift; path = RxSwift/ObserverType.swift; sourceTree = ""; }; + D7C86301CD1D600AA7E068851356C388 /* Create.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Create.swift; path = RxSwift/Observables/Create.swift; sourceTree = ""; }; + DAD80AB0E90EE946B2DE8AF20A063BFE /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = Sources/Optional.swift; sourceTree = ""; }; + DC01A9598EB317206B15721CCF44D4C5 /* GroupBy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupBy.swift; path = RxSwift/Observables/GroupBy.swift; sourceTree = ""; }; + DDA7EFAF3754E3204528DF074253BB8D /* ReplaySubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReplaySubject.swift; path = RxSwift/Subjects/ReplaySubject.swift; sourceTree = ""; }; + E388061D44B77E43C627EC5C2A1B5E74 /* ImmediateSchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImmediateSchedulerType.swift; path = RxSwift/ImmediateSchedulerType.swift; sourceTree = ""; }; + E44DC83C20BD673B98FD159AFE87D54D /* EventLogger.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EventLogger.swift; path = Sources/EventLogger.swift; sourceTree = ""; }; + E45A7C3937EA2BD7B809383A083E7570 /* Scheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Scheduler.swift; path = Sources/Scheduler.swift; sourceTree = ""; }; + E79C7C7361732EDC62CA930797D63904 /* ScheduledItemType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItemType.swift; path = RxSwift/Schedulers/Internal/ScheduledItemType.swift; sourceTree = ""; }; + E826AD57ED3060670F6A393595511FDB /* Reactive.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reactive.swift; path = RxSwift/Reactive.swift; sourceTree = ""; }; + E8480F4C4E69A22F23F4EFE5EB810864 /* SubscriptionDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscriptionDisposable.swift; path = RxSwift/Disposables/SubscriptionDisposable.swift; sourceTree = ""; }; + E8BDBB317A647BED7C8B9317AA9AA7EB /* UninhabitedTypeGuards.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UninhabitedTypeGuards.swift; path = Sources/UninhabitedTypeGuards.swift; sourceTree = ""; }; EC1A791AFE96CDA5622C47984E9BC9E3 /* Pods-SpeedTestTests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-SpeedTestTests-frameworks.sh"; sourceTree = ""; }; - EC859AD860BFB0BC7BF8DE756098E271 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; - F71B35B33118E267C791DF9671DB4B47 /* Pods_SpeedTestTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_SpeedTestTests.framework; path = "Pods-SpeedTestTests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; - F7508A87DAD82D00401628ED25840498 /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; - F82CA826788EB21CAED9AB7A61CB7289 /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; - F88A68DAFCA3F86B83387D36FC32E261 /* MainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MainScheduler.swift; path = RxSwift/Schedulers/MainScheduler.swift; sourceTree = ""; }; - F9757333012BF772F4247DF841ED7935 /* PrimitiveSequence+Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PrimitiveSequence+Zip+arity.swift"; path = "RxSwift/Traits/PrimitiveSequence+Zip+arity.swift"; sourceTree = ""; }; - FA469C34D0EF836534B9EEB63B256DC4 /* SubscriptionDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscriptionDisposable.swift; path = RxSwift/Disposables/SubscriptionDisposable.swift; sourceTree = ""; }; - FAEC2E787170816AAB96CBFA83740657 /* WithLatestFrom.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WithLatestFrom.swift; path = RxSwift/Observables/WithLatestFrom.swift; sourceTree = ""; }; - FB98879951B60465272D8B90E39AC845 /* RxMutableBox.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxMutableBox.swift; path = RxSwift/RxMutableBox.swift; sourceTree = ""; }; + ED97D9D6733783480CD6EDCCD6F85E0C /* ScheduledDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledDisposable.swift; path = RxSwift/Disposables/ScheduledDisposable.swift; sourceTree = ""; }; + F0C45A27DC8EC05EAF142135B5A67834 /* OperationQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OperationQueueScheduler.swift; path = RxSwift/Schedulers/OperationQueueScheduler.swift; sourceTree = ""; }; + F12C37CD0DFABEF2D597A81073377359 /* Range.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Range.swift; path = RxSwift/Observables/Range.swift; sourceTree = ""; }; + F16D73F7D479F3BE8DB88673189FB14D /* ResultExtensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ResultExtensions.swift; path = Sources/ResultExtensions.swift; sourceTree = ""; }; + F35D19B3B82D092F7F7F789F815CE5F4 /* Scan.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Scan.swift; path = RxSwift/Observables/Scan.swift; sourceTree = ""; }; + F4ED3B844E77EC35A3422774EAF7DED2 /* Lock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Lock.swift; path = RxSwift/Concurrency/Lock.swift; sourceTree = ""; }; + F6B50FBF38287E14A48A3EA4D745568F /* Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Rx.swift; path = RxSwift/Rx.swift; sourceTree = ""; }; + F7539FBA4DE081BA605E936BEF11D883 /* SignalProducer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SignalProducer.swift; path = Sources/SignalProducer.swift; sourceTree = ""; }; + F87D9465992CEA630BE417FC7868C484 /* ReactiveSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = ReactiveSwift.framework; path = ReactiveSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FA37B00D4300ADEDF8FB73363425EED4 /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = RxSwift/Observables/Map.swift; sourceTree = ""; }; + FEEF26419AC066446518D9D171E49E3A /* ObservableConvertibleType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableConvertibleType.swift; path = RxSwift/ObservableConvertibleType.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - BB85F7563AB3CF76548A6A1C5F42386B /* Frameworks */ = { + 21DCC03C18A3D3A7DBF8862FA68ACF8E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 695C2D0242295C6450A7F6330471B7FC /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 288823AF5218F8F6B06C8CC968BCA871 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 850F7D942640C8F0E58A143E37BECC21 /* Foundation.framework in Frameworks */, + 88109443D950C6F779C61E28D56DDEC0 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - D35F3B0FC7A8DC9668DD9C9E59961C60 /* Frameworks */ = { + C58E2F060D702FFE777DDC011439D502 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 94E59D1A5AF689747AB1EFA5B2A8C6BA /* Foundation.framework in Frameworks */, + C57A6C666E9D7EB9B8B38E60A284E278 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 075F35518886A09EA1FA6CEF10019317 /* Pods */ = { + isa = PBXGroup; + children = ( + 7B1D22AB6BDB9B6E037C73661A61A548 /* ReactiveSwift */, + 102D5EB33787F1B18D94F78DA31F4892 /* RxSwift */, + ); + name = Pods; + sourceTree = ""; + }; + 102D5EB33787F1B18D94F78DA31F4892 /* RxSwift */ = { + isa = PBXGroup; + children = ( + A433E0251ADE40C48B64D32E0A65A7D8 /* AddRef.swift */, + 1E1AB48B54F45F5054FEA5BBF90FFB20 /* Amb.swift */, + 1FFC42154BD2B0451000470877BCA75C /* AnonymousDisposable.swift */, + 6C6F5D5B3FB6C9FE9802A1F9DA2041FD /* AnonymousObserver.swift */, + BFAADB332B016CC2E05DC377A4586CAA /* AnyObserver.swift */, + 0FD23B77696683254C845D9E7270FA25 /* AsMaybe.swift */, + D25CF4C826D65F08417B0B3906BEE080 /* AsSingle.swift */, + A674F1C4A77CEB37A6FD4B0FE8BB0906 /* AsyncLock.swift */, + 943CDB8979A44F79605D7C581CC55580 /* AsyncSubject.swift */, + 222E3B261C4A898F9728230C4E6C5472 /* AtomicInt.swift */, + 46021142BE4F3C15C44B2A173CE263BE /* Bag.swift */, + AA9819C64B1BDB53C623124B5A3A9F6D /* Bag+Rx.swift */, + 38D97D3F5C1CED6E78333D1549277688 /* BehaviorSubject.swift */, + 71129D9105A5E651FC2CCCE7A999E48F /* BinaryDisposable.swift */, + 16EB310540F44ECD13B956664981373D /* BooleanDisposable.swift */, + 48142E2FA28D3DBCD712308F4F24CC0E /* Buffer.swift */, + 6416D38D72ECCD0E5291778D21F53FA4 /* Cancelable.swift */, + CAA2F528B005F78152AD33DED8EBE235 /* Catch.swift */, + 26F407D14E1493E8D4AA3049C0C2B293 /* CombineLatest.swift */, + 06F04DA2BBEFB1AB011376B20BA92415 /* CombineLatest+arity.swift */, + C8B7FD477438657A51429AB16E2B6854 /* CombineLatest+Collection.swift */, + C959E1A895BC2404A85BAF49A8A3F698 /* CompactMap.swift */, + 1CB2E417378373476655F23897B7D0F4 /* Completable.swift */, + 3A500E1DCDAA1AEEDDED3611CAB37647 /* Completable+AndThen.swift */, + A16E1DE0980686599F47F6830A6E6529 /* CompositeDisposable.swift */, + 10580DF14A779C6A0F3A26B5266A0C65 /* Concat.swift */, + 1111163020378F1263875AF87327EA2B /* ConcurrentDispatchQueueScheduler.swift */, + 136C533FBAD2065CF922C5D4178507F4 /* ConcurrentMainScheduler.swift */, + 416A696DE5B535AEA1BF453FA1E2154C /* ConnectableObservableType.swift */, + D7C86301CD1D600AA7E068851356C388 /* Create.swift */, + A6935DBC6D830FA58B6F00DE6F939916 /* CurrentThreadScheduler.swift */, + 8180670A16C2146033A448DD77D9294C /* Date+Dispatch.swift */, + 86B612D0B2C41C3A1CA70200986B23EA /* Debounce.swift */, + 1B743B5D3AD8D6EAC35F09B4A07ED221 /* Debug.swift */, + ACE978FC15EDD537F57236BD94D063F1 /* DefaultIfEmpty.swift */, + 818CDCC1E417ACEF273725C82FB518EE /* Deferred.swift */, + 5EBC60B461BE55F69A204B8D1E281A2E /* Delay.swift */, + 43A45F8546554D26D53520E66037989F /* DelaySubscription.swift */, + 9C1367B7E3A62B3918270152C10ED32C /* Dematerialize.swift */, + 7B8DC00B4257C11ED799A9297843DF7F /* Deprecated.swift */, + 47C1149F3C5794854FE51478609C957B /* DispatchQueue+Extensions.swift */, + 7EA8A7E536DA0583DA76D23A47117F6D /* DispatchQueueConfiguration.swift */, + 38A9FE71D02057E76EF25465B491DD11 /* Disposable.swift */, + 49952D18F2FE454FC6B0BB584E3C87AE /* Disposables.swift */, + 6BCEDB95F6A4FB5CF35F3D125C63AF3F /* DisposeBag.swift */, + 0CCBA2716A417112FA97C9221DE72681 /* DisposeBase.swift */, + 464ECD6DA7A1EBCAD3C85E4F28EB6AC8 /* DistinctUntilChanged.swift */, + ABBAAC34E04605A6F459AC797C8D0213 /* Do.swift */, + 7CCA9B21D16565E6B165F12FCD70EAD9 /* ElementAt.swift */, + CC2B98C06689F58B33FC5B6B75B3ECFB /* Empty.swift */, + B11C0033F9533132D424D4B730C0F5E8 /* Enumerated.swift */, + 6FBCAD665FA5718C63FEB7C456EA3B63 /* Error.swift */, + 7F6583D7F8E68A885F2F1E9517A44634 /* Errors.swift */, + 33B8DBF05C340F518F9850ECF1DB48AF /* Event.swift */, + 881F24B385762FFB15EF37D3340405A9 /* Filter.swift */, + B3123C761FFF570332DAC5E7A8D5265F /* First.swift */, + 6FFC2FD1DCB87A14C1D7C2EF0A07D425 /* Generate.swift */, + DC01A9598EB317206B15721CCF44D4C5 /* GroupBy.swift */, + 6D84DC35F26963DA11DAAC90A4577765 /* GroupedObservable.swift */, + 70FA50883E931662880526F3DD1C230A /* HistoricalScheduler.swift */, + 75DA0DA36E5BBDC292DE099BD1B06DC9 /* HistoricalSchedulerTimeConverter.swift */, + E388061D44B77E43C627EC5C2A1B5E74 /* ImmediateSchedulerType.swift */, + 9A72063DAB47887233C0B02410F2A229 /* InfiniteSequence.swift */, + 86BE5495FD6250F9A47065F2E24D9B97 /* InvocableScheduledItem.swift */, + 2718EE1F40BF5A72D9410328CFC72747 /* InvocableType.swift */, + C2010CDEC317A362AB9FACE331E38718 /* Just.swift */, + F4ED3B844E77EC35A3422774EAF7DED2 /* Lock.swift */, + BAFF4A1222A4EE1E936576B5E281863F /* LockOwnerType.swift */, + B83355F8333C2B35BD219E79655A71C6 /* MainScheduler.swift */, + FA37B00D4300ADEDF8FB73363425EED4 /* Map.swift */, + 4223D4EC521F560272A60443E84F13CE /* Materialize.swift */, + 23CED774E31E8B168D85D4ECCB042643 /* Maybe.swift */, + B409AEC546D48C982232951729CA8103 /* Merge.swift */, + 04977683CA90E6037B7707BE7DFB710B /* Multicast.swift */, + 3CC9CE34F10A9A35653402267C9460B4 /* Never.swift */, + 85B624ACBF9E210375CB613F46F660F9 /* NopDisposable.swift */, + D04399814E7A289CAF87D70B59DEDDB3 /* Observable.swift */, + FEEF26419AC066446518D9D171E49E3A /* ObservableConvertibleType.swift */, + 3AA28D955567B852298A5D87F02C8F21 /* ObservableType.swift */, + 124140C3CF78161EFF9502BEFB068507 /* ObservableType+Extensions.swift */, + 849055E8CB8F92B218DD19C216FF0EFB /* ObservableType+PrimitiveSequence.swift */, + 4C3E65B33B2FF09471EBD74DB3EDA751 /* ObserveOn.swift */, + 5C8E6A92293F2ECD8AEC67D1A3A07ACE /* ObserverBase.swift */, + D6DF2E79A3DF6185ED45ED3C74E62AA5 /* ObserverType.swift */, + F0C45A27DC8EC05EAF142135B5A67834 /* OperationQueueScheduler.swift */, + 4C2AADA46DDBDFA4BC647000AB189C5F /* Optional.swift */, + 64AF9C701AE2F9B64D1B7D8629BABFA2 /* Platform.Darwin.swift */, + C591009344E52A280A0DF1010217A26B /* Platform.Linux.swift */, + 0C1A16308DDE5843D95C4F85B11025A5 /* PrimitiveSequence.swift */, + D4A19D802A29C857DF55899C88835D2D /* PrimitiveSequence+Zip+arity.swift */, + 1ECA604A47966C4735B434BC6DA2A177 /* PriorityQueue.swift */, + 0D88A5563A68F78D8FB9E7641A78E3E6 /* Producer.swift */, + 141B8F8F6CBEC21B549FDDFDA7A2DB5E /* PublishSubject.swift */, + 87D64E6ABAEEBF0D658153E5F00563F6 /* Queue.swift */, + F12C37CD0DFABEF2D597A81073377359 /* Range.swift */, + E826AD57ED3060670F6A393595511FDB /* Reactive.swift */, + 1605D69B978CEFB408B33EBD19332CE5 /* RecursiveLock.swift */, + 6F82671F5C0E6F66A1EDBAB6223A396E /* RecursiveScheduler.swift */, + 2F7EC7A583D5177AAF95BAA2F69F7A4D /* Reduce.swift */, + B38742F2A310BB91E002963C66EE18F9 /* RefCountDisposable.swift */, + 0C79D1BC58EA7994FC6EED8B1420E21C /* Repeat.swift */, + DDA7EFAF3754E3204528DF074253BB8D /* ReplaySubject.swift */, + 9260027C815A321953195CEC95FA2E30 /* RetryWhen.swift */, + F6B50FBF38287E14A48A3EA4D745568F /* Rx.swift */, + 1D5902520E2FB22A99F6E2D48C484ECC /* RxMutableBox.swift */, + CBADBB25DFE793AD037F1C0D82996E78 /* Sample.swift */, + F35D19B3B82D092F7F7F789F815CE5F4 /* Scan.swift */, + ED97D9D6733783480CD6EDCCD6F85E0C /* ScheduledDisposable.swift */, + 54177EB2B2D573E374DE620CD8A07E2D /* ScheduledItem.swift */, + E79C7C7361732EDC62CA930797D63904 /* ScheduledItemType.swift */, + CCD084FB95A9B12E041CE8DC1339CC2E /* SchedulerServices+Emulation.swift */, + 4A165B3B061C9B1D4DC8E5DAB9DDABFF /* SchedulerType.swift */, + 038F225C8F23D07ACF31BD010CEC3FCB /* Sequence.swift */, + C947A95C4B3D381C602A417EFD72787C /* SerialDispatchQueueScheduler.swift */, + 2AD71EE6B56554451CC09C0D11A557E0 /* SerialDisposable.swift */, + 03900D108AD7A7765B68240EB9313869 /* ShareReplayScope.swift */, + C6E4A009A9456241DE76D86AA92CE87C /* Single.swift */, + 4A6A401C28480D667C988A1F6BE1FB42 /* SingleAssignmentDisposable.swift */, + 909ED74747DC5BACB9C55AEA4D0BAA23 /* SingleAsync.swift */, + B0CD6E465F1DC81CE057B393DA114935 /* Sink.swift */, + 9F9DF2C471E8F5A446BD5F3B2AF64751 /* Skip.swift */, + CF52C1EC5F01AAC22B7276F4363EEB40 /* SkipUntil.swift */, + B874CAB52B08912C053A8E98E4F6B245 /* SkipWhile.swift */, + CE9C4D2AA2FEF93131A2797A7182576B /* StartWith.swift */, + BCA627C08DB6947FE4A75C6CDE0A913A /* String+Rx.swift */, + 560667B676984E93B5FB59D8F8187A64 /* SubjectType.swift */, + 60E6FE990DF652A3EBE755640EDBDF4E /* SubscribeOn.swift */, + E8480F4C4E69A22F23F4EFE5EB810864 /* SubscriptionDisposable.swift */, + 2BFC42BBC0266D0109E1356451424F81 /* SwiftSupport.swift */, + D5BD792020DA9F4954DB5E711B88A5C6 /* Switch.swift */, + 615F53F30FC4997851C4E179BC17969F /* SwitchIfEmpty.swift */, + 1B5CEE1040AA17B845C38191C8456105 /* SynchronizedDisposeType.swift */, + B2BD7C5430821B1797DDBB13A563C0DC /* SynchronizedOnType.swift */, + ACCDD1317DD115FE47EBE54B4E319877 /* SynchronizedUnsubscribeType.swift */, + 0E26795766A973976E8862FBFF103408 /* TailRecursiveSink.swift */, + 0F6E10E62C00A66FF62AD38BB7E783BD /* Take.swift */, + CCE221F334E6722B8B8416576482340F /* TakeLast.swift */, + 15A840CC90B8D3BAD9EABDD41BE16D71 /* TakeUntil.swift */, + 1977D8DBA9130EF0286977D17E0E3FB6 /* TakeWhile.swift */, + 26F8A06E7618E1B78B5D27A2C28BD7E2 /* Throttle.swift */, + 3EE7A7E598D75E301DFA1177AFF2BF15 /* Timeout.swift */, + ADF76FE5BAD7F7167C22F55BF15B6A31 /* Timer.swift */, + 1A7438B8B58F8F6E6C0219AFA0EDF56D /* ToArray.swift */, + 0C5B9A502A600B56D05F3A37BCCB082B /* Using.swift */, + 10F3B2BC25A8E02655B282CE7D407EC9 /* VirtualTimeConverterType.swift */, + 2A019FA65289E40EC9ED581F854C9D1C /* VirtualTimeScheduler.swift */, + 14490319BFBC29BB70901D29672A9AD1 /* Window.swift */, + 615A1505F8D5DC0674E4198FBD6E7E5C /* WithLatestFrom.swift */, + 14B6E7D3F989CC972FEEEA9E428FE9B7 /* Zip.swift */, + 9E0A10482D8F901E259114C0249A1261 /* Zip+arity.swift */, + AF2E65C764782E6ED7D1BAF868909BA1 /* Zip+Collection.swift */, + AA365B22335CFB372645F3CE417A3B2C /* Support Files */, + ); + name = RxSwift; + path = RxSwift; + sourceTree = ""; + }; 53943DB524275923B3FA621EED382052 /* Pods-SpeedTestTests */ = { isa = PBXGroup; children = ( @@ -386,26 +622,48 @@ path = "Target Support Files/Pods-SpeedTestTests"; sourceTree = ""; }; - 5855B69ED90913C271A4DA219F304817 /* Support Files */ = { + 7B1D22AB6BDB9B6E037C73661A61A548 /* ReactiveSwift */ = { isa = PBXGroup; children = ( - E76EE1D6D327FBE42B802436B6E5DBBB /* RxSwift.modulemap */, - 6D669D2B1969E2BCE4DED7161293460F /* RxSwift.xcconfig */, - 58746BF458A9D6B1B131E43917E1AC73 /* RxSwift-dummy.m */, - B37BB553F77A15D0B8A8BF3B70F5F2FC /* RxSwift-Info.plist */, - DE7BD84048A07F9A732906E15927E2F5 /* RxSwift-prefix.pch */, - 07E14D5018327B9D23E609DF824E4E36 /* RxSwift-umbrella.h */, + 7A9AB27F2A6CD3FB8B947176D0F228F1 /* Action.swift */, + 8AE71314BA1E364D614F9E15E41DD46E /* Atomic.swift */, + 928265E5C82E2CE242668268AB0AB7A4 /* Bag.swift */, + C46373391CDCBA2FF4C663E4F1263F62 /* Deprecations+Removals.swift */, + BF43252AFDF541A39F6083C7C0410D3C /* Disposable.swift */, + 41A4F32477479664F726767C4A01E7B5 /* Event.swift */, + E44DC83C20BD673B98FD159AFE87D54D /* EventLogger.swift */, + 8AA2345DD8FA01DA8C7F5C07DBAE80AE /* Flatten.swift */, + 0A89E0286754DC69A2D1F91523DB0495 /* FoundationExtensions.swift */, + 83600B5B0DF0A906401995187215ABE5 /* Lifetime.swift */, + 70235626E65FBDD5D1CC30E7EE6E55FD /* Observer.swift */, + DAD80AB0E90EE946B2DE8AF20A063BFE /* Optional.swift */, + B424B118CC6D52AF47567EC0DED4AB9E /* Property.swift */, + 0FFF244A5764C5A15DB00266892650A7 /* Reactive.swift */, + F16D73F7D479F3BE8DB88673189FB14D /* ResultExtensions.swift */, + E45A7C3937EA2BD7B809383A083E7570 /* Scheduler.swift */, + 616B57782F104485154E1B59EEEAF26B /* Signal.swift */, + F7539FBA4DE081BA605E936BEF11D883 /* SignalProducer.swift */, + 096A461278DBA4D9E3790AD0153012E1 /* UnidirectionalBinding.swift */, + E8BDBB317A647BED7C8B9317AA9AA7EB /* UninhabitedTypeGuards.swift */, + 144D91B492709EDF6F03EF19CB81501D /* ValidatingProperty.swift */, + 92977A13BAA3D10CBB1E285663591554 /* Support Files */, ); - name = "Support Files"; - path = "../Target Support Files/RxSwift"; + name = ReactiveSwift; + path = ReactiveSwift; sourceTree = ""; }; - 9B055D0CFEA43187E72B03DED11F5662 /* iOS */ = { + 92977A13BAA3D10CBB1E285663591554 /* Support Files */ = { isa = PBXGroup; children = ( - CB4607EFCA7C5F75397649E792E2AFCB /* Foundation.framework */, + 73CC285A0970DA08D4D96C90682B76EC /* ReactiveSwift.modulemap */, + A7DA933C1F6993AD9DB4BF3D9250B705 /* ReactiveSwift.xcconfig */, + 358DDDE9642A15D1B039CFB3DB084775 /* ReactiveSwift-dummy.m */, + 1BF49369D912E56427765EDB1A95D9A1 /* ReactiveSwift-Info.plist */, + B07FF1E50CAC8390DB61819BFCA1EA82 /* ReactiveSwift-prefix.pch */, + AD967D6DD7C1B506DBBD109F6EC99657 /* ReactiveSwift-umbrella.h */, ); - name = iOS; + name = "Support Files"; + path = "../Target Support Files/ReactiveSwift"; sourceTree = ""; }; 9C97081076FB0EF9E0F48F50E8158DD0 /* Targets Support Files */ = { @@ -416,172 +674,36 @@ name = "Targets Support Files"; sourceTree = ""; }; - AB41016C14448EEBCEF4242DC9717C8E /* RxSwift */ = { + AA365B22335CFB372645F3CE417A3B2C /* Support Files */ = { isa = PBXGroup; children = ( - 2274A4FABE921F12C377C27E8F92A9F3 /* AddRef.swift */, - E49710A6B497C193740AF6A425589D07 /* Amb.swift */, - 3E1B998F98983D222C15C2DA33E99B61 /* AnonymousDisposable.swift */, - 987D881E9A3A698D1447833FB87334FD /* AnonymousObserver.swift */, - 2F313DE547D913B19C56B7820225BA20 /* AnyObserver.swift */, - 8E7E771A623979EF95A322F1107FFEB8 /* AsMaybe.swift */, - 72EF4AC0B5074A2E29B2428B3A7E0ADE /* AsSingle.swift */, - 752F32A59CBBFCAA84277A6D86DCD2CD /* AsyncLock.swift */, - 55806A569FBE99EF1D5EF177F0E55541 /* AsyncSubject.swift */, - 50A45279A2F183B85BDD344D764EBE13 /* AtomicInt.swift */, - 7DE89160B0C8B1120FD3BE4D5135DFAC /* Bag.swift */, - E975D5A109D443919A2684C7C1A0AF76 /* Bag+Rx.swift */, - 7A5FEAF703A4D3E2E46A3F1554B8C0D5 /* BehaviorSubject.swift */, - B7B0F7B6582F69152A462C140699234A /* BinaryDisposable.swift */, - 4EB28BF72935934FB28144A700AB0054 /* BooleanDisposable.swift */, - D7E3BFCE0B1839472BF8C261911036EC /* Buffer.swift */, - 878F7DAE257E28A5866FE720753AA0AC /* Cancelable.swift */, - 70EE902503459EFA68F4E81979BA2222 /* Catch.swift */, - 9A787BC2076D63A7ACFD626D1DE5A9EC /* CombineLatest.swift */, - C56FF046AD8A4053530C22905A5A7C7D /* CombineLatest+arity.swift */, - 70B0F97F33E48BB3438584F09E674E10 /* CombineLatest+Collection.swift */, - 1C7AEFCBAE8882AB113116AC76B8D329 /* CompactMap.swift */, - CCC8DB7E83D31D79474DDEB93766B06F /* Completable.swift */, - 5E209853647CCABA40FF10E958258341 /* Completable+AndThen.swift */, - 48792B925801208B04C1CFF407072A42 /* CompositeDisposable.swift */, - 1FFBC6AC68411BAC76597A4912382BC2 /* Concat.swift */, - A17214F0A5E8878853A63430D553B610 /* ConcurrentDispatchQueueScheduler.swift */, - C5A0F66C1F84A92178BD9484D19E319A /* ConcurrentMainScheduler.swift */, - 376EB75F9B880D9FD1B6F2F45131CBDF /* ConnectableObservableType.swift */, - D7C122750E8C0F3A45FD8E0DBDFDC8F9 /* Create.swift */, - DA7DB61CF15B4BA52CBDB3F60C68DBB8 /* CurrentThreadScheduler.swift */, - D6EA9BD9058FCE9132A39EEBF8AEF716 /* Date+Dispatch.swift */, - DAC198B408CE132567385BC58F92959D /* Debounce.swift */, - 91CE9840E02A9CAC89AD1E42B4AF9C55 /* Debug.swift */, - CDEAED7C0CE5E328FBEF2211BB04FC98 /* DefaultIfEmpty.swift */, - 167B521463C24DAC8198866F49CB61AD /* Deferred.swift */, - 2A3E9F59FE2E8B99CF1A7161ACD4C312 /* Delay.swift */, - E4E35C91B560F36745E6DDC9E2723BE1 /* DelaySubscription.swift */, - AF4CDCFCAC74B4A6BB27AEC4F605B525 /* Dematerialize.swift */, - E2A0EED0C095518127F9A305A5070650 /* Deprecated.swift */, - EC859AD860BFB0BC7BF8DE756098E271 /* DispatchQueue+Extensions.swift */, - E16A1D9EAA7F04D2D367D496695C0FCD /* DispatchQueueConfiguration.swift */, - 9695003960CFCFCAB6973EF2930244D0 /* Disposable.swift */, - D82409C496F92C2FEFC48A70F451BDB1 /* Disposables.swift */, - 6BBDBEF351A55D2369D808A0B910D6B7 /* DisposeBag.swift */, - 651B56536404EDA63606BAD39BF3AA23 /* DisposeBase.swift */, - 67A66A067BB487D24B58DDE50654AF46 /* DistinctUntilChanged.swift */, - D493DD6B080AC568B6FA0618686C3D76 /* Do.swift */, - E7CF663929B98F4C512EE9AE045E2B17 /* ElementAt.swift */, - BC870E2DA4EA3A208D6CC128C774774A /* Empty.swift */, - 50232F56C3A7B75C934C7BC82692AF59 /* Enumerated.swift */, - AC232B350290EEFAF1C80C342AC435EB /* Error.swift */, - 8F60E23C9CDED9D731140F98B1118425 /* Errors.swift */, - E598BBB34F3194609B47FE65035F38FF /* Event.swift */, - 4A77F87BF09F886F0FFE5EE14CDD1BF9 /* Filter.swift */, - 932F8FCB03BF9A7A375D9E46B79444CF /* First.swift */, - 5E4EE54B0B8056EACFF23E79FC6FA13B /* Generate.swift */, - 181F7A0CAFDFC849A468C6C9C50F1C58 /* GroupBy.swift */, - C231C2128176D458FC8B7DCD727AD97C /* GroupedObservable.swift */, - 92286F3AF1F2E2EC69A9FF583722C8D1 /* HistoricalScheduler.swift */, - AA54B4558300360287F36AB44B39FE4C /* HistoricalSchedulerTimeConverter.swift */, - 069F01BC4A1392ED2E66E02E6339A8F3 /* ImmediateSchedulerType.swift */, - 0F6810A13B1F72B2F10E9B60A055ED2F /* InfiniteSequence.swift */, - 9139B8639FD885639FB93B756DD9B7E8 /* InvocableScheduledItem.swift */, - B2AD331471133FE73D9A9360C4D6FD06 /* InvocableType.swift */, - 07299265E8DC2DE35499F40E85D9F81C /* Just.swift */, - C47D23DFB0E9DBCD27717F395BD82A96 /* Lock.swift */, - 4E3E5057B9A128271581BCCBE98B7275 /* LockOwnerType.swift */, - F88A68DAFCA3F86B83387D36FC32E261 /* MainScheduler.swift */, - B07026266021D7A9212562587B8FF47D /* Map.swift */, - 769044E4D29F65C4310FC11D40304806 /* Materialize.swift */, - 306DE0E6D87978242135F33A6C4D5A1D /* Maybe.swift */, - 6D79FAFD822FBEB7CD95E9F70918B6F1 /* Merge.swift */, - B6F99B771E28A26E71C366754C343D1C /* Multicast.swift */, - 1C1C3C1D616B940D3BA19D47FEE9B3B2 /* Never.swift */, - 5D3E1B7821FAF644D9A989EA39898832 /* NopDisposable.swift */, - 0563003B44EC515724F308FCD3CD8193 /* Observable.swift */, - 87BA7F3696D6A4CC74082CA4873A8A96 /* ObservableConvertibleType.swift */, - 71C921D4C61C49477F7D45BF9F0D596A /* ObservableType.swift */, - E48DDFC33C9573D6329F36C2CC9EF9D3 /* ObservableType+Extensions.swift */, - 16D52A30C471E02F800ADCA71FEA34A2 /* ObservableType+PrimitiveSequence.swift */, - E7551FC1EB41CFC063B934CDCB82C2E8 /* ObserveOn.swift */, - 72B4B6D8E329E01070B008308A8C15EE /* ObserverBase.swift */, - C1997FB7E29CE3D6373F93A1ABF00097 /* ObserverType.swift */, - 2D20C0518E27696964A5D7E0A5E2D9BD /* OperationQueueScheduler.swift */, - E7575A0C8D35E860B313DFA0AD7CF4F8 /* Optional.swift */, - 594376167C7F58F7C62FAB5F552C508D /* Platform.Darwin.swift */, - 34A007B93A08FF145FCED1BCFF259603 /* Platform.Linux.swift */, - C65FC7CD4FFA07D7C5C259EF2B050391 /* PrimitiveSequence.swift */, - F9757333012BF772F4247DF841ED7935 /* PrimitiveSequence+Zip+arity.swift */, - BC889F2478204688AA933DCF4693C636 /* PriorityQueue.swift */, - 3288AFCEC296C92324275DCD605E92F7 /* Producer.swift */, - 181AFF6EE7661E0BD553B973424023DC /* PublishSubject.swift */, - F7508A87DAD82D00401628ED25840498 /* Queue.swift */, - 3BB96FC10EB906309699733BA4835AB6 /* Range.swift */, - 0CEE237A47CB832B82BE9AB11E02E3BE /* Reactive.swift */, - F82CA826788EB21CAED9AB7A61CB7289 /* RecursiveLock.swift */, - 33FD1981C6F35453F660B293D58E3CF7 /* RecursiveScheduler.swift */, - B65E171AC22F631D21200DB4EBE231AB /* Reduce.swift */, - E4DE329BEF1CB87ED4F38CA6ADFD7B9F /* RefCountDisposable.swift */, - BC501375543E136ADE66E557A92401C9 /* Repeat.swift */, - 6BDADF0926AD1A5EEB6ECC2DD4AC32FC /* ReplaySubject.swift */, - 52AAACBB14FE9BD1C035AD7F56B7A438 /* RetryWhen.swift */, - 4E5C36EB3E39AF68E36D08CCDA4C653A /* Rx.swift */, - FB98879951B60465272D8B90E39AC845 /* RxMutableBox.swift */, - 89EAB316B1E600239C78B09CE940E8F9 /* Sample.swift */, - 474F10EA67A5905D2AF0EDB7D4BF60DE /* Scan.swift */, - 3BE36BD7E39BF9D232A5347DAD9AC32C /* ScheduledDisposable.swift */, - 663E825CA6C7EADB658061705B9A6CB3 /* ScheduledItem.swift */, - 5617CC15404DAF3805EB0070B19BC157 /* ScheduledItemType.swift */, - 34E9FB2FDCD209FC08E7D6E73BC5CE8C /* SchedulerServices+Emulation.swift */, - AEF509447FD82026F923DD5E1C1FB989 /* SchedulerType.swift */, - AAE41578A30310AC2C7F256279DEB314 /* Sequence.swift */, - 4732CAC567AB9E6FC2ED425A091B661F /* SerialDispatchQueueScheduler.swift */, - 75D7D076BF1319E12D146579A1E3AA47 /* SerialDisposable.swift */, - 8D3D54E33FF3238304C7C9913E792B28 /* ShareReplayScope.swift */, - DD47069C123FA0ACB2DCBE886D7B3BC1 /* Single.swift */, - E1F6C870393D220B3AF7BFDFDE76E6AA /* SingleAssignmentDisposable.swift */, - 6BB07C02339DCC64F774319E1496DA6D /* SingleAsync.swift */, - B66FDBB09F58822C66816A25FA954182 /* Sink.swift */, - 6C9640FFD356546806E100F45E8A44FB /* Skip.swift */, - 9834F595A96BDB23A404BBB215DAB955 /* SkipUntil.swift */, - 72D303B43AC9702530301C44D37B20E6 /* SkipWhile.swift */, - 85A96C066DF600D628B06989E1DA8C23 /* StartWith.swift */, - 67DD374AA04E414FE2AE2F74B5AFDC60 /* String+Rx.swift */, - E3CB1DE79E00A059411D7A8112BBA296 /* SubjectType.swift */, - 01A7E7A407382AF5941B06CE4C7325DF /* SubscribeOn.swift */, - FA469C34D0EF836534B9EEB63B256DC4 /* SubscriptionDisposable.swift */, - D2BBE46A95AB6C7F71E42E35BA96CD78 /* SwiftSupport.swift */, - 58552F09308C4BB15C6E3C993A5B03CD /* Switch.swift */, - 19B2B2B7EB6B462C9BAF4D02BB1596B7 /* SwitchIfEmpty.swift */, - 33497C1B69A3756EC9868E624CEECE4C /* SynchronizedDisposeType.swift */, - 9FFCE1932228F377D03BCC121EDF4434 /* SynchronizedOnType.swift */, - 2E4173F63456BB3C1FE17283F5FCBB21 /* SynchronizedUnsubscribeType.swift */, - 3C0832711C1CFEAECBE58CEACA4813F3 /* TailRecursiveSink.swift */, - 2278F7BA462362D40764DC52273D2382 /* Take.swift */, - 2C845DF990EACA316A5B424082798634 /* TakeLast.swift */, - 7999131F2F79B776A2951B564923046F /* TakeUntil.swift */, - EB6F7DE7EB92D46B5A113578044EB90B /* TakeWhile.swift */, - A19B5A5B86E47172C1EBDAF854330561 /* Throttle.swift */, - 08DB7A2C782A192306FF01CCED728618 /* Timeout.swift */, - CD607973F7533D994C5BAF02DB65BF8E /* Timer.swift */, - 90610A4859390D4BC2483853E6A3AE85 /* ToArray.swift */, - 93E3B6350CE7DC6A8D4CA9C97AF58633 /* Using.swift */, - 93F23F6F42CC3531743DFE2134556E82 /* VirtualTimeConverterType.swift */, - 1EE4B540DCCB2925913C2EBAF3D9124C /* VirtualTimeScheduler.swift */, - 80F00E9F12804718CAA29E7808208EE1 /* Window.swift */, - FAEC2E787170816AAB96CBFA83740657 /* WithLatestFrom.swift */, - 012D7D176B48342A29FBBF46AFBD0624 /* Zip.swift */, - 29650A70429833A1243416EE598E3D43 /* Zip+arity.swift */, - 9EB728D69EE6493BDBE5D071062BB3C6 /* Zip+Collection.swift */, - 5855B69ED90913C271A4DA219F304817 /* Support Files */, + A5E2483DCCA8F64A1F4B7C2742B95039 /* RxSwift.modulemap */, + 883AAA7A0359C1678B657C204B29628B /* RxSwift.xcconfig */, + BCB5F4845E6E32094586D7AC473EC638 /* RxSwift-dummy.m */, + 066EA75C23239E88AFD38D843C35D737 /* RxSwift-Info.plist */, + 2CC16A8516226A1BC69001BEFD46F978 /* RxSwift-prefix.pch */, + 8AE2A60F25C513E34FABCFD5F06CEBF7 /* RxSwift-umbrella.h */, ); - name = RxSwift; - path = RxSwift; + name = "Support Files"; + path = "../Target Support Files/RxSwift"; sourceTree = ""; }; - ACEF89ABAB23E10C09A4FD86F4DFAFA0 /* Pods */ = { + C0834CEBB1379A84116EF29F93051C60 /* iOS */ = { isa = PBXGroup; children = ( - AB41016C14448EEBCEF4242DC9717C8E /* RxSwift */, + 3212113385A8FBBDB272BD23C409FF61 /* Foundation.framework */, ); - name = Pods; + name = iOS; + sourceTree = ""; + }; + C1CA39F12C06AAF1838D38E67D3B2377 /* Products */ = { + isa = PBXGroup; + children = ( + 137A5FDBD494F2E59438C6531490ECC5 /* Pods_SpeedTestTests.framework */, + F87D9465992CEA630BE417FC7868C484 /* ReactiveSwift.framework */, + 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift.framework */, + ); + name = Products; sourceTree = ""; }; CF1408CF629C7361332E53B88F7BD30C = { @@ -589,8 +711,8 @@ children = ( 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */, - ACEF89ABAB23E10C09A4FD86F4DFAFA0 /* Pods */, - E3DD824699C1FA92FF3EFF818C40953B /* Products */, + 075F35518886A09EA1FA6CEF10019317 /* Pods */, + C1CA39F12C06AAF1838D38E67D3B2377 /* Products */, 9C97081076FB0EF9E0F48F50E8158DD0 /* Targets Support Files */, ); sourceTree = ""; @@ -598,69 +720,87 @@ D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */ = { isa = PBXGroup; children = ( - 9B055D0CFEA43187E72B03DED11F5662 /* iOS */, + C0834CEBB1379A84116EF29F93051C60 /* iOS */, ); name = Frameworks; sourceTree = ""; }; - E3DD824699C1FA92FF3EFF818C40953B /* Products */ = { - isa = PBXGroup; - children = ( - F71B35B33118E267C791DF9671DB4B47 /* Pods_SpeedTestTests.framework */, - 0F4B8AAECAC0596375E5202E6005273B /* RxSwift.framework */, - ); - name = Products; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 365847BCF5F77060DF1A70851ED92EC4 /* Headers */ = { + 4282C4B70C220AE888F7D7F92B7BA92B /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - C3F119E2B62D5E076C9F556FB70806E6 /* RxSwift-umbrella.h in Headers */, + DAEB3A87FF8A72A708FC186BE709D6BB /* Pods-SpeedTestTests-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - A9F4EF7DE4A145DB2575E985A26326C3 /* Headers */ = { + 6C1FB177E1FB48651D8FE952FDFD1CDC /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 71C71ECD882C26578FB10F663A557AA3 /* Pods-SpeedTestTests-umbrella.h in Headers */, + 5B656B6DEFBB0EF2BECA60932689A8B7 /* RxSwift-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 93ED68EA70AE940ECB2AF79F9EE5C064 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 259BE7147C34DF767EE744B3370963A3 /* ReactiveSwift-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 08B8EF1A02DE30CBEFB370FFE1C123C0 /* ReactiveSwift */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9D6C9C10B9D662B4303FC0EBFF60D63D /* Build configuration list for PBXNativeTarget "ReactiveSwift" */; + buildPhases = ( + 93ED68EA70AE940ECB2AF79F9EE5C064 /* Headers */, + E58294C5CD13B5C7810347D725B24640 /* Sources */, + C58E2F060D702FFE777DDC011439D502 /* Frameworks */, + 0722D854B69D944AA8ACD9451E84653D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ReactiveSwift; + productName = ReactiveSwift; + productReference = F87D9465992CEA630BE417FC7868C484 /* ReactiveSwift.framework */; + productType = "com.apple.product-type.framework"; + }; 7D3C7B92C1D6DBA09BA4753E951685ED /* Pods-SpeedTestTests */ = { isa = PBXNativeTarget; - buildConfigurationList = D237D7827D02D0A342678F891BAB388A /* Build configuration list for PBXNativeTarget "Pods-SpeedTestTests" */; + buildConfigurationList = D8416090F9D7F3A40C106DE8A00C8E94 /* Build configuration list for PBXNativeTarget "Pods-SpeedTestTests" */; buildPhases = ( - A9F4EF7DE4A145DB2575E985A26326C3 /* Headers */, - 565D4471CB7F43C63844B71C201BC6B2 /* Sources */, - BB85F7563AB3CF76548A6A1C5F42386B /* Frameworks */, - 3DF0565141AF7C16CF2B34A18DC3E331 /* Resources */, + 4282C4B70C220AE888F7D7F92B7BA92B /* Headers */, + 363DE8422047FDE52F6BC65A9D7D80FD /* Sources */, + 288823AF5218F8F6B06C8CC968BCA871 /* Frameworks */, + B03559AFAB04B4DF00ED29065313D6C8 /* Resources */, ); buildRules = ( ); dependencies = ( - B4B97E334B82359D1EC659C825B48753 /* PBXTargetDependency */, + FF339DC4158EAB1A978F62ACFB72AEAB /* PBXTargetDependency */, + B486CCC699F83E86F20096972F7B71CB /* PBXTargetDependency */, ); name = "Pods-SpeedTestTests"; productName = "Pods-SpeedTestTests"; - productReference = F71B35B33118E267C791DF9671DB4B47 /* Pods_SpeedTestTests.framework */; + productReference = 137A5FDBD494F2E59438C6531490ECC5 /* Pods_SpeedTestTests.framework */; productType = "com.apple.product-type.framework"; }; EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */ = { isa = PBXNativeTarget; - buildConfigurationList = 4BEA5E9C5F5F5EBD0F134084E82F1CB7 /* Build configuration list for PBXNativeTarget "RxSwift" */; + buildConfigurationList = 5EA291D224EF14DF4C5B0CC4FF5AFBE6 /* Build configuration list for PBXNativeTarget "RxSwift" */; buildPhases = ( - 365847BCF5F77060DF1A70851ED92EC4 /* Headers */, - 84FA7E29AA3E2966C44CF1503CB4782C /* Sources */, - D35F3B0FC7A8DC9668DD9C9E59961C60 /* Frameworks */, - 02B592865E1E60AED9B508C22F7257F7 /* Resources */, + 6C1FB177E1FB48651D8FE952FDFD1CDC /* Headers */, + 15F68CE2AA11870693EAE0F1FD72E434 /* Sources */, + 21DCC03C18A3D3A7DBF8862FA68ACF8E /* Frameworks */, + 7EBBBA5481E0DA601CDB02D6A9107A2D /* Resources */, ); buildRules = ( ); @@ -668,7 +808,7 @@ ); name = RxSwift; productName = RxSwift; - productReference = 0F4B8AAECAC0596375E5202E6005273B /* RxSwift.framework */; + productReference = 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ @@ -677,36 +817,44 @@ BFDFE7DC352907FC980B868725387E98 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0930; - LastUpgradeCheck = 0930; + LastSwiftUpdateCheck = 1100; + LastUpgradeCheck = 1100; }; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 10.0"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = CF1408CF629C7361332E53B88F7BD30C; - productRefGroup = E3DD824699C1FA92FF3EFF818C40953B /* Products */; + productRefGroup = C1CA39F12C06AAF1838D38E67D3B2377 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 7D3C7B92C1D6DBA09BA4753E951685ED /* Pods-SpeedTestTests */, + 08B8EF1A02DE30CBEFB370FFE1C123C0 /* ReactiveSwift */, EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 02B592865E1E60AED9B508C22F7257F7 /* Resources */ = { + 0722D854B69D944AA8ACD9451E84653D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7EBBBA5481E0DA601CDB02D6A9107A2D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 3DF0565141AF7C16CF2B34A18DC3E331 /* Resources */ = { + B03559AFAB04B4DF00ED29065313D6C8 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -716,254 +864,259 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 565D4471CB7F43C63844B71C201BC6B2 /* Sources */ = { + 15F68CE2AA11870693EAE0F1FD72E434 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 43B16DDB3D5918D5311750AECA0852E2 /* Pods-SpeedTestTests-dummy.m in Sources */, + 4018D04EFFFB41BAFDAF771A46D17190 /* AddRef.swift in Sources */, + 6C5A4DBCACAFC5842E6C0C0BB405CF8D /* Amb.swift in Sources */, + 2066B802CD5EE10B7EB31F45087771E7 /* AnonymousDisposable.swift in Sources */, + E060A3B61583147855DDF23368350929 /* AnonymousObserver.swift in Sources */, + 816C318B7A7D7C24E6017545558780FF /* AnyObserver.swift in Sources */, + 9CEAF2A6B8551ECED2EA3897DAD37D61 /* AsMaybe.swift in Sources */, + DD69FC6190FB0C4D8574932D64296693 /* AsSingle.swift in Sources */, + 0CE9B22B9CF1D6BAAB6818B655C3BAA8 /* AsyncLock.swift in Sources */, + F023436537FB3460AA7073BCFFD078AA /* AsyncSubject.swift in Sources */, + 9A8362B931B67A195EEF99D1D5787C95 /* AtomicInt.swift in Sources */, + E822E6FCFDEB95CF949DBC5FE59C2745 /* Bag+Rx.swift in Sources */, + 7D28D11F4FAA31632DB2CF1BC29AD441 /* Bag.swift in Sources */, + 35C8E014E23B79DD2E81F9A3CB06CBF8 /* BehaviorSubject.swift in Sources */, + 0BDC3CA3A6146B13A9888F7C07BC4722 /* BinaryDisposable.swift in Sources */, + 41479B8E61A8D1F6D9BD7DDDE0A3D3FF /* BooleanDisposable.swift in Sources */, + BD95E4BC718104C84F7851658AA3FE29 /* Buffer.swift in Sources */, + F996F714EC4FD3EE059CCCF0E8F9E7A2 /* Cancelable.swift in Sources */, + 52959B2DBDABF67EE84B668630D99958 /* Catch.swift in Sources */, + 24F634748E68CD7B8226EBBB45E3F30C /* CombineLatest+arity.swift in Sources */, + 7C689B24B97556FCD447B4D32C40D0ED /* CombineLatest+Collection.swift in Sources */, + 5E6945651475F73AB34C1AEBE937013C /* CombineLatest.swift in Sources */, + 5DC99ECACE479596E644115F745B38E6 /* CompactMap.swift in Sources */, + B73FAE22FC2C65D60C28A64E77052EB4 /* Completable+AndThen.swift in Sources */, + 4F53CECC2B262774607D98C45C5F7CE8 /* Completable.swift in Sources */, + A34F91EC384833CC0A348278A208992E /* CompositeDisposable.swift in Sources */, + ABD7FB4FA4E20A445F2528C91486D9C3 /* Concat.swift in Sources */, + C6FFB5DC01D6D855057BDB7B9D3C3C7D /* ConcurrentDispatchQueueScheduler.swift in Sources */, + D88D1773D62A011C69B6EBC40C976BEB /* ConcurrentMainScheduler.swift in Sources */, + 1C2ABE3286100015AB5AD375F6C846AF /* ConnectableObservableType.swift in Sources */, + E05C3E0B8D466582B98045FF27EC5464 /* Create.swift in Sources */, + 4D8B3BE5F99171A4D1205B606B69F79E /* CurrentThreadScheduler.swift in Sources */, + 25796C6EBD25AB379B015ADF82EE1EE5 /* Date+Dispatch.swift in Sources */, + 3AD25AD9C8728A9A86FFE6EC25FA9BFE /* Debounce.swift in Sources */, + B333454B3020CEDEC9BDBEF0E8400FFB /* Debug.swift in Sources */, + 02912A00FC9AC0534AC160268C6EA5CC /* DefaultIfEmpty.swift in Sources */, + 60052D900CCEAEA66B2010EAC44BAA07 /* Deferred.swift in Sources */, + CDAD526F22D894E420C5741C700CE322 /* Delay.swift in Sources */, + C667FA9B9CA2B99DC20A8D4AF10B2D68 /* DelaySubscription.swift in Sources */, + 3E256795F6BB882B6664D74AFA4F5FDF /* Dematerialize.swift in Sources */, + 93E81EB50E68C3C420019ACE8A4A2197 /* Deprecated.swift in Sources */, + 5B121DC2FDA622AC0AD34621B9628B43 /* DispatchQueue+Extensions.swift in Sources */, + 5A351E279F8F63E0D8BFF14BC15B8144 /* DispatchQueueConfiguration.swift in Sources */, + 30ADE54AB0A7977B017F30B52209EECC /* Disposable.swift in Sources */, + 65FD5D2FF0833408E12236FCB0E42C24 /* Disposables.swift in Sources */, + AAF0DCFF1D57D2ADF8ADD5424CA5A86C /* DisposeBag.swift in Sources */, + 3A385C67DFF818E91D54F33FBD6FB7DE /* DisposeBase.swift in Sources */, + DDCA2294062DEE92F3FDC1E7CB72E840 /* DistinctUntilChanged.swift in Sources */, + 98007C0C6060C697C9193EFB39A8E927 /* Do.swift in Sources */, + 64F73958A768D74A7C45DDEFCE480654 /* ElementAt.swift in Sources */, + EFA35142E87F39D8E1B51948A1F795AD /* Empty.swift in Sources */, + 01670D708938741AB647D33821B489D2 /* Enumerated.swift in Sources */, + B08325501BE96BAE7DEA0EDB4C3E4478 /* Error.swift in Sources */, + 170A43301BBF4101108638668FF34DEE /* Errors.swift in Sources */, + 4EAEADDF7427C16CB82699DF48965A0F /* Event.swift in Sources */, + 5DBA1F21AAE770A20D3C8D8DD769013C /* Filter.swift in Sources */, + CD4ADA36A7DF68D26DDE8214363856F4 /* First.swift in Sources */, + 6CBC14F3CC53081CBD6F8FED6B7B7874 /* Generate.swift in Sources */, + 2146EBC9AD0F764FB5A08C8B1F6BB604 /* GroupBy.swift in Sources */, + F7E285B8F3BA0E3C7EF6AFA17708FBD7 /* GroupedObservable.swift in Sources */, + 119A325E155541452F432B23FECA24E0 /* HistoricalScheduler.swift in Sources */, + 43764C8719E0B6C43333BFE14605C54A /* HistoricalSchedulerTimeConverter.swift in Sources */, + 4030F2E41D3B55189558F48CDE8DECFF /* ImmediateSchedulerType.swift in Sources */, + 498A81CFDAA604E2A6C602BB6C00575C /* InfiniteSequence.swift in Sources */, + DCD250EB247CA3362A697180B0182086 /* InvocableScheduledItem.swift in Sources */, + 43FBA3428C3C5DD96158EB605E38DC11 /* InvocableType.swift in Sources */, + B8D36F26D5452163DC4BC19B6D06A28C /* Just.swift in Sources */, + 3DB6D1DE2CF5FA22FE46BC1E6499E37A /* Lock.swift in Sources */, + 1C5FCB11BDA6B695859066A82E0A3962 /* LockOwnerType.swift in Sources */, + 80FCBBEADEB4B6CB604AEDCA5C9BA34A /* MainScheduler.swift in Sources */, + 9ADF15C6FA880CA3AEC4D7B14BC0EB7F /* Map.swift in Sources */, + 48F98DADB3283A18D18095778AAF4334 /* Materialize.swift in Sources */, + 2CE4C4AED40EA9755848498A687FEB16 /* Maybe.swift in Sources */, + FA99DE9AD216F43B08E06A301A65BF1E /* Merge.swift in Sources */, + 5BE1AF801B6F3E2AF365B69F066F268E /* Multicast.swift in Sources */, + 22E362389674EB5F349D28163B8BA1CF /* Never.swift in Sources */, + 049CA7046095813FAB9CAB24E3E3C04F /* NopDisposable.swift in Sources */, + 9F2F4F0D0F959C2E06818775F0CDF0D1 /* Observable.swift in Sources */, + 6D3C1A1EEF289BEF78464D964CAD416E /* ObservableConvertibleType.swift in Sources */, + A7655A896348660BB60A8F46DC8B8CF9 /* ObservableType+Extensions.swift in Sources */, + CF0588B8A21F79EBDDA3A5E0AFD3B480 /* ObservableType+PrimitiveSequence.swift in Sources */, + 4BE5939AF4C323CB7AFF8E4186449499 /* ObservableType.swift in Sources */, + 578289037D6D6B75AE26BCD55B6A64DD /* ObserveOn.swift in Sources */, + 901C1FFA2B8F7E5AA667D995163682F0 /* ObserverBase.swift in Sources */, + 953762806E37C8CDF25BD38C740FF722 /* ObserverType.swift in Sources */, + 51F56A370E86EA66D4533D91CE2E088C /* OperationQueueScheduler.swift in Sources */, + E1D09901E7F579D08345E3DD25E8C5E8 /* Optional.swift in Sources */, + F568CDFE9189631D2C10CC527C1BD33A /* Platform.Darwin.swift in Sources */, + E0A9095EBD109A44CBC85AD84D7B2819 /* Platform.Linux.swift in Sources */, + 3DBE3AEDC40B41E826C365D8CA247217 /* PrimitiveSequence+Zip+arity.swift in Sources */, + EF2214EBE4FEEFD5E8171F6C4E5F2BBE /* PrimitiveSequence.swift in Sources */, + BDC1C85FC295E69FEED6436CABD6B5A1 /* PriorityQueue.swift in Sources */, + 9C8BF8D864399F4CE1AA7511B05F5E53 /* Producer.swift in Sources */, + 68E40ACE329722C65A6A8D590A49CDB6 /* PublishSubject.swift in Sources */, + DB3F362A380421D822B8AF97F8D80FCD /* Queue.swift in Sources */, + 5BBAF6797B81F267510263D80B8197BF /* Range.swift in Sources */, + 92D0B5DCE541366E791E4E2D12915751 /* Reactive.swift in Sources */, + 6A9AAA0728FF5F65038B5F7488BFF5BC /* RecursiveLock.swift in Sources */, + 6B3B23BA169A57B7416235BB113808F6 /* RecursiveScheduler.swift in Sources */, + 5A4E6C8DC64E05677CBCD58BB2877EE8 /* Reduce.swift in Sources */, + 4AC39B2213528DD3BDA4C243B14E37ED /* RefCountDisposable.swift in Sources */, + F73D3DFAB783E7DBAD910C2C0AE6140C /* Repeat.swift in Sources */, + D29B07F9BB89DD02DF8479E59674915A /* ReplaySubject.swift in Sources */, + 3D3010B87410A0F556596DF882B103F0 /* RetryWhen.swift in Sources */, + 0D42F06544FB8922A2A65009FAB3583F /* Rx.swift in Sources */, + 0FCFBD94D256BDB1E065EF3DCDCA5393 /* RxMutableBox.swift in Sources */, + 1EB069D5C9FB689AB1CCB587B3890DF0 /* RxSwift-dummy.m in Sources */, + 0A2BA8C6F0199E9D7749A9566202C758 /* Sample.swift in Sources */, + 18F1C4F429EA4EE47863C59F183F6758 /* Scan.swift in Sources */, + 7EDD2A215B6E80D4E2EBE92F99F6410F /* ScheduledDisposable.swift in Sources */, + 8E7E2AF1C299262FEA6D473BE01BD935 /* ScheduledItem.swift in Sources */, + A9ADF31E6D9B024261F99D9787EB1921 /* ScheduledItemType.swift in Sources */, + 95392ACCB07214CE44543153D49EF2D7 /* SchedulerServices+Emulation.swift in Sources */, + E5856E1162F623E87FBF41836214CD2B /* SchedulerType.swift in Sources */, + DC1B356C82B075C5D1D2BC57B12BE44D /* Sequence.swift in Sources */, + DED3055847861EDDF90F925377D5D714 /* SerialDispatchQueueScheduler.swift in Sources */, + D19C9CB44E37C7DCDFEA752129E20BD1 /* SerialDisposable.swift in Sources */, + E05DA5DB5B8295E44B101DC8072944BC /* ShareReplayScope.swift in Sources */, + 2A4823904796E1CA89E86E0DDD180BAE /* Single.swift in Sources */, + CD694C0B16BF9542A27DD7946AB77F3A /* SingleAssignmentDisposable.swift in Sources */, + 2714A15AD83759B3639EA631D596D22A /* SingleAsync.swift in Sources */, + 69EFD659067C53680C77D8B57F1D1965 /* Sink.swift in Sources */, + 837EBAA86949F7E6998F2E74ECE3F424 /* Skip.swift in Sources */, + 0E095B3BB4591D548D35430EDE48C4B6 /* SkipUntil.swift in Sources */, + 10E96C8BA5EEECE3378CA40D8B01411A /* SkipWhile.swift in Sources */, + E1568E4EEBD20A839AE8D485F76E94CD /* StartWith.swift in Sources */, + 36ED2437C10C08EDEC51764D2AD5E002 /* String+Rx.swift in Sources */, + 786C12158AB5FD4716E8BF8296B65FA7 /* SubjectType.swift in Sources */, + 7DEAA92B9F585386A82AACD633F00CDD /* SubscribeOn.swift in Sources */, + 7696B97F3023FE444D94C963CBD702AE /* SubscriptionDisposable.swift in Sources */, + 2597376F5FFD083F6353D503E729A90C /* SwiftSupport.swift in Sources */, + ADB2CF20567AF529197A1091FA531B1E /* Switch.swift in Sources */, + 829E7231D40238B884E2B9D8151ACCDB /* SwitchIfEmpty.swift in Sources */, + C4E4D6818A36C89F8BA49A05E293BA5F /* SynchronizedDisposeType.swift in Sources */, + A5176420651EB50AD675EF9F62E0016A /* SynchronizedOnType.swift in Sources */, + 62AC2EE31140FD90DF4CB9E84EB1D69E /* SynchronizedUnsubscribeType.swift in Sources */, + 5E290FC57A79D804C79FE2965828678F /* TailRecursiveSink.swift in Sources */, + 75775C05191E91911C191F0986760184 /* Take.swift in Sources */, + 96D58161696810A52CCD104B3C25496C /* TakeLast.swift in Sources */, + E687FA252C567B7BDEB2C01EDB4097A1 /* TakeUntil.swift in Sources */, + E4069D575BE2E2FB54C8488A93181834 /* TakeWhile.swift in Sources */, + 9459D3C756860382C479FADB0A0B7A7F /* Throttle.swift in Sources */, + 114F5668F8B2C7A328966299B99CE5BE /* Timeout.swift in Sources */, + D165B42B89C543C053698AE43992A772 /* Timer.swift in Sources */, + 67B1E0AD31FD7C44E31E241D6D97BB15 /* ToArray.swift in Sources */, + 4FE2DB9FA1369193B5D4B0613C9AE5DB /* Using.swift in Sources */, + 350E28A9E921E9F9E5B3C2E77CB3BFF2 /* VirtualTimeConverterType.swift in Sources */, + 06A5235E9085439CC10A1F3BF43110D5 /* VirtualTimeScheduler.swift in Sources */, + 5467DA8A0A477B4414120B9AD955FAF0 /* Window.swift in Sources */, + D9319698B5B17CDBF62256F90E991EB6 /* WithLatestFrom.swift in Sources */, + 919B2EF09439DC404F918854676773FE /* Zip+arity.swift in Sources */, + A70A1B109F6E624265FA027F766B0232 /* Zip+Collection.swift in Sources */, + 734C83E2143BA00000E8FADA79B4754D /* Zip.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 84FA7E29AA3E2966C44CF1503CB4782C /* Sources */ = { + 363DE8422047FDE52F6BC65A9D7D80FD /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 10D995A6A50A1F4C3D28184B934F6A35 /* AddRef.swift in Sources */, - 02A949CB014B6A490CD9C0EBD8B9F3DF /* Amb.swift in Sources */, - 9ABCA5F08F43DC5F05CD094092F75ADE /* AnonymousDisposable.swift in Sources */, - BDED91D633AA1983E5A67B8128E05234 /* AnonymousObserver.swift in Sources */, - E4128B12254F47FEE2E915BC828BB680 /* AnyObserver.swift in Sources */, - 59E474030FA5E9D0CA129A072FF56808 /* AsMaybe.swift in Sources */, - A383874C9FF5FDF3C50230B7CECE23A4 /* AsSingle.swift in Sources */, - B92833B4E5BBBFBFB24441D8176A4AEF /* AsyncLock.swift in Sources */, - 3781BA60E511450E9A22703DEC854154 /* AsyncSubject.swift in Sources */, - D9B90A747F561F5809B1B13398623180 /* AtomicInt.swift in Sources */, - D9B77BADB41468BE70DAC25803050054 /* Bag+Rx.swift in Sources */, - 64DD354BAB0986E0E87D9309103F4B63 /* Bag.swift in Sources */, - 37E8DCDE7CA61F0C12D774BA553E9525 /* BehaviorSubject.swift in Sources */, - 95583A3AD97E369F924E039C12B58866 /* BinaryDisposable.swift in Sources */, - D9BA913218F72D08C2032D489C8AC002 /* BooleanDisposable.swift in Sources */, - BC5FE46EE548A548B440D070DF24EB04 /* Buffer.swift in Sources */, - 712FD04C67CCDE6F4CA10B6DFF53AE56 /* Cancelable.swift in Sources */, - 74F3A0AF31490C4E3932DFED9BE5D689 /* Catch.swift in Sources */, - 1C767BF644464DE62BEB5C638C35A27E /* CombineLatest+arity.swift in Sources */, - B952B076B721D7A580F04C7BB0FB854C /* CombineLatest+Collection.swift in Sources */, - D4AA3FB82F427707196ED9AF3050315F /* CombineLatest.swift in Sources */, - 2A1501D58FAD345D7BADD8FE331C5F3B /* CompactMap.swift in Sources */, - B92B3B3CD9A5EFB573B0708E621AECC4 /* Completable+AndThen.swift in Sources */, - C5AF3F7093ED5A06BFD5259F4BF86328 /* Completable.swift in Sources */, - C59FC470BE2A3165194188162A71A96E /* CompositeDisposable.swift in Sources */, - 1C120001157EB215BFB8D4A61973864E /* Concat.swift in Sources */, - 5EF60FB96CDC276C589470FA1FC05C86 /* ConcurrentDispatchQueueScheduler.swift in Sources */, - 4B655E78A858B92DCBE47A725AE84B60 /* ConcurrentMainScheduler.swift in Sources */, - 85B83B8E6B2850400F1231318FE2CBAA /* ConnectableObservableType.swift in Sources */, - D93B3464EDF3046FAE88CD740FB41D5A /* Create.swift in Sources */, - 5605F5212A6EA73AB45704A8CD9372BF /* CurrentThreadScheduler.swift in Sources */, - BE094D7ECBF3E53D8F428D0F8D676AEE /* Date+Dispatch.swift in Sources */, - 8C5780DB24F88FED0C99B2DAFCE9A9B0 /* Debounce.swift in Sources */, - 22789593B093B489DAD1D2F8C3289203 /* Debug.swift in Sources */, - 5B1432EFE051CE8542DACB6C881633AF /* DefaultIfEmpty.swift in Sources */, - 21CF4EA34645F13A88F5E8B95AC29B0A /* Deferred.swift in Sources */, - 2948F7E90A4094D0838042BF406328C7 /* Delay.swift in Sources */, - F059E01A6F668D4323E8AA8B829C319F /* DelaySubscription.swift in Sources */, - 2DF88FA76C9EA8D08367DFE180E639F4 /* Dematerialize.swift in Sources */, - 96411BE4F9F5F13A1D294F834F345A8C /* Deprecated.swift in Sources */, - 229E4B34FD637F75DE2482DA2CA6574A /* DispatchQueue+Extensions.swift in Sources */, - B5405E851BC3EE239BE984881729C5C0 /* DispatchQueueConfiguration.swift in Sources */, - 090EC252A320ACCE2E20DBB808A7ADD0 /* Disposable.swift in Sources */, - 36BD1858768BEB09C85016AB17026C22 /* Disposables.swift in Sources */, - 95B50D34D42473A825CA022A0AB3E3B2 /* DisposeBag.swift in Sources */, - 7D16C62A2053EE65BC360CAC50B29B85 /* DisposeBase.swift in Sources */, - A953B4C58C9C88492C4AAB83AB80A88F /* DistinctUntilChanged.swift in Sources */, - 20B4327C56941179B54C52A11A791423 /* Do.swift in Sources */, - 78298ADDE86F786E90A8A726473DFDD1 /* ElementAt.swift in Sources */, - 516D5CE1DDE6304462EE46D97AD5511C /* Empty.swift in Sources */, - AFA6D34905BB6EC19E2732DDBC2F29C2 /* Enumerated.swift in Sources */, - EF046775B5834F37554BCEAA84A72CD5 /* Error.swift in Sources */, - C40658C5DCC74AB1C91C5AADDBF4CF28 /* Errors.swift in Sources */, - 4701FB27A2A5F95D589F0352FADA79C0 /* Event.swift in Sources */, - 1F4685399CB83A36B2530D2E624AF11C /* Filter.swift in Sources */, - F3B782903EC34C12754EB7F302AF610A /* First.swift in Sources */, - 965D0444A70B5EC5F44E5DE8F3526473 /* Generate.swift in Sources */, - A07A2CAFC16448BBCADEBCF3E6AE619B /* GroupBy.swift in Sources */, - 920387D4074E8839B3D102DD63B45791 /* GroupedObservable.swift in Sources */, - 18F6681A17081BD11CD25B3F20E3C9E3 /* HistoricalScheduler.swift in Sources */, - B4F60F4FBB05BB4651F48A356CA2E412 /* HistoricalSchedulerTimeConverter.swift in Sources */, - 428BDE4DA26F3137965A07BCDD86CCF5 /* ImmediateSchedulerType.swift in Sources */, - 306799CEB9E954F70E6B04A4151FDA46 /* InfiniteSequence.swift in Sources */, - 87A9A76C34551F9C6C808B11DFDA9245 /* InvocableScheduledItem.swift in Sources */, - 2B66A5B233A6D99A6872C1893F97EB86 /* InvocableType.swift in Sources */, - A185A17C8B21436DC5BCC73F44BE99B2 /* Just.swift in Sources */, - 060B98A5D2D2D7DA32D061E66D1212C5 /* Lock.swift in Sources */, - 834DDAC2BD2B8B5F3EE9083AF9837391 /* LockOwnerType.swift in Sources */, - 6FECE751FE85F866EC758404991012C7 /* MainScheduler.swift in Sources */, - EF911DC502F4EBBC602D3765233C38B1 /* Map.swift in Sources */, - BA8EC7529065111272A4FA01C11A3D64 /* Materialize.swift in Sources */, - C23217F0F25980F861EDD5F462B35316 /* Maybe.swift in Sources */, - 270678DEE2C346CD4BFF2BC06C2F90FB /* Merge.swift in Sources */, - 1F1988F428A13D6ABD0FE13FCBD89D72 /* Multicast.swift in Sources */, - 1A9CC2706D139FD5DEFF44C72C934F25 /* Never.swift in Sources */, - F037EC426CB22C61DC42C53929B58461 /* NopDisposable.swift in Sources */, - B67836312A5EB1F580D76D2B22A6E906 /* Observable.swift in Sources */, - C23CCE94FD722E5A5C162CB200466F83 /* ObservableConvertibleType.swift in Sources */, - 4A3E884CED7CD18AB0AA40E8BE54842C /* ObservableType+Extensions.swift in Sources */, - 5782DCD1477EFC6396F6F45C5E46C033 /* ObservableType+PrimitiveSequence.swift in Sources */, - 17722BE03F7B5E5E25D440315A121439 /* ObservableType.swift in Sources */, - 4EF994316123FBA40568D0A277A58399 /* ObserveOn.swift in Sources */, - A303F4252DCDD78AEBC2B994CCB1B340 /* ObserverBase.swift in Sources */, - 73EC147D6B962F7EF427CFE13A4E9FA8 /* ObserverType.swift in Sources */, - 976115218A5FE95A07BF0FC60D460850 /* OperationQueueScheduler.swift in Sources */, - 86977C3CB6E1246F6DDE10A8FF8F306E /* Optional.swift in Sources */, - DFF994904AEC19EC8861E3233FBB1FA2 /* Platform.Darwin.swift in Sources */, - 7EA3C3BFD7B3B35F020DF1EF50C3B00E /* Platform.Linux.swift in Sources */, - 05D7FABB08C6666A7D63234D68E602F2 /* PrimitiveSequence+Zip+arity.swift in Sources */, - 962A5B803659BBF43DBC1438F5D46D30 /* PrimitiveSequence.swift in Sources */, - B4839D44F447030944349761A03ECCCA /* PriorityQueue.swift in Sources */, - EAA4CF152ADD14DD714C9210C4272BF7 /* Producer.swift in Sources */, - BCC6DAD730DC025E6E149E732317C59C /* PublishSubject.swift in Sources */, - 374218DF6948B2E9514D1E148A6154EF /* Queue.swift in Sources */, - B65A0A1244D1584C3DA8A84F1F4DF644 /* Range.swift in Sources */, - 6F0D723277FFE043C4FEB54C0E94E3FB /* Reactive.swift in Sources */, - A3CFEEC67EEE47CF1287A80CA0EBA3FD /* RecursiveLock.swift in Sources */, - 44E269AB3B1BBF2746E2CB4479982887 /* RecursiveScheduler.swift in Sources */, - DCFEE5F9795EC2120A29EA202D26699B /* Reduce.swift in Sources */, - A7B1CEE272FA065BCDE192EC13C4E288 /* RefCountDisposable.swift in Sources */, - 169EA35AF6A61349381E0508B61F4D49 /* Repeat.swift in Sources */, - F7647A452BD8B9D3ABA2B27C5E281CA2 /* ReplaySubject.swift in Sources */, - 6061E9C5328EC38DE98F7A9EA26D9082 /* RetryWhen.swift in Sources */, - 7594B7CE0F85102FA5D9F58B1EBABB71 /* Rx.swift in Sources */, - B76D304F0849BB5E7C6D46ED75F248FD /* RxMutableBox.swift in Sources */, - 31FB64B52DE94DB2BFA1B17848B268FD /* RxSwift-dummy.m in Sources */, - 9F5992C37BFF9D066E2B39990C1D4A79 /* Sample.swift in Sources */, - 3021A8AE5959452BD21997CA8C126CD9 /* Scan.swift in Sources */, - C137E2628E1FD659662AB6D16CC95033 /* ScheduledDisposable.swift in Sources */, - CAE248D10EF6E99863D18FB9906ED3B6 /* ScheduledItem.swift in Sources */, - 02FD4ADA12298BDF172AD1ED60F93522 /* ScheduledItemType.swift in Sources */, - DA77A2BE647B59AC47FF50C84E4AAE18 /* SchedulerServices+Emulation.swift in Sources */, - 31AB4FBDC3146035B7F265F36CE05B61 /* SchedulerType.swift in Sources */, - 3CFC709C2287A04B80A4B2A6E9D860B7 /* Sequence.swift in Sources */, - 679344A9097862B6E979AEDE43D54FAD /* SerialDispatchQueueScheduler.swift in Sources */, - DDE4C3A200978199BB6DB8D72C990983 /* SerialDisposable.swift in Sources */, - 4B9377FFE5EEC0A597B9D7E46678CF05 /* ShareReplayScope.swift in Sources */, - D6B675670B8BD1F9E317CFA2471EE6E7 /* Single.swift in Sources */, - B58B19CE594B511CB290A1E7D5F304B0 /* SingleAssignmentDisposable.swift in Sources */, - D87AFA7FF659C0FF9432929C2951CD97 /* SingleAsync.swift in Sources */, - 70F573D3C1841C765353F8FED2CF0AC6 /* Sink.swift in Sources */, - DE488CB06623208D0CD63FEC39E28675 /* Skip.swift in Sources */, - C7BB1A38A77108201F7A5071F16A9511 /* SkipUntil.swift in Sources */, - 23B610152008B94B7D406A7D6BFE044C /* SkipWhile.swift in Sources */, - F22215E45AB372FA8D48062A6E8BCC7D /* StartWith.swift in Sources */, - 609408A30B183CAEC4C9D3491148FC96 /* String+Rx.swift in Sources */, - 4E85586A71691C866DE7BBDE8E5A22E9 /* SubjectType.swift in Sources */, - 3BB80A2F097BFB068E0C7D35E5CD7242 /* SubscribeOn.swift in Sources */, - D219A4016E471D45195458719AEC9D3B /* SubscriptionDisposable.swift in Sources */, - 7EA69DC18F902601DCD269042537DAE1 /* SwiftSupport.swift in Sources */, - 79FBCB64980B6E4A1338534572CF6D2D /* Switch.swift in Sources */, - 5D6BB4D14A7FA4A748405FC7D1E713F7 /* SwitchIfEmpty.swift in Sources */, - 7DEF07041653823A4369D23636048D4F /* SynchronizedDisposeType.swift in Sources */, - 0302AB35D61D7CC16621DE3EB9E5C4ED /* SynchronizedOnType.swift in Sources */, - DDEAF8D022C1F849C353332547A8F5EF /* SynchronizedUnsubscribeType.swift in Sources */, - F42ECF65DB5D0D8F65E2F10DEBC09A1D /* TailRecursiveSink.swift in Sources */, - D9821D4C4A8BCBAD2F381238AF1970E1 /* Take.swift in Sources */, - 3411B2340A79F2F3C098303F1F50EC9B /* TakeLast.swift in Sources */, - C9427DD70225FCCF56DE65166319A44D /* TakeUntil.swift in Sources */, - BFAEB6ADC9B47FFE11453CEACE2D62EC /* TakeWhile.swift in Sources */, - 5EF3D14AABA18971D9CBFD379DEF8342 /* Throttle.swift in Sources */, - 5360507BF8FD8E1165527B76D4C3CC89 /* Timeout.swift in Sources */, - 76EF084E53C3804B1C776CCD67FEB9E3 /* Timer.swift in Sources */, - CD07FAC8B8C8650E384D95F7AD270048 /* ToArray.swift in Sources */, - 5C47DE456BA87393E7E4556C3F4A29B8 /* Using.swift in Sources */, - 68F27AE118E94E70FD2038F64611571E /* VirtualTimeConverterType.swift in Sources */, - AD3772A208DAAC8FEAA29120D0975004 /* VirtualTimeScheduler.swift in Sources */, - B98F5BBBB6ABA7F14C61B2064B461D3A /* Window.swift in Sources */, - B4DC02636E7D7EC2B3EB90FCAFE646DD /* WithLatestFrom.swift in Sources */, - F1C701E17D204CDDDFF1BD79D2F83D24 /* Zip+arity.swift in Sources */, - 0BD56F15A29CCD0E1CFCF0505CE7E19C /* Zip+Collection.swift in Sources */, - 1848D2995C8279FD8E2E6ABF5D841B98 /* Zip.swift in Sources */, + 2885AA71C5B2AB74419A81270B1F68E3 /* Pods-SpeedTestTests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E58294C5CD13B5C7810347D725B24640 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 903F5D7445CCBE92F6F6B9AE7431A756 /* Action.swift in Sources */, + 754ADE52D9972F60BCDD9113BC452C32 /* Atomic.swift in Sources */, + E5A0C334AA8D8BDF9584A77B64F55599 /* Bag.swift in Sources */, + 212E37330B2EE9058E21C03B04BDC0F9 /* Deprecations+Removals.swift in Sources */, + C47662C1EF5D5DCDAC5C993EE18AC095 /* Disposable.swift in Sources */, + 69182AEC6A4022999099278A5977494A /* Event.swift in Sources */, + BCA62AF4479783CEBC1A9443D1A7FFEA /* EventLogger.swift in Sources */, + 53267AC8D59401E882954F0ADD24B87F /* Flatten.swift in Sources */, + 0681EF9707D9CC4F69FE11D3C48C0659 /* FoundationExtensions.swift in Sources */, + E0308CBE21DE89A7AA62551F16578304 /* Lifetime.swift in Sources */, + 8B4CBF7AD5DDA658BCB7E8D939F1A829 /* Observer.swift in Sources */, + 88296C90ACB3968788ED9C7D53D661A5 /* Optional.swift in Sources */, + 7C9EFBE6B93212C73D12DABF15FBA9EA /* Property.swift in Sources */, + B397928461945EC67D0C863EBE61899C /* Reactive.swift in Sources */, + 6D59D8BAC5B3723B390094A96CCB060A /* ReactiveSwift-dummy.m in Sources */, + 0810484E07381D9DDB7FA921D1AE5624 /* ResultExtensions.swift in Sources */, + E4C4F3E52516A9C5E3A18CE8CFBB4E13 /* Scheduler.swift in Sources */, + BB0A800EDA70827B28B4B2E28B96C6E8 /* Signal.swift in Sources */, + 3BEF2CF5FB56FF6949B715C255A8D316 /* SignalProducer.swift in Sources */, + 51EA4D0F33C66DB2505645FFE31CD7AF /* UnidirectionalBinding.swift in Sources */, + DDD1698D35501DCFF3B731E906D80F18 /* UninhabitedTypeGuards.swift in Sources */, + BAEF9CEF2AE7BC78522CABDD33699BFF /* ValidatingProperty.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - B4B97E334B82359D1EC659C825B48753 /* PBXTargetDependency */ = { + B486CCC699F83E86F20096972F7B71CB /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = RxSwift; target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; - targetProxy = B678F51CCA816C93D41CD33C9E258E9C /* PBXContainerItemProxy */; + targetProxy = 89968FCCBB466431C135B1DAACA0A705 /* PBXContainerItemProxy */; + }; + FF339DC4158EAB1A978F62ACFB72AEAB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ReactiveSwift; + target = 08B8EF1A02DE30CBEFB370FFE1C123C0 /* ReactiveSwift */; + targetProxy = 43D69BABC7C9123379154D61B2E9BEE0 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 07488D4657FB0A78086563621D425F8A /* Debug */ = { + 002F61366E961D7A67F88BAFC42B0CA7 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 883AAA7A0359C1678B657C204B29628B /* RxSwift.xcconfig */; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "POD_CONFIGURATION_DEBUG=1", - "DEBUG=1", + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - PRODUCT_NAME = "$(TARGET_NAME)"; - STRIP_INSTALLED_PRODUCT = NO; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; - SYMROOT = "${SRCROOT}/../build"; + MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; + PRODUCT_MODULE_NAME = RxSwift; + PRODUCT_NAME = RxSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 1712C2663B88060804280B94A23DFBB7 /* Release */ = { + 24D0B5F3AE2D59075423FD29B3E05F22 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A90E43BE8DAE0A05C4499DDE5025DE8C /* Pods-SpeedTestTests.release.xcconfig */; + baseConfigurationReference = 883AAA7A0359C1678B657C204B29628B /* RxSwift.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -973,23 +1126,22 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACH_O_TYPE = staticlib; - MODULEMAP_FILE = "Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.modulemap"; - OTHER_LDFLAGS = ""; - OTHER_LIBTOOLFLAGS = ""; - PODS_ROOT = "$(SRCROOT)"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; + PRODUCT_MODULE_NAME = RxSwift; + PRODUCT_NAME = RxSwift; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -997,10 +1149,11 @@ }; name = Release; }; - 1CDAE5CC3549574C7AA6917C775C2D47 /* Release */ = { + 45C958964437A13AFD7B6BFFAC4F2472 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6D669D2B1969E2BCE4DED7161293460F /* RxSwift.xcconfig */; + baseConfigurationReference = A90E43BE8DAE0A05C4499DDE5025DE8C /* Pods-SpeedTestTests.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -1010,22 +1163,23 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; + INFOPLIST_FILE = "Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; - PRODUCT_MODULE_NAME = RxSwift; - PRODUCT_NAME = RxSwift; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -1033,9 +1187,9 @@ }; name = Release; }; - 6CF5E9B2FFF0771D6C87155FEB775DA6 /* Debug */ = { + 782D79DDC7750EF08E44023FE0AA5348 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6D669D2B1969E2BCE4DED7161293460F /* RxSwift.xcconfig */; + baseConfigurationReference = A7DA933C1F6993AD9DB4BF3D9250B705 /* ReactiveSwift.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; @@ -1046,8 +1200,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/ReactiveSwift/ReactiveSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ReactiveSwift/ReactiveSwift-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -1055,20 +1209,20 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; - PRODUCT_MODULE_NAME = RxSwift; - PRODUCT_NAME = RxSwift; + MODULEMAP_FILE = "Target Support Files/ReactiveSwift/ReactiveSwift.modulemap"; + PRODUCT_MODULE_NAME = ReactiveSwift; + PRODUCT_NAME = ReactiveSwift; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 5.1; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; - A1962E6FF39BBAC201A2E5DDF99557DF /* Release */ = { + 8F17DC3A99F99FBAD606CE6963886315 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1123,12 +1277,112 @@ STRIP_INSTALLED_PRODUCT = NO; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + 916E0404255105F480DC4950B7625F7A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; SYMROOT = "${SRCROOT}/../build"; }; + name = Debug; + }; + 98E79152511F0E2AE7F61550A0906790 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A7DA933C1F6993AD9DB4BF3D9250B705 /* ReactiveSwift.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/ReactiveSwift/ReactiveSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ReactiveSwift/ReactiveSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/ReactiveSwift/ReactiveSwift.modulemap"; + PRODUCT_MODULE_NAME = ReactiveSwift; + PRODUCT_NAME = ReactiveSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.1; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; name = Release; }; - C38A9B244DD51C914447A82748CA3676 /* Debug */ = { + A6467044C771561FA31FA0F794EBBC9E /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 09C540500A583CA3D8CF67548F66082E /* Pods-SpeedTestTests.debug.xcconfig */; buildSettings = { @@ -1171,26 +1425,35 @@ 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( - 07488D4657FB0A78086563621D425F8A /* Debug */, - A1962E6FF39BBAC201A2E5DDF99557DF /* Release */, + 916E0404255105F480DC4950B7625F7A /* Debug */, + 8F17DC3A99F99FBAD606CE6963886315 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5EA291D224EF14DF4C5B0CC4FF5AFBE6 /* Build configuration list for PBXNativeTarget "RxSwift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 002F61366E961D7A67F88BAFC42B0CA7 /* Debug */, + 24D0B5F3AE2D59075423FD29B3E05F22 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 4BEA5E9C5F5F5EBD0F134084E82F1CB7 /* Build configuration list for PBXNativeTarget "RxSwift" */ = { + 9D6C9C10B9D662B4303FC0EBFF60D63D /* Build configuration list for PBXNativeTarget "ReactiveSwift" */ = { isa = XCConfigurationList; buildConfigurations = ( - 6CF5E9B2FFF0771D6C87155FEB775DA6 /* Debug */, - 1CDAE5CC3549574C7AA6917C775C2D47 /* Release */, + 782D79DDC7750EF08E44023FE0AA5348 /* Debug */, + 98E79152511F0E2AE7F61550A0906790 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - D237D7827D02D0A342678F891BAB388A /* Build configuration list for PBXNativeTarget "Pods-SpeedTestTests" */ = { + D8416090F9D7F3A40C106DE8A00C8E94 /* Build configuration list for PBXNativeTarget "Pods-SpeedTestTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - C38A9B244DD51C914447A82748CA3676 /* Debug */, - 1712C2663B88060804280B94A23DFBB7 /* Release */, + A6467044C771561FA31FA0F794EBBC9E /* Debug */, + 45C958964437A13AFD7B6BFFAC4F2472 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/Pods-SpeedTestTests.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/Pods-SpeedTestTests.xcscheme new file mode 100644 index 0000000..d542685 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/Pods-SpeedTestTests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/ReactiveSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/ReactiveSwift.xcscheme new file mode 100644 index 0000000..ce416bb --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/ReactiveSwift.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/RxSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/RxSwift.xcscheme new file mode 100644 index 0000000..7b649f0 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/RxSwift.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..009bd3f --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,26 @@ + + + + + SchemeUserState + + Pods-SpeedTestTests.xcscheme + + isShown + + + ReactiveSwift.xcscheme + + isShown + + + RxSwift.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + + diff --git a/Pods/ReactiveSwift/LICENSE.md b/Pods/ReactiveSwift/LICENSE.md new file mode 100644 index 0000000..49bc374 --- /dev/null +++ b/Pods/ReactiveSwift/LICENSE.md @@ -0,0 +1,19 @@ +**Copyright (c) 2012 - 2016, GitHub, Inc.** +**All rights reserved.** + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/ReactiveSwift/README.md b/Pods/ReactiveSwift/README.md new file mode 100644 index 0000000..71a925d --- /dev/null +++ b/Pods/ReactiveSwift/README.md @@ -0,0 +1,157 @@ +

+ ReactiveSwift

+ Streams of values over time. Tailored for Swift.

+ Latest ReactiveSwift Documentation Join the ReactiveSwift Slack community. +

+
+ +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](#carthage) [![CocoaPods compatible](https://img.shields.io/cocoapods/v/ReactiveSwift.svg)](#cocoapods) [![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-orange.svg)](#swift-package-manager) [![GitHub release](https://img.shields.io/github/release/ReactiveCocoa/ReactiveSwift.svg)](https://github.com/ReactiveCocoa/ReactiveSwift/releases) ![Swift 5.0](https://img.shields.io/badge/Swift-5.0-orange.svg) ![platforms](https://img.shields.io/badge/platform-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-lightgrey.svg) + +🎉 [Getting Started](#getting-started) 🚄 [Release Roadmap](#release-roadmap) + +## What is ReactiveSwift? +__ReactiveSwift__ offers composable, declarative and flexible primitives that are built around the grand concept of ___streams of values over time___. + +These primitives can be used to uniformly represent common Cocoa and generic programming patterns that are fundamentally an act of observation, e.g. delegate pattern, callback closures, notifications, control actions, responder chain events, [futures/promises](https://en.wikipedia.org/wiki/Futures_and_promises) and [key-value observing](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html) (KVO). + +Because all of these different mechanisms can be represented in the _same_ way, +it’s easy to declaratively compose them together, with less spaghetti +code and state to bridge the gap. + +## Getting Started + +1. **[Core Reactive Primitives][]** + + An overview of the semantics and example use cases of the ReactiveSwift primitives, including [`Signal`][], [`SignalProducer`][], [`Property`][] and [`Action`][]. + +1. **[Basic Operators][]** + + An overview of the operators provided to compose and transform streams of values. + +1. **[ReactiveCocoa][ReactiveCocoa]** + + Building on top of ReactiveSwift, **ReactiveCocoa** extends Cocoa platform frameworks with reactive bindings and extensions. + + [![GitHub release](https://img.shields.io/github/release/ReactiveCocoa/ReactiveCocoa.svg)](https://github.com/ReactiveCocoa/ReactiveCocoa/releases)[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/ReactiveCocoa/ReactiveCocoa/#carthage) [![CocoaPods compatible](https://img.shields.io/cocoapods/v/ReactiveCocoa.svg)](https://github.com/ReactiveCocoa/ReactiveCocoa/#cocoapods) + +1. **[How does ReactiveSwift relate to RxSwift?][]** + + An overview of how ReactiveSwift differs from RxSwift for Swift idiomaticity. + +## Examples + +1. **Interactive Form UI** + + ReactiveSwift includes a [_UI Examples_ playground][], which demonstrates: + * how to build an interactive form UI with bindings, properties and `Action`s, with a live view in action. + * how to use reactive primitives to implement the Model-View-ViewModel architectural pattern, with the View Model being the source of truth for the View. + +1. **[Online Searching][]** + +## Advanced Topics + +1. **[ReactiveCocoa][]** + + Bindings and reactive extensions for Cocoa and Cocoa Touch frameworks are offered separately as ReactiveCocoa. + +1. **[API Reference][]** + +1. **[API Contracts][]** + + Contracts of the ReactiveSwift primitives, Best Practices with ReactiveSwift, and Guidelines on implementing custom operators. + +1. **[Debugging Techniques][]** + +## Installation + +ReactiveSwift supports macOS 10.9+, iOS 8.0+, watchOS 2.0+, tvOS 9.0+ and Linux. + +#### Carthage + +If you use [Carthage][] to manage your dependencies, simply add +ReactiveSwift to your `Cartfile`: + +``` +github "ReactiveCocoa/ReactiveSwift" ~> 5.0 +``` + +If you use Carthage to build your dependencies, make sure you have added `ReactiveSwift.framework` to the "_Linked Frameworks and Libraries_" section of your target, and have included them in your Carthage framework copying build phase. + +#### CocoaPods + +If you use [CocoaPods][] to manage your dependencies, simply add +ReactiveSwift to your `Podfile`: + +``` +pod 'ReactiveSwift', '~> 5.0' +``` + +#### Swift Package Manager + +If you use Swift Package Manager, simply add ReactiveSwift as a dependency +of your package in `Package.swift`: + +``` +.package(url: "https://github.com/ReactiveCocoa/ReactiveSwift.git", from: "5.0.0") +``` + +#### Git submodule + + 1. Add the ReactiveSwift repository as a [submodule][] of your + application’s repository. + 1. Run `git submodule update --init --recursive` from within the ReactiveCocoa folder. + 1. Drag and drop `ReactiveSwift.xcodeproj` into your application’s Xcode + project or workspace. + 1. On the “General” tab of your application target’s settings, add + `ReactiveSwift.framework` to the “Embedded Binaries” section. + 1. If your application target does not contain Swift code at all, you should also + set the `EMBEDDED_CONTENT_CONTAINS_SWIFT` build setting to “Yes”. + +## Playground + +We also provide a great Playground, so you can get used to ReactiveCocoa's operators. In order to start using it: + + 1. Clone the ReactiveSwift repository. + 1. Retrieve the project dependencies using one of the following terminal commands from the ReactiveSwift project root directory: + - `git submodule update --init --recursive` **OR**, if you have [Carthage][] installed + - `carthage checkout` + 1. Open `ReactiveSwift.xcworkspace` + 1. Build `ReactiveSwift-macOS` scheme + 1. Finally open the `ReactiveSwift.playground` + 1. Choose `View > Show Debug Area` + +## Have a question? +If you need any help, please visit our [GitHub issues][] or [Stack Overflow][]. Feel free to file an issue if you do not manage to find any solution from the archives. + +## Release Roadmap +**Current Stable Release:**
[![GitHub release](https://img.shields.io/github/release/ReactiveCocoa/ReactiveSwift.svg)](https://github.com/ReactiveCocoa/ReactiveSwift/releases) + +### Plan of Record +#### ABI stability release +ReactiveSwift is expected to declare library ABI stability when Swift rolls out resilence support. Until then, ReactiveSwift would incrementally adopt new language features that help move towards to goal. The ETA is Swift 5. + +[Core Reactive Primitives]: Documentation/ReactivePrimitives.md +[Basic Operators]: Documentation/BasicOperators.md +[How does ReactiveSwift relate to RxSwift?]: Documentation/RxComparison.md +[API Contracts]: Documentation/APIContracts.md +[API Reference]: http://reactivecocoa.io/reactiveswift/docs/latest/ +[Debugging Techniques]: Documentation/DebuggingTechniques.md +[Online Searching]: Documentation/Example.OnlineSearch.md +[_UI Examples_ playground]: https://github.com/ReactiveCocoa/ReactiveSwift/blob/master/ReactiveSwift-UIExamples.playground/Pages/ValidatingProperty.xcplaygroundpage/Contents.swift + +[`Action`]: Documentation/ReactivePrimitives.md#action-a-serialized-worker-with-a-preset-action +[`SignalProducer`]: Documentation/ReactivePrimitives.md#signalproducer-deferred-work-that-creates-a-stream-of-values +[`Signal`]: Documentation/ReactivePrimitives.md#signal-a-unidirectional-stream-of-events +[`Property`]: Documentation/ReactivePrimitives.md#property-an-observable-box-that-always-holds-a-value + +[ReactiveCocoa]: https://github.com/ReactiveCocoa/ReactiveCocoa/#readme + +[Carthage]: https://github.com/Carthage/Carthage/#readme +[CocoaPods]: https://cocoapods.org/ +[submodule]: https://git-scm.com/docs/git-submodule + +[GitHub issues]: https://github.com/ReactiveCocoa/ReactiveSwift/issues?q=is%3Aissue+label%3Aquestion+ +[Stack Overflow]: http://stackoverflow.com/questions/tagged/reactive-cocoa + +[Looking for the Objective-C API?]: https://github.com/ReactiveCocoa/ReactiveObjC/#readme +[Still using Swift 2.x?]: https://github.com/ReactiveCocoa/ReactiveCocoa/tree/v4.0.0 diff --git a/Pods/ReactiveSwift/Sources/Action.swift b/Pods/ReactiveSwift/Sources/Action.swift new file mode 100644 index 0000000..a6eeafa --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Action.swift @@ -0,0 +1,375 @@ +import Dispatch +import Foundation + +/// `Action` represents a repeatable work like `SignalProducer`. But on top of the +/// isolation of produced `Signal`s from a `SignalProducer`, `Action` provides +/// higher-order features like availability and mutual exclusion. +/// +/// Similar to a produced `Signal` from a `SignalProducer`, each unit of the repreatable +/// work may output zero or more values, and terminate with or without an error at some +/// point. +/// +/// The core of `Action` is the `execute` closure it created with. For every execution +/// attempt with a varying input, if the `Action` is enabled, it would request from the +/// `execute` closure a customized unit of work — represented by a `SignalProducer`. +/// Specifically, the `execute` closure would be supplied with the latest state of +/// `Action` and the external input from `apply()`. +/// +/// `Action` enforces serial execution, and disables the `Action` during the execution. +public final class Action { + private struct ActionState { + var isEnabled: Bool { + return isUserEnabled && !isExecuting + } + + var isUserEnabled: Bool + var isExecuting: Bool + var value: Value + } + + private let execute: (Action, Input) -> SignalProducer> + private let eventsObserver: Signal.Event, Never>.Observer + private let disabledErrorsObserver: Signal<(), Never>.Observer + + private let deinitToken: Lifetime.Token + + /// The lifetime of the `Action`. + public let lifetime: Lifetime + + /// A signal of all events generated from all units of work of the `Action`. + /// + /// In other words, this sends every `Event` from every unit of work that the `Action` + /// executes. + public let events: Signal.Event, Never> + + /// A signal of all values generated from all units of work of the `Action`. + /// + /// In other words, this sends every value from every unit of work that the `Action` + /// executes. + public let values: Signal + + /// A signal of all errors generated from all units of work of the `Action`. + /// + /// In other words, this sends every error from every unit of work that the `Action` + /// executes. + public let errors: Signal + + /// A signal of all failed attempts to start a unit of work of the `Action`. + public let disabledErrors: Signal<(), Never> + + /// A signal of all completed events generated from applications of the action. + /// + /// In other words, this will send completed events from every signal generated + /// by each SignalProducer returned from apply(). + public let completed: Signal<(), Never> + + /// Whether the action is currently executing. + public let isExecuting: Property + + /// Whether the action is currently enabled. + public let isEnabled: Property + + /// Initializes an `Action` that would be conditionally enabled depending on its + /// state. + /// + /// When the `Action` is asked to start the execution with an input value, a unit of + /// work — represented by a `SignalProducer` — would be created by invoking + /// `execute` with the latest state and the input value. + /// + /// - note: `Action` guarantees that changes to `state` are observed in a + /// thread-safe way. Thus, the value passed to `isEnabled` will + /// always be identical to the value passed to `execute`, for each + /// application of the action. + /// + /// - note: This initializer should only be used if you need to provide + /// custom input can also influence whether the action is enabled. + /// The various convenience initializers should cover most use cases. + /// + /// - parameters: + /// - state: A property to be the state of the `Action`. + /// - isEnabled: A predicate which determines the availability of the `Action`, + /// given the latest `Action` state. + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to be + /// executed by the `Action`. + public init(state: State, enabledIf isEnabled: @escaping (State.Value) -> Bool, execute: @escaping (State.Value, Input) -> SignalProducer) { + let isUserEnabled = isEnabled + + (lifetime, deinitToken) = Lifetime.make() + + // `Action` retains its state property. + lifetime.observeEnded { _ = state } + + (events, eventsObserver) = Signal.Event, Never>.pipe() + (disabledErrors, disabledErrorsObserver) = Signal<(), Never>.pipe() + + values = events.filterMap { $0.value } + errors = events.filterMap { $0.error } + completed = events.filterMap { $0.isCompleted ? () : nil } + + let actionState = MutableProperty(ActionState(isUserEnabled: true, isExecuting: false, value: state.value)) + + // `isEnabled` and `isExecuting` have their own backing so that when the observers + // of these synchronously affects the action state, the signal of the action state + // does not deadlock due to the recursion. + let isExecuting = MutableProperty(false) + self.isExecuting = Property(capturing: isExecuting) + let isEnabled = MutableProperty(actionState.value.isEnabled) + self.isEnabled = Property(capturing: isEnabled) + + func modifyActionState(_ action: (inout ActionState) throws -> Result) rethrows -> Result { + return try actionState.begin { storage in + let oldState = storage.value + defer { + let newState = storage.value + if oldState.isEnabled != newState.isEnabled { + isEnabled.value = newState.isEnabled + } + if oldState.isExecuting != newState.isExecuting { + isExecuting.value = newState.isExecuting + } + } + return try storage.modify(action) + } + } + + lifetime += state.producer.startWithValues { value in + modifyActionState { state in + state.value = value + state.isUserEnabled = isUserEnabled(value) + } + } + + self.execute = { action, input in + return SignalProducer { observer, lifetime in + let latestState: State.Value? = modifyActionState { state in + guard state.isEnabled else { + return nil + } + + state.isExecuting = true + return state.value + } + + guard let state = latestState else { + observer.send(error: .disabled) + action.disabledErrorsObserver.send(value: ()) + return + } + + let interruptHandle = execute(state, input).start { event in + observer.send(event.mapError(ActionError.producerFailed)) + action.eventsObserver.send(value: event) + } + + lifetime.observeEnded { + interruptHandle.dispose() + modifyActionState { $0.isExecuting = false } + } + } + } + } + + /// Initializes an `Action` that uses a property as its state. + /// + /// When the `Action` is asked to start the execution, a unit of work — represented by + /// a `SignalProducer` — would be created by invoking `execute` with the latest value + /// of the state. + /// + /// - parameters: + /// - state: A property to be the state of the `Action`. + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to + /// be executed by the `Action`. + public convenience init(state: P, execute: @escaping (P.Value, Input) -> SignalProducer) { + self.init(state: state, enabledIf: { _ in true }, execute: execute) + } + + /// Initializes an `Action` that would be conditionally enabled. + /// + /// When the `Action` is asked to start the execution with an input value, a unit of + /// work — represented by a `SignalProducer` — would be created by invoking + /// `execute` with the input value. + /// + /// - parameters: + /// - isEnabled: A property which determines the availability of the `Action`. + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to be + /// executed by the `Action`. + public convenience init(enabledIf isEnabled: P, execute: @escaping (Input) -> SignalProducer) where P.Value == Bool { + self.init(state: isEnabled, enabledIf: { $0 }) { _, input in + execute(input) + } + } + + /// Initializes an `Action` that uses a property of optional as its state. + /// + /// When the `Action` is asked to start executing, a unit of work (represented by + /// a `SignalProducer`) is created by invoking `execute` with the latest value + /// of the state and the `input` that was passed to `apply()`. + /// + /// If the property holds a `nil`, the `Action` would be disabled until it is not + /// `nil`. + /// + /// - parameters: + /// - state: A property of optional to be the state of the `Action`. + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to + /// be executed by the `Action`. + public convenience init(unwrapping state: P, execute: @escaping (T, Input) -> SignalProducer) where P.Value == T? { + self.init(state: state, enabledIf: { $0 != nil }) { state, input in + execute(state!, input) + } + } + + /// Initializes an `Action` that uses a `ValidatingProperty` as its state. + /// + /// When the `Action` is asked to start executing, a unit of work (represented by + /// a `SignalProducer`) is created by invoking `execute` with the latest value + /// of the state and the `input` that was passed to `apply()`. + /// + /// If the `ValidatingProperty` does not hold a valid value, the `Action` would be + /// disabled until it's valid. + /// + /// - parameters: + /// - state: A `ValidatingProperty` to be the state of the `Action`. + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to + /// be executed by the `Action`. + public convenience init(validated state: ValidatingProperty, execute: @escaping (T, Input) -> SignalProducer) { + self.init(unwrapping: state.result.map { $0.value }, execute: execute) + } + + + /// Initializes an `Action` that would always be enabled. + /// + /// When the `Action` is asked to start the execution with an input value, a unit of + /// work — represented by a `SignalProducer` — would be created by invoking + /// `execute` with the input value. + /// + /// - parameters: + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to be + /// executed by the `Action`. + public convenience init(execute: @escaping (Input) -> SignalProducer) { + self.init(enabledIf: Property(value: true), execute: execute) + } + + deinit { + eventsObserver.sendCompleted() + disabledErrorsObserver.sendCompleted() + } + + /// Create a `SignalProducer` that would attempt to create and start a unit of work of + /// the `Action`. The `SignalProducer` would forward only events generated by the unit + /// of work it created. + /// + /// If the execution attempt is failed, the producer would fail with + /// `ActionError.disabled`. + /// + /// - parameters: + /// - input: A value to be used to create the unit of work. + /// + /// - returns: A producer that forwards events generated by its started unit of work, + /// or emits `ActionError.disabled` if the execution attempt is failed. + public func apply(_ input: Input) -> SignalProducer> { + return execute(self, input) + } +} + +extension Action: BindingTargetProvider { + public var bindingTarget: BindingTarget { + return BindingTarget(lifetime: lifetime) { [weak self] in self?.apply($0).start() } + } +} + +extension Action where Input == Void { + /// Create a `SignalProducer` that would attempt to create and start a unit of work of + /// the `Action`. The `SignalProducer` would forward only events generated by the unit + /// of work it created. + /// + /// If the execution attempt is failed, the producer would fail with + /// `ActionError.disabled`. + /// + /// - returns: A producer that forwards events generated by its started unit of work, + /// or emits `ActionError.disabled` if the execution attempt is failed. + public func apply() -> SignalProducer> { + return apply(()) + } + + /// Initializes an `Action` that uses a property of optional as its state. + /// + /// When the `Action` is asked to start the execution, a unit of work — represented by + /// a `SignalProducer` — would be created by invoking `execute` with the latest value + /// of the state. + /// + /// If the property holds a `nil`, the `Action` would be disabled until it is not + /// `nil`. + /// + /// - parameters: + /// - state: A property of optional to be the state of the `Action`. + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to + /// be executed by the `Action`. + public convenience init(unwrapping state: P, execute: @escaping (T) -> SignalProducer) where P.Value == T? { + self.init(unwrapping: state) { state, _ in + execute(state) + } + } + + /// Initializes an `Action` that uses a `ValidatingProperty` as its state. + /// + /// When the `Action` is asked to start executing, a unit of work (represented by + /// a `SignalProducer`) is created by invoking `execute` with the latest value + /// of the state and the `input` that was passed to `apply()`. + /// + /// If the `ValidatingProperty` does not hold a valid value, the `Action` would be + /// disabled until it's valid. + /// + /// - parameters: + /// - state: A `ValidatingProperty` to be the state of the `Action`. + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to + /// be executed by the `Action`. + public convenience init(validated state: ValidatingProperty, execute: @escaping (T) -> SignalProducer) { + self.init(validated: state) { state, _ in + execute(state) + } + } + + /// Initializes an `Action` that uses a property as its state. + /// + /// When the `Action` is asked to start the execution, a unit of work — represented by + /// a `SignalProducer` — would be created by invoking `execute` with the latest value + /// of the state. + /// + /// - parameters: + /// - state: A property to be the state of the `Action`. + /// - execute: A closure that produces a unit of work, as `SignalProducer`, to + /// be executed by the `Action`. + public convenience init(state: P, execute: @escaping (T) -> SignalProducer) where P.Value == T { + self.init(state: state) { state, _ in + execute(state) + } + } +} + +/// `ActionError` represents the error that could be emitted by a unit of work of a +/// certain `Action`. +public enum ActionError: Swift.Error { + /// The execution attempt was failed, since the `Action` was disabled. + case disabled + + /// The unit of work emitted an error. + case producerFailed(Error) +} + +extension ActionError where Error: Equatable { + public static func == (lhs: ActionError, rhs: ActionError) -> Bool { + switch (lhs, rhs) { + case (.disabled, .disabled): + return true + + case let (.producerFailed(left), .producerFailed(right)): + return left == right + + default: + return false + } + } +} + +extension ActionError: Equatable where Error: Equatable {} + diff --git a/Pods/ReactiveSwift/Sources/Atomic.swift b/Pods/ReactiveSwift/Sources/Atomic.swift new file mode 100644 index 0000000..de92d8e --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Atomic.swift @@ -0,0 +1,283 @@ +// +// Atomic.swift +// ReactiveSwift +// +// Created by Justin Spahr-Summers on 2014-06-10. +// Copyright (c) 2014 GitHub. All rights reserved. +// + +import Foundation +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) +import MachO +#endif + +/// A simple, generic lock-free finite state machine. +/// +/// - warning: `deinitialize` must be called to dispose of the consumed memory. +internal struct UnsafeAtomicState where State.RawValue == Int32 { + internal typealias Transition = (expected: State, next: State) +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) + private let value: UnsafeMutablePointer + + /// Create a finite state machine with the specified initial state. + /// + /// - parameters: + /// - initial: The desired initial state. + internal init(_ initial: State) { + value = UnsafeMutablePointer.allocate(capacity: 1) + value.initialize(to: initial.rawValue) + } + + /// Deinitialize the finite state machine. + internal func deinitialize() { + value.deinitialize(count: 1) + value.deallocate() + } + + /// Compare the current state with the specified state. + /// + /// - parameters: + /// - expected: The expected state. + /// + /// - returns: `true` if the current state matches the expected state. + /// `false` otherwise. + internal func `is`(_ expected: State) -> Bool { + return expected.rawValue == value.pointee + } + + /// Try to transition from the expected current state to the specified next + /// state. + /// + /// - parameters: + /// - expected: The expected state. + /// - next: The state to transition to. + /// + /// - returns: `true` if the transition succeeds. `false` otherwise. + internal func tryTransition(from expected: State, to next: State) -> Bool { + return OSAtomicCompareAndSwap32Barrier(expected.rawValue, + next.rawValue, + value) + } +#else + private let value: Atomic + + /// Create a finite state machine with the specified initial state. + /// + /// - parameters: + /// - initial: The desired initial state. + internal init(_ initial: State) { + value = Atomic(initial.rawValue) + } + + /// Deinitialize the finite state machine. + internal func deinitialize() {} + + /// Compare the current state with the specified state. + /// + /// - parameters: + /// - expected: The expected state. + /// + /// - returns: `true` if the current state matches the expected state. + /// `false` otherwise. + internal func `is`(_ expected: State) -> Bool { + return value.value == expected.rawValue + } + + /// Try to transition from the expected current state to the specified next + /// state. + /// + /// - parameters: + /// - expected: The expected state. + /// + /// - returns: `true` if the transition succeeds. `false` otherwise. + internal func tryTransition(from expected: State, to next: State) -> Bool { + return value.modify { value in + if value == expected.rawValue { + value = next.rawValue + return true + } + return false + } + } +#endif +} + +/// `Lock` exposes `os_unfair_lock` on supported platforms, with pthread mutex as the +/// fallback. +internal class Lock { + #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) + @available(iOS 10.0, *) + @available(macOS 10.12, *) + @available(tvOS 10.0, *) + @available(watchOS 3.0, *) + internal final class UnfairLock: Lock { + private let _lock: os_unfair_lock_t + + override init() { + _lock = .allocate(capacity: 1) + _lock.initialize(to: os_unfair_lock()) + super.init() + } + + override func lock() { + os_unfair_lock_lock(_lock) + } + + override func unlock() { + os_unfair_lock_unlock(_lock) + } + + override func `try`() -> Bool { + return os_unfair_lock_trylock(_lock) + } + + deinit { + _lock.deinitialize(count: 1) + _lock.deallocate() + } + } + #endif + + internal final class PthreadLock: Lock { + private let _lock: UnsafeMutablePointer + + init(recursive: Bool = false) { + _lock = .allocate(capacity: 1) + _lock.initialize(to: pthread_mutex_t()) + + let attr = UnsafeMutablePointer.allocate(capacity: 1) + attr.initialize(to: pthread_mutexattr_t()) + pthread_mutexattr_init(attr) + + defer { + pthread_mutexattr_destroy(attr) + attr.deinitialize(count: 1) + attr.deallocate() + } + + pthread_mutexattr_settype(attr, Int32(recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_ERRORCHECK)) + + let status = pthread_mutex_init(_lock, attr) + assert(status == 0, "Unexpected pthread mutex error code: \(status)") + + super.init() + } + + override func lock() { + let status = pthread_mutex_lock(_lock) + assert(status == 0, "Unexpected pthread mutex error code: \(status)") + } + + override func unlock() { + let status = pthread_mutex_unlock(_lock) + assert(status == 0, "Unexpected pthread mutex error code: \(status)") + } + + override func `try`() -> Bool { + let status = pthread_mutex_trylock(_lock) + switch status { + case 0: + return true + case EBUSY, EAGAIN: + return false + default: + assertionFailure("Unexpected pthread mutex error code: \(status)") + return false + } + } + + deinit { + let status = pthread_mutex_destroy(_lock) + assert(status == 0, "Unexpected pthread mutex error code: \(status)") + + _lock.deinitialize(count: 1) + _lock.deallocate() + } + } + + static func make() -> Lock { + #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) + if #available(*, iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0) { + return UnfairLock() + } + #endif + + return PthreadLock() + } + + private init() {} + + func lock() { fatalError() } + func unlock() { fatalError() } + func `try`() -> Bool { fatalError() } +} + +/// An atomic variable. +public final class Atomic { + private let lock: Lock + private var _value: Value + + /// Atomically get or set the value of the variable. + public var value: Value { + get { + return withValue { $0 } + } + + set(newValue) { + swap(newValue) + } + } + + /// Initialize the variable with the given initial value. + /// + /// - parameters: + /// - value: Initial value for `self`. + public init(_ value: Value) { + _value = value + lock = Lock.make() + } + + /// Atomically modifies the variable. + /// + /// - parameters: + /// - action: A closure that takes the current value. + /// + /// - returns: The result of the action. + @discardableResult + public func modify(_ action: (inout Value) throws -> Result) rethrows -> Result { + lock.lock() + defer { lock.unlock() } + + return try action(&_value) + } + + /// Atomically perform an arbitrary action using the current value of the + /// variable. + /// + /// - parameters: + /// - action: A closure that takes the current value. + /// + /// - returns: The result of the action. + @discardableResult + public func withValue(_ action: (Value) throws -> Result) rethrows -> Result { + lock.lock() + defer { lock.unlock() } + + return try action(_value) + } + + /// Atomically replace the contents of the variable. + /// + /// - parameters: + /// - newValue: A new value for the variable. + /// + /// - returns: The old value. + @discardableResult + public func swap(_ newValue: Value) -> Value { + return modify { (value: inout Value) in + let oldValue = value + value = newValue + return oldValue + } + } +} diff --git a/Pods/ReactiveSwift/Sources/Bag.swift b/Pods/ReactiveSwift/Sources/Bag.swift new file mode 100644 index 0000000..e38b92b --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Bag.swift @@ -0,0 +1,99 @@ +// +// Bag.swift +// ReactiveSwift +// +// Created by Justin Spahr-Summers on 2014-07-10. +// Copyright (c) 2014 GitHub. All rights reserved. +// + +/// An unordered, non-unique collection of values of type `Element`. +public struct Bag { + /// A uniquely identifying token for removing a value that was inserted into a + /// Bag. + public struct Token { + fileprivate let value: UInt64 + } + + fileprivate var elements: ContiguousArray + fileprivate var tokens: ContiguousArray + + private var nextToken: Token + + public init() { + elements = ContiguousArray() + tokens = ContiguousArray() + nextToken = Token(value: 0) + } + + public init(_ elements: S) where S.Iterator.Element == Element { + self.elements = ContiguousArray(elements) + self.nextToken = Token(value: UInt64(self.elements.count)) + self.tokens = ContiguousArray(0.. Token { + let token = nextToken + + // Practically speaking, this would overflow only if we have 101% uptime and we + // manage to call `insert(_:)` every 1 ns for 500+ years non-stop. + nextToken = Token(value: token.value &+ 1) + + elements.append(value) + tokens.append(token.value) + + return token + } + + /// Remove a value, given the token returned from `insert()`. + /// + /// - note: If the value has already been removed, nothing happens. + /// + /// - parameters: + /// - token: A token returned from a call to `insert()`. + @discardableResult + public mutating func remove(using token: Token) -> Element? { + guard let index = indices.first(where: { tokens[$0] == token.value }) else { + return nil + } + + tokens.remove(at: index) + return elements.remove(at: index) + } +} + +extension Bag: RandomAccessCollection { + public var startIndex: Int { + return elements.startIndex + } + + public var endIndex: Int { + return elements.endIndex + } + + public subscript(index: Int) -> Element { + return elements[index] + } + + public func makeIterator() -> Iterator { + return Iterator(elements.makeIterator()) + } + + /// An iterator of `Bag`. + public struct Iterator: IteratorProtocol { + private var base: ContiguousArray.Iterator + + fileprivate init(_ base: ContiguousArray.Iterator) { + self.base = base + } + + public mutating func next() -> Element? { + return base.next() + } + } +} diff --git a/Pods/ReactiveSwift/Sources/Deprecations+Removals.swift b/Pods/ReactiveSwift/Sources/Deprecations+Removals.swift new file mode 100644 index 0000000..c19fed1 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Deprecations+Removals.swift @@ -0,0 +1,16 @@ +import Foundation +import Dispatch + +// MARK: Unavailable methods in ReactiveSwift 3.0. +extension Signal { + @available(*, unavailable, message:"Use the `Signal.init` that accepts a two-argument generator.") + public convenience init(_ generator: (Observer) -> Disposable?) { fatalError() } +} + +extension Lifetime { + @discardableResult + @available(*, unavailable, message:"Use `observeEnded(_:)` with a method reference to `dispose()` instead.") + public func add(_ d: Disposable?) -> Disposable? { fatalError() } +} + +// MARK: Deprecated types diff --git a/Pods/ReactiveSwift/Sources/Disposable.swift b/Pods/ReactiveSwift/Sources/Disposable.swift new file mode 100644 index 0000000..73220db --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Disposable.swift @@ -0,0 +1,380 @@ +// +// Disposable.swift +// ReactiveSwift +// +// Created by Justin Spahr-Summers on 2014-06-02. +// Copyright (c) 2014 GitHub. All rights reserved. +// + +/// Represents something that can be “disposed”, usually associated with freeing +/// resources or canceling work. +public protocol Disposable: class { + /// Whether this disposable has been disposed already. + var isDisposed: Bool { get } + + /// Disposing of the resources represented by `self`. If `self` has already + /// been disposed of, it does nothing. + /// + /// - note: Implementations must issue a memory barrier. + func dispose() +} + +/// Represents the state of a disposable. +private enum DisposableState: Int32 { + /// The disposable is active. + case active + + /// The disposable has been disposed. + case disposed +} + +extension UnsafeAtomicState where State == DisposableState { + /// Try to transition from `active` to `disposed`. + /// + /// - returns: `true` if the transition succeeds. `false` otherwise. + @inline(__always) + fileprivate func tryDispose() -> Bool { + return tryTransition(from: .active, to: .disposed) + } +} + +/// A disposable that does not have side effect upon disposal. +internal final class _SimpleDisposable: Disposable { + private let state = UnsafeAtomicState(.active) + + var isDisposed: Bool { + return state.is(.disposed) + } + + func dispose() { + _ = state.tryDispose() + } + + deinit { + state.deinitialize() + } +} + +/// A disposable that has already been disposed. +internal final class NopDisposable: Disposable { + static let shared = NopDisposable() + var isDisposed = true + func dispose() {} + private init() {} +} + +/// A type-erased disposable that forwards operations to an underlying disposable. +public final class AnyDisposable: Disposable { + private final class ActionDisposable: Disposable { + let state: UnsafeAtomicState + var action: (() -> Void)? + + var isDisposed: Bool { + return state.is(.disposed) + } + + init(_ action: (() -> Void)?) { + self.state = UnsafeAtomicState(.active) + self.action = action + } + + deinit { + state.deinitialize() + } + + func dispose() { + if state.tryDispose() { + action?() + action = nil + } + } + } + + private let base: Disposable + + public var isDisposed: Bool { + return base.isDisposed + } + + /// Create a disposable which runs the given action upon disposal. + /// + /// - parameters: + /// - action: A closure to run when calling `dispose()`. + public init(_ action: @escaping () -> Void) { + base = ActionDisposable(action) + } + + /// Create a disposable. + public init() { + base = _SimpleDisposable() + } + + /// Create a disposable which wraps the given disposable. + /// + /// - parameters: + /// - disposable: The disposable to be wrapped. + public init(_ disposable: Disposable) { + base = disposable + } + + public func dispose() { + base.dispose() + } +} + +/// A disposable that will dispose of any number of other disposables. +public final class CompositeDisposable: Disposable { + private let disposables: Atomic?> + private var state: UnsafeAtomicState + + public var isDisposed: Bool { + return state.is(.disposed) + } + + /// Initialize a `CompositeDisposable` containing the given sequence of + /// disposables. + /// + /// - parameters: + /// - disposables: A collection of objects conforming to the `Disposable` + /// protocol + public init(_ disposables: S) where S.Iterator.Element == Disposable { + let bag = Bag(disposables) + self.disposables = Atomic(bag) + self.state = UnsafeAtomicState(.active) + } + + /// Initialize a `CompositeDisposable` containing the given sequence of + /// disposables. + /// + /// - parameters: + /// - disposables: A collection of objects conforming to the `Disposable` + /// protocol + public convenience init(_ disposables: S) + where S.Iterator.Element == Disposable? + { + self.init(disposables.compactMap { $0 }) + } + + /// Initializes an empty `CompositeDisposable`. + public convenience init() { + self.init([Disposable]()) + } + + public func dispose() { + if state.tryDispose(), let disposables = disposables.swap(nil) { + for disposable in disposables { + disposable.dispose() + } + } + } + + /// Add the given disposable to the composite. + /// + /// - parameters: + /// - disposable: A disposable. + /// + /// - returns: A disposable to remove `disposable` from the composite. `nil` if the + /// composite has been disposed of, `disposable` has been disposed of, or + /// `disposable` is `nil`. + @discardableResult + public func add(_ disposable: Disposable?) -> Disposable? { + guard let d = disposable, !d.isDisposed, !isDisposed else { + disposable?.dispose() + return nil + } + + return disposables.modify { disposables in + guard let token = disposables?.insert(d) else { return nil } + + return AnyDisposable { [weak self] in + self?.disposables.modify { + $0?.remove(using: token) + } + } + } + } + + /// Add the given action to the composite. + /// + /// - parameters: + /// - action: A closure to be invoked when the composite is disposed of. + /// + /// - returns: A disposable to remove `disposable` from the composite. `nil` if the + /// composite has been disposed of, `disposable` has been disposed of, or + /// `disposable` is `nil`. + @discardableResult + public func add(_ action: @escaping () -> Void) -> Disposable? { + return add(AnyDisposable(action)) + } + + deinit { + state.deinitialize() + } + + /// Adds the right-hand-side disposable to the left-hand-side + /// `CompositeDisposable`. + /// + /// ```` + /// disposable += producer + /// .filter { ... } + /// .map { ... } + /// .start(observer) + /// ```` + /// + /// - parameters: + /// - lhs: Disposable to add to. + /// - rhs: Disposable to add. + /// + /// - returns: An instance of `DisposableHandle` that can be used to opaquely + /// remove the disposable later (if desired). + @discardableResult + public static func += (lhs: CompositeDisposable, rhs: Disposable?) -> Disposable? { + return lhs.add(rhs) + } + + /// Adds the right-hand-side `ActionDisposable` to the left-hand-side + /// `CompositeDisposable`. + /// + /// ```` + /// disposable += { ... } + /// ```` + /// + /// - parameters: + /// - lhs: Disposable to add to. + /// - rhs: Closure to add as a disposable. + /// + /// - returns: An instance of `DisposableHandle` that can be used to opaquely + /// remove the disposable later (if desired). + @discardableResult + public static func += (lhs: CompositeDisposable, rhs: @escaping () -> Void) -> Disposable? { + return lhs.add(rhs) + } +} + +/// A disposable that, upon deinitialization, will automatically dispose of +/// its inner disposable. +public final class ScopedDisposable: Disposable { + /// The disposable which will be disposed when the ScopedDisposable + /// deinitializes. + public let inner: Inner + + public var isDisposed: Bool { + return inner.isDisposed + } + + /// Initialize the receiver to dispose of the argument upon + /// deinitialization. + /// + /// - parameters: + /// - disposable: A disposable to dispose of when deinitializing. + public init(_ disposable: Inner) { + inner = disposable + } + + deinit { + dispose() + } + + public func dispose() { + return inner.dispose() + } +} + +extension ScopedDisposable where Inner == AnyDisposable { + /// Initialize the receiver to dispose of the argument upon + /// deinitialization. + /// + /// - parameters: + /// - disposable: A disposable to dispose of when deinitializing, which + /// will be wrapped in an `AnyDisposable`. + public convenience init(_ disposable: Disposable) { + self.init(Inner(disposable)) + } +} + +extension ScopedDisposable where Inner == CompositeDisposable { + /// Adds the right-hand-side disposable to the left-hand-side + /// `ScopedDisposable`. + /// + /// ```` + /// disposable += { ... } + /// ```` + /// + /// - parameters: + /// - lhs: Disposable to add to. + /// - rhs: Disposable to add. + /// + /// - returns: An instance of `DisposableHandle` that can be used to opaquely + /// remove the disposable later (if desired). + @discardableResult + public static func += (lhs: ScopedDisposable, rhs: Disposable?) -> Disposable? { + return lhs.inner.add(rhs) + } + + /// Adds the right-hand-side disposable to the left-hand-side + /// `ScopedDisposable`. + /// + /// ```` + /// disposable += { ... } + /// ```` + /// + /// - parameters: + /// - lhs: Disposable to add to. + /// - rhs: Closure to add as a disposable. + /// + /// - returns: An instance of `DisposableHandle` that can be used to opaquely + /// remove the disposable later (if desired). + @discardableResult + public static func += (lhs: ScopedDisposable, rhs: @escaping () -> Void) -> Disposable? { + return lhs.inner.add(rhs) + } +} + +/// A disposable that disposes of its wrapped disposable, and allows its +/// wrapped disposable to be replaced. +public final class SerialDisposable: Disposable { + private let _inner: Atomic + private var state: UnsafeAtomicState + + public var isDisposed: Bool { + return state.is(.disposed) + } + + /// The current inner disposable to dispose of. + /// + /// Whenever this property is set (even to the same value!), the previous + /// disposable is automatically disposed. + public var inner: Disposable? { + get { + return _inner.value + } + + set(disposable) { + _inner.swap(disposable)?.dispose() + + if let disposable = disposable, isDisposed { + disposable.dispose() + } + } + } + + /// Initializes the receiver to dispose of the argument when the + /// SerialDisposable is disposed. + /// + /// - parameters: + /// - disposable: Optional disposable. + public init(_ disposable: Disposable? = nil) { + self._inner = Atomic(disposable) + self.state = UnsafeAtomicState(DisposableState.active) + } + + public func dispose() { + if state.tryDispose() { + _inner.swap(nil)?.dispose() + } + } + + deinit { + state.deinitialize() + } +} diff --git a/Pods/ReactiveSwift/Sources/Event.swift b/Pods/ReactiveSwift/Sources/Event.swift new file mode 100644 index 0000000..7c2495c --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Event.swift @@ -0,0 +1,1037 @@ +import Foundation +import Dispatch + +extension Signal { + /// Represents a signal event. + /// + /// Signals must conform to the grammar: + /// `value* (failed | completed | interrupted)?` + public enum Event { + /// A value provided by the signal. + case value(Value) + + /// The signal terminated because of an error. No further events will be + /// received. + case failed(Error) + + /// The signal successfully terminated. No further events will be received. + case completed + + /// Event production on the signal has been interrupted. No further events + /// will be received. + /// + /// - important: This event does not signify the successful or failed + /// completion of the signal. + case interrupted + + /// Whether this event is a completed event. + public var isCompleted: Bool { + switch self { + case .completed: + return true + + case .value, .failed, .interrupted: + return false + } + } + + /// Whether this event indicates signal termination (i.e., that no further + /// events will be received). + public var isTerminating: Bool { + switch self { + case .value: + return false + + case .failed, .completed, .interrupted: + return true + } + } + + /// Lift the given closure over the event's value. + /// + /// - important: The closure is called only on `value` type events. + /// + /// - parameters: + /// - f: A closure that accepts a value and returns a new value + /// + /// - returns: An event with function applied to a value in case `self` is a + /// `value` type of event. + public func map(_ f: (Value) -> U) -> Signal.Event { + switch self { + case let .value(value): + return .value(f(value)) + + case let .failed(error): + return .failed(error) + + case .completed: + return .completed + + case .interrupted: + return .interrupted + } + } + + /// Lift the given closure over the event's error. + /// + /// - important: The closure is called only on failed type event. + /// + /// - parameters: + /// - f: A closure that accepts an error object and returns + /// a new error object + /// + /// - returns: An event with function applied to an error object in case + /// `self` is a `.Failed` type of event. + public func mapError(_ f: (Error) -> F) -> Signal.Event { + switch self { + case let .value(value): + return .value(value) + + case let .failed(error): + return .failed(f(error)) + + case .completed: + return .completed + + case .interrupted: + return .interrupted + } + } + + /// Unwrap the contained `value` value. + public var value: Value? { + if case let .value(value) = self { + return value + } else { + return nil + } + } + + /// Unwrap the contained `Error` value. + public var error: Error? { + if case let .failed(error) = self { + return error + } else { + return nil + } + } + } +} + +extension Signal.Event where Value: Equatable, Error: Equatable { + public static func == (lhs: Signal.Event, rhs: Signal.Event) -> Bool { + switch (lhs, rhs) { + case let (.value(left), .value(right)): + return left == right + + case let (.failed(left), .failed(right)): + return left == right + + case (.completed, .completed): + return true + + case (.interrupted, .interrupted): + return true + + default: + return false + } + } +} + +extension Signal.Event: Equatable where Value: Equatable, Error: Equatable {} + +extension Signal.Event: CustomStringConvertible { + public var description: String { + switch self { + case let .value(value): + return "VALUE \(value)" + + case let .failed(error): + return "FAILED \(error)" + + case .completed: + return "COMPLETED" + + case .interrupted: + return "INTERRUPTED" + } + } +} + +/// Event protocol for constraining signal extensions +public protocol EventProtocol { + /// The value type of an event. + associatedtype Value + /// The error type of an event. If errors aren't possible then `Never` can + /// be used. + associatedtype Error: Swift.Error + /// Extracts the event from the receiver. + var event: Signal.Event { get } +} + +extension Signal.Event: EventProtocol { + public var event: Signal.Event { + return self + } +} + +// Event Transformations +// +// Operators backed by event transformations have such characteristics: +// +// 1. Unary +// The operator applies to only one stream. +// +// 2. Serial +// The outcome need not be synchronously emitted, but all events must be delivered in +// serial order. +// +// 3. No side effect upon interruption. +// The operator must not perform any side effect upon receving `interrupted`. +// +// Examples of ineligible operators (for now): +// +// 1. `timeout` +// This operator forwards the `failed` event on a different scheduler. +// +// 2. `combineLatest` +// This operator applies to two or more streams. +// +// 3. `SignalProducer.then` +// This operator starts a second stream when the first stream completes. +// +// 4. `on` +// This operator performs side effect upon interruption. + +extension Signal.Event { + internal typealias Transformation = (@escaping Signal.Observer.Action, Lifetime) -> Signal.Observer.Action + + internal static func filter(_ isIncluded: @escaping (Value) -> Bool) -> Transformation { + return { action, _ in + return { event in + switch event { + case let .value(value): + if isIncluded(value) { + action(.value(value)) + } + + case .completed: + action(.completed) + + case let .failed(error): + action(.failed(error)) + + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static func filterMap(_ transform: @escaping (Value) -> U?) -> Transformation { + return { action, _ in + return { event in + switch event { + case let .value(value): + if let newValue = transform(value) { + action(.value(newValue)) + } + + case .completed: + action(.completed) + + case let .failed(error): + action(.failed(error)) + + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static func map(_ transform: @escaping (Value) -> U) -> Transformation { + return { action, _ in + return { event in + switch event { + case let .value(value): + action(.value(transform(value))) + + case .completed: + action(.completed) + + case let .failed(error): + action(.failed(error)) + + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static func mapError(_ transform: @escaping (Error) -> E) -> Transformation { + return { action, _ in + return { event in + switch event { + case let .value(value): + action(.value(value)) + + case .completed: + action(.completed) + + case let .failed(error): + action(.failed(transform(error))) + + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static var materialize: Transformation.Event, Never> { + return { action, _ in + return { event in + action(.value(event)) + + switch event { + case .interrupted: + action(.interrupted) + + case .completed, .failed: + action(.completed) + + case .value: + break + } + } + } + } + + internal static var materializeResults: Transformation, Never> { + return { action, _ in + return { event in + switch event { + case .value(let value): + action(.value(Result(success: value))) + + case .failed(let error): + action(.value(Result(failure: error))) + action(.completed) + + case .completed: + action(.completed) + + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static func attemptMap(_ transform: @escaping (Value) -> Result) -> Transformation { + return { action, _ in + return { event in + switch event { + case let .value(value): + switch transform(value) { + case let .success(value): + action(.value(value)) + case let .failure(error): + action(.failed(error)) + } + case let .failed(error): + action(.failed(error)) + case .completed: + action(.completed) + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static func attempt(_ action: @escaping (Value) -> Result<(), Error>) -> Transformation { + return attemptMap { value -> Result in + return action(value).map { _ in value } + } + } +} + +extension Signal.Event where Error == Swift.Error { + internal static func attempt(_ action: @escaping (Value) throws -> Void) -> Transformation { + return attemptMap { value in + try action(value) + return value + } + } + + internal static func attemptMap(_ transform: @escaping (Value) throws -> U) -> Transformation { + return attemptMap { value in + Result { try transform(value) } + } + } +} + +extension Signal.Event { + internal static func take(first count: Int) -> Transformation { + assert(count >= 1) + + return { action, _ in + var taken = 0 + + return { event in + guard let value = event.value else { + action(event) + return + } + + if taken < count { + taken += 1 + action(.value(value)) + } + + if taken == count { + action(.completed) + } + } + } + } + + internal static func take(last count: Int) -> Transformation { + return { action, _ in + var buffer: [Value] = [] + buffer.reserveCapacity(count) + + return { event in + switch event { + case let .value(value): + // To avoid exceeding the reserved capacity of the buffer, + // we remove then add. Remove elements until we have room to + // add one more. + while (buffer.count + 1) > count { + buffer.remove(at: 0) + } + + buffer.append(value) + case let .failed(error): + action(.failed(error)) + case .completed: + buffer.forEach { action(.value($0)) } + action(.completed) + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static func take(while shouldContinue: @escaping (Value) -> Bool) -> Transformation { + return { action, _ in + return { event in + if let value = event.value, !shouldContinue(value) { + action(.completed) + } else { + action(event) + } + } + } + } + + internal static func skip(first count: Int) -> Transformation { + precondition(count > 0) + + return { action, _ in + var skipped = 0 + + return { event in + if case .value = event, skipped < count { + skipped += 1 + } else { + action(event) + } + } + } + } + + internal static func skip(while shouldContinue: @escaping (Value) -> Bool) -> Transformation { + return { action, _ in + var isSkipping = true + + return { event in + switch event { + case let .value(value): + isSkipping = isSkipping && shouldContinue(value) + if !isSkipping { + fallthrough + } + + case .failed, .completed, .interrupted: + action(event) + } + } + } + } +} + +extension Signal.Event where Value: EventProtocol, Error == Never { + internal static var dematerialize: Transformation { + return { action, _ in + return { event in + switch event { + case let .value(innerEvent): + action(innerEvent.event) + + case .failed: + fatalError("Never is impossible to construct") + + case .completed: + action(.completed) + + case .interrupted: + action(.interrupted) + } + } + } + } +} + +extension Signal.Event where Value: ResultProtocol, Error == Never { + internal static var dematerializeResults: Transformation { + return { action, _ in + return { event in + let event = event.map { $0.result } + + switch event { + case .value(.success(let value)): + action(.value(value)) + + case .value(.failure(let error)): + action(.failed(error)) + + case .failed: + fatalError("Never is impossible to construct") + + case .completed: + action(.completed) + + case .interrupted: + action(.interrupted) + } + } + } + } +} + +extension Signal.Event where Value: OptionalProtocol { + internal static var skipNil: Transformation { + return filterMap { $0.optional } + } +} + +/// A reference type which wraps an array to auxiliate the collection of values +/// for `collect` operator. +private final class CollectState { + var values: [Value] = [] + + /// Collects a new value. + func append(_ value: Value) { + values.append(value) + } + + /// Check if there are any items remaining. + /// + /// - note: This method also checks if there weren't collected any values + /// and, in that case, it means an empty array should be sent as the + /// result of collect. + var isEmpty: Bool { + /// We use capacity being zero to determine if we haven't collected any + /// value since we're keeping the capacity of the array to avoid + /// unnecessary and expensive allocations). This also guarantees + /// retro-compatibility around the original `collect()` operator. + return values.isEmpty && values.capacity > 0 + } + + /// Removes all values previously collected if any. + func flush() { + // Minor optimization to avoid consecutive allocations. Can + // be useful for sequences of regular or similar size and to + // track if any value was ever collected. + values.removeAll(keepingCapacity: true) + } +} + +extension Signal.Event { + internal static var collect: Transformation<[Value], Error> { + return collect { _, _ in false } + } + + internal static func collect(count: Int) -> Transformation<[Value], Error> { + precondition(count > 0) + return collect { values in values.count == count } + } + + internal static func collect(_ shouldEmit: @escaping (_ collectedValues: [Value]) -> Bool) -> Transformation<[Value], Error> { + return { action, _ in + let state = CollectState() + + return { event in + switch event { + case let .value(value): + state.append(value) + if shouldEmit(state.values) { + action(.value(state.values)) + state.flush() + } + case .completed: + if !state.isEmpty { + action(.value(state.values)) + } + action(.completed) + case let .failed(error): + action(.failed(error)) + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static func collect(_ shouldEmit: @escaping (_ collected: [Value], _ latest: Value) -> Bool) -> Transformation<[Value], Error> { + return { action, _ in + let state = CollectState() + + return { event in + switch event { + case let .value(value): + if shouldEmit(state.values, value) { + action(.value(state.values)) + state.flush() + } + state.append(value) + case .completed: + if !state.isEmpty { + action(.value(state.values)) + } + action(.completed) + case let .failed(error): + action(.failed(error)) + case .interrupted: + action(.interrupted) + } + } + } + } + + /// Implementation detail of `combinePrevious`. A default argument of a `nil` initial + /// is deliberately avoided, since in the case of `Value` being an optional, the + /// `nil` literal would be materialized as `Optional.none` instead of `Value`, + /// thus changing the semantic. + internal static func combinePrevious(initial: Value?) -> Transformation<(Value, Value), Error> { + return { action, _ in + var previous = initial + + return { event in + switch event { + case let .value(value): + if let previous = previous { + action(.value((previous, value))) + } + previous = value + case .completed: + action(.completed) + case let .failed(error): + action(.failed(error)) + case .interrupted: + action(.interrupted) + } + } + } + } + + internal static func skipRepeats(_ isEquivalent: @escaping (Value, Value) -> Bool) -> Transformation { + return { action, _ in + var previous: Value? + + return { event in + switch event { + case let .value(value): + if let previous = previous, isEquivalent(previous, value) { + return + } + previous = value + fallthrough + case .completed, .interrupted, .failed: + action(event) + } + } + } + } + + internal static func uniqueValues(_ transform: @escaping (Value) -> Identity) -> Transformation { + return { action, _ in + var seenValues: Set = [] + + return { event in + switch event { + case let .value(value): + let identity = transform(value) + let (inserted, _) = seenValues.insert(identity) + if inserted { + fallthrough + } + + case .failed, .completed, .interrupted: + action(event) + } + } + } + } + + internal static func scan(into initialResult: U, _ nextPartialResult: @escaping (inout U, Value) -> Void) -> Transformation { + return { action, _ in + var accumulator = initialResult + + return { event in + action(event.map { value in + nextPartialResult(&accumulator, value) + return accumulator + }) + } + } + } + + internal static func scan(_ initialResult: U, _ nextPartialResult: @escaping (U, Value) -> U) -> Transformation { + return scan(into: initialResult) { $0 = nextPartialResult($0, $1) } + } + + internal static func reduce(into initialResult: U, _ nextPartialResult: @escaping (inout U, Value) -> Void) -> Transformation { + return { action, _ in + var accumulator = initialResult + + return { event in + switch event { + case let .value(value): + nextPartialResult(&accumulator, value) + case .completed: + action(.value(accumulator)) + action(.completed) + case .interrupted: + action(.interrupted) + case let .failed(error): + action(.failed(error)) + } + } + } + } + + internal static func reduce(_ initialResult: U, _ nextPartialResult: @escaping (U, Value) -> U) -> Transformation { + return reduce(into: initialResult) { $0 = nextPartialResult($0, $1) } + } + + internal static func observe(on scheduler: Scheduler) -> Transformation { + return { action, lifetime in + lifetime.observeEnded { + scheduler.schedule { + action(.interrupted) + } + } + + return { event in + scheduler.schedule { + if !lifetime.hasEnded { + action(event) + } + } + } + } + } + + internal static func lazyMap(on scheduler: Scheduler, transform: @escaping (Value) -> U) -> Transformation { + return { action, lifetime in + let box = Atomic(nil) + let completionDisposable = SerialDisposable() + let valueDisposable = SerialDisposable() + + lifetime += valueDisposable + lifetime += completionDisposable + + lifetime.observeEnded { + scheduler.schedule { + action(.interrupted) + } + } + + return { event in + switch event { + case let .value(value): + // Schedule only when there is no prior outstanding value. + if box.swap(value) == nil { + valueDisposable.inner = scheduler.schedule { + if let value = box.swap(nil) { + action(.value(transform(value))) + } + } + } + + case .completed, .failed: + // Completion and failure should not discard the outstanding + // value. + completionDisposable.inner = scheduler.schedule { + action(event.map(transform)) + } + + case .interrupted: + // `interrupted` overrides any outstanding value and any + // scheduled completion/failure. + valueDisposable.dispose() + completionDisposable.dispose() + scheduler.schedule { + action(.interrupted) + } + } + } + } + } + + internal static func delay(_ interval: TimeInterval, on scheduler: DateScheduler) -> Transformation { + precondition(interval >= 0) + + return { action, lifetime in + lifetime.observeEnded { + scheduler.schedule { + action(.interrupted) + } + } + + return { event in + switch event { + case .failed, .interrupted: + scheduler.schedule { + action(event) + } + + case .value, .completed: + let date = scheduler.currentDate.addingTimeInterval(interval) + scheduler.schedule(after: date) { + if !lifetime.hasEnded { + action(event) + } + } + } + } + } + } + + internal static func throttle(_ interval: TimeInterval, on scheduler: DateScheduler) -> Transformation { + precondition(interval >= 0) + + return { action, lifetime in + let state: Atomic> = Atomic(ThrottleState()) + let schedulerDisposable = SerialDisposable() + + lifetime.observeEnded { + schedulerDisposable.dispose() + scheduler.schedule { action(.interrupted) } + } + + return { event in + guard let value = event.value else { + schedulerDisposable.inner = scheduler.schedule { + action(event) + } + return + } + + let scheduleDate: Date = state.modify { state in + state.pendingValue = value + + let proposedScheduleDate: Date + if let previousDate = state.previousDate, previousDate <= scheduler.currentDate { + proposedScheduleDate = previousDate.addingTimeInterval(interval) + } else { + proposedScheduleDate = scheduler.currentDate + } + + return proposedScheduleDate < scheduler.currentDate ? scheduler.currentDate : proposedScheduleDate + } + + schedulerDisposable.inner = scheduler.schedule(after: scheduleDate) { + if let pendingValue = state.modify({ $0.retrieveValue(date: scheduleDate) }) { + action(.value(pendingValue)) + } + } + } + } + } + + internal static func debounce(_ interval: TimeInterval, on scheduler: DateScheduler, discardWhenCompleted: Bool) -> Transformation { + precondition(interval >= 0) + + let state: Atomic> = Atomic(ThrottleState(previousDate: scheduler.currentDate, pendingValue: nil)) + + return { action, lifetime in + let d = SerialDisposable() + + lifetime.observeEnded { + d.dispose() + scheduler.schedule { action(.interrupted) } + } + + return { event in + switch event { + case let .value(value): + state.modify { state in + state.pendingValue = value + } + let date = scheduler.currentDate.addingTimeInterval(interval) + d.inner = scheduler.schedule(after: date) { + if let pendingValue = state.modify({ $0.retrieveValue(date: date) }) { + action(.value(pendingValue)) + } + } + + case .completed: + d.inner = scheduler.schedule { + let pending: (value: Value, previousDate: Date)? = state.modify { state in + defer { state.pendingValue = nil } + guard let pendingValue = state.pendingValue, let previousDate = state.previousDate else { return nil } + return (pendingValue, previousDate) + } + if !discardWhenCompleted, let (pendingValue, previousDate) = pending { + scheduler.schedule(after: previousDate.addingTimeInterval(interval)) { + action(.value(pendingValue)) + action(.completed) + } + } else { + action(.completed) + } + } + + case .failed, .interrupted: + d.inner = scheduler.schedule { + action(event) + } + } + } + } + } + + internal static func collect(every interval: DispatchTimeInterval, on scheduler: DateScheduler, skipEmpty: Bool, discardWhenCompleted: Bool) -> Transformation<[Value], Error> { + return { action, lifetime in + let state = Atomic>(.init(skipEmpty: skipEmpty)) + let d = SerialDisposable() + + d.inner = scheduler.schedule(after: scheduler.currentDate.addingTimeInterval(interval), interval: interval, leeway: interval * 0.1) { + let (currentValues, isCompleted) = state.modify { ($0.collect(), $0.isCompleted) } + if let currentValues = currentValues { + action(.value(currentValues)) + } + if isCompleted { + action(.completed) + } + } + + lifetime.observeEnded { + d.dispose() + scheduler.schedule { action(.interrupted) } + } + + return { event in + switch event { + case let .value(value): + state.modify { $0.values.append(value) } + case let .failed(error): + d.inner = scheduler.schedule { action(.failed(error)) } + case .completed where !discardWhenCompleted: + state.modify { $0.isCompleted = true } + case .completed: + d.inner = scheduler.schedule { action(.completed) } + case .interrupted: + d.inner = scheduler.schedule { action(.interrupted) } + } + } + } + } +} + +private struct CollectEveryState { + let skipEmpty: Bool + var values: [Value] = [] + var isCompleted: Bool = false + + init(skipEmpty: Bool) { + self.skipEmpty = skipEmpty + } + + var hasValues: Bool { + return !values.isEmpty || !skipEmpty + } + + mutating func collect() -> [Value]? { + guard hasValues else { return nil } + defer { values.removeAll() } + return values + } +} + +private struct ThrottleState { + var previousDate: Date? + var pendingValue: Value? + + mutating func retrieveValue(date: Date) -> Value? { + defer { + if pendingValue != nil { + pendingValue = nil + previousDate = date + } + } + return pendingValue + } +} + +extension Signal.Event where Error == Never { + internal static func promoteError(_: F.Type) -> Transformation { + return { action, _ in + return { event in + switch event { + case let .value(value): + action(.value(value)) + case .failed: + fatalError("Never is impossible to construct") + case .completed: + action(.completed) + case .interrupted: + action(.interrupted) + } + } + } + } +} + +extension Signal.Event where Value == Never { + internal static func promoteValue(_: U.Type) -> Transformation { + return { action, _ in + return { event in + action(event.promoteValue()) + } + } + } +} + +extension Signal.Event where Value == Never { + internal func promoteValue() -> Signal.Event { + switch event { + case .value: + fatalError("Never is impossible to construct") + case let .failed(error): + return .failed(error) + case .completed: + return .completed + case .interrupted: + return .interrupted + } + } +} diff --git a/Pods/ReactiveSwift/Sources/EventLogger.swift b/Pods/ReactiveSwift/Sources/EventLogger.swift new file mode 100644 index 0000000..f44170b --- /dev/null +++ b/Pods/ReactiveSwift/Sources/EventLogger.swift @@ -0,0 +1,174 @@ +// +// EventLogger.swift +// ReactiveSwift +// +// Created by Rui Peres on 30/04/2016. +// Copyright © 2016 GitHub. All rights reserved. +// + +import Foundation + +/// A namespace for logging event types. +public enum LoggingEvent { + public enum Signal: String { + case value, completed, failed, terminated, disposed, interrupted + + public static let allEvents: Set = [ + .value, .completed, .failed, .terminated, .disposed, .interrupted, + ] + } + + public enum SignalProducer: String { + case starting, started, value, completed, failed, terminated, disposed, interrupted + + public static let allEvents: Set = [ + .starting, .started, .value, .completed, .failed, .terminated, .disposed, .interrupted, + ] + } +} + +public func defaultEventLog(identifier: String, event: String, fileName: String, functionName: String, lineNumber: Int) { + print("[\(identifier)] \(event) fileName: \(fileName), functionName: \(functionName), lineNumber: \(lineNumber)") +} + +/// A type that represents an event logging function. +/// Signature is: +/// - identifier +/// - event +/// - fileName +/// - functionName +/// - lineNumber +public typealias EventLogger = ( + _ identifier: String, + _ event: String, + _ fileName: String, + _ functionName: String, + _ lineNumber: Int +) -> Void + +// See https://bugs.swift.org/browse/SR-6796. +fileprivate struct LogContext { + let events: Set + let identifier: String + let fileName: String + let functionName: String + let lineNumber: Int + let logger: EventLogger + + func log(_ event: Event) -> ((T) -> Void)? { + return event.logIfNeeded(events: self.events) { event in + self.logger(self.identifier, event, self.fileName, self.functionName, self.lineNumber) + } + } + + func log(_ event: Event) -> (() -> Void)? { + return event.logIfNeededNoArg(events: self.events) { event in + self.logger(self.identifier, event, self.fileName, self.functionName, self.lineNumber) + } + } +} + +extension Signal { + /// Logs all events that the receiver sends. By default, it will print to + /// the standard output. + /// + /// - parameters: + /// - identifier: a string to identify the Signal firing events. + /// - events: Types of events to log. + /// - fileName: Name of the file containing the code which fired the + /// event. + /// - functionName: Function where event was fired. + /// - lineNumber: Line number where event was fired. + /// - logger: Logger that logs the events. + /// + /// - returns: Signal that, when observed, logs the fired events. + public func logEvents(identifier: String = "", events: Set = LoggingEvent.Signal.allEvents, fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, logger: @escaping EventLogger = defaultEventLog) -> Signal { + let logContext = LogContext(events: events, + identifier: identifier, + fileName: fileName, + functionName: functionName, + lineNumber: lineNumber, + logger: logger) + + return self.on( + failed: logContext.log(.failed), + completed: logContext.log(.completed), + interrupted: logContext.log(.interrupted), + terminated: logContext.log(.terminated), + disposed: logContext.log(.disposed), + value: logContext.log(.value) + ) + } +} + +extension SignalProducer { + /// Logs all events that the receiver sends. By default, it will print to + /// the standard output. + /// + /// - parameters: + /// - identifier: a string to identify the SignalProducer firing events. + /// - events: Types of events to log. + /// - fileName: Name of the file containing the code which fired the + /// event. + /// - functionName: Function where event was fired. + /// - lineNumber: Line number where event was fired. + /// - logger: Logger that logs the events. + /// + /// - returns: Signal producer that, when started, logs the fired events. + public func logEvents(identifier: String = "", + events: Set = LoggingEvent.SignalProducer.allEvents, + fileName: String = #file, + functionName: String = #function, + lineNumber: Int = #line, + logger: @escaping EventLogger = defaultEventLog + ) -> SignalProducer { + let logContext = LogContext(events: events, + identifier: identifier, + fileName: fileName, + functionName: functionName, + lineNumber: lineNumber, + logger: logger) + + return self.on( + starting: logContext.log(.starting), + started: logContext.log(.started), + failed: logContext.log(.failed), + completed: logContext.log(.completed), + interrupted: logContext.log(.interrupted), + terminated: logContext.log(.terminated), + disposed: logContext.log(.disposed), + value: logContext.log(.value) + ) + } +} + +private protocol LoggingEventProtocol: Hashable, RawRepresentable {} +extension LoggingEvent.Signal: LoggingEventProtocol {} +extension LoggingEvent.SignalProducer: LoggingEventProtocol {} + +private extension LoggingEventProtocol { + // FIXME: See https://bugs.swift.org/browse/SR-6796 and the discussion in https://github.com/apple/swift/pull/14477. + // Due to differences in the type checker, this method cannot + // overload the generic `logIfNeeded`, or otherwise it would lead to + // infinite recursion with Swift 4.0.x. + func logIfNeededNoArg(events: Set, logger: @escaping (String) -> Void) -> (() -> Void)? { + return (self.logIfNeeded(events: events, logger: logger) as ((()) -> Void)?) + .map { closure in + { closure(()) } + } + } + + func logIfNeeded(events: Set, logger: @escaping (String) -> Void) -> ((T) -> Void)? { + guard events.contains(self) else { + return nil + } + + return { value in + if value is Void { + logger("\(self.rawValue)") + } else { + logger("\(self.rawValue) \(value)") + } + } + } +} diff --git a/Pods/ReactiveSwift/Sources/Flatten.swift b/Pods/ReactiveSwift/Sources/Flatten.swift new file mode 100644 index 0000000..99ddd36 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Flatten.swift @@ -0,0 +1,1132 @@ +// +// Flatten.swift +// ReactiveSwift +// +// Created by Neil Pankey on 11/30/15. +// Copyright © 2015 GitHub. All rights reserved. +// + +/// Describes how a stream of inner streams should be flattened into a stream of values. +public struct FlattenStrategy { + fileprivate enum Kind { + case concurrent(limit: UInt) + case latest + case race + } + + fileprivate let kind: Kind + + private init(kind: Kind) { + self.kind = kind + } + + /// The stream of streams is merged, so that any value sent by any of the inner + /// streams is forwarded immediately to the flattened stream of values. + /// + /// The flattened stream of values completes only when the stream of streams, and all + /// the inner streams it sent, have completed. + /// + /// Any interruption of inner streams is treated as completion, and does not interrupt + /// the flattened stream of values. + /// + /// Any failure from the inner streams is propagated immediately to the flattened + /// stream of values. + public static let merge = FlattenStrategy(kind: .concurrent(limit: .max)) + + /// The stream of streams is concatenated, so that only values from one inner stream + /// are forwarded at a time, in the order the inner streams are received. + /// + /// In other words, if an inner stream is received when a previous inner stream has + /// yet terminated, the received stream would be enqueued. + /// + /// The flattened stream of values completes only when the stream of streams, and all + /// the inner streams it sent, have completed. + /// + /// Any interruption of inner streams is treated as completion, and does not interrupt + /// the flattened stream of values. + /// + /// Any failure from the inner streams is propagated immediately to the flattened + /// stream of values. + public static let concat = FlattenStrategy(kind: .concurrent(limit: 1)) + + /// The stream of streams is merged with the given concurrency cap, so that any value + /// sent by any of the inner streams on the fly is forwarded immediately to the + /// flattened stream of values. + /// + /// In other words, if an inner stream is received when a previous inner stream has + /// yet terminated, the received stream would be enqueued. + /// + /// The flattened stream of values completes only when the stream of streams, and all + /// the inner streams it sent, have completed. + /// + /// Any interruption of inner streams is treated as completion, and does not interrupt + /// the flattened stream of values. + /// + /// Any failure from the inner streams is propagated immediately to the flattened + /// stream of values. + /// + /// - precondition: `limit > 0`. + public static func concurrent(limit: UInt) -> FlattenStrategy { + return FlattenStrategy(kind: .concurrent(limit: limit)) + } + + /// Forward only values from the latest inner stream sent by the stream of streams. + /// The active inner stream is disposed of as a new inner stream is received. + /// + /// The flattened stream of values completes only when the stream of streams, and all + /// the inner streams it sent, have completed. + /// + /// Any interruption of inner streams is treated as completion, and does not interrupt + /// the flattened stream of values. + /// + /// Any failure from the inner streams is propagated immediately to the flattened + /// stream of values. + public static let latest = FlattenStrategy(kind: .latest) + + /// Forward only events from the first inner stream that sends an event. Any other + /// in-flight inner streams is disposed of when the winning inner stream is + /// determined. + /// + /// The flattened stream of values completes only when the stream of streams, and the + /// winning inner stream, have completed. + /// + /// Any interruption of inner streams is propagated immediately to the flattened + /// stream of values. + /// + /// Any failure from the inner streams is propagated immediately to the flattened + /// stream of values. + public static let race = FlattenStrategy(kind: .race) +} + +extension Signal where Value: SignalProducerConvertible, Error == Value.Error { + /// Flattens the inner producers sent upon `signal` (into a single signal of + /// values), according to the semantics of the given strategy. + /// + /// - note: If `signal` or an active inner producer fails, the returned + /// signal will forward that failure immediately. + /// + /// - warning: `interrupted` events on inner producers will be treated like + /// `completed` events on inner producers. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + public func flatten(_ strategy: FlattenStrategy) -> Signal { + switch strategy.kind { + case .concurrent(let limit): + return self.concurrent(limit: limit) + + case .latest: + return self.switchToLatest() + + case .race: + return self.race() + } + } +} + +extension Signal where Value: SignalProducerConvertible, Error == Never { + /// Flattens the inner producers sent upon `signal` (into a single signal of + /// values), according to the semantics of the given strategy. + /// + /// - note: If `signal` or an active inner producer fails, the returned + /// signal will forward that failure immediately. + /// + /// - warning: `interrupted` events on inner producers will be treated like + /// `completed` events on inner producers. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + public func flatten(_ strategy: FlattenStrategy) -> Signal { + return self + .promoteError(Value.Error.self) + .flatten(strategy) + } +} + +extension Signal where Value: SignalProducerConvertible, Error == Never, Value.Error == Never { + /// Flattens the inner producers sent upon `signal` (into a single signal of + /// values), according to the semantics of the given strategy. + /// + /// - warning: `interrupted` events on inner producers will be treated like + /// `completed` events on inner producers. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + public func flatten(_ strategy: FlattenStrategy) -> Signal { + switch strategy.kind { + case .concurrent(let limit): + return self.concurrent(limit: limit) + + case .latest: + return self.switchToLatest() + + case .race: + return self.race() + } + } +} + +extension Signal where Value: SignalProducerConvertible, Value.Error == Never { + /// Flattens the inner producers sent upon `signal` (into a single signal of + /// values), according to the semantics of the given strategy. + /// + /// - note: If `signal` fails, the returned signal will forward that failure + /// immediately. + /// + /// - warning: `interrupted` events on inner producers will be treated like + /// `completed` events on inner producers. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + public func flatten(_ strategy: FlattenStrategy) -> Signal { + return self.flatMap(strategy) { $0.producer.promoteError(Error.self) } + } +} + +extension SignalProducer where Value: SignalProducerConvertible, Error == Value.Error { + /// Flattens the inner producers sent upon `producer` (into a single + /// producer of values), according to the semantics of the given strategy. + /// + /// - note: If `producer` or an active inner producer fails, the returned + /// producer will forward that failure immediately. + /// + /// - warning: `interrupted` events on inner producers will be treated like + /// `completed` events on inner producers. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + public func flatten(_ strategy: FlattenStrategy) -> SignalProducer { + switch strategy.kind { + case .concurrent(let limit): + return self.concurrent(limit: limit) + + case .latest: + return self.switchToLatest() + + case .race: + return self.race() + } + } +} + +extension SignalProducer where Value: SignalProducerConvertible, Error == Never { + /// Flattens the inner producers sent upon `producer` (into a single + /// producer of values), according to the semantics of the given strategy. + /// + /// - note: If an active inner producer fails, the returned producer will + /// forward that failure immediately. + /// + /// - warning: `interrupted` events on inner producers will be treated like + /// `completed` events on inner producers. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + public func flatten(_ strategy: FlattenStrategy) -> SignalProducer { + return self + .promoteError(Value.Error.self) + .flatten(strategy) + } +} + +extension SignalProducer where Value: SignalProducerConvertible, Error == Never, Value.Error == Never { + /// Flattens the inner producers sent upon `producer` (into a single + /// producer of values), according to the semantics of the given strategy. + /// + /// - warning: `interrupted` events on inner producers will be treated like + /// `completed` events on inner producers. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + public func flatten(_ strategy: FlattenStrategy) -> SignalProducer { + switch strategy.kind { + case .concurrent(let limit): + return self.concurrent(limit: limit) + + case .latest: + return self.switchToLatest() + + case .race: + return self.race() + } + } +} + +extension SignalProducer where Value: SignalProducerConvertible, Value.Error == Never { + /// Flattens the inner producers sent upon `signal` (into a single signal of + /// values), according to the semantics of the given strategy. + /// + /// - note: If `signal` fails, the returned signal will forward that failure + /// immediately. + /// + /// - warning: `interrupted` events on inner producers will be treated like + /// `completed` events on inner producers. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + public func flatten(_ strategy: FlattenStrategy) -> SignalProducer { + return self.flatMap(strategy) { $0.producer.promoteError(Error.self) } + } +} + +extension Signal where Value: Sequence { + /// Flattens the `sequence` value sent by `signal`. + public func flatten() -> Signal { + return self.flatMap(.merge, SignalProducer.init) + } +} + +extension SignalProducer where Value: Sequence { + /// Flattens the `sequence` value sent by `signal`. + public func flatten() -> SignalProducer { + return self.flatMap(.merge, SignalProducer.init) + } +} + +extension Signal where Value: SignalProducerConvertible, Error == Value.Error { + fileprivate func concurrent(limit: UInt) -> Signal { + precondition(limit > 0, "The concurrent limit must be greater than zero.") + + return Signal { relayObserver, lifetime in + lifetime += self.observeConcurrent(relayObserver, limit, lifetime) + } + } + + fileprivate func observeConcurrent(_ observer: Signal.Observer, _ limit: UInt, _ lifetime: Lifetime) -> Disposable? { + let state = Atomic(ConcurrentFlattenState(limit: limit)) + + func startNextIfNeeded() { + while let producer = state.modify({ $0.dequeue() }) { + let producerState = UnsafeAtomicState(.starting) + let deinitializer = ScopedDisposable(AnyDisposable(producerState.deinitialize)) + + producer.startWithSignal { signal, inner in + let handle = lifetime += inner + + signal.observe { event in + switch event { + case .completed, .interrupted: + handle?.dispose() + + let shouldComplete: Bool = state.modify { state in + state.activeCount -= 1 + return state.shouldComplete + } + + withExtendedLifetime(deinitializer) { + if shouldComplete { + observer.sendCompleted() + } else if producerState.is(.started) { + startNextIfNeeded() + } + } + + case .value, .failed: + observer.send(event) + } + } + } + + withExtendedLifetime(deinitializer) { + producerState.setStarted() + } + } + } + + return observe { event in + switch event { + case let .value(value): + state.modify { $0.queue.append(value.producer) } + startNextIfNeeded() + + case let .failed(error): + observer.send(error: error) + + case .completed: + let shouldComplete: Bool = state.modify { state in + state.isOuterCompleted = true + return state.shouldComplete + } + + if shouldComplete { + observer.sendCompleted() + } + + case .interrupted: + observer.sendInterrupted() + } + } + } +} + +extension SignalProducer where Value: SignalProducerConvertible, Error == Value.Error { + fileprivate func concurrent(limit: UInt) -> SignalProducer { + precondition(limit > 0, "The concurrent limit must be greater than zero.") + + return SignalProducer { relayObserver, lifetime in + self.startWithSignal { signal, interruptHandle in + lifetime += interruptHandle + + _ = signal.observeConcurrent(relayObserver, limit, lifetime) + } + } + } +} + +extension SignalProducer { + /// `concat`s `next` onto `self`. + /// + /// - parameters: + /// - next: A follow-up producer to concat `self` with. + /// + /// - returns: A producer that will start `self` and then on completion of + /// `self` - will start `next`. + public func concat(_ next: SignalProducer) -> SignalProducer { + return SignalProducer, Error>([ self, next ]).flatten(.concat) + } + + /// `concat`s `next` onto `self`. + /// + /// - parameters: + /// - next: A follow-up producer to concat `self` with. + /// + /// - returns: A producer that will start `self` and then on completion of + /// `self` - will start `next`. + public func concat(_ next: Next) -> SignalProducer where Next.Value == Value, Next.Error == Error { + return concat(next.producer) + } + + /// `concat`s `value` onto `self`. + /// + /// - parameters: + /// - value: A value to concat onto `self`. + /// + /// - returns: A producer that, when started, will emit own values and on + /// completion will emit a `value`. + public func concat(value: Value) -> SignalProducer { + return concat(SignalProducer(value: value)) + } + + /// `concat`s `error` onto `self`. + /// + /// - parameters: + /// - error: An error to concat onto `self`. + /// + /// - returns: A producer that, when started, will emit own values and on + /// completion will emit an `error`. + public func concat(error: Error) -> SignalProducer { + return concat(SignalProducer(error: error)) + } + + /// `concat`s `self` onto initial `previous`. + /// + /// - parameters: + /// - previous: A producer to start before `self`. + /// + /// - returns: A signal producer that, when started, first emits values from + /// `previous` producer and then from `self`. + public func prefix(_ previous: SignalProducer) -> SignalProducer { + return previous.concat(self) + } + + /// `concat`s `self` onto initial `previous`. + /// + /// - parameters: + /// - previous: A producer to start before `self`. + /// + /// - returns: A signal producer that, when started, first emits values from + /// `previous` producer and then from `self`. + public func prefix(_ previous: Previous) -> SignalProducer where Previous.Value == Value, Previous.Error == Error { + return prefix(previous.producer) + } + + /// `concat`s `self` onto initial `value`. + /// + /// - parameters: + /// - value: A first value to emit. + /// + /// - returns: A producer that, when started, first emits `value`, then all + /// values emited by `self`. + public func prefix(value: Value) -> SignalProducer { + return prefix(SignalProducer(value: value)) + } +} + +private final class ConcurrentFlattenState { + typealias Producer = ReactiveSwift.SignalProducer + + /// The limit of active producers. + let limit: UInt + + /// The number of active producers. + var activeCount: UInt = 0 + + /// The producers waiting to be started. + var queue: [Producer] = [] + + /// Whether the outer producer has completed. + var isOuterCompleted = false + + /// Whether the flattened signal should complete. + var shouldComplete: Bool { + return isOuterCompleted && activeCount == 0 && queue.isEmpty + } + + init(limit: UInt) { + self.limit = limit + } + + /// Dequeue the next producer if one should be started. + /// + /// - returns: The `Producer` to start or `nil` if no producer should be + /// started. + func dequeue() -> Producer? { + if activeCount < limit, !queue.isEmpty { + activeCount += 1 + return queue.removeFirst() + } else { + return nil + } + } +} + +private enum ProducerState: Int32 { + case starting + case started +} + +extension UnsafeAtomicState where State == ProducerState { + fileprivate func setStarted() { + precondition(tryTransition(from: .starting, to: .started), "The transition is not supposed to fail.") + } +} + +extension Signal { + /// Merges the given signals into a single `Signal` that will emit all + /// values from each of them, and complete when all of them have completed. + /// + /// - parameters: + /// - signals: A sequence of signals to merge. + public static func merge(_ signals: Seq) -> Signal where Seq.Iterator.Element == Signal + { + return SignalProducer, Error>(signals) + .flatten(.merge) + .startAndRetrieveSignal() + } + + /// Merges the given signals into a single `Signal` that will emit all + /// values from each of them, and complete when all of them have completed. + /// + /// - parameters: + /// - signals: A list of signals to merge. + public static func merge(_ signals: Signal...) -> Signal { + return Signal.merge(signals) + } +} + +extension SignalProducer { + /// Merges the given producers into a single `SignalProducer` that will emit + /// all values from each of them, and complete when all of them have + /// completed. + /// + /// - parameters: + /// - producers: A sequence of producers to merge. + public static func merge(_ producers: Seq) -> SignalProducer where Seq.Iterator.Element == SignalProducer + { + return SignalProducer(producers).flatten(.merge) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error { + return SignalProducer.merge([a.producer, b.producer]) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B, _ c: C) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error, C.Value == Value, C.Error == Error { + return SignalProducer.merge([a.producer, b.producer, c.producer]) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B, _ c: C, _ d: D) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error, C.Value == Value, C.Error == Error, D.Value == Value, D.Error == Error { + return SignalProducer.merge([a.producer, b.producer, c.producer, d.producer]) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error, C.Value == Value, C.Error == Error, D.Value == Value, D.Error == Error, E.Value == Value, E.Error == Error { + return SignalProducer.merge([a.producer, b.producer, c.producer, d.producer, e.producer]) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error, C.Value == Value, C.Error == Error, D.Value == Value, D.Error == Error, E.Value == Value, E.Error == Error, F.Value == Value, F.Error == Error { + return SignalProducer.merge([a.producer, b.producer, c.producer, d.producer, e.producer, f.producer]) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error, C.Value == Value, C.Error == Error, D.Value == Value, D.Error == Error, E.Value == Value, E.Error == Error, F.Value == Value, F.Error == Error, G.Value == Value, G.Error == Error { + return SignalProducer.merge([a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer]) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error, C.Value == Value, C.Error == Error, D.Value == Value, D.Error == Error, E.Value == Value, E.Error == Error, F.Value == Value, F.Error == Error, G.Value == Value, G.Error == Error, H.Value == Value, H.Error == Error { + return SignalProducer.merge([a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer]) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error, C.Value == Value, C.Error == Error, D.Value == Value, D.Error == Error, E.Value == Value, E.Error == Error, F.Value == Value, F.Error == Error, G.Value == Value, G.Error == Error, H.Value == Value, H.Error == Error, I.Value == Value, I.Error == Error { + return SignalProducer.merge([a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer, i.producer]) + } + + /// Merge the values of all the given producers, in the manner described by `merge(_:)`. + public static func merge(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I, _ j: J) -> SignalProducer where A.Value == Value, A.Error == Error, B.Value == Value, B.Error == Error, C.Value == Value, C.Error == Error, D.Value == Value, D.Error == Error, E.Value == Value, E.Error == Error, F.Value == Value, F.Error == Error, G.Value == Value, G.Error == Error, H.Value == Value, H.Error == Error, I.Value == Value, I.Error == Error, J.Value == Value, J.Error == Error { + return SignalProducer.merge([a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer, i.producer, j.producer]) + } +} + +extension Signal where Value: SignalProducerConvertible, Error == Value.Error { + /// Returns a signal that forwards values from the latest signal sent on + /// `signal`, ignoring values sent on previous inner signal. + /// + /// - warning: An error sent on `signal` or the latest inner signal will be + /// sent on the returned signal. + /// + /// - note: The returned signal completes when `signal` and the latest inner + /// signal have both completed. + fileprivate func switchToLatest() -> Signal { + return Signal { observer, lifetime in + let serial = SerialDisposable() + lifetime += serial + lifetime += self.observeSwitchToLatest(observer, serial) + } + } + + fileprivate func observeSwitchToLatest(_ observer: Signal.Observer, _ latestInnerDisposable: SerialDisposable) -> Disposable? { + let state = Atomic(LatestState()) + + return self.observe { event in + switch event { + case let .value(p): + p.producer.startWithSignal { innerSignal, innerDisposable in + state.modify { + // When we replace the disposable below, this prevents + // the generated Interrupted event from doing any work. + $0.replacingInnerSignal = true + } + + latestInnerDisposable.inner = innerDisposable + + state.modify { + $0.replacingInnerSignal = false + $0.innerSignalComplete = false + } + + innerSignal.observe { event in + switch event { + case .interrupted: + // If interruption occurred as a result of a new + // producer arriving, we don't want to notify our + // observer. + let shouldComplete: Bool = state.modify { state in + if !state.replacingInnerSignal { + state.innerSignalComplete = true + } + return !state.replacingInnerSignal && state.outerSignalComplete + } + + if shouldComplete { + observer.sendCompleted() + } + + case .completed: + let shouldComplete: Bool = state.modify { + $0.innerSignalComplete = true + return $0.outerSignalComplete + } + + if shouldComplete { + observer.sendCompleted() + } + + case .value, .failed: + observer.send(event) + } + } + } + + case let .failed(error): + observer.send(error: error) + + case .completed: + let shouldComplete: Bool = state.modify { + $0.outerSignalComplete = true + return $0.innerSignalComplete + } + + if shouldComplete { + observer.sendCompleted() + } + + case .interrupted: + observer.sendInterrupted() + } + } + } +} + +extension SignalProducer where Value: SignalProducerConvertible, Error == Value.Error { + /// - warning: An error sent on `self` or the latest inner producer will be + /// sent on the returned producer. + /// + /// - note: The returned producer completes when `self` and the latest inner + /// producer have both completed. + /// + /// - returns: A producer that forwards values from the latest producer sent + /// on `self`, ignoring values sent on previous inner producer. + fileprivate func switchToLatest() -> SignalProducer { + return SignalProducer { observer, lifetime in + let latestInnerDisposable = SerialDisposable() + lifetime += latestInnerDisposable + + self.startWithSignal { signal, signalDisposable in + lifetime += signalDisposable + lifetime += signal.observeSwitchToLatest(observer, latestInnerDisposable) + } + } + } +} + +private struct LatestState { + var outerSignalComplete: Bool = false + var innerSignalComplete: Bool = true + + var replacingInnerSignal: Bool = false +} + +extension Signal where Value: SignalProducerConvertible, Error == Value.Error { + /// Returns a signal that forwards values from the "first input signal to send an event" + /// (winning signal) that is sent on `self`, ignoring values sent from other inner signals. + /// + /// An error sent on `self` or the winning inner signal will be sent on the + /// returned signal. + /// + /// The returned signal completes when `self` and the winning inner signal have both completed. + fileprivate func race() -> Signal { + return Signal { observer, lifetime in + let relayDisposable = CompositeDisposable() + lifetime += relayDisposable + lifetime += self.observeRace(observer, relayDisposable) + } + } + + fileprivate func observeRace(_ observer: Signal.Observer, _ relayDisposable: CompositeDisposable) -> Disposable? { + let state = Atomic(RaceState()) + + return self.observe { event in + switch event { + case let .value(innerProducer): + // Ignore consecutive `innerProducer`s if any `innerSignal` already sent an event. + guard !relayDisposable.isDisposed else { + return + } + + innerProducer.producer.startWithSignal { innerSignal, innerDisposable in + state.modify { + $0.innerSignalComplete = false + } + + let disposableHandle = relayDisposable.add(innerDisposable) + var isWinningSignal = false + + innerSignal.observe { event in + if !isWinningSignal { + isWinningSignal = state.modify { state in + guard !state.isActivated else { + return false + } + + state.isActivated = true + return true + } + + // Ignore non-winning signals. + guard isWinningSignal else { return } + + // The disposals would be run exactly once immediately after + // the winning signal flips `state.isActivated`. + disposableHandle?.dispose() + relayDisposable.dispose() + } + + switch event { + case .completed: + let shouldComplete: Bool = state.modify { state in + state.innerSignalComplete = true + return state.outerSignalComplete + } + + if shouldComplete { + observer.sendCompleted() + } + + case .value, .failed, .interrupted: + observer.send(event) + } + } + } + + case let .failed(error): + observer.send(error: error) + + case .completed: + let shouldComplete: Bool = state.modify { state in + state.outerSignalComplete = true + return state.innerSignalComplete + } + + if shouldComplete { + observer.sendCompleted() + } + + case .interrupted: + observer.sendInterrupted() + } + } + } +} + +extension SignalProducer where Value: SignalProducerConvertible, Error == Value.Error { + /// Returns a producer that forwards values from the "first input producer to send an event" + /// (winning producer) that is sent on `self`, ignoring values sent from other inner producers. + /// + /// An error sent on `self` or the winning inner producer will be sent on the + /// returned producer. + /// + /// The returned producer completes when `self` and the winning inner producer have both completed. + fileprivate func race() -> SignalProducer { + return SignalProducer { observer, lifetime in + let relayDisposable = CompositeDisposable() + lifetime += relayDisposable + + self.startWithSignal { signal, signalDisposable in + lifetime += signalDisposable + lifetime += signal.observeRace(observer, relayDisposable) + } + } + } +} + +private struct RaceState { + var outerSignalComplete = false + var innerSignalComplete = true + var isActivated = false +} + +extension Signal { + /// Maps each event from `signal` to a new signal, then flattens the + /// resulting producers (into a signal of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If `signal` or any of the created producers fail, the + /// returned signal will forward that failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> SignalProducer) -> Signal{ + return map(transform).flatten(strategy) + } + + /// Maps each event from `signal` to a new signal, then flattens the + /// resulting producers (into a signal of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If `signal` or any of the created producers fail, the + /// returned signal will forward that failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> Signal where Inner.Error == Error { + return flatMap(strategy) { transform($0).producer } + } + + /// Maps each event from `signal` to a new signal, then flattens the + /// resulting producers (into a signal of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If `signal` fails, the returned signal will forward that + /// failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> SignalProducer) -> Signal { + return map(transform).flatten(strategy) + } + + /// Maps each event from `signal` to a new signal, then flattens the + /// resulting producers (into a signal of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If `signal` fails, the returned signal will forward that + /// failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> Signal where Inner.Error == Never { + return flatMap(strategy) { transform($0).producer } + } +} + +extension Signal where Error == Never { + /// Maps each event from `signal` to a new signal, then flattens the + /// resulting signals (into a signal of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If any of the created signals emit an error, the returned + /// signal will forward that error immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> SignalProducer) -> Signal { + return map(transform).flatten(strategy) + } + + /// Maps each event from `signal` to a new signal, then flattens the + /// resulting signals (into a signal of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If any of the created signals emit an error, the returned + /// signal will forward that error immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> Signal { + return flatMap(strategy) { transform($0).producer } + } + + /// Maps each event from `signal` to a new signal, then flattens the + /// resulting signals (into a signal of values), according to the + /// semantics of the given strategy. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> SignalProducer) -> Signal { + return map(transform).flatten(strategy) + } + + /// Maps each event from `signal` to a new signal, then flattens the + /// resulting signals (into a signal of values), according to the + /// semantics of the given strategy. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> Signal where Inner.Error == Never { + return flatMap(strategy) { transform($0).producer } + } +} + +extension SignalProducer { + /// Maps each event from `self` to a new producer, then flattens the + /// resulting producers (into a producer of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If `self` or any of the created producers fail, the returned + /// producer will forward that failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> SignalProducer) -> SignalProducer { + return map(transform).flatten(strategy) + } + + /// Maps each event from `self` to a new producer, then flattens the + /// resulting producers (into a producer of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If `self` or any of the created producers fail, the returned + /// producer will forward that failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> SignalProducer where Inner.Error == Error { + return flatMap(strategy) { transform($0).producer } + } + + /// Maps each event from `self` to a new producer, then flattens the + /// resulting producers (into a producer of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If `self` fails, the returned producer will forward that + /// failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> SignalProducer) -> SignalProducer { + return map(transform).flatten(strategy) + } + + /// Maps each event from `self` to a new producer, then flattens the + /// resulting producers (into a producer of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If `self` fails, the returned producer will forward that + /// failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> SignalProducer where Inner.Error == Never { + return flatMap(strategy) { transform($0).producer } + } +} + +extension SignalProducer where Error == Never { + /// Maps each event from `self` to a new producer, then flattens the + /// resulting producers (into a producer of values), according to the + /// semantics of the given strategy. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> SignalProducer) -> SignalProducer { + return map(transform).flatten(strategy) + } + + /// Maps each event from `self` to a new producer, then flattens the + /// resulting producers (into a producer of values), according to the + /// semantics of the given strategy. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> SignalProducer where Inner.Error == Error { + return flatMap(strategy) { transform($0).producer } + } + + /// Maps each event from `self` to a new producer, then flattens the + /// resulting producers (into a producer of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If any of the created producers fail, the returned producer + /// will forward that failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> SignalProducer) -> SignalProducer { + return map(transform).flatten(strategy) + } + + /// Maps each event from `self` to a new producer, then flattens the + /// resulting producers (into a producer of values), according to the + /// semantics of the given strategy. + /// + /// - warning: If any of the created producers fail, the returned producer + /// will forward that failure immediately. + /// + /// - parameters: + /// - strategy: Strategy used when flattening signals. + /// - transform: A closure that takes a value emitted by `self` and + /// returns a signal producer with transformed value. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> SignalProducer { + return flatMap(strategy) { transform($0).producer } + } +} + +extension Signal { + /// Catches any failure that may occur on the input signal, mapping to a new + /// producer that starts in its place. + /// + /// - parameters: + /// - transform: A closure that accepts emitted error and returns a signal + /// producer with a different type of error. + public func flatMapError(_ transform: @escaping (Error) -> SignalProducer) -> Signal { + return Signal { observer, lifetime in + lifetime += self.observeFlatMapError(transform, observer, SerialDisposable()) + } + } + + /// Catches any failure that may occur on the input signal, mapping to a new + /// producer that starts in its place. + /// + /// - parameters: + /// - transform: A closure that accepts emitted error and returns a signal + /// producer with a different type of error. + public func flatMapError(_ transform: @escaping (Error) -> Inner) -> Signal where Inner.Value == Value { + return flatMapError { transform($0).producer } + } + + fileprivate func observeFlatMapError( + _ handler: @escaping (Error) -> Inner, + _ observer: Signal.Observer, + _ serialDisposable: SerialDisposable) -> Disposable? where Inner.Value == Value { + return self.observe { event in + switch event { + case let .value(value): + observer.send(value: value) + case let .failed(error): + handler(error).producer.startWithSignal { signal, disposable in + serialDisposable.inner = disposable + signal.observe(observer) + } + case .completed: + observer.sendCompleted() + case .interrupted: + observer.sendInterrupted() + } + } + } +} + +extension SignalProducer { + /// Catches any failure that may occur on the input producer, mapping to a + /// new producer that starts in its place. + /// + /// - parameters: + /// - transform: A closure that accepts emitted error and returns a signal + /// producer with a different type of error. + public func flatMapError(_ transform: @escaping (Error) -> SignalProducer) -> SignalProducer { + return SignalProducer { observer, lifetime in + let serialDisposable = SerialDisposable() + lifetime += serialDisposable + + self.startWithSignal { signal, signalDisposable in + serialDisposable.inner = signalDisposable + + _ = signal.observeFlatMapError(transform, observer, serialDisposable) + } + } + } + + /// Catches any failure that may occur on the input producer, mapping to a + /// new producer that starts in its place. + /// + /// - parameters: + /// - transform: A closure that accepts emitted error and returns a signal + /// producer with a different type of error. + public func flatMapError(_ transform: @escaping (Error) -> Inner) -> SignalProducer where Inner.Value == Value { + return flatMapError { transform($0).producer } + } +} diff --git a/Pods/ReactiveSwift/Sources/FoundationExtensions.swift b/Pods/ReactiveSwift/Sources/FoundationExtensions.swift new file mode 100644 index 0000000..2856811 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/FoundationExtensions.swift @@ -0,0 +1,136 @@ +// +// FoundationExtensions.swift +// ReactiveSwift +// +// Created by Justin Spahr-Summers on 2014-10-19. +// Copyright (c) 2014 GitHub. All rights reserved. +// + +import Foundation +import Dispatch + +#if os(Linux) + import let CDispatch.NSEC_PER_USEC + import let CDispatch.NSEC_PER_SEC +#endif + +extension NotificationCenter: ReactiveExtensionsProvider {} + +extension Reactive where Base: NotificationCenter { + /// Returns a Signal to observe posting of the specified notification. + /// + /// - parameters: + /// - name: name of the notification to observe + /// - object: an instance which sends the notifications + /// + /// - returns: A Signal of notifications posted that match the given criteria. + /// + /// - note: The signal does not terminate naturally. Observers must be + /// explicitly disposed to avoid leaks. + public func notifications(forName name: Notification.Name?, object: AnyObject? = nil) -> Signal { + return Signal { [base = self.base] observer, lifetime in + let notificationObserver = base.addObserver(forName: name, object: object, queue: nil) { notification in + observer.send(value: notification) + } + + lifetime.observeEnded { + base.removeObserver(notificationObserver) + } + } + } +} + +private let defaultSessionError = NSError(domain: "org.reactivecocoa.ReactiveSwift.Reactivity.URLSession.dataWithRequest", + code: 1, + userInfo: nil) + +extension URLSession: ReactiveExtensionsProvider {} + +extension Reactive where Base: URLSession { + /// Returns a SignalProducer which performs the work associated with an + /// `NSURLSession` + /// + /// - parameters: + /// - request: A request that will be performed when the producer is + /// started + /// + /// - returns: A producer that will execute the given request once for each + /// invocation of `start()`. + /// + /// - note: This method will not send an error event in the case of a server + /// side error (i.e. when a response with status code other than + /// 200...299 is received). + public func data(with request: URLRequest) -> SignalProducer<(Data, URLResponse), Error> { + return SignalProducer { [base = self.base] observer, lifetime in + let task = base.dataTask(with: request) { data, response, error in + if let data = data, let response = response { + observer.send(value: (data, response)) + observer.sendCompleted() + } else { + observer.send(error: error ?? defaultSessionError) + } + } + + lifetime.observeEnded(task.cancel) + task.resume() + } + } +} + +extension Date { + internal func addingTimeInterval(_ interval: DispatchTimeInterval) -> Date { + return addingTimeInterval(interval.timeInterval) + } +} + +extension DispatchTimeInterval { + internal var timeInterval: TimeInterval { + switch self { + case let .seconds(s): + return TimeInterval(s) + case let .milliseconds(ms): + return TimeInterval(TimeInterval(ms) / 1000.0) + case let .microseconds(us): + return TimeInterval(Int64(us)) * TimeInterval(NSEC_PER_USEC) / TimeInterval(NSEC_PER_SEC) + case let .nanoseconds(ns): + return TimeInterval(ns) / TimeInterval(NSEC_PER_SEC) + case .never: + return .infinity + } + } + + // This was added purely so that our test scheduler to "go backwards" in + // time. See `TestScheduler.rewind(by interval: DispatchTimeInterval)`. + internal static prefix func -(lhs: DispatchTimeInterval) -> DispatchTimeInterval { + switch lhs { + case let .seconds(s): + return .seconds(-s) + case let .milliseconds(ms): + return .milliseconds(-ms) + case let .microseconds(us): + return .microseconds(-us) + case let .nanoseconds(ns): + return .nanoseconds(-ns) + case .never: + return .never + } + } + + /// Scales a time interval by the given scalar specified in `rhs`. + /// + /// - returns: Scaled interval in minimal appropriate unit + internal static func *(lhs: DispatchTimeInterval, rhs: Double) -> DispatchTimeInterval { + let seconds = lhs.timeInterval * rhs + var result: DispatchTimeInterval = .never + if let integerTimeInterval = Int(exactly: (seconds * 1000 * 1000 * 1000).rounded()) { + result = .nanoseconds(integerTimeInterval) + } else if let integerTimeInterval = Int(exactly: (seconds * 1000 * 1000).rounded()) { + result = .microseconds(integerTimeInterval) + } else if let integerTimeInterval = Int(exactly: (seconds * 1000).rounded()) { + result = .milliseconds(integerTimeInterval) + } else if let integerTimeInterval = Int(exactly: (seconds).rounded()) { + result = .seconds(integerTimeInterval) + } + return result + } +} diff --git a/Pods/ReactiveSwift/Sources/Lifetime.swift b/Pods/ReactiveSwift/Sources/Lifetime.swift new file mode 100644 index 0000000..bf06e32 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Lifetime.swift @@ -0,0 +1,114 @@ +import Foundation + +/// Represents the lifetime of an object, and provides a hook to observe when +/// the object deinitializes. +public final class Lifetime { + private let disposables: CompositeDisposable + + /// A signal that sends a `completed` event when the lifetime ends. + /// + /// - note: Consider using `Lifetime.observeEnded` if only a closure observer + /// is to be attached. + public var ended: Signal { + return Signal { observer, lifetime in + lifetime += (disposables += observer.sendCompleted) + } + } + + /// A flag indicating whether the lifetime has ended. + public var hasEnded: Bool { + return disposables.isDisposed + } + + /// Initialize a `Lifetime` object with the supplied composite disposable. + /// + /// - parameters: + /// - signal: The composite disposable. + internal init(_ disposables: CompositeDisposable) { + self.disposables = disposables + } + + /// Initialize a `Lifetime` from a lifetime token, which is expected to be + /// associated with an object. + /// + /// - important: The resulting lifetime object does not retain the lifetime + /// token. + /// + /// - parameters: + /// - token: A lifetime token for detecting the deinitialization of the + /// associated object. + public convenience init(_ token: Token) { + self.init(token.disposables) + } + + /// Observe the termination of `self`. + /// + /// - parameters: + /// - action: The action to be invoked when `self` ends. + /// + /// - returns: A disposable that detaches `action` from the lifetime, or `nil` + /// if `lifetime` has already ended. + @discardableResult + public func observeEnded(_ action: @escaping () -> Void) -> Disposable? { + return disposables += action + } + + /// Add the given disposable as an observer of `self`. + /// + /// - parameters: + /// - disposable: The disposable to be disposed of when `self` ends. + /// + /// - returns: A disposable that detaches `disposable` from the lifetime, or `nil` + /// if `lifetime` has already ended. + @discardableResult + public static func += (lifetime: Lifetime, disposable: Disposable?) -> Disposable? { + guard let dispose = disposable?.dispose else { return nil } + return lifetime.observeEnded(dispose) + } +} + +extension Lifetime { + /// Factory method for creating a `Lifetime` and its associated `Token`. + /// + /// - returns: A `(lifetime, token)` tuple. + public static func make() -> (lifetime: Lifetime, token: Token) { + let token = Token() + return (Lifetime(token), token) + } + + /// A `Lifetime` that has already ended. + public static let empty: Lifetime = { + let disposables = CompositeDisposable() + disposables.dispose() + return Lifetime(disposables) + }() +} + +extension Lifetime { + /// A token object which completes its associated `Lifetime` when + /// it deinitializes, or when `dispose()` is called. + /// + /// It is generally used in conjuncion with `Lifetime` as a private + /// deinitialization trigger. + /// + /// ``` + /// class MyController { + /// private let (lifetime, token) = Lifetime.make() + /// } + /// ``` + public final class Token { + fileprivate let disposables: CompositeDisposable + + public init() { + disposables = CompositeDisposable() + } + + public func dispose() { + disposables.dispose() + } + + deinit { + dispose() + } + } +} diff --git a/Pods/ReactiveSwift/Sources/Observer.swift b/Pods/ReactiveSwift/Sources/Observer.swift new file mode 100644 index 0000000..f5945aa --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Observer.swift @@ -0,0 +1,133 @@ +// +// Observer.swift +// ReactiveSwift +// +// Created by Andy Matuschak on 10/2/15. +// Copyright © 2015 GitHub. All rights reserved. +// + +extension Signal { + /// An Observer is a simple wrapper around a function which can receive Events + /// (typically from a Signal). + public final class Observer { + public typealias Action = (Event) -> Void + private let _send: Action + + /// Whether the observer should send an `interrupted` event as it deinitializes. + private let interruptsOnDeinit: Bool + + /// An initializer that accepts a closure accepting an event for the + /// observer. + /// + /// - parameters: + /// - action: A closure to lift over received event. + /// - interruptsOnDeinit: `true` if the observer should send an `interrupted` + /// event as it deinitializes. `false` otherwise. + internal init(action: @escaping Action, interruptsOnDeinit: Bool) { + self._send = action + self.interruptsOnDeinit = interruptsOnDeinit + } + + /// An initializer that accepts a closure accepting an event for the + /// observer. + /// + /// - parameters: + /// - action: A closure to lift over received event. + public init(_ action: @escaping Action) { + self._send = action + self.interruptsOnDeinit = false + } + + /// An initializer that accepts closures for different event types. + /// + /// - parameters: + /// - value: Optional closure executed when a `value` event is observed. + /// - failed: Optional closure that accepts an `Error` parameter when a + /// failed event is observed. + /// - completed: Optional closure executed when a `completed` event is + /// observed. + /// - interruped: Optional closure executed when an `interrupted` event is + /// observed. + public convenience init( + value: ((Value) -> Void)? = nil, + failed: ((Error) -> Void)? = nil, + completed: (() -> Void)? = nil, + interrupted: (() -> Void)? = nil + ) { + self.init { event in + switch event { + case let .value(v): + value?(v) + + case let .failed(error): + failed?(error) + + case .completed: + completed?() + + case .interrupted: + interrupted?() + } + } + } + + internal convenience init(mappingInterruptedToCompleted observer: Signal.Observer) { + self.init { event in + switch event { + case .value, .completed, .failed: + observer.send(event) + case .interrupted: + observer.sendCompleted() + } + } + } + + deinit { + if interruptsOnDeinit { + // Since `Signal` would ensure that only one terminal event would ever be + // sent for any given `Signal`, we do not need to assert any condition + // here. + _send(.interrupted) + } + } + + /// Puts an event into `self`. + public func send(_ event: Event) { + _send(event) + } + + /// Puts a `value` event into `self`. + /// + /// - parameters: + /// - value: A value sent with the `value` event. + public func send(value: Value) { + _send(.value(value)) + } + + /// Puts a failed event into `self`. + /// + /// - parameters: + /// - error: An error object sent with failed event. + public func send(error: Error) { + _send(.failed(error)) + } + + /// Puts a `completed` event into `self`. + public func sendCompleted() { + _send(.completed) + } + + /// Puts an `interrupted` event into `self`. + public func sendInterrupted() { + _send(.interrupted) + } + } +} + +/// FIXME: Cannot be placed in `Deprecations+Removal.swift` if compiling with +/// Xcode 9.2. +extension Signal.Observer { + /// An action that will be performed upon arrival of the event. + @available(*, unavailable, renamed:"send(_:)") + public var action: Action { fatalError() } +} diff --git a/Pods/ReactiveSwift/Sources/Optional.swift b/Pods/ReactiveSwift/Sources/Optional.swift new file mode 100644 index 0000000..1e8584c --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Optional.swift @@ -0,0 +1,42 @@ +// +// Optional.swift +// ReactiveSwift +// +// Created by Neil Pankey on 6/24/15. +// Copyright (c) 2015 GitHub. All rights reserved. +// + +/// An optional protocol for use in type constraints. +public protocol OptionalProtocol { + /// The type contained in the otpional. + associatedtype Wrapped + + init(reconstructing value: Wrapped?) + + /// Extracts an optional from the receiver. + var optional: Wrapped? { get } +} + +extension Optional: OptionalProtocol { + public var optional: Wrapped? { + return self + } + + public init(reconstructing value: Wrapped?) { + self = value + } +} + +extension Signal { + /// Turns each value into an Optional. + internal func optionalize() -> Signal { + return map(Optional.init) + } +} + +extension SignalProducer { + /// Turns each value into an Optional. + internal func optionalize() -> SignalProducer { + return lift { $0.optionalize() } + } +} diff --git a/Pods/ReactiveSwift/Sources/Property.swift b/Pods/ReactiveSwift/Sources/Property.swift new file mode 100644 index 0000000..a5c62fe --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Property.swift @@ -0,0 +1,808 @@ +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +import Darwin.POSIX.pthread +#else +import Glibc +#endif + +// FIXME: The `Error == Never` constraint is retained for Swift 4.0.x +// compatibility, since `BindingSource` did not impose such constraint +// due to the absence of conditional conformance. + +/// Represents a property that allows observation of its changes. +/// +/// Only classes can conform to this protocol, because having a signal +/// for changes over time implies the origin must have a unique identity. +public protocol PropertyProtocol: class, BindingSource { + /// The current value of the property. + var value: Value { get } + + /// The values producer of the property. + /// + /// It produces a signal that sends the property's current value, + /// followed by all changes over time. It completes when the property + /// has deinitialized, or has no further change. + /// + /// - note: If `self` is a composed property, the producer would be + /// bound to the lifetime of its sources. + var producer: SignalProducer { get } + + /// A signal that will send the property's changes over time. It + /// completes when the property has deinitialized, or has no further + /// change. + /// + /// - note: If `self` is a composed property, the signal would be + /// bound to the lifetime of its sources. + var signal: Signal { get } +} + +/// Represents an observable property that can be mutated directly. +public protocol MutablePropertyProtocol: PropertyProtocol, BindingTargetProvider { + /// The current value of the property. + var value: Value { get set } + + /// The lifetime of the property. + var lifetime: Lifetime { get } +} + +/// Default implementation of `BindingTargetProvider` for mutable properties. +extension MutablePropertyProtocol { + public var bindingTarget: BindingTarget { + return BindingTarget(lifetime: lifetime) { [weak self] in self?.value = $0 } + } +} + +/// Represents a mutable property that can be safety composed by exposing its +/// synchronization mechanic through the defined closure-based interface. +public protocol ComposableMutablePropertyProtocol: MutablePropertyProtocol { + /// Atomically performs an arbitrary action using the current value of the + /// variable. + /// + /// - parameters: + /// - action: A closure that accepts current property value. + /// + /// - returns: the result of the action. + func withValue(_ action: (Value) throws -> Result) rethrows -> Result + + /// Atomically modifies the variable. + /// + /// - parameters: + /// - action: A closure that accepts old property value and returns a new + /// property value. + /// + /// - returns: The result of the action. + func modify(_ action: (inout Value) throws -> Result) rethrows -> Result +} + +// Property operators. +// +// A composed property is a transformed view of its sources, and does not +// own its lifetime. Its producer and signal are bound to the lifetime of +// its sources. + +extension PropertyProtocol { + /// Lifts a unary SignalProducer operator to operate upon PropertyProtocol instead. + fileprivate func lift(_ transform: @escaping (SignalProducer) -> SignalProducer) -> Property { + return Property(unsafeProducer: transform(producer)) + } + + /// Lifts a binary SignalProducer operator to operate upon PropertyProtocol instead. + fileprivate func lift(_ transform: @escaping (SignalProducer) -> (SignalProducer) -> SignalProducer) -> (P) -> Property { + return { other in + return Property(unsafeProducer: transform(self.producer)(other.producer)) + } + } +} + +extension PropertyProtocol { + /// Maps the current value and all subsequent values to a new property. + /// + /// - parameters: + /// - transform: A closure that will map the current `value` of this + /// `Property` to a new value. + /// + /// - returns: A property that holds a mapped value from `self`. + public func map(_ transform: @escaping (Value) -> U) -> Property { + return lift { $0.map(transform) } + } + + /// Map the current value and all susequent values to a new constant property. + /// + /// - parameters: + /// - value: A new value. + /// + /// - returns: A property that holds a mapped value from `self`. + public func map(value: U) -> Property { + return lift { $0.map(value: value) } + } + + /// Maps the current value and all subsequent values to a new property + /// by applying a key path. + /// + /// - parameters: + /// - keyPath: A key path relative to the property's `Value` type. + /// + /// - returns: A property that holds a mapped value from `self`. + public func map(_ keyPath: KeyPath) -> Property { + return lift { $0.map(keyPath) } + } + + /// Passes only the values of the property that pass the given predicate + /// to a new property. + /// + /// - parameters: + /// - initial: A `Property` always needs a `value`. The initial `value` is necessary in case the + /// predicate excludes the first (or all) `value`s of this `Property` + /// - predicate: A closure that accepts value and returns `Bool` denoting + /// whether current `value` of this `Property` has passed the test. + /// + /// - returns: A property that holds only values from `self` passing the given predicate. + public func filter(initial: Value, _ predicate: @escaping (Value) -> Bool) -> Property { + return Property(initial: initial, then: self.producer.filter(predicate)) + } + + /// Combines the current value and the subsequent values of two `Property`s in + /// the manner described by `Signal.combineLatest(with:)`. + /// + /// - parameters: + /// - other: A property to combine `self`'s value with. + /// + /// - returns: A property that holds a tuple containing values of `self` and + /// the given property. + public func combineLatest(with other: P) -> Property<(Value, P.Value)> { + return Property.combineLatest(self, other) + } + + /// Zips the current value and the subsequent values of two `Property`s in + /// the manner described by `Signal.zipWith`. + /// + /// - parameters: + /// - other: A property to zip `self`'s value with. + /// + /// - returns: A property that holds a tuple containing values of `self` and + /// the given property. + public func zip(with other: P) -> Property<(Value, P.Value)> { + return Property.zip(self, other) + } + + /// Forward events from `self` with history: values of the returned property + /// are a tuple whose first member is the previous value and whose second + /// member is the current value. `initial` is supplied as the first member + /// when `self` sends its first value. + /// + /// - parameters: + /// - initial: A value that will be combined with the first value sent by + /// `self`. + /// + /// - returns: A property that holds tuples that contain previous and + /// current values of `self`. + public func combinePrevious(_ initial: Value) -> Property<(Value, Value)> { + return lift { $0.combinePrevious(initial) } + } + + /// Forward only values from `self` that are not considered equivalent to its + /// consecutive predecessor. + /// + /// - note: The first value is always forwarded. + /// + /// - parameters: + /// - isEquivalent: A closure to determine whether two values are equivalent. + /// + /// - returns: A property which conditionally forwards values from `self`. + public func skipRepeats(_ isEquivalent: @escaping (Value, Value) -> Bool) -> Property { + return lift { $0.skipRepeats(isEquivalent) } + } +} + +extension PropertyProtocol where Value: Equatable { + /// Forward only values from `self` that are not equal to its consecutive predecessor. + /// + /// - note: The first value is always forwarded. + /// + /// - returns: A property which conditionally forwards values from `self`. + public func skipRepeats() -> Property { + return lift { $0.skipRepeats() } + } +} + +extension PropertyProtocol where Value: PropertyProtocol { + /// Flattens the inner property held by `self` (into a single property of + /// values), according to the semantics of the given strategy. + /// + /// - parameters: + /// - strategy: The preferred flatten strategy. + /// + /// - returns: A property that sends the values of its inner properties. + public func flatten(_ strategy: FlattenStrategy) -> Property { + return lift { $0.flatMap(strategy) { $0.producer } } + } +} + +extension PropertyProtocol { + /// Maps each property from `self` to a new property, then flattens the + /// resulting properties (into a single property), according to the + /// semantics of the given strategy. + /// + /// - parameters: + /// - strategy: The preferred flatten strategy. + /// - transform: The transform to be applied on `self` before flattening. + /// + /// - returns: A property that sends the values of its inner properties. + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> P) -> Property { + return lift { $0.flatMap(strategy) { transform($0).producer } } + } + + /// Forward only those values from `self` that have unique identities across + /// the set of all values that have been held. + /// + /// - note: This causes the identities to be retained to check for + /// uniqueness. + /// + /// - parameters: + /// - transform: A closure that accepts a value and returns identity + /// value. + /// + /// - returns: A property that sends unique values during its lifetime. + public func uniqueValues(_ transform: @escaping (Value) -> Identity) -> Property { + return lift { $0.uniqueValues(transform) } + } +} + +extension PropertyProtocol where Value: Hashable { + /// Forwards only those values from `self` that are unique across the set of + /// all values that have been seen. + /// + /// - note: This causes the identities to be retained to check for uniqueness. + /// Providing a function that returns a unique value for each sent + /// value can help you reduce the memory footprint. + /// + /// - returns: A property that sends unique values during its lifetime. + public func uniqueValues() -> Property { + return lift { $0.uniqueValues() } + } +} + +extension PropertyProtocol { + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B) -> Property<(A.Value, B.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b) } + } + + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C) -> Property<(Value, B.Value, C.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b, c) } + } + + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D) -> Property<(Value, B.Value, C.Value, D.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b, c, d) } + } + + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Property<(Value, B.Value, C.Value, D.Value, E.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b, c, d, e) } + } + + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b, c, d, e, f) } + } + + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b, c, d, e, f, g) } + } + + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b, c, d, e, f, g, h) } + } + + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value, I.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b, c, d, e, f, g, h, i) } + } + + /// Combines the values of all the given properties, in the manner described + /// by `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I, _ j: J) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value, I.Value, J.Value)> where A.Value == Value { + return a.lift { SignalProducer.combineLatest($0, b, c, d, e, f, g, h, i, j) } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. Returns nil if the sequence is empty. + public static func combineLatest(_ properties: S) -> Property<[S.Iterator.Element.Value]>? where S.Iterator.Element: PropertyProtocol { + let producers = properties.map { $0.producer } + guard !producers.isEmpty else { + return nil + } + + return Property(unsafeProducer: SignalProducer.combineLatest(producers)) + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B) -> Property<(Value, B.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C) -> Property<(Value, B.Value, C.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b, c) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D) -> Property<(Value, B.Value, C.Value, D.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b, c, d) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Property<(Value, B.Value, C.Value, D.Value, E.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b, c, d, e) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b, c, d, e, f) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b, c, d, e, f, g) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b, c, d, e, f, g, h) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value, I.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b, c, d, e, f, g, h, i) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I, _ j: J) -> Property<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value, I.Value, J.Value)> where A.Value == Value { + return a.lift { SignalProducer.zip($0, b, c, d, e, f, g, h, i, j) } + } + + /// Zips the values of all the given properties, in the manner described by + /// `zip(with:)`. Returns nil if the sequence is empty. + public static func zip(_ properties: S) -> Property<[S.Iterator.Element.Value]>? where S.Iterator.Element: PropertyProtocol { + let producers = properties.map { $0.producer } + guard !producers.isEmpty else { + return nil + } + + return Property(unsafeProducer: SignalProducer.zip(producers)) + } +} + +extension PropertyProtocol where Value == Bool { + /// Create a property that computes a logical NOT in the latest values of `self`. + /// + /// - returns: A property that contains the logical NOT results. + public func negate() -> Property { + return self.lift { $0.negate() } + } + + /// Create a property that computes a logical AND between the latest values of `self` + /// and `property`. + /// + /// - parameters: + /// - property: Property to be combined with `self`. + /// + /// - returns: A property that contains the logical AND results. + public func and(_ property: P) -> Property where P.Value == Value { + return self.lift(SignalProducer.and)(property) + } + + /// Create a property that computes a logical AND between the latest values of `properties`. + /// + /// - parameters: + /// - property: Collection of properties to be combined. + /// + /// - returns: A property that contains the logical AND results. + public static func all(_ properties: Properties) -> Property where P.Value == Value, Properties.Element == P { + return Property(initial: properties.map { $0.value }.reduce(true) { $0 && $1 }, then: SignalProducer.all(properties)) + } + + /// Create a property that computes a logical OR between the latest values of `self` + /// and `property`. + /// + /// - parameters: + /// - property: Property to be combined with `self`. + /// + /// - returns: A property that contains the logical OR results. + public func or(_ property: P) -> Property where P.Value == Value { + return self.lift(SignalProducer.or)(property) + } + + /// Create a property that computes a logical OR between the latest values of `properties`. + /// + /// - parameters: + /// - properties: Collection of properties to be combined. + /// + /// - returns: A property that contains the logical OR results. + public static func any(_ properties: Properties) -> Property where P.Value == Value, Properties.Element == P { + return Property(initial: properties.map { $0.value }.reduce(false) { $0 || $1 }, then: SignalProducer.any(properties)) + } +} + +/// A read-only property that can be observed for its changes over time. There +/// are three categories of read-only properties: +/// +/// # Constant property +/// Created by `Property(value:)`, the producer and signal of a constant +/// property would complete immediately when it is initialized. +/// +/// # Existential property +/// Created by `Property(capturing:)`, it wraps any arbitrary `PropertyProtocol` +/// types, and passes through the behavior. Note that it would retain the +/// wrapped property. +/// +/// Existential property would be deprecated when generalized existential +/// eventually lands in Swift. +/// +/// # Composed property +/// A composed property presents a composed view of its sources, which can be +/// one or more properties, a producer, or a signal. It can be created using +/// property composition operators, `Property(_:)` or `Property(initial:then:)`. +/// +/// It does not own its lifetime, and its producer and signal are bound to the +/// lifetime of its sources. It also does not have an influence on its sources, +/// so retaining a composed property would not prevent its sources from +/// deinitializing. +/// +/// Note that composed properties do not retain any of its sources. +public final class Property: PropertyProtocol { + private let _value: () -> Value + + /// The current value of the property. + public var value: Value { + return _value() + } + + /// A producer for Signals that will send the property's current + /// value, followed by all changes over time, then complete when the + /// property has deinitialized or has no further changes. + /// + /// - note: If `self` is a composed property, the producer would be + /// bound to the lifetime of its sources. + public let producer: SignalProducer + + /// A signal that will send the property's changes over time, then + /// complete when the property has deinitialized or has no further changes. + /// + /// - note: If `self` is a composed property, the signal would be + /// bound to the lifetime of its sources. + public let signal: Signal + + /// Initializes a constant property. + /// + /// - parameters: + /// - property: A value of the constant property. + public init(value: Value) { + _value = { value } + producer = SignalProducer(value: value) + signal = Signal.empty + } + + /// Initializes an existential property which wraps the given property. + /// + /// - note: The resulting property retains the given property. + /// + /// - parameters: + /// - property: A property to be wrapped. + public init(capturing property: P) where P.Value == Value { + _value = { property.value } + producer = property.producer + signal = property.signal + } + + /// Initializes a composed property which reflects the given property. + /// + /// - note: The resulting property does not retain the given property. + /// + /// - parameters: + /// - property: A property to be wrapped. + public convenience init(_ property: P) where P.Value == Value { + self.init(unsafeProducer: property.producer) + } + + /// Initializes a composed property that first takes on `initial`, then each + /// value sent on a signal created by `producer`. + /// + /// - parameters: + /// - initial: Starting value for the property. + /// - values: A producer that will start immediately and send values to + /// the property. + public convenience init(initial: Value, then values: SignalProducer) { + self.init(unsafeProducer: SignalProducer { observer, lifetime in + observer.send(value: initial) + lifetime += values.start(Signal.Observer(mappingInterruptedToCompleted: observer)) + }) + } + + /// Initializes a composed property that first takes on `initial`, then each + /// value sent on a signal created by `producer`. + /// + /// - parameters: + /// - initial: Starting value for the property. + /// - values: A producer that will start immediately and send values to + /// the property. + public convenience init(initial: Value, then values: Values) where Values.Value == Value, Values.Error == Never { + self.init(initial: initial, then: values.producer) + } + + /// Initialize a composed property from a producer that promises to send + /// at least one value synchronously in its start handler before sending any + /// subsequent event. + /// + /// - important: The producer and the signal of the created property would + /// complete only when the `unsafeProducer` completes. + /// + /// - warning: If the producer fails its promise, a fatal error would be + /// raised. + /// + /// - warning: `unsafeProducer` should not emit any `interrupted` event unless it is + /// a result of being interrupted by the downstream. + /// + /// - parameters: + /// - unsafeProducer: The composed producer for creating the property. + fileprivate init(unsafeProducer: SignalProducer) { + // The ownership graph: + // + // ------------ weak ----------- strong ------------------ + // | Upstream | ~~~~~~~~> | Box | <======== | SignalProducer | <=== strong + // ------------ ----------- // ------------------ \\ + // \\ // \\ + // \\ ------------ weak ----------- <== ------------ + // ==> | Observer | ~~~~> | Relay | <=========================== | Property | + // strong ------------ ----------- strong ------------ + + let box = PropertyBox(nil) + + // A composed property tracks its active consumers through its relay signal, and + // interrupts `unsafeProducer` if the relay signal terminates. + let disposable = SerialDisposable() + let (relay, observer) = Signal.pipe(disposable: disposable) + + disposable.inner = unsafeProducer.start { [weak box] event in + // `observer` receives `interrupted` only as a result of the termination of + // `signal`, and would not be delivered anyway. So transforming + // `interrupted` to `completed` is unnecessary here. + + guard let box = box else { + // Just forward the event, since no one owns the box or IOW no demand + // for a cached latest value. + return observer.send(event) + } + + box.begin { storage in + storage.modify { value in + if let newValue = event.value { + value = newValue + } + } + observer.send(event) + } + } + + // Verify that an initial is sent. This is friendlier than deadlocking + // in the event that one isn't. + guard box.value != nil else { + fatalError("The producer promised to send at least one value. Received none.") + } + + _value = { box.value! } + signal = relay + + producer = SignalProducer { [box, relay] observer, lifetime in + box.withValue { value in + observer.send(value: value!) + lifetime += relay.observe(Signal.Observer(mappingInterruptedToCompleted: observer)) + } + } + } +} + +extension Property where Value: OptionalProtocol { + /// Initializes a composed property that first takes on `initial`, then each + /// value sent on a signal created by `producer`. + /// + /// - parameters: + /// - initial: Starting value for the property. + /// - values: A producer that will start immediately and send values to + /// the property. + public convenience init(initial: Value, then values: SignalProducer) { + self.init(initial: initial, then: values.map(Value.init(reconstructing:))) + } + + /// Initializes a composed property that first takes on `initial`, then each + /// value sent on a signal created by `producer`. + /// + /// - parameters: + /// - initial: Starting value for the property. + /// - values: A producer that will start immediately and send values to + /// the property. + public convenience init(initial: Value, then values: Values) where Values.Value == Value.Wrapped, Values.Error == Never { + self.init(initial: initial, then: values.producer) + } +} + +/// A mutable property of type `Value` that allows observation of its changes. +/// +/// Instances of this class are thread-safe. +public final class MutableProperty: ComposableMutablePropertyProtocol { + private let token: Lifetime.Token + private let observer: Signal.Observer + private let box: PropertyBox + + /// The current value of the property. + /// + /// Setting this to a new value will notify all observers of `signal`, or + /// signals created using `producer`. + public var value: Value { + get { return box.value } + set { modify { $0 = newValue } } + } + + /// The lifetime of the property. + public let lifetime: Lifetime + + /// A signal that will send the property's changes over time, + /// then complete when the property has deinitialized. + public let signal: Signal + + /// A producer for Signals that will send the property's current value, + /// followed by all changes over time, then complete when the property has + /// deinitialized. + public var producer: SignalProducer { + return SignalProducer { [box, signal] observer, lifetime in + box.withValue { value in + observer.send(value: value) + lifetime += signal.observe(Signal.Observer(mappingInterruptedToCompleted: observer)) + } + } + } + + /// Initializes a mutable property that first takes on `initialValue` + /// + /// - parameters: + /// - initialValue: Starting value for the mutable property. + public init(_ initialValue: Value) { + (signal, observer) = Signal.pipe() + (lifetime, token) = Lifetime.make() + + /// Need a recursive lock around `value` to allow recursive access to + /// `value`. Note that recursive sets will still deadlock because the + /// underlying producer prevents sending recursive events. + box = PropertyBox(initialValue) + } + + /// Atomically replaces the contents of the variable. + /// + /// - parameters: + /// - newValue: New property value. + /// + /// - returns: The previous property value. + @discardableResult + public func swap(_ newValue: Value) -> Value { + return modify { value in + defer { value = newValue } + return value + } + } + + /// Atomically modifies the variable. + /// + /// - parameters: + /// - action: A closure that accepts an inout reference to the value. + /// + /// - returns: The result of the action. + @discardableResult + public func modify(_ action: (inout Value) throws -> Result) rethrows -> Result { + return try box.begin { storage in + defer { observer.send(value: storage.value) } + return try storage.modify(action) + } + } + + /// Atomically modifies the variable. + /// + /// - warning: The reference should not be escaped. + /// + /// - parameters: + /// - action: A closure that accepts a reference to the property storage. + /// + /// - returns: The result of the action. + @discardableResult + internal func begin(_ action: (PropertyStorage) throws -> Result) rethrows -> Result { + return try box.begin(action) + } + + /// Atomically performs an arbitrary action using the current value of the + /// variable. + /// + /// - parameters: + /// - action: A closure that accepts current property value. + /// + /// - returns: the result of the action. + @discardableResult + public func withValue(_ action: (Value) throws -> Result) rethrows -> Result { + return try box.withValue { try action($0) } + } + + deinit { + observer.sendCompleted() + } +} + +internal struct PropertyStorage { + private unowned let box: PropertyBox + + var value: Value { + return box._value + } + + func modify(_ action: (inout Value) throws -> Result) rethrows -> Result { + guard !box.isModifying else { fatalError("Nested modifications violate exclusivity of access.") } + box.isModifying = true + defer { box.isModifying = false } + return try action(&box._value) + } + + fileprivate init(_ box: PropertyBox) { + self.box = box + } +} + +/// A reference counted box which holds a recursive lock and a value storage. +/// +/// The requirement of a `Value?` storage from composed properties prevents further +/// implementation sharing with `MutableProperty`. +private final class PropertyBox { + + private let lock: Lock.PthreadLock + fileprivate var _value: Value + fileprivate var isModifying = false + + internal var value: Value { + lock.lock() + defer { lock.unlock() } + return _value + } + + init(_ value: Value) { + _value = value + lock = Lock.PthreadLock(recursive: true) + } + + func withValue(_ action: (Value) throws -> Result) rethrows -> Result { + lock.lock() + defer { lock.unlock() } + return try action(_value) + } + + func begin(_ action: (PropertyStorage) throws -> Result) rethrows -> Result { + lock.lock() + defer { lock.unlock() } + return try action(PropertyStorage(self)) + } +} diff --git a/Pods/ReactiveSwift/Sources/Reactive.swift b/Pods/ReactiveSwift/Sources/Reactive.swift new file mode 100644 index 0000000..064d336 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Reactive.swift @@ -0,0 +1,33 @@ +/// Describes a provider of reactive extensions. +/// +/// - note: `ReactiveExtensionsProvider` does not indicate whether a type is +/// reactive. It is intended for extensions to types that are not owned +/// by the module in order to avoid name collisions and return type +/// ambiguities. +public protocol ReactiveExtensionsProvider {} + +extension ReactiveExtensionsProvider { + /// A proxy which hosts reactive extensions for `self`. + public var reactive: Reactive { + return Reactive(self) + } + + /// A proxy which hosts static reactive extensions for the type of `self`. + public static var reactive: Reactive.Type { + return Reactive.self + } +} + +/// A proxy which hosts reactive extensions of `Base`. +public struct Reactive { + /// The `Base` instance the extensions would be invoked with. + public let base: Base + + /// Construct a proxy + /// + /// - parameters: + /// - base: The object to be proxied. + fileprivate init(_ base: Base) { + self.base = base + } +} diff --git a/Pods/ReactiveSwift/Sources/ResultExtensions.swift b/Pods/ReactiveSwift/Sources/ResultExtensions.swift new file mode 100644 index 0000000..b8b5525 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/ResultExtensions.swift @@ -0,0 +1,44 @@ +extension Result: SignalProducerConvertible { + public var producer: SignalProducer { + return .init(result: self) + } + + internal var value: Success? { + switch self { + case let .success(value): return value + case .failure: return nil + } + } + + internal var error: Failure? { + switch self { + case .success: return nil + case let .failure(error): return error + } + } +} + +/// A protocol that can be used to constrain associated types as `Result`. +internal protocol ResultProtocol { + associatedtype Success + associatedtype Failure: Swift.Error + + init(success: Success) + init(failure: Failure) + + var result: Result { get } +} + +extension Result: ResultProtocol { + internal init(success: Success) { + self = .success(success) + } + + internal init(failure: Failure) { + self = .failure(failure) + } + + internal var result: Result { + return self + } +} diff --git a/Pods/ReactiveSwift/Sources/Scheduler.swift b/Pods/ReactiveSwift/Sources/Scheduler.swift new file mode 100644 index 0000000..dab02a9 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Scheduler.swift @@ -0,0 +1,613 @@ +// +// Scheduler.swift +// ReactiveSwift +// +// Created by Justin Spahr-Summers on 2014-06-02. +// Copyright (c) 2014 GitHub. All rights reserved. +// + +import Dispatch +import Foundation + +#if os(Linux) + import let CDispatch.NSEC_PER_SEC +#endif + +/// Represents a serial queue of work items. +public protocol Scheduler: class { + /// Enqueues an action on the scheduler. + /// + /// When the work is executed depends on the scheduler in use. + /// + /// - parameters: + /// - action: The action to be scheduled. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + @discardableResult + func schedule(_ action: @escaping () -> Void) -> Disposable? +} + +/// A particular kind of scheduler that supports enqueuing actions at future +/// dates. +public protocol DateScheduler: Scheduler { + /// The current date, as determined by this scheduler. + /// + /// This can be implemented to deterministically return a known date (e.g., + /// for testing purposes). + var currentDate: Date { get } + + /// Schedules an action for execution at or after the given date. + /// + /// - parameters: + /// - date: The start date. + /// - action: A closure of the action to be performed. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + @discardableResult + func schedule(after date: Date, action: @escaping () -> Void) -> Disposable? + + /// Schedules a recurring action at the given interval, beginning at the + /// given date. + /// + /// - parameters: + /// - date: The start date. + /// - interval: A repetition interval. + /// - leeway: Some delta for repetition. + /// - action: A closure of the action to be performed. + /// + /// - note: If you plan to specify an `interval` value greater than 200,000 + /// seconds, use `schedule(after:interval:leeway:action)` instead + /// and specify your own `leeway` value to avoid potential overflow. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + @discardableResult + func schedule(after date: Date, interval: DispatchTimeInterval, leeway: DispatchTimeInterval, action: @escaping () -> Void) -> Disposable? +} + +/// A scheduler that performs all work synchronously. +public final class ImmediateScheduler: Scheduler { + public init() {} + + /// Immediately calls passed in `action`. + /// + /// - parameters: + /// - action: A closure of the action to be performed. + /// + /// - returns: `nil`. + @discardableResult + public func schedule(_ action: @escaping () -> Void) -> Disposable? { + action() + return nil + } +} + +/// A scheduler that performs all work on the main queue, as soon as possible. +/// +/// If the caller is already running on the main queue when an action is +/// scheduled, it may be run synchronously. However, ordering between actions +/// will always be preserved. +public final class UIScheduler: Scheduler { + private static let dispatchSpecificKey = DispatchSpecificKey() + private static let dispatchSpecificValue = UInt8.max + private static var __once: () = { + DispatchQueue.main.setSpecific(key: UIScheduler.dispatchSpecificKey, + value: dispatchSpecificValue) + }() + + #if os(Linux) + private var queueLength: Atomic = Atomic(0) + #else + // `inout` references do not guarantee atomicity. Use `UnsafeMutablePointer` + // instead. + // + // https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20161205/004147.html + private let queueLength: UnsafeMutablePointer = { + let memory = UnsafeMutablePointer.allocate(capacity: 1) + memory.initialize(to: 0) + return memory + }() + + deinit { + queueLength.deinitialize(count: 1) + queueLength.deallocate() + } + #endif + + /// Initializes `UIScheduler` + public init() { + /// This call is to ensure the main queue has been setup appropriately + /// for `UIScheduler`. It is only called once during the application + /// lifetime, since Swift has a `dispatch_once` like mechanism to + /// lazily initialize global variables and static variables. + _ = UIScheduler.__once + } + + /// Queues an action to be performed on main queue. If the action is called + /// on the main thread and no work is queued, no scheduling takes place and + /// the action is called instantly. + /// + /// - parameters: + /// - action: A closure of the action to be performed on the main thread. + /// + /// - returns: `Disposable` that can be used to cancel the work before it + /// begins. + @discardableResult + public func schedule(_ action: @escaping () -> Void) -> Disposable? { + let positionInQueue = enqueue() + + // If we're already running on the main queue, and there isn't work + // already enqueued, we can skip scheduling and just execute directly. + if positionInQueue == 1 && DispatchQueue.getSpecific(key: UIScheduler.dispatchSpecificKey) == UIScheduler.dispatchSpecificValue { + action() + dequeue() + return nil + } else { + let disposable = AnyDisposable() + + DispatchQueue.main.async { + defer { self.dequeue() } + guard !disposable.isDisposed else { return } + action() + } + + return disposable + } + } + + private func dequeue() { + #if os(Linux) + queueLength.modify { $0 -= 1 } + #else + OSAtomicDecrement32(queueLength) + #endif + } + + private func enqueue() -> Int32 { + #if os(Linux) + return queueLength.modify { value -> Int32 in + value += 1 + return value + } + #else + return OSAtomicIncrement32(queueLength) + #endif + } +} + +/// A `Hashable` wrapper for `DispatchSourceTimer`. `Hashable` conformance is +/// based on the identity of the wrapper object rather than the wrapped +/// `DispatchSourceTimer`, so two wrappers wrapping the same timer will *not* +/// be equal. +private final class DispatchSourceTimerWrapper: Hashable { + private let value: DispatchSourceTimer + + #if swift(>=4.1.50) + fileprivate func hash(into hasher: inout Hasher) { + hasher.combine(ObjectIdentifier(self)) + } + #else + fileprivate var hashValue: Int { + return ObjectIdentifier(self).hashValue + } + #endif + + fileprivate init(_ value: DispatchSourceTimer) { + self.value = value + } + + fileprivate static func ==(lhs: DispatchSourceTimerWrapper, rhs: DispatchSourceTimerWrapper) -> Bool { + // Note that this isn't infinite recursion thanks to `===`. + return lhs === rhs + } +} + +/// A scheduler backed by a serial GCD queue. +public final class QueueScheduler: DateScheduler { + /// A singleton `QueueScheduler` that always targets the main thread's GCD + /// queue. + /// + /// - note: Unlike `UIScheduler`, this scheduler supports scheduling for a + /// future date, and will always schedule asynchronously (even if + /// already running on the main thread). + public static let main = QueueScheduler(internalQueue: DispatchQueue.main) + + public var currentDate: Date { + return Date() + } + + public let queue: DispatchQueue + + private var timers: Atomic> + + internal init(internalQueue: DispatchQueue) { + queue = internalQueue + timers = Atomic(Set()) + } + + /// Initializes a scheduler that will target the given queue with its + /// work. + /// + /// - note: Even if the queue is concurrent, all work items enqueued with + /// the `QueueScheduler` will be serial with respect to each other. + /// + /// - warning: Obsoleted in OS X 10.11 + @available(OSX, deprecated:10.10, obsoleted:10.11, message:"Use init(qos:name:targeting:) instead") + @available(iOS, deprecated:8.0, obsoleted:9.0, message:"Use init(qos:name:targeting:) instead.") + public convenience init(queue: DispatchQueue, name: String = "org.reactivecocoa.ReactiveSwift.QueueScheduler") { + self.init(internalQueue: DispatchQueue(label: name, target: queue)) + } + + /// Initializes a scheduler that creates a new serial queue with the + /// given quality of service class. + /// + /// - parameters: + /// - qos: Dispatch queue's QoS value. + /// - name: A name for the queue in the form of reverse domain. + /// - targeting: (Optional) The queue on which this scheduler's work is + /// targeted + @available(OSX 10.10, *) + public convenience init( + qos: DispatchQoS = .default, + name: String = "org.reactivecocoa.ReactiveSwift.QueueScheduler", + targeting targetQueue: DispatchQueue? = nil + ) { + self.init(internalQueue: DispatchQueue( + label: name, + qos: qos, + target: targetQueue + )) + } + + /// Schedules action for dispatch on internal queue + /// + /// - parameters: + /// - action: A closure of the action to be scheduled. + /// + /// - returns: `Disposable` that can be used to cancel the work before it + /// begins. + @discardableResult + public func schedule(_ action: @escaping () -> Void) -> Disposable? { + let d = AnyDisposable() + + queue.async { + if !d.isDisposed { + action() + } + } + + return d + } + + private func wallTime(with date: Date) -> DispatchWallTime { + let (seconds, frac) = modf(date.timeIntervalSince1970) + + let nsec: Double = frac * Double(NSEC_PER_SEC) + let walltime = timespec(tv_sec: Int(seconds), tv_nsec: Int(nsec)) + + return DispatchWallTime(timespec: walltime) + } + + /// Schedules an action for execution at or after the given date. + /// + /// - parameters: + /// - date: The start date. + /// - action: A closure of the action to be performed. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + @discardableResult + public func schedule(after date: Date, action: @escaping () -> Void) -> Disposable? { + let d = AnyDisposable() + + queue.asyncAfter(wallDeadline: wallTime(with: date)) { + if !d.isDisposed { + action() + } + } + + return d + } + + /// Schedules a recurring action at the given interval and beginning at the + /// given start date. A reasonable default timer interval leeway is + /// provided. + /// + /// - parameters: + /// - date: A date to schedule the first action for. + /// - interval: A repetition interval. + /// - action: Closure of the action to repeat. + /// + /// - note: If you plan to specify an `interval` value greater than 200,000 + /// seconds, use `schedule(after:interval:leeway:action)` instead + /// and specify your own `leeway` value to avoid potential overflow. + /// + /// - returns: Optional disposable that can be used to cancel the work + /// before it begins. + @discardableResult + public func schedule(after date: Date, interval: DispatchTimeInterval, action: @escaping () -> Void) -> Disposable? { + // Apple's "Power Efficiency Guide for Mac Apps" recommends a leeway of + // at least 10% of the timer interval. + return schedule(after: date, interval: interval, leeway: interval * 0.1, action: action) + } + + /// Schedules a recurring action at the given interval with provided leeway, + /// beginning at the given start time. + /// + /// - precondition: `interval` must be non-negative number. + /// - precondition: `leeway` must be non-negative number. + /// + /// - parameters: + /// - date: A date to schedule the first action for. + /// - interval: A repetition interval. + /// - leeway: Some delta for repetition interval. + /// - action: A closure of the action to repeat. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + @discardableResult + public func schedule(after date: Date, interval: DispatchTimeInterval, leeway: DispatchTimeInterval, action: @escaping () -> Void) -> Disposable? { + precondition(interval.timeInterval >= 0) + precondition(leeway.timeInterval >= 0) + + let timer = DispatchSource.makeTimerSource( + flags: DispatchSource.TimerFlags(rawValue: UInt(0)), + queue: queue + ) + + #if swift(>=4.0) + timer.schedule(wallDeadline: wallTime(with: date), + repeating: interval, + leeway: leeway) + #else + timer.scheduleRepeating(wallDeadline: wallTime(with: date), + interval: interval, + leeway: leeway) + #endif + + timer.setEventHandler(handler: action) + timer.resume() + + let wrappedTimer = DispatchSourceTimerWrapper(timer) + + timers.modify { timers in + timers.insert(wrappedTimer) + } + + return AnyDisposable { [weak self] in + timer.cancel() + + if let scheduler = self { + scheduler.timers.modify { timers in + timers.remove(wrappedTimer) + } + } + } + } +} + +/// A scheduler that implements virtualized time, for use in testing. +public final class TestScheduler: DateScheduler { + private final class ScheduledAction { + let date: Date + let action: () -> Void + + init(date: Date, action: @escaping () -> Void) { + self.date = date + self.action = action + } + + func less(_ rhs: ScheduledAction) -> Bool { + return date < rhs.date + } + } + + private let lock = NSRecursiveLock() + private var _currentDate: Date + + /// The virtual date that the scheduler is currently at. + public var currentDate: Date { + let d: Date + + lock.lock() + d = _currentDate + lock.unlock() + + return d + } + + private var scheduledActions: [ScheduledAction] = [] + + /// Initializes a TestScheduler with the given start date. + /// + /// - parameters: + /// - startDate: The start date of the scheduler. + public init(startDate: Date = Date(timeIntervalSinceReferenceDate: 0)) { + lock.name = "org.reactivecocoa.ReactiveSwift.TestScheduler" + _currentDate = startDate + } + + private func schedule(_ action: ScheduledAction) -> Disposable { + lock.lock() + scheduledActions.append(action) + scheduledActions.sort { $0.less($1) } + lock.unlock() + + return AnyDisposable { + self.lock.lock() + self.scheduledActions = self.scheduledActions.filter { $0 !== action } + self.lock.unlock() + } + } + + /// Enqueues an action on the scheduler. + /// + /// - note: The work is executed on `currentDate` as it is understood by the + /// scheduler. + /// + /// - parameters: + /// - action: An action that will be performed on scheduler's + /// `currentDate`. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + @discardableResult + public func schedule(_ action: @escaping () -> Void) -> Disposable? { + return schedule(ScheduledAction(date: currentDate, action: action)) + } + + /// Schedules an action for execution after some delay. + /// + /// - parameters: + /// - delay: A delay for execution. + /// - action: A closure of the action to perform. + /// + /// - returns: Optional disposable that can be used to cancel the work + /// before it begins. + @discardableResult + public func schedule(after delay: DispatchTimeInterval, action: @escaping () -> Void) -> Disposable? { + return schedule(after: currentDate.addingTimeInterval(delay), action: action) + } + + /// Schedules an action for execution at or after the given date. + /// + /// - parameters: + /// - date: A starting date. + /// - action: A closure of the action to perform. + /// + /// - returns: Optional disposable that can be used to cancel the work + /// before it begins. + @discardableResult + public func schedule(after date: Date, action: @escaping () -> Void) -> Disposable? { + return schedule(ScheduledAction(date: date, action: action)) + } + + /// Schedules a recurring action at the given interval, beginning at the + /// given start date. + /// + /// - precondition: `interval` must be non-negative. + /// + /// - parameters: + /// - date: A date to schedule the first action for. + /// - interval: A repetition interval. + /// - disposable: A disposable. + /// - action: A closure of the action to repeat. + /// + /// - note: If you plan to specify an `interval` value greater than 200,000 + /// seconds, use `schedule(after:interval:leeway:action)` instead + /// and specify your own `leeway` value to avoid potential overflow. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + private func schedule(after date: Date, interval: DispatchTimeInterval, disposable: SerialDisposable, action: @escaping () -> Void) { + precondition(interval.timeInterval >= 0) + + disposable.inner = schedule(after: date) { [unowned self] in + action() + self.schedule(after: date.addingTimeInterval(interval), interval: interval, disposable: disposable, action: action) + } + } + + /// Schedules a recurring action after given delay repeated at the given, + /// interval, beginning at the given interval counted from `currentDate`. + /// + /// - parameters: + /// - delay: A delay for action's dispatch. + /// - interval: A repetition interval. + /// - leeway: Some delta for repetition interval. + /// - action: A closure of the action to repeat. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + @discardableResult + public func schedule(after delay: DispatchTimeInterval, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .seconds(0), action: @escaping () -> Void) -> Disposable? { + return schedule(after: currentDate.addingTimeInterval(delay), interval: interval, leeway: leeway, action: action) + } + + /// Schedules a recurring action at the given interval with + /// provided leeway, beginning at the given start date. + /// + /// - parameters: + /// - date: A date to schedule the first action for. + /// - interval: A repetition interval. + /// - leeway: Some delta for repetition interval. + /// - action: A closure of the action to repeat. + /// + /// - returns: Optional `Disposable` that can be used to cancel the work + /// before it begins. + public func schedule(after date: Date, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .seconds(0), action: @escaping () -> Void) -> Disposable? { + let disposable = SerialDisposable() + schedule(after: date, interval: interval, disposable: disposable, action: action) + return disposable + } + + /// Advances the virtualized clock by an extremely tiny interval, dequeuing + /// and executing any actions along the way. + /// + /// This is intended to be used as a way to execute actions that have been + /// scheduled to run as soon as possible. + public func advance() { + advance(by: .nanoseconds(1)) + } + + /// Advances the virtualized clock by the given interval, dequeuing and + /// executing any actions along the way. + /// + /// - parameters: + /// - interval: Interval by which the current date will be advanced. + public func advance(by interval: DispatchTimeInterval) { + lock.lock() + advance(to: currentDate.addingTimeInterval(interval)) + lock.unlock() + } + + /// Advances the virtualized clock to the given future date, dequeuing and + /// executing any actions up until that point. + /// + /// - parameters: + /// - newDate: Future date to which the virtual clock will be advanced. + public func advance(to newDate: Date) { + lock.lock() + + assert(currentDate <= newDate) + + while scheduledActions.count > 0 { + if newDate < scheduledActions[0].date { + break + } + + _currentDate = scheduledActions[0].date + + let scheduledAction = scheduledActions.remove(at: 0) + scheduledAction.action() + } + + _currentDate = newDate + + lock.unlock() + } + + /// Dequeues and executes all scheduled actions, leaving the scheduler's + /// date at `Date.distantFuture()`. + public func run() { + advance(to: Date.distantFuture) + } + + /// Rewinds the virtualized clock by the given interval. + /// This simulates that user changes device date. + /// + /// - parameters: + /// - interval: An interval by which the current date will be retreated. + public func rewind(by interval: DispatchTimeInterval) { + lock.lock() + + let newDate = currentDate.addingTimeInterval(-interval) + assert(currentDate >= newDate) + _currentDate = newDate + + lock.unlock() + + } +} diff --git a/Pods/ReactiveSwift/Sources/Signal.swift b/Pods/ReactiveSwift/Sources/Signal.swift new file mode 100644 index 0000000..54451d2 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/Signal.swift @@ -0,0 +1,2279 @@ +import Foundation +import Dispatch + +/// A push-driven stream that sends Events over time, parameterized by the type +/// of values being sent (`Value`) and the type of failure that can occur +/// (`Error`). If no failures should be possible, Never can be specified for +/// `Error`. +/// +/// An observer of a Signal will see the exact same sequence of events as all +/// other observers. In other words, events will be sent to all observers at the +/// same time. +/// +/// Signals are generally used to represent event streams that are already “in +/// progress,” like notifications, user input, etc. To represent streams that +/// must first be _started_, see the SignalProducer type. +/// +/// A Signal is kept alive until either of the following happens: +/// 1. its input observer receives a terminating event; or +/// 2. it has no active observers, and is not being retained. +public final class Signal { + /// The `Signal` core which manages the event stream. + /// + /// A `Signal` is the externally retained shell of the `Signal` core. The separation + /// enables an explicit metric for the `Signal` self-disposal in case of having no + /// observer and no external retain. + /// + /// `Signal` ownership graph from the perspective of an operator. + /// Note that there is no circular strong reference in the graph. + /// ``` + /// ------------ -------------- -------- + /// | | | endObserve | | | + /// | | <~~ weak ~~~ | disposable | <== strong === | | + /// | | -------------- | | ... downstream(s) + /// | Upstream | ------------ | | + /// | Core | === strong ==> | Observer | === strong ==> | Core | + /// ------------ ===\\ ------------ -------- ===\\ + /// \\ ------------------ ^^ \\ + /// \\ | Signal (shell) | === strong ==// \\ + /// \\ ------------------ \\ + /// || strong || strong + /// vv vv + /// ------------------- ------------------- + /// | Other observers | | Other observers | + /// ------------------- ------------------- + /// ``` + private let core: Core + + private final class Core { + /// The disposable associated with the signal. + /// + /// Disposing of `disposable` is assumed to remove the generator + /// observer from its attached `Signal`, so that the generator observer + /// as the last +1 retain of the `Signal` core may deinitialize. + private let disposable: CompositeDisposable + + /// The state of the signal. + private var state: State + + /// Used to ensure that all state accesses are serialized. + private let stateLock: Lock + + /// Used to ensure that events are serialized during delivery to observers. + private let sendLock: Lock + + fileprivate init(_ generator: (Observer, Lifetime) -> Void) { + state = .alive(Bag(), hasDeinitialized: false) + + stateLock = Lock.make() + sendLock = Lock.make() + disposable = CompositeDisposable() + + // The generator observer retains the `Signal` core. + generator(Observer(action: self.send, interruptsOnDeinit: true), Lifetime(disposable)) + } + + private func send(_ event: Event) { + if event.isTerminating { + // Recursive events are disallowed for `value` events, but are permitted + // for termination events. Specifically: + // + // - `interrupted` + // It can inadvertently be sent by downstream consumers as part of the + // `SignalProducer` mechanics. + // + // - `completed` + // If a downstream consumer weakly references an object, invocation of + // such consumer may cause a race condition with its weak retain against + // the last strong release of the object. If the `Lifetime` of the + // object is being referenced by an upstream `take(during:)`, a + // signal recursion might occur. + // + // So we would treat termination events specially. If it happens to + // occur while the `sendLock` is acquired, the observer call-out and + // the disposal would be delegated to the current sender, or + // occasionally one of the senders waiting on `sendLock`. + + self.stateLock.lock() + + if case let .alive(observers, _) = state { + self.state = .terminating(observers, .init(event)) + self.stateLock.unlock() + } else { + self.stateLock.unlock() + } + + tryToCommitTermination() + } else { + self.sendLock.lock() + self.stateLock.lock() + + if case let .alive(observers, _) = self.state { + self.stateLock.unlock() + + for observer in observers { + observer.send(event) + } + } else { + self.stateLock.unlock() + } + + self.sendLock.unlock() + + // Check if the status has been bumped to `terminating` due to a + // terminal event being sent concurrently or recursively. + // + // The check is deliberately made outside of the `sendLock` so that it + // covers also any potential concurrent terminal event in one shot. + // + // Related PR: + // https://github.com/ReactiveCocoa/ReactiveSwift/pull/112 + // + // While calling `tryToCommitTermination` is sufficient, this is a fast + // path for the recurring value delivery. + // + // Note that this cannot be `try` since any concurrent observer bag + // manipulation might then cause the terminating state being missed. + stateLock.lock() + if case .terminating = state { + stateLock.unlock() + tryToCommitTermination() + } else { + stateLock.unlock() + } + } + } + + /// Observe the Signal by sending any future events to the given observer. + /// + /// - parameters: + /// - observer: An observer to forward the events to. + /// + /// - returns: A `Disposable` which can be used to disconnect the observer, + /// or `nil` if the signal has already terminated. + fileprivate func observe(_ observer: Observer) -> Disposable? { + var token: Bag.Token? + + stateLock.lock() + + if case let .alive(observers, hasDeinitialized) = state { + var newObservers = observers + token = newObservers.insert(observer) + self.state = .alive(newObservers, hasDeinitialized: hasDeinitialized) + } + + stateLock.unlock() + + if let token = token { + return AnyDisposable { [weak self] in + self?.removeObserver(with: token) + } + } else { + observer.sendInterrupted() + return nil + } + } + + /// Remove the observer associated with the given token. + /// + /// - parameters: + /// - token: The token of the observer to remove. + private func removeObserver(with token: Bag.Token) { + stateLock.lock() + + if case let .alive(observers, hasDeinitialized) = state { + var newObservers = observers + let observer = newObservers.remove(using: token) + self.state = .alive(newObservers, hasDeinitialized: hasDeinitialized) + + // Ensure `observer` is deallocated after `stateLock` is + // released to avoid deadlocks. + withExtendedLifetime(observer) { + // Start the disposal of the `Signal` core if the `Signal` has + // deinitialized and there is no active observer. + tryToDisposeSilentlyIfQualified(unlocking: stateLock) + } + } else { + stateLock.unlock() + } + } + + /// Try to commit the termination, or in other words transition the signal from a + /// terminating state to a terminated state. + /// + /// It fails gracefully if the signal is alive or has terminated. Calling this + /// method as a result of a false positive `terminating` check is permitted. + /// + /// - precondition: `stateLock` must not be acquired by the caller. + private func tryToCommitTermination() { + // Acquire `stateLock`. If the termination has still not yet been + // handled, take it over and bump the status to `terminated`. + stateLock.lock() + + if case let .terminating(observers, terminationKind) = state { + // Try to acquire the `sendLock`, and fail gracefully since the current + // lock holder would attempt to commit after it is done anyway. + if sendLock.try() { + state = .terminated + stateLock.unlock() + + if let event = terminationKind.materialize() { + for observer in observers { + observer.send(event) + } + } + + sendLock.unlock() + disposable.dispose() + return + } + } + + stateLock.unlock() + } + + /// Try to dispose of the signal silently if the `Signal` has deinitialized and + /// has no observer. + /// + /// It fails gracefully if the signal is terminating or terminated, has one or + /// more observers, or has not deinitialized. + /// + /// - precondition: `stateLock` must have been acquired by the caller. + /// + /// - parameters: + /// - stateLock: The `stateLock` acquired by the caller. + private func tryToDisposeSilentlyIfQualified(unlocking stateLock: Lock) { + assert(!stateLock.try(), "Calling `unconditionallyTerminate` without acquiring `stateLock`.") + + if case let .alive(observers, true) = state, observers.isEmpty { + // Transition to `terminated` directly only if there is no event delivery + // on going. + if sendLock.try() { + self.state = .terminated + stateLock.unlock() + sendLock.unlock() + + disposable.dispose() + return + } + + self.state = .terminating(Bag(), .silent) + stateLock.unlock() + + tryToCommitTermination() + return + } + + stateLock.unlock() + } + + /// Acknowledge the deinitialization of the `Signal`. + fileprivate func signalDidDeinitialize() { + stateLock.lock() + + // Mark the `Signal` has now deinitialized. + if case let .alive(observers, false) = state { + state = .alive(observers, hasDeinitialized: true) + } + + // Attempt to start the disposal of the signal if it has no active observer. + tryToDisposeSilentlyIfQualified(unlocking: stateLock) + } + + deinit { + disposable.dispose() + } + } + + /// Initialize a Signal that will immediately invoke the given generator, + /// then forward events sent to the given observer. + /// + /// - note: The disposable returned from the closure will be automatically + /// disposed if a terminating event is sent to the observer. The + /// Signal itself will remain alive until the observer is released. + /// + /// - parameters: + /// - generator: A closure that accepts an implicitly created observer + /// that will act as an event emitter for the signal. + public init(_ generator: (Observer, Lifetime) -> Void) { + core = Core(generator) + } + + /// Observe the Signal by sending any future events to the given observer. + /// + /// - note: If the Signal has already terminated, the observer will + /// immediately receive an `interrupted` event. + /// + /// - parameters: + /// - observer: An observer to forward the events to. + /// + /// - returns: A `Disposable` which can be used to disconnect the observer, + /// or `nil` if the signal has already terminated. + @discardableResult + public func observe(_ observer: Observer) -> Disposable? { + return core.observe(observer) + } + + deinit { + core.signalDidDeinitialize() + } + + /// The state of a `Signal`. + /// + /// `SignalState` is guaranteed to be laid out as a tagged pointer by the Swift + /// compiler in the support targets of the Swift 3.0.1 ABI. + /// + /// The Swift compiler has also an optimization for enums with payloads that are + /// all reference counted, and at most one no-payload case. + private enum State { + // `TerminationKind` is constantly pointer-size large to keep `Signal.Core` + // allocation size independent of the actual `Value` and `Error` types. + enum TerminationKind { + case completed + case interrupted + case failed(Swift.Error) + case silent + + init(_ event: Event) { + switch event { + case .value: + fatalError() + case .interrupted: + self = .interrupted + case let .failed(error): + self = .failed(error) + case .completed: + self = .completed + } + } + + func materialize() -> Event? { + switch self { + case .completed: + return .completed + case .interrupted: + return .interrupted + case let .failed(error): + return .failed(error as! Error) + case .silent: + return nil + } + } + } + + /// The `Signal` is alive. + case alive(Bag, hasDeinitialized: Bool) + + /// The `Signal` has received a termination event, and is about to be + /// terminated. + case terminating(Bag, TerminationKind) + + /// The `Signal` has terminated. + case terminated + } +} + +extension Signal { + /// A Signal that never sends any events to its observers. + public static var never: Signal { + return self.init { observer, lifetime in + // If `observer` deinitializes, the `Signal` would interrupt which is + // undesirable for `Signal.never`. + lifetime.observeEnded { _ = observer } + } + } + + /// A Signal that completes immediately without emitting any value. + public static var empty: Signal { + return self.init { observer, _ in + observer.sendCompleted() + } + } + + /// Create a `Signal` that will be controlled by sending events to an + /// input observer. + /// + /// - note: The `Signal` will remain alive until a terminating event is sent + /// to the input observer, or until it has no observers and there + /// are no strong references to it. + /// + /// - parameters: + /// - disposable: An optional disposable to associate with the signal, and + /// to be disposed of when the signal terminates. + /// + /// - returns: A 2-tuple of the output end of the pipe as `Signal`, and the input end + /// of the pipe as `Signal.Observer`. + public static func pipe(disposable: Disposable? = nil) -> (output: Signal, input: Observer) { + var observer: Observer! + + let signal = self.init { innerObserver, lifetime in + observer = innerObserver + lifetime += disposable + } + + return (signal, observer) + } +} + +public protocol SignalProtocol: class { + /// The type of values being sent by `self`. + associatedtype Value + + /// The type of error that can occur on `self`. + associatedtype Error: Swift.Error + + /// The materialized `self`. + var signal: Signal { get } +} + +extension Signal: SignalProtocol { + public var signal: Signal { + return self + } +} + +extension Signal: SignalProducerConvertible { + public var producer: SignalProducer { + return SignalProducer(self) + } +} + +extension Signal { + /// Observe `self` for all events being emitted. + /// + /// - note: If `self` has terminated, the closure would be invoked with an + /// `interrupted` event immediately. + /// + /// - parameters: + /// - action: A closure to be invoked with every event from `self`. + /// + /// - returns: A disposable to detach `action` from `self`. `nil` if `self` has + /// terminated. + @discardableResult + public func observe(_ action: @escaping Signal.Observer.Action) -> Disposable? { + return observe(Observer(action)) + } + + /// Observe `self` for all values being emitted, and if any, the failure. + /// + /// - parameters: + /// - action: A closure to be invoked with values from `self`, or the propagated + /// error should any `failed` event is emitted. + /// + /// - returns: A disposable to detach `action` from `self`. `nil` if `self` has + /// terminated. + @discardableResult + public func observeResult(_ action: @escaping (Result) -> Void) -> Disposable? { + return observe( + Observer( + value: { action(.success($0)) }, + failed: { action(.failure($0)) } + ) + ) + } + + /// Observe `self` for its completion. + /// + /// - parameters: + /// - action: A closure to be invoked when a `completed` event is emitted. + /// + /// - returns: A disposable to detach `action` from `self`. `nil` if `self` has + /// terminated. + @discardableResult + public func observeCompleted(_ action: @escaping () -> Void) -> Disposable? { + return observe(Observer(completed: action)) + } + + /// Observe `self` for its failure. + /// + /// - parameters: + /// - action: A closure to be invoked with the propagated error, should any + /// `failed` event is emitted. + /// + /// - returns: A disposable to detach `action` from `self`. `nil` if `self` has + /// terminated. + @discardableResult + public func observeFailed(_ action: @escaping (Error) -> Void) -> Disposable? { + return observe(Observer(failed: action)) + } + + /// Observe `self` for its interruption. + /// + /// - note: If `self` has terminated, the closure would be invoked immediately. + /// + /// - parameters: + /// - action: A closure to be invoked when an `interrupted` event is emitted. + /// + /// - returns: A disposable to detach `action` from `self`. `nil` if `self` has + /// terminated. + @discardableResult + public func observeInterrupted(_ action: @escaping () -> Void) -> Disposable? { + return observe(Observer(interrupted: action)) + } +} + +extension Signal where Error == Never { + /// Observe `self` for all values being emitted. + /// + /// - parameters: + /// - action: A closure to be invoked with values from `self`. + /// + /// - returns: A disposable to detach `action` from `self`. `nil` if `self` has + /// terminated. + @discardableResult + public func observeValues(_ action: @escaping (Value) -> Void) -> Disposable? { + return observe(Observer(value: action)) + } +} + +extension Signal { + /// Perform an action upon every event from `self`. The action may generate zero or + /// more events. + /// + /// - precondition: The action must be synchronous. + /// + /// - parameters: + /// - transform: A closure that creates the said action from the given event + /// closure. + /// + /// - returns: A signal that forwards events yielded by the action. + internal func flatMapEvent(_ transform: @escaping Event.Transformation) -> Signal { + return Signal { output, lifetime in + // Create an input sink whose events would go through the given + // event transformation, and have the resulting events propagated + // to the resulting `Signal`. + let input = transform(output.send, lifetime) + lifetime += self.observe(input) + } + } + + /// Map each value in the signal to a new value. + /// + /// - parameters: + /// - transform: A closure that accepts a value from the `value` event and + /// returns a new value. + /// + /// - returns: A signal that will send new values. + public func map(_ transform: @escaping (Value) -> U) -> Signal { + return flatMapEvent(Signal.Event.map(transform)) + } + + /// Map each value in the signal to a new constant value. + /// + /// - parameters: + /// - value: A new value. + /// + /// - returns: A signal that will send new values. + public func map(value: U) -> Signal { + return map { _ in value } + } + + /// Map each value in the signal to a new value by applying a key path. + /// + /// - parameters: + /// - keyPath: A key path relative to the signal's `Value` type. + /// + /// - returns: A signal that will send new values. + public func map(_ keyPath: KeyPath) -> Signal { + return map { $0[keyPath: keyPath] } + } + + /// Map errors in the signal to a new error. + /// + /// - parameters: + /// - transform: A closure that accepts current error object and returns + /// a new type of error object. + /// + /// - returns: A signal that will send new type of errors. + public func mapError(_ transform: @escaping (Error) -> F) -> Signal { + return flatMapEvent(Signal.Event.mapError(transform)) + } + + /// Maps each value in the signal to a new value, lazily evaluating the + /// supplied transformation on the specified scheduler. + /// + /// - important: Unlike `map`, there is not a 1-1 mapping between incoming + /// values, and values sent on the returned signal. If + /// `scheduler` has not yet scheduled `transform` for + /// execution, then each new value will replace the last one as + /// the parameter to `transform` once it is finally executed. + /// + /// - parameters: + /// - transform: The closure used to obtain the returned value from this + /// signal's underlying value. + /// + /// - returns: A signal that sends values obtained using `transform` as this + /// signal sends values. + public func lazyMap(on scheduler: Scheduler, transform: @escaping (Value) -> U) -> Signal { + return flatMapEvent(Signal.Event.lazyMap(on: scheduler, transform: transform)) + } + + /// Preserve only values which pass the given closure. + /// + /// - parameters: + /// - isIncluded: A closure to determine whether a value from `self` should be + /// included in the returned `Signal`. + /// + /// - returns: A signal that forwards the values passing the given closure. + public func filter(_ isIncluded: @escaping (Value) -> Bool) -> Signal { + return flatMapEvent(Signal.Event.filter(isIncluded)) + } + + /// Applies `transform` to values from `signal` and forwards values with non `nil` results unwrapped. + /// - parameters: + /// - transform: A closure that accepts a value from the `value` event and + /// returns a new optional value. + /// + /// - returns: A signal that will send new values, that are non `nil` after the transformation. + public func filterMap(_ transform: @escaping (Value) -> U?) -> Signal { + return flatMapEvent(Signal.Event.filterMap(transform)) + } +} + +extension Signal where Value: OptionalProtocol { + /// Unwrap non-`nil` values and forward them on the returned signal, `nil` + /// values are dropped. + /// + /// - returns: A signal that sends only non-nil values. + public func skipNil() -> Signal { + return flatMapEvent(Signal.Event.skipNil) + } +} + +extension Signal { + /// Take up to `n` values from the signal and then complete. + /// + /// - precondition: `count` must be non-negative number. + /// + /// - parameters: + /// - count: A number of values to take from the signal. + /// + /// - returns: A signal that will yield the first `count` values from `self` + public func take(first count: Int) -> Signal { + precondition(count >= 0) + guard count >= 1 else { return .empty } + return flatMapEvent(Signal.Event.take(first: count)) + } + + /// Collect all values sent by the signal then forward them as a single + /// array and complete. + /// + /// - note: When `self` completes without collecting any value, it will send + /// an empty array of values. + /// + /// - returns: A signal that will yield an array of values when `self` + /// completes. + public func collect() -> Signal<[Value], Error> { + return flatMapEvent(Signal.Event.collect) + } + + /// Collect at most `count` values from `self`, forward them as a single + /// array and complete. + /// + /// - note: When the count is reached the array is sent and the signal + /// starts over yielding a new array of values. + /// + /// - note: When `self` completes any remaining values will be sent, the + /// last array may not have `count` values. Alternatively, if were + /// not collected any values will sent an empty array of values. + /// + /// - precondition: `count` should be greater than zero. + /// + public func collect(count: Int) -> Signal<[Value], Error> { + return flatMapEvent(Signal.Event.collect(count: count)) + } + + /// Collect values from `self`, and emit them if the predicate passes. + /// + /// When `self` completes any remaining values will be sent, regardless of the + /// collected values matching `shouldEmit` or not. + /// + /// If `self` completes without having emitted any value, an empty array would be + /// emitted, followed by the completion of the returned `Signal`. + /// + /// ```` + /// let (signal, observer) = Signal.pipe() + /// + /// signal + /// .collect { values in values.reduce(0, combine: +) == 8 } + /// .observeValues { print($0) } + /// + /// observer.send(value: 1) + /// observer.send(value: 3) + /// observer.send(value: 4) + /// observer.send(value: 7) + /// observer.send(value: 1) + /// observer.send(value: 5) + /// observer.send(value: 6) + /// observer.sendCompleted() + /// + /// // Output: + /// // [1, 3, 4] + /// // [7, 1] + /// // [5, 6] + /// ```` + /// + /// - parameters: + /// - shouldEmit: A closure to determine, when every time a new value is received, + /// whether the collected values should be emitted. The new value + /// is included in the collected values. + /// + /// - returns: A signal of arrays of values, as instructed by the `shouldEmit` + /// closure. + public func collect(_ shouldEmit: @escaping (_ collectedValues: [Value]) -> Bool) -> Signal<[Value], Error> { + return flatMapEvent(Signal.Event.collect(shouldEmit)) + } + + /// Collect values from `self`, and emit them if the predicate passes. + /// + /// When `self` completes any remaining values will be sent, regardless of the + /// collected values matching `shouldEmit` or not. + /// + /// If `self` completes without having emitted any value, an empty array would be + /// emitted, followed by the completion of the returned `Signal`. + /// + /// ```` + /// let (signal, observer) = Signal.pipe() + /// + /// signal + /// .collect { values, value in value == 7 } + /// .observeValues { print($0) } + /// + /// observer.send(value: 1) + /// observer.send(value: 1) + /// observer.send(value: 7) + /// observer.send(value: 7) + /// observer.send(value: 5) + /// observer.send(value: 6) + /// observer.sendCompleted() + /// + /// // Output: + /// // [1, 1] + /// // [7] + /// // [7, 5, 6] + /// ```` + /// + /// - parameters: + /// - shouldEmit: A closure to determine, when every time a new value is received, + /// whether the collected values should be emitted. The new value + /// is **not** included in the collected values, and is included when + /// the next value is received. + /// + /// - returns: A signal of arrays of values, as instructed by the `shouldEmit` + /// closure. + public func collect(_ shouldEmit: @escaping (_ collected: [Value], _ latest: Value) -> Bool) -> Signal<[Value], Error> { + return flatMapEvent(Signal.Event.collect(shouldEmit)) + } + + /// Forward the latest values on `scheduler` every `interval`. + /// + /// - note: If `self` terminates while values are being accumulated, + /// the behaviour will be determined by `discardWhenCompleted`. + /// If `true`, the values will be discarded and the returned signal + /// will terminate immediately. + /// If `false`, that values will be delivered at the next interval. + /// + /// - parameters: + /// - interval: A repetition interval. + /// - scheduler: A scheduler to send values on. + /// - skipEmpty: Whether empty arrays should be sent if no values were + /// accumulated during the interval. + /// - discardWhenCompleted: A boolean to indicate if the latest unsent + /// values should be discarded on completion. + /// + /// - returns: A signal that sends all values that are sent from `self` at + /// `interval` seconds apart. + public func collect(every interval: DispatchTimeInterval, on scheduler: DateScheduler, skipEmpty: Bool = false, discardWhenCompleted: Bool = true) -> Signal<[Value], Error> { + return flatMapEvent(Signal.Event.collect(every: interval, on: scheduler, skipEmpty: skipEmpty, discardWhenCompleted: discardWhenCompleted)) + } + + /// Forward all events onto the given scheduler, instead of whichever + /// scheduler they originally arrived upon. + /// + /// - parameters: + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A signal that will yield `self` values on provided scheduler. + public func observe(on scheduler: Scheduler) -> Signal { + return flatMapEvent(Signal.Event.observe(on: scheduler)) + } +} + +extension Signal { + /// Combine the latest value of the receiver with the latest value from the + /// given signal. + /// + /// - note: The returned signal will not send a value until both inputs have + /// sent at least one value each. + /// + /// - note: If either signal is interrupted, the returned signal will also + /// be interrupted. + /// + /// - note: The returned signal will not complete until both inputs + /// complete. + /// + /// - parameters: + /// - otherSignal: A signal to combine `self`'s value with. + /// + /// - returns: A signal that will yield a tuple containing values of `self` + /// and given signal. + public func combineLatest(with other: Signal) -> Signal<(Value, U), Error> { + return Signal.combineLatest(self, other) + } + + /// Merge the given signal into a single `Signal` that will emit all + /// values from both of them, and complete when all of them have completed. + /// + /// - parameters: + /// - other: A signal to merge `self`'s value with. + /// + /// - returns: A signal that sends all values of `self` and given signal. + public func merge(with other: Signal) -> Signal { + return Signal.merge(self, other) + } + + /// Delay `value` and `completed` events by the given interval, forwarding + /// them on the given scheduler. + /// + /// - note: failed and `interrupted` events are always scheduled + /// immediately. + /// + /// - precondition: `interval` must be non-negative number. + /// + /// - parameters: + /// - interval: Interval to delay `value` and `completed` events by. + /// - scheduler: A scheduler to deliver delayed events on. + /// + /// - returns: A signal that will delay `value` and `completed` events and + /// will yield them on given scheduler. + public func delay(_ interval: TimeInterval, on scheduler: DateScheduler) -> Signal { + return flatMapEvent(Signal.Event.delay(interval, on: scheduler)) + } + + /// Skip first `count` number of values then act as usual. + /// + /// - precondition: `count` must be non-negative number. + /// + /// - parameters: + /// - count: A number of values to skip. + /// + /// - returns: A signal that will skip the first `count` values, then + /// forward everything afterward. + public func skip(first count: Int) -> Signal { + guard count != 0 else { return self } + return flatMapEvent(Signal.Event.skip(first: count)) + } + + /// Treat all Events from `self` as plain values, allowing them to be + /// manipulated just like any other value. + /// + /// In other words, this brings Events “into the monad”. + /// + /// - note: When a Completed or Failed event is received, the resulting + /// signal will send the Event itself and then complete. When an + /// Interrupted event is received, the resulting signal will send + /// the Event itself and then interrupt. + /// + /// - returns: A signal that sends events as its values. + public func materialize() -> Signal { + return flatMapEvent(Signal.Event.materialize) + } + + /// Treats all Results from the input producer as plain values, allowing them + /// to be manipulated just like any other value. + /// + /// In other words, this brings Results “into the monad.” + /// + /// - note: When a Failed event is received, the resulting producer will + /// send the `Result.failure` itself and then complete. + /// + /// - returns: A producer that sends results as its values. + public func materializeResults() -> Signal, Never> { + return flatMapEvent(Signal.Event.materializeResults) + } +} + +extension Signal where Value: EventProtocol, Error == Never { + /// Translate a signal of `Event` _values_ into a signal of those events + /// themselves. + /// + /// - returns: A signal that sends values carried by `self` events. + public func dematerialize() -> Signal { + return flatMapEvent(Signal.Event.dematerialize) + } +} + +extension Signal where Error == Never { + /// Translate a signal of `Result` _values_ into a signal of those events + /// themselves. + /// + /// - returns: A signal that sends values carried by `self` events. + public func dematerializeResults() -> Signal where Value == Result { + return flatMapEvent(Signal.Event.dematerializeResults) + } +} + +extension Signal { + /// Inject side effects to be performed upon the specified signal events. + /// + /// - parameters: + /// - event: A closure that accepts an event and is invoked on every + /// received event. + /// - failed: A closure that accepts error object and is invoked for + /// failed event. + /// - completed: A closure that is invoked for `completed` event. + /// - interrupted: A closure that is invoked for `interrupted` event. + /// - terminated: A closure that is invoked for any terminating event. + /// - disposed: A closure added as disposable when signal completes. + /// - value: A closure that accepts a value from `value` event. + /// + /// - returns: A signal with attached side-effects for given event cases. + public func on( + event: ((Event) -> Void)? = nil, + failed: ((Error) -> Void)? = nil, + completed: (() -> Void)? = nil, + interrupted: (() -> Void)? = nil, + terminated: (() -> Void)? = nil, + disposed: (() -> Void)? = nil, + value: ((Value) -> Void)? = nil + ) -> Signal { + return Signal { observer, lifetime in + if let action = disposed { + lifetime.observeEnded(action) + } + + lifetime += signal.observe { receivedEvent in + event?(receivedEvent) + + switch receivedEvent { + case let .value(v): + value?(v) + + case let .failed(error): + failed?(error) + + case .completed: + completed?() + + case .interrupted: + interrupted?() + } + + if receivedEvent.isTerminating { + terminated?() + } + + observer.send(receivedEvent) + } + } + } +} + +private struct SampleState { + var latestValue: Value? + var isSignalCompleted: Bool = false + var isSamplerCompleted: Bool = false +} + +extension Signal { + /// Forward the latest value from `self` with the value from `sampler` as a + /// tuple, only when`sampler` sends a `value` event. + /// + /// - note: If `sampler` fires before a value has been observed on `self`, + /// nothing happens. + /// + /// - parameters: + /// - sampler: A signal that will trigger the delivery of `value` event + /// from `self`. + /// + /// - returns: A signal that will send values from `self` and `sampler`, + /// sampled (possibly multiple times) by `sampler`, then complete + /// once both input signals have completed, or interrupt if + /// either input signal is interrupted. + public func sample(with sampler: Signal) -> Signal<(Value, T), Error> { + return Signal<(Value, T), Error> { observer, lifetime in + let state = Atomic(SampleState()) + + lifetime += self.observe { event in + switch event { + case let .value(value): + state.modify { + $0.latestValue = value + } + + case let .failed(error): + observer.send(error: error) + + case .completed: + let shouldComplete: Bool = state.modify { + $0.isSignalCompleted = true + return $0.isSamplerCompleted + } + + if shouldComplete { + observer.sendCompleted() + } + + case .interrupted: + observer.sendInterrupted() + } + } + + lifetime += sampler.observe { event in + switch event { + case .value(let samplerValue): + if let value = state.value.latestValue { + observer.send(value: (value, samplerValue)) + } + + case .completed: + let shouldComplete: Bool = state.modify { + $0.isSamplerCompleted = true + return $0.isSignalCompleted + } + + if shouldComplete { + observer.sendCompleted() + } + + case .interrupted: + observer.sendInterrupted() + + case .failed: + break + } + } + } + } + + /// Forward the latest value from `self` whenever `sampler` sends a `value` + /// event. + /// + /// - note: If `sampler` fires before a value has been observed on `self`, + /// nothing happens. + /// + /// - parameters: + /// - sampler: A signal that will trigger the delivery of `value` event + /// from `self`. + /// + /// - returns: A signal that will send values from `self`, sampled (possibly + /// multiple times) by `sampler`, then complete once both input + /// signals have completed, or interrupt if either input signal + /// is interrupted. + public func sample(on sampler: Signal<(), Never>) -> Signal { + return sample(with: sampler) + .map { $0.0 } + } + + /// Forward the latest value from `samplee` with the value from `self` as a + /// tuple, only when `self` sends a `value` event. + /// This is like a flipped version of `sample(with:)`, but `samplee`'s + /// terminal events are completely ignored. + /// + /// - note: If `self` fires before a value has been observed on `samplee`, + /// nothing happens. + /// + /// - parameters: + /// - samplee: A signal whose latest value is sampled by `self`. + /// + /// - returns: A signal that will send values from `self` and `samplee`, + /// sampled (possibly multiple times) by `self`, then terminate + /// once `self` has terminated. **`samplee`'s terminated events + /// are ignored**. + public func withLatest(from samplee: Signal) -> Signal<(Value, U), Error> { + return Signal<(Value, U), Error> { observer, lifetime in + let state = Atomic(nil) + + lifetime += samplee.observeValues { value in + state.value = value + } + + lifetime += self.observe { event in + switch event { + case let .value(value): + if let value2 = state.value { + observer.send(value: (value, value2)) + } + case .completed: + observer.sendCompleted() + case let .failed(error): + observer.send(error: error) + case .interrupted: + observer.sendInterrupted() + } + } + } + } + + /// Forward the latest value from `samplee` with the value from `self` as a + /// tuple, only when `self` sends a `value` event. + /// This is like a flipped version of `sample(with:)`, but `samplee`'s + /// terminal events are completely ignored. + /// + /// - note: If `self` fires before a value has been observed on `samplee`, + /// nothing happens. + /// + /// - parameters: + /// - samplee: A producer whose latest value is sampled by `self`. + /// + /// - returns: A signal that will send values from `self` and `samplee`, + /// sampled (possibly multiple times) by `self`, then terminate + /// once `self` has terminated. **`samplee`'s terminated events + /// are ignored**. + public func withLatest(from samplee: SignalProducer) -> Signal<(Value, U), Error> { + return Signal<(Value, U), Error> { observer, lifetime in + samplee.startWithSignal { signal, disposable in + lifetime += disposable + lifetime += self.withLatest(from: signal).observe(observer) + } + } + } + + /// Forward the latest value from `samplee` with the value from `self` as a + /// tuple, only when `self` sends a `value` event. + /// This is like a flipped version of `sample(with:)`, but `samplee`'s + /// terminal events are completely ignored. + /// + /// - note: If `self` fires before a value has been observed on `samplee`, + /// nothing happens. + /// + /// - parameters: + /// - samplee: A producer whose latest value is sampled by `self`. + /// + /// - returns: A signal that will send values from `self` and `samplee`, + /// sampled (possibly multiple times) by `self`, then terminate + /// once `self` has terminated. **`samplee`'s terminated events + /// are ignored**. + public func withLatest(from samplee: Samplee) -> Signal<(Value, Samplee.Value), Error> where Samplee.Error == Never { + return withLatest(from: samplee.producer) + } +} + +extension Signal { + /// Forwards events from `self` until `lifetime` ends, at which point the + /// returned signal will complete. + /// + /// - parameters: + /// - lifetime: A lifetime whose `ended` signal will cause the returned + /// signal to complete. + /// + /// - returns: A signal that will deliver events until `lifetime` ends. + public func take(during lifetime: Lifetime) -> Signal { + return Signal { observer, innerLifetime in + innerLifetime += self.observe(observer) + innerLifetime += lifetime.observeEnded(observer.sendCompleted) + } + } + + /// Forward events from `self` until `trigger` sends a `value` or + /// `completed` event, at which point the returned signal will complete. + /// + /// - parameters: + /// - trigger: A signal whose `value` or `completed` events will stop the + /// delivery of `value` events from `self`. + /// + /// - returns: A signal that will deliver events until `trigger` sends + /// `value` or `completed` events. + public func take(until trigger: Signal<(), Never>) -> Signal { + return Signal { observer, lifetime in + lifetime += self.observe(observer) + lifetime += trigger.observe { event in + switch event { + case .value, .completed: + observer.sendCompleted() + + case .failed, .interrupted: + break + } + } + } + } + + /// Do not forward any values from `self` until `trigger` sends a `value` or + /// `completed` event, at which point the returned signal behaves exactly + /// like `signal`. + /// + /// - parameters: + /// - trigger: A signal whose `value` or `completed` events will start the + /// deliver of events on `self`. + /// + /// - returns: A signal that will deliver events once the `trigger` sends + /// `value` or `completed` events. + public func skip(until trigger: Signal<(), Never>) -> Signal { + return Signal { observer, lifetime in + let disposable = SerialDisposable() + lifetime += disposable + + disposable.inner = trigger.observe { event in + switch event { + case .value, .completed: + disposable.inner = self.observe(observer) + + case .failed, .interrupted: + break + } + } + } + } + + /// Forward events from `self` with history: values of the returned signal + /// are a tuples whose first member is the previous value and whose second member + /// is the current value. `initial` is supplied as the first member when `self` + /// sends its first value. + /// + /// - parameters: + /// - initial: A value that will be combined with the first value sent by + /// `self`. + /// + /// - returns: A signal that sends tuples that contain previous and current + /// sent values of `self`. + public func combinePrevious(_ initial: Value) -> Signal<(Value, Value), Error> { + return flatMapEvent(Signal.Event.combinePrevious(initial: initial)) + } + + /// Forward events from `self` with history: values of the returned signal + /// are a tuples whose first member is the previous value and whose second member + /// is the current value. + /// + /// The returned `Signal` would not emit any tuple until it has received at least two + /// values. + /// + /// - returns: A signal that sends tuples that contain previous and current + /// sent values of `self`. + public func combinePrevious() -> Signal<(Value, Value), Error> { + return flatMapEvent(Signal.Event.combinePrevious(initial: nil)) + } + + /// Combine all values from `self`, and forward only the final accumulated result. + /// + /// See `scan(_:_:)` if the resulting producer needs to forward also the partial + /// results. + /// + /// - parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - nextPartialResult: A closure that combines the accumulating value and the + /// latest value from `self`. The result would be used in the + /// next call of `nextPartialResult`, or emit to the returned + /// `Signal` when `self` completes. + /// + /// - returns: A signal that sends the final result as `self` completes. + public func reduce(_ initialResult: U, _ nextPartialResult: @escaping (U, Value) -> U) -> Signal { + return flatMapEvent(Signal.Event.reduce(initialResult, nextPartialResult)) + } + + /// Combine all values from `self`, and forward only the final accumulated result. + /// + /// See `scan(into:_:)` if the resulting producer needs to forward also the partial + /// results. + /// + /// - parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - nextPartialResult: A closure that combines the accumulating value and the + /// latest value from `self`. The result would be used in the + /// next call of `nextPartialResult`, or emit to the returned + /// `Signal` when `self` completes. + /// + /// - returns: A signal that sends the final result as `self` completes. + public func reduce(into initialResult: U, _ nextPartialResult: @escaping (inout U, Value) -> Void) -> Signal { + return flatMapEvent(Signal.Event.reduce(into: initialResult, nextPartialResult)) + } + + /// Combine all values from `self`, and forward the partial results and the final + /// result. + /// + /// See `reduce(_:_:)` if the resulting producer needs to forward only the final + /// result. + /// + /// - parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - nextPartialResult: A closure that combines the accumulating value and the + /// latest value from `self`. The result would be forwarded, + /// and would be used in the next call of `nextPartialResult`. + /// + /// - returns: A signal that sends the partial results of the accumuation, and the + /// final result as `self` completes. + public func scan(_ initialResult: U, _ nextPartialResult: @escaping (U, Value) -> U) -> Signal { + return flatMapEvent(Signal.Event.scan(initialResult, nextPartialResult)) + } + + /// Combine all values from `self`, and forward the partial results and the final + /// result. + /// + /// See `reduce(into:_:)` if the resulting producer needs to forward only the final + /// result. + /// + /// - parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - nextPartialResult: A closure that combines the accumulating value and the + /// latest value from `self`. The result would be forwarded, + /// and would be used in the next call of `nextPartialResult`. + /// + /// - returns: A signal that sends the partial results of the accumuation, and the + /// final result as `self` completes. + public func scan(into initialResult: U, _ nextPartialResult: @escaping (inout U, Value) -> Void) -> Signal { + return flatMapEvent(Signal.Event.scan(into: initialResult, nextPartialResult)) + } +} + +extension Signal where Value: Equatable { + /// Forward only values from `self` that are not equal to its immediately preceding + /// value. + /// + /// - note: The first value is always forwarded. + /// + /// - returns: A signal which conditionally forwards values from `self`. + public func skipRepeats() -> Signal { + return flatMapEvent(Signal.Event.skipRepeats(==)) + } +} + +extension Signal { + /// Forward only values from `self` that are not considered equivalent to its + /// immediately preceding value. + /// + /// - note: The first value is always forwarded. + /// + /// - parameters: + /// - isEquivalent: A closure to determine whether two values are equivalent. + /// + /// - returns: A signal which conditionally forwards values from `self`. + public func skipRepeats(_ isEquivalent: @escaping (Value, Value) -> Bool) -> Signal { + return flatMapEvent(Signal.Event.skipRepeats(isEquivalent)) + } + + /// Do not forward any value from `self` until `shouldContinue` returns `false`, at + /// which point the returned signal starts to forward values from `self`, including + /// the one leading to the toggling. + /// + /// - parameters: + /// - shouldContinue: A closure to determine whether the skipping should continue. + /// + /// - returns: A signal which conditionally forwards values from `self`. + public func skip(while shouldContinue: @escaping (Value) -> Bool) -> Signal { + return flatMapEvent(Signal.Event.skip(while: shouldContinue)) + } + + /// Forward events from `self` until `replacement` begins sending events. + /// + /// - parameters: + /// - replacement: A signal to wait to wait for values from and start + /// sending them as a replacement to `self`'s values. + /// + /// - returns: A signal which passes through `value`, failed, and + /// `interrupted` events from `self` until `replacement` sends + /// an event, at which point the returned signal will send that + /// event and switch to passing through events from `replacement` + /// instead, regardless of whether `self` has sent events + /// already. + public func take(untilReplacement signal: Signal) -> Signal { + return Signal { observer, lifetime in + let signalDisposable = self.observe { event in + switch event { + case .completed: + break + + case .value, .failed, .interrupted: + observer.send(event) + } + } + + lifetime += signalDisposable + lifetime += signal.observe { event in + signalDisposable?.dispose() + observer.send(event) + } + } + } + + /// Wait until `self` completes and then forward the final `count` values + /// on the returned signal. + /// + /// - parameters: + /// - count: Number of last events to send after `self` completes. + /// + /// - returns: A signal that receives up to `count` values from `self` + /// after `self` completes. + public func take(last count: Int) -> Signal { + return flatMapEvent(Signal.Event.take(last: count)) + } + + /// Forward any values from `self` until `shouldContinue` returns `false`, at which + /// point the returned signal would complete. + /// + /// - parameters: + /// - shouldContinue: A closure to determine whether the forwarding of values should + /// continue. + /// + /// - returns: A signal which conditionally forwards values from `self`. + public func take(while shouldContinue: @escaping (Value) -> Bool) -> Signal { + return flatMapEvent(Signal.Event.take(while: shouldContinue)) + } +} + +extension Signal { + /// Zip elements of two signals into pairs. The elements of any Nth pair + /// are the Nth elements of the two input signals. + /// + /// - parameters: + /// - otherSignal: A signal to zip values with. + /// + /// - returns: A signal that sends tuples of `self` and `otherSignal`. + public func zip(with other: Signal) -> Signal<(Value, U), Error> { + return Signal.zip(self, other) + } + + /// Forward the latest value on `scheduler` after at least `interval` + /// seconds have passed since *the returned signal* last sent a value. + /// + /// If `self` always sends values more frequently than `interval` seconds, + /// then the returned signal will send a value every `interval` seconds. + /// + /// To measure from when `self` last sent a value, see `debounce`. + /// + /// - seealso: `debounce` + /// + /// - note: If multiple values are received before the interval has elapsed, + /// the latest value is the one that will be passed on. + /// + /// - note: If `self` terminates while a value is being throttled, that + /// value will be discarded and the returned signal will terminate + /// immediately. + /// + /// - note: If the device time changed backwards before previous date while + /// a value is being throttled, and if there is a new value sent, + /// the new value will be passed anyway. + /// + /// - precondition: `interval` must be non-negative number. + /// + /// - parameters: + /// - interval: Number of seconds to wait between sent values. + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A signal that sends values at least `interval` seconds + /// appart on a given scheduler. + public func throttle(_ interval: TimeInterval, on scheduler: DateScheduler) -> Signal { + return flatMapEvent(Signal.Event.throttle(interval, on: scheduler)) + } + + /// Conditionally throttles values sent on the receiver whenever + /// `shouldThrottle` is true, forwarding values on the given scheduler. + /// + /// - note: While `shouldThrottle` remains false, values are forwarded on the + /// given scheduler. If multiple values are received while + /// `shouldThrottle` is true, the latest value is the one that will + /// be passed on. + /// + /// - note: If the input signal terminates while a value is being throttled, + /// that value will be discarded and the returned signal will + /// terminate immediately. + /// + /// - note: If `shouldThrottle` completes before the receiver, and its last + /// value is `true`, the returned signal will remain in the throttled + /// state, emitting no further values until it terminates. + /// + /// - parameters: + /// - shouldThrottle: A boolean property that controls whether values + /// should be throttled. + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A signal that sends values only while `shouldThrottle` is false. + public func throttle(while shouldThrottle: P, on scheduler: Scheduler) -> Signal + where P.Value == Bool + { + return Signal { observer, lifetime in + let initial: ThrottleWhileState = .resumed + let state = Atomic(initial) + let schedulerDisposable = SerialDisposable() + lifetime += schedulerDisposable + + lifetime += shouldThrottle.producer + .skipRepeats() + .startWithValues { shouldThrottle in + let valueToSend = state.modify { state -> Value? in + guard !state.isTerminated else { return nil } + + if shouldThrottle { + state = .throttled(nil) + } else { + defer { state = .resumed } + + if case let .throttled(value?) = state { + return value + } + } + + return nil + } + + if let value = valueToSend { + schedulerDisposable.inner = scheduler.schedule { + observer.send(value: value) + } + } + } + + lifetime += self.observe { event in + let eventToSend = state.modify { state -> Event? in + switch event { + case let .value(value): + switch state { + case .throttled: + state = .throttled(value) + return nil + case .resumed: + return event + case .terminated: + return nil + } + + case .completed, .interrupted, .failed: + state = .terminated + return event + } + } + + if let event = eventToSend { + schedulerDisposable.inner = scheduler.schedule { + observer.send(event) + } + } + } + } + } + + /// Forward the latest value on `scheduler` after at least `interval` + /// seconds have passed since `self` last sent a value. + /// + /// If `self` always sends values more frequently than `interval` seconds, + /// then the returned signal will never send any values. + /// + /// To measure from when the *returned signal* last sent a value, see + /// `throttle`. + /// + /// - seealso: `throttle` + /// + /// - note: If multiple values are received before the interval has elapsed, + /// the latest value is the one that will be passed on. + /// + /// - note: If `self` terminates while a value is being debounced, + /// the behaviour will be determined by `discardWhenCompleted`. + /// If `true`, that value will be discarded and the returned producer + /// will terminate immediately. + /// If `false`, that value will be delivered at the next debounce + /// interval. + /// + /// - precondition: `interval` must be non-negative number. + /// + /// - parameters: + /// - interval: A number of seconds to wait before sending a value. + /// - scheduler: A scheduler to send values on. + /// - discardWhenCompleted: A boolean to indicate if the latest value + /// should be discarded on completion. + /// + /// - returns: A signal that sends values that are sent from `self` at least + /// `interval` seconds apart. + public func debounce(_ interval: TimeInterval, on scheduler: DateScheduler, discardWhenCompleted: Bool = true) -> Signal { + return flatMapEvent(Signal.Event.debounce(interval, on: scheduler, discardWhenCompleted: discardWhenCompleted)) + } +} + +extension Signal { + /// Forward only those values from `self` that have unique identities across + /// the set of all values that have been seen. + /// + /// - note: This causes the identities to be retained to check for + /// uniqueness. + /// + /// - parameters: + /// - transform: A closure that accepts a value and returns identity + /// value. + /// + /// - returns: A signal that sends unique values during its lifetime. + public func uniqueValues(_ transform: @escaping (Value) -> Identity) -> Signal { + return flatMapEvent(Signal.Event.uniqueValues(transform)) + } +} + +extension Signal where Value: Hashable { + /// Forward only those values from `self` that are unique across the set of + /// all values that have been seen. + /// + /// - note: This causes the values to be retained to check for uniqueness. + /// Providing a function that returns a unique value for each sent + /// value can help you reduce the memory footprint. + /// + /// - returns: A signal that sends unique values during its lifetime. + public func uniqueValues() -> Signal { + return uniqueValues { $0 } + } +} + +private enum ThrottleWhileState { + case resumed + case throttled(Value?) + case terminated + + var isTerminated: Bool { + switch self { + case .terminated: + return true + case .resumed, .throttled: + return false + } + } +} + +private protocol SignalAggregateStrategy: class { + /// Update the latest value of the signal at `position` to be `value`. + /// + /// - parameters: + /// - value: The latest value emitted by the signal at `position`. + /// - position: The position of the signal. + func update(_ value: Any, at position: Int) + + /// Record the completion of the signal at `position`. + /// + /// - parameters: + /// - position: The position of the signal. + func complete(at position: Int) + + init(count: Int, action: @escaping (AggregateStrategyEvent) -> Void) +} + +private enum AggregateStrategyEvent { + case value(ContiguousArray) + case completed +} + +extension Signal { + // Threading of `CombineLatestStrategy` and `ZipStrategy`. + // + // The threading models of these strategies mirror that of `Signal.Core` to allow + // recursive termial event from the upstreams that is triggered by the combined + // values. + // + // The strategies do not unique the delivery of `completed`, since `Signal` already + // guarantees that no event would ever be delivered after a terminal event. + + private final class CombineLatestStrategy: SignalAggregateStrategy { + private enum Placeholder { + case none + } + + var values: ContiguousArray + + private var _haveAllSentInitial: Bool + private var haveAllSentInitial: Bool { + get { + if _haveAllSentInitial { + return true + } + + _haveAllSentInitial = values.reduce(true) { $0 && !($1 is Placeholder) } + return _haveAllSentInitial + } + } + + private let count: Int + private let lock: Lock + + private let completion: Atomic + private let action: (AggregateStrategyEvent) -> Void + + func update(_ value: Any, at position: Int) { + lock.lock() + values[position] = value + + if haveAllSentInitial { + action(.value(values)) + } + + lock.unlock() + + if completion.value == self.count, lock.try() { + action(.completed) + lock.unlock() + } + } + + func complete(at position: Int) { + let count: Int = completion.modify { count in + count += 1 + return count + } + + if count == self.count, lock.try() { + action(.completed) + lock.unlock() + } + } + + init(count: Int, action: @escaping (AggregateStrategyEvent) -> Void) { + self.count = count + self.lock = Lock.make() + self.values = ContiguousArray(repeating: Placeholder.none, count: count) + self._haveAllSentInitial = false + self.completion = Atomic(0) + self.action = action + } + } + + private final class ZipStrategy: SignalAggregateStrategy { + private let stateLock: Lock + private let sendLock: Lock + + private var values: ContiguousArray<[Any]> + private var canEmit: Bool { + return values.reduce(true) { $0 && !$1.isEmpty } + } + + private var hasConcurrentlyCompleted: Bool + private var isCompleted: ContiguousArray + + private var hasCompletedAndEmptiedSignal: Bool { + return Swift.zip(values, isCompleted).contains(where: { $0.0.isEmpty && $0.1 }) + } + + private var areAllCompleted: Bool { + return isCompleted.reduce(true) { $0 && $1 } + } + + private let action: (AggregateStrategyEvent) -> Void + + func update(_ value: Any, at position: Int) { + stateLock.lock() + values[position].append(value) + + if canEmit { + var buffer = ContiguousArray() + buffer.reserveCapacity(values.count) + + for index in values.indices { + buffer.append(values[index].removeFirst()) + } + + let shouldComplete = areAllCompleted || hasCompletedAndEmptiedSignal + sendLock.lock() + stateLock.unlock() + + action(.value(buffer)) + + if shouldComplete { + action(.completed) + } + + sendLock.unlock() + + stateLock.lock() + + if hasConcurrentlyCompleted { + sendLock.lock() + action(.completed) + sendLock.unlock() + } + } + + stateLock.unlock() + } + + func complete(at position: Int) { + stateLock.lock() + isCompleted[position] = true + + if hasConcurrentlyCompleted || areAllCompleted || hasCompletedAndEmptiedSignal { + if sendLock.try() { + stateLock.unlock() + + action(.completed) + sendLock.unlock() + return + } + + hasConcurrentlyCompleted = true + } + + stateLock.unlock() + } + + init(count: Int, action: @escaping (AggregateStrategyEvent) -> Void) { + self.values = ContiguousArray(repeating: [], count: count) + self.hasConcurrentlyCompleted = false + self.isCompleted = ContiguousArray(repeating: false, count: count) + self.action = action + self.sendLock = Lock.make() + self.stateLock = Lock.make() + } + } + + private final class AggregateBuilder { + fileprivate var startHandlers: [(_ index: Int, _ strategy: Strategy, _ action: @escaping (Signal.Event) -> Void) -> Disposable?] + + init() { + self.startHandlers = [] + } + + @discardableResult + func add(_ signal: Signal) -> Self { + startHandlers.append { index, strategy, action in + return signal.observe { event in + switch event { + case let .value(value): + strategy.update(value, at: index) + + case .completed: + strategy.complete(at: index) + + case .interrupted: + action(.interrupted) + + case let .failed(error): + action(.failed(error)) + } + } + } + + return self + } + } + + private convenience init(_ builder: AggregateBuilder, _ transform: @escaping (ContiguousArray) -> Value) { + self.init { observer, lifetime in + let strategy = Strategy(count: builder.startHandlers.count) { event in + switch event { + case let .value(value): + observer.send(value: transform(value)) + case .completed: + observer.sendCompleted() + } + } + + for (index, action) in builder.startHandlers.enumerated() where !lifetime.hasEnded { + lifetime += action(index, strategy) { observer.send($0.promoteValue()) } + } + } + } + + private convenience init(_ strategy: Strategy.Type, _ signals: S) where Value == [U], S.Iterator.Element == Signal { + self.init(signals.reduce(AggregateBuilder()) { $0.add($1) }) { $0.map { $0 as! U } } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal) where Value == (A, B) { + self.init(AggregateBuilder().add(a).add(b)) { + return ($0[0] as! A, $0[1] as! B) + } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal, _ c: Signal) where Value == (A, B, C) { + self.init(AggregateBuilder().add(a).add(b).add(c)) { + return ($0[0] as! A, $0[1] as! B, $0[2] as! C) + } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal) where Value == (A, B, C, D) { + self.init(AggregateBuilder().add(a).add(b).add(c).add(d)) { + return ($0[0] as! A, $0[1] as! B, $0[2] as! C, $0[3] as! D) + } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal) where Value == (A, B, C, D, E) { + self.init(AggregateBuilder().add(a).add(b).add(c).add(d).add(e)) { + return ($0[0] as! A, $0[1] as! B, $0[2] as! C, $0[3] as! D, $0[4] as! E) + } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal) where Value == (A, B, C, D, E, F) { + self.init(AggregateBuilder().add(a).add(b).add(c).add(d).add(e).add(f)) { + return ($0[0] as! A, $0[1] as! B, $0[2] as! C, $0[3] as! D, $0[4] as! E, $0[5] as! F) + } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal) where Value == (A, B, C, D, E, F, G) { + self.init(AggregateBuilder().add(a).add(b).add(c).add(d).add(e).add(f).add(g)) { + return ($0[0] as! A, $0[1] as! B, $0[2] as! C, $0[3] as! D, $0[4] as! E, $0[5] as! F, $0[6] as! G) + } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal) where Value == (A, B, C, D, E, F, G, H) { + self.init(AggregateBuilder().add(a).add(b).add(c).add(d).add(e).add(f).add(g).add(h)) { + return ($0[0] as! A, $0[1] as! B, $0[2] as! C, $0[3] as! D, $0[4] as! E, $0[5] as! F, $0[6] as! G, $0[7] as! H) + } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal) where Value == (A, B, C, D, E, F, G, H, I) { + self.init(AggregateBuilder().add(a).add(b).add(c).add(d).add(e).add(f).add(g).add(h).add(i)) { + return ($0[0] as! A, $0[1] as! B, $0[2] as! C, $0[3] as! D, $0[4] as! E, $0[5] as! F, $0[6] as! G, $0[7] as! H, $0[8] as! I) + } + } + + private convenience init(_ strategy: Strategy.Type, _ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal, _ j: Signal) where Value == (A, B, C, D, E, F, G, H, I, J) { + self.init(AggregateBuilder().add(a).add(b).add(c).add(d).add(e).add(f).add(g).add(h).add(i).add(j)) { + return ($0[0] as! A, $0[1] as! B, $0[2] as! C, $0[3] as! D, $0[4] as! E, $0[5] as! F, $0[6] as! G, $0[7] as! H, $0[8] as! I, $0[9] as! J) + } + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal) -> Signal<(Value, B), Error> { + return .init(CombineLatestStrategy.self, a, b) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal, _ c: Signal) -> Signal<(Value, B, C), Error> { + return .init(CombineLatestStrategy.self, a, b, c) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal) -> Signal<(Value, B, C, D), Error> { + return .init(CombineLatestStrategy.self, a, b, c, d) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal) -> Signal<(Value, B, C, D, E), Error> { + return .init(CombineLatestStrategy.self, a, b, c, d, e) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal) -> Signal<(Value, B, C, D, E, F), Error> { + return .init(CombineLatestStrategy.self, a, b, c, d, e, f) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal) -> Signal<(Value, B, C, D, E, F, G), Error> { + return .init(CombineLatestStrategy.self, a, b, c, d, e, f, g) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal) -> Signal<(Value, B, C, D, E, F, G, H), Error> { + return .init(CombineLatestStrategy.self, a, b, c, d, e, f, g, h) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal) -> Signal<(Value, B, C, D, E, F, G, H, I), Error> { + return .init(CombineLatestStrategy.self, a, b, c, d, e, f, g, h, i) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal, _ j: Signal) -> Signal<(Value, B, C, D, E, F, G, H, I, J), Error> { + return .init(CombineLatestStrategy.self, a, b, c, d, e, f, g, h, i, j) + } + + /// Combines the values of all the given signals, in the manner described by + /// `combineLatest(with:)`. No events will be sent if the sequence is empty. + public static func combineLatest(_ signals: S) -> Signal<[Value], Error> where S.Iterator.Element == Signal { + return .init(CombineLatestStrategy.self, signals) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal) -> Signal<(Value, B), Error> { + return .init(ZipStrategy.self, a, b) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal, _ c: Signal) -> Signal<(Value, B, C), Error> { + return .init(ZipStrategy.self, a, b, c) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal) -> Signal<(Value, B, C, D), Error> { + return .init(ZipStrategy.self, a, b, c, d) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal) -> Signal<(Value, B, C, D, E), Error> { + return .init(ZipStrategy.self, a, b, c, d, e) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal) -> Signal<(Value, B, C, D, E, F), Error> { + return .init(ZipStrategy.self, a, b, c, d, e, f) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal) -> Signal<(Value, B, C, D, E, F, G), Error> { + return .init(ZipStrategy.self, a, b, c, d, e, f, g) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal) -> Signal<(Value, B, C, D, E, F, G, H), Error> { + return .init(ZipStrategy.self, a, b, c, d, e, f, g, h) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal) -> Signal<(Value, B, C, D, E, F, G, H, I), Error> { + return .init(ZipStrategy.self, a, b, c, d, e, f, g, h, i) + } + + /// Zip the values of all the given signals, in the manner described by `zip(with:)`. + public static func zip(_ a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal, _ j: Signal) -> Signal<(Value, B, C, D, E, F, G, H, I, J), Error> { + return .init(ZipStrategy.self, a, b, c, d, e, f, g, h, i, j) + } + + /// Zips the values of all the given signals, in the manner described by + /// `zip(with:)`. No events will be sent if the sequence is empty. + public static func zip(_ signals: S) -> Signal<[Value], Error> where S.Iterator.Element == Signal { + return .init(ZipStrategy.self, signals) + } +} + +extension Signal { + /// Forward events from `self` until `interval`. Then if signal isn't + /// completed yet, fails with `error` on `scheduler`. + /// + /// - note: If the interval is 0, the timeout will be scheduled immediately. + /// The signal must complete synchronously (or on a faster + /// scheduler) to avoid the timeout. + /// + /// - precondition: `interval` must be non-negative number. + /// + /// - parameters: + /// - error: Error to send with failed event if `self` is not completed + /// when `interval` passes. + /// - interval: Number of seconds to wait for `self` to complete. + /// - scheudler: A scheduler to deliver error on. + /// + /// - returns: A signal that sends events for at most `interval` seconds, + /// then, if not `completed` - sends `error` with failed event + /// on `scheduler`. + public func timeout(after interval: TimeInterval, raising error: Error, on scheduler: DateScheduler) -> Signal { + precondition(interval >= 0) + + return Signal { observer, lifetime in + let date = scheduler.currentDate.addingTimeInterval(interval) + + lifetime += scheduler.schedule(after: date) { + observer.send(error: error) + } + + lifetime += self.observe(observer) + } + } +} + +extension Signal where Error == Never { + /// Promote a signal that does not generate failures into one that can. + /// + /// - note: This does not actually cause failures to be generated for the + /// given signal, but makes it easier to combine with other signals + /// that may fail; for example, with operators like + /// `combineLatestWith`, `zipWith`, `flatten`, etc. + /// + /// - parameters: + /// - _ An `ErrorType`. + /// + /// - returns: A signal that has an instantiatable `ErrorType`. + public func promoteError(_: F.Type = F.self) -> Signal { + return flatMapEvent(Signal.Event.promoteError(F.self)) + } + + /// Promote a signal that does not generate failures into one that can. + /// + /// - note: This does not actually cause failures to be generated for the + /// given signal, but makes it easier to combine with other signals + /// that may fail; for example, with operators like + /// `combineLatestWith`, `zipWith`, `flatten`, etc. + /// + /// - parameters: + /// - _ An `ErrorType`. + /// + /// - returns: A signal that has an instantiatable `ErrorType`. + public func promoteError(_: Error.Type = Error.self) -> Signal { + return self + } + + /// Forward events from `self` until `interval`. Then if signal isn't + /// completed yet, fails with `error` on `scheduler`. + /// + /// - note: If the interval is 0, the timeout will be scheduled immediately. + /// The signal must complete synchronously (or on a faster + /// scheduler) to avoid the timeout. + /// + /// - parameters: + /// - interval: Number of seconds to wait for `self` to complete. + /// - error: Error to send with `failed` event if `self` is not completed + /// when `interval` passes. + /// - scheudler: A scheduler to deliver error on. + /// + /// - returns: A signal that sends events for at most `interval` seconds, + /// then, if not `completed` - sends `error` with `failed` event + /// on `scheduler`. + public func timeout( + after interval: TimeInterval, + raising error: NewError, + on scheduler: DateScheduler + ) -> Signal { + return self + .promoteError(NewError.self) + .timeout(after: interval, raising: error, on: scheduler) + } +} + +extension Signal where Value == Never { + /// Promote a signal that does not generate values, as indicated by `Never`, to be + /// a signal of the given type of value. + /// + /// - note: The promotion does not result in any value being generated. + /// + /// - parameters: + /// - _ The type of value to promote to. + /// + /// - returns: A signal that forwards all terminal events from `self`. + public func promoteValue(_: U.Type = U.self) -> Signal { + return flatMapEvent(Signal.Event.promoteValue(U.self)) + } + + /// Promote a signal that does not generate values, as indicated by `Never`, to be + /// a signal of the given type of value. + /// + /// - note: The promotion does not result in any value being generated. + /// + /// - parameters: + /// - _ The type of value to promote to. + /// + /// - returns: A signal that forwards all terminal events from `self`. + public func promoteValue(_: Value.Type = Value.self) -> Signal { + return self + } +} + +extension Signal where Value == Bool { + /// Create a signal that computes a logical NOT in the latest values of `self`. + /// + /// - returns: A signal that emits the logical NOT results. + public func negate() -> Signal { + return self.map(!) + } + + /// Create a signal that computes a logical AND between the latest values of `self` + /// and `signal`. + /// + /// - parameters: + /// - signal: Signal to be combined with `self`. + /// + /// - returns: A signal that emits the logical AND results. + public func and(_ signal: Signal) -> Signal { + return type(of: self).all([self, signal]) + } + + /// Create a signal that computes a logical AND between the latest values of `booleans`. + /// + /// - parameters: + /// - booleans: A collection of boolean signals to be combined. + /// + /// - returns: A signal that emits the logical AND results. + public static func all(_ booleans: BooleansCollection) -> Signal where BooleansCollection.Element == Signal { + return combineLatest(booleans).map { $0.reduce(true) { $0 && $1 } } + } + + /// Create a signal that computes a logical OR between the latest values of `self` + /// and `signal`. + /// + /// - parameters: + /// - signal: Signal to be combined with `self`. + /// + /// - returns: A signal that emits the logical OR results. + public func or(_ signal: Signal) -> Signal { + return type(of: self).any([self, signal]) + } + + /// Create a signal that computes a logical OR between the latest values of `booleans`. + /// + /// - parameters: + /// - booleans: A collection of boolean signals to be combined. + /// + /// - returns: A signal that emits the logical OR results. + public static func any(_ booleans: BooleansCollection) -> Signal where BooleansCollection.Element == Signal { + return combineLatest(booleans).map { $0.reduce(false) { $0 || $1 } } + } +} + +extension Signal { + /// Apply an action to every value from `self`, and forward the value if the action + /// succeeds. If the action fails with an error, the returned `Signal` would propagate + /// the failure and terminate. + /// + /// - parameters: + /// - action: An action which yields a `Result`. + /// + /// - returns: A signal which forwards the values from `self` until the given action + /// fails. + public func attempt(_ action: @escaping (Value) -> Result<(), Error>) -> Signal { + return flatMapEvent(Signal.Event.attempt(action)) + } + + /// Apply a transform to every value from `self`, and forward the transformed value + /// if the action succeeds. If the action fails with an error, the returned `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - action: A transform which yields a `Result` of the transformed value or the + /// error. + /// + /// - returns: A signal which forwards the transformed values. + public func attemptMap(_ transform: @escaping (Value) -> Result) -> Signal { + return flatMapEvent(Signal.Event.attemptMap(transform)) + } +} + +extension Signal where Error == Never { + /// Apply a throwable action to every value from `self`, and forward the values + /// if the action succeeds. If the action throws an error, the returned `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - action: A throwable closure to perform an arbitrary action on the value. + /// + /// - returns: A signal which forwards the successful values of the given action. + public func attempt(_ action: @escaping (Value) throws -> Void) -> Signal { + return self + .promoteError(Swift.Error.self) + .attempt(action) + } + + /// Apply a throwable transform to every value from `self`, and forward the results + /// if the action succeeds. If the transform throws an error, the returned `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - transform: A throwable transform. + /// + /// - returns: A signal which forwards the successfully transformed values. + public func attemptMap(_ transform: @escaping (Value) throws -> U) -> Signal { + return self + .promoteError(Swift.Error.self) + .attemptMap(transform) + } +} + +extension Signal where Error == Swift.Error { + /// Apply a throwable action to every value from `self`, and forward the values + /// if the action succeeds. If the action throws an error, the returned `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - action: A throwable closure to perform an arbitrary action on the value. + /// + /// - returns: A signal which forwards the successful values of the given action. + public func attempt(_ action: @escaping (Value) throws -> Void) -> Signal { + return flatMapEvent(Signal.Event.attempt(action)) + } + + /// Apply a throwable transform to every value from `self`, and forward the results + /// if the action succeeds. If the transform throws an error, the returned `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - transform: A throwable transform. + /// + /// - returns: A signal which forwards the successfully transformed values. + public func attemptMap(_ transform: @escaping (Value) throws -> U) -> Signal { + return flatMapEvent(Signal.Event.attemptMap(transform)) + } +} diff --git a/Pods/ReactiveSwift/Sources/SignalProducer.swift b/Pods/ReactiveSwift/Sources/SignalProducer.swift new file mode 100644 index 0000000..0cdcb10 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/SignalProducer.swift @@ -0,0 +1,2956 @@ +import Dispatch +import Foundation + +/// A SignalProducer creates Signals that can produce values of type `Value` +/// and/or fail with errors of type `Error`. If no failure should be possible, +/// `Never` can be specified for `Error`. +/// +/// SignalProducers can be used to represent operations or tasks, like network +/// requests, where each invocation of `start()` will create a new underlying +/// operation. This ensures that consumers will receive the results, versus a +/// plain Signal, where the results might be sent before any observers are +/// attached. +/// +/// Because of the behavior of `start()`, different Signals created from the +/// producer may see a different version of Events. The Events may arrive in a +/// different order between Signals, or the stream might be completely +/// different! +public struct SignalProducer { + public typealias ProducedSignal = Signal + + /// `core` is the actual implementation for this `SignalProducer`. It is responsible + /// of: + /// + /// 1. handling the single-observer `start`; and + /// 2. building `Signal`s on demand via its `makeInstance()` method, which produces a + /// `Signal` with the associated side effect and interrupt handle. + fileprivate let core: SignalProducerCore + + /// Convert an entity into its equivalent representation as `SignalProducer`. + /// + /// - parameters: + /// - base: The entity to convert from. + public init(_ base: T) where T.Value == Value, T.Error == Error { + self = base.producer + } + + /// Initializes a `SignalProducer` that will emit the same events as the + /// given signal. + /// + /// If the Disposable returned from `start()` is disposed or a terminating + /// event is sent to the observer, the given signal will be disposed. + /// + /// - parameters: + /// - signal: A signal to observe after starting the producer. + public init(_ signal: Signal) { + self.init { observer, lifetime in + lifetime += signal.observe(observer) + } + } + + /// Initialize a `SignalProducer` which invokes the supplied starting side + /// effect once upon the creation of every produced `Signal`, or in other + /// words, for every invocation of `startWithSignal(_:)`, `start(_:)` and + /// their convenience shorthands. + /// + /// The supplied starting side effect would be given (1) an input `Observer` + /// to emit events to the produced `Signal`; and (2) a `Lifetime` to bind + /// resources to the lifetime of the produced `Signal`. + /// + /// The `Lifetime` of a produced `Signal` ends when: (1) a terminal event is + /// sent to the input `Observer`; or (2) when the produced `Signal` is + /// interrupted via the disposable yielded at the starting call. + /// + /// - parameters: + /// - startHandler: The starting side effect. + public init(_ startHandler: @escaping (Signal.Observer, Lifetime) -> Void) { + self.init(SignalCore { + let disposable = CompositeDisposable() + let (signal, observer) = Signal.pipe(disposable: disposable) + let observerDidSetup = { startHandler(observer, Lifetime(disposable)) } + let interruptHandle = AnyDisposable(observer.sendInterrupted) + + return SignalProducerCore.Instance(signal: signal, + observerDidSetup: observerDidSetup, + interruptHandle: interruptHandle) + }) + } + + /// Create a SignalProducer. + /// + /// - parameters: + /// - core: The `SignalProducer` core. + internal init(_ core: SignalProducerCore) { + self.core = core + } + + /// Creates a producer for a `Signal` that will immediately send one value + /// then complete. + /// + /// - parameters: + /// - value: A value that should be sent by the `Signal` in a `value` + /// event. + public init(value: Value) { + self.init(GeneratorCore { observer, _ in + observer.send(value: value) + observer.sendCompleted() + }) + } + + /// Creates a producer for a `Signal` that immediately sends one value, then + /// completes. + /// + /// This initializer differs from `init(value:)` in that its sole `value` + /// event is constructed lazily by invoking the supplied `action` when + /// the `SignalProducer` is started. + /// + /// - parameters: + /// - action: A action that yields a value to be sent by the `Signal` as + /// a `value` event. + public init(_ action: @escaping () -> Value) { + self.init(GeneratorCore { observer, _ in + observer.send(value: action()) + observer.sendCompleted() + }) + } + + /// Create a `SignalProducer` that will attempt the given operation once for + /// each invocation of `start()`. + /// + /// Upon success, the started signal will send the resulting value then + /// complete. Upon failure, the started signal will fail with the error that + /// occurred. + /// + /// - parameters: + /// - action: A closure that returns instance of `Result`. + public init(_ action: @escaping () -> Result) { + self.init(GeneratorCore { observer, _ in + switch action() { + case let .success(value): + observer.send(value: value) + observer.sendCompleted() + case let .failure(error): + observer.send(error: error) + } + }) + } + + /// Creates a producer for a `Signal` that will immediately fail with the + /// given error. + /// + /// - parameters: + /// - error: An error that should be sent by the `Signal` in a `failed` + /// event. + public init(error: Error) { + self.init(GeneratorCore { observer, _ in observer.send(error: error) }) + } + + /// Creates a producer for a Signal that will immediately send one value + /// then complete, or immediately fail, depending on the given Result. + /// + /// - parameters: + /// - result: A `Result` instance that will send either `value` event if + /// `result` is `success`ful or `failed` event if `result` is a + /// `failure`. + public init(result: Result) { + switch result { + case let .success(value): + self.init(value: value) + + case let .failure(error): + self.init(error: error) + } + } + + /// Creates a producer for a Signal that will immediately send the values + /// from the given sequence, then complete. + /// + /// - parameters: + /// - values: A sequence of values that a `Signal` will send as separate + /// `value` events and then complete. + public init(_ values: S) where S.Iterator.Element == Value { + self.init(GeneratorCore(isDisposable: true) { observer, disposable in + for value in values { + observer.send(value: value) + + if disposable.isDisposed { + break + } + } + + observer.sendCompleted() + }) + } + + /// Creates a producer for a Signal that will immediately send the values + /// from the given sequence, then complete. + /// + /// - parameters: + /// - first: First value for the `Signal` to send. + /// - second: Second value for the `Signal` to send. + /// - tail: Rest of the values to be sent by the `Signal`. + public init(values first: Value, _ second: Value, _ tail: Value...) { + self.init([ first, second ] + tail) + } + + /// A producer for a Signal that immediately completes without sending any values. + public static var empty: SignalProducer { + return SignalProducer(GeneratorCore { observer, _ in observer.sendCompleted() }) + } + + /// A producer for a Signal that immediately interrupts when started, without + /// sending any values. + internal static var interrupted: SignalProducer { + return SignalProducer(GeneratorCore { observer, _ in observer.sendInterrupted() }) + } + + /// A producer for a Signal that never sends any events to its observers. + public static var never: SignalProducer { + return self.init { observer, lifetime in + lifetime.observeEnded { _ = observer } + } + } + + /// Create a `Signal` from `self`, pass it into the given closure, and start the + /// associated work on the produced `Signal` as the closure returns. + /// + /// - parameters: + /// - setup: A closure to be invoked before the work associated with the produced + /// `Signal` commences. Both the produced `Signal` and an interrupt handle + /// of the signal would be passed to the closure. + /// - returns: The return value of the given setup closure. + @discardableResult + public func startWithSignal(_ setup: (_ signal: Signal, _ interruptHandle: Disposable) -> Result) -> Result { + let instance = core.makeInstance() + let result = setup(instance.signal, instance.interruptHandle) + if !instance.interruptHandle.isDisposed { + instance.observerDidSetup() + } + return result + } +} + +/// `SignalProducerCore` is the actual implementation of a `SignalProducer`. +/// +/// While `SignalProducerCore` still requires all subclasses to be able to produce +/// instances of `Signal`s, the abstraction enables room of optimization for common +/// compositional and single-observer use cases. +internal class SignalProducerCore { + /// `Instance` represents an instance of `Signal` created from a + /// `SignalProducer`. In addition to the `Signal` itself, it includes also the + /// starting side effect and an interrupt handle for this particular instance. + /// + /// It is the responsibility of the `Instance` consumer to ensure the + /// starting side effect is invoked exactly once, and is invoked after observations + /// has properly setup. + struct Instance { + let signal: Signal + let observerDidSetup: () -> Void + let interruptHandle: Disposable + } + + func makeInstance() -> Instance { + fatalError() + } + + /// Start the producer with an observer created by the given generator. + /// + /// The created observer **must** manaully dispose of the given upstream interrupt + /// handle iff it performs any event transformation that might result in a terminal + /// event. + /// + /// - parameters: + /// - generator: The closure to generate an observer. + /// + /// - returns: A disposable to interrupt the started producer instance. + @discardableResult + func start(_ generator: (_ upstreamInterruptHandle: Disposable) -> Signal.Observer) -> Disposable { + fatalError() + } + + /// Perform an action upon every event from `self`. The action may generate zero or + /// more events. + /// + /// - precondition: The action must be synchronous. + /// + /// - parameters: + /// - transform: A closure that creates the said action from the given event + /// closure. + /// + /// - returns: A producer that forwards events yielded by the action. + internal func flatMapEvent(_ transform: @escaping Signal.Event.Transformation) -> SignalProducer { + return SignalProducer(TransformerCore(source: self, transform: transform)) + } +} + +private final class SignalCore: SignalProducerCore { + private let _make: () -> Instance + + init(_ action: @escaping () -> Instance) { + self._make = action + } + + @discardableResult + override func start(_ generator: (Disposable) -> Signal.Observer) -> Disposable { + let instance = makeInstance() + instance.signal.observe(generator(instance.interruptHandle)) + instance.observerDidSetup() + return instance.interruptHandle + } + + override func makeInstance() -> Instance { + return _make() + } +} + +/// `TransformerCore` composes event transforms, and is intended to back synchronous +/// `SignalProducer` operators in general via the core-level operator `Core.flatMapEvent`. +/// +/// It takes advantage of the deferred, single-observer nature of SignalProducer. For +/// example, when we do: +/// +/// ``` +/// upstream.map(transform).filterMap(filteringTransform).start() +/// ``` +/// +/// It is contractually guaranteed that these operators would always end up producing a +/// chain of streams, each with a _single and persistent_ observer to its upstream. The +/// multicasting & detaching capabilities of Signal is useless in these scenarios. +/// +/// So TransformerCore builds on top of this very fact, and composes directly at the +/// level of event transforms, without any `Signal` in between. +/// +/// - note: This core does not use `Signal` unless it is requested via `makeInstance()`. +private final class TransformerCore: SignalProducerCore { + private let source: SignalProducerCore + private let transform: Signal.Event.Transformation + + init(source: SignalProducerCore, transform: @escaping Signal.Event.Transformation) { + self.source = source + self.transform = transform + } + + @discardableResult + internal override func start(_ generator: (Disposable) -> Signal.Observer) -> Disposable { + // Collect all resources related to this transformed producer instance. + let disposables = CompositeDisposable() + + source.start { upstreamInterrupter in + // Backpropagate the terminal event, if any, to the upstream. + disposables += upstreamInterrupter + + var hasDeliveredTerminalEvent = false + + // Generate the output sink that receives transformed output. + let output = generator(disposables) + + // Wrap the output sink to enforce the "no event beyond the terminal + // event" contract, and the disposal upon termination. + let wrappedOutput: Signal.Observer.Action = { event in + if !hasDeliveredTerminalEvent { + output.send(event) + + if event.isTerminating { + // Mark that a terminal event has already been + // delivered. + hasDeliveredTerminalEvent = true + + // Disposed of all associated resources, and notify + // the upstream too. + disposables.dispose() + } + } + } + + // Create an input sink whose events would go through the given + // event transformation, and have the resulting events propagated + // to the output sink above. + let input = transform(wrappedOutput, Lifetime(disposables)) + + // Return the input sink to the source producer core. + return Signal.Observer(input) + } + + // Manual interruption disposes of `disposables`, which in turn notifies + // the event transformation side effects, and the upstream instance. + return disposables + } + + internal override func flatMapEvent(_ transform: @escaping Signal.Event.Transformation) -> SignalProducer { + return SignalProducer(TransformerCore(source: source) { [innerTransform = self.transform] action, lifetime in + return innerTransform(transform(action, lifetime), lifetime) + }) + } + + internal override func makeInstance() -> Instance { + let disposable = SerialDisposable() + let (signal, observer) = Signal.pipe(disposable: disposable) + + func observerDidSetup() { + start { interrupter in + disposable.inner = interrupter + return observer + } + } + + return Instance(signal: signal, + observerDidSetup: observerDidSetup, + interruptHandle: disposable) + } +} + +/// `GeneratorCore` wraps a generator closure that would be invoked upon a produced +/// `Signal` when started. The generator closure is passed only the input observer and the +/// cancel disposable. +/// +/// It is intended for constant `SignalProducers`s that synchronously emits all events +/// without escaping the `Observer`. +/// +/// - note: This core does not use `Signal` unless it is requested via `makeInstance()`. +private final class GeneratorCore: SignalProducerCore { + private let isDisposable: Bool + private let generator: (Signal.Observer, Disposable) -> Void + + init(isDisposable: Bool = false, _ generator: @escaping (Signal.Observer, Disposable) -> Void) { + self.isDisposable = isDisposable + self.generator = generator + } + + @discardableResult + internal override func start(_ observerGenerator: (Disposable) -> Signal.Observer) -> Disposable { + // Object allocation is a considerable overhead. So unless the core is configured + // to be disposable, we would reuse the already-disposed, shared `NopDisposable`. + let d: Disposable = isDisposable ? _SimpleDisposable() : NopDisposable.shared + generator(observerGenerator(d), d) + return d + } + + internal override func makeInstance() -> Instance { + let (signal, observer) = Signal.pipe() + let d = AnyDisposable(observer.sendInterrupted) + + return Instance(signal: signal, + observerDidSetup: { self.generator(observer, d) }, + interruptHandle: d) + } +} + +extension SignalProducer where Error == Never { + /// Creates a producer for a `Signal` that will immediately send one value + /// then complete. + /// + /// - parameters: + /// - value: A value that should be sent by the `Signal` in a `value` + /// event. + public init(value: Value) { + self.init(GeneratorCore { observer, _ in + observer.send(value: value) + observer.sendCompleted() + }) + } + + /// Creates a producer for a Signal that will immediately send the values + /// from the given sequence, then complete. + /// + /// - parameters: + /// - values: A sequence of values that a `Signal` will send as separate + /// `value` events and then complete. + public init(_ values: S) where S.Iterator.Element == Value { + self.init(GeneratorCore(isDisposable: true) { observer, disposable in + for value in values { + observer.send(value: value) + + if disposable.isDisposed { + break + } + } + + observer.sendCompleted() + }) + } + + /// Creates a producer for a Signal that will immediately send the values + /// from the given sequence, then complete. + /// + /// - parameters: + /// - first: First value for the `Signal` to send. + /// - second: Second value for the `Signal` to send. + /// - tail: Rest of the values to be sent by the `Signal`. + public init(values first: Value, _ second: Value, _ tail: Value...) { + self.init([ first, second ] + tail) + } +} + +extension SignalProducer where Error == Swift.Error { + /// Create a `SignalProducer` that will attempt the given failable operation once for + /// each invocation of `start()`. + /// + /// Upon success, the started producer will send the resulting value then + /// complete. Upon failure, the started signal will fail with the error that + /// occurred. + /// + /// - parameters: + /// - operation: A failable closure. + public init(_ action: @escaping () throws -> Value) { + self.init { + return Result { + return try action() + } + } + } +} + +/// Represents reactive primitives that can be represented by `SignalProducer`. +public protocol SignalProducerConvertible { + /// The type of values being sent by `self`. + associatedtype Value + + /// The type of error that can occur on `self`. + associatedtype Error: Swift.Error + + /// The `SignalProducer` representation of `self`. + var producer: SignalProducer { get } +} + +/// A protocol for constraining associated types to `SignalProducer`. +public protocol SignalProducerProtocol { + /// The type of values being sent by `self`. + associatedtype Value + + /// The type of error that can occur on `self`. + associatedtype Error: Swift.Error + + /// The materialized `self`. + var producer: SignalProducer { get } +} + +extension SignalProducer: SignalProducerConvertible, SignalProducerProtocol { + public var producer: SignalProducer { + return self + } +} + +extension SignalProducer { + /// Create a `Signal` from `self`, and observe it with the given observer. + /// + /// - parameters: + /// - observer: An observer to attach to the produced `Signal`. + /// + /// - returns: A disposable to interrupt the produced `Signal`. + @discardableResult + public func start(_ observer: Signal.Observer = .init()) -> Disposable { + return core.start { _ in observer } + } + + /// Create a `Signal` from `self`, and observe the `Signal` for all events + /// being emitted. + /// + /// - parameters: + /// - action: A closure to be invoked with every event from `self`. + /// + /// - returns: A disposable to interrupt the produced `Signal`. + @discardableResult + public func start(_ action: @escaping Signal.Observer.Action) -> Disposable { + return start(Signal.Observer(action)) + } + + /// Create a `Signal` from `self`, and observe the `Signal` for all values being + /// emitted, and if any, its failure. + /// + /// - parameters: + /// - action: A closure to be invoked with values from `self`, or the propagated + /// error should any `failed` event is emitted. + /// + /// - returns: A disposable to interrupt the produced `Signal`. + @discardableResult + public func startWithResult(_ action: @escaping (Result) -> Void) -> Disposable { + return start( + Signal.Observer( + value: { action(.success($0)) }, + failed: { action(.failure($0)) } + ) + ) + } + + /// Create a `Signal` from `self`, and observe its completion. + /// + /// - parameters: + /// - action: A closure to be invoked when a `completed` event is emitted. + /// + /// - returns: A disposable to interrupt the produced `Signal`. + @discardableResult + public func startWithCompleted(_ action: @escaping () -> Void) -> Disposable { + return start(Signal.Observer(completed: action)) + } + + /// Create a `Signal` from `self`, and observe its failure. + /// + /// - parameters: + /// - action: A closure to be invoked with the propagated error, should any + /// `failed` event is emitted. + /// + /// - returns: A disposable to interrupt the produced `Signal`. + @discardableResult + public func startWithFailed(_ action: @escaping (Error) -> Void) -> Disposable { + return start(Signal.Observer(failed: action)) + } + + /// Create a `Signal` from `self`, and observe its interruption. + /// + /// - parameters: + /// - action: A closure to be invoked when an `interrupted` event is emitted. + /// + /// - returns: A disposable to interrupt the produced `Signal`. + @discardableResult + public func startWithInterrupted(_ action: @escaping () -> Void) -> Disposable { + return start(Signal.Observer(interrupted: action)) + } + + /// Creates a `Signal` from the producer. + /// + /// This is equivalent to `SignalProducer.startWithSignal`, but it has + /// the downside that any values emitted synchronously upon starting will + /// be missed by the observer, because it won't be able to subscribe in time. + /// That's why we don't want this method to be exposed as `public`, + /// but it's useful internally. + internal func startAndRetrieveSignal() -> Signal { + var result: Signal! + self.startWithSignal { signal, _ in + result = signal + } + + return result + } + + /// Create a `Signal` from `self` in the manner described by `startWithSignal`, and + /// put the interrupt handle into the given `CompositeDisposable`. + /// + /// - parameters: + /// - lifetime: The `Lifetime` the interrupt handle to be added to. + /// - setup: A closure that accepts the produced `Signal`. + fileprivate func startWithSignal(during lifetime: Lifetime, setup: (Signal) -> Void) { + startWithSignal { signal, interruptHandle in + lifetime += interruptHandle + setup(signal) + } + } +} + +extension SignalProducer where Error == Never { + /// Create a `Signal` from `self`, and observe the `Signal` for all values being + /// emitted. + /// + /// - parameters: + /// - action: A closure to be invoked with values from the produced `Signal`. + /// + /// - returns: A disposable to interrupt the produced `Signal`. + @discardableResult + public func startWithValues(_ action: @escaping (Value) -> Void) -> Disposable { + return start(Signal.Observer(value: action)) + } +} + +extension SignalProducer { + /// Lift an unary Signal operator to operate upon SignalProducers instead. + /// + /// In other words, this will create a new `SignalProducer` which will apply + /// the given `Signal` operator to _every_ created `Signal`, just as if the + /// operator had been applied to each `Signal` yielded from `start()`. + /// + /// - parameters: + /// - transform: An unary operator to lift. + /// + /// - returns: A signal producer that applies signal's operator to every + /// created signal. + public func lift(_ transform: @escaping (Signal) -> Signal) -> SignalProducer { + return SignalProducer { observer, lifetime in + self.startWithSignal { signal, interrupter in + lifetime += interrupter + transform(signal).observe(observer) + } + } + } + + /// Lift a binary Signal operator to operate upon SignalProducers. + /// + /// The left producer would first be started. When both producers are synchronous this + /// order can be important depending on the operator to generate correct results. + /// + /// - returns: A factory that creates a SignalProducer with the given operator + /// applied. `self` would be the LHS, and the factory input would + /// be the RHS. + fileprivate func liftLeft(_ transform: @escaping (Signal) -> (Signal) -> Signal) -> (SignalProducer) -> SignalProducer { + return { right in + return SignalProducer { observer, lifetime in + right.startWithSignal { rightSignal, rightInterrupter in + lifetime += rightInterrupter + + self.startWithSignal { leftSignal, leftInterrupter in + lifetime += leftInterrupter + transform(leftSignal)(rightSignal).observe(observer) + } + } + } + } + } + + /// Lift a binary Signal operator to operate upon SignalProducers. + /// + /// The right producer would first be started. When both producers are synchronous + /// this order can be important depending on the operator to generate correct results. + /// + /// - returns: A factory that creates a SignalProducer with the given operator + /// applied. `self` would be the LHS, and the factory input would + /// be the RHS. + fileprivate func liftRight(_ transform: @escaping (Signal) -> (Signal) -> Signal) -> (SignalProducer) -> SignalProducer { + return { right in + return SignalProducer { observer, lifetime in + self.startWithSignal { leftSignal, leftInterrupter in + lifetime += leftInterrupter + + right.startWithSignal { rightSignal, rightInterrupter in + lifetime += rightInterrupter + transform(leftSignal)(rightSignal).observe(observer) + } + } + } + } + } + + /// Lift a binary Signal operator to operate upon SignalProducers instead. + /// + /// In other words, this will create a new `SignalProducer` which will apply + /// the given `Signal` operator to _every_ `Signal` created from the two + /// producers, just as if the operator had been applied to each `Signal` + /// yielded from `start()`. + /// + /// - note: starting the returned producer will start the receiver of the + /// operator, which may not be adviseable for some operators. + /// + /// - parameters: + /// - transform: A binary operator to lift. + /// + /// - returns: A binary operator that operates on two signal producers. + public func lift(_ transform: @escaping (Signal) -> (Signal) -> Signal) -> (SignalProducer) -> SignalProducer { + return liftRight(transform) + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ setup: (Signal, Signal) -> Void) { + b.startWithSignal(during: lifetime) { b in + a.startWithSignal(during: lifetime) { setup($0, b) } + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ setup: (Signal, Signal, Signal) -> Void) { + c.startWithSignal(during: lifetime) { c in + flattenStart(lifetime, a, b) { setup($0, $1, c) } + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ setup: (Signal, Signal, Signal, Signal) -> Void) { + d.startWithSignal(during: lifetime) { d in + flattenStart(lifetime, a, b, c) { setup($0, $1, $2, d) } + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ setup: (Signal, Signal, Signal, Signal, Signal) -> Void) { + e.startWithSignal(during: lifetime) { e in + flattenStart(lifetime, a, b, c, d) { setup($0, $1, $2, $3, e) } + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ setup: (Signal, Signal, Signal, Signal, Signal, Signal) -> Void) { + f.startWithSignal(during: lifetime) { f in + flattenStart(lifetime, a, b, c, d, e) { setup($0, $1, $2, $3, $4, f) } + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ setup: (Signal, Signal, Signal, Signal, Signal, Signal, Signal) -> Void) { + g.startWithSignal(during: lifetime) { g in + flattenStart(lifetime, a, b, c, d, e, f) { setup($0, $1, $2, $3, $4, $5, g) } + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer, _ setup: (Signal, Signal, Signal, Signal, Signal, Signal, Signal, Signal) -> Void) { + h.startWithSignal(during: lifetime) { h in + flattenStart(lifetime, a, b, c, d, e, f, g) { setup($0, $1, $2, $3, $4, $5, $6, h) } + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer, _ i: SignalProducer, _ setup: (Signal, Signal, Signal, Signal, Signal, Signal, Signal, Signal, Signal) -> Void) { + i.startWithSignal(during: lifetime) { i in + flattenStart(lifetime, a, b, c, d, e, f, g, h) { setup($0, $1, $2, $3, $4, $5, $6, $7, i) } + } +} + +/// Start the producers in the argument order. +/// +/// - parameters: +/// - disposable: The `CompositeDisposable` to collect the interrupt handles of all +/// produced `Signal`s. +/// - setup: The closure to accept all produced `Signal`s at once. +private func flattenStart(_ lifetime: Lifetime, _ a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer, _ i: SignalProducer, _ j: SignalProducer, _ setup: (Signal, Signal, Signal, Signal, Signal, Signal, Signal, Signal, Signal, Signal) -> Void) { + j.startWithSignal(during: lifetime) { j in + flattenStart(lifetime, a, b, c, d, e, f, g, h, i) { setup($0, $1, $2, $3, $4, $5, $6, $7, $8, j) } + } +} + +extension SignalProducer { + /// Map each value in the producer to a new value. + /// + /// - parameters: + /// - transform: A closure that accepts a value and returns a different + /// value. + /// + /// - returns: A signal producer that, when started, will send a mapped + /// value of `self.` + public func map(_ transform: @escaping (Value) -> U) -> SignalProducer { + return core.flatMapEvent(Signal.Event.map(transform)) + } + + /// Map each value in the producer to a new constant value. + /// + /// - parameters: + /// - value: A new value. + /// + /// - returns: A signal producer that, when started, will send a mapped + /// value of `self`. + public func map(value: U) -> SignalProducer { + return lift { $0.map(value: value) } + } + + /// Map each value in the producer to a new value by applying a key path. + /// + /// - parameters: + /// - keyPath: A key path relative to the producer's `Value` type. + /// + /// - returns: A producer that will send new values. + public func map(_ keyPath: KeyPath) -> SignalProducer { + return core.flatMapEvent(Signal.Event.filterMap { $0[keyPath: keyPath] }) + } + + /// Map errors in the producer to a new error. + /// + /// - parameters: + /// - transform: A closure that accepts an error object and returns a + /// different error. + /// + /// - returns: A producer that emits errors of new type. + public func mapError(_ transform: @escaping (Error) -> F) -> SignalProducer { + return core.flatMapEvent(Signal.Event.mapError(transform)) + } + + /// Maps each value in the producer to a new value, lazily evaluating the + /// supplied transformation on the specified scheduler. + /// + /// - important: Unlike `map`, there is not a 1-1 mapping between incoming + /// values, and values sent on the returned producer. If + /// `scheduler` has not yet scheduled `transform` for + /// execution, then each new value will replace the last one as + /// the parameter to `transform` once it is finally executed. + /// + /// - parameters: + /// - transform: The closure used to obtain the returned value from this + /// producer's underlying value. + /// + /// - returns: A producer that, when started, sends values obtained using + /// `transform` as this producer sends values. + public func lazyMap(on scheduler: Scheduler, transform: @escaping (Value) -> U) -> SignalProducer { + return core.flatMapEvent(Signal.Event.lazyMap(on: scheduler, transform: transform)) + } + + /// Preserve only values which pass the given closure. + /// + /// - parameters: + /// - isIncluded: A closure to determine whether a value from `self` should be + /// included in the produced `Signal`. + /// + /// - returns: A producer that, when started, forwards the values passing the given + /// closure. + public func filter(_ isIncluded: @escaping (Value) -> Bool) -> SignalProducer { + return core.flatMapEvent(Signal.Event.filter(isIncluded)) + } + + /// Applies `transform` to values from the producer and forwards values with non `nil` results unwrapped. + /// - parameters: + /// - transform: A closure that accepts a value from the `value` event and + /// returns a new optional value. + /// + /// - returns: A producer that will send new values, that are non `nil` after the transformation. + public func filterMap(_ transform: @escaping (Value) -> U?) -> SignalProducer { + return core.flatMapEvent(Signal.Event.filterMap(transform)) + } + + /// Yield the first `count` values from the input producer. + /// + /// - precondition: `count` must be non-negative number. + /// + /// - parameters: + /// - count: A number of values to take from the signal. + /// + /// - returns: A producer that, when started, will yield the first `count` + /// values from `self`. + public func take(first count: Int) -> SignalProducer { + guard count >= 1 else { return .interrupted } + return core.flatMapEvent(Signal.Event.take(first: count)) + } + + /// Yield an array of values when `self` completes. + /// + /// - note: When `self` completes without collecting any value, it will send + /// an empty array of values. + /// + /// - returns: A producer that, when started, will yield an array of values + /// when `self` completes. + public func collect() -> SignalProducer<[Value], Error> { + return core.flatMapEvent(Signal.Event.collect) + } + + /// Yield an array of values until it reaches a certain count. + /// + /// - precondition: `count` must be greater than zero. + /// + /// - note: When the count is reached the array is sent and the signal + /// starts over yielding a new array of values. + /// + /// - note: When `self` completes any remaining values will be sent, the + /// last array may not have `count` values. Alternatively, if were + /// not collected any values will sent an empty array of values. + /// + /// - returns: A producer that, when started, collects at most `count` + /// values from `self`, forwards them as a single array and + /// completes. + public func collect(count: Int) -> SignalProducer<[Value], Error> { + return core.flatMapEvent(Signal.Event.collect(count: count)) + } + + /// Collect values from `self`, and emit them if the predicate passes. + /// + /// When `self` completes any remaining values will be sent, regardless of the + /// collected values matching `shouldEmit` or not. + /// + /// If `self` completes without having emitted any value, an empty array would be + /// emitted, followed by the completion of the produced `Signal`. + /// + /// ```` + /// let (producer, observer) = SignalProducer.buffer(1) + /// + /// producer + /// .collect { values in values.reduce(0, combine: +) == 8 } + /// .startWithValues { print($0) } + /// + /// observer.send(value: 1) + /// observer.send(value: 3) + /// observer.send(value: 4) + /// observer.send(value: 7) + /// observer.send(value: 1) + /// observer.send(value: 5) + /// observer.send(value: 6) + /// observer.sendCompleted() + /// + /// // Output: + /// // [1, 3, 4] + /// // [7, 1] + /// // [5, 6] + /// ```` + /// + /// - parameters: + /// - shouldEmit: A closure to determine, when every time a new value is received, + /// whether the collected values should be emitted. + /// + /// - returns: A producer of arrays of values, as instructed by the `shouldEmit` + /// closure. + public func collect(_ shouldEmit: @escaping (_ values: [Value]) -> Bool) -> SignalProducer<[Value], Error> { + return core.flatMapEvent(Signal.Event.collect(shouldEmit)) + } + + /// Collect values from `self`, and emit them if the predicate passes. + /// + /// When `self` completes any remaining values will be sent, regardless of the + /// collected values matching `shouldEmit` or not. + /// + /// If `self` completes without having emitted any value, an empty array would be + /// emitted, followed by the completion of the produced `Signal`. + /// + /// ```` + /// let (producer, observer) = SignalProducer.buffer(1) + /// + /// producer + /// .collect { values, value in value == 7 } + /// .startWithValues { print($0) } + /// + /// observer.send(value: 1) + /// observer.send(value: 1) + /// observer.send(value: 7) + /// observer.send(value: 7) + /// observer.send(value: 5) + /// observer.send(value: 6) + /// observer.sendCompleted() + /// + /// // Output: + /// // [1, 1] + /// // [7] + /// // [7, 5, 6] + /// ```` + /// + /// - parameters: + /// - shouldEmit: A closure to determine, when every time a new value is received, + /// whether the collected values should be emitted. The new value + /// is **not** included in the collected values, and is included when + /// the next value is received. + /// + /// - returns: A producer of arrays of values, as instructed by the `shouldEmit` + /// closure. + public func collect(_ shouldEmit: @escaping (_ collected: [Value], _ latest: Value) -> Bool) -> SignalProducer<[Value], Error> { + return core.flatMapEvent(Signal.Event.collect(shouldEmit)) + } + + /// Forward the latest values on `scheduler` every `interval`. + /// + /// - note: If `self` terminates while values are being accumulated, + /// the behaviour will be determined by `discardWhenCompleted`. + /// If `true`, the values will be discarded and the returned producer + /// will terminate immediately. + /// If `false`, that values will be delivered at the next interval. + /// + /// - parameters: + /// - interval: A repetition interval. + /// - scheduler: A scheduler to send values on. + /// - skipEmpty: Whether empty arrays should be sent if no values were + /// accumulated during the interval. + /// - discardWhenCompleted: A boolean to indicate if the latest unsent + /// values should be discarded on completion. + /// + /// - returns: A producer that sends all values that are sent from `self` + /// at `interval` seconds apart. + public func collect(every interval: DispatchTimeInterval, on scheduler: DateScheduler, skipEmpty: Bool = false, discardWhenCompleted: Bool = true) -> SignalProducer<[Value], Error> { + return core.flatMapEvent(Signal.Event.collect(every: interval, on: scheduler, skipEmpty: skipEmpty, discardWhenCompleted: discardWhenCompleted)) + } + + /// Forward all events onto the given scheduler, instead of whichever + /// scheduler they originally arrived upon. + /// + /// - parameters: + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A producer that, when started, will yield `self` values on + /// provided scheduler. + public func observe(on scheduler: Scheduler) -> SignalProducer { + return core.flatMapEvent(Signal.Event.observe(on: scheduler)) + } + + /// Combine the latest value of the receiver with the latest value from the + /// given producer. + /// + /// - note: The returned producer will not send a value until both inputs + /// have sent at least one value each. + /// + /// - note: If either producer is interrupted, the returned producer will + /// also be interrupted. + /// + /// - note: The returned producer will not complete until both inputs + /// complete. + /// + /// - parameters: + /// - other: A producer to combine `self`'s value with. + /// + /// - returns: A producer that, when started, will yield a tuple containing + /// values of `self` and given producer. + public func combineLatest(with other: SignalProducer) -> SignalProducer<(Value, U), Error> { + return SignalProducer.combineLatest(self, other) + } + + /// Combine the latest value of the receiver with the latest value from the + /// given producer. + /// + /// - note: The returned producer will not send a value until both inputs + /// have sent at least one value each. + /// + /// - note: If either producer is interrupted, the returned producer will + /// also be interrupted. + /// + /// - note: The returned producer will not complete until both inputs + /// complete. + /// + /// - parameters: + /// - other: A producer to combine `self`'s value with. + /// + /// - returns: A producer that, when started, will yield a tuple containing + /// values of `self` and given producer. + public func combineLatest(with other: Other) -> SignalProducer<(Value, Other.Value), Error> where Other.Error == Error { + return combineLatest(with: other.producer) + } + + /// Merge the given producer into a single `SignalProducer` that will emit all + /// values from both of them, and complete when all of them have completed. + /// + /// - parameters: + /// - other: A producer to merge `self`'s value with. + /// + /// - returns: A producer that sends all values of `self` and given producer. + public func merge(with other: SignalProducer) -> SignalProducer { + return SignalProducer.merge(self, other) + } + + /// Merge the given producer into a single `SignalProducer` that will emit all + /// values from both of them, and complete when all of them have completed. + /// + /// - parameters: + /// - other: A producer to merge `self`'s value with. + /// + /// - returns: A producer that sends all values of `self` and given producer. + public func merge(with other: Other) -> SignalProducer where Other.Value == Value, Other.Error == Error { + return merge(with: other.producer) + } + + /// Delay `value` and `completed` events by the given interval, forwarding + /// them on the given scheduler. + /// + /// - note: `failed` and `interrupted` events are always scheduled + /// immediately. + /// + /// - parameters: + /// - interval: Interval to delay `value` and `completed` events by. + /// - scheduler: A scheduler to deliver delayed events on. + /// + /// - returns: A producer that, when started, will delay `value` and + /// `completed` events and will yield them on given scheduler. + public func delay(_ interval: TimeInterval, on scheduler: DateScheduler) -> SignalProducer { + return core.flatMapEvent(Signal.Event.delay(interval, on: scheduler)) + } + + /// Skip the first `count` values, then forward everything afterward. + /// + /// - parameters: + /// - count: A number of values to skip. + /// + /// - returns: A producer that, when started, will skip the first `count` + /// values, then forward everything afterward. + public func skip(first count: Int) -> SignalProducer { + guard count != 0 else { return self } + return core.flatMapEvent(Signal.Event.skip(first: count)) + } + + /// Treats all Events from the input producer as plain values, allowing them + /// to be manipulated just like any other value. + /// + /// In other words, this brings Events “into the monad.” + /// + /// - note: When a Completed or Failed event is received, the resulting + /// producer will send the Event itself and then complete. When an + /// `interrupted` event is received, the resulting producer will + /// send the `Event` itself and then interrupt. + /// + /// - returns: A producer that sends events as its values. + public func materialize() -> SignalProducer { + return core.flatMapEvent(Signal.Event.materialize) + } + + /// Treats all Results from the input producer as plain values, allowing them + /// to be manipulated just like any other value. + /// + /// In other words, this brings Results “into the monad.” + /// + /// - note: When a Failed event is received, the resulting producer will + /// send the `Result.failure` itself and then complete. + /// + /// - returns: A producer that sends results as its values. + public func materializeResults() -> SignalProducer, Never> { + return core.flatMapEvent(Signal.Event.materializeResults) + } + + /// Forward the latest value from `self` with the value from `sampler` as a + /// tuple, only when `sampler` sends a `value` event. + /// + /// - note: If `sampler` fires before a value has been observed on `self`, + /// nothing happens. + /// + /// - parameters: + /// - sampler: A producer that will trigger the delivery of `value` event + /// from `self`. + /// + /// - returns: A producer that will send values from `self` and `sampler`, + /// sampled (possibly multiple times) by `sampler`, then complete + /// once both input producers have completed, or interrupt if + /// either input producer is interrupted. + public func sample(with sampler: SignalProducer) -> SignalProducer<(Value, U), Error> { + return liftLeft(Signal.sample(with:))(sampler) + } + + /// Forward the latest value from `self` with the value from `sampler` as a + /// tuple, only when `sampler` sends a `value` event. + /// + /// - note: If `sampler` fires before a value has been observed on `self`, + /// nothing happens. + /// + /// - parameters: + /// - sampler: A producer that will trigger the delivery of `value` event + /// from `self`. + /// + /// - returns: A producer that will send values from `self` and `sampler`, + /// sampled (possibly multiple times) by `sampler`, then complete + /// once both input producers have completed, or interrupt if + /// either input producer is interrupted. + public func sample(with sampler: Sampler) -> SignalProducer<(Value, Sampler.Value), Error> where Sampler.Error == Never { + return sample(with: sampler.producer) + } + + /// Forward the latest value from `self` whenever `sampler` sends a `value` + /// event. + /// + /// - note: If `sampler` fires before a value has been observed on `self`, + /// nothing happens. + /// + /// - parameters: + /// - sampler: A producer that will trigger the delivery of `value` event + /// from `self`. + /// + /// - returns: A producer that, when started, will send values from `self`, + /// sampled (possibly multiple times) by `sampler`, then complete + /// once both input producers have completed, or interrupt if + /// either input producer is interrupted. + public func sample(on sampler: SignalProducer<(), Never>) -> SignalProducer { + return liftLeft(Signal.sample(on:))(sampler) + } + + /// Forward the latest value from `self` whenever `sampler` sends a `value` + /// event. + /// + /// - note: If `sampler` fires before a value has been observed on `self`, + /// nothing happens. + /// + /// - parameters: + /// - sampler: A producer that will trigger the delivery of `value` event + /// from `self`. + /// + /// - returns: A producer that, when started, will send values from `self`, + /// sampled (possibly multiple times) by `sampler`, then complete + /// once both input producers have completed, or interrupt if + /// either input producer is interrupted. + public func sample(on sampler: Sampler) -> SignalProducer where Sampler.Value == (), Sampler.Error == Never { + return sample(on: sampler.producer) + } + + /// Forward the latest value from `samplee` with the value from `self` as a + /// tuple, only when `self` sends a `value` event. + /// This is like a flipped version of `sample(with:)`, but `samplee`'s + /// terminal events are completely ignored. + /// + /// - note: If `self` fires before a value has been observed on `samplee`, + /// nothing happens. + /// + /// - parameters: + /// - samplee: A producer whose latest value is sampled by `self`. + /// + /// - returns: A producer that will send values from `self` and `samplee`, + /// sampled (possibly multiple times) by `self`, then terminate + /// once `self` has terminated. **`samplee`'s terminated events + /// are ignored**. + public func withLatest(from samplee: SignalProducer) -> SignalProducer<(Value, U), Error> { + return liftRight(Signal.withLatest)(samplee.producer) + } + + /// Forward the latest value from `samplee` with the value from `self` as a + /// tuple, only when `self` sends a `value` event. + /// This is like a flipped version of `sample(with:)`, but `samplee`'s + /// terminal events are completely ignored. + /// + /// - note: If `self` fires before a value has been observed on `samplee`, + /// nothing happens. + /// + /// - parameters: + /// - samplee: A producer whose latest value is sampled by `self`. + /// + /// - returns: A producer that will send values from `self` and `samplee`, + /// sampled (possibly multiple times) by `self`, then terminate + /// once `self` has terminated. **`samplee`'s terminated events + /// are ignored**. + public func withLatest(from samplee: Samplee) -> SignalProducer<(Value, Samplee.Value), Error> where Samplee.Error == Never { + return withLatest(from: samplee.producer) + } + + /// Forwards events from `self` until `lifetime` ends, at which point the + /// returned producer will complete. + /// + /// - parameters: + /// - lifetime: A lifetime whose `ended` signal will cause the returned + /// producer to complete. + /// + /// - returns: A producer that will deliver events until `lifetime` ends. + public func take(during lifetime: Lifetime) -> SignalProducer { + return lift { $0.take(during: lifetime) } + } + + /// Forward events from `self` until `trigger` sends a `value` or `completed` + /// event, at which point the returned producer will complete. + /// + /// - parameters: + /// - trigger: A producer whose `value` or `completed` events will stop the + /// delivery of `value` events from `self`. + /// + /// - returns: A producer that will deliver events until `trigger` sends + /// `value` or `completed` events. + public func take(until trigger: SignalProducer<(), Never>) -> SignalProducer { + return liftRight(Signal.take(until:))(trigger) + } + + /// Forward events from `self` until `trigger` sends a `value` or `completed` + /// event, at which point the returned producer will complete. + /// + /// - parameters: + /// - trigger: A producer whose `value` or `completed` events will stop the + /// delivery of `value` events from `self`. + /// + /// - returns: A producer that will deliver events until `trigger` sends + /// `value` or `completed` events. + public func take(until trigger: Trigger) -> SignalProducer where Trigger.Value == (), Trigger.Error == Never { + return take(until: trigger.producer) + } + + /// Do not forward any values from `self` until `trigger` sends a `value` + /// or `completed`, at which point the returned producer behaves exactly + /// like `producer`. + /// + /// - parameters: + /// - trigger: A producer whose `value` or `completed` events will start + /// the deliver of events on `self`. + /// + /// - returns: A producer that will deliver events once the `trigger` sends + /// `value` or `completed` events. + public func skip(until trigger: SignalProducer<(), Never>) -> SignalProducer { + return liftRight(Signal.skip(until:))(trigger) + } + + /// Do not forward any values from `self` until `trigger` sends a `value` + /// or `completed`, at which point the returned producer behaves exactly + /// like `producer`. + /// + /// - parameters: + /// - trigger: A producer whose `value` or `completed` events will start + /// the deliver of events on `self`. + /// + /// - returns: A producer that will deliver events once the `trigger` sends + /// `value` or `completed` events. + public func skip(until trigger: Trigger) -> SignalProducer where Trigger.Value == (), Trigger.Error == Never { + return skip(until: trigger.producer) + } + + /// Forward events from `self` with history: values of the returned producer + /// are a tuples whose first member is the previous value and whose second member + /// is the current value. `initial` is supplied as the first member when `self` + /// sends its first value. + /// + /// - parameters: + /// - initial: A value that will be combined with the first value sent by + /// `self`. + /// + /// - returns: A producer that sends tuples that contain previous and current + /// sent values of `self`. + public func combinePrevious(_ initial: Value) -> SignalProducer<(Value, Value), Error> { + return core.flatMapEvent(Signal.Event.combinePrevious(initial: initial)) + } + + /// Forward events from `self` with history: values of the produced signal + /// are a tuples whose first member is the previous value and whose second member + /// is the current value. + /// + /// The produced `Signal` would not emit any tuple until it has received at least two + /// values. + /// + /// - returns: A producer that sends tuples that contain previous and current + /// sent values of `self`. + public func combinePrevious() -> SignalProducer<(Value, Value), Error> { + return core.flatMapEvent(Signal.Event.combinePrevious(initial: nil)) + } + + /// Combine all values from `self`, and forward the final result. + /// + /// See `scan(_:_:)` if the resulting producer needs to forward also the partial + /// results. + /// + /// - parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - nextPartialResult: A closure that combines the accumulating value and the + /// latest value from `self`. The result would be used in the + /// next call of `nextPartialResult`, or emit to the returned + /// `Signal` when `self` completes. + /// + /// - returns: A producer that sends the final result as `self` completes. + public func reduce(_ initialResult: U, _ nextPartialResult: @escaping (U, Value) -> U) -> SignalProducer { + return core.flatMapEvent(Signal.Event.reduce(initialResult, nextPartialResult)) + } + + /// Combine all values from `self`, and forward the final result. + /// + /// See `scan(into:_:)` if the resulting producer needs to forward also the partial + /// results. + /// + /// - parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - nextPartialResult: A closure that combines the accumulating value and the + /// latest value from `self`. The result would be used in the + /// next call of `nextPartialResult`, or emit to the returned + /// `Signal` when `self` completes. + /// + /// - returns: A producer that sends the final value as `self` completes. + public func reduce(into initialResult: U, _ nextPartialResult: @escaping (inout U, Value) -> Void) -> SignalProducer { + return core.flatMapEvent(Signal.Event.reduce(into: initialResult, nextPartialResult)) + } + + /// Combine all values from `self`, and forward the partial results and the final + /// result. + /// + /// See `reduce(_:_:)` if the resulting producer needs to forward only the final + /// result. + /// + /// - parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - nextPartialResult: A closure that combines the accumulating value and the + /// latest value from `self`. The result would be forwarded, + /// and would be used in the next call of `nextPartialResult`. + /// + /// - returns: A producer that sends the partial results of the accumuation, and the + /// final result as `self` completes. + public func scan(_ initialResult: U, _ nextPartialResult: @escaping (U, Value) -> U) -> SignalProducer { + return core.flatMapEvent(Signal.Event.scan(initialResult, nextPartialResult)) + } + + /// Combine all values from `self`, and forward the partial results and the final + /// result. + /// + /// See `reduce(into:_:)` if the resulting producer needs to forward only the final + /// result. + /// + /// - parameters: + /// - initialResult: The value to use as the initial accumulating value. + /// - nextPartialResult: A closure that combines the accumulating value and the + /// latest value from `self`. The result would be forwarded, + /// and would be used in the next call of `nextPartialResult`. + /// + /// - returns: A producer that sends the partial results of the accumuation, and the + /// final result as `self` completes. + public func scan(into initialResult: U, _ nextPartialResult: @escaping (inout U, Value) -> Void) -> SignalProducer { + return core.flatMapEvent(Signal.Event.scan(into: initialResult, nextPartialResult)) + } + + /// Forward only values from `self` that are not considered equivalent to its + /// immediately preceding value. + /// + /// - note: The first value is always forwarded. + /// + /// - parameters: + /// - isEquivalent: A closure to determine whether two values are equivalent. + /// + /// - returns: A producer which conditionally forwards values from `self` + public func skipRepeats(_ isEquivalent: @escaping (Value, Value) -> Bool) -> SignalProducer { + return core.flatMapEvent(Signal.Event.skipRepeats(isEquivalent)) + } + + /// Do not forward any value from `self` until `shouldContinue` returns `false`, at + /// which point the returned signal starts to forward values from `self`, including + /// the one leading to the toggling. + /// + /// - parameters: + /// - shouldContinue: A closure to determine whether the skipping should continue. + /// + /// - returns: A producer which conditionally forwards values from `self`. + public func skip(while shouldContinue: @escaping (Value) -> Bool) -> SignalProducer { + return core.flatMapEvent(Signal.Event.skip(while: shouldContinue)) + } + + /// Forwards events from `self` until `replacement` begins sending events. + /// + /// - parameters: + /// - replacement: A producer to wait to wait for values from and start + /// sending them as a replacement to `self`'s values. + /// + /// - returns: A producer which passes through `value`, `failed`, and + /// `interrupted` events from `self` until `replacement` sends an + /// event, at which point the returned producer will send that + /// event and switch to passing through events from `replacement` + /// instead, regardless of whether `self` has sent events + /// already. + public func take(untilReplacement replacement: SignalProducer) -> SignalProducer { + return liftRight(Signal.take(untilReplacement:))(replacement) + } + + /// Forwards events from `self` until `replacement` begins sending events. + /// + /// - parameters: + /// - replacement: A producer to wait to wait for values from and start + /// sending them as a replacement to `self`'s values. + /// + /// - returns: A producer which passes through `value`, `failed`, and + /// `interrupted` events from `self` until `replacement` sends an + /// event, at which point the returned producer will send that + /// event and switch to passing through events from `replacement` + /// instead, regardless of whether `self` has sent events + /// already. + public func take(untilReplacement replacement: Replacement) -> SignalProducer where Replacement.Value == Value, Replacement.Error == Error { + return take(untilReplacement: replacement.producer) + } + + /// Wait until `self` completes and then forward the final `count` values + /// on the returned producer. + /// + /// - parameters: + /// - count: Number of last events to send after `self` completes. + /// + /// - returns: A producer that receives up to `count` values from `self` + /// after `self` completes. + public func take(last count: Int) -> SignalProducer { + return core.flatMapEvent(Signal.Event.take(last: count)) + } + + /// Forward any values from `self` until `shouldContinue` returns `false`, at which + /// point the produced `Signal` would complete. + /// + /// - parameters: + /// - shouldContinue: A closure to determine whether the forwarding of values should + /// continue. + /// + /// - returns: A producer which conditionally forwards values from `self`. + public func take(while shouldContinue: @escaping (Value) -> Bool) -> SignalProducer { + return core.flatMapEvent(Signal.Event.take(while: shouldContinue)) + } + + /// Zip elements of two producers into pairs. The elements of any Nth pair + /// are the Nth elements of the two input producers. + /// + /// - parameters: + /// - other: A producer to zip values with. + /// + /// - returns: A producer that sends tuples of `self` and `otherProducer`. + public func zip(with other: SignalProducer) -> SignalProducer<(Value, U), Error> { + return SignalProducer.zip(self, other) + } + + /// Zip elements of two producers into pairs. The elements of any Nth pair + /// are the Nth elements of the two input producers. + /// + /// - parameters: + /// - other: A producer to zip values with. + /// + /// - returns: A producer that sends tuples of `self` and `otherProducer`. + public func zip(with other: Other) -> SignalProducer<(Value, Other.Value), Error> where Other.Error == Error { + return zip(with: other.producer) + } + + /// Apply an action to every value from `self`, and forward the value if the action + /// succeeds. If the action fails with an error, the produced `Signal` would propagate + /// the failure and terminate. + /// + /// - parameters: + /// - action: An action which yields a `Result`. + /// + /// - returns: A producer which forwards the values from `self` until the given action + /// fails. + public func attempt(_ action: @escaping (Value) -> Result<(), Error>) -> SignalProducer { + return core.flatMapEvent(Signal.Event.attempt(action)) + } + + /// Apply a transform to every value from `self`, and forward the transformed value + /// if the action succeeds. If the action fails with an error, the produced `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - action: A transform which yields a `Result` of the transformed value or the + /// error. + /// + /// - returns: A producer which forwards the transformed values. + public func attemptMap(_ action: @escaping (Value) -> Result) -> SignalProducer { + return core.flatMapEvent(Signal.Event.attemptMap(action)) + } + + /// Forward the latest value on `scheduler` after at least `interval` + /// seconds have passed since *the returned signal* last sent a value. + /// + /// If `self` always sends values more frequently than `interval` seconds, + /// then the returned signal will send a value every `interval` seconds. + /// + /// To measure from when `self` last sent a value, see `debounce`. + /// + /// - seealso: `debounce` + /// + /// - note: If multiple values are received before the interval has elapsed, + /// the latest value is the one that will be passed on. + /// + /// - note: If `self` terminates while a value is being throttled, that + /// value will be discarded and the returned producer will terminate + /// immediately. + /// + /// - note: If the device time changed backwards before previous date while + /// a value is being throttled, and if there is a new value sent, + /// the new value will be passed anyway. + /// + /// - parameters: + /// - interval: Number of seconds to wait between sent values. + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A producer that sends values at least `interval` seconds + /// appart on a given scheduler. + public func throttle(_ interval: TimeInterval, on scheduler: DateScheduler) -> SignalProducer { + return core.flatMapEvent(Signal.Event.throttle(interval, on: scheduler)) + } + + /// Conditionally throttles values sent on the receiver whenever + /// `shouldThrottle` is true, forwarding values on the given scheduler. + /// + /// - note: While `shouldThrottle` remains false, values are forwarded on the + /// given scheduler. If multiple values are received while + /// `shouldThrottle` is true, the latest value is the one that will + /// be passed on. + /// + /// - note: If the input signal terminates while a value is being throttled, + /// that value will be discarded and the returned signal will + /// terminate immediately. + /// + /// - note: If `shouldThrottle` completes before the receiver, and its last + /// value is `true`, the returned signal will remain in the throttled + /// state, emitting no further values until it terminates. + /// + /// - parameters: + /// - shouldThrottle: A boolean property that controls whether values + /// should be throttled. + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A producer that sends values only while `shouldThrottle` is false. + public func throttle(while shouldThrottle: P, on scheduler: Scheduler) -> SignalProducer + where P.Value == Bool + { + // Using `Property.init(_:)` avoids capturing a strong reference + // to `shouldThrottle`, so that we don't extend its lifetime. + let shouldThrottle = Property(shouldThrottle) + + return lift { $0.throttle(while: shouldThrottle, on: scheduler) } + } + + /// Forward the latest value on `scheduler` after at least `interval` + /// seconds have passed since `self` last sent a value. + /// + /// If `self` always sends values more frequently than `interval` seconds, + /// then the returned signal will never send any values. + /// + /// To measure from when the *returned signal* last sent a value, see + /// `throttle`. + /// + /// - seealso: `throttle` + /// + /// - note: If multiple values are received before the interval has elapsed, + /// the latest value is the one that will be passed on. + /// + /// - note: If `self` terminates while a value is being debounced, + /// the behaviour will be determined by `discardWhenCompleted`. + /// If `true`, that value will be discarded and the returned producer + /// will terminate immediately. + /// If `false`, that value will be delivered at the next debounce + /// interval. + /// + /// - parameters: + /// - interval: A number of seconds to wait before sending a value. + /// - scheduler: A scheduler to send values on. + /// - discardWhenCompleted: A boolean to indicate if the latest value + /// should be discarded on completion. + /// + /// - returns: A producer that sends values that are sent from `self` at + /// least `interval` seconds apart. + public func debounce(_ interval: TimeInterval, on scheduler: DateScheduler, discardWhenCompleted: Bool = true) -> SignalProducer { + return core.flatMapEvent(Signal.Event.debounce(interval, on: scheduler, discardWhenCompleted: discardWhenCompleted)) + } + + /// Forward events from `self` until `interval`. Then if producer isn't + /// completed yet, fails with `error` on `scheduler`. + /// + /// - note: If the interval is 0, the timeout will be scheduled immediately. + /// The producer must complete synchronously (or on a faster + /// scheduler) to avoid the timeout. + /// + /// - parameters: + /// - interval: Number of seconds to wait for `self` to complete. + /// - error: Error to send with `failed` event if `self` is not completed + /// when `interval` passes. + /// - scheduler: A scheduler to deliver error on. + /// + /// - returns: A producer that sends events for at most `interval` seconds, + /// then, if not `completed` - sends `error` with `failed` event + /// on `scheduler`. + public func timeout(after interval: TimeInterval, raising error: Error, on scheduler: DateScheduler) -> SignalProducer { + return lift { $0.timeout(after: interval, raising: error, on: scheduler) } + } +} + +extension SignalProducer where Value: OptionalProtocol { + /// Unwraps non-`nil` values and forwards them on the returned signal, `nil` + /// values are dropped. + /// + /// - returns: A producer that sends only non-nil values. + public func skipNil() -> SignalProducer { + return core.flatMapEvent(Signal.Event.skipNil) + } +} + +extension SignalProducer where Value: EventProtocol, Error == Never { + /// The inverse of materialize(), this will translate a producer of `Event` + /// _values_ into a producer of those events themselves. + /// + /// - returns: A producer that sends values carried by `self` events. + public func dematerialize() -> SignalProducer { + return core.flatMapEvent(Signal.Event.dematerialize) + } +} + +extension SignalProducer where Error == Never { + /// The inverse of materializeResults(), this will translate a producer of `Result` + /// _values_ into a producer of those events themselves. + /// + /// - returns: A producer that sends values carried by `self` results. + public func dematerializeResults() -> SignalProducer where Value == Result { + return core.flatMapEvent(Signal.Event.dematerializeResults) + } +} + +extension SignalProducer where Error == Never { + /// Promote a producer that does not generate failures into one that can. + /// + /// - note: This does not actually cause failers to be generated for the + /// given producer, but makes it easier to combine with other + /// producers that may fail; for example, with operators like + /// `combineLatestWith`, `zipWith`, `flatten`, etc. + /// + /// - parameters: + /// - _ An `ErrorType`. + /// + /// - returns: A producer that has an instantiatable `ErrorType`. + public func promoteError(_: F.Type = F.self) -> SignalProducer { + return core.flatMapEvent(Signal.Event.promoteError(F.self)) + } + + /// Promote a producer that does not generate failures into one that can. + /// + /// - note: This does not actually cause failers to be generated for the + /// given producer, but makes it easier to combine with other + /// producers that may fail; for example, with operators like + /// `combineLatestWith`, `zipWith`, `flatten`, etc. + /// + /// - parameters: + /// - _ An `ErrorType`. + /// + /// - returns: A producer that has an instantiatable `ErrorType`. + public func promoteError(_: Error.Type = Error.self) -> SignalProducer { + return self + } + + /// Forward events from `self` until `interval`. Then if producer isn't + /// completed yet, fails with `error` on `scheduler`. + /// + /// - note: If the interval is 0, the timeout will be scheduled immediately. + /// The producer must complete synchronously (or on a faster + /// scheduler) to avoid the timeout. + /// + /// - parameters: + /// - interval: Number of seconds to wait for `self` to complete. + /// - error: Error to send with `failed` event if `self` is not completed + /// when `interval` passes. + /// - scheudler: A scheduler to deliver error on. + /// + /// - returns: A producer that sends events for at most `interval` seconds, + /// then, if not `completed` - sends `error` with `failed` event + /// on `scheduler`. + public func timeout( + after interval: TimeInterval, + raising error: NewError, + on scheduler: DateScheduler + ) -> SignalProducer { + return lift { $0.timeout(after: interval, raising: error, on: scheduler) } + } + + /// Apply a throwable action to every value from `self`, and forward the values + /// if the action succeeds. If the action throws an error, the produced `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - action: A throwable closure to perform an arbitrary action on the value. + /// + /// - returns: A producer which forwards the successful values of the given action. + public func attempt(_ action: @escaping (Value) throws -> Void) -> SignalProducer { + return self + .promoteError(Swift.Error.self) + .attempt(action) + } + + /// Apply a throwable action to every value from `self`, and forward the results + /// if the action succeeds. If the action throws an error, the produced `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - action: A throwable closure to perform an arbitrary action on the value, and + /// yield a result. + /// + /// - returns: A producer which forwards the successful results of the given action. + public func attemptMap(_ action: @escaping (Value) throws -> U) -> SignalProducer { + return self + .promoteError(Swift.Error.self) + .attemptMap(action) + } +} + +extension SignalProducer where Error == Swift.Error { + /// Apply a throwable action to every value from `self`, and forward the values + /// if the action succeeds. If the action throws an error, the produced `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - action: A throwable closure to perform an arbitrary action on the value. + /// + /// - returns: A producer which forwards the successful values of the given action. + public func attempt(_ action: @escaping (Value) throws -> Void) -> SignalProducer { + return core.flatMapEvent(Signal.Event.attempt(action)) + } + + /// Apply a throwable transform to every value from `self`, and forward the results + /// if the action succeeds. If the transform throws an error, the produced `Signal` + /// would propagate the failure and terminate. + /// + /// - parameters: + /// - transform: A throwable transform. + /// + /// - returns: A producer which forwards the successfully transformed values. + public func attemptMap(_ transform: @escaping (Value) throws -> U) -> SignalProducer { + return core.flatMapEvent(Signal.Event.attemptMap(transform)) + } +} + +extension SignalProducer where Value == Never { + /// Promote a producer that does not generate values, as indicated by `Never`, + /// to be a producer of the given type of value. + /// + /// - note: The promotion does not result in any value being generated. + /// + /// - parameters: + /// - _ The type of value to promote to. + /// + /// - returns: A producer that forwards all terminal events from `self`. + public func promoteValue(_: U.Type = U.self) -> SignalProducer { + return core.flatMapEvent(Signal.Event.promoteValue(U.self)) + } + + /// Promote a producer that does not generate values, as indicated by `Never`, + /// to be a producer of the given type of value. + /// + /// - note: The promotion does not result in any value being generated. + /// + /// - parameters: + /// - _ The type of value to promote to. + /// + /// - returns: A producer that forwards all terminal events from `self`. + public func promoteValue(_: Value.Type = Value.self) -> SignalProducer { + return self + } +} + +extension SignalProducer where Value: Equatable { + /// Forward only values from `self` that are not equal to its immediately preceding + /// value. + /// + /// - note: The first value is always forwarded. + /// + /// - returns: A producer which conditionally forwards values from `self`. + public func skipRepeats() -> SignalProducer { + return core.flatMapEvent(Signal.Event.skipRepeats(==)) + } +} + +extension SignalProducer { + /// Forward only those values from `self` that have unique identities across + /// the set of all values that have been seen. + /// + /// - note: This causes the identities to be retained to check for + /// uniqueness. + /// + /// - parameters: + /// - transform: A closure that accepts a value and returns identity + /// value. + /// + /// - returns: A producer that sends unique values during its lifetime. + public func uniqueValues(_ transform: @escaping (Value) -> Identity) -> SignalProducer { + return core.flatMapEvent(Signal.Event.uniqueValues(transform)) + } +} + +extension SignalProducer where Value: Hashable { + /// Forward only those values from `self` that are unique across the set of + /// all values that have been seen. + /// + /// - note: This causes the values to be retained to check for uniqueness. + /// Providing a function that returns a unique value for each sent + /// value can help you reduce the memory footprint. + /// + /// - returns: A producer that sends unique values during its lifetime. + public func uniqueValues() -> SignalProducer { + return uniqueValues { $0 } + } +} + +extension SignalProducer { + /// Injects side effects to be performed upon the specified producer events. + /// + /// - note: In a composed producer, `starting` is invoked in the reverse + /// direction of the flow of events. + /// + /// - parameters: + /// - starting: A closure that is invoked before the producer is started. + /// - started: A closure that is invoked after the producer is started. + /// - event: A closure that accepts an event and is invoked on every + /// received event. + /// - failed: A closure that accepts error object and is invoked for + /// `failed` event. + /// - completed: A closure that is invoked for `completed` event. + /// - interrupted: A closure that is invoked for `interrupted` event. + /// - terminated: A closure that is invoked for any terminating event. + /// - disposed: A closure added as disposable when signal completes. + /// - value: A closure that accepts a value from `value` event. + /// + /// - returns: A producer with attached side-effects for given event cases. + public func on( + starting: (() -> Void)? = nil, + started: (() -> Void)? = nil, + event: ((ProducedSignal.Event) -> Void)? = nil, + failed: ((Error) -> Void)? = nil, + completed: (() -> Void)? = nil, + interrupted: (() -> Void)? = nil, + terminated: (() -> Void)? = nil, + disposed: (() -> Void)? = nil, + value: ((Value) -> Void)? = nil + ) -> SignalProducer { + return SignalProducer(SignalCore { + let instance = self.core.makeInstance() + let signal = instance.signal.on(event: event, + failed: failed, + completed: completed, + interrupted: interrupted, + terminated: terminated, + disposed: disposed, + value: value) + + return .init(signal: signal, + observerDidSetup: { starting?(); instance.observerDidSetup(); started?() }, + interruptHandle: instance.interruptHandle) + }) + } + + /// Start the returned producer on the given `Scheduler`. + /// + /// - note: This implies that any side effects embedded in the producer will + /// be performed on the given scheduler as well. + /// + /// - note: Events may still be sent upon other schedulers — this merely + /// affects where the `start()` method is run. + /// + /// - parameters: + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A producer that will deliver events on given `scheduler` when + /// started. + public func start(on scheduler: Scheduler) -> SignalProducer { + return SignalProducer { observer, lifetime in + lifetime += scheduler.schedule { + self.startWithSignal { signal, signalDisposable in + lifetime += signalDisposable + signal.observe(observer) + } + } + } + } +} + +extension SignalProducer { + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B) -> SignalProducer<(Value, B.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer) { Signal.combineLatest($0, $1).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C) -> SignalProducer<(Value, B.Value, C.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer) { Signal.combineLatest($0, $1, $2).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D) -> SignalProducer<(Value, B.Value, C.Value, D.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer) { Signal.combineLatest($0, $1, $2, $3).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer) { Signal.combineLatest($0, $1, $2, $3, $4).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer) { Signal.combineLatest($0, $1, $2, $3, $4, $5).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error, G.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer) { Signal.combineLatest($0, $1, $2, $3, $4, $5, $6).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error, G.Error == Error, H.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer) { Signal.combineLatest($0, $1, $2, $3, $4, $5, $6, $7).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value, I.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error, G.Error == Error, H.Error == Error, I.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer, i.producer) { Signal.combineLatest($0, $1, $2, $3, $4, $5, $6, $7, $8).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. + public static func combineLatest(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I, _ j: J) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value, I.Value, J.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error, G.Error == Error, H.Error == Error, I.Error == Error, J.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer, i.producer, j.producer) { Signal.combineLatest($0, $1, $2, $3, $4, $5, $6, $7, $8, $9).observe(observer) } + } + } + + /// Combines the values of all the given producers, in the manner described by + /// `combineLatest(with:)`. Will return an empty `SignalProducer` if the sequence is empty. + public static func combineLatest(_ producers: S) -> SignalProducer<[Value], Error> where S.Iterator.Element: SignalProducerConvertible, S.Iterator.Element.Value == Value, S.Iterator.Element.Error == Error { + return start(producers, Signal.combineLatest) + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B) -> SignalProducer<(Value, B.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer) { Signal.zip($0, $1).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C) -> SignalProducer<(Value, B.Value, C.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer) { Signal.zip($0, $1, $2).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D) -> SignalProducer<(Value, B.Value, C.Value, D.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer) { Signal.zip($0, $1, $2, $3).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer) { Signal.zip($0, $1, $2, $3, $4).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer) { Signal.zip($0, $1, $2, $3, $4, $5).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error, G.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer) { Signal.zip($0, $1, $2, $3, $4, $5, $6).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error, G.Error == Error, H.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer) { Signal.zip($0, $1, $2, $3, $4, $5, $6, $7).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value, I.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error, G.Error == Error, H.Error == Error, I.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer, i.producer) { Signal.zip($0, $1, $2, $3, $4, $5, $6, $7, $8).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zip(with:)`. + public static func zip(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I, _ j: J) -> SignalProducer<(Value, B.Value, C.Value, D.Value, E.Value, F.Value, G.Value, H.Value, I.Value, J.Value), Error> where A.Value == Value, A.Error == Error, B.Error == Error, C.Error == Error, D.Error == Error, E.Error == Error, F.Error == Error, G.Error == Error, H.Error == Error, I.Error == Error, J.Error == Error { + return .init { observer, lifetime in + flattenStart(lifetime, a.producer, b.producer, c.producer, d.producer, e.producer, f.producer, g.producer, h.producer, i.producer, j.producer) { Signal.zip($0, $1, $2, $3, $4, $5, $6, $7, $8, $9).observe(observer) } + } + } + + /// Zips the values of all the given producers, in the manner described by + /// `zipWith`. Will return an empty `SignalProducer` if the sequence is empty. + public static func zip(_ producers: S) -> SignalProducer<[Value], Error> where S.Iterator.Element: SignalProducerConvertible, S.Iterator.Element.Value == Value, S.Iterator.Element.Error == Error { + return start(producers, Signal.zip) + } + + private static func start(_ producers: S, _ transform: @escaping (ReversedCollection<[Signal]>) -> Signal<[Value], Error>) -> SignalProducer<[Value], Error> where S.Iterator.Element: SignalProducerConvertible, S.Iterator.Element.Value == Value, S.Iterator.Element.Error == Error { + return SignalProducer<[Value], Error> { observer, lifetime in + var producers = Array(producers) + var signals: [Signal] = [] + + guard !producers.isEmpty else { + observer.sendCompleted() + return + } + + func start() { + guard !producers.isEmpty else { + transform(signals.reversed()).observe(observer) + return + } + + producers.removeLast().producer.startWithSignal { signal, interruptHandle in + lifetime += interruptHandle + signals.append(signal) + + start() + } + } + + start() + } + } +} + +extension SignalProducer { + /// Repeat `self` a total of `count` times. In other words, start producer + /// `count` number of times, each one after previously started producer + /// completes. + /// + /// - note: Repeating `1` time results in an equivalent signal producer. + /// + /// - note: Repeating `0` times results in a producer that instantly + /// completes. + /// + /// - precondition: `count` must be non-negative integer. + /// + /// - parameters: + /// - count: Number of repetitions. + /// + /// - returns: A signal producer start sequentially starts `self` after + /// previously started producer completes. + public func `repeat`(_ count: Int) -> SignalProducer { + precondition(count >= 0) + + if count == 0 { + return .empty + } else if count == 1 { + return producer + } + + return SignalProducer { observer, lifetime in + let serialDisposable = SerialDisposable() + lifetime += serialDisposable + + func iterate(_ current: Int) { + self.startWithSignal { signal, signalDisposable in + serialDisposable.inner = signalDisposable + + signal.observe { event in + if case .completed = event { + let remainingTimes = current - 1 + if remainingTimes > 0 { + iterate(remainingTimes) + } else { + observer.sendCompleted() + } + } else { + observer.send(event) + } + } + } + } + + iterate(count) + } + } + + /// Ignore failures up to `count` times. + /// + /// - precondition: `count` must be non-negative integer. + /// + /// - parameters: + /// - count: Number of retries. + /// + /// - returns: A signal producer that restarts up to `count` times. + public func retry(upTo count: Int) -> SignalProducer { + precondition(count >= 0) + + if count == 0 { + return producer + } else { + return flatMapError { _ in + self.retry(upTo: count - 1) + } + } + } + + /// Delays retrying on failure by `interval` up to `count` attempts. + /// + /// - precondition: `count` must be non-negative integer. + /// + /// - parameters: + /// - count: Number of retries. + /// - interval: An interval between invocations. + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A signal producer that restarts up to `count` times. + public func retry(upTo count: Int, interval: TimeInterval, on scheduler: DateScheduler) -> SignalProducer { + precondition(count >= 0) + + if count == 0 { + return producer + } + + var retries = count + + return flatMapError { error -> SignalProducer in + // The final attempt shouldn't defer the error if it fails + var producer = SignalProducer(error: error) + if retries > 0 { + producer = SignalProducer.empty + .delay(interval, on: scheduler) + .concat(producer) + } + + retries -= 1 + return producer + } + .retry(upTo: count) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. Any failure or interruption sent from `self` is + /// forwarded immediately, in which case `replacement` will not be started, + /// and none of its events will be be forwarded. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: SignalProducer) -> SignalProducer { + return _then(replacement.promoteError(Error.self)) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. Any failure or interruption sent from `self` is + /// forwarded immediately, in which case `replacement` will not be started, + /// and none of its events will be be forwarded. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: Replacement) -> SignalProducer where Replacement.Error == Never { + return then(replacement.producer) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. Any failure or interruption sent from `self` is + /// forwarded immediately, in which case `replacement` will not be started, + /// and none of its events will be be forwarded. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: SignalProducer) -> SignalProducer { + return _then(replacement) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. Any failure or interruption sent from `self` is + /// forwarded immediately, in which case `replacement` will not be started, + /// and none of its events will be be forwarded. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: Replacement) -> SignalProducer where Replacement.Error == Error { + return then(replacement.producer) + } + + // NOTE: The overload below is added to disambiguate compile-time selection of + // `then(_:)`. + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. Any failure or interruption sent from `self` is + /// forwarded immediately, in which case `replacement` will not be started, + /// and none of its events will be be forwarded. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: SignalProducer) -> SignalProducer { + return _then(replacement) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. Any failure or interruption sent from `self` is + /// forwarded immediately, in which case `replacement` will not be started, + /// and none of its events will be be forwarded. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: Replacement) -> SignalProducer where Replacement.Value == Value, Replacement.Error == Error { + return then(replacement.producer) + } + + // NOTE: The method below is the shared implementation of `then(_:)`. The underscore + // prefix is added to avoid self referencing in `then(_:)` overloads with + // regard to the most specific rule of overload selection in Swift. + + internal func _then(_ replacement: Replacement) -> SignalProducer where Replacement.Error == Error { + return SignalProducer { observer, lifetime in + self.startWithSignal { signal, signalDisposable in + lifetime += signalDisposable + + signal.observe { event in + switch event { + case let .failed(error): + observer.send(error: error) + case .completed: + lifetime += replacement.producer.start(observer) + case .interrupted: + observer.sendInterrupted() + case .value: + break + } + } + } + } + } +} + +extension SignalProducer where Error == Never { + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: SignalProducer) -> SignalProducer { + return promoteError(F.self)._then(replacement) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: Replacement) -> SignalProducer { + return then(replacement.producer) + } + + // NOTE: The overload below is added to disambiguate compile-time selection of + // `then(_:)`. + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: SignalProducer) -> SignalProducer { + return _then(replacement) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: Replacement) -> SignalProducer where Replacement.Error == Never { + return then(replacement.producer) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: SignalProducer) -> SignalProducer { + return _then(replacement) + } + + /// Wait for completion of `self`, *then* forward all events from + /// `replacement`. + /// + /// - note: All values sent from `self` are ignored. + /// + /// - parameters: + /// - replacement: A producer to start when `self` completes. + /// + /// - returns: A producer that sends events from `self` and then from + /// `replacement` when `self` completes. + public func then(_ replacement: Replacement) -> SignalProducer where Replacement.Value == Value, Replacement.Error == Never { + return then(replacement.producer) + } +} + +extension SignalProducer { + /// Start the producer, then block, waiting for the first value. + /// + /// When a single value or error is sent, the returned `Result` will + /// represent those cases. However, when no values are sent, `nil` will be + /// returned. + /// + /// - returns: Result when single `value` or `failed` event is received. + /// `nil` when no events are received. + public func first() -> Result? { + return take(first: 1).single() + } + + /// Start the producer, then block, waiting for events: `value` and + /// `completed`. + /// + /// When a single value or error is sent, the returned `Result` will + /// represent those cases. However, when no values are sent, or when more + /// than one value is sent, `nil` will be returned. + /// + /// - returns: Result when single `value` or `failed` event is received. + /// `nil` when 0 or more than 1 events are received. + public func single() -> Result? { + let semaphore = DispatchSemaphore(value: 0) + var result: Result? + + take(first: 2).start { event in + switch event { + case let .value(value): + if result != nil { + // Move into failure state after recieving another value. + result = nil + return + } + result = .success(value) + case let .failed(error): + result = .failure(error) + semaphore.signal() + case .completed, .interrupted: + semaphore.signal() + } + } + + semaphore.wait() + return result + } + + /// Start the producer, then block, waiting for the last value. + /// + /// When a single value or error is sent, the returned `Result` will + /// represent those cases. However, when no values are sent, `nil` will be + /// returned. + /// + /// - returns: Result when single `value` or `failed` event is received. + /// `nil` when no events are received. + public func last() -> Result? { + return take(last: 1).single() + } + + /// Starts the producer, then blocks, waiting for completion. + /// + /// When a completion or error is sent, the returned `Result` will represent + /// those cases. + /// + /// - returns: Result when single `completion` or `failed` event is + /// received. + public func wait() -> Result<(), Error> { + return then(SignalProducer<(), Error>(value: ())).last() ?? .success(()) + } + + /// Creates a new `SignalProducer` that will multicast values emitted by + /// the underlying producer, up to `capacity`. + /// This means that all clients of this `SignalProducer` will see the same + /// version of the emitted values/errors. + /// + /// The underlying `SignalProducer` will not be started until `self` is + /// started for the first time. When subscribing to this producer, all + /// previous values (up to `capacity`) will be emitted, followed by any new + /// values. + /// + /// If you find yourself needing *the current value* (the last buffered + /// value) you should consider using `PropertyType` instead, which, unlike + /// this operator, will guarantee at compile time that there's always a + /// buffered value. This operator is not recommended in most cases, as it + /// will introduce an implicit relationship between the original client and + /// the rest, so consider alternatives like `PropertyType`, or representing + /// your stream using a `Signal` instead. + /// + /// This operator is only recommended when you absolutely need to introduce + /// a layer of caching in front of another `SignalProducer`. + /// + /// - precondition: `capacity` must be non-negative integer. + /// + /// - parameters: + /// - capacity: Number of values to hold. + /// + /// - returns: A caching producer that will hold up to last `capacity` + /// values. + public func replayLazily(upTo capacity: Int) -> SignalProducer { + precondition(capacity >= 0, "Invalid capacity: \(capacity)") + + // This will go "out of scope" when the returned `SignalProducer` goes + // out of scope. This lets us know when we're supposed to dispose the + // underlying producer. This is necessary because `struct`s don't have + // `deinit`. + let lifetimeToken = Lifetime.Token() + let lifetime = Lifetime(lifetimeToken) + + let state = Atomic(ReplayState(upTo: capacity)) + + let start: Atomic<(() -> Void)?> = Atomic { + // Start the underlying producer. + self + .take(during: lifetime) + .start { event in + let observers: Bag.Observer>? = state.modify { state in + defer { state.enqueue(event) } + return state.observers + } + observers?.forEach { $0.send(event) } + } + } + + return SignalProducer { observer, lifetime in + // Don't dispose of the original producer until all observers + // have terminated. + lifetime.observeEnded { _ = lifetimeToken } + + while true { + var result: Result.Observer>.Token?, ReplayError>! + state.modify { + result = $0.observe(observer) + } + + switch result! { + case let .success(token): + if let token = token { + lifetime.observeEnded { + state.modify { + $0.removeObserver(using: token) + } + } + } + + // Start the underlying producer if it has never been started. + start.swap(nil)?() + + // Terminate the replay loop. + return + + case let .failure(error): + error.values.forEach(observer.send(value:)) + } + } + } + } +} + +extension SignalProducer where Value == Bool { + /// Create a producer that computes a logical NOT in the latest values of `self`. + /// + /// - returns: A producer that emits the logical NOT results. + public func negate() -> SignalProducer { + return map(!) + } + + /// Create a producer that computes a logical AND between the latest values of `self` + /// and `producer`. + /// + /// - parameters: + /// - booleans: A producer of booleans to be combined with `self`. + /// + /// - returns: A producer that emits the logical AND results. + public func and(_ booleans: SignalProducer) -> SignalProducer { + return type(of: self).all([self, booleans]) + } + + /// Create a producer that computes a logical AND between the latest values of `self` + /// and `producer`. + /// + /// - parameters: + /// - booleans: A producer of booleans to be combined with `self`. + /// + /// - returns: A producer that emits the logical AND results. + public func and(_ booleans: Booleans) -> SignalProducer where Booleans.Value == Value, Booleans.Error == Error { + return and(booleans.producer) + } + + /// Create a producer that computes a logical AND between the latest values of `booleans`. + /// + /// - parameters: + /// - booleans: A collection of boolean producers to be combined. + /// + /// - returns: A producer that emits the logical AND results. + public static func all(_ booleans: BooleansCollection) -> SignalProducer where BooleansCollection.Element == SignalProducer { + return combineLatest(booleans).map { $0.reduce(true) { $0 && $1 } } + } + + /// Create a producer that computes a logical AND between the latest values of `booleans`. + /// + /// - parameters: + /// - booleans: A collection of boolean producers to be combined. + /// + /// - returns: A producer that emits the logical AND results. + public static func all(_ booleans: BooleansCollection) -> SignalProducer where Booleans.Value == Value, Booleans.Error == Error, BooleansCollection.Element == Booleans { + return all(booleans.map { $0.producer }) + } + + /// Create a producer that computes a logical OR between the latest values of `self` + /// and `producer`. + /// + /// - parameters: + /// - booleans: A producer of booleans to be combined with `self`. + /// + /// - returns: A producer that emits the logical OR results. + public func or(_ booleans: SignalProducer) -> SignalProducer { + return type(of: self).any([self, booleans]) + } + + /// Create a producer that computes a logical OR between the latest values of `self` + /// and `producer`. + /// + /// - parameters: + /// - booleans: A producer of booleans to be combined with `self`. + /// + /// - returns: A producer that emits the logical OR results. + public func or(_ booleans: Booleans) -> SignalProducer where Booleans.Value == Value, Booleans.Error == Error { + return or(booleans.producer) + } + + /// Create a producer that computes a logical OR between the latest values of `booleans`. + /// + /// - parameters: + /// - booleans: A collection of boolean producers to be combined. + /// + /// - returns: A producer that emits the logical OR results. + public static func any(_ booleans: BooleansCollection) -> SignalProducer where BooleansCollection.Element == SignalProducer { + return combineLatest(booleans).map { $0.reduce(false) { $0 || $1 } } + } + + /// Create a producer that computes a logical OR between the latest values of `booleans`. + /// + /// - parameters: + /// - booleans: A collection of boolean producers to be combined. + /// + /// - returns: A producer that emits the logical OR results. + public static func any(_ booleans: BooleansCollection) -> SignalProducer where Booleans.Value == Value, Booleans.Error == Error, BooleansCollection.Element == Booleans { + return any(booleans.map { $0.producer }) + } +} + +/// Represents a recoverable error of an observer not being ready for an +/// attachment to a `ReplayState`, and the observer should replay the supplied +/// values before attempting to observe again. +private struct ReplayError: Error { + /// The values that should be replayed by the observer. + let values: [Value] +} + +private struct ReplayState { + let capacity: Int + + /// All cached values. + var values: [Value] = [] + + /// A termination event emitted by the underlying producer. + /// + /// This will be nil if termination has not occurred. + var terminationEvent: Signal.Event? + + /// The observers currently attached to the caching producer, or `nil` if the + /// caching producer was terminated. + var observers: Bag.Observer>? = Bag() + + /// The set of in-flight replay buffers. + var replayBuffers: [ObjectIdentifier: [Value]] = [:] + + /// Initialize the replay state. + /// + /// - parameters: + /// - capacity: The maximum amount of values which can be cached by the + /// replay state. + init(upTo capacity: Int) { + self.capacity = capacity + } + + /// Attempt to observe the replay state. + /// + /// - warning: Repeatedly observing the replay state with the same observer + /// should be avoided. + /// + /// - parameters: + /// - observer: The observer to be registered. + /// + /// - returns: If the observer is successfully attached, a `Result.success` + /// with the corresponding removal token would be returned. + /// Otherwise, a `Result.failure` with a `ReplayError` would be + /// returned. + mutating func observe(_ observer: Signal.Observer) -> Result.Observer>.Token?, ReplayError> { + // Since the only use case is `replayLazily`, which always creates a unique + // `Observer` for every produced signal, we can use the ObjectIdentifier of + // the `Observer` to track them directly. + let id = ObjectIdentifier(observer) + + switch replayBuffers[id] { + case .none where !values.isEmpty: + // No in-flight replay buffers was found, but the `ReplayState` has one or + // more cached values in the `ReplayState`. The observer should replay + // them before attempting to observe again. + replayBuffers[id] = [] + return .failure(ReplayError(values: values)) + + case let .some(buffer) where !buffer.isEmpty: + // An in-flight replay buffer was found with one or more buffered values. + // The observer should replay them before attempting to observe again. + defer { replayBuffers[id] = [] } + return .failure(ReplayError(values: buffer)) + + case let .some(buffer) where buffer.isEmpty: + // Since an in-flight but empty replay buffer was found, the observer is + // ready to be attached to the `ReplayState`. + replayBuffers.removeValue(forKey: id) + + default: + // No values has to be replayed. The observer is ready to be attached to + // the `ReplayState`. + break + } + + if let event = terminationEvent { + observer.send(event) + } + + return .success(observers?.insert(observer)) + } + + /// Enqueue the supplied event to the replay state. + /// + /// - parameter: + /// - event: The event to be cached. + mutating func enqueue(_ event: Signal.Event) { + switch event { + case let .value(value): + for key in replayBuffers.keys { + replayBuffers[key]!.append(value) + } + + switch capacity { + case 0: + // With a capacity of zero, `state.values` can never be filled. + break + + case 1: + values = [value] + + default: + values.append(value) + + let overflow = values.count - capacity + if overflow > 0 { + values.removeFirst(overflow) + } + } + + case .completed, .failed, .interrupted: + // Disconnect all observers and prevent future attachments. + terminationEvent = event + observers = nil + } + } + + /// Remove the observer represented by the supplied token. + /// + /// - parameters: + /// - token: The token of the observer to be removed. + mutating func removeObserver(using token: Bag.Observer>.Token) { + observers?.remove(using: token) + } +} + +extension SignalProducer where Value == Date, Error == Never { + /// Create a repeating timer of the given interval, with a reasonable default + /// leeway, sending updates on the given scheduler. + /// + /// - note: This timer will never complete naturally, so all invocations of + /// `start()` must be disposed to avoid leaks. + /// + /// - precondition: `interval` must be non-negative number. + /// + /// - note: If you plan to specify an `interval` value greater than 200,000 + /// seconds, use `timer(interval:on:leeway:)` instead + /// and specify your own `leeway` value to avoid potential overflow. + /// + /// - parameters: + /// - interval: An interval between invocations. + /// - scheduler: A scheduler to deliver events on. + /// + /// - returns: A producer that sends `Date` values every `interval` seconds. + public static func timer(interval: DispatchTimeInterval, on scheduler: DateScheduler) -> SignalProducer { + // Apple's "Power Efficiency Guide for Mac Apps" recommends a leeway of + // at least 10% of the timer interval. + return timer(interval: interval, on: scheduler, leeway: interval * 0.1) + } + + /// Creates a repeating timer of the given interval, sending updates on the + /// given scheduler. + /// + /// - note: This timer will never complete naturally, so all invocations of + /// `start()` must be disposed to avoid leaks. + /// + /// - precondition: `interval` must be non-negative number. + /// + /// - precondition: `leeway` must be non-negative number. + /// + /// - parameters: + /// - interval: An interval between invocations. + /// - scheduler: A scheduler to deliver events on. + /// - leeway: Interval leeway. Apple's "Power Efficiency Guide for Mac Apps" + /// recommends a leeway of at least 10% of the timer interval. + /// + /// - returns: A producer that sends `Date` values every `interval` seconds. + public static func timer(interval: DispatchTimeInterval, on scheduler: DateScheduler, leeway: DispatchTimeInterval) -> SignalProducer { + precondition(interval.timeInterval >= 0) + precondition(leeway.timeInterval >= 0) + + return SignalProducer { observer, lifetime in + lifetime += scheduler.schedule( + after: scheduler.currentDate.addingTimeInterval(interval), + interval: interval, + leeway: leeway, + action: { observer.send(value: scheduler.currentDate) } + ) + } + } +} diff --git a/Pods/ReactiveSwift/Sources/UnidirectionalBinding.swift b/Pods/ReactiveSwift/Sources/UnidirectionalBinding.swift new file mode 100644 index 0000000..64a43e9 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/UnidirectionalBinding.swift @@ -0,0 +1,190 @@ +import Foundation +import Dispatch + +precedencegroup BindingPrecedence { + associativity: right + + // Binds tighter than assignment but looser than everything else + higherThan: AssignmentPrecedence +} + +infix operator <~ : BindingPrecedence + +/// Describes a source which can be bound. +public protocol BindingSource: SignalProducerConvertible where Error == Never {} +extension Signal: BindingSource where Error == Never {} +extension SignalProducer: BindingSource where Error == Never {} + +/// Describes an entity which be bond towards. +public protocol BindingTargetProvider { + associatedtype Value + + var bindingTarget: BindingTarget { get } +} + +extension BindingTargetProvider { + /// Binds a source to a target, updating the target's value to the latest + /// value sent by the source. + /// + /// - note: The binding will automatically terminate when the target is + /// deinitialized, or when the source sends a `completed` event. + /// + /// ```` + /// let property = MutableProperty(0) + /// let signal = Signal({ /* do some work after some time */ }) + /// property <~ signal + /// ```` + /// + /// ```` + /// let property = MutableProperty(0) + /// let signal = Signal({ /* do some work after some time */ }) + /// let disposable = property <~ signal + /// ... + /// // Terminates binding before property dealloc or signal's + /// // `completed` event. + /// disposable.dispose() + /// ```` + /// + /// - parameters: + /// - target: A target to be bond to. + /// - source: A source to bind. + /// + /// - returns: A disposable that can be used to terminate binding before the + /// deinitialization of the target or the source's `completed` + /// event. + @discardableResult + public static func <~ + + (provider: Self, source: Source) -> Disposable? + where Source.Value == Value + { + return source.producer + .take(during: provider.bindingTarget.lifetime) + .startWithValues(provider.bindingTarget.action) + } + + /// Binds a source to a target, updating the target's value to the latest + /// value sent by the source. + /// + /// - note: The binding will automatically terminate when the target is + /// deinitialized, or when the source sends a `completed` event. + /// + /// ```` + /// let property = MutableProperty(0) + /// let signal = Signal({ /* do some work after some time */ }) + /// property <~ signal + /// ```` + /// + /// ```` + /// let property = MutableProperty(0) + /// let signal = Signal({ /* do some work after some time */ }) + /// let disposable = property <~ signal + /// ... + /// // Terminates binding before property dealloc or signal's + /// // `completed` event. + /// disposable.dispose() + /// ```` + /// + /// - parameters: + /// - target: A target to be bond to. + /// - source: A source to bind. + /// + /// - returns: A disposable that can be used to terminate binding before the + /// deinitialization of the target or the source's `completed` + /// event. + @discardableResult + public static func <~ + + (provider: Self, source: Source) -> Disposable? + where Value == Source.Value? + { + return provider <~ source.producer.optionalize() + } +} + +extension Signal.Observer { + /// Binds a source to a target, updating the target's value to the latest + /// value sent by the source. + /// + /// - note: Only `value` events will be forwarded to the Observer. + /// The binding will automatically terminate when the target is + /// deinitialized, or when the source sends a `completed` event. + /// + /// - parameters: + /// - target: A target to be bond to. + /// - source: A source to bind. + /// + /// - returns: A disposable that can be used to terminate binding before the + /// deinitialization of the target or the source's `completed` + /// event. + @discardableResult + public static func <~ + + (observer: Signal.Observer, source: Source) -> Disposable? + where Source.Value == Value + { + return source.producer.startWithValues { [weak observer] in + observer?.send(value: $0) + } + } +} + +/// A binding target that can be used with the `<~` operator. +public struct BindingTarget: BindingTargetProvider { + public let lifetime: Lifetime + public let action: (Value) -> Void + + public var bindingTarget: BindingTarget { + return self + } + + /// Creates a binding target which consumes values on the specified scheduler. + /// + /// If no scheduler is specified, the binding target would consume the value + /// immediately. + /// + /// - parameters: + /// - scheduler: The scheduler on which the `action` consumes the values. + /// - lifetime: The expected lifetime of any bindings towards `self`. + /// - action: The action to consume values. + public init(on scheduler: Scheduler = ImmediateScheduler(), lifetime: Lifetime, action: @escaping (Value) -> Void) { + self.lifetime = lifetime + + if scheduler is ImmediateScheduler { + self.action = action + } else { + self.action = { value in + scheduler.schedule { + action(value) + } + } + } + } + + /// Creates a binding target which consumes values on the specified scheduler. + /// + /// If no scheduler is specified, the binding target would consume the value + /// immediately. + /// + /// - parameters: + /// - scheduler: The scheduler on which the key path consumes the values. + /// - lifetime: The expected lifetime of any bindings towards `self`. + /// - object: The object to consume values. + /// - keyPath: The key path of the object that consumes values. + public init(on scheduler: Scheduler = ImmediateScheduler(), lifetime: Lifetime, object: Object, keyPath: WritableKeyPath) { + self.init(on: scheduler, lifetime: lifetime) { [weak object] in object?[keyPath: keyPath] = $0 } + } +} + +extension Optional: BindingTargetProvider where Wrapped: BindingTargetProvider { + public typealias Value = Wrapped.Value + + public var bindingTarget: BindingTarget { + switch self { + case let .some(provider): + return provider.bindingTarget + case .none: + return BindingTarget(lifetime: .empty, action: { _ in }) + } + } +} diff --git a/Pods/ReactiveSwift/Sources/UninhabitedTypeGuards.swift b/Pods/ReactiveSwift/Sources/UninhabitedTypeGuards.swift new file mode 100644 index 0000000..9fa0bd7 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/UninhabitedTypeGuards.swift @@ -0,0 +1,146 @@ +// Observation + +extension SignalProducer { + @available(*, unavailable, message:"Transform the error to `Never` beforehand, or use `startWithResult` instead") + @discardableResult + public func startWithValues(_ action: @escaping (Value) -> Void) -> Disposable { observingUninhabitedTypeError() } +} + +extension Signal { + @available(*, unavailable, message:"Transform the error to `Never` beforehand, or use `observeResult` instead") + @discardableResult + public func observeValues(_ action: @escaping (Value) -> Void) -> Disposable? { observingUninhabitedTypeError() } +} + +extension SignalProducer where Value == Never { + @discardableResult + @available(*, deprecated, message:"`Result.success` is never delivered - value type `Never` is uninstantiable (Use at runtime would trap)") + public func startWithResult(_ action: @escaping (Result) -> Void) -> Disposable { observingUninhabitedTypeError() } +} + +extension SignalProducer where Value == Never, Error == Never { + @discardableResult + @available(*, deprecated, message:"Observer is never called - value type `Never` and error type `Never` are uninstantiable (Use at runtime would trap)") + public func startWithResult(_ action: @escaping (Result) -> Void) -> Disposable { observingUninhabitedTypeError() } + + @discardableResult + @available(*, deprecated, message:"Observer is never called - value type `Never` is uninstantiable (Use at runtime would trap)") + public func startWithValues(_ action: @escaping (Value) -> Void) -> Disposable { observingUninhabitedTypeError() } +} + +extension SignalProducer where Error == Never { + @discardableResult + @available(*, deprecated, message:"Observer is never called - error type `Never` is uninstantiable (Use at runtime would trap)") + public func startWithFailed(_ action: @escaping (Error) -> Void) -> Disposable { observingUninhabitedTypeError() } +} + +extension Signal where Value == Never { + @discardableResult + @available(*, deprecated, message:"`Result.success` is never delivered - value type `Never` is uninstantiable (Use at runtime would trap)") + public func observeResult(_ action: @escaping (Result) -> Void) -> Disposable? { observingUninhabitedTypeError() } +} + +extension Signal where Value == Never, Error == Never { + @discardableResult + @available(*, deprecated, message:"Observer is never called - value type `Never` and error type `Never` are uninstantiable (Use at runtime would trap)") + public func observeResult(_ action: @escaping (Result) -> Void) -> Disposable? { observingUninhabitedTypeError() } + + @discardableResult + @available(*, deprecated, message:"Observer is never called - value type `Never` is uninstantiable (Use at runtime would trap)") + public func observeValues(_ action: @escaping (Value) -> Void) -> Disposable? { observingUninhabitedTypeError() } +} + +extension Signal where Error == Never { + @discardableResult + @available(*, deprecated, message:"Observer is never invoked - error type `Never` is uninstantiable (Use at runtime would trap)") + public func observeFailed(_ action: @escaping (Error) -> Void) -> Disposable? { observingUninhabitedTypeError() } +} + +// flatMap +extension SignalProducer where Value == Never { + @discardableResult + @available(*, deprecated, message:"Use `promoteValue` instead - value type `Never` is uninstantiable (Use at runtime would trap)") + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> SignalProducer where Inner.Error == Error { observingUninhabitedTypeError() } + + @discardableResult + @available(*, deprecated, message:"Use `promoteValue` instead - value type `Never` is uninstantiable (Use at runtime would trap)") + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> SignalProducer where Inner.Error == Never { observingUninhabitedTypeError() } +} + +extension SignalProducer where Value == Never, Error == Never { + @discardableResult + @available(*, deprecated, message:"Use `promoteValue` instead - value type `Never` and error type `Never` are uninstantiable (Use at runtime would trap)") + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> SignalProducer { observingUninhabitedTypeError() } + + @discardableResult + @available(*, deprecated, message:"Use `promoteValue` instead - value type `Never` and error type `Never` are uninstantiable (Use at runtime would trap)") + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> SignalProducer where Inner.Error == Error { observingUninhabitedTypeError() } +} + +extension SignalProducer where Error == Never { + @discardableResult + @available(*, deprecated, message:"Use `promoteError` instead - error type `Never` is uninstantiable (Use at runtime would trap)") + public func flatMapError(_ transform: @escaping (Error) -> SignalProducer) -> SignalProducer { observingUninhabitedTypeError() } +} + +extension Signal where Value == Never { + @discardableResult + @available(*, deprecated, message:"Use `promoteValue` instead - value type `Never` is uninstantiable (Use at runtime would trap)") + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> Signal where Inner.Error == Error { observingUninhabitedTypeError() } + + @discardableResult + @available(*, deprecated, message:"Use `promoteValue` instead - value type `Never` is uninstantiable (Use at runtime would trap)") + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> Signal where Inner.Error == Never { observingUninhabitedTypeError() } + +} + +extension Signal where Value == Never, Error == Never { + @discardableResult + @available(*, deprecated, message:"Use `promoteValue` instead - value type `Never` and error type `Never` are uninstantiable (Use at runtime would trap)") + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> Signal { observingUninhabitedTypeError() } + + @discardableResult + @available(*, deprecated, message:"Use `promoteValue` instead - value type `Never` and error type `Never` are uninstantiable (Use at runtime would trap)") + public func flatMap(_ strategy: FlattenStrategy, _ transform: @escaping (Value) -> Inner) -> Signal where Inner.Error == Error { observingUninhabitedTypeError() } +} + +extension Signal where Error == Never { + @discardableResult + @available(*, deprecated, message:"Use `promoteError` instead - error type `Never` is uninstantiable (Use at runtime would trap)") + public func flatMapError(_ transform: @escaping (Error) -> SignalProducer) -> Signal { observingUninhabitedTypeError() } +} + +@inline(never) +private func observingUninhabitedTypeError() -> Never { + fatalError("Detected an attempt to observe (or create streams to transform) uninstantiable events. This is considered a logical error, and appropriate operators should be used instead. Please refer to the warnings raised by the compiler.") +} + +/* +func test() { + SignalProducer.never.startWithValues { _ in } + Signal.never.observeValues { _ in } + + SignalProducer.never.startWithResult { _ in } + SignalProducer.never.startWithResult { _ in } + SignalProducer.never.startWithFailed { _ in } + SignalProducer.never.startWithFailed { _ in } + Signal.never.observeResult { _ in } + Signal.never.observeResult { _ in } + Signal.never.observeFailed { _ in } + Signal.never.observeFailed { _ in } + + SignalProducer.never.flatMap(.latest) { _ in SignalProducer.empty } + SignalProducer.never.flatMap(.latest) { _ in SignalProducer.empty } + SignalProducer.never.flatMap(.latest) { _ in SignalProducer.empty } + SignalProducer.never.flatMap(.latest) { _ in SignalProducer.empty } + SignalProducer.never.flatMapError { _ in SignalProducer.empty } + SignalProducer.never.flatMapError { _ in SignalProducer.empty } + + Signal.never.flatMap(.latest) { _ in SignalProducer.empty } + Signal.never.flatMap(.latest) { _ in SignalProducer.empty } + Signal.never.flatMap(.latest) { _ in SignalProducer.empty } + Signal.never.flatMap(.latest) { _ in SignalProducer.empty } + Signal.never.flatMapError { _ in SignalProducer.empty } + Signal.never.flatMapError { _ in SignalProducer.empty } +} +*/ diff --git a/Pods/ReactiveSwift/Sources/ValidatingProperty.swift b/Pods/ReactiveSwift/Sources/ValidatingProperty.swift new file mode 100644 index 0000000..d5cabe4 --- /dev/null +++ b/Pods/ReactiveSwift/Sources/ValidatingProperty.swift @@ -0,0 +1,325 @@ +/// A mutable property that validates mutations before committing them. +/// +/// If the property wraps an arbitrary mutable property, changes originated from +/// the inner property are monitored, and would be automatically validated. +/// Note that these would still appear as committed values even if they fail the +/// validation. +/// +/// ``` +/// let root = MutableProperty("Valid") +/// let outer = ValidatingProperty(root) { +/// $0 == "Valid" ? .valid : .invalid(.outerInvalid) +/// } +/// +/// outer.result.value // `.valid("Valid") +/// +/// root.value = "🎃" +/// outer.result.value // `.invalid("🎃", .outerInvalid)` +/// ``` +public final class ValidatingProperty: MutablePropertyProtocol { + private let getter: () -> Value + private let setter: (Value) -> Void + + /// The result of the last attempted edit of the root property. + public let result: Property + + /// The current value of the property. + /// + /// The value could have failed the validation. Refer to `result` for the + /// latest validation result. + public var value: Value { + get { return getter() } + set { setter(newValue) } + } + + /// A producer for Signals that will send the property's current value, + /// followed by all changes over time, then complete when the property has + /// deinitialized. + public let producer: SignalProducer + + /// A signal that will send the property's changes over time, + /// then complete when the property has deinitialized. + public let signal: Signal + + /// The lifetime of the property. + public let lifetime: Lifetime + + /// Create a `ValidatingProperty` that presents a mutable validating + /// view for an inner mutable property. + /// + /// The proposed value is only committed when `valid` is returned by the + /// `validator` closure. + /// + /// - note: `inner` is retained by the created property. + /// + /// - parameters: + /// - inner: The inner property which validated values are committed to. + /// - validator: The closure to invoke for any proposed value to `self`. + public init( + _ inner: Inner, + _ validator: @escaping (Value) -> Decision + ) where Inner.Value == Value { + getter = { inner.value } + producer = inner.producer + signal = inner.signal + lifetime = inner.lifetime + + // This flag temporarily suspends the monitoring on the inner property for + // writebacks that are triggered by successful validations. + var isSettingInnerValue = false + + (result, setter) = inner.withValue { initial in + let mutableResult = MutableProperty(Result(initial, validator(initial))) + + mutableResult <~ inner.signal + .filter { _ in !isSettingInnerValue } + .map { Result($0, validator($0)) } + + return (Property(capturing: mutableResult), { input in + // Acquire the lock of `inner` to ensure no modification happens until + // the validation logic here completes. + inner.withValue { _ in + let writebackValue: Value? = mutableResult.modify { result in + result = Result(input, validator(input)) + return result.value + } + + if let value = writebackValue { + isSettingInnerValue = true + inner.value = value + isSettingInnerValue = false + } + } + }) + } + } + + /// Create a `ValidatingProperty` that validates mutations before + /// committing them. + /// + /// The proposed value is only committed when `valid` is returned by the + /// `validator` closure. + /// + /// - parameters: + /// - initial: The initial value of the property. It is not required to + /// pass the validation as specified by `validator`. + /// - validator: The closure to invoke for any proposed value to `self`. + public convenience init( + _ initial: Value, + _ validator: @escaping (Value) -> Decision + ) { + self.init(MutableProperty(initial), validator) + } + + /// Create a `ValidatingProperty` that presents a mutable validating + /// view for an inner mutable property. + /// + /// The proposed value is only committed when `valid` is returned by the + /// `validator` closure. + /// + /// - note: `inner` is retained by the created property. + /// + /// - parameters: + /// - inner: The inner property which validated values are committed to. + /// - other: The property that `validator` depends on. + /// - validator: The closure to invoke for any proposed value to `self`. + public convenience init( + _ inner: MutableProperty, + with other: Other, + _ validator: @escaping (Value, Other.Value) -> Decision + ) { + // Capture a copy that reflects `other` without influencing the lifetime of + // `other`. + let other = Property(other) + + self.init(inner) { input in + return validator(input, other.value) + } + + // When `other` pushes out a new value, the resulting property would react + // by revalidating itself with its last attempted value, regardless of + // success or failure. + other.signal + .take(during: lifetime) + .observeValues { [weak self] _ in + guard let s = self else { return } + + switch s.result.value { + case let .invalid(value, _): + s.value = value + + case let .coerced(_, value, _): + s.value = value + + case let .valid(value): + s.value = value + } + } + } + + /// Create a `ValidatingProperty` that validates mutations before + /// committing them. + /// + /// The proposed value is only committed when `valid` is returned by the + /// `validator` closure. + /// + /// - parameters: + /// - initial: The initial value of the property. It is not required to + /// pass the validation as specified by `validator`. + /// - other: The property that `validator` depends on. + /// - validator: The closure to invoke for any proposed value to `self`. + public convenience init( + _ initial: Value, + with other: Other, + _ validator: @escaping (Value, Other.Value) -> Decision + ) { + self.init(MutableProperty(initial), with: other, validator) + } + + /// Create a `ValidatingProperty` which validates mutations before + /// committing them. + /// + /// The proposed value is only committed when `valid` is returned by the + /// `validator` closure. + /// + /// - note: `inner` is retained by the created property. + /// + /// - parameters: + /// - initial: The initial value of the property. It is not required to + /// pass the validation as specified by `validator`. + /// - other: The property that `validator` depends on. + /// - validator: The closure to invoke for any proposed value to `self`. + public convenience init( + _ initial: Value, + with other: ValidatingProperty, + _ validator: @escaping (Value, U) -> Decision + ) { + self.init(MutableProperty(initial), with: other, validator) + } + + /// Create a `ValidatingProperty` that presents a mutable validating + /// view for an inner mutable property. + /// + /// The proposed value is only committed when `valid` is returned by the + /// `validator` closure. + /// + /// - parameters: + /// - inner: The inner property which validated values are committed to. + /// - other: The property that `validator` depends on. + /// - validator: The closure to invoke for any proposed value to `self`. + public convenience init( + _ inner: MutableProperty, + with other: ValidatingProperty, + _ validator: @escaping (Value, U) -> Decision + ) { + // Capture only `other.result` but not `other`. + let otherValidations = other.result + + self.init(inner) { input in + let otherValue: U + + switch otherValidations.value { + case let .valid(value): + otherValue = value + + case let .coerced(_, value, _): + otherValue = value + + case let .invalid(value, _): + otherValue = value + } + + return validator(input, otherValue) + } + + // When `other` pushes out a new validation result, the resulting property + // would react by revalidating itself with its last attempted value, + // regardless of success or failure. + otherValidations.signal + .take(during: lifetime) + .observeValues { [weak self] _ in + guard let s = self else { return } + + switch s.result.value { + case let .invalid(value, _): + s.value = value + + case let .coerced(_, value, _): + s.value = value + + case let .valid(value): + s.value = value + } + } + } + + /// Represents a decision of a validator of a validating property made on a + /// proposed value. + public enum Decision { + /// The proposed value is valid. + case valid + + /// The proposed value is invalid, but the validator coerces it into a + /// replacement which it deems valid. + case coerced(Value, ValidationError?) + + /// The proposed value is invalid. + case invalid(ValidationError) + } + + /// Represents the result of the validation performed by a validating property. + public enum Result { + /// The proposed value is valid. + case valid(Value) + + /// The proposed value is invalid, but the validator was able to coerce it + /// into a replacement which it deemed valid. + case coerced(replacement: Value, proposed: Value, error: ValidationError?) + + /// The proposed value is invalid. + case invalid(Value, ValidationError) + + /// Whether the value is invalid. + public var isInvalid: Bool { + if case .invalid = self { + return true + } else { + return false + } + } + + /// Extract the valid value, or `nil` if the value is invalid. + public var value: Value? { + switch self { + case let .valid(value): + return value + case let .coerced(value, _, _): + return value + case .invalid: + return nil + } + } + + /// Extract the error if the value is invalid. + public var error: ValidationError? { + if case let .invalid(_, error) = self { + return error + } else { + return nil + } + } + + fileprivate init(_ value: Value, _ decision: Decision) { + switch decision { + case .valid: + self = .valid(value) + + case let .coerced(replacement, error): + self = .coerced(replacement: replacement, proposed: value, error: error) + + case let .invalid(error): + self = .invalid(value, error) + } + } + } +} diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-acknowledgements.markdown b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-acknowledgements.markdown index 17a9658..c1d83b4 100644 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-acknowledgements.markdown +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-acknowledgements.markdown @@ -1,6 +1,29 @@ # Acknowledgements This application makes use of the following third party libraries: +## ReactiveSwift + +**Copyright (c) 2012 - 2016, GitHub, Inc.** +**All rights reserved.** + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ## RxSwift **The MIT License** diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-acknowledgements.plist b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-acknowledgements.plist index a9fa5ec..f5f8035 100644 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-acknowledgements.plist +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-acknowledgements.plist @@ -12,6 +12,35 @@ Type PSGroupSpecifier + + FooterText + **Copyright (c) 2012 - 2016, GitHub, Inc.** +**All rights reserved.** + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + License + MIT + Title + ReactiveSwift + Type + PSGroupSpecifier + FooterText **The MIT License** diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Debug-input-files.xcfilelist b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Debug-input-files.xcfilelist index d6f2a66..ed1de65 100644 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Debug-input-files.xcfilelist +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Debug-input-files.xcfilelist @@ -1,2 +1,3 @@ ${PODS_ROOT}/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks.sh +${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework ${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Debug-output-files.xcfilelist b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Debug-output-files.xcfilelist index 88c38b0..153c2e0 100644 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Debug-output-files.xcfilelist +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Debug-output-files.xcfilelist @@ -1 +1,2 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveSwift.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Release-input-files.xcfilelist b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Release-input-files.xcfilelist index d6f2a66..ed1de65 100644 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Release-input-files.xcfilelist +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Release-input-files.xcfilelist @@ -1,2 +1,3 @@ ${PODS_ROOT}/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks.sh +${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework ${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Release-output-files.xcfilelist b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Release-output-files.xcfilelist index 88c38b0..153c2e0 100644 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Release-output-files.xcfilelist +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks-Release-output-files.xcfilelist @@ -1 +1,2 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveSwift.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks.sh b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks.sh index be37ecd..93b227d 100755 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks.sh +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests-frameworks.sh @@ -94,7 +94,7 @@ install_dsym() { binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" # Strip invalid architectures so "fat" simulator / device frameworks work on device - if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then strip_invalid_archs "$binary" fi @@ -161,9 +161,11 @@ strip_invalid_archs() { if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework" install_framework "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework" install_framework "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework" fi if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.debug.xcconfig b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.debug.xcconfig index 34106f9..8004173 100644 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.debug.xcconfig +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.debug.xcconfig @@ -1,10 +1,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift/ReactiveSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" -OTHER_LDFLAGS = $(inherited) -framework "RxSwift" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift/ReactiveSwift.framework/Headers" -isystem "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" +OTHER_LDFLAGS = $(inherited) -framework "ReactiveSwift" -framework "RxSwift" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.release.xcconfig b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.release.xcconfig index 34106f9..8004173 100644 --- a/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.release.xcconfig +++ b/Pods/Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.release.xcconfig @@ -1,10 +1,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift/ReactiveSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" -OTHER_LDFLAGS = $(inherited) -framework "RxSwift" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift/ReactiveSwift.framework/Headers" -isystem "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" +OTHER_LDFLAGS = $(inherited) -framework "ReactiveSwift" -framework "RxSwift" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-Info.plist b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-Info.plist new file mode 100644 index 0000000..2eb204d --- /dev/null +++ b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 6.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-dummy.m b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-dummy.m new file mode 100644 index 0000000..2f7b75c --- /dev/null +++ b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_ReactiveSwift : NSObject +@end +@implementation PodsDummy_ReactiveSwift +@end diff --git a/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-prefix.pch b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-umbrella.h b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-umbrella.h new file mode 100644 index 0000000..20aed9e --- /dev/null +++ b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double ReactiveSwiftVersionNumber; +FOUNDATION_EXPORT const unsigned char ReactiveSwiftVersionString[]; + diff --git a/Pods/Target Support Files/ReactiveSwift/ReactiveSwift.modulemap b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift.modulemap new file mode 100644 index 0000000..0e32187 --- /dev/null +++ b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift.modulemap @@ -0,0 +1,6 @@ +framework module ReactiveSwift { + umbrella header "ReactiveSwift-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/ReactiveSwift/ReactiveSwift.xcconfig b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift.xcconfig new file mode 100644 index 0000000..b6d1185 --- /dev/null +++ b/Pods/Target Support Files/ReactiveSwift/ReactiveSwift.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ReactiveSwift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings +OTHER_SWIFT_FLAGS[config=Release] = $(inherited) -suppress-warnings +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/ReactiveSwift +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/SpeedTest.xcodeproj/project.pbxproj b/SpeedTest.xcodeproj/project.pbxproj index d96dba9..896d125 100644 --- a/SpeedTest.xcodeproj/project.pbxproj +++ b/SpeedTest.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 69D4373B22FC5B11008233B9 /* ReactiveSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69D4373A22FC5B11008233B9 /* ReactiveSwiftTests.swift */; }; B919F6FA2FD596D7C43C33D1 /* Pods_SpeedTestTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3B8730AB70E2662A0E106CC /* Pods_SpeedTestTests.framework */; }; F64D61F622F4334A00315E19 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F64D61F522F4334A00315E19 /* AppDelegate.swift */; }; F64D61F822F4334A00315E19 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F64D61F722F4334A00315E19 /* SceneDelegate.swift */; }; @@ -32,6 +33,7 @@ /* Begin PBXFileReference section */ 01C790B0CCF8F5785B4C5466 /* Pods-SpeedTestTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SpeedTestTests.release.xcconfig"; path = "Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.release.xcconfig"; sourceTree = ""; }; + 69D4373A22FC5B11008233B9 /* ReactiveSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactiveSwiftTests.swift; sourceTree = ""; }; 71D841E05F10EEEF73ACE790 /* Pods-SpeedTestTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SpeedTestTests.debug.xcconfig"; path = "Target Support Files/Pods-SpeedTestTests/Pods-SpeedTestTests.debug.xcconfig"; sourceTree = ""; }; C3B8730AB70E2662A0E106CC /* Pods_SpeedTestTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SpeedTestTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F64D61F222F4334A00315E19 /* SpeedTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpeedTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -123,8 +125,9 @@ F64D620B22F4334B00315E19 /* SpeedTestTests */ = { isa = PBXGroup; children = ( - F64D620C22F4334B00315E19 /* RxSwiftTests.swift */, F6C7F85D22F4406E0016721E /* CombineTests.swift */, + 69D4373A22FC5B11008233B9 /* ReactiveSwiftTests.swift */, + F64D620C22F4334B00315E19 /* RxSwiftTests.swift */, F64D620E22F4334B00315E19 /* Info.plist */, ); path = SpeedTestTests; @@ -288,6 +291,7 @@ files = ( F64D620D22F4334B00315E19 /* RxSwiftTests.swift in Sources */, F6796E8A22F9562C0009E85D /* Publisher+Anonymous.swift in Sources */, + 69D4373B22FC5B11008233B9 /* ReactiveSwiftTests.swift in Sources */, F6C7F85E22F4406E0016721E /* CombineTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/SpeedTest.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist b/SpeedTest.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..837d27b --- /dev/null +++ b/SpeedTest.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + SpeedTest.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/SpeedTest.xcworkspace/xcuserdata/olejnjak.xcuserdatad/UserInterfaceState.xcuserstate b/SpeedTest.xcworkspace/xcuserdata/olejnjak.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..3cb3bd1a05750a9e5a74fd87a27c4daaee8378b2 GIT binary patch literal 19603 zcmeHvd3;kv_xH@bH)*=0NlROHXlZGiwn?)zOINx>S=!Q#osza`8)%b~q(A{>!lr@> zBH{urEeIkAh=9NYf{5bICYzvwh=8D?f+(Q8XYOsf0FTe}d*AoZU-L;bch)m!&di)S z=R3Eeq0Z`bsnuT~j2Ofs4vCPMb8@bc5mPJ&y3F?A^P%w%`aY%_&C?2Vi25FHFB_KUYMky#44MoFHF&cqJqOoWk zav~RML{rdIGz~SO>1YO;i3oZGJ&GPfkE18hlV}-w7CncSqZR07vTDh z7f0b}tithFjdSrpJP7CE!FUKBiihERT!0Jla9o6oaS1NP<#+-%;|e?xyKp0(f~VqX zxCu|kbMZVpA3uVh!b|Yecqx7fzl>kOtMF@hJKlkJ;(y^?csG6*@5k@s5AjF%Gkg@E zz+d9C_*eWJzK(C;-|>fy{8Gh$&`Dm{O*UnZTHt3Z{~&VrrQ>rh%Ex%wPyJpLv8?$Sh(OGs~D4 zn3tFqW%#`JUD%#%FE*5oVAZUK)v`J^flX&K*i1Hy&1MI(!`OVbgdN3JvQ?~&wX==v40awn zpIyv8#V%)8urIP}+1J^1?0WVMb`QIkeV5(GzQ^uo-)BEy53rxHpR>o=6YNR$6nl>S zmc7LO#9n7_v43-ZoRstDg18=BBp1a+a|$k=({Tx0Avc^W;)=Nvu9Pd|MsOp!QQT;5 z3^$%Lb5)#$tLEysdaj`~!q!+z8}&hbiHL}a7m*Ne z;zN9iACay_VW=MpM-iw$ibPQ;8YzfBk&%&P44Fh0k;P;Qd79{etW1Z+JgLEMwYi)b zl`iWPv&&LdF7J_TsWvy(xpJzkF1w@H1+mUtyQ8#dsBB_R#H`H06!a_Rhoi6CHP%P8zv{dm0t*)jbOM~43tdM!QGQw)B zvQKpa6+$S(;V|23pf#H-+fvb3lV_{8L-t}z9jqXhsQ2{DM!$%7uXfxMaMhZcTvoyaLn9u^rMI-Zz3;1=nBY9;!DIw)@ zzN-IgQi>ZamZ}nv0s3{u7g@|yoGd)ae3Z&bsqfhG7{29hCrA5g6ycAyjb#+px6D0wf3pQtTt=CxuIMh_P}H+W?6RF5Y06( zz4|^dPo8ax)oHD$v%n+?zduK%!(La%Pg<3|y4q=h$#s7{E_+Q)ouw+Pmd-7x=K<7o zsHYC(uU!7%4rMgDYV8iF;{Iehw{q=uRUpMj5M4VTLbICD!z6-43D0gcYZaOe9ELCH z4}7KHD7l{;2{OF^Eri)aSAeD#v;Y-J!uMQ5{GVqkE<#ICU<+D|o+7a%t_3}fmJ%gV zk@zu`<~&=KWtzn~zN&S_9cr=FxN3#ApGUJ^AyEN%q|nrh=%umw#o1O6Tf5Edfc9QQ zMV?k(K`Uu1&8UTFh_*v3rPa{A`|GFk@pZJWT;3(Wcvz#$3}e+^^GZnSQ1=_?Z7P-< z&_=Wgy@@uXx6l@}6>TGWVjxChB8eo4B$E`9x)yD36U*JaSnefhZDN_pi)GILilsy4 zgn9Nq5z9}hSbjzZc*OD$70bgQgYYHkB!mA($-B#?9)UQ8&In?68pJM(3dGkScG)EU z9#IR3y6q`)9(^y!&;^j8+<#xhlm9CEoyx_J=qL0ux`uv1zoOsJb##LaB6(ym8A67V zVI-dvkixa-W}95x;pO5k8Qvxr#k^dU{jXg7kL3dUf?QxfQq(FJSVrZ-E_{Hi!Y8VA zz;Foe&dUVu1~O3s1B`ouOqAX)6a7B)6bZ%QyiDMJAQL10eGyN71&&35%{YdPYQ}M7 zG>IPvnoB-x_r)#;EV858_Cikq4NgXZYq1vVa01q212$q4PQ*!MEEz|}lX5bFm`Mex zBvos13J6gh9)Qzv2F}D;D2!P69j}_ykXm9T6X7X-l*{a>vABw}hm5v5bLy-$bRR00 zhX~QxmMPXsOP+It6%-wd6E+2TTmCY$!)m5VZ&1g)L+zEVI%A*^ok0(TE>P_n9Z+v; zq)>0Jx!zjWR4xzhSivyZW9sOxc^?s3c3Y(b^iNoYtqrwyo5g9ZZv^$r?$GE|YEU8X zi7l6>RZVeK@m)~fla^%A<>X{$=yl4>tei|`f-X^`G-HzJZub=_XrP-IB!%3URAO~eg%LJmT#2o(;wo&x)wl-N zk_IxB%pkMKT=Im6-bvU_>8-={*hVH32XU^%4R|tk5Ep4AQz*TW_qEW8yh4Z7?f@;n zTps(+88gk5lZq`3W(OUga=GH4a|>;hnd=%Y;pq}VBdA27{TUQ`{~VZsXWiEeg5ALN zX{3pAJv?2g0Syl=&1|&RReAdVD1Q9Dl270#@gg#lJVYL*CFMfVqNE2j{0x5nzTz+7 z<#+`l#7$;H@d2&cOe^h2a5Icc3tmZ&3{_^Axga3qkqVDF1v4xs61!*rmu3`sn3qH* z@6oeYWK^u)U^Im#rsm`h9F$j3TsC@KjmQ4qDkN934O#%5cH5 zQqkzLIN?AWO4w1wjg^(4=Ub|d1_b(a3F-cTV{l7QFyV-(rE51hmG&UPW%lYr;A5w~~(=E_$b#9%x#!1yLi?h;UZ2%E~M7pkpr$-754tP`! zCtNSmeY~nTH@~>VGR>vT1l{Y1PqZQi6mg-I_VOJ_??${SxpC@*l}c5-a7JFK(dvj4 z7Bm^@3Nr|ZE1^`D=9M}@@op>3D{wS{651g))KehWVx|jKvBd?4-x_C!EHa@+N+VzA zkwBlMl;&h2Cn1!Yw2ba81JdCT8rYJVMY_OgFt}Xa6Uulhq^DcEBd-ePxV749fjQB& zEw!Yn!P1^0M{@Cz!9#`)d(iQ(vraoSzwHbNB?^a+Z&Ocs9eZVAQNBmthV+usf1|*b z49$n+5hG!FznAYVqw*gR3%SRPZIy(UG5N>FmrpSJR8&@3s-d|NbiD^U=|TtVCah`v z0|-kowU)pp0BMa*m%W~sAU-lvjk46C8aWF`x4vK0S||EUsvB5el3$#c4F}%5tSqRP z-x=iIaJ1`l#O~8D8KPPzRX{C50k!6ahB^kMtKQ~v3@pkRHFDJGP_Hv!cczKQp!Ur7sTwy83|htMg4tsrUyo1|wU*F)LLGLfhd$AI zFY$4et?j9xy{ta3f+;=}3@%q8y%s{lz?e>BrU8BR@S6p(jgVFY;f}3nL5{RwtfI6E zG|+U~%H`Hp>`YN8{o>@;o#9p!?Tl&bsW0@@NC z5gihJE&2k5!tZyYW1>qCIxRW_pHpr06axJod7!)(B%lU(Ej+bLRwW-p$D$5CbX@MI zvwh5jdT5>wHDH!+m-Z-wuZ5=8!|n06}fl_;p~z|39U zQ0Vc;_kM&z*UNW&*w(wyW8C(!NBs`WthO!g(a(#%hzi!W=KB4|meN5d9DOcF1*{$qub_ctY{S<}5(@t)UlqzCk znNVnEH-0!y--+M~QR9QGDHe@5I^SLE>B# zD%Q|=alCjigcE5l7wFiq-=HjeLzBZ=Q|k)N04>K7nrEw2#f56s8ra>a&P4Md^xJS= z7s4T*RyI1O2yq@j&eW;C_p7>6dDixsD+Vq0B2_+ zH=2(Yf=Txo^a40)SAm;$1DHkMM!V3v;HLcq9YV*@Y1mILpetY)`yJf|_pBF|;x4#5 zIAiU2vry#;5Q(d>I_6 zw-^>2r$J0_CK8;cCUB1q0k`NlriPgej?lTxlgx9x>vJ3PF7pX<3|yU8m>Vo&ec2E; zj8(EGaAOv*quFZK!9L6`V3)Bi>;_l^4zNerv+Py&PfpBr;X*kjjN%}0IaYF$xre#O zxfi(CxNY2i?kIPTyT<)3l8SnXVns=!Jkdx|jcBT9zG#_fwP>s8eORF{h<+D~#UU_0 zMi{qI;)&uJ;>X1=iZ_b)iVus=i*I;&d3E=S^-A?B@G^V3yykm7@3r1*kJk~e3toRn zd?kG)T1l>Cw8SQvEmp> z6XlcYQ{pqx$L;f+&jz3Oea`s&=IiU*&o|L`xUbch_&(>m$@fFwbH0E21^UJKW%-Tu zYxH~4Z;jtxzf*p{Nu|ow0^lRxK{$2c4{(1gY{~UOIDZ4E_1r9>hgY<3qj(bsGz){i9rj4-U#|U=vr`K za6)id@U-CN!MlUchOi-#A$cKnA&Wvbha3;N)wOrmjINfhk9FP9^+?y7-FkLQ?`G+? zpxef7$GY9>9@;&p`=stqb$`42S3S5MF+GO&nA+o|9`EUNd^F?Dc7{8@>DV9@x8~_w&8q>wUFPNT2jR6Zuc@1wC|q2 zKZFK{W`x#-J{P(_^jcW2ut8ysVa;Kmhu!WM)vvVQ?0y^jeHHE#ZVImsUmCtI{8~ic zh+z>kBi2QH+26arsef(%XZs)Me={;Fazx}Kk#9#{is}}X7d1URd1_)ijRmN9sgAPf%w1GdUYM_Zl^VYn!%dcnw^?owK3XC?Q-oGI;k#KH%qr& z_e(--f+gXlgp>L%`eFJ<^!xOG8H@&pVT0kaF~T^(xWahC6l5wiJ#P9iQIwdOI4f~i z;-5)|Bv;brq@R_Prj5Am10R*m2y6{U#dB^IrVH>XxfCdSJKW72peD?&@$lL z^zihm^wsGXGZYyUGuCJPl&Q{iWNyv8nU$3FP}bgTHhW<9g6z+80&_}pUdZ`6w_k2e z?z-G-1N8%E4BR_NG-$}6rv{zK>z!Abw>IzEVB_G22Jau@H>7yT3q!sg8Z*=}bmuT; z*x+GL4?C0JKi`)Bb^$8LD|ou#tHP+l$%X$KE*@SueEIP2i!?0dvX0t5+G}*#=+&cdjL8}E z%$N&f^<(FcJw7gK+_Z5YjqfqOZv5_YS-H9VtqGzDBPP5);f}e$++w~_kyo*z;#y@^ z<+GJns?w{LR$aEFT9#NYR;N}kslHT`TJv#0nPAZtR zX42id5p^5uCG`{Pch~}LlWhC#eeBchhZ|xW<~N+3oHY5F$=4i19IKt!InKG=6$A&& zPaC5f=QW<2k~U@els~4HO?_)xz%<*mPn%+z9&5TdJ$L%6Gq@R*Gxp64o9Ui;?xBo_ znjgjwS3JCLR`{&Bvo3(U`!%C~ zk0d|x@}u0N)<-{oO!wIHkNv%%YQe_~)eDy`yz_YF;~zhvdE&Vz?mk)lgyxuMT(e?H>* z#n0b)q4tGi%QKg6T+wUAV=HdHSoPwOm(pL_@N(~$7ruP!73(V}n+G;;Yl&=Gwo<%u z%F6Fom90APs_E6Wt9z_oxcaX(wl!y8D|&7JTI1TaulIU=(K=>b-9Bpj z;T?l_?Aw{VbL+oU|5~#vY}fML!Mhi|b|JdQX67<=OE$*Pl=PSu_I<;y8w z-abu0iC^%Q{HtYO_xif!8^t#p&l=9|K9_y&({GEvJ$=6N{FU#V-`%+|_j~F0%P#i4 zxb~9v(yq(7mk<3g=7$Sc8m`>FI{(LjA6NVo{nM78(|`W-+Q@4cesTPA_t(dN>;BuC z>j~HQ-6*{A_3!n+-@duvkM4iG_NVF31Gh%px_Eo)9j`mj{iXP8=ifvAK6AJJ?p@Lw zOg~Q7xHdaeHdr-RIvexB7(|1RI(1qnb5BcCey3;1F=Hl}Zg|^I%M5CGdUzIZ6KXTI zRS9;>76PUxuoc}K50?J?;vtqMz?`&#%?{6*TjH?WT?B)*CjhWC;jLQ97|`fy(PTKK z&I91sW1xjR17NXL;F{eGPT6f}2l^MR@;N#M8pvhPKK=qom^bzX{X+&|uyAmn zWa4aqe-!}is~8|(qrk*J4uD@~&_9;ot@r@`6n~Bn;Ul1ToWWlMgzG%MfG^_9j29Ee zgfsn_7=US|f$ovdj9|txlNdWQm6^#b0r1sw0A0Pw>}Nh=4lzfWubJ?P$)WrrlAiE{G4$c=uuDw{yE+Aqxc#?ZfX0 z%&@fJeW+-BiMi_ocS1An~^_Z+nq5WGZei9 zan1NJd5Y+Sj9;{66rN9F>nr35A$%Im>V#4vZN5rScu~w6{4L1dcOZS=gZy10&yZ#0 zS@Iltp1eSoufadyE8q|O5uZn4sE({4FOq0C&V@V_2BRAfycMulxd2oG7N*e%55%p+ zTmkMk7e%6g={hqzCnq~2%c#uOsI!#`h8&7=%QPyD`UG8u){vWJ$jK61NkWZKI@9bJ zVRn`YIF}JtS8Xxa*Xt~hQZA3~*pg79JioXIfJb%*g<9~~7rMFt@WmqmmVZNN!3bP~6)2iTE>qt?Dq+T;-C=>LWxKItKM-Rn?&d}-&YIsV}7$17bGYM`p44njb z@L%|Ee3wBCCNGhf$t$Fpw2+mn85V^xB1R1VC1e%xcVotled%u&(NWK?fGNrVj2_t3 z;kg)a4f*CN)*8V{7Dq{cAjiQEVy&^!g2muHa+O&vQ-vDZN_Vcb)MbTiRtf~7?c~{< z4ZQn-=4$N>6TtLEF>f$|OcyvJ1v4Q`SEd`&o$0~!WO~7osSkOTtR`#7Yh*2Xovb74 z$s1$?*+@2#H{W1FnJ{FBwJm~*5)%bs1*~$hAXb~nJK#s(L-z7gwGYDYkestqNjCw+GARp&o3Z5ZT5?9!*qecGc3cp<^MW1JCG#hgN~Jp{)?g zcI+bn9UT@YxHouzw{yIQJlMVX#VWi(=!K_I9v5BJxfJ-mJ;|*@D}Xb>PXi>iHpvqr zP!au)oUl6EXz&bj3X=wl43kRUYGwwIEy5s_m9+6c&t<81@{0?Tg{>`2Hj_iPl7F?W zQp_M`C<~1yFhw&Q`D`DX9{3OL4+tn!qdm@?$k+uvF6V%(m0&RBbB>Xj6?m z{6ZM#nP^rE^APhe`G9-`8wlfOW&_o8U=Gh4-QG?qPXRdq6Zpds9dW75qs(J~4TO;p zv@cvDWGNv8p13^d1E{{KR~>W zqIXX5L}uFnhrkwvTxaW-w_GS%Qz zP9Cw;nQK5QjF_tfRuX*THh#lvmDPLm2XsoM?R1m@DD9yqXByzo>D`ldkp*ErL%t%% z$&U~UB=U|E@L*yhmby%ghhtYw`^_OU{vR$$9b} zxj?>O%Up$R6*g8>&-?;Tf;#3pxd@A`fL6W?auQ9h(B<%d(aQfLSSX7C{>Nf+sTKam zat}l+w+-A1ej;-wzbu*@{HI2NLSZAH;U$v43m`VE?ZE`~3X!!}ezT2)9V? zo0% z>51e9`JLP(f2;zzwzH{#MvMkY{u87c6vLi8m=M+kP#r8&srKb8GEe3AV_5HcbWUx( zC{kQ$rw7N-PKkVRxPQ_P9D?#8owD$?(L`hd0o zIQTf>B1f*Z&Si1Xj(ai}u){sd6{NCd z+vLWa8;jjo(oWe-mfYJ8z60eHMy5@5bJ=j1OJX=xL?x@FJ*q4e6b#d5K*~rRrt&6}FjeabrI>mbx*N zm#tz~v9Ch(8aI}^aU>tFr6U;HrYF%$LBdW3`>Co;F#-YnH(BVl6A%H<0ivyJxxDwk zDUs)NHd>q>K5byP!MU8>$ZlfaWH+;Kv0K=!ZXDpofo|Nzjf31c*o{Nnxa%7BZBz%o zW$?6vUwOA1K*w-8?+%j$e!|>1LO7wf9(3Sp6p%%gu;Q#?F!5cDPC-0D4a>1nl?-lu z@hix*1~aIVRdmaDmN+bQ+lErY)hdt9bbnELBF}EJ0Y0~q9{WLo80fG!HoyrU%yxC= z2DtB)*+dUsf==#XkI(=;#7}hXA$#zQ8F0`R&fG?N0M}`?ZAWhQL-u1p zNV6ZgagS#96E{GxTh9T);*i02%ERr0>=6{x!X9D|yKyf!?%e{8x-Z;pV+Ltyh4kUVA1vlrT_`rZw2?|4trW%dePK@I^0 z&Fob-4yU)r_zO$y&+IRBa?T+Kn)w#mQ*N*~+w1$ojr+IPcbmN~Ab|))@p2XYDmW#*P#x!u>fBi2#_?2uG$2PX5&FQ${H;{w_!6MxvsS5z{b#KuA3Xjw)Kze$-z~}RqRo&H@M0B z^308MW2GCbAX4}U9QW{jZ0jXCp6g>?fNA6@w}_^=yi^4kpzLE9vQ zQJ^*)x}AIGm@u>GRtf7;$Gmh)gSf5`=b3aoVp6yw2q_d-p5t)X9ruo{kkr;_=TcN8 zgyrJ?V*COGn>Dq_fGq@81zri^4Tw%^P~`X8%qGFaOQ~&*fcvHNI0s`1acvFrYm8ux z;Kp*}UUB0Ayu!nka}xjs3ZUE;t{fHd`!-j>+eN$FZT)+|sA>~+ZR-eE!&yN%xmq{Q zZssPsaSr8mSR*W9g$_%#1rAA7S#VORfn!$t(IUH*7@J^&rD$$$GG18_z!lts;!e>2 zwGKEs>BdmnR#L(6_y}C6H43eQ`U>;4< z=so9hfsJkF{Zu7+)hQD+3EBFb9CcPgR>s&idu)RGp(CMy zH-8W~8cgsV325mT(FTt`8W|P9Bg?x3KpBqL_NfAqLb%oB-M4dE$GZ3&0>T_N-hVO{ z|A%BCUKJ07b|j)j6#>y2EjY^BuNAgvBF3wy8LQ3O3SG6&c2G>r99>Qqy_eEgk00|Nj1T(wE0XN^NnVy<{4eD9y{u1|H^tWzh=vz$rZ3>TtTC5J0=DEDo@UWzk#mf<-{yR;$2VCnWQ3 zmSJY+B(P?9+H4cmylkP_fsO{g9iSkuYFZn2@*C?bEDnOfZ6cO<6UG~E7<0r+E+Zlm z0JrhW!|w6-4FweMLuf9%9-@VKD%K|A-qPR0?ddmcxl2Ku&L~34l`%q1b>CO z&U(QM5F+8V2ZPvRb}T!It%p|}Oa`ow6JB&M1$6D{>`cH75q35^mserIUm*MfMyk^v z`v{qH|KJ|x8o4Q@RJ*ef>e%d#`oY^X^Z+Ct07RSsBCf)l8UBWMF^GT^Kh~d>!#f!i zY#}?2g>wMwx`&8o*k{@2;k^qlg7VzVt^{3q4ZMG0FZ&hy1Bc=53Aq4ZYUCDkPjN4C z&D=_EHNco&=f31Faz6o#=~wPLcbof*yDP#XRwNg76Gez3MbV-d(PYtd(LB+UqNSqe zMJ=L@qBliviMEP+i522lu@V4iiviBGNxWISMZ8VCUA$AgOZ*OioA!y1iBE`6iBF5a z5`QB;2T-RA;)~+TUShBQUU^=Vyq@xU%j<;K?~-6iA4!-bT+&~nk{Bh4l4MD$WPl_? zk|oKJk9qJwBo!~vtJI{NF_b`A<4fihgF7+PaJ<7Yz+veTi?eKPa zPw}4SJ>7ez_ru=A`$g|v-e-LnpJ<=KJ~p2xeAfGH_1W&T(`Od|sXq5P3Zn~=_cuB=@#iW=||E} zq@PI-N)JnqN{>lTNKZ*mOTUs{l>X}P>)!_ep@aR){ipgb_FwJ4-TzM+l6lDjWqoCl zvS?Y1EKa7A>19S)qAXcvlRYMDk*$+$lWmvnlSwW3xrS>aMlQA|^~6|)s{ z6;CLZDwZjpQ@o&9p;)WfuGp#ArFciNSFumAU-5zBnBs)ul;X7FYsFc`w~Fr+-z#p! z7-Gs}7R0QN`7q`@K)YnIy<+>shQ{`bjfjnmjgHmF8e$oEB0<2j$;81<`w51=Nl)Dlf?zZ#l@-O)N$Ilgg8T-DK054 zB`z&4JuWjYJ1#eFP~6zKS#ew9_QZV~cTLGEBb9pP7^PGBm~xBqUFCk|2g;9>pC~_5 zo>Tsy{8{;n@;BuT6{GT2`KqKU89>assd}h-srsnmREYpLD^r!L>QqiuqiU+ENkssD zHdi%Y^{DCv)k@WN)lSs`)oImFs%xr0<3;g4@gecy08Q&39~GYxUl2b&escU1@rwYc z_H_I+@z2J86n`ZCMEt4v)A3)${}6v8{&xId@psi&?X3<}Ye1_hRadC1)Ya-*b-jAJ zdcJzGdWm|edYSrV^;Y#x^&#~s4X5!2CvK`HU6ZNF)(qE-)Qr}Q)r{9zG&LHlW|F2} z)1+CXY1X{1c|)^N^CrOIj%iM4PHApwL$pcSq1uVshqVi|uW4V`uGenRZqjbnZqaVj zZr6UMJ*YjbJ*qvXJ)u3Ty`a6Qy{x^W{X=_8dq?}X&KIC`GF^Z!L>I2>uZz+tbZNRF zy79URx(Z#Du3A^Co2aYP*>nxMIl6heM|6+r7V4hREz&)uds_F5?pfUy-BI1mgzgCg z63hwn5>_R=m+)!A!GyyJM-$E@Tu8W>a5>>h!jB0*C*09vJ*yY#ee`~Mf4yAaS0AU> z=yiI%K1rXVPt&LC3-lxPcD+l#P`^~aUjL^4BmHsxH~Mq>^ZE<=i~4K&U-j4Zzw7_d z-!iZUsiB)eZAdlb8U`5#8-^P44I>Pr3}X!A;2NyiFw3yQu*Y!HaL(|p;XA`GhUbgB8XqW3{o?INA8H zah~xJ<738!#wEt3#%0FmjmwRzjBgsZ7`GXB7wg-K5) zElz4l+L*K@>FuPQNqds^CB2_?AnDVj<4GryzDv5CbT#Scr0YpHlWry5N%l?dmfSPB zPjXmtL~>-ZF4>Trn4FS4AUPvBKY4g^adKJmsN^xpwE&;AB~MOvB~MA7lRP(hUh*T! zOOsztZb^PM`L*PA$s3Y)B=1Vzll*S-{^SpmKTN)yB1#EN2~O#j(lez`N@$8QMV+Ec zF{C7>B&Q5Y8J<#-G9qPk%D9y36l+Rdiao`V;!1I+JejgGWmC#qDce$Zr0hz0C*_lr zPg6ciIhb-W<$9_#Ri4@JlUTa#K5LODJpJ F{{iH?`-=bo literal 0 HcmV?d00001 diff --git a/SpeedTestTests/ReactiveSwiftTests.swift b/SpeedTestTests/ReactiveSwiftTests.swift new file mode 100644 index 0000000..eb9b06f --- /dev/null +++ b/SpeedTestTests/ReactiveSwiftTests.swift @@ -0,0 +1,308 @@ +// +// ReactiveSwiftTests.swift +// SpeedTestTests +// +// Created by Jakub Olejník on 08/08/2019. +// Copyright © 2019 QuickBird Studios. All rights reserved. +// + +import XCTest +import ReactiveSwift + +class ReactiveSwiftTests: XCTestCase { + + func testPublishSubjectPumping() { + measure { + var sum = 0 + let subject = Signal.pipe() + + let subscription = subject.output + .observeValues { x in + sum += x + } + + for _ in 0 ..< iterations * 100 { + subject.input.send(value: 1) + } + + subscription?.dispose() + + XCTAssertEqual(sum, iterations * 100) + } + } + + func testPublishSubjectPumpingTwoSubscriptions() { + measure { + var sum = 0 + let subject = Signal.pipe() + + let subscription1 = subject.output + .observeValues { x in + sum += x + } + + let subscription2 = subject.output + .observeValues { x in + sum += x + } + + for _ in 0 ..< iterations * 100 { + subject.input.send(value: 1) + } + + subscription1?.dispose() + subscription2?.dispose() + + XCTAssertEqual(sum, iterations * 100 * 2) + } + } + + func testPublishSubjectCreating() { + measure { + var sum = 0 + + for _ in 0 ..< iterations * 10 { + let subject = Signal.pipe() + + let subscription = subject.output + .observeValues { x in + sum += x + } + + for _ in 0 ..< 1 { + subject.input.send(value: 1) + } + + subscription?.dispose() + } + + XCTAssertEqual(sum, iterations * 10) + } + } + + func testMapFilterPumping() { + measure { + var sum = 0 + + let subscription = SignalProducer { observer, _ in + for _ in 0 ..< iterations * 10 { + observer.send(value: 1) + } + observer.sendCompleted() + } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .startWithValues { x in + sum += x + } + + subscription.dispose() + + XCTAssertEqual(sum, iterations * 10) + } + } + + func testMapFilterCreating() { + measure { + var sum = 0 + + for _ in 0 ..< iterations { + let subscription = SignalProducer { observer, _ in + for _ in 0 ..< 1 { + observer.send(value: 1) + } + observer.sendCompleted() + } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .map { $0 }.filter { _ in true } + .startWithValues { x in + sum += x + } + + subscription.dispose() + } + + XCTAssertEqual(sum, iterations) + } + } + + func testFlatMapsPumping() { + measure { + var sum = 0 + + // need to create subexpressions, otherwise compiler is unable to type-check + let partialProducer = SignalProducer { observer, _ in + for _ in 0 ..< iterations * 10 { + observer.send(value: 1) + } + observer.sendCompleted() + } + .flatMap(.merge) { x in SignalProducer(value: x) } + .flatMap(.merge) { x in SignalProducer(value: x) } + .flatMap(.merge) { x in SignalProducer(value: x) } + + let subscription = partialProducer.flatMap(.merge) { x in SignalProducer(value: x) } + .flatMap(.merge) { x in SignalProducer(value: x) } + .startWithValues { x in + sum += x + } + + subscription.dispose() + + XCTAssertEqual(sum, iterations * 10) + } + } + + func testFlatMapsCreating() { + measure { + var sum = 0 + for _ in 0 ..< iterations { + + // need to create subexpressions, otherwise compiler is unable to type-check + let partialProducer = SignalProducer { observer, _ in + for _ in 0 ..< 1 { + observer.send(value: 1) + } + observer.sendCompleted() + } + .flatMap(.merge) { x in SignalProducer(value: x) } + .flatMap(.merge) { x in SignalProducer(value: x) } + .flatMap(.merge) { x in SignalProducer(value: x) } + + let subscription = partialProducer.flatMap(.merge) { x in SignalProducer(value: x) } + .flatMap(.merge) { x in SignalProducer(value: x) } + .startWithValues { x in + sum += x + } + + subscription.dispose() + } + + XCTAssertEqual(sum, iterations) + } + } + + func testFlatMapLatestPumping() { + measure { + var sum = 0 + + // need to create subexpressions, otherwise compiler is unable to type-check + let partialProducer = SignalProducer { observer, _ in + for _ in 0 ..< iterations * 10 { + observer.send(value: 1) + } + observer.sendCompleted() + } + .flatMap(.latest) { x in SignalProducer(value: x) } + .flatMap(.latest) { x in SignalProducer(value: x) } + .flatMap(.latest) { x in SignalProducer(value: x) } + + let subscription = partialProducer.flatMap(.latest) { x in SignalProducer(value: x) } + .flatMap(.latest) { x in SignalProducer(value: x) } + .startWithValues { x in + sum += x + } + + subscription.dispose() + + XCTAssertEqual(sum, iterations * 10) + } + } + + func testFlatMapLatestCreating() { + measure { + var sum = 0 + for _ in 0 ..< iterations { + // need to create subexpressions, otherwise compiler is unable to type-check + let partialProducer = SignalProducer { observer, _ in + for _ in 0 ..< 1 { + observer.send(value: 1) + } + observer.sendCompleted() + } + .flatMap(.latest) { x in SignalProducer(value: x) } + .flatMap(.latest) { x in SignalProducer(value: x) } + .flatMap(.latest) { x in SignalProducer(value: x) } + + let subscription = partialProducer.flatMap(.latest) { x in SignalProducer(value: x) } + .flatMap(.latest) { x in SignalProducer(value: x) } + .startWithValues { x in + sum += x + } + + subscription.dispose() + } + + XCTAssertEqual(sum, iterations) + } + } + + func testCombineLatestPumping() { + measure { + var sum = 0 + var last = SignalProducer.combineLatest( + SignalProducer(value: 1), SignalProducer(value: 1), SignalProducer(value: 1), + SignalProducer { observer, _ in + for _ in 0 ..< iterations * 10 { + observer.send(value: 1) + } + observer.sendCompleted() + }) + .map { x, _, _ ,_ in x } + + for _ in 0 ..< 6 { + last = SignalProducer.combineLatest(SignalProducer(value: 1), SignalProducer(value: 1), SignalProducer(value: 1), last) + .map { x, _, _ ,_ in x } + } + + let subscription = last + .startWithValues { x in + sum += x + } + + subscription.dispose() + + XCTAssertEqual(sum, iterations * 10) + } + } + + func testCombineLatestCreating() { + measure { + var sum = 0 + for _ in 0 ..< iterations { + var last = SignalProducer.combineLatest( + SignalProducer(value: 1), SignalProducer(value: 1), SignalProducer(value: 1), + SignalProducer { observer, _ in + for _ in 0 ..< 1 { + observer.send(value: 1) + } + observer.sendCompleted() + }) + .map { x, _, _ ,_ in x } + + for _ in 0 ..< 6 { + last = SignalProducer.combineLatest(SignalProducer(value: 1), SignalProducer(value: 1), SignalProducer(value: 1), last) + .map { x, _, _ ,_ in x } + } + + let subscription = last + .startWithValues { x in + sum += x + } + + subscription.dispose() + } + + XCTAssertEqual(sum, iterations) + } + } +} + From 4648330fc963de476a67f0b0e0ee8860e78d2bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Olejni=CC=81k?= Date: Thu, 8 Aug 2019 15:39:14 +0200 Subject: [PATCH 2/4] Add comment to podfile --- Podfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile b/Podfile index bc24561..c3938e5 100644 --- a/Podfile +++ b/Podfile @@ -8,5 +8,5 @@ use_frameworks! target "SpeedTestTests" do project 'SpeedTest.xcodeproj' pod 'RxSwift', '~> 5.0' -pod 'ReactiveSwift', :git => "https://github.com/ReactiveCocoa/ReactiveSwift.git", :tag => "6.1.0" +pod 'ReactiveSwift', :git => "https://github.com/ReactiveCocoa/ReactiveSwift.git", :tag => "6.1.0" # version 6.1 is not pushed to trunk end From 1685d09cc457f7f3d045f0f7e3fc23bf12ecab0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Olejni=CC=81k?= Date: Thu, 8 Aug 2019 15:40:03 +0200 Subject: [PATCH 3/4] Remove xcuserdata --- .../xcschemes/Pods-SpeedTestTests.xcscheme | 58 ----------------- .../xcschemes/ReactiveSwift.xcscheme | 60 ------------------ .../xcschemes/RxSwift.xcscheme | 60 ------------------ .../xcschemes/xcschememanagement.plist | 26 -------- .../UserInterfaceState.xcuserstate | Bin 19603 -> 0 bytes 5 files changed, 204 deletions(-) delete mode 100644 Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/Pods-SpeedTestTests.xcscheme delete mode 100644 Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/ReactiveSwift.xcscheme delete mode 100644 Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/RxSwift.xcscheme delete mode 100644 Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 SpeedTest.xcworkspace/xcuserdata/olejnjak.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/Pods-SpeedTestTests.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/Pods-SpeedTestTests.xcscheme deleted file mode 100644 index d542685..0000000 --- a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/Pods-SpeedTestTests.xcscheme +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/ReactiveSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/ReactiveSwift.xcscheme deleted file mode 100644 index ce416bb..0000000 --- a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/ReactiveSwift.xcscheme +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/RxSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/RxSwift.xcscheme deleted file mode 100644 index 7b649f0..0000000 --- a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/RxSwift.xcscheme +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist b/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 009bd3f..0000000 --- a/Pods/Pods.xcodeproj/xcuserdata/olejnjak.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - SchemeUserState - - Pods-SpeedTestTests.xcscheme - - isShown - - - ReactiveSwift.xcscheme - - isShown - - - RxSwift.xcscheme - - isShown - - - - SuppressBuildableAutocreation - - - diff --git a/SpeedTest.xcworkspace/xcuserdata/olejnjak.xcuserdatad/UserInterfaceState.xcuserstate b/SpeedTest.xcworkspace/xcuserdata/olejnjak.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 3cb3bd1a05750a9e5a74fd87a27c4daaee8378b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19603 zcmeHvd3;kv_xH@bH)*=0NlROHXlZGiwn?)zOINx>S=!Q#osza`8)%b~q(A{>!lr@> zBH{urEeIkAh=9NYf{5bICYzvwh=8D?f+(Q8XYOsf0FTe}d*AoZU-L;bch)m!&di)S z=R3Eeq0Z`bsnuT~j2Ofs4vCPMb8@bc5mPJ&y3F?A^P%w%`aY%_&C?2Vi25FHFB_KUYMky#44MoFHF&cqJqOoWk zav~RML{rdIGz~SO>1YO;i3oZGJ&GPfkE18hlV}-w7CncSqZR07vTDh z7f0b}tithFjdSrpJP7CE!FUKBiihERT!0Jla9o6oaS1NP<#+-%;|e?xyKp0(f~VqX zxCu|kbMZVpA3uVh!b|Yecqx7fzl>kOtMF@hJKlkJ;(y^?csG6*@5k@s5AjF%Gkg@E zz+d9C_*eWJzK(C;-|>fy{8Gh$&`Dm{O*UnZTHt3Z{~&VrrQ>rh%Ex%wPyJpLv8?$Sh(OGs~D4 zn3tFqW%#`JUD%#%FE*5oVAZUK)v`J^flX&K*i1Hy&1MI(!`OVbgdN3JvQ?~&wX==v40awn zpIyv8#V%)8urIP}+1J^1?0WVMb`QIkeV5(GzQ^uo-)BEy53rxHpR>o=6YNR$6nl>S zmc7LO#9n7_v43-ZoRstDg18=BBp1a+a|$k=({Tx0Avc^W;)=Nvu9Pd|MsOp!QQT;5 z3^$%Lb5)#$tLEysdaj`~!q!+z8}&hbiHL}a7m*Ne z;zN9iACay_VW=MpM-iw$ibPQ;8YzfBk&%&P44Fh0k;P;Qd79{etW1Z+JgLEMwYi)b zl`iWPv&&LdF7J_TsWvy(xpJzkF1w@H1+mUtyQ8#dsBB_R#H`H06!a_Rhoi6CHP%P8zv{dm0t*)jbOM~43tdM!QGQw)B zvQKpa6+$S(;V|23pf#H-+fvb3lV_{8L-t}z9jqXhsQ2{DM!$%7uXfxMaMhZcTvoyaLn9u^rMI-Zz3;1=nBY9;!DIw)@ zzN-IgQi>ZamZ}nv0s3{u7g@|yoGd)ae3Z&bsqfhG7{29hCrA5g6ycAyjb#+px6D0wf3pQtTt=CxuIMh_P}H+W?6RF5Y06( zz4|^dPo8ax)oHD$v%n+?zduK%!(La%Pg<3|y4q=h$#s7{E_+Q)ouw+Pmd-7x=K<7o zsHYC(uU!7%4rMgDYV8iF;{Iehw{q=uRUpMj5M4VTLbICD!z6-43D0gcYZaOe9ELCH z4}7KHD7l{;2{OF^Eri)aSAeD#v;Y-J!uMQ5{GVqkE<#ICU<+D|o+7a%t_3}fmJ%gV zk@zu`<~&=KWtzn~zN&S_9cr=FxN3#ApGUJ^AyEN%q|nrh=%umw#o1O6Tf5Edfc9QQ zMV?k(K`Uu1&8UTFh_*v3rPa{A`|GFk@pZJWT;3(Wcvz#$3}e+^^GZnSQ1=_?Z7P-< z&_=Wgy@@uXx6l@}6>TGWVjxChB8eo4B$E`9x)yD36U*JaSnefhZDN_pi)GILilsy4 zgn9Nq5z9}hSbjzZc*OD$70bgQgYYHkB!mA($-B#?9)UQ8&In?68pJM(3dGkScG)EU z9#IR3y6q`)9(^y!&;^j8+<#xhlm9CEoyx_J=qL0ux`uv1zoOsJb##LaB6(ym8A67V zVI-dvkixa-W}95x;pO5k8Qvxr#k^dU{jXg7kL3dUf?QxfQq(FJSVrZ-E_{Hi!Y8VA zz;Foe&dUVu1~O3s1B`ouOqAX)6a7B)6bZ%QyiDMJAQL10eGyN71&&35%{YdPYQ}M7 zG>IPvnoB-x_r)#;EV858_Cikq4NgXZYq1vVa01q212$q4PQ*!MEEz|}lX5bFm`Mex zBvos13J6gh9)Qzv2F}D;D2!P69j}_ykXm9T6X7X-l*{a>vABw}hm5v5bLy-$bRR00 zhX~QxmMPXsOP+It6%-wd6E+2TTmCY$!)m5VZ&1g)L+zEVI%A*^ok0(TE>P_n9Z+v; zq)>0Jx!zjWR4xzhSivyZW9sOxc^?s3c3Y(b^iNoYtqrwyo5g9ZZv^$r?$GE|YEU8X zi7l6>RZVeK@m)~fla^%A<>X{$=yl4>tei|`f-X^`G-HzJZub=_XrP-IB!%3URAO~eg%LJmT#2o(;wo&x)wl-N zk_IxB%pkMKT=Im6-bvU_>8-={*hVH32XU^%4R|tk5Ep4AQz*TW_qEW8yh4Z7?f@;n zTps(+88gk5lZq`3W(OUga=GH4a|>;hnd=%Y;pq}VBdA27{TUQ`{~VZsXWiEeg5ALN zX{3pAJv?2g0Syl=&1|&RReAdVD1Q9Dl270#@gg#lJVYL*CFMfVqNE2j{0x5nzTz+7 z<#+`l#7$;H@d2&cOe^h2a5Icc3tmZ&3{_^Axga3qkqVDF1v4xs61!*rmu3`sn3qH* z@6oeYWK^u)U^Im#rsm`h9F$j3TsC@KjmQ4qDkN934O#%5cH5 zQqkzLIN?AWO4w1wjg^(4=Ub|d1_b(a3F-cTV{l7QFyV-(rE51hmG&UPW%lYr;A5w~~(=E_$b#9%x#!1yLi?h;UZ2%E~M7pkpr$-754tP`! zCtNSmeY~nTH@~>VGR>vT1l{Y1PqZQi6mg-I_VOJ_??${SxpC@*l}c5-a7JFK(dvj4 z7Bm^@3Nr|ZE1^`D=9M}@@op>3D{wS{651g))KehWVx|jKvBd?4-x_C!EHa@+N+VzA zkwBlMl;&h2Cn1!Yw2ba81JdCT8rYJVMY_OgFt}Xa6Uulhq^DcEBd-ePxV749fjQB& zEw!Yn!P1^0M{@Cz!9#`)d(iQ(vraoSzwHbNB?^a+Z&Ocs9eZVAQNBmthV+usf1|*b z49$n+5hG!FznAYVqw*gR3%SRPZIy(UG5N>FmrpSJR8&@3s-d|NbiD^U=|TtVCah`v z0|-kowU)pp0BMa*m%W~sAU-lvjk46C8aWF`x4vK0S||EUsvB5el3$#c4F}%5tSqRP z-x=iIaJ1`l#O~8D8KPPzRX{C50k!6ahB^kMtKQ~v3@pkRHFDJGP_Hv!cczKQp!Ur7sTwy83|htMg4tsrUyo1|wU*F)LLGLfhd$AI zFY$4et?j9xy{ta3f+;=}3@%q8y%s{lz?e>BrU8BR@S6p(jgVFY;f}3nL5{RwtfI6E zG|+U~%H`Hp>`YN8{o>@;o#9p!?Tl&bsW0@@NC z5gihJE&2k5!tZyYW1>qCIxRW_pHpr06axJod7!)(B%lU(Ej+bLRwW-p$D$5CbX@MI zvwh5jdT5>wHDH!+m-Z-wuZ5=8!|n06}fl_;p~z|39U zQ0Vc;_kM&z*UNW&*w(wyW8C(!NBs`WthO!g(a(#%hzi!W=KB4|meN5d9DOcF1*{$qub_ctY{S<}5(@t)UlqzCk znNVnEH-0!y--+M~QR9QGDHe@5I^SLE>B# zD%Q|=alCjigcE5l7wFiq-=HjeLzBZ=Q|k)N04>K7nrEw2#f56s8ra>a&P4Md^xJS= z7s4T*RyI1O2yq@j&eW;C_p7>6dDixsD+Vq0B2_+ zH=2(Yf=Txo^a40)SAm;$1DHkMM!V3v;HLcq9YV*@Y1mILpetY)`yJf|_pBF|;x4#5 zIAiU2vry#;5Q(d>I_6 zw-^>2r$J0_CK8;cCUB1q0k`NlriPgej?lTxlgx9x>vJ3PF7pX<3|yU8m>Vo&ec2E; zj8(EGaAOv*quFZK!9L6`V3)Bi>;_l^4zNerv+Py&PfpBr;X*kjjN%}0IaYF$xre#O zxfi(CxNY2i?kIPTyT<)3l8SnXVns=!Jkdx|jcBT9zG#_fwP>s8eORF{h<+D~#UU_0 zMi{qI;)&uJ;>X1=iZ_b)iVus=i*I;&d3E=S^-A?B@G^V3yykm7@3r1*kJk~e3toRn zd?kG)T1l>Cw8SQvEmp> z6XlcYQ{pqx$L;f+&jz3Oea`s&=IiU*&o|L`xUbch_&(>m$@fFwbH0E21^UJKW%-Tu zYxH~4Z;jtxzf*p{Nu|ow0^lRxK{$2c4{(1gY{~UOIDZ4E_1r9>hgY<3qj(bsGz){i9rj4-U#|U=vr`K za6)id@U-CN!MlUchOi-#A$cKnA&Wvbha3;N)wOrmjINfhk9FP9^+?y7-FkLQ?`G+? zpxef7$GY9>9@;&p`=stqb$`42S3S5MF+GO&nA+o|9`EUNd^F?Dc7{8@>DV9@x8~_w&8q>wUFPNT2jR6Zuc@1wC|q2 zKZFK{W`x#-J{P(_^jcW2ut8ysVa;Kmhu!WM)vvVQ?0y^jeHHE#ZVImsUmCtI{8~ic zh+z>kBi2QH+26arsef(%XZs)Me={;Fazx}Kk#9#{is}}X7d1URd1_)ijRmN9sgAPf%w1GdUYM_Zl^VYn!%dcnw^?owK3XC?Q-oGI;k#KH%qr& z_e(--f+gXlgp>L%`eFJ<^!xOG8H@&pVT0kaF~T^(xWahC6l5wiJ#P9iQIwdOI4f~i z;-5)|Bv;brq@R_Prj5Am10R*m2y6{U#dB^IrVH>XxfCdSJKW72peD?&@$lL z^zihm^wsGXGZYyUGuCJPl&Q{iWNyv8nU$3FP}bgTHhW<9g6z+80&_}pUdZ`6w_k2e z?z-G-1N8%E4BR_NG-$}6rv{zK>z!Abw>IzEVB_G22Jau@H>7yT3q!sg8Z*=}bmuT; z*x+GL4?C0JKi`)Bb^$8LD|ou#tHP+l$%X$KE*@SueEIP2i!?0dvX0t5+G}*#=+&cdjL8}E z%$N&f^<(FcJw7gK+_Z5YjqfqOZv5_YS-H9VtqGzDBPP5);f}e$++w~_kyo*z;#y@^ z<+GJns?w{LR$aEFT9#NYR;N}kslHT`TJv#0nPAZtR zX42id5p^5uCG`{Pch~}LlWhC#eeBchhZ|xW<~N+3oHY5F$=4i19IKt!InKG=6$A&& zPaC5f=QW<2k~U@els~4HO?_)xz%<*mPn%+z9&5TdJ$L%6Gq@R*Gxp64o9Ui;?xBo_ znjgjwS3JCLR`{&Bvo3(U`!%C~ zk0d|x@}u0N)<-{oO!wIHkNv%%YQe_~)eDy`yz_YF;~zhvdE&Vz?mk)lgyxuMT(e?H>* z#n0b)q4tGi%QKg6T+wUAV=HdHSoPwOm(pL_@N(~$7ruP!73(V}n+G;;Yl&=Gwo<%u z%F6Fom90APs_E6Wt9z_oxcaX(wl!y8D|&7JTI1TaulIU=(K=>b-9Bpj z;T?l_?Aw{VbL+oU|5~#vY}fML!Mhi|b|JdQX67<=OE$*Pl=PSu_I<;y8w z-abu0iC^%Q{HtYO_xif!8^t#p&l=9|K9_y&({GEvJ$=6N{FU#V-`%+|_j~F0%P#i4 zxb~9v(yq(7mk<3g=7$Sc8m`>FI{(LjA6NVo{nM78(|`W-+Q@4cesTPA_t(dN>;BuC z>j~HQ-6*{A_3!n+-@duvkM4iG_NVF31Gh%px_Eo)9j`mj{iXP8=ifvAK6AJJ?p@Lw zOg~Q7xHdaeHdr-RIvexB7(|1RI(1qnb5BcCey3;1F=Hl}Zg|^I%M5CGdUzIZ6KXTI zRS9;>76PUxuoc}K50?J?;vtqMz?`&#%?{6*TjH?WT?B)*CjhWC;jLQ97|`fy(PTKK z&I91sW1xjR17NXL;F{eGPT6f}2l^MR@;N#M8pvhPKK=qom^bzX{X+&|uyAmn zWa4aqe-!}is~8|(qrk*J4uD@~&_9;ot@r@`6n~Bn;Ul1ToWWlMgzG%MfG^_9j29Ee zgfsn_7=US|f$ovdj9|txlNdWQm6^#b0r1sw0A0Pw>}Nh=4lzfWubJ?P$)WrrlAiE{G4$c=uuDw{yE+Aqxc#?ZfX0 z%&@fJeW+-BiMi_ocS1An~^_Z+nq5WGZei9 zan1NJd5Y+Sj9;{66rN9F>nr35A$%Im>V#4vZN5rScu~w6{4L1dcOZS=gZy10&yZ#0 zS@Iltp1eSoufadyE8q|O5uZn4sE({4FOq0C&V@V_2BRAfycMulxd2oG7N*e%55%p+ zTmkMk7e%6g={hqzCnq~2%c#uOsI!#`h8&7=%QPyD`UG8u){vWJ$jK61NkWZKI@9bJ zVRn`YIF}JtS8Xxa*Xt~hQZA3~*pg79JioXIfJb%*g<9~~7rMFt@WmqmmVZNN!3bP~6)2iTE>qt?Dq+T;-C=>LWxKItKM-Rn?&d}-&YIsV}7$17bGYM`p44njb z@L%|Ee3wBCCNGhf$t$Fpw2+mn85V^xB1R1VC1e%xcVotled%u&(NWK?fGNrVj2_t3 z;kg)a4f*CN)*8V{7Dq{cAjiQEVy&^!g2muHa+O&vQ-vDZN_Vcb)MbTiRtf~7?c~{< z4ZQn-=4$N>6TtLEF>f$|OcyvJ1v4Q`SEd`&o$0~!WO~7osSkOTtR`#7Yh*2Xovb74 z$s1$?*+@2#H{W1FnJ{FBwJm~*5)%bs1*~$hAXb~nJK#s(L-z7gwGYDYkestqNjCw+GARp&o3Z5ZT5?9!*qecGc3cp<^MW1JCG#hgN~Jp{)?g zcI+bn9UT@YxHouzw{yIQJlMVX#VWi(=!K_I9v5BJxfJ-mJ;|*@D}Xb>PXi>iHpvqr zP!au)oUl6EXz&bj3X=wl43kRUYGwwIEy5s_m9+6c&t<81@{0?Tg{>`2Hj_iPl7F?W zQp_M`C<~1yFhw&Q`D`DX9{3OL4+tn!qdm@?$k+uvF6V%(m0&RBbB>Xj6?m z{6ZM#nP^rE^APhe`G9-`8wlfOW&_o8U=Gh4-QG?qPXRdq6Zpds9dW75qs(J~4TO;p zv@cvDWGNv8p13^d1E{{KR~>W zqIXX5L}uFnhrkwvTxaW-w_GS%Qz zP9Cw;nQK5QjF_tfRuX*THh#lvmDPLm2XsoM?R1m@DD9yqXByzo>D`ldkp*ErL%t%% z$&U~UB=U|E@L*yhmby%ghhtYw`^_OU{vR$$9b} zxj?>O%Up$R6*g8>&-?;Tf;#3pxd@A`fL6W?auQ9h(B<%d(aQfLSSX7C{>Nf+sTKam zat}l+w+-A1ej;-wzbu*@{HI2NLSZAH;U$v43m`VE?ZE`~3X!!}ezT2)9V? zo0% z>51e9`JLP(f2;zzwzH{#MvMkY{u87c6vLi8m=M+kP#r8&srKb8GEe3AV_5HcbWUx( zC{kQ$rw7N-PKkVRxPQ_P9D?#8owD$?(L`hd0o zIQTf>B1f*Z&Si1Xj(ai}u){sd6{NCd z+vLWa8;jjo(oWe-mfYJ8z60eHMy5@5bJ=j1OJX=xL?x@FJ*q4e6b#d5K*~rRrt&6}FjeabrI>mbx*N zm#tz~v9Ch(8aI}^aU>tFr6U;HrYF%$LBdW3`>Co;F#-YnH(BVl6A%H<0ivyJxxDwk zDUs)NHd>q>K5byP!MU8>$ZlfaWH+;Kv0K=!ZXDpofo|Nzjf31c*o{Nnxa%7BZBz%o zW$?6vUwOA1K*w-8?+%j$e!|>1LO7wf9(3Sp6p%%gu;Q#?F!5cDPC-0D4a>1nl?-lu z@hix*1~aIVRdmaDmN+bQ+lErY)hdt9bbnELBF}EJ0Y0~q9{WLo80fG!HoyrU%yxC= z2DtB)*+dUsf==#XkI(=;#7}hXA$#zQ8F0`R&fG?N0M}`?ZAWhQL-u1p zNV6ZgagS#96E{GxTh9T);*i02%ERr0>=6{x!X9D|yKyf!?%e{8x-Z;pV+Ltyh4kUVA1vlrT_`rZw2?|4trW%dePK@I^0 z&Fob-4yU)r_zO$y&+IRBa?T+Kn)w#mQ*N*~+w1$ojr+IPcbmN~Ab|))@p2XYDmW#*P#x!u>fBi2#_?2uG$2PX5&FQ${H;{w_!6MxvsS5z{b#KuA3Xjw)Kze$-z~}RqRo&H@M0B z^308MW2GCbAX4}U9QW{jZ0jXCp6g>?fNA6@w}_^=yi^4kpzLE9vQ zQJ^*)x}AIGm@u>GRtf7;$Gmh)gSf5`=b3aoVp6yw2q_d-p5t)X9ruo{kkr;_=TcN8 zgyrJ?V*COGn>Dq_fGq@81zri^4Tw%^P~`X8%qGFaOQ~&*fcvHNI0s`1acvFrYm8ux z;Kp*}UUB0Ayu!nka}xjs3ZUE;t{fHd`!-j>+eN$FZT)+|sA>~+ZR-eE!&yN%xmq{Q zZssPsaSr8mSR*W9g$_%#1rAA7S#VORfn!$t(IUH*7@J^&rD$$$GG18_z!lts;!e>2 zwGKEs>BdmnR#L(6_y}C6H43eQ`U>;4< z=so9hfsJkF{Zu7+)hQD+3EBFb9CcPgR>s&idu)RGp(CMy zH-8W~8cgsV325mT(FTt`8W|P9Bg?x3KpBqL_NfAqLb%oB-M4dE$GZ3&0>T_N-hVO{ z|A%BCUKJ07b|j)j6#>y2EjY^BuNAgvBF3wy8LQ3O3SG6&c2G>r99>Qqy_eEgk00|Nj1T(wE0XN^NnVy<{4eD9y{u1|H^tWzh=vz$rZ3>TtTC5J0=DEDo@UWzk#mf<-{yR;$2VCnWQ3 zmSJY+B(P?9+H4cmylkP_fsO{g9iSkuYFZn2@*C?bEDnOfZ6cO<6UG~E7<0r+E+Zlm z0JrhW!|w6-4FweMLuf9%9-@VKD%K|A-qPR0?ddmcxl2Ku&L~34l`%q1b>CO z&U(QM5F+8V2ZPvRb}T!It%p|}Oa`ow6JB&M1$6D{>`cH75q35^mserIUm*MfMyk^v z`v{qH|KJ|x8o4Q@RJ*ef>e%d#`oY^X^Z+Ct07RSsBCf)l8UBWMF^GT^Kh~d>!#f!i zY#}?2g>wMwx`&8o*k{@2;k^qlg7VzVt^{3q4ZMG0FZ&hy1Bc=53Aq4ZYUCDkPjN4C z&D=_EHNco&=f31Faz6o#=~wPLcbof*yDP#XRwNg76Gez3MbV-d(PYtd(LB+UqNSqe zMJ=L@qBliviMEP+i522lu@V4iiviBGNxWISMZ8VCUA$AgOZ*OioA!y1iBE`6iBF5a z5`QB;2T-RA;)~+TUShBQUU^=Vyq@xU%j<;K?~-6iA4!-bT+&~nk{Bh4l4MD$WPl_? zk|oKJk9qJwBo!~vtJI{NF_b`A<4fihgF7+PaJ<7Yz+veTi?eKPa zPw}4SJ>7ez_ru=A`$g|v-e-LnpJ<=KJ~p2xeAfGH_1W&T(`Od|sXq5P3Zn~=_cuB=@#iW=||E} zq@PI-N)JnqN{>lTNKZ*mOTUs{l>X}P>)!_ep@aR){ipgb_FwJ4-TzM+l6lDjWqoCl zvS?Y1EKa7A>19S)qAXcvlRYMDk*$+$lWmvnlSwW3xrS>aMlQA|^~6|)s{ z6;CLZDwZjpQ@o&9p;)WfuGp#ArFciNSFumAU-5zBnBs)ul;X7FYsFc`w~Fr+-z#p! z7-Gs}7R0QN`7q`@K)YnIy<+>shQ{`bjfjnmjgHmF8e$oEB0<2j$;81<`w51=Nl)Dlf?zZ#l@-O)N$Ilgg8T-DK054 zB`z&4JuWjYJ1#eFP~6zKS#ew9_QZV~cTLGEBb9pP7^PGBm~xBqUFCk|2g;9>pC~_5 zo>Tsy{8{;n@;BuT6{GT2`KqKU89>assd}h-srsnmREYpLD^r!L>QqiuqiU+ENkssD zHdi%Y^{DCv)k@WN)lSs`)oImFs%xr0<3;g4@gecy08Q&39~GYxUl2b&escU1@rwYc z_H_I+@z2J86n`ZCMEt4v)A3)${}6v8{&xId@psi&?X3<}Ye1_hRadC1)Ya-*b-jAJ zdcJzGdWm|edYSrV^;Y#x^&#~s4X5!2CvK`HU6ZNF)(qE-)Qr}Q)r{9zG&LHlW|F2} z)1+CXY1X{1c|)^N^CrOIj%iM4PHApwL$pcSq1uVshqVi|uW4V`uGenRZqjbnZqaVj zZr6UMJ*YjbJ*qvXJ)u3Ty`a6Qy{x^W{X=_8dq?}X&KIC`GF^Z!L>I2>uZz+tbZNRF zy79URx(Z#Du3A^Co2aYP*>nxMIl6heM|6+r7V4hREz&)uds_F5?pfUy-BI1mgzgCg z63hwn5>_R=m+)!A!GyyJM-$E@Tu8W>a5>>h!jB0*C*09vJ*yY#ee`~Mf4yAaS0AU> z=yiI%K1rXVPt&LC3-lxPcD+l#P`^~aUjL^4BmHsxH~Mq>^ZE<=i~4K&U-j4Zzw7_d z-!iZUsiB)eZAdlb8U`5#8-^P44I>Pr3}X!A;2NyiFw3yQu*Y!HaL(|p;XA`GhUbgB8XqW3{o?INA8H zah~xJ<738!#wEt3#%0FmjmwRzjBgsZ7`GXB7wg-K5) zElz4l+L*K@>FuPQNqds^CB2_?AnDVj<4GryzDv5CbT#Scr0YpHlWry5N%l?dmfSPB zPjXmtL~>-ZF4>Trn4FS4AUPvBKY4g^adKJmsN^xpwE&;AB~MOvB~MA7lRP(hUh*T! zOOsztZb^PM`L*PA$s3Y)B=1Vzll*S-{^SpmKTN)yB1#EN2~O#j(lez`N@$8QMV+Ec zF{C7>B&Q5Y8J<#-G9qPk%D9y36l+Rdiao`V;!1I+JejgGWmC#qDce$Zr0hz0C*_lr zPg6ciIhb-W<$9_#Ri4@JlUTa#K5LODJpJ F{{iH?`-=bo From 895b4548a697ba374425a5c520103e9bf2afa104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Olejni=CC=81k?= Date: Thu, 8 Aug 2019 20:27:54 +0200 Subject: [PATCH 4/4] Remove sendCompleted() --- SpeedTestTests/ReactiveSwiftTests.swift | 8 -------- 1 file changed, 8 deletions(-) diff --git a/SpeedTestTests/ReactiveSwiftTests.swift b/SpeedTestTests/ReactiveSwiftTests.swift index eb9b06f..9b441db 100644 --- a/SpeedTestTests/ReactiveSwiftTests.swift +++ b/SpeedTestTests/ReactiveSwiftTests.swift @@ -88,7 +88,6 @@ class ReactiveSwiftTests: XCTestCase { for _ in 0 ..< iterations * 10 { observer.send(value: 1) } - observer.sendCompleted() } .map { $0 }.filter { _ in true } .map { $0 }.filter { _ in true } @@ -115,7 +114,6 @@ class ReactiveSwiftTests: XCTestCase { for _ in 0 ..< 1 { observer.send(value: 1) } - observer.sendCompleted() } .map { $0 }.filter { _ in true } .map { $0 }.filter { _ in true } @@ -143,7 +141,6 @@ class ReactiveSwiftTests: XCTestCase { for _ in 0 ..< iterations * 10 { observer.send(value: 1) } - observer.sendCompleted() } .flatMap(.merge) { x in SignalProducer(value: x) } .flatMap(.merge) { x in SignalProducer(value: x) } @@ -171,7 +168,6 @@ class ReactiveSwiftTests: XCTestCase { for _ in 0 ..< 1 { observer.send(value: 1) } - observer.sendCompleted() } .flatMap(.merge) { x in SignalProducer(value: x) } .flatMap(.merge) { x in SignalProducer(value: x) } @@ -199,7 +195,6 @@ class ReactiveSwiftTests: XCTestCase { for _ in 0 ..< iterations * 10 { observer.send(value: 1) } - observer.sendCompleted() } .flatMap(.latest) { x in SignalProducer(value: x) } .flatMap(.latest) { x in SignalProducer(value: x) } @@ -226,7 +221,6 @@ class ReactiveSwiftTests: XCTestCase { for _ in 0 ..< 1 { observer.send(value: 1) } - observer.sendCompleted() } .flatMap(.latest) { x in SignalProducer(value: x) } .flatMap(.latest) { x in SignalProducer(value: x) } @@ -254,7 +248,6 @@ class ReactiveSwiftTests: XCTestCase { for _ in 0 ..< iterations * 10 { observer.send(value: 1) } - observer.sendCompleted() }) .map { x, _, _ ,_ in x } @@ -284,7 +277,6 @@ class ReactiveSwiftTests: XCTestCase { for _ in 0 ..< 1 { observer.send(value: 1) } - observer.sendCompleted() }) .map { x, _, _ ,_ in x }