From c8ec89bae0d10dc287547dba3e29963ec5c6eeb4 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 2 Feb 2017 18:59:18 +0300 Subject: [PATCH] no message --- SSignalKit.xcodeproj/project.pbxproj | 413 +++++++++++++++++- SSignalKit/SQueue.h | 1 + SSignalKit/SQueue.m | 14 + SSignalKit/SSignal+Catch.h | 1 + SSignalKit/SSignal+Catch.m | 53 +++ SSignalKit/SSignal+Mapping.h | 1 + SSignalKit/SSignal+Mapping.m | 43 ++ SSignalKit/SSignal+Meta.h | 2 + SSignalKit/SSignal+Meta.m | 36 +- SSignalKitTests/SSignalBasicTests.m | 59 +++ SwiftSignalKit copy-Info.plist | 26 ++ SwiftSignalKit/Atomic.swift | 27 +- SwiftSignalKit/Bag.swift | 50 ++- SwiftSignalKit/Disposable.swift | 70 +-- SwiftSignalKit/Lock.swift | 19 + SwiftSignalKit/Multicast.swift | 88 ++++ SwiftSignalKit/Promise.swift | 86 +++- SwiftSignalKit/Queue.swift | 75 ++-- SwiftSignalKit/Signal.swift | 46 +- SwiftSignalKit/Signal_Catch.swift | 164 +++---- SwiftSignalKit/Signal_Combine.swift | 30 +- SwiftSignalKit/Signal_Dispatch.swift | 180 ++++---- SwiftSignalKit/Signal_Mapping.swift | 102 ++++- SwiftSignalKit/Signal_Materialize.swift | 40 ++ SwiftSignalKit/Signal_Merge.swift | 7 + SwiftSignalKit/Signal_Meta.swift | 109 +++-- SwiftSignalKit/Signal_Reduce.swift | 88 ++-- SwiftSignalKit/Signal_SideEffects.swift | 143 ++++-- SwiftSignalKit/Signal_Single.swift | 8 +- SwiftSignalKit/Signal_Take.swift | 48 +- SwiftSignalKit/Signal_Timing.swift | 90 ++-- SwiftSignalKit/Subscriber.swift | 43 +- SwiftSignalKit/ThreadPool.swift | 36 +- SwiftSignalKit/Timer.swift | 29 +- .../{Pipe.swift => ValuePipe.swift} | 9 +- SwiftSignalKitMac/Info.plist | 26 ++ SwiftSignalKitMac/SwiftSignalKitMac.h | 19 + SwiftSignalKitTests/DeallocatingObject.swift | 2 +- SwiftSignalKitTests/PerformanceTests.swift | 166 +++++++ .../SwiftSignalKitBasicTests.swift | 64 +-- .../SwiftSignalKitFunctionsTests.swift | 134 +++--- 41 files changed, 2034 insertions(+), 613 deletions(-) create mode 100644 SwiftSignalKit copy-Info.plist create mode 100644 SwiftSignalKit/Lock.swift create mode 100644 SwiftSignalKit/Multicast.swift create mode 100644 SwiftSignalKit/Signal_Materialize.swift create mode 100644 SwiftSignalKit/Signal_Merge.swift rename SwiftSignalKit/{Pipe.swift => ValuePipe.swift} (81%) create mode 100644 SwiftSignalKitMac/Info.plist create mode 100644 SwiftSignalKitMac/SwiftSignalKitMac.h create mode 100644 SwiftSignalKitTests/PerformanceTests.swift diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 9d389f62c6..878cb2b0b2 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -67,7 +67,7 @@ D0085B531B282BEE00EAF753 /* ThreadPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3F1B282BEE00EAF753 /* ThreadPool.swift */; }; D0085B541B282BEE00EAF753 /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B401B282BEE00EAF753 /* Timer.swift */; }; D0085B551B282BEE00EAF753 /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B411B282BEE00EAF753 /* Queue.swift */; }; - D0085B561B282BEE00EAF753 /* Pipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B421B282BEE00EAF753 /* Pipe.swift */; }; + D0085B561B282BEE00EAF753 /* ValuePipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B421B282BEE00EAF753 /* ValuePipe.swift */; }; D0085B571B282BEE00EAF753 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B431B282BEE00EAF753 /* Bag.swift */; }; D0085B581B282BEE00EAF753 /* Signal_Take.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B441B282BEE00EAF753 /* Signal_Take.swift */; }; D0085B591B282BEE00EAF753 /* Signal_Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B451B282BEE00EAF753 /* Signal_Catch.swift */; }; @@ -83,14 +83,44 @@ D0085B661B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B631B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift */; }; D0085B671B282C2800EAF753 /* DeallocatingObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B641B282C2800EAF753 /* DeallocatingObject.swift */; }; D0085B681B282C2800EAF753 /* SwiftSignalKitBasicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B651B282C2800EAF753 /* SwiftSignalKitBasicTests.swift */; }; + D02720B11CD0E005006F1506 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02720B01CD0E005006F1506 /* PerformanceTests.swift */; }; D0445DE41A7C2CA500267924 /* SSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0445DD81A7C2CA500267924 /* SSignalKit.framework */; }; D0445E571A7C3FB400267924 /* SDisposableTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E561A7C3FB400267924 /* SDisposableTests.m */; }; + D05F09A81C9EF77100BB6F96 /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05F09A71C9EF77100BB6F96 /* Multicast.swift */; }; + D066BD0A1C7FE06700D7A576 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D066BD091C7FE06700D7A576 /* Lock.swift */; }; D06F106C1A85561E00485185 /* SSignalBasicTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D06F106B1A85561E00485185 /* SSignalBasicTests.m */; }; D06F10711A855E2D00485185 /* DeallocatingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D06F10701A855E2D00485185 /* DeallocatingObject.m */; }; D06F10731A85882000485185 /* SSignalPerformanceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D06F10721A85882000485185 /* SSignalPerformanceTests.m */; }; D07A5CFD1BBDE6E400451791 /* Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07A5CFC1BBDE6E400451791 /* Promise.swift */; }; D09FD73E1BA9BAB900FF0A4F /* SVariable.h in Headers */ = {isa = PBXBuildFile; fileRef = D09FD73C1BA9BAB900FF0A4F /* SVariable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D09FD73F1BA9BAB900FF0A4F /* SVariable.m in Sources */ = {isa = PBXBuildFile; fileRef = D09FD73D1BA9BAB900FF0A4F /* SVariable.m */; }; + D0B417F11D7DFA63004562A4 /* SwiftSignalKitMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B417EF1D7DFA63004562A4 /* SwiftSignalKitMac.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0B417F61D7DFAAB004562A4 /* Signal_Timing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3C1B282BEE00EAF753 /* Signal_Timing.swift */; }; + D0B417F71D7DFAAB004562A4 /* Signal_SideEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3D1B282BEE00EAF753 /* Signal_SideEffects.swift */; }; + D0B417F81D7DFAAB004562A4 /* Signal_Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3E1B282BEE00EAF753 /* Signal_Dispatch.swift */; }; + D0B417F91D7DFAAB004562A4 /* ThreadPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3F1B282BEE00EAF753 /* ThreadPool.swift */; }; + D0B417FA1D7DFAAB004562A4 /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B401B282BEE00EAF753 /* Timer.swift */; }; + D0B417FB1D7DFAAB004562A4 /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B411B282BEE00EAF753 /* Queue.swift */; }; + D0B417FC1D7DFAAB004562A4 /* ValuePipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B421B282BEE00EAF753 /* ValuePipe.swift */; }; + D0B417FD1D7DFAAB004562A4 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B431B282BEE00EAF753 /* Bag.swift */; }; + D0B417FE1D7DFAAB004562A4 /* Signal_Take.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B441B282BEE00EAF753 /* Signal_Take.swift */; }; + D0B417FF1D7DFAAB004562A4 /* Signal_Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B451B282BEE00EAF753 /* Signal_Catch.swift */; }; + D0B418001D7DFAAB004562A4 /* Signal_Single.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B461B282BEE00EAF753 /* Signal_Single.swift */; }; + D0B418011D7DFAAB004562A4 /* Signal_Meta.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B471B282BEE00EAF753 /* Signal_Meta.swift */; }; + D0B418021D7DFAAB004562A4 /* Signal_Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B481B282BEE00EAF753 /* Signal_Combine.swift */; }; + D0B418031D7DFAAB004562A4 /* Signal_Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FC1A391CA3284F0056AE9A /* Signal_Merge.swift */; }; + D0B418041D7DFAAB004562A4 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B491B282BEE00EAF753 /* Atomic.swift */; }; + D0B418051D7DFAAB004562A4 /* Signal_Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4A1B282BEE00EAF753 /* Signal_Reduce.swift */; }; + D0B418061D7DFAAB004562A4 /* Signal_Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CD17B11CC17C83007C5650 /* Signal_Materialize.swift */; }; + D0B418071D7DFAAB004562A4 /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4B1B282BEE00EAF753 /* Signal.swift */; }; + D0B418081D7DFAAB004562A4 /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4C1B282BEE00EAF753 /* Disposable.swift */; }; + D0B418091D7DFAAB004562A4 /* Signal_Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4D1B282BEE00EAF753 /* Signal_Mapping.swift */; }; + D0B4180A1D7DFAAB004562A4 /* Subscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4E1B282BEE00EAF753 /* Subscriber.swift */; }; + D0B4180B1D7DFAAB004562A4 /* Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07A5CFC1BBDE6E400451791 /* Promise.swift */; }; + D0B4180C1D7DFAAB004562A4 /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05F09A71C9EF77100BB6F96 /* Multicast.swift */; }; + D0B4180D1D7DFAAB004562A4 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D066BD091C7FE06700D7A576 /* Lock.swift */; }; + D0CD17B21CC17C83007C5650 /* Signal_Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CD17B11CC17C83007C5650 /* Signal_Materialize.swift */; }; + D0FC1A3A1CA3284F0056AE9A /* Signal_Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FC1A391CA3284F0056AE9A /* Signal_Merge.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -175,7 +205,7 @@ D0085B3F1B282BEE00EAF753 /* ThreadPool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadPool.swift; sourceTree = ""; }; D0085B401B282BEE00EAF753 /* Timer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Timer.swift; sourceTree = ""; }; D0085B411B282BEE00EAF753 /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queue.swift; sourceTree = ""; }; - D0085B421B282BEE00EAF753 /* Pipe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pipe.swift; sourceTree = ""; }; + D0085B421B282BEE00EAF753 /* ValuePipe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValuePipe.swift; sourceTree = ""; }; D0085B431B282BEE00EAF753 /* Bag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bag.swift; sourceTree = ""; }; D0085B441B282BEE00EAF753 /* Signal_Take.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Take.swift; sourceTree = ""; }; D0085B451B282BEE00EAF753 /* Signal_Catch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Catch.swift; sourceTree = ""; }; @@ -191,11 +221,14 @@ D0085B631B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSignalKitFunctionsTests.swift; sourceTree = ""; }; D0085B641B282C2800EAF753 /* DeallocatingObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeallocatingObject.swift; sourceTree = ""; }; D0085B651B282C2800EAF753 /* SwiftSignalKitBasicTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSignalKitBasicTests.swift; sourceTree = ""; }; + D02720B01CD0E005006F1506 /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = ""; }; D0445DD81A7C2CA500267924 /* SSignalKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D0445DDC1A7C2CA500267924 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SSignalKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D0445DE91A7C2CA500267924 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D0445E561A7C3FB400267924 /* SDisposableTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDisposableTests.m; sourceTree = ""; }; + D05F09A71C9EF77100BB6F96 /* Multicast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Multicast.swift; sourceTree = ""; }; + D066BD091C7FE06700D7A576 /* Lock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lock.swift; sourceTree = ""; }; D06F106B1A85561E00485185 /* SSignalBasicTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignalBasicTests.m; sourceTree = ""; }; D06F106F1A855E2D00485185 /* DeallocatingObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeallocatingObject.h; sourceTree = ""; }; D06F10701A855E2D00485185 /* DeallocatingObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeallocatingObject.m; sourceTree = ""; }; @@ -203,6 +236,12 @@ D07A5CFC1BBDE6E400451791 /* Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Promise.swift; sourceTree = ""; }; D09FD73C1BA9BAB900FF0A4F /* SVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVariable.h; sourceTree = ""; }; D09FD73D1BA9BAB900FF0A4F /* SVariable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVariable.m; sourceTree = ""; }; + D0B417E71D7DFA40004562A4 /* SwiftSignalKit copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "SwiftSignalKit copy-Info.plist"; path = "/Users/peter/Documents/Telegram-iOS/submodules/SSignalKit/SwiftSignalKit copy-Info.plist"; sourceTree = ""; }; + D0B417ED1D7DFA63004562A4 /* SwiftSignalKitMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftSignalKitMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0B417EF1D7DFA63004562A4 /* SwiftSignalKitMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftSignalKitMac.h; sourceTree = ""; }; + D0B417F01D7DFA63004562A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D0CD17B11CC17C83007C5650 /* Signal_Materialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Materialize.swift; sourceTree = ""; }; + D0FC1A391CA3284F0056AE9A /* Signal_Merge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Merge.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -236,6 +275,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D0B417E91D7DFA63004562A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -249,20 +295,24 @@ D0085B3F1B282BEE00EAF753 /* ThreadPool.swift */, D0085B401B282BEE00EAF753 /* Timer.swift */, D0085B411B282BEE00EAF753 /* Queue.swift */, - D0085B421B282BEE00EAF753 /* Pipe.swift */, + D0085B421B282BEE00EAF753 /* ValuePipe.swift */, D0085B431B282BEE00EAF753 /* Bag.swift */, D0085B441B282BEE00EAF753 /* Signal_Take.swift */, D0085B451B282BEE00EAF753 /* Signal_Catch.swift */, D0085B461B282BEE00EAF753 /* Signal_Single.swift */, D0085B471B282BEE00EAF753 /* Signal_Meta.swift */, D0085B481B282BEE00EAF753 /* Signal_Combine.swift */, + D0FC1A391CA3284F0056AE9A /* Signal_Merge.swift */, D0085B491B282BEE00EAF753 /* Atomic.swift */, D0085B4A1B282BEE00EAF753 /* Signal_Reduce.swift */, + D0CD17B11CC17C83007C5650 /* Signal_Materialize.swift */, D0085B4B1B282BEE00EAF753 /* Signal.swift */, D0085B4C1B282BEE00EAF753 /* Disposable.swift */, D0085B4D1B282BEE00EAF753 /* Signal_Mapping.swift */, D0085B4E1B282BEE00EAF753 /* Subscriber.swift */, D07A5CFC1BBDE6E400451791 /* Promise.swift */, + D05F09A71C9EF77100BB6F96 /* Multicast.swift */, + D066BD091C7FE06700D7A576 /* Lock.swift */, D0085B261B282B9800EAF753 /* SwiftSignalKit.h */, D0085B241B282B9800EAF753 /* Supporting Files */, ); @@ -283,6 +333,7 @@ D0085B631B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift */, D0085B641B282C2800EAF753 /* DeallocatingObject.swift */, D0085B651B282C2800EAF753 /* SwiftSignalKitBasicTests.swift */, + D02720B01CD0E005006F1506 /* PerformanceTests.swift */, D0085B311B282B9800EAF753 /* Supporting Files */, ); path = SwiftSignalKitTests; @@ -303,7 +354,9 @@ D0445DE71A7C2CA500267924 /* SSignalKitTests */, D0085B231B282B9800EAF753 /* SwiftSignalKit */, D0085B301B282B9800EAF753 /* SwiftSignalKitTests */, + D0B417EE1D7DFA63004562A4 /* SwiftSignalKitMac */, D0445DD91A7C2CA500267924 /* Products */, + D0B417E71D7DFA40004562A4 /* SwiftSignalKit copy-Info.plist */, ); sourceTree = ""; }; @@ -314,6 +367,7 @@ D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */, D0085B221B282B9800EAF753 /* SwiftSignalKit.framework */, D0085B2C1B282B9800EAF753 /* SwiftSignalKitTests.xctest */, + D0B417ED1D7DFA63004562A4 /* SwiftSignalKitMac.framework */, ); name = Products; sourceTree = ""; @@ -409,6 +463,15 @@ name = "Supporting Files"; sourceTree = ""; }; + D0B417EE1D7DFA63004562A4 /* SwiftSignalKitMac */ = { + isa = PBXGroup; + children = ( + D0B417EF1D7DFA63004562A4 /* SwiftSignalKitMac.h */, + D0B417F01D7DFA63004562A4 /* Info.plist */, + ); + path = SwiftSignalKitMac; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -455,6 +518,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D0B417EA1D7DFA63004562A4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D0B417F11D7DFA63004562A4 /* SwiftSignalKitMac.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -530,6 +601,24 @@ productReference = D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + D0B417EC1D7DFA63004562A4 /* SwiftSignalKitMac */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0B417F21D7DFA63004562A4 /* Build configuration list for PBXNativeTarget "SwiftSignalKitMac" */; + buildPhases = ( + D0B417E81D7DFA63004562A4 /* Sources */, + D0B417E91D7DFA63004562A4 /* Frameworks */, + D0B417EA1D7DFA63004562A4 /* Headers */, + D0B417EB1D7DFA63004562A4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftSignalKitMac; + productName = SwiftSignalKitMac; + productReference = D0B417ED1D7DFA63004562A4 /* SwiftSignalKitMac.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -538,21 +627,27 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0710; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Telegram; TargetAttributes = { D0085B211B282B9800EAF753 = { CreatedOnToolsVersion = 6.3.1; + ProvisioningStyle = Manual; }; D0085B2B1B282B9800EAF753 = { CreatedOnToolsVersion = 6.3.1; }; D0445DD71A7C2CA500267924 = { CreatedOnToolsVersion = 6.1.1; + ProvisioningStyle = Manual; }; D0445DE21A7C2CA500267924 = { CreatedOnToolsVersion = 6.1.1; }; + D0B417EC1D7DFA63004562A4 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Manual; + }; }; }; buildConfigurationList = D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */; @@ -571,6 +666,7 @@ D0445DE21A7C2CA500267924 /* SSignalKitTests */, D0085B211B282B9800EAF753 /* SwiftSignalKit */, D0085B2B1B282B9800EAF753 /* SwiftSignalKitTests */, + D0B417EC1D7DFA63004562A4 /* SwiftSignalKitMac */, ); }; /* End PBXProject section */ @@ -604,6 +700,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D0B417EB1D7DFA63004562A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -612,16 +715,20 @@ buildActionMask = 2147483647; files = ( D0085B521B282BEE00EAF753 /* Signal_Dispatch.swift in Sources */, - D0085B561B282BEE00EAF753 /* Pipe.swift in Sources */, + D0085B561B282BEE00EAF753 /* ValuePipe.swift in Sources */, D0085B551B282BEE00EAF753 /* Queue.swift in Sources */, D0085B591B282BEE00EAF753 /* Signal_Catch.swift in Sources */, D0085B601B282BEE00EAF753 /* Disposable.swift in Sources */, + D0FC1A3A1CA3284F0056AE9A /* Signal_Merge.swift in Sources */, D0085B531B282BEE00EAF753 /* ThreadPool.swift in Sources */, + D0CD17B21CC17C83007C5650 /* Signal_Materialize.swift in Sources */, D0085B5F1B282BEE00EAF753 /* Signal.swift in Sources */, D07A5CFD1BBDE6E400451791 /* Promise.swift in Sources */, D0085B5E1B282BEE00EAF753 /* Signal_Reduce.swift in Sources */, D0085B621B282BEE00EAF753 /* Subscriber.swift in Sources */, + D066BD0A1C7FE06700D7A576 /* Lock.swift in Sources */, D0085B581B282BEE00EAF753 /* Signal_Take.swift in Sources */, + D05F09A81C9EF77100BB6F96 /* Multicast.swift in Sources */, D0085B501B282BEE00EAF753 /* Signal_Timing.swift in Sources */, D0085B541B282BEE00EAF753 /* Timer.swift in Sources */, D0085B5B1B282BEE00EAF753 /* Signal_Meta.swift in Sources */, @@ -640,6 +747,7 @@ files = ( D0085B671B282C2800EAF753 /* DeallocatingObject.swift in Sources */, D0085B681B282C2800EAF753 /* SwiftSignalKitBasicTests.swift in Sources */, + D02720B11CD0E005006F1506 /* PerformanceTests.swift in Sources */, D0085B661B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -688,6 +796,37 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D0B417E81D7DFA63004562A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0B417F61D7DFAAB004562A4 /* Signal_Timing.swift in Sources */, + D0B417F71D7DFAAB004562A4 /* Signal_SideEffects.swift in Sources */, + D0B417F81D7DFAAB004562A4 /* Signal_Dispatch.swift in Sources */, + D0B417F91D7DFAAB004562A4 /* ThreadPool.swift in Sources */, + D0B417FA1D7DFAAB004562A4 /* Timer.swift in Sources */, + D0B417FB1D7DFAAB004562A4 /* Queue.swift in Sources */, + D0B417FC1D7DFAAB004562A4 /* ValuePipe.swift in Sources */, + D0B417FD1D7DFAAB004562A4 /* Bag.swift in Sources */, + D0B417FE1D7DFAAB004562A4 /* Signal_Take.swift in Sources */, + D0B417FF1D7DFAAB004562A4 /* Signal_Catch.swift in Sources */, + D0B418001D7DFAAB004562A4 /* Signal_Single.swift in Sources */, + D0B418011D7DFAAB004562A4 /* Signal_Meta.swift in Sources */, + D0B418021D7DFAAB004562A4 /* Signal_Combine.swift in Sources */, + D0B418031D7DFAAB004562A4 /* Signal_Merge.swift in Sources */, + D0B418041D7DFAAB004562A4 /* Atomic.swift in Sources */, + D0B418051D7DFAAB004562A4 /* Signal_Reduce.swift in Sources */, + D0B418061D7DFAAB004562A4 /* Signal_Materialize.swift in Sources */, + D0B418071D7DFAAB004562A4 /* Signal.swift in Sources */, + D0B418081D7DFAAB004562A4 /* Disposable.swift in Sources */, + D0B418091D7DFAAB004562A4 /* Signal_Mapping.swift in Sources */, + D0B4180A1D7DFAAB004562A4 /* Subscriber.swift in Sources */, + D0B4180B1D7DFAAB004562A4 /* Promise.swift in Sources */, + D0B4180C1D7DFAAB004562A4 /* Multicast.swift in Sources */, + D0B4180D1D7DFAAB004562A4 /* Lock.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -707,11 +846,14 @@ D0085B361B282B9800EAF753 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + ARCHS = "$(ARCHS_STANDARD)"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -723,20 +865,28 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 3.0; }; name = Debug; }; D0085B371B282B9800EAF753 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = YES; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SwiftSignalKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -744,8 +894,12 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -767,6 +921,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -785,6 +940,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -813,6 +970,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -859,6 +1017,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -878,6 +1037,7 @@ D0445DEF1A7C2CA500267924 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -891,6 +1051,7 @@ ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; name = Debug; @@ -898,6 +1059,8 @@ D0445DF01A7C2CA500267924 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -910,6 +1073,7 @@ MACH_O_TYPE = staticlib; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; name = Release; @@ -958,6 +1122,230 @@ }; name = Release; }; + D086A5741CC0117500F08284 /* Hockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + 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 = 8.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Hockeyapp; + }; + D086A5751CC0117500F08284 /* Hockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = YES; + INFOPLIST_FILE = SSignalKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + SKIP_INSTALL = YES; + }; + name = Hockeyapp; + }; + D086A5761CC0117500F08284 /* Hockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = SSignalKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + XCTest, + "-ObjC", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Hockeyapp; + }; + D086A5771CC0117500F08284 /* Hockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SwiftSignalKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 3.0; + }; + name = Hockeyapp; + }; + D086A5781CC0117500F08284 /* Hockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SwiftSignalKitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Hockeyapp; + }; + D0B417F31D7DFA63004562A4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = SwiftSignalKitMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.SwiftSignalKitMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + D0B417F41D7DFA63004562A4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = SwiftSignalKitMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.SwiftSignalKitMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + D0B417F51D7DFA63004562A4 /* Hockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = SwiftSignalKitMac/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.SwiftSignalKitMac; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + }; + name = Hockeyapp; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -966,6 +1354,7 @@ buildConfigurations = ( D0085B361B282B9800EAF753 /* Debug */, D0085B371B282B9800EAF753 /* Release */, + D086A5771CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -975,6 +1364,7 @@ buildConfigurations = ( D0085B391B282B9800EAF753 /* Debug */, D0085B3A1B282B9800EAF753 /* Release */, + D086A5781CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -984,6 +1374,7 @@ buildConfigurations = ( D0445DEC1A7C2CA500267924 /* Debug */, D0445DED1A7C2CA500267924 /* Release */, + D086A5741CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -993,6 +1384,7 @@ buildConfigurations = ( D0445DEF1A7C2CA500267924 /* Debug */, D0445DF01A7C2CA500267924 /* Release */, + D086A5751CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -1002,6 +1394,17 @@ buildConfigurations = ( D0445DF21A7C2CA500267924 /* Debug */, D0445DF31A7C2CA500267924 /* Release */, + D086A5761CC0117500F08284 /* Hockeyapp */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D0B417F21D7DFA63004562A4 /* Build configuration list for PBXNativeTarget "SwiftSignalKitMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0B417F31D7DFA63004562A4 /* Debug */, + D0B417F41D7DFA63004562A4 /* Release */, + D0B417F51D7DFA63004562A4 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/SSignalKit/SQueue.h b/SSignalKit/SQueue.h index a1782b2112..228334c888 100644 --- a/SSignalKit/SQueue.h +++ b/SSignalKit/SQueue.h @@ -10,6 +10,7 @@ - (void)dispatch:(dispatch_block_t)block; - (void)dispatchSync:(dispatch_block_t)block; +- (void)dispatch:(dispatch_block_t)block synchronous:(bool)synchronous; - (dispatch_queue_t)_dispatch_queue; diff --git a/SSignalKit/SQueue.m b/SSignalKit/SQueue.m index ed0b4463bd..d5b5553af8 100644 --- a/SSignalKit/SQueue.m +++ b/SSignalKit/SQueue.m @@ -98,6 +98,20 @@ static const void *SQueueSpecificKey = &SQueueSpecificKey; dispatch_sync(_queue, block); } +- (void)dispatch:(dispatch_block_t)block synchronous:(bool)synchronous { + if (_queueSpecific != NULL && dispatch_get_specific(SQueueSpecificKey) == _queueSpecific) + block(); + else if (_specialIsMainQueue && [NSThread isMainThread]) + block(); + else { + if (synchronous) { + dispatch_sync(_queue, block); + } else { + dispatch_async(_queue, block); + } + } +} + - (bool)isCurrentQueue { if (_queueSpecific != NULL && dispatch_get_specific(SQueueSpecificKey) == _queueSpecific) diff --git a/SSignalKit/SSignal+Catch.h b/SSignalKit/SSignal+Catch.h index 5cbdad90c9..dc8898c062 100644 --- a/SSignalKit/SSignal+Catch.h +++ b/SSignalKit/SSignal+Catch.h @@ -4,5 +4,6 @@ - (SSignal *)catch:(SSignal *(^)(id error))f; - (SSignal *)restart; +- (SSignal *)retryIf:(bool (^)(id error))predicate; @end diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m index 2387c88946..f61e277750 100644 --- a/SSignalKit/SSignal+Catch.m +++ b/SSignalKit/SSignal+Catch.m @@ -91,4 +91,57 @@ static dispatch_block_t recursiveBlock(void (^block)(dispatch_block_t recurse)) }]; } +- (SSignal *)retryIf:(bool (^)(id error))predicate { + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SAtomic *shouldRestart = [[SAtomic alloc] initWithValue:@true]; + + SMetaDisposable *currentDisposable = [[SMetaDisposable alloc] init]; + + void (^start)() = recursiveBlock(^(dispatch_block_t recurse) + { + NSNumber *currentShouldRestart = [shouldRestart with:^id(NSNumber *current) + { + return current; + }]; + + if ([currentShouldRestart boolValue]) + { + id disposable = [self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + if (predicate(error)) { + recurse(); + } else { + [subscriber putError:error]; + } + } completed:^ + { + [shouldRestart modify:^id(__unused id current) { + return @false; + }]; + [subscriber putCompletion]; + }]; + [currentDisposable setDisposable:disposable]; + } else { + [subscriber putCompletion]; + } + }); + + start(); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + [currentDisposable dispose]; + + [shouldRestart modify:^id(__unused id current) + { + return @false; + }]; + }]; + }]; +} + @end diff --git a/SSignalKit/SSignal+Mapping.h b/SSignalKit/SSignal+Mapping.h index 42446ddb2a..81a16816e2 100644 --- a/SSignalKit/SSignal+Mapping.h +++ b/SSignalKit/SSignal+Mapping.h @@ -4,5 +4,6 @@ - (SSignal *)map:(id (^)(id))f; - (SSignal *)filter:(bool (^)(id))f; +- (SSignal *)ignoreRepeated; @end diff --git a/SSignalKit/SSignal+Mapping.m b/SSignalKit/SSignal+Mapping.m index 7dc47cf4c3..cd3a3ece0a 100644 --- a/SSignalKit/SSignal+Mapping.m +++ b/SSignalKit/SSignal+Mapping.m @@ -1,5 +1,18 @@ #import "SSignal+Mapping.h" +#import "SAtomic.h" + +@interface SSignalIgnoreRepeatedState: NSObject + +@property (nonatomic, strong) id value; +@property (nonatomic) bool hasValue; + +@end + +@implementation SSignalIgnoreRepeatedState + +@end + @implementation SSignal (Mapping) - (SSignal *)map:(id (^)(id))f @@ -37,4 +50,34 @@ }]; } +- (SSignal *)ignoreRepeated { + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { + SAtomic *state = [[SAtomic alloc] initWithValue:[[SSignalIgnoreRepeatedState alloc] init]]; + + return [self startWithNext:^(id next) { + bool shouldPassthrough = [[state with:^id(SSignalIgnoreRepeatedState *state) { + if (!state.hasValue) { + state.hasValue = true; + state.value = next; + return @true; + } else if ((state.value == nil && next == nil) || [(id)state.value isEqual:next]) { + return @false; + } + state.value = next; + return @true; + }] boolValue]; + + if (shouldPassthrough) { + [subscriber putNext:next]; + } + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + @end diff --git a/SSignalKit/SSignal+Meta.h b/SSignalKit/SSignal+Meta.h index 8a1dd0d48f..2d90df13f8 100644 --- a/SSignalKit/SSignal+Meta.h +++ b/SSignalKit/SSignal+Meta.h @@ -7,8 +7,10 @@ - (SSignal *)switchToLatest; - (SSignal *)mapToSignal:(SSignal *(^)(id))f; - (SSignal *)mapToQueue:(SSignal *(^)(id))f; +- (SSignal *)mapToThrottled:(SSignal *(^)(id))f; - (SSignal *)then:(SSignal *)signal; - (SSignal *)queue; +- (SSignal *)throttled; + (SSignal *)defer:(SSignal *(^)())generator; @end diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 43e2d93c10..f6ad4124e6 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -20,13 +20,14 @@ NSMutableArray *_queuedSignals; bool _queueMode; + bool _throttleMode; } @end @implementation SSignalQueueState -- (instancetype)initWithSubscriber:(SSubscriber *)subscriber queueMode:(bool)queueMode +- (instancetype)initWithSubscriber:(SSubscriber *)subscriber queueMode:(bool)queueMode throttleMode:(bool)throttleMode { self = [super init]; if (self != nil) @@ -35,6 +36,7 @@ _currentDisposable = [[SMetaDisposable alloc] init]; _queuedSignals = queueMode ? [[NSMutableArray alloc] init] : nil; _queueMode = queueMode; + _throttleMode = throttleMode; } return self; } @@ -48,8 +50,10 @@ { bool startSignal = false; OSSpinLockLock(&_lock); - if (_queueMode && _executingSignal) - { + if (_queueMode && _executingSignal) { + if (_throttleMode) { + [_queuedSignals removeAllObjects]; + } [_queuedSignals addObject:signal]; } else @@ -152,7 +156,7 @@ { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:false]; + SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:false throttleMode:false]; [state beginWithDisposable:[self startWithNext:^(id next) { @@ -179,6 +183,10 @@ return [[self map:f] queue]; } +- (SSignal *)mapToThrottled:(SSignal *(^)(id))f { + return [[self map:f] throttled]; +} + - (SSignal *)then:(SSignal *)signal { return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) @@ -216,7 +224,7 @@ { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:true]; + SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:true throttleMode:false]; [state beginWithDisposable:[self startWithNext:^(id next) { @@ -233,6 +241,24 @@ }]; } +- (SSignal *)throttled { + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { + SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:true throttleMode:true]; + [state beginWithDisposable:[self startWithNext:^(id next) + { + [state enqueueSignal:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [state beginCompletion]; + }]]; + + return state; + }]; +} + + (SSignal *)defer:(SSignal *(^)())generator { return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index cb5a986af6..56ca98337c 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -702,4 +702,63 @@ } } +- (void)testRetryIfNoError { + SSignal *s = [[SSignal single:@1] retryIf:^bool(__unused id error) { + return true; + }]; + [s startWithNext:^(id next) { + XCTAssertEqual(next, @1); + }]; +} + +- (void)testRetryErrorNoMatch { + SSignal *s = [[SSignal fail:@false] retryIf:^bool(id error) { + return false; + }]; +} + +- (void)testRetryErrorMatch { + __block counter = 1; + SSignal *s = [[[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { + if (counter == 1) { + counter++; + [subscriber putError:@true]; + } else { + [subscriber putNext:@(counter)]; + } + return nil; + }] retryIf:^bool(id error) { + return [error boolValue]; + }]; + + __block int value = 0; + [s startWithNext:^(id next) { + value = [next intValue]; + }]; + + XCTAssertEqual(value, 2); +} + +- (void)testRetryErrorFailNoMatch { + __block counter = 1; + SSignal *s = [[[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { + if (counter == 1) { + counter++; + [subscriber putError:@true]; + } else { + [subscriber putError:@false]; + } + return nil; + }] retryIf:^bool(id error) { + return [error boolValue]; + }]; + + __block bool errorMatches = false; + [s startWithNext:nil error:^(id error) { + errorMatches = ![error boolValue]; + } completed:nil]; + + XCTAssert(errorMatches); +} + @end diff --git a/SwiftSignalKit copy-Info.plist b/SwiftSignalKit copy-Info.plist new file mode 100644 index 0000000000..d3de8eefb6 --- /dev/null +++ b/SwiftSignalKit copy-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/SwiftSignalKit/Atomic.swift b/SwiftSignalKit/Atomic.swift index ae7dd94ab4..e6afddf50b 100644 --- a/SwiftSignalKit/Atomic.swift +++ b/SwiftSignalKit/Atomic.swift @@ -1,35 +1,42 @@ import Foundation public final class Atomic { - private var lock: OSSpinLock = 0 + private var lock: pthread_mutex_t private var value: T public init(value: T) { + self.lock = pthread_mutex_t() self.value = value + + pthread_mutex_init(&self.lock, nil) } - public func with(f: T -> R) -> R { - OSSpinLockLock(&self.lock) + deinit { + pthread_mutex_destroy(&self.lock) + } + + public func with(_ f: (T) -> R) -> R { + pthread_mutex_lock(&self.lock) let result = f(self.value) - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) return result } - public func modify(f: T -> T) -> T { - OSSpinLockLock(&self.lock) + public func modify(_ f: (T) -> T) -> T { + pthread_mutex_lock(&self.lock) let result = f(self.value) self.value = result - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) return result } - public func swap(value: T) -> T { - OSSpinLockLock(&self.lock) + public func swap(_ value: T) -> T { + pthread_mutex_lock(&self.lock) let previous = self.value self.value = value - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) return previous } diff --git a/SwiftSignalKit/Bag.swift b/SwiftSignalKit/Bag.swift index a4ec0c84b9..cb3d771446 100644 --- a/SwiftSignalKit/Bag.swift +++ b/SwiftSignalKit/Bag.swift @@ -9,28 +9,66 @@ public final class Bag { public init() { } - public func add(item: T) -> Index { + public func add(_ item: T) -> Index { let key = self.nextIndex - self.nextIndex++ + self.nextIndex += 1 self.items.append(item) self.itemKeys.append(key) return key } - public func remove(index: Index) { + public func get(_ index: Index) -> T? { var i = 0 for key in self.itemKeys { if key == index { - self.items.removeAtIndex(i) - self.itemKeys.removeAtIndex(i) + return self.items[i] + } + i += 1 + } + return nil + } + + public func remove(_ index: Index) { + var i = 0 + for key in self.itemKeys { + if key == index { + self.items.remove(at: i) + self.itemKeys.remove(at: i) break } - i++ + i += 1 } } + public func removeAll() { + self.items.removeAll() + self.itemKeys.removeAll() + } + public func copyItems() -> [T] { return self.items } + + public func copyItemsWithIndices() -> [(Index, T)] { + var result: [(Index, T)] = [] + var i = 0 + for key in self.itemKeys { + result.append((key, self.items[i])) + i += 1 + } + return result + } + + public var isEmpty: Bool { + return self.items.isEmpty + } + + public var first: (Index, T)? { + if !self.items.isEmpty { + return (self.itemKeys[0], self.items[0]) + } else { + return nil + } + } } diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift index 2efd074979..4b38627a8e 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -1,50 +1,50 @@ import Foundation -public protocol Disposable -{ +public protocol Disposable: class { func dispose() } -internal struct _EmptyDisposable : Disposable { - internal func dispose() { +final class _EmptyDisposable: Disposable { + func dispose() { } } public let EmptyDisposable: Disposable = _EmptyDisposable() -public final class ActionDisposable : Disposable -{ +public final class ActionDisposable : Disposable { private var action: () -> Void - private var lock: OSSpinLock = 0 + private var lock: Int32 = 0 - public init(action: () -> Void) { + public init(action: @escaping() -> Void) { self.action = action } public func dispose() { - var action = doNothing - OSSpinLockLock(&self.lock) - action = self.action - self.action = doNothing - OSSpinLockUnlock(&self.lock) - action() + if OSAtomicCompareAndSwap32(0, 1, &self.lock) { + self.action() + self.action = doNothing + } } } -public final class MetaDisposable : Disposable -{ - private var lock: OSSpinLock = 0 +public final class MetaDisposable : Disposable { + private var lock = pthread_mutex_t() private var disposed = false private var disposable: Disposable! = nil public init() { + pthread_mutex_init(&self.lock, nil) } - public func set(disposable: Disposable?) { + deinit { + pthread_mutex_destroy(&self.lock) + } + + public func set(_ disposable: Disposable?) { var previousDisposable: Disposable! = nil var disposeImmediately = false - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) disposeImmediately = self.disposed if !disposeImmediately { previousDisposable = self.disposable @@ -54,7 +54,7 @@ public final class MetaDisposable : Disposable self.disposable = nil } } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if previousDisposable != nil { previousDisposable.dispose() @@ -71,13 +71,13 @@ public final class MetaDisposable : Disposable { var disposable: Disposable! = nil - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) if !self.disposed { self.disposed = true disposable = self.disposable self.disposable = nil } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if disposable != nil { disposable.dispose() @@ -86,39 +86,51 @@ public final class MetaDisposable : Disposable } public final class DisposableSet : Disposable { - private var lock: OSSpinLock = 0 + private var lock = pthread_mutex_t() private var disposed = false private var disposables: [Disposable] = [] public init() { - + pthread_mutex_init(&self.lock, nil) } - public func add(disposable: Disposable) { + deinit { + pthread_mutex_destroy(&self.lock) + } + + public func add(_ disposable: Disposable) { var disposeImmediately = false - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) if self.disposed { disposeImmediately = true } else { self.disposables.append(disposable) } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if disposeImmediately { disposable.dispose() } } + public func remove(_ disposable: Disposable) { + pthread_mutex_lock(&self.lock) + if let index = self.disposables.index(where: { $0 === disposable }) { + self.disposables.remove(at: index) + } + pthread_mutex_unlock(&self.lock) + } + public func dispose() { var disposables: [Disposable] = [] - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) if !self.disposed { self.disposed = true disposables = self.disposables self.disposables = [] } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if disposables.count != 0 { for disposable in disposables { diff --git a/SwiftSignalKit/Lock.swift b/SwiftSignalKit/Lock.swift new file mode 100644 index 0000000000..42847f2579 --- /dev/null +++ b/SwiftSignalKit/Lock.swift @@ -0,0 +1,19 @@ +import Foundation + +public final class Lock { + private var mutex = pthread_mutex_t() + + public init() { + pthread_mutex_init(&self.mutex, nil) + } + + deinit { + pthread_mutex_destroy(&self.mutex) + } + + public func locked(_ f: () -> ()) { + pthread_mutex_lock(&self.mutex) + f() + pthread_mutex_unlock(&self.mutex) + } +} diff --git a/SwiftSignalKit/Multicast.swift b/SwiftSignalKit/Multicast.swift new file mode 100644 index 0000000000..b1ddec5a3c --- /dev/null +++ b/SwiftSignalKit/Multicast.swift @@ -0,0 +1,88 @@ +import Foundation + +private final class MulticastInstance { + let disposable: Disposable + var subscribers = Bag<(T) -> Void>() + var lock = Lock() + + init(disposable: Disposable) { + self.disposable = disposable + } +} + +public final class Multicast { + private let lock = Lock() + private var instances: [String: MulticastInstance] = [:] + + public init() { + } + + public func get(key: String, signal: Signal) -> Signal { + return Signal { subscriber in + var instance: MulticastInstance! + var beginDisposable: MetaDisposable? + self.lock.locked { + if let existing = self.instances[key] { + instance = existing + } else { + let disposable = MetaDisposable() + instance = MulticastInstance(disposable: disposable) + beginDisposable = disposable + } + } + + var index: Bag<(T) -> Void>.Index! + instance.lock.locked { + index = instance.subscribers.add({ next in + subscriber.putNext(next) + }) + } + + if let beginDisposable = beginDisposable { + beginDisposable.set(signal.start(next: { next in + var subscribers: [(T) -> Void]! + instance.lock.locked { + subscribers = instance.subscribers.copyItems() + } + for subscriber in subscribers { + subscriber(next) + } + }, error: { _ in + self.lock.locked { + let _ = self.instances.removeValue(forKey: key) + } + }, completed: { + self.lock.locked { + self.instances.removeValue(forKey: key) + } + })) + } + + return ActionDisposable { + var remove = false + instance.lock.locked { + instance.subscribers.remove(index) + if instance.subscribers.isEmpty { + remove = true + } + } + + if remove { + self.lock.locked { + let _ = self.instances.removeValue(forKey: key) + } + } + } + } + } +} + +public final class MulticastPromise { + public let subscribers = Bag<(T) -> Void>() + public let lock = Lock() + public var value: T? + + public init() { + + } +} diff --git a/SwiftSignalKit/Promise.swift b/SwiftSignalKit/Promise.swift index 00e96b9649..036e6f4fe4 100644 --- a/SwiftSignalKit/Promise.swift +++ b/SwiftSignalKit/Promise.swift @@ -1,33 +1,36 @@ import Foundation -public class Promise { +public final class Promise { private var value: T? - private var lock: OSSpinLock = 0 + private var lock = pthread_mutex_t() private let disposable = MetaDisposable() - private let subscribers = Bag Void>() + private let subscribers = Bag<(T) -> Void>() public init(_ value: T) { self.value = value + pthread_mutex_init(&self.lock, nil) } public init() { + pthread_mutex_init(&self.lock, nil) } deinit { + pthread_mutex_destroy(&self.lock) self.disposable.dispose() } - public func set(signal: Signal) { - OSSpinLockLock(&self.lock) + public func set(_ signal: Signal) { + pthread_mutex_lock(&self.lock) self.value = nil - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) self.disposable.set(signal.start(next: { [weak self] next in if let strongSelf = self { - OSSpinLockLock(&strongSelf.lock) + pthread_mutex_lock(&strongSelf.lock) strongSelf.value = next let subscribers = strongSelf.subscribers.copyItems() - OSSpinLockUnlock(&strongSelf.lock); + pthread_mutex_unlock(&strongSelf.lock) for subscriber in subscribers { subscriber(next) @@ -38,12 +41,12 @@ public class Promise { public func get() -> Signal { return Signal { subscriber in - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) let currentValue = self.value let index = self.subscribers.add({ next in subscriber.putNext(next) }) - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if let currentValue = currentValue { @@ -51,9 +54,68 @@ public class Promise { } return ActionDisposable { - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) self.subscribers.remove(index) - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) + } + } + } +} + +public final class ValuePromise { + private var value: T? + private var lock = pthread_mutex_t() + private let subscribers = Bag<(T) -> Void>() + public let ignoreRepeated: Bool + + public init(_ value: T, ignoreRepeated: Bool = false) { + self.value = value + self.ignoreRepeated = ignoreRepeated + pthread_mutex_init(&self.lock, nil) + } + + public init(ignoreRepeated: Bool = false) { + self.ignoreRepeated = ignoreRepeated + pthread_mutex_init(&self.lock, nil) + } + + deinit { + pthread_mutex_destroy(&self.lock) + } + + public func set(_ value: T) { + pthread_mutex_lock(&self.lock) + let subscribers: [(T) -> Void] + if !self.ignoreRepeated || self.value != value { + self.value = value + subscribers = self.subscribers.copyItems() + } else { + subscribers = [] + } + pthread_mutex_unlock(&self.lock); + + for subscriber in subscribers { + subscriber(value) + } + } + + public func get() -> Signal { + return Signal { subscriber in + pthread_mutex_lock(&self.lock) + let currentValue = self.value + let index = self.subscribers.add({ next in + subscriber.putNext(next) + }) + pthread_mutex_unlock(&self.lock) + + if let currentValue = currentValue { + subscriber.putNext(currentValue) + } + + return ActionDisposable { + pthread_mutex_lock(&self.lock) + self.subscribers.remove(index) + pthread_mutex_unlock(&self.lock) } } } diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 178903b22d..30d6f65e8c 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -1,16 +1,17 @@ import Foundation -private let _QueueSpecificKey = NSObject() -private let QueueSpecificKey: UnsafePointer = UnsafePointer(Unmanaged.passUnretained(_QueueSpecificKey).toOpaque()) +private let QueueSpecificKey = DispatchSpecificKey() -private let globalMainQueue = Queue(queue: dispatch_get_main_queue(), specialIsMainQueue: true) +private let globalMainQueue = Queue(queue: DispatchQueue.main, specialIsMainQueue: true) +private let globalDefaultQueue = Queue(queue: DispatchQueue.global(qos: .default), specialIsMainQueue: false) +private let globalBackgroundQueue = Queue(queue: DispatchQueue.global(qos: .background), specialIsMainQueue: false) public final class Queue { - private let nativeQueue: dispatch_queue_t - private var specific: UnsafeMutablePointer + private let nativeQueue: DispatchQueue + private var specific = NSObject() private let specialIsMainQueue: Bool - public var queue: dispatch_queue_t { + public var queue: DispatchQueue { get { return self.nativeQueue } @@ -21,65 +22,67 @@ public final class Queue { } public class func concurrentDefaultQueue() -> Queue { - return Queue(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), specialIsMainQueue: false) + return globalDefaultQueue } public class func concurrentBackgroundQueue() -> Queue { - return Queue(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), specialIsMainQueue: false) + return globalBackgroundQueue } - public init(queue: dispatch_queue_t) { + public init(queue: DispatchQueue) { self.nativeQueue = queue - self.specific = nil self.specialIsMainQueue = false } - private init(queue: dispatch_queue_t, specialIsMainQueue: Bool) { + fileprivate init(queue: DispatchQueue, specialIsMainQueue: Bool) { self.nativeQueue = queue - self.specific = nil self.specialIsMainQueue = specialIsMainQueue } public init(name: String? = nil) { - if let name = name { - self.nativeQueue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL) - } else { - self.nativeQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) - } - self.specific = nil + self.nativeQueue = DispatchQueue(label: name ?? "", qos: .default) + self.specialIsMainQueue = false - self.specific = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()) - dispatch_queue_set_specific(self.nativeQueue, QueueSpecificKey, self.specific, nil) + self.nativeQueue.setSpecific(key: QueueSpecificKey, value: self.specific) } - public func async(f: Void -> Void) { - if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { - f() - } else if self.specialIsMainQueue && NSThread.isMainThread() { - f() + public func isCurrent() -> Bool { + if DispatchQueue.getSpecific(key: QueueSpecificKey) === self.specific { + return true + } else if self.specialIsMainQueue && Thread.isMainThread { + return true } else { - dispatch_async(self.nativeQueue, f) + return false } } - public func sync(f: Void -> Void) { - if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { - f() - } else if self.specialIsMainQueue && NSThread.isMainThread() { + public func async(_ f: @escaping () -> Void) { + if self.isCurrent() { f() } else { - dispatch_sync(self.nativeQueue, f) + self.nativeQueue.async(execute: f) } } - public func dispatch(f: Void -> Void) { - if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { - f() - } else if self.specialIsMainQueue && NSThread.isMainThread() { + public func sync(_ f: () -> Void) { + if self.isCurrent() { f() } else { - dispatch_async(self.nativeQueue, f) + self.nativeQueue.sync(execute: f) } } + + public func justDispatch(_ f: @escaping () -> Void) { + self.nativeQueue.async(execute: f) + } + + public func justDispatchWithQoS(qos: DispatchQoS, _ f: @escaping () -> Void) { + self.nativeQueue.async(group: nil, qos: qos, flags: [.enforceQoS], execute: f) + } + + public func after(_ delay: Double, _ f: @escaping(Void) -> Void) { + let time: DispatchTime = DispatchTime.now() + delay + self.nativeQueue.asyncAfter(deadline: time, execute: f) + } } diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index 1f8ab3d127..ea59ccd763 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -8,9 +8,14 @@ public func identity(a: A) -> A { return a; } -infix operator |> { associativity left precedence 95 } +precedencegroup PipeRight { + associativity: left + higherThan: DefaultPrecedence +} -public func |> (value: T, function: (T -> U)) -> U { +infix operator |> : PipeRight + +public func |> (value: T, function: ((T) -> U)) -> U { return function(value) } @@ -30,16 +35,47 @@ private final class SubscriberDisposable : Disposable { } public struct Signal { - private let generator: Subscriber -> Disposable + private let generator: (Subscriber) -> Disposable - public init(_ generator: Subscriber -> Disposable) { + public init(_ generator: @escaping(Subscriber) -> Disposable) { self.generator = generator } - public func start(next next: (T -> Void)! = nil, error: (E -> Void)! = nil, completed: (() -> Void)! = nil) -> Disposable { + public func start(next: ((T) -> Void)! = nil, error: ((E) -> Void)! = nil, completed: (() -> Void)! = nil) -> Disposable { let subscriber = Subscriber(next: next, error: error, completed: completed) let disposable = self.generator(subscriber) subscriber.assignDisposable(disposable) return SubscriberDisposable(subscriber: subscriber, disposable: disposable) } + + public static func single(_ value: T) -> Signal { + return Signal { subscriber in + subscriber.putNext(value) + subscriber.putCompletion() + + return EmptyDisposable + } + } + + public static func complete() -> Signal { + return Signal { subscriber in + subscriber.putCompletion() + + return EmptyDisposable + } + } + + public static func fail(_ error: E) -> Signal { + return Signal { subscriber in + subscriber.putError(error) + + return EmptyDisposable + } + } + + public static func never() -> Signal { + return Signal { _ in + return EmptyDisposable + } + } } diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index 80733ba4e6..b7b4a320a1 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -1,36 +1,38 @@ import Foundation -public func `catch`(f: E -> Signal)(signal: Signal) -> Signal { - return Signal { subscriber in - let disposable = DisposableSet() - - disposable.add(signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - let anotherSignal = f(error) +public func `catch`(_ f: @escaping(E) -> Signal) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + let disposable = DisposableSet() - disposable.add(anotherSignal.start(next: { next in + disposable.add(signal.start(next: { next in subscriber.putNext(next) }, error: { error in - subscriber.putError(error) + let anotherSignal = f(error) + + disposable.add(anotherSignal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) }, completed: { subscriber.putCompletion() })) - }, completed: { - subscriber.putCompletion() - })) - - return disposable + + return disposable + } } } -private func recursiveFunction(f: (Void -> Void) -> Void) -> (Void -> Void) { +private func recursiveFunction(_ f: @escaping(@escaping(Void) -> Void) -> Void) -> ((Void) -> Void) { return { f(recursiveFunction(f)) } } -public func restart(signal: Signal) -> Signal { +public func restart(_ signal: Signal) -> Signal { return Signal { subscriber in let shouldRestart = Atomic(value: true) let currentDisposable = MetaDisposable() @@ -55,76 +57,80 @@ public func restart(signal: Signal) -> Signal { return ActionDisposable { currentDisposable.dispose() - shouldRestart.swap(false) + let _ = shouldRestart.swap(false) } } } -public func recurse(latestValue: T?)(signal: Signal) -> Signal { - return Signal { subscriber in - let shouldRestart = Atomic(value: true) - let currentDisposable = MetaDisposable() - - let start = recursiveFunction { recurse in - let currentShouldRestart = shouldRestart.with { value in - return value +public func recurse(_ latestValue: T?) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + let shouldRestart = Atomic(value: true) + let currentDisposable = MetaDisposable() + + let start = recursiveFunction { recurse in + let currentShouldRestart = shouldRestart.with { value in + return value + } + if currentShouldRestart { + let disposable = signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + recurse() + }) + currentDisposable.set(disposable) + } } - if currentShouldRestart { - let disposable = signal.start(next: { next in - subscriber.putNext(next) + + start() + + return ActionDisposable { + currentDisposable.dispose() + let _ = shouldRestart.swap(false) + } + } + } +} + +public func retry(_ delayIncrement: Double, maxDelay: Double, onQueue queue: Queue) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + let shouldRetry = Atomic(value: true) + let currentDelay = Atomic(value: 0.0) + let currentDisposable = MetaDisposable() + + let start = recursiveFunction { recurse in + let currentShouldRetry = shouldRetry.with { value in + return value + } + if currentShouldRetry { + let disposable = signal.start(next: { next in + subscriber.putNext(next) }, error: { error in - subscriber.putError(error) + let delay = currentDelay.modify { value in + return min(maxDelay, value + delayIncrement) + } + + let time: DispatchTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) + queue.queue.asyncAfter(deadline: time, execute: { + recurse() + }) }, completed: { - recurse() - }) - currentDisposable.set(disposable) + let _ = shouldRetry.swap(false) + subscriber.putCompletion() + }) + currentDisposable.set(disposable) + } + } + + start() + + return ActionDisposable { + currentDisposable.dispose() + let _ = shouldRetry.swap(false) } - } - - start() - - return ActionDisposable { - currentDisposable.dispose() - shouldRestart.swap(false) - } - } -} - -public func retry(delayIncrement: Double, maxDelay: Double, onQueue queue: Queue)(signal: Signal) -> Signal { - return Signal { subscriber in - let shouldRetry = Atomic(value: true) - let currentDelay = Atomic(value: 0.0) - let currentDisposable = MetaDisposable() - - let start = recursiveFunction { recurse in - let currentShouldRetry = shouldRetry.with { value in - return value - } - if currentShouldRetry { - let disposable = signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - let delay = currentDelay.modify { value in - return min(maxDelay, value + delayIncrement) - } - - let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))) - dispatch_after(delayTime, queue.queue) { - recurse() - } - }, completed: { - shouldRetry.swap(false) - subscriber.putCompletion() - }) - currentDisposable.set(disposable) - } - } - - start() - - return ActionDisposable { - currentDisposable.dispose() - shouldRetry.swap(false) } } } diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index c9d455b033..ff32728c75 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -6,7 +6,7 @@ private struct SignalCombineState { let error: Bool } -private func combineLatestAny(signals: [Signal], combine: [Any] -> R, initialValues: [Int : Any]) -> Signal { +private func combineLatestAny(_ signals: [Signal], combine: @escaping([Any]) -> R, initialValues: [Int : Any]) -> Signal { return Signal { subscriber in let state = Atomic(value: SignalCombineState(values: initialValues, completed: Set(), error: false)) let disposable = DisposableSet() @@ -36,7 +36,7 @@ private func combineLatestAny(signals: [Signal], combine: [Any] -> } }, error: { error in var emitError = false - state.modify { current in + let _ = state.modify { current in if !current.error { emitError = true return SignalCombineState(values: current.values, completed: current.completed, error: true) @@ -49,7 +49,7 @@ private func combineLatestAny(signals: [Signal], combine: [Any] -> } }, completed: { var emitCompleted = false - state.modify { current in + let _ = state.modify { current in if !current.completed.contains(index) { var completed = current.completed completed.insert(index) @@ -70,7 +70,7 @@ private func combineLatestAny(signals: [Signal], combine: [Any] -> } } -private func signalOfAny(signal: Signal) -> Signal { +private func signalOfAny(_ signal: Signal) -> Signal { return Signal { subscriber in return signal.start(next: { next in subscriber.putNext(next) @@ -82,26 +82,40 @@ private func signalOfAny(signal: Signal) -> Signal { } } -public func combineLatest(s1: Signal, _ s2: Signal) -> Signal<(T1, T2), E> { +public func combineLatest(_ s1: Signal, _ s2: Signal) -> Signal<(T1, T2), E> { return combineLatestAny([signalOfAny(s1), signalOfAny(s2)], combine: { values in return (values[0] as! T1, values[1] as! T2) }, initialValues: [:]) } -public func combineLatest(s1: Signal, _ v1: T1, _ s2: Signal, _ v2: T2) -> Signal<(T1, T2), E> { +public func combineLatest(_ s1: Signal, _ v1: T1, _ s2: Signal, _ v2: T2) -> Signal<(T1, T2), E> { return combineLatestAny([signalOfAny(s1), signalOfAny(s2)], combine: { values in return (values[0] as! T1, values[1] as! T2) }, initialValues: [0: v1, 1: v2]) } -public func combineLatest(s1: Signal, _ s2: Signal, _ s3: Signal) -> Signal<(T1, T2, T3), E> { +public func combineLatest(_ s1: Signal, _ s2: Signal, _ s3: Signal) -> Signal<(T1, T2, T3), E> { return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3)], combine: { values in return (values[0] as! T1, values[1] as! T2, values[2] as! T3) }, initialValues: [:]) } -public func combineLatest(s1: Signal, _ s2: Signal, _ s3: Signal, s4: Signal) -> Signal<(T1, T2, T3, T4), E> { +public func combineLatest(_ s1: Signal, _ s2: Signal, _ s3: Signal, s4: Signal) -> Signal<(T1, T2, T3, T4), E> { return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4)], combine: { values in return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4) }, initialValues: [:]) } + +public func combineLatest(_ signals: [Signal]) -> Signal<[T], E> { + if signals.count == 0 { + return single([T](), E.self) + } + + return combineLatestAny(signals.map({signalOfAny($0)}), combine: { values in + var combined: [T] = [] + for value in values { + combined.append(value as! T) + } + return combined + }, initialValues: [:]) +} diff --git a/SwiftSignalKit/Signal_Dispatch.swift b/SwiftSignalKit/Signal_Dispatch.swift index f25cb7761d..c5ed6daaaa 100644 --- a/SwiftSignalKit/Signal_Dispatch.swift +++ b/SwiftSignalKit/Signal_Dispatch.swift @@ -1,92 +1,122 @@ import Foundation -public func deliverOn(queue: Queue)(signal: Signal) -> Signal { - return Signal { subscriber in - return signal.start(next: { next in - queue.dispatch { - subscriber.putNext(next) - } - }, error: { error in - queue.dispatch { - subscriber.putError(error) - } - }, completed: { - queue.dispatch { - subscriber.putCompletion() - } - }) - } -} - -public func deliverOnMainQueue(signal: Signal) -> Signal { - return signal |> deliverOn(Queue.mainQueue()) -} - -public func deliverOn(threadPool: ThreadPool)(signal: Signal) -> Signal { - return Signal { subscriber in - let queue = threadPool.nextQueue() - return signal.start(next: { next in - queue.addTask(ThreadPoolTask { state in - if !state.cancelled { +public func deliverOn(_ queue: Queue) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + queue.async { subscriber.putNext(next) } - }) - }, error: { error in - queue.addTask(ThreadPoolTask { state in - if !state.cancelled { + }, error: { error in + queue.async { subscriber.putError(error) } - }) - }, completed: { - queue.addTask(ThreadPoolTask { state in - if !state.cancelled { + }, completed: { + queue.async { subscriber.putCompletion() } }) - }) + } } } -public func runOn(threadPool: ThreadPool)(signal: Signal) -> Signal { - return Signal { subscriber in - let cancelled = false - let disposable = MetaDisposable() - - let task = ThreadPoolTask { state in - if cancelled || state.cancelled { - return +public func deliverOnMainQueue(_ signal: Signal) -> Signal { + return signal |> deliverOn(Queue.mainQueue()) +} + +public func deliverOn(_ threadPool: ThreadPool) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + let queue = threadPool.nextQueue() + return signal.start(next: { next in + queue.addTask(ThreadPoolTask { state in + if !state.cancelled { + subscriber.putNext(next) + } + }) + }, error: { error in + queue.addTask(ThreadPoolTask { state in + if !state.cancelled { + subscriber.putError(error) + } + }) + }, completed: { + queue.addTask(ThreadPoolTask { state in + if !state.cancelled { + subscriber.putCompletion() + } + }) + }) + } + } +} + +public func runOn(_ queue: Queue) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + if queue.isCurrent() { + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } else { + var cancelled = false + let disposable = MetaDisposable() + + disposable.set(ActionDisposable { + cancelled = true + }) + + queue.async { + if cancelled { + return + } + + disposable.set(signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + } + + return disposable + } + } + } +} + +public func runOn(_ threadPool: ThreadPool) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + let cancelled = false + let disposable = MetaDisposable() + + let task = ThreadPoolTask { state in + if cancelled || state.cancelled { + return + } + + disposable.set(signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) } - disposable.set(signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - })) + disposable.set(ActionDisposable { + task.cancel() + }) + + threadPool.addTask(task) + + return disposable } - - disposable.set(ActionDisposable { - task.cancel() - }) - - threadPool.addTask(task) - - return disposable - } -} - -public func bufferOn(queue: Queue, timeout: Double)(signal: Signal) -> Signal<[T], E> { - return Signal { subscriber in - let timer = Timer(timeout: timeout, `repeat`: false, completion: { - - }, queue: queue) - return signal.start(next: { next in - - }, error: { error in - subscriber.putError(error) - }, completed: { - - }) } } diff --git a/SwiftSignalKit/Signal_Mapping.swift b/SwiftSignalKit/Signal_Mapping.swift index fdec5584f9..c67a4ae44f 100644 --- a/SwiftSignalKit/Signal_Mapping.swift +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -1,21 +1,67 @@ import Foundation -public func map(f: T -> R)(signal: Signal) -> Signal { - return Signal { subscriber in - return signal.start(next: { next in - subscriber.putNext(f(next)) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - }) +public func map(_ f: @escaping(T) -> R) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + subscriber.putNext(f(next)) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } } } -public func filter(f: T -> Bool)(signal: Signal) -> Signal { - return Signal { subscriber in +public func filter(_ f: @escaping(T) -> Bool) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + if f(next) { + subscriber.putNext(next) + } + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } + } +} + +public func mapError(_ f: @escaping(E) -> R) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(f(error)) + }, completed: { + subscriber.putCompletion() + }) + } + } +} + +private class DistinctUntilChangedContext { + var value: T? +} + +public func distinctUntilChanged(_ signal: Signal) -> Signal { + return Signal { subscriber in + let context = Atomic(value: DistinctUntilChangedContext()) + return signal.start(next: { next in - if f(next) { + let pass = context.with { context -> Bool in + if let value = context.value, value == next { + return false + } else { + context.value = next + return true + } + } + if pass { subscriber.putNext(next) } }, error: { error in @@ -26,14 +72,28 @@ public func filter(f: T -> Bool)(signal: Signal) -> Signal { } } -public func mapError(f: E -> R)(signal: Signal) -> Signal { - return Signal { subscriber in - return signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - subscriber.putError(f(error)) - }, completed: { - subscriber.putCompletion() - }) +public func distinctUntilChanged(isEqual: @escaping (T, T) -> Bool) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + let context = Atomic(value: DistinctUntilChangedContext()) + + return signal.start(next: { next in + let pass = context.with { context -> Bool in + if let value = context.value, isEqual(value, next) { + return false + } else { + context.value = next + return true + } + } + if pass { + subscriber.putNext(next) + } + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } } } diff --git a/SwiftSignalKit/Signal_Materialize.swift b/SwiftSignalKit/Signal_Materialize.swift new file mode 100644 index 0000000000..92e7a9b3c9 --- /dev/null +++ b/SwiftSignalKit/Signal_Materialize.swift @@ -0,0 +1,40 @@ +import Foundation + +public enum SignalEvent { + case Next(T) + case Error(E) + case Completion +} + +public func dematerialize(signal: Signal) -> Signal, NoError> { + return Signal { subscriber in + return signal.start(next: { next in + subscriber.putNext(.Next(next)) + }, error: { error in + subscriber.putNext(.Error(error)) + subscriber.putCompletion() + }, completed: { + subscriber.putNext(.Completion) + subscriber.putCompletion() + }) + } +} + +public func materialize(signal: Signal, NoError>) -> Signal { + return Signal { subscriber in + return signal.start(next: { next in + switch next { + case let .Next(next): + subscriber.putNext(next) + case let .Error(error): + subscriber.putError(error) + case .Completion: + subscriber.putCompletion() + } + }, error: { _ in + subscriber.putCompletion() + }, completed: { + subscriber.putCompletion() + }) + } +} diff --git a/SwiftSignalKit/Signal_Merge.swift b/SwiftSignalKit/Signal_Merge.swift new file mode 100644 index 0000000000..df0dac256a --- /dev/null +++ b/SwiftSignalKit/Signal_Merge.swift @@ -0,0 +1,7 @@ +import Foundation + +/*public func merge(signal1: Signal, signal2: Signal) -> Signal { + return Signal { subscriber in + + } +}*/ diff --git a/SwiftSignalKit/Signal_Meta.swift b/SwiftSignalKit/Signal_Meta.swift index 34b275e30f..3534359b90 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -11,20 +11,25 @@ private final class SignalQueueState : Disposable { var queuedSignals: [Signal] = [] let queueMode: Bool + let throttleMode: Bool - init(subscriber: Subscriber, queueMode: Bool) { + init(subscriber: Subscriber, queueMode: Bool, throttleMode: Bool) { self.subscriber = subscriber self.queueMode = queueMode + self.throttleMode = throttleMode } - func beginWithDisposable(disposable: Disposable) { + func beginWithDisposable(_ disposable: Disposable) { self.disposable = disposable } - func enqueueSignal(signal: Signal) { + func enqueueSignal(_ signal: Signal) { var startSignal = false OSSpinLockLock(&self.lock) if self.queueMode && self.executingSignal { + if self.throttleMode { + self.queuedSignals.removeAll() + } self.queuedSignals.append(signal) } else { self.executingSignal = true @@ -56,7 +61,7 @@ private final class SignalQueueState : Disposable { if self.queueMode { if self.queuedSignals.count != 0 { nextSignal = self.queuedSignals[0] - self.queuedSignals.removeAtIndex(0) + self.queuedSignals.remove(at: 0) self.executingSignal = true } else { terminated = self.terminated @@ -106,9 +111,9 @@ private final class SignalQueueState : Disposable { } } -public func switchToLatest(signal: Signal, E>) -> Signal { +public func switchToLatest(_ signal: Signal, E>) -> Signal { return Signal { subscriber in - let state = SignalQueueState(subscriber: subscriber, queueMode: false) + let state = SignalQueueState(subscriber: subscriber, queueMode: false, throttleMode: false) state.beginWithDisposable(signal.start(next: { next in state.enqueueSignal(next) }, error: { error in @@ -120,9 +125,9 @@ public func switchToLatest(signal: Signal, E>) -> Signal(signal: Signal, E>) -> Signal { +public func queue(_ signal: Signal, E>) -> Signal { return Signal { subscriber in - let state = SignalQueueState(subscriber: subscriber, queueMode: true) + let state = SignalQueueState(subscriber: subscriber, queueMode: true, throttleMode: false) state.beginWithDisposable(signal.start(next: { next in state.enqueueSignal(next) }, error: { error in @@ -134,37 +139,83 @@ public func queue(signal: Signal, E>) -> Signal { } } -public func mapToSignal(f: T -> Signal)(signal: Signal) -> Signal { - return signal |> map { f($0) } |> switchToLatest -} - -public func mapToQueue(f: T -> Signal)(signal: Signal) -> Signal { - return signal |> map { f($0) } |> queue -} - -public func then(nextSignal: Signal)(signal: Signal) -> Signal { - return Signal { subscriber in - let disposable = DisposableSet() - - disposable.add(signal.start(next: { next in - subscriber.putNext(next) +public func throttled(_ signal: Signal, E>) -> Signal { + return Signal { subscriber in + let state = SignalQueueState(subscriber: subscriber, queueMode: true, throttleMode: true) + state.beginWithDisposable(signal.start(next: { next in + state.enqueueSignal(next) }, error: { error in subscriber.putError(error) }, completed: { - disposable.add(nextSignal.start(next: { next in - subscriber.putNext(next) + state.beginCompletion() + })) + return state + } +} + +public func mapToSignal(_ f: @escaping(T) -> Signal) -> (Signal) -> Signal { + return { signal -> Signal in + return Signal, E> { subscriber in + return signal.start(next: { next in + subscriber.putNext(f(next)) }, error: { error in subscriber.putError(error) }, completed: { subscriber.putCompletion() - })) - })) - - return disposable + }) + } |> switchToLatest } } -public func `defer`(generator: () -> Signal) -> Signal { +public func mapToSignalPromotingError(_ f: @escaping(T) -> Signal) -> (Signal) -> Signal { + return { signal -> Signal in + return Signal, E> { subscriber in + return signal.start(next: { next in + subscriber.putNext(f(next)) + }, completed: { + subscriber.putCompletion() + }) + } |> switchToLatest + } +} + +public func mapToQueue(_ f: @escaping(T) -> Signal) -> (Signal) -> Signal { + return { signal -> Signal in + return signal |> map { f($0) } |> queue + } +} + +public func mapToThrottled(_ f: @escaping(T) -> Signal) -> (Signal) -> Signal { + return { signal -> Signal in + return signal |> map { f($0) } |> throttled + } +} + +public func then(_ nextSignal: Signal) -> (Signal) -> Signal { + return { signal -> Signal in + return Signal { subscriber in + let disposable = DisposableSet() + + disposable.add(signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + disposable.add(nextSignal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + })) + + return disposable + } + } +} + +public func deferred(_ generator: @escaping() -> Signal) -> Signal { return Signal { subscriber in return generator().start(next: { next in subscriber.putNext(next) diff --git a/SwiftSignalKit/Signal_Reduce.swift b/SwiftSignalKit/Signal_Reduce.swift index b2623d06cc..d42ad64f5b 100644 --- a/SwiftSignalKit/Signal_Reduce.swift +++ b/SwiftSignalKit/Signal_Reduce.swift @@ -1,35 +1,39 @@ import Foundation -public func reduceLeft(value: T, f: (T, T) -> T)(signal: Signal) -> Signal { - return Signal { subscriber in - var currentValue = value - - return signal.start(next: { next in - currentValue = f(currentValue, next) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putNext(currentValue) - subscriber.putCompletion() - }) - } -} - -public func reduceLeft(value: T, f: (T, T, T -> Void) -> T)(signal: Signal) -> Signal { - return Signal { subscriber in - var currentValue = value - let emit: T -> Void = { next in - subscriber.putNext(next) - } - - return signal.start(next: { next in - currentValue = f(currentValue, next, emit) +public func reduceLeft(value: T, f: @escaping(T, T) -> T) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + var currentValue = value + + return signal.start(next: { next in + currentValue = f(currentValue, next) }, error: { error in subscriber.putError(error) }, completed: { subscriber.putNext(currentValue) subscriber.putCompletion() - }) + }) + } + } +} + +public func reduceLeft(value: T, f: @escaping(T, T, (T) -> Void) -> T) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + var currentValue = value + let emit: (T) -> Void = { next in + subscriber.putNext(next) + } + + return signal.start(next: { next in + currentValue = f(currentValue, next, emit) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putNext(currentValue) + subscriber.putCompletion() + }) + } } } @@ -51,17 +55,17 @@ private final class ReduceQueueState : Disposable { var generator: (T, T) -> Signal<(T, Passthrough), E> var value: T - init(subscriber: Subscriber, value: T, generator: (T, T) -> Signal<(T, Passthrough), E>) { + init(subscriber: Subscriber, value: T, generator: @escaping(T, T) -> Signal<(T, Passthrough), E>) { self.subscriber = subscriber self.generator = generator self.value = value } - func beginWithDisposable(disposable: Disposable) { + func beginWithDisposable(_ disposable: Disposable) { self.disposable = disposable } - func enqueueNext(next: T) { + func enqueueNext(_ next: T) { var startSignal = false var currentValue: T OSSpinLockLock(&self.lock) @@ -92,7 +96,7 @@ private final class ReduceQueueState : Disposable { } } - func updateValue(value: T) { + func updateValue(_ value: T) { OSSpinLockLock(&self.lock) self.value = value OSSpinLockUnlock(&self.lock) @@ -110,7 +114,7 @@ private final class ReduceQueueState : Disposable { self.executingSignal = false if self.queuedValues.count != 0 { nextSignal = self.generator(self.value, self.queuedValues[0]) - self.queuedValues.removeAtIndex(0) + self.queuedValues.remove(at: 0) self.executingSignal = true } else { currentValue = self.value @@ -168,16 +172,18 @@ private final class ReduceQueueState : Disposable { } } -public func reduceLeft(value: T, generator: (T, T) -> Signal<(T, Passthrough), E>)(signal: Signal) -> Signal { - return Signal { subscriber in - let state = ReduceQueueState(subscriber: subscriber, value: value, generator: generator) - state.beginWithDisposable(signal.start(next: { next in - state.enqueueNext(next) - }, error: { error in - subscriber.putError(error) - }, completed: { - state.beginCompletion() - })) - return state +public func reduceLeft(_ value: T, generator: @escaping(T, T) -> Signal<(T, Passthrough), E>) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + let state = ReduceQueueState(subscriber: subscriber, value: value, generator: generator) + state.beginWithDisposable(signal.start(next: { next in + state.enqueueNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + state.beginCompletion() + })) + return state + } } } diff --git a/SwiftSignalKit/Signal_SideEffects.swift b/SwiftSignalKit/Signal_SideEffects.swift index 9b8904c849..f3f480f6a2 100644 --- a/SwiftSignalKit/Signal_SideEffects.swift +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -1,45 +1,116 @@ import Foundation -public func beforeNext(f: T -> R)(signal: Signal) -> Signal { - return Signal { subscriber in - return signal.start(next: { next in - let _ = f(next) - subscriber.putNext(next) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - }) +public func beforeNext(_ f: @escaping(T) -> R) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + let _ = f(next) + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } } } -public func afterNext(f: T -> R)(signal: Signal) -> Signal { - return Signal { subscriber in - return signal.start(next: { next in - subscriber.putNext(next) - let _ = f(next) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - }) +public func afterNext(_ f: @escaping(T) -> R) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + subscriber.putNext(next) + let _ = f(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } } } -public func afterDisposed(f: Void -> R)(signal: Signal) -> Signal { - return Signal { subscriber in - let disposable = DisposableSet() - disposable.add(signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - })) - disposable.add(ActionDisposable { - let _ = f() - }) - - return disposable +public func beforeStarted(_ f: @escaping() -> Void) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + f() + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } } -} \ No newline at end of file +} + +public func beforeCompleted(_ f: @escaping() -> Void) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + f() + subscriber.putCompletion() + }) + } + } +} + +public func afterCompleted(_ f: @escaping() -> Void) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + f() + }) + } + } +} + +public func afterDisposed(_ f: @escaping(Void) -> R) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + let disposable = DisposableSet() + disposable.add(signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + disposable.add(ActionDisposable { + let _ = f() + }) + + return disposable + } + } +} + +public func withState(_ signal: Signal, _ initialState: @escaping() -> S, next: @escaping(T, S) -> Void = { _ in }, error: @escaping(E, S) -> Void = { _ in }, completed: @escaping(S) -> Void = { _ in }, disposed: @escaping(S) -> Void = { _ in }) -> Signal { + return Signal { subscriber in + let state = initialState() + let disposable = signal.start(next: { vNext in + next(vNext, state) + subscriber.putNext(vNext) + }, error: { vError in + error(vError, state) + subscriber.putError(vError) + }, completed: { + completed(state) + subscriber.putCompletion() + }) + return ActionDisposable { + disposable.dispose() + disposed(state) + } + } +} diff --git a/SwiftSignalKit/Signal_Single.swift b/SwiftSignalKit/Signal_Single.swift index a17dde6db4..c2d658dbb2 100644 --- a/SwiftSignalKit/Signal_Single.swift +++ b/SwiftSignalKit/Signal_Single.swift @@ -1,6 +1,6 @@ import Foundation -public func single(value: T, _ errorType: E.Type) -> Signal { +public func single(_ value: T, _ errorType: E.Type) -> Signal { return Signal { subscriber in subscriber.putNext(value) subscriber.putCompletion() @@ -9,7 +9,7 @@ public func single(value: T, _ errorType: E.Type) -> Signal { } } -public func fail(valueType: T.Type, _ error: E) -> Signal { +public func fail(_ valueType: T.Type, _ error: E) -> Signal { return Signal { subscriber in subscriber.putError(error) @@ -17,7 +17,7 @@ public func fail(valueType: T.Type, _ error: E) -> Signal { } } -public func complete(valueType: T.Type, _ error: E.Type) -> Signal { +public func complete(_ valueType: T.Type, _ error: E.Type) -> Signal { return Signal { subscriber in subscriber.putCompletion() @@ -25,7 +25,7 @@ public func complete(valueType: T.Type, _ error: E.Type) -> Signal { } } -public func never(valueType: T.Type, _ error: E.Type) -> Signal { +public func never(_ valueType: T.Type, _ error: E.Type) -> Signal { return Signal { _ in return EmptyDisposable } diff --git a/SwiftSignalKit/Signal_Take.swift b/SwiftSignalKit/Signal_Take.swift index a7a9b563c4..3a4eda1cee 100644 --- a/SwiftSignalKit/Signal_Take.swift +++ b/SwiftSignalKit/Signal_Take.swift @@ -1,28 +1,30 @@ import Foundation -public func take(count: Int)(signal: Signal) -> Signal { - return Signal { subscriber in - let counter = Atomic(value: 0) - return signal.start(next: { next in - var passthrough = false - var complete = false - counter.modify { value in - let updatedCount = value + 1 - passthrough = updatedCount <= count - complete = updatedCount == count - return updatedCount - } - if passthrough { - subscriber.putNext(next) - } - if complete { +public func take(_ count: Int) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + let counter = Atomic(value: 0) + return signal.start(next: { next in + var passthrough = false + var complete = false + let _ = counter.modify { value in + let updatedCount = value + 1 + passthrough = updatedCount <= count + complete = updatedCount == count + return updatedCount + } + if passthrough { + subscriber.putNext(next) + } + if complete { + subscriber.putCompletion() + } + }, error: { error in + subscriber.putError(error) + }, completed: { subscriber.putCompletion() - } - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - }) + }) + } } } @@ -30,7 +32,7 @@ public func last(signal: Signal) -> Signal { return Signal { subscriber in let value = Atomic(value: nil) return signal.start(next: { next in - value.swap(next) + let _ = value.swap(next) }, error: { error in subscriber.putError(error) }, completed: { completed in diff --git a/SwiftSignalKit/Signal_Timing.swift b/SwiftSignalKit/Signal_Timing.swift index ae483dbab9..ad1c7bc82c 100644 --- a/SwiftSignalKit/Signal_Timing.swift +++ b/SwiftSignalKit/Signal_Timing.swift @@ -1,56 +1,60 @@ import Foundation -public func delay(timeout: NSTimeInterval, queue: Queue)(signal: Signal) -> Signal { - return Signal { subscriber in - let disposable = MetaDisposable() - let timer = Timer(timeout: timeout, `repeat`: false, completion: { - disposable.set(signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - })) - }, queue: queue) - disposable.set(ActionDisposable { - timer.invalidate() - }) - timer.start() - return disposable +public func delay(_ timeout: Double, queue: Queue) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + let disposable = MetaDisposable() + let timer = Timer(timeout: timeout, repeat: false, completion: { + disposable.set(signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + }, queue: queue) + disposable.set(ActionDisposable { + timer.invalidate() + }) + timer.start() + return disposable + } } } -public func timeout(timeout: NSTimeInterval, queue: Queue, alternate: Signal)(signal: Signal) -> Signal { - return Signal { subscriber in - let disposable = MetaDisposable() - let timer = Timer(timeout: timeout, `repeat`: false, completion: { - disposable.set(alternate.start(next: { next in +public func timeout(_ timeout: Double, queue: Queue, alternate: Signal) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + let disposable = MetaDisposable() + let timer = Timer(timeout: timeout, repeat: false, completion: { + disposable.set(alternate.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + }, queue: queue) + + disposable.set(signal.start(next: { next in + timer.invalidate() subscriber.putNext(next) }, error: { error in + timer.invalidate() subscriber.putError(error) }, completed: { + timer.invalidate() subscriber.putCompletion() })) - }, queue: queue) - - disposable.set(signal.start(next: { next in - timer.invalidate() - subscriber.putNext(next) - }, error: { error in - timer.invalidate() - subscriber.putError(error) - }, completed: { - timer.invalidate() - subscriber.putCompletion() - })) - timer.start() - - let disposableSet = DisposableSet() - disposableSet.add(ActionDisposable { - timer.invalidate() - }) - disposableSet.add(disposable) - - return disposableSet + timer.start() + + let disposableSet = DisposableSet() + disposableSet.add(ActionDisposable { + timer.invalidate() + }) + disposableSet.add(disposable) + + return disposableSet + } } } diff --git a/SwiftSignalKit/Subscriber.swift b/SwiftSignalKit/Subscriber.swift index 2b74e2f57c..65626a9af6 100644 --- a/SwiftSignalKit/Subscriber.swift +++ b/SwiftSignalKit/Subscriber.swift @@ -1,21 +1,26 @@ import Foundation public final class Subscriber { - private var next: (T -> Void)! - private var error: (E -> Void)! + private var next: ((T) -> Void)! + private var error: ((E) -> Void)! private var completed: (() -> Void)! - private var lock: OSSpinLock = 0 + private var lock = pthread_mutex_t() private var terminated = false internal var disposable: Disposable! - public init(next: (T -> Void)! = nil, error: (E -> Void)! = nil, completed: (() -> Void)! = nil) { + public init(next: ((T) -> Void)! = nil, error: ((E) -> Void)! = nil, completed: (() -> Void)! = nil) { self.next = next self.error = error self.completed = completed + pthread_mutex_init(&self.lock, nil) } - internal func assignDisposable(disposable: Disposable) { + deinit { + pthread_mutex_destroy(&self.lock) + } + + internal func assignDisposable(_ disposable: Disposable) { if self.terminated { disposable.dispose() } else { @@ -24,34 +29,34 @@ public final class Subscriber { } internal func markTerminatedWithoutDisposal() { - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) if !self.terminated { self.terminated = true self.next = nil self.error = nil self.completed = nil } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) } - public func putNext(next: T) { - var action: (T -> Void)! = nil - OSSpinLockLock(&self.lock) + public func putNext(_ next: T) { + var action: ((T) -> Void)! = nil + pthread_mutex_lock(&self.lock) if !self.terminated { action = self.next } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if action != nil { action(next) } } - public func putError(error: E) { + public func putError(_ error: E) { var shouldDispose = false - var action: (E -> Void)! = nil + var action: ((E) -> Void)! = nil - OSSpinLockLock(&self.lock); + pthread_mutex_lock(&self.lock) if !self.terminated { action = self.error shouldDispose = true; @@ -60,14 +65,14 @@ public final class Subscriber { self.completed = nil; self.terminated = true } - OSSpinLockUnlock(&self.lock); + pthread_mutex_unlock(&self.lock) if action != nil { action(error) } if shouldDispose && self.disposable != nil { - let disposable = self.disposable + let disposable = self.disposable! disposable.dispose() self.disposable = nil } @@ -77,7 +82,7 @@ public final class Subscriber { var shouldDispose = false var action: (() -> Void)! = nil - OSSpinLockLock(&self.lock); + pthread_mutex_lock(&self.lock) if !self.terminated { action = self.completed shouldDispose = true; @@ -86,14 +91,14 @@ public final class Subscriber { self.completed = nil; self.terminated = true } - OSSpinLockUnlock(&self.lock); + pthread_mutex_unlock(&self.lock) if action != nil { action() } if shouldDispose && self.disposable != nil { - let disposable = self.disposable + let disposable = self.disposable! disposable.dispose() self.disposable = nil } diff --git a/SwiftSignalKit/ThreadPool.swift b/SwiftSignalKit/ThreadPool.swift index 74b86e8c30..eb149f6446 100644 --- a/SwiftSignalKit/ThreadPool.swift +++ b/SwiftSignalKit/ThreadPool.swift @@ -6,13 +6,13 @@ public final class ThreadPoolTaskState { public final class ThreadPoolTask { private let state = ThreadPoolTaskState() - private let action: ThreadPoolTaskState -> () + private let action: (ThreadPoolTaskState) -> () - public init(_ action: ThreadPoolTaskState -> ()) { + public init(_ action: @escaping(ThreadPoolTaskState) -> ()) { self.action = action } - internal func execute() { + func execute() { if !state.cancelled { self.action(self.state) } @@ -31,7 +31,7 @@ public final class ThreadPoolQueue : Equatable { self.threadPool = threadPool } - public func addTask(task: ThreadPoolTask) { + public func addTask(_ task: ThreadPoolTask) { if let threadPool = self.threadPool { threadPool.workOnQueue(self, action: { self.tasks.append(task) @@ -39,17 +39,17 @@ public final class ThreadPoolQueue : Equatable { } } - private func popFirstTask() -> ThreadPoolTask? { + fileprivate func popFirstTask() -> ThreadPoolTask? { if self.tasks.count != 0 { let task = self.tasks[0]; - self.tasks.removeAtIndex(0) + self.tasks.remove(at: 0) return task } else { return nil } } - private func hasTasks() -> Bool { + fileprivate func hasTasks() -> Bool { return self.tasks.count != 0 } } @@ -59,13 +59,13 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { } @objc public final class ThreadPool: NSObject { - private var threads: [NSThread] = [] + private var threads: [Thread] = [] private var queues: [ThreadPoolQueue] = [] private var takenQueues: [ThreadPoolQueue] = [] private var mutex: pthread_mutex_t private var condition: pthread_cond_t - @objc class func threadEntryPoint(threadPool: ThreadPool) { + @objc class func threadEntryPoint(_ threadPool: ThreadPool) { var queue: ThreadPoolQueue! while (true) { @@ -74,8 +74,8 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { pthread_mutex_lock(&threadPool.mutex); if queue != nil { - if let index = threadPool.takenQueues.indexOf(queue) { - threadPool.takenQueues.removeAtIndex(index) + if let index = threadPool.takenQueues.index(of: queue) { + threadPool.takenQueues.remove(at: index) } if queue.hasTasks() { @@ -97,8 +97,8 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { task = queue.popFirstTask() threadPool.takenQueues.append(queue) - if let index = threadPool.queues.indexOf(queue) { - threadPool.queues.removeAtIndex(index) + if let index = threadPool.queues.index(of: queue) { + threadPool.queues.remove(at: index) } break @@ -125,7 +125,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { super.init() for _ in 0 ..< threadCount { - let thread = NSThread(target: ThreadPool.self, selector: Selector("threadEntryPoint:"), object: self) + let thread = Thread(target: ThreadPool.self, selector: #selector(ThreadPool.threadEntryPoint(_:)), object: self) thread.threadPriority = threadPriority self.threads.append(thread) thread.start() @@ -137,12 +137,12 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { pthread_cond_destroy(&self.condition) } - public func addTask(task: ThreadPoolTask) { + public func addTask(_ task: ThreadPoolTask) { let tempQueue = self.nextQueue() tempQueue.addTask(task) } - private func workOnQueue(queue: ThreadPoolQueue, action: () -> ()) { + fileprivate func workOnQueue(_ queue: ThreadPoolQueue, action: () -> ()) { pthread_mutex_lock(&self.mutex) action() if !self.queues.contains(queue) && !self.takenQueues.contains(queue) { @@ -157,7 +157,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { } public func isCurrentThreadInPool() -> Bool { - let currentThread = NSThread.currentThread() + let currentThread = Thread.current for thread in self.threads { if currentThread.isEqual(thread) { return true @@ -165,4 +165,4 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { } return false } -} \ No newline at end of file +} diff --git a/SwiftSignalKit/Timer.swift b/SwiftSignalKit/Timer.swift index 965ca96747..e88379b0fe 100644 --- a/SwiftSignalKit/Timer.swift +++ b/SwiftSignalKit/Timer.swift @@ -1,13 +1,13 @@ import Foundation public final class Timer { - private var timer: dispatch_source_t! - private var timeout: NSTimeInterval + private var timer: DispatchSourceTimer? + private var timeout: Double private var `repeat`: Bool - private var completion: Void -> Void + private var completion: (Void) -> Void private var queue: Queue - public init(timeout: NSTimeInterval, `repeat`: Bool, completion: Void -> Void, queue: Queue) { + public init(timeout: Double, `repeat`: Bool, completion: @escaping(Void) -> Void, queue: Queue) { self.timeout = timeout self.`repeat` = `repeat` self.completion = completion @@ -19,9 +19,8 @@ public final class Timer { } public func start() { - self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue.queue) - dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, Int64(self.timeout * NSTimeInterval(NSEC_PER_SEC))), self.`repeat` ? UInt64(self.timeout * NSTimeInterval(NSEC_PER_SEC)) : DISPATCH_TIME_FOREVER, 0); - dispatch_source_set_event_handler(self.timer, { [weak self] in + let timer = DispatchSource.makeTimerSource(queue: self.queue.queue) + timer.setEventHandler(handler: { [weak self] in if let strongSelf = self { strongSelf.completion() if !strongSelf.`repeat` { @@ -29,12 +28,22 @@ public final class Timer { } } }) - dispatch_resume(self.timer) + self.timer = timer + + if self.`repeat` { + let time: DispatchTime = DispatchTime.now() + self.timeout + timer.scheduleRepeating(deadline: time, interval: self.timeout) + } else { + let time: DispatchTime = DispatchTime.now() + self.timeout + timer.scheduleOneshot(deadline: time) + } + + timer.resume() } public func invalidate() { - if self.timer != nil { - dispatch_source_cancel(self.timer) + if let timer = self.timer { + timer.cancel() self.timer = nil } } diff --git a/SwiftSignalKit/Pipe.swift b/SwiftSignalKit/ValuePipe.swift similarity index 81% rename from SwiftSignalKit/Pipe.swift rename to SwiftSignalKit/ValuePipe.swift index 883b9c3071..f36f56ee70 100644 --- a/SwiftSignalKit/Pipe.swift +++ b/SwiftSignalKit/ValuePipe.swift @@ -1,10 +1,9 @@ import Foundation -public final class Pipe { - let subscribers = Atomic(value: Bag Void>()) +public final class ValuePipe { + private let subscribers = Atomic(value: Bag<(T) -> Void>()) public init() { - } public func signal() -> Signal { @@ -29,8 +28,8 @@ public final class Pipe { } } - public func putNext(next: T) { - let items = self.subscribers.with { value -> [T -> Void] in + public func putNext(_ next: T) { + let items = self.subscribers.with { value -> [(T) -> Void] in return value.copyItems() } for f in items { diff --git a/SwiftSignalKitMac/Info.plist b/SwiftSignalKitMac/Info.plist new file mode 100644 index 0000000000..ab41b55afe --- /dev/null +++ b/SwiftSignalKitMac/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2016 Telegram. All rights reserved. + NSPrincipalClass + + + diff --git a/SwiftSignalKitMac/SwiftSignalKitMac.h b/SwiftSignalKitMac/SwiftSignalKitMac.h new file mode 100644 index 0000000000..eef45f9dd5 --- /dev/null +++ b/SwiftSignalKitMac/SwiftSignalKitMac.h @@ -0,0 +1,19 @@ +// +// SwiftSignalKitMac.h +// SwiftSignalKitMac +// +// Created by Peter on 9/5/16. +// Copyright © 2016 Telegram. All rights reserved. +// + +#import + +//! Project version number for SwiftSignalKitMac. +FOUNDATION_EXPORT double SwiftSignalKitMacVersionNumber; + +//! Project version string for SwiftSignalKitMac. +FOUNDATION_EXPORT const unsigned char SwiftSignalKitMacVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/SwiftSignalKitTests/DeallocatingObject.swift b/SwiftSignalKitTests/DeallocatingObject.swift index 1b759b9cdd..840ca1075b 100644 --- a/SwiftSignalKitTests/DeallocatingObject.swift +++ b/SwiftSignalKitTests/DeallocatingObject.swift @@ -8,7 +8,7 @@ internal class DeallocatingObject : CustomStringConvertible { } deinit { - self.deallocated.memory = true + self.deallocated.pointee = true } var description: String { diff --git a/SwiftSignalKitTests/PerformanceTests.swift b/SwiftSignalKitTests/PerformanceTests.swift new file mode 100644 index 0000000000..041c3b8654 --- /dev/null +++ b/SwiftSignalKitTests/PerformanceTests.swift @@ -0,0 +1,166 @@ +import UIKit +import XCTest +import SwiftSignalKit +import Foundation + +final class DisposableLock { + private var action: (() -> Void)? + private var lock = pthread_mutex_t() + + init(action: () -> Void) { + self.action = action + pthread_mutex_init(&self.lock, nil) + } + + func dispose() { + var action: (() -> Void)? + pthread_mutex_lock(&self.lock) + action = self.action + self.action = nil + pthread_mutex_unlock(&self.lock) + if let action = action { + action() + } + } +} + +final class DisposableSpinLock { + private var action: (() -> Void)? + private var lock = OSSpinLock() + + init(action: () -> Void) { + self.action = action + } + + func dispose() { + var action: (() -> Void)? + OSSpinLockLock(&self.lock) + action = self.action + self.action = nil + OSSpinLockUnlock(&self.lock) + if let action = action { + action() + } + } +} + +final class DisposableNoLock { + private var action: (() -> Void)? + + init(action: () -> Void) { + self.action = action + } + + func dispose() { + var action: (() -> Void)? + action = self.action + self.action = nil + if let action = action { + action() + } + } +} + +final class DisposableAtomic { + private var action: () -> Void + private var disposed: Int32 = 0 + + init(action: () -> Void) { + self.action = action + } + + func dispose() { + if OSAtomicCompareAndSwap32(0, 1, &self.disposed) { + self.action() + } + } +} + +class PerformanceTests: XCTestCase { + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testMeasureLock() { + measure { + for _ in 0 ..< 1000000 { + let disposable = DisposableLock(action: {}) + disposable.dispose() + } + } + } + + func testMeasureSpinlock() { + measure { + for _ in 0 ..< 1000000 { + let disposable = DisposableSpinLock(action: {}) + disposable.dispose() + } + } + } + + func testMeasureAtomic() { + measure { + for _ in 0 ..< 1000000 { + let disposable = DisposableAtomic(action: {}) + disposable.dispose() + } + } + } + + func read(_ idxin: Int, _ size: Int, _ tree: inout [Int: Int], _ reads: inout Set) -> Int { + var idx = idxin + var sum = 0 + while idx <= size { + print("read at \(idx)") + if let value = tree[idx] { + sum += value + } + reads.insert(idx) + idx += (idx & -idx) + } + return sum + } + + func update(_ idxin: Int, _ val: Int, _ tree: inout [Int: Int], _ updates: inout Set) { + var idx = idxin + while (idx > 0) { + if let value = tree[idx] { + tree[idx] = value + val + } else { + tree[idx] = val + } + //print("write at \(idx)") + updates.insert(idx) + idx -= (idx & -idx) + } + } + + func testTree() { + let size = 2_000_000 + var dict: [Int: Int] = [:] + + var updates = Set() + var index = 0 + for _ in 1 ..< 100_000 { + //update(Int(1 + arc4random_uniform(UInt32(size))), 1, &dict, &updates) + update(index, 1, &dict, &updates) + index += Int(1 + arc4random_uniform(100)) + } + update(size - 1, 1, &dict, &updates) + print("update ops = \(updates.count), tree = \(dict.count) items") + + var reads = Set() + let sum = read(1, size, &dict, &reads) + print("read = \(sum) ops = \(reads.count)") + + update(99, -2, &dict, &updates) + reads.removeAll() + let sum2 = read(1, size, &dict, &reads) + print("read2 = \(sum2) ops = \(reads.count)") + } +} diff --git a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift index 91ed5ac9fa..813e89f007 100644 --- a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift +++ b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift @@ -17,7 +17,7 @@ class SwiftSignalKitTests: XCTestCase { if true { var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) let disposable = ActionDisposable(action: { [object] () -> Void in - object.debugDescription + let _ = object.debugDescription disposed = true }) object = nil @@ -33,9 +33,9 @@ class SwiftSignalKitTests: XCTestCase { var deallocated = false var disposed = false if true { - var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) - let disposable = ActionDisposable(action: { [object] () -> Void in - object.debugDescription + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let _ = ActionDisposable(action: { [object] () -> Void in + let _ = object.debugDescription disposed = true }) } @@ -47,9 +47,9 @@ class SwiftSignalKitTests: XCTestCase { var deallocated = false var disposed = false if true { - var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) let disposable = ActionDisposable(action: { [object] () -> Void in - object.debugDescription + let _ = object.debugDescription disposed = true }) @@ -67,15 +67,15 @@ class SwiftSignalKitTests: XCTestCase { var deallocated2 = false var disposed2 = false if true { - var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in - object1.debugDescription + let _ = object1.debugDescription disposed1 = true }) - var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in - object2.debugDescription + let _ = object2.debugDescription disposed2 = true }) @@ -94,9 +94,9 @@ class SwiftSignalKitTests: XCTestCase { var deallocated = false var disposed = false if true { - var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) let disposable = ActionDisposable(action: { [object] () -> Void in - object.debugDescription + let _ = object.debugDescription disposed = true }) @@ -111,9 +111,9 @@ class SwiftSignalKitTests: XCTestCase { var deallocated = false var disposed = false if true { - var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) let disposable = ActionDisposable(action: { [object] () -> Void in - object.debugDescription + let _ = object.debugDescription disposed = true }) @@ -131,15 +131,15 @@ class SwiftSignalKitTests: XCTestCase { var deallocated2 = false var disposed2 = false if true { - var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in - object1.debugDescription + let _ = object1.debugDescription disposed1 = true }) - var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in - object2.debugDescription + let _ = object2.debugDescription disposed2 = true }) @@ -158,9 +158,9 @@ class SwiftSignalKitTests: XCTestCase { var deallocated = false var disposed = false if true { - var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) let disposable = ActionDisposable(action: { [object] () -> Void in - object.debugDescription + let _ = object.debugDescription disposed = true }) @@ -177,15 +177,15 @@ class SwiftSignalKitTests: XCTestCase { var deallocated2 = false var disposed2 = false if true { - var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in - object1.debugDescription + let _ = object1.debugDescription disposed1 = true }) - var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in - object2.debugDescription + let _ = object2.debugDescription disposed2 = true }) @@ -205,15 +205,15 @@ class SwiftSignalKitTests: XCTestCase { var deallocated2 = false var disposed2 = false if true { - var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in - object1.debugDescription + let _ = object1.debugDescription disposed1 = true }) - var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in - object2.debugDescription + let _ = object2.debugDescription disposed2 = true }) @@ -234,15 +234,15 @@ class SwiftSignalKitTests: XCTestCase { var deallocated2 = false var disposed2 = false if true { - var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in - object1.debugDescription + let _ = object1.debugDescription disposed1 = true }) - var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in - object2.debugDescription + let _ = object2.debugDescription disposed2 = true }) diff --git a/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift b/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift index 76752847ca..a7c418579d 100644 --- a/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift +++ b/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift @@ -2,7 +2,7 @@ import UIKit import XCTest import SwiftSignalKit -func singleSignalInt(value: Signal) -> Signal, Void> { +func singleSignalInt(_ value: Signal) -> Signal, Void> { return Signal { subscriber in subscriber.putNext(value) subscriber.putCompletion() @@ -30,14 +30,14 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let signal = Signal { [object] subscriber in subscriber.putNext(1) return ActionDisposable { - object?.description + let _ = object?.description disposed = true } } let disposable = signal.start(next: { [object] next in generated = true - object?.description + let _ = object?.description }) object = nil @@ -65,17 +65,17 @@ class SwiftSignalKitFunctionsTests: XCTestCase { subscriber.putCompletion() return ActionDisposable { - object?.description + let _ = object?.description disposed = true } } let disposable = signal.start(next: { [object] next in generated = true - object?.description + let _ = object?.description }, completed: { [object] completed = true - object?.description + let _ = object?.description }) object = nil @@ -105,21 +105,21 @@ class SwiftSignalKitFunctionsTests: XCTestCase { subscriber.putNext(1) return ActionDisposable { - object?.description + let _ = object?.description disposed = true } } let disposable = signal.start(next: { [object] next in generated = true - object?.description + let _ = object?.description }, error: { [object] _ in error = true - object?.description + let _ = object?.description }, completed: { [object] completed = true - object?.description + let _ = object?.description }) object = nil @@ -147,7 +147,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { subscriber.putNext(1) return ActionDisposable { - object?.description + let _ = object?.description disposed = true } } @@ -155,7 +155,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let disposable = signal.start(next: { [object] next in generated = next == 2 - object?.description + let _ = object?.description }) object = nil @@ -185,7 +185,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { } var result = 0 - catchSignal.start(next: { next in + let _ = catchSignal.start(next: { next in result += next }) @@ -195,14 +195,14 @@ class SwiftSignalKitFunctionsTests: XCTestCase { func testSubscriberDisposal() { var disposed = false var generated = false - var queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + let queue = DispatchQueue(label: "") if true { let signal = Signal { subscriber in - dispatch_async(queue, { + queue.async { usleep(200) subscriber.putNext(1) - }) + } return ActionDisposable { disposed = true } @@ -213,7 +213,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { }) disposable.dispose() - dispatch_barrier_sync(queue, {}) + queue.sync(flags: [.barrier], execute: {}) XCTAssertTrue(disposed, "disposed != true") XCTAssertFalse(generated, "generated != false") @@ -245,7 +245,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { } }) - signal.start(next: { next in + let _ = signal.start(next: { next in result += next }) @@ -271,7 +271,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let signal = combineLatest(s1, s2) var completed = false - signal.start(next: { next in + let _ = signal.start(next: { next in XCTAssert(next.0 == 1 && next.1 == 2, "next != (1, 2)") return }, completed: { @@ -300,7 +300,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let signal = combineLatest(s1, s2, s3) var completed = false - signal.start(next: { next in + let _ = signal.start(next: { next in XCTAssert(next.0 == 1 && next.1 == 2 && next.2 == 3, "next != (1, 2, 3)") return }, completed: { @@ -315,19 +315,19 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let s3 = complete(Int.self, Void.self) var singleEmitted = false - s1.start(next: { next in + let _ = s1.start(next: { next in singleEmitted = next == 1 }) XCTAssert(singleEmitted == true, "singleEmitted != true") var errorEmitted = false - s2.start(error: { error in + let _ = s2.start(error: { error in errorEmitted = true }) XCTAssert(errorEmitted == true, "errorEmitted != true") var completedEmitted = false - s3.start(completed: { + let _ = s3.start(completed: { completedEmitted = true }) XCTAssert(completedEmitted == true, "errorEmitted != true") @@ -345,15 +345,15 @@ class SwiftSignalKitFunctionsTests: XCTestCase { var deallocatedThree = false if true { - var objectOne: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedOne) - var objectTwo: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedTwo) - var objectThree: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedThree) + let objectOne: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedOne) + let objectTwo: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedTwo) + let objectThree: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedThree) let one = Signal { subscriber in subscriber.putNext(1) subscriber.putCompletion() return ActionDisposable { [objectOne] in - objectOne?.description + let _ = objectOne?.description disposedOne = true } } @@ -362,7 +362,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { subscriber.putNext(2) subscriber.putCompletion() return ActionDisposable { [objectTwo] in - objectTwo?.description + let _ = objectTwo?.description disposedTwo = true } } @@ -371,14 +371,14 @@ class SwiftSignalKitFunctionsTests: XCTestCase { subscriber.putNext(3) subscriber.putCompletion() return ActionDisposable { [objectThree] in - objectThree?.description + let _ = objectThree?.description disposedThree = true } } let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> switchToLatest - signal.start(next: { next in + let _ = signal.start(next: { next in result.append(next) }, completed: { completedAll = true @@ -405,7 +405,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let signal = singleSignalInt(one) |> switchToLatest - signal.start(error: { error in + let _ = signal.start(error: { error in errorGenerated = true }) @@ -413,7 +413,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { } func testQueue() { - let q = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) + let q = DispatchQueue(label: "") var disposedOne = false var disposedTwo = false @@ -422,30 +422,30 @@ class SwiftSignalKitFunctionsTests: XCTestCase { var result: [Int] = [] let one = Signal { subscriber in - dispatch_async(q, { + q.async { subscriber.putNext(1) subscriber.putCompletion() - }) + } return ActionDisposable { disposedOne = true } } let two = Signal { subscriber in - dispatch_async(q, { + q.async { subscriber.putNext(2) subscriber.putCompletion() - }) + } return ActionDisposable { disposedTwo = true } } let three = Signal { subscriber in - dispatch_async(q, { + q.async { subscriber.putNext(3) subscriber.putCompletion() - }) + } return ActionDisposable { disposedThree = true } @@ -453,7 +453,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue - signal.start(next: { next in + let _ = signal.start(next: { next in print("next: \(next)") result.append(next) }, completed: { @@ -470,7 +470,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { } func testQueueInterrupted() { - let q = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) + let q = DispatchQueue(label: "") var disposedOne = false var disposedTwo = false @@ -480,20 +480,20 @@ class SwiftSignalKitFunctionsTests: XCTestCase { var result: [Int] = [] let one = Signal { subscriber in - dispatch_async(q, { + q.async { subscriber.putNext(1) subscriber.putCompletion() - }) + } return ActionDisposable { disposedOne = true } } let two = Signal { subscriber in - dispatch_async(q, { + q.async { subscriber.putNext(2) subscriber.putError(Void()) - }) + } return ActionDisposable { disposedTwo = true } @@ -501,10 +501,10 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let three = Signal { subscriber in startedThird = true - dispatch_async(q, { + q.async { subscriber.putNext(3) subscriber.putCompletion() - }) + } return ActionDisposable { disposedThree = true } @@ -512,7 +512,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue - signal.start(next: { next in + let _ = signal.start(next: { next in result.append(next) }, completed: { completedAll = true @@ -529,7 +529,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { } func testQueueDisposed() { - let q = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) + let q = DispatchQueue(label: "") var disposedOne = false var disposedTwo = false @@ -542,13 +542,13 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let one = Signal { subscriber in startedFirst = true var cancelled = false - dispatch_async(q, { + q.async { if !cancelled { usleep(100 * 1000) subscriber.putNext(1) subscriber.putCompletion() } - }) + } return ActionDisposable { cancelled = true disposedOne = true @@ -558,13 +558,13 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let two = Signal { subscriber in startedSecond = true var cancelled = false - dispatch_async(q, { + q.async { if !cancelled { usleep(100 * 1000) subscriber.putNext(2) subscriber.putError(Void()) } - }) + } return ActionDisposable { cancelled = true disposedTwo = true @@ -574,13 +574,13 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let three = Signal { subscriber in startedThird = true var cancelled = false - dispatch_async(q, { + q.async { if !cancelled { usleep(100 * 1000) subscriber.putNext(3) subscriber.putCompletion() } - }) + } return ActionDisposable { cancelled = true disposedThree = true @@ -605,18 +605,18 @@ class SwiftSignalKitFunctionsTests: XCTestCase { } func testRestart() { - let q = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT) + let q = DispatchQueue(label: "", attributes: [.concurrent]) let signal = Signal { subscriber in - dispatch_async(q, { + q.async { subscriber.putNext(1) subscriber.putCompletion() - }) + } return EmptyDisposable } var result = 0 - (signal |> restart |> take(3)).start(next: { next in + let _ = (signal |> restart |> take(3)).start(next: { next in result += next }) @@ -626,7 +626,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { } func testPipe() { - let pipe = Pipe() + let pipe = ValuePipe() var result1 = 0 let disposable1 = pipe.signal().start(next: { next in @@ -674,7 +674,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { return complete(Void.self, NoError.self) |> deliverOn(q) } - queued.start() + let _ = queued.start() } func testReduceSignal() { @@ -698,7 +698,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { }) var values: [Int] = [] - reduced.start(next: { next in + let _ = reduced.start(next: { next in values.append(next) }) @@ -718,4 +718,16 @@ class SwiftSignalKitFunctionsTests: XCTestCase { XCTAssert(values[i] == value, "at \(i): \(values[i]) != \(value)") } } + + func testMainQueueReentrant() { + let q = Queue.mainQueue() + + var a = 1 + q.async { + usleep(150 * 1000) + a = 2 + } + + XCTAssert(a == 2) + } }