From 2066b31b057805c6ae229c3c59a0358d48724fba Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 31 Jan 2015 00:18:30 +0300 Subject: [PATCH 001/122] Initial Commit --- SSignalKit.xcodeproj/project.pbxproj | 409 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + SSignalKit/Info.plist | 26 ++ SSignalKit/SSignalKit.h | 19 + SSignalKitTests/Info.plist | 24 + SSignalKitTests/SSignalKitTests.m | 40 ++ 6 files changed, 525 insertions(+) create mode 100644 SSignalKit.xcodeproj/project.pbxproj create mode 100644 SSignalKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 SSignalKit/Info.plist create mode 100644 SSignalKit/SSignalKit.h create mode 100644 SSignalKitTests/Info.plist create mode 100644 SSignalKitTests/SSignalKitTests.m diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..71def90c48 --- /dev/null +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -0,0 +1,409 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DDD1A7C2CA500267924 /* SSignalKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445DE41A7C2CA500267924 /* SSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0445DD81A7C2CA500267924 /* SSignalKit.framework */; }; + D0445DEB1A7C2CA500267924 /* SSignalKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + D0445DE51A7C2CA500267924 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D0445DCF1A7C2CA500267924 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0445DD71A7C2CA500267924; + remoteInfo = SSignalKit; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; + D0445DDD1A7C2CA500267924 /* SSignalKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSignalKit.h; 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 = ""; }; + D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SSignalKitTests.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D0445DD41A7C2CA500267924 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0445DE01A7C2CA500267924 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D0445DE41A7C2CA500267924 /* SSignalKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D0445DCE1A7C2CA500267924 = { + isa = PBXGroup; + children = ( + D0445DDA1A7C2CA500267924 /* SSignalKit */, + D0445DE71A7C2CA500267924 /* SSignalKitTests */, + D0445DD91A7C2CA500267924 /* Products */, + ); + sourceTree = ""; + }; + D0445DD91A7C2CA500267924 /* Products */ = { + isa = PBXGroup; + children = ( + D0445DD81A7C2CA500267924 /* SSignalKit.framework */, + D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + D0445DDA1A7C2CA500267924 /* SSignalKit */ = { + isa = PBXGroup; + children = ( + D0445DDD1A7C2CA500267924 /* SSignalKit.h */, + D0445DDB1A7C2CA500267924 /* Supporting Files */, + ); + path = SSignalKit; + sourceTree = ""; + }; + D0445DDB1A7C2CA500267924 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + D0445DDC1A7C2CA500267924 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + D0445DE71A7C2CA500267924 /* SSignalKitTests */ = { + isa = PBXGroup; + children = ( + D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */, + D0445DE81A7C2CA500267924 /* Supporting Files */, + ); + path = SSignalKitTests; + sourceTree = ""; + }; + D0445DE81A7C2CA500267924 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + D0445DE91A7C2CA500267924 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + D0445DD51A7C2CA500267924 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + D0445DD71A7C2CA500267924 /* SSignalKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0445DEE1A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKit" */; + buildPhases = ( + D0445DD31A7C2CA500267924 /* Sources */, + D0445DD41A7C2CA500267924 /* Frameworks */, + D0445DD51A7C2CA500267924 /* Headers */, + D0445DD61A7C2CA500267924 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SSignalKit; + productName = SSignalKit; + productReference = D0445DD81A7C2CA500267924 /* SSignalKit.framework */; + productType = "com.apple.product-type.framework"; + }; + D0445DE21A7C2CA500267924 /* SSignalKitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0445DF11A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKitTests" */; + buildPhases = ( + D0445DDF1A7C2CA500267924 /* Sources */, + D0445DE01A7C2CA500267924 /* Frameworks */, + D0445DE11A7C2CA500267924 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D0445DE61A7C2CA500267924 /* PBXTargetDependency */, + ); + name = SSignalKitTests; + productName = SSignalKitTests; + productReference = D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D0445DCF1A7C2CA500267924 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = Telegram; + TargetAttributes = { + D0445DD71A7C2CA500267924 = { + CreatedOnToolsVersion = 6.1.1; + }; + D0445DE21A7C2CA500267924 = { + CreatedOnToolsVersion = 6.1.1; + }; + }; + }; + buildConfigurationList = D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = D0445DCE1A7C2CA500267924; + productRefGroup = D0445DD91A7C2CA500267924 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D0445DD71A7C2CA500267924 /* SSignalKit */, + D0445DE21A7C2CA500267924 /* SSignalKitTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D0445DD61A7C2CA500267924 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0445DE11A7C2CA500267924 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D0445DD31A7C2CA500267924 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0445DDF1A7C2CA500267924 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0445DEB1A7C2CA500267924 /* SSignalKitTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + D0445DE61A7C2CA500267924 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D0445DD71A7C2CA500267924 /* SSignalKit */; + targetProxy = D0445DE51A7C2CA500267924 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + D0445DEC1A7C2CA500267924 /* Debug */ = { + 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 = NO; + CURRENT_PROJECT_VERSION = 1; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + 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 = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + D0445DED1A7C2CA500267924 /* Release */ = { + 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_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + 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 = Release; + }; + D0445DEF1A7C2CA500267924 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = SSignalKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + D0445DF01A7C2CA500267924 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = SSignalKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + D0445DF21A7C2CA500267924 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = SSignalKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + D0445DF31A7C2CA500267924 /* Release */ = { + 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"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0445DEC1A7C2CA500267924 /* Debug */, + D0445DED1A7C2CA500267924 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D0445DEE1A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0445DEF1A7C2CA500267924 /* Debug */, + D0445DF01A7C2CA500267924 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + D0445DF11A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0445DF21A7C2CA500267924 /* Debug */, + D0445DF31A7C2CA500267924 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = D0445DCF1A7C2CA500267924 /* Project object */; +} diff --git a/SSignalKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SSignalKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..2141ad337b --- /dev/null +++ b/SSignalKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/SSignalKit/Info.plist b/SSignalKit/Info.plist new file mode 100644 index 0000000000..f6228f96e7 --- /dev/null +++ b/SSignalKit/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.telegram.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h new file mode 100644 index 0000000000..dde27ab5b1 --- /dev/null +++ b/SSignalKit/SSignalKit.h @@ -0,0 +1,19 @@ +// +// SSignalKit.h +// SSignalKit +// +// Created by Peter on 31/01/15. +// Copyright (c) 2015 Telegram. All rights reserved. +// + +#import + +//! Project version number for SSignalKit. +FOUNDATION_EXPORT double SSignalKitVersionNumber; + +//! Project version string for SSignalKit. +FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/SSignalKitTests/Info.plist b/SSignalKitTests/Info.plist new file mode 100644 index 0000000000..29dacae6b5 --- /dev/null +++ b/SSignalKitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.telegram.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/SSignalKitTests/SSignalKitTests.m b/SSignalKitTests/SSignalKitTests.m new file mode 100644 index 0000000000..d10930a863 --- /dev/null +++ b/SSignalKitTests/SSignalKitTests.m @@ -0,0 +1,40 @@ +// +// SSignalKitTests.m +// SSignalKitTests +// +// Created by Peter on 31/01/15. +// Copyright (c) 2015 Telegram. All rights reserved. +// + +#import +#import + +@interface SSignalKitTests : XCTestCase + +@end + +@implementation SSignalKitTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // This is an example of a functional test case. + XCTAssert(YES, @"Pass"); +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end From 34a7d245da54d7f389d8dfab4249d3d6155e8126 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 31 Jan 2015 00:20:06 +0300 Subject: [PATCH 002/122] Added .gitignore --- .gitignore | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..f86224615d --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate + From cd0d3c8aa4317fcf185a33fb05e8430379fec8c2 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 31 Jan 2015 02:39:38 +0300 Subject: [PATCH 003/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 319 +++++++++++++++++++++++++ SSignalKit/SAtomic.h | 11 + SSignalKit/SAtomic.m | 64 +++++ SSignalKit/SBag.h | 11 + SSignalKit/SBag.m | 74 ++++++ SSignalKit/SBlockDisposable.h | 7 + SSignalKit/SBlockDisposable.m | 42 ++++ SSignalKit/SCompositeDisposable.h | 7 + SSignalKit/SCompositeDisposable.m | 60 +++++ SSignalKit/SDisposable.h | 7 + SSignalKit/SEvent.h | 18 ++ SSignalKit/SEvent.m | 37 +++ SSignalKit/SMetaDisposable.h | 7 + SSignalKit/SMetaDisposable.m | 51 ++++ SSignalKit/SMulticastSignalManager.h | 7 + SSignalKit/SMulticastSignalManager.m | 66 +++++ SSignalKit/SQueue.h | 9 + SSignalKit/SQueue.m | 32 +++ SSignalKit/SSignal+Accumulate.h | 7 + SSignalKit/SSignal+Accumulate.m | 28 +++ SSignalKit/SSignal+Catch.h | 7 + SSignalKit/SSignal+Catch.m | 38 +++ SSignalKit/SSignal+Combine.h | 8 + SSignalKit/SSignal+Combine.m | 129 ++++++++++ SSignalKit/SSignal+Concat.h | 5 + SSignalKit/SSignal+Concat.m | 15 ++ SSignalKit/SSignal+Dispatch.h | 13 + SSignalKit/SSignal+Dispatch.m | 127 ++++++++++ SSignalKit/SSignal+Mapping.h | 8 + SSignalKit/SSignal+Mapping.m | 42 ++++ SSignalKit/SSignal+Meta.h | 9 + SSignalKit/SSignal+Meta.m | 75 ++++++ SSignalKit/SSignal+Multicast.h | 7 + SSignalKit/SSignal+Multicast.m | 131 ++++++++++ SSignalKit/SSignal+SideEffects.h | 10 + SSignalKit/SSignal+SideEffects.m | 83 +++++++ SSignalKit/SSignal+Single.h | 10 + SSignalKit/SSignal+Single.m | 63 +++++ SSignalKit/SSignal+Timing.h | 9 + SSignalKit/SSignal+Timing.m | 36 +++ SSignalKit/SSignal.h | 19 ++ SSignalKit/SSignal.m | 28 +++ SSignalKit/SSignalKit.h | 23 +- SSignalKit/SSubscriber.h | 30 +++ SSignalKit/SSubscriber.m | 163 +++++++++++++ SSignalKit/SThreadPool.h | 18 ++ SSignalKit/SThreadPool.m | 227 ++++++++++++++++++ SSignalKit/STimer.h | 12 + SSignalKit/STimer.m | 79 ++++++ SSignalKitTests/SBlockDisposableTest.m | 55 +++++ 50 files changed, 2342 insertions(+), 1 deletion(-) create mode 100644 SSignalKit/SAtomic.h create mode 100644 SSignalKit/SAtomic.m create mode 100644 SSignalKit/SBag.h create mode 100644 SSignalKit/SBag.m create mode 100644 SSignalKit/SBlockDisposable.h create mode 100644 SSignalKit/SBlockDisposable.m create mode 100644 SSignalKit/SCompositeDisposable.h create mode 100644 SSignalKit/SCompositeDisposable.m create mode 100644 SSignalKit/SDisposable.h create mode 100644 SSignalKit/SEvent.h create mode 100644 SSignalKit/SEvent.m create mode 100644 SSignalKit/SMetaDisposable.h create mode 100644 SSignalKit/SMetaDisposable.m create mode 100644 SSignalKit/SMulticastSignalManager.h create mode 100644 SSignalKit/SMulticastSignalManager.m create mode 100644 SSignalKit/SQueue.h create mode 100644 SSignalKit/SQueue.m create mode 100644 SSignalKit/SSignal+Accumulate.h create mode 100644 SSignalKit/SSignal+Accumulate.m create mode 100644 SSignalKit/SSignal+Catch.h create mode 100644 SSignalKit/SSignal+Catch.m create mode 100644 SSignalKit/SSignal+Combine.h create mode 100644 SSignalKit/SSignal+Combine.m create mode 100644 SSignalKit/SSignal+Concat.h create mode 100644 SSignalKit/SSignal+Concat.m create mode 100644 SSignalKit/SSignal+Dispatch.h create mode 100644 SSignalKit/SSignal+Dispatch.m create mode 100644 SSignalKit/SSignal+Mapping.h create mode 100644 SSignalKit/SSignal+Mapping.m create mode 100644 SSignalKit/SSignal+Meta.h create mode 100644 SSignalKit/SSignal+Meta.m create mode 100644 SSignalKit/SSignal+Multicast.h create mode 100644 SSignalKit/SSignal+Multicast.m create mode 100644 SSignalKit/SSignal+SideEffects.h create mode 100644 SSignalKit/SSignal+SideEffects.m create mode 100644 SSignalKit/SSignal+Single.h create mode 100644 SSignalKit/SSignal+Single.m create mode 100644 SSignalKit/SSignal+Timing.h create mode 100644 SSignalKit/SSignal+Timing.m create mode 100644 SSignalKit/SSignal.h create mode 100644 SSignalKit/SSignal.m create mode 100644 SSignalKit/SSubscriber.h create mode 100644 SSignalKit/SSubscriber.m create mode 100644 SSignalKit/SThreadPool.h create mode 100644 SSignalKit/SThreadPool.m create mode 100644 SSignalKit/STimer.h create mode 100644 SSignalKit/STimer.m create mode 100644 SSignalKitTests/SBlockDisposableTest.m diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 71def90c48..0a5c374660 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -10,6 +10,77 @@ D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DDD1A7C2CA500267924 /* SSignalKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445DE41A7C2CA500267924 /* SSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0445DD81A7C2CA500267924 /* SSignalKit.framework */; }; D0445DEB1A7C2CA500267924 /* SSignalKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */; }; + D0445E221A7C2D7300267924 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF61A7C2D7300267924 /* SBlockDisposable.m */; }; + D0445E231A7C2D7300267924 /* SAtomic.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DF71A7C2D7300267924 /* SAtomic.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E241A7C2D7300267924 /* SAtomic.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF81A7C2D7300267924 /* SAtomic.m */; }; + D0445E251A7C2D7300267924 /* SBag.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DF91A7C2D7300267924 /* SBag.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E261A7C2D7300267924 /* SBag.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFA1A7C2D7300267924 /* SBag.m */; }; + D0445E271A7C2D7300267924 /* SBlockDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E281A7C2D7300267924 /* SCompositeDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFC1A7C2D7300267924 /* SCompositeDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E291A7C2D7300267924 /* SCompositeDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFD1A7C2D7300267924 /* SCompositeDisposable.m */; }; + D0445E2A1A7C2D7300267924 /* SDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFE1A7C2D7300267924 /* SDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E2B1A7C2D7300267924 /* SEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFF1A7C2D7300267924 /* SEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E2C1A7C2D7300267924 /* SEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E001A7C2D7300267924 /* SEvent.m */; }; + D0445E2D1A7C2D7300267924 /* SMetaDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E011A7C2D7300267924 /* SMetaDisposable.m */; }; + D0445E2E1A7C2D7300267924 /* SMulticastSignalManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E021A7C2D7300267924 /* SMulticastSignalManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E2F1A7C2D7300267924 /* SMulticastSignalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */; }; + D0445E301A7C2D7300267924 /* SSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E041A7C2D7300267924 /* SSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E311A7C2D7300267924 /* SSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E051A7C2D7300267924 /* SSignal.m */; }; + D0445E321A7C2D7300267924 /* SSignal+Accumulate.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E061A7C2D7300267924 /* SSignal+Accumulate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E331A7C2D7300267924 /* SSignal+Accumulate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */; }; + D0445E341A7C2D7300267924 /* SSignal+Catch.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E081A7C2D7300267924 /* SSignal+Catch.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E351A7C2D7300267924 /* SSignal+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E091A7C2D7300267924 /* SSignal+Catch.m */; }; + D0445E361A7C2D7300267924 /* SSignal+Combine.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E371A7C2D7300267924 /* SSignal+Combine.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */; }; + D0445E381A7C2D7300267924 /* SSignal+Concat.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E0C1A7C2D7300267924 /* SSignal+Concat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E391A7C2D7300267924 /* SSignal+Concat.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0D1A7C2D7300267924 /* SSignal+Concat.m */; }; + D0445E3A1A7C2D7300267924 /* SSignal+Dispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E3B1A7C2D7300267924 /* SSignal+Dispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */; }; + D0445E3C1A7C2D7300267924 /* SSignal+Mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E101A7C2D7300267924 /* SSignal+Mapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E3D1A7C2D7300267924 /* SSignal+Mapping.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E111A7C2D7300267924 /* SSignal+Mapping.m */; }; + D0445E3E1A7C2D7300267924 /* SSignal+Meta.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E121A7C2D7300267924 /* SSignal+Meta.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E3F1A7C2D7300267924 /* SSignal+Meta.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E131A7C2D7300267924 /* SSignal+Meta.m */; }; + D0445E401A7C2D7300267924 /* SSignal+Multicast.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E141A7C2D7300267924 /* SSignal+Multicast.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E411A7C2D7300267924 /* SSignal+Multicast.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E151A7C2D7300267924 /* SSignal+Multicast.m */; }; + D0445E421A7C2D7300267924 /* SSignal+SideEffects.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E161A7C2D7300267924 /* SSignal+SideEffects.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E431A7C2D7300267924 /* SSignal+SideEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E171A7C2D7300267924 /* SSignal+SideEffects.m */; }; + D0445E441A7C2D7300267924 /* SSignal+Single.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E181A7C2D7300267924 /* SSignal+Single.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E451A7C2D7300267924 /* SSignal+Single.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E191A7C2D7300267924 /* SSignal+Single.m */; }; + D0445E461A7C2D7300267924 /* SSignal+Timing.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E1A1A7C2D7300267924 /* SSignal+Timing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E471A7C2D7300267924 /* SSignal+Timing.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */; }; + D0445E481A7C2D7300267924 /* SSubscriber.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E1C1A7C2D7300267924 /* SSubscriber.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E491A7C2D7300267924 /* SSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1D1A7C2D7300267924 /* SSubscriber.m */; }; + D0445E4A1A7C2D7300267924 /* SThreadPool.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E1E1A7C2D7300267924 /* SThreadPool.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E4B1A7C2D7300267924 /* SThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1F1A7C2D7300267924 /* SThreadPool.m */; }; + D0445E4E1A7C2D8A00267924 /* SQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E4C1A7C2D8A00267924 /* SQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E4F1A7C2D8A00267924 /* SQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E4D1A7C2D8A00267924 /* SQueue.m */; }; + D0445E511A7C2DBF00267924 /* SMetaDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E501A7C2DBF00267924 /* SMetaDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E541A7C2E9D00267924 /* STimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E521A7C2E9D00267924 /* STimer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0445E551A7C2E9D00267924 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E531A7C2E9D00267924 /* STimer.m */; }; + D0445E571A7C3FB400267924 /* SBlockDisposableTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E561A7C3FB400267924 /* SBlockDisposableTest.m */; }; + D0445E731A7C447D00267924 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF61A7C2D7300267924 /* SBlockDisposable.m */; }; + D0445E741A7C447D00267924 /* SAtomic.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF81A7C2D7300267924 /* SAtomic.m */; }; + D0445E751A7C447D00267924 /* SBag.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFA1A7C2D7300267924 /* SBag.m */; }; + D0445E761A7C447D00267924 /* SCompositeDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFD1A7C2D7300267924 /* SCompositeDisposable.m */; }; + D0445E771A7C447D00267924 /* SEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E001A7C2D7300267924 /* SEvent.m */; }; + D0445E781A7C447D00267924 /* SMetaDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E011A7C2D7300267924 /* SMetaDisposable.m */; }; + D0445E791A7C447D00267924 /* SMulticastSignalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */; }; + D0445E7A1A7C447D00267924 /* SSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E051A7C2D7300267924 /* SSignal.m */; }; + D0445E7B1A7C447D00267924 /* SSignal+Accumulate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */; }; + D0445E7C1A7C447D00267924 /* SSignal+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E091A7C2D7300267924 /* SSignal+Catch.m */; }; + D0445E7D1A7C447D00267924 /* SSignal+Combine.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */; }; + D0445E7E1A7C447D00267924 /* SSignal+Concat.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0D1A7C2D7300267924 /* SSignal+Concat.m */; }; + D0445E7F1A7C447D00267924 /* SSignal+Dispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */; }; + D0445E801A7C447D00267924 /* SSignal+Mapping.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E111A7C2D7300267924 /* SSignal+Mapping.m */; }; + D0445E811A7C447D00267924 /* SSignal+Meta.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E131A7C2D7300267924 /* SSignal+Meta.m */; }; + D0445E821A7C447D00267924 /* SSignal+Multicast.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E151A7C2D7300267924 /* SSignal+Multicast.m */; }; + D0445E831A7C447D00267924 /* SSignal+SideEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E171A7C2D7300267924 /* SSignal+SideEffects.m */; }; + D0445E841A7C447D00267924 /* SSignal+Single.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E191A7C2D7300267924 /* SSignal+Single.m */; }; + D0445E851A7C447D00267924 /* SSignal+Timing.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */; }; + D0445E861A7C447D00267924 /* SSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1D1A7C2D7300267924 /* SSubscriber.m */; }; + D0445E871A7C447D00267924 /* SThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1F1A7C2D7300267924 /* SThreadPool.m */; }; + D0445E881A7C447D00267924 /* SQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E4D1A7C2D8A00267924 /* SQueue.m */; }; + D0445E891A7C447D00267924 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E531A7C2E9D00267924 /* STimer.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -22,6 +93,18 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + D0445E5A1A7C446000267924 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 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 = ""; }; @@ -29,6 +112,55 @@ 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 = ""; }; D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SSignalKitTests.m; sourceTree = ""; }; + D0445DF61A7C2D7300267924 /* SBlockDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBlockDisposable.m; sourceTree = ""; }; + D0445DF71A7C2D7300267924 /* SAtomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAtomic.h; sourceTree = ""; }; + D0445DF81A7C2D7300267924 /* SAtomic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAtomic.m; sourceTree = ""; }; + D0445DF91A7C2D7300267924 /* SBag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBag.h; sourceTree = ""; }; + D0445DFA1A7C2D7300267924 /* SBag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBag.m; sourceTree = ""; }; + D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBlockDisposable.h; sourceTree = ""; }; + D0445DFC1A7C2D7300267924 /* SCompositeDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCompositeDisposable.h; sourceTree = ""; }; + D0445DFD1A7C2D7300267924 /* SCompositeDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCompositeDisposable.m; sourceTree = ""; }; + D0445DFE1A7C2D7300267924 /* SDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposable.h; sourceTree = ""; }; + D0445DFF1A7C2D7300267924 /* SEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SEvent.h; sourceTree = ""; }; + D0445E001A7C2D7300267924 /* SEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SEvent.m; sourceTree = ""; }; + D0445E011A7C2D7300267924 /* SMetaDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMetaDisposable.m; sourceTree = ""; }; + D0445E021A7C2D7300267924 /* SMulticastSignalManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMulticastSignalManager.h; sourceTree = ""; }; + D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMulticastSignalManager.m; sourceTree = ""; }; + D0445E041A7C2D7300267924 /* SSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSignal.h; sourceTree = ""; }; + D0445E051A7C2D7300267924 /* SSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignal.m; sourceTree = ""; }; + D0445E061A7C2D7300267924 /* SSignal+Accumulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Accumulate.h"; sourceTree = ""; }; + D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Accumulate.m"; sourceTree = ""; }; + D0445E081A7C2D7300267924 /* SSignal+Catch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Catch.h"; sourceTree = ""; }; + D0445E091A7C2D7300267924 /* SSignal+Catch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Catch.m"; sourceTree = ""; }; + D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Combine.h"; sourceTree = ""; }; + D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Combine.m"; sourceTree = ""; }; + D0445E0C1A7C2D7300267924 /* SSignal+Concat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Concat.h"; sourceTree = ""; }; + D0445E0D1A7C2D7300267924 /* SSignal+Concat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Concat.m"; sourceTree = ""; }; + D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Dispatch.h"; sourceTree = ""; }; + D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Dispatch.m"; sourceTree = ""; }; + D0445E101A7C2D7300267924 /* SSignal+Mapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Mapping.h"; sourceTree = ""; }; + D0445E111A7C2D7300267924 /* SSignal+Mapping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Mapping.m"; sourceTree = ""; }; + D0445E121A7C2D7300267924 /* SSignal+Meta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Meta.h"; sourceTree = ""; }; + D0445E131A7C2D7300267924 /* SSignal+Meta.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Meta.m"; sourceTree = ""; }; + D0445E141A7C2D7300267924 /* SSignal+Multicast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Multicast.h"; sourceTree = ""; }; + D0445E151A7C2D7300267924 /* SSignal+Multicast.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Multicast.m"; sourceTree = ""; }; + D0445E161A7C2D7300267924 /* SSignal+SideEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+SideEffects.h"; sourceTree = ""; }; + D0445E171A7C2D7300267924 /* SSignal+SideEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+SideEffects.m"; sourceTree = ""; }; + D0445E181A7C2D7300267924 /* SSignal+Single.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Single.h"; sourceTree = ""; }; + D0445E191A7C2D7300267924 /* SSignal+Single.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Single.m"; sourceTree = ""; }; + D0445E1A1A7C2D7300267924 /* SSignal+Timing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Timing.h"; sourceTree = ""; }; + D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Timing.m"; sourceTree = ""; }; + D0445E1C1A7C2D7300267924 /* SSubscriber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSubscriber.h; sourceTree = ""; }; + D0445E1D1A7C2D7300267924 /* SSubscriber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSubscriber.m; sourceTree = ""; }; + D0445E1E1A7C2D7300267924 /* SThreadPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPool.h; sourceTree = ""; }; + D0445E1F1A7C2D7300267924 /* SThreadPool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPool.m; sourceTree = ""; }; + D0445E4C1A7C2D8A00267924 /* SQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQueue.h; sourceTree = ""; }; + D0445E4D1A7C2D8A00267924 /* SQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQueue.m; sourceTree = ""; }; + D0445E501A7C2DBF00267924 /* SMetaDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMetaDisposable.h; sourceTree = ""; }; + D0445E521A7C2E9D00267924 /* STimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STimer.h; sourceTree = ""; }; + D0445E531A7C2E9D00267924 /* STimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STimer.m; sourceTree = ""; }; + D0445E561A7C3FB400267924 /* SBlockDisposableTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBlockDisposableTest.m; sourceTree = ""; }; + D0445E5C1A7C446000267924 /* libSSignalKitStatic.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSSignalKitStatic.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -47,6 +179,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D0445E591A7C446000267924 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -64,6 +203,7 @@ children = ( D0445DD81A7C2CA500267924 /* SSignalKit.framework */, D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */, + D0445E5C1A7C446000267924 /* libSSignalKitStatic.a */, ); name = Products; sourceTree = ""; @@ -71,6 +211,53 @@ D0445DDA1A7C2CA500267924 /* SSignalKit */ = { isa = PBXGroup; children = ( + D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */, + D0445DF61A7C2D7300267924 /* SBlockDisposable.m */, + D0445DF71A7C2D7300267924 /* SAtomic.h */, + D0445DF81A7C2D7300267924 /* SAtomic.m */, + D0445DF91A7C2D7300267924 /* SBag.h */, + D0445DFA1A7C2D7300267924 /* SBag.m */, + D0445DFC1A7C2D7300267924 /* SCompositeDisposable.h */, + D0445DFD1A7C2D7300267924 /* SCompositeDisposable.m */, + D0445DFE1A7C2D7300267924 /* SDisposable.h */, + D0445DFF1A7C2D7300267924 /* SEvent.h */, + D0445E001A7C2D7300267924 /* SEvent.m */, + D0445E501A7C2DBF00267924 /* SMetaDisposable.h */, + D0445E011A7C2D7300267924 /* SMetaDisposable.m */, + D0445E021A7C2D7300267924 /* SMulticastSignalManager.h */, + D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */, + D0445E041A7C2D7300267924 /* SSignal.h */, + D0445E051A7C2D7300267924 /* SSignal.m */, + D0445E061A7C2D7300267924 /* SSignal+Accumulate.h */, + D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */, + D0445E081A7C2D7300267924 /* SSignal+Catch.h */, + D0445E091A7C2D7300267924 /* SSignal+Catch.m */, + D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */, + D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */, + D0445E0C1A7C2D7300267924 /* SSignal+Concat.h */, + D0445E0D1A7C2D7300267924 /* SSignal+Concat.m */, + D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */, + D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */, + D0445E101A7C2D7300267924 /* SSignal+Mapping.h */, + D0445E111A7C2D7300267924 /* SSignal+Mapping.m */, + D0445E121A7C2D7300267924 /* SSignal+Meta.h */, + D0445E131A7C2D7300267924 /* SSignal+Meta.m */, + D0445E141A7C2D7300267924 /* SSignal+Multicast.h */, + D0445E151A7C2D7300267924 /* SSignal+Multicast.m */, + D0445E161A7C2D7300267924 /* SSignal+SideEffects.h */, + D0445E171A7C2D7300267924 /* SSignal+SideEffects.m */, + D0445E181A7C2D7300267924 /* SSignal+Single.h */, + D0445E191A7C2D7300267924 /* SSignal+Single.m */, + D0445E1A1A7C2D7300267924 /* SSignal+Timing.h */, + D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */, + D0445E1C1A7C2D7300267924 /* SSubscriber.h */, + D0445E1D1A7C2D7300267924 /* SSubscriber.m */, + D0445E1E1A7C2D7300267924 /* SThreadPool.h */, + D0445E1F1A7C2D7300267924 /* SThreadPool.m */, + D0445E4C1A7C2D8A00267924 /* SQueue.h */, + D0445E4D1A7C2D8A00267924 /* SQueue.m */, + D0445E521A7C2E9D00267924 /* STimer.h */, + D0445E531A7C2E9D00267924 /* STimer.m */, D0445DDD1A7C2CA500267924 /* SSignalKit.h */, D0445DDB1A7C2CA500267924 /* Supporting Files */, ); @@ -90,6 +277,7 @@ children = ( D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */, D0445DE81A7C2CA500267924 /* Supporting Files */, + D0445E561A7C3FB400267924 /* SBlockDisposableTest.m */, ); path = SSignalKitTests; sourceTree = ""; @@ -109,7 +297,31 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + D0445E481A7C2D7300267924 /* SSubscriber.h in Headers */, + D0445E2E1A7C2D7300267924 /* SMulticastSignalManager.h in Headers */, + D0445E271A7C2D7300267924 /* SBlockDisposable.h in Headers */, + D0445E4A1A7C2D7300267924 /* SThreadPool.h in Headers */, + D0445E541A7C2E9D00267924 /* STimer.h in Headers */, + D0445E301A7C2D7300267924 /* SSignal.h in Headers */, + D0445E321A7C2D7300267924 /* SSignal+Accumulate.h in Headers */, + D0445E361A7C2D7300267924 /* SSignal+Combine.h in Headers */, + D0445E2A1A7C2D7300267924 /* SDisposable.h in Headers */, + D0445E421A7C2D7300267924 /* SSignal+SideEffects.h in Headers */, + D0445E3E1A7C2D7300267924 /* SSignal+Meta.h in Headers */, + D0445E2B1A7C2D7300267924 /* SEvent.h in Headers */, + D0445E281A7C2D7300267924 /* SCompositeDisposable.h in Headers */, + D0445E341A7C2D7300267924 /* SSignal+Catch.h in Headers */, + D0445E4E1A7C2D8A00267924 /* SQueue.h in Headers */, + D0445E441A7C2D7300267924 /* SSignal+Single.h in Headers */, + D0445E251A7C2D7300267924 /* SBag.h in Headers */, + D0445E3A1A7C2D7300267924 /* SSignal+Dispatch.h in Headers */, + D0445E401A7C2D7300267924 /* SSignal+Multicast.h in Headers */, + D0445E511A7C2DBF00267924 /* SMetaDisposable.h in Headers */, + D0445E231A7C2D7300267924 /* SAtomic.h in Headers */, + D0445E461A7C2D7300267924 /* SSignal+Timing.h in Headers */, + D0445E381A7C2D7300267924 /* SSignal+Concat.h in Headers */, D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */, + D0445E3C1A7C2D7300267924 /* SSignal+Mapping.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -152,6 +364,23 @@ productReference = D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + D0445E5B1A7C446000267924 /* SSignalKitStatic */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0445E6D1A7C446000267924 /* Build configuration list for PBXNativeTarget "SSignalKitStatic" */; + buildPhases = ( + D0445E581A7C446000267924 /* Sources */, + D0445E591A7C446000267924 /* Frameworks */, + D0445E5A1A7C446000267924 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SSignalKitStatic; + productName = SSignalKitStatic; + productReference = D0445E5C1A7C446000267924 /* libSSignalKitStatic.a */; + productType = "com.apple.product-type.library.static"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -167,6 +396,9 @@ D0445DE21A7C2CA500267924 = { CreatedOnToolsVersion = 6.1.1; }; + D0445E5B1A7C446000267924 = { + CreatedOnToolsVersion = 6.1.1; + }; }; }; buildConfigurationList = D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */; @@ -182,6 +414,7 @@ projectRoot = ""; targets = ( D0445DD71A7C2CA500267924 /* SSignalKit */, + D0445E5B1A7C446000267924 /* SSignalKitStatic */, D0445DE21A7C2CA500267924 /* SSignalKitTests */, ); }; @@ -209,6 +442,29 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D0445E451A7C2D7300267924 /* SSignal+Single.m in Sources */, + D0445E2D1A7C2D7300267924 /* SMetaDisposable.m in Sources */, + D0445E3B1A7C2D7300267924 /* SSignal+Dispatch.m in Sources */, + D0445E4F1A7C2D8A00267924 /* SQueue.m in Sources */, + D0445E241A7C2D7300267924 /* SAtomic.m in Sources */, + D0445E4B1A7C2D7300267924 /* SThreadPool.m in Sources */, + D0445E551A7C2E9D00267924 /* STimer.m in Sources */, + D0445E3D1A7C2D7300267924 /* SSignal+Mapping.m in Sources */, + D0445E351A7C2D7300267924 /* SSignal+Catch.m in Sources */, + D0445E411A7C2D7300267924 /* SSignal+Multicast.m in Sources */, + D0445E2C1A7C2D7300267924 /* SEvent.m in Sources */, + D0445E261A7C2D7300267924 /* SBag.m in Sources */, + D0445E331A7C2D7300267924 /* SSignal+Accumulate.m in Sources */, + D0445E471A7C2D7300267924 /* SSignal+Timing.m in Sources */, + D0445E291A7C2D7300267924 /* SCompositeDisposable.m in Sources */, + D0445E311A7C2D7300267924 /* SSignal.m in Sources */, + D0445E491A7C2D7300267924 /* SSubscriber.m in Sources */, + D0445E391A7C2D7300267924 /* SSignal+Concat.m in Sources */, + D0445E431A7C2D7300267924 /* SSignal+SideEffects.m in Sources */, + D0445E3F1A7C2D7300267924 /* SSignal+Meta.m in Sources */, + D0445E371A7C2D7300267924 /* SSignal+Combine.m in Sources */, + D0445E2F1A7C2D7300267924 /* SMulticastSignalManager.m in Sources */, + D0445E221A7C2D7300267924 /* SBlockDisposable.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -217,6 +473,37 @@ buildActionMask = 2147483647; files = ( D0445DEB1A7C2CA500267924 /* SSignalKitTests.m in Sources */, + D0445E571A7C3FB400267924 /* SBlockDisposableTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0445E581A7C446000267924 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0445E841A7C447D00267924 /* SSignal+Single.m in Sources */, + D0445E781A7C447D00267924 /* SMetaDisposable.m in Sources */, + D0445E7F1A7C447D00267924 /* SSignal+Dispatch.m in Sources */, + D0445E881A7C447D00267924 /* SQueue.m in Sources */, + D0445E741A7C447D00267924 /* SAtomic.m in Sources */, + D0445E871A7C447D00267924 /* SThreadPool.m in Sources */, + D0445E891A7C447D00267924 /* STimer.m in Sources */, + D0445E801A7C447D00267924 /* SSignal+Mapping.m in Sources */, + D0445E7C1A7C447D00267924 /* SSignal+Catch.m in Sources */, + D0445E821A7C447D00267924 /* SSignal+Multicast.m in Sources */, + D0445E771A7C447D00267924 /* SEvent.m in Sources */, + D0445E751A7C447D00267924 /* SBag.m in Sources */, + D0445E7B1A7C447D00267924 /* SSignal+Accumulate.m in Sources */, + D0445E851A7C447D00267924 /* SSignal+Timing.m in Sources */, + D0445E761A7C447D00267924 /* SCompositeDisposable.m in Sources */, + D0445E7A1A7C447D00267924 /* SSignal.m in Sources */, + D0445E861A7C447D00267924 /* SSubscriber.m in Sources */, + D0445E7E1A7C447D00267924 /* SSignal+Concat.m in Sources */, + D0445E831A7C447D00267924 /* SSignal+SideEffects.m in Sources */, + D0445E811A7C447D00267924 /* SSignal+Meta.m in Sources */, + D0445E7D1A7C447D00267924 /* SSignal+Combine.m in Sources */, + D0445E791A7C447D00267924 /* SMulticastSignalManager.m in Sources */, + D0445E731A7C447D00267924 /* SBlockDisposable.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -324,6 +611,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; 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"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -339,6 +627,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; 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"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -375,6 +664,28 @@ }; name = Release; }; + D0445E6E1A7C446000267924 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + D0445E6F1A7C446000267924 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -403,6 +714,14 @@ ); defaultConfigurationIsVisible = 0; }; + D0445E6D1A7C446000267924 /* Build configuration list for PBXNativeTarget "SSignalKitStatic" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0445E6E1A7C446000267924 /* Debug */, + D0445E6F1A7C446000267924 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; /* End XCConfigurationList section */ }; rootObject = D0445DCF1A7C2CA500267924 /* Project object */; diff --git a/SSignalKit/SAtomic.h b/SSignalKit/SAtomic.h new file mode 100644 index 0000000000..98aa4da05a --- /dev/null +++ b/SSignalKit/SAtomic.h @@ -0,0 +1,11 @@ +#import + +@interface SAtomic : NSObject + +- (instancetype)initWithValue:(id)value; +- (id)swap:(id)newValue; +- (id)value; +- (id)modify:(id (^)(id))f; +- (id)with:(id (^)(id))f; + +@end diff --git a/SSignalKit/SAtomic.m b/SSignalKit/SAtomic.m new file mode 100644 index 0000000000..b52e580a82 --- /dev/null +++ b/SSignalKit/SAtomic.m @@ -0,0 +1,64 @@ +#import "SAtomic.h" + +#import + +@interface SAtomic () +{ + volatile OSSpinLock _lock; + id _value; +} + +@end + +@implementation SAtomic + +- (instancetype)initWithValue:(id)value +{ + self = [super init]; + if (self != nil) + { + _value = value; + } + return self; +} + +- (id)swap:(id)newValue +{ + id previousValue = nil; + OSSpinLockLock(&_lock); + previousValue = _value; + _value = newValue; + OSSpinLockUnlock(&_lock); + return previousValue; +} + +- (id)value +{ + id previousValue = nil; + OSSpinLockLock(&_lock); + previousValue = _value; + OSSpinLockUnlock(&_lock); + + return previousValue; +} + +- (id)modify:(id (^)(id))f +{ + id newValue = nil; + OSSpinLockLock(&_lock); + newValue = f(_value); + _value = newValue; + OSSpinLockUnlock(&_lock); + return newValue; +} + +- (id)with:(id (^)(id))f +{ + id result = nil; + OSSpinLockLock(&_lock); + result = f(_value); + OSSpinLockUnlock(&_lock); + return result; +} + +@end diff --git a/SSignalKit/SBag.h b/SSignalKit/SBag.h new file mode 100644 index 0000000000..7b79ead30f --- /dev/null +++ b/SSignalKit/SBag.h @@ -0,0 +1,11 @@ +#import + +@interface SBag : NSObject + +- (NSInteger)addItem:(id)item; +- (void)enumerateItems:(void (^)(id))block; +- (void)removeItem:(NSInteger)key; +- (bool)isEmpty; +- (NSArray *)copyItems; + +@end diff --git a/SSignalKit/SBag.m b/SSignalKit/SBag.m new file mode 100644 index 0000000000..c83f206235 --- /dev/null +++ b/SSignalKit/SBag.m @@ -0,0 +1,74 @@ +#import "SBag.h" + +@interface SBag () +{ + NSInteger _nextKey; + NSMutableArray *_items; + NSMutableArray *_itemKeys; +} + +@end + +@implementation SBag + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + _items = [[NSMutableArray alloc] init]; + _itemKeys = [[NSMutableArray alloc] init]; + } + return self; +} + +- (NSInteger)addItem:(id)item +{ + if (item == nil) + return -1; + + NSInteger key = _nextKey; + [_items addObject:item]; + [_itemKeys addObject:@(key)]; + _nextKey++; + + return key; +} + +- (void)enumerateItems:(void (^)(id))block +{ + if (block) + { + for (id item in _items) + { + block(item); + } + } +} + +- (void)removeItem:(NSInteger)key +{ + NSUInteger index = 0; + for (NSNumber *itemKey in _itemKeys) + { + if ([itemKey integerValue] == key) + { + [_items removeObjectAtIndex:index]; + [_itemKeys removeObjectAtIndex:index]; + break; + } + index++; + } +} + +- (bool)isEmpty +{ + return _items.count == 0; +} + +- (NSArray *)copyItems +{ + return [[NSArray alloc] initWithArray:_items]; +} + +@end diff --git a/SSignalKit/SBlockDisposable.h b/SSignalKit/SBlockDisposable.h new file mode 100644 index 0000000000..0d130881dd --- /dev/null +++ b/SSignalKit/SBlockDisposable.h @@ -0,0 +1,7 @@ +#import "SDisposable.h" + +@interface SBlockDisposable : NSObject + +- (instancetype)initWithBlock:(void (^)())block; + +@end diff --git a/SSignalKit/SBlockDisposable.m b/SSignalKit/SBlockDisposable.m new file mode 100644 index 0000000000..05908db7f6 --- /dev/null +++ b/SSignalKit/SBlockDisposable.m @@ -0,0 +1,42 @@ +#import "SBlockDisposable.h" + +#import +#import +#import + +@interface SBlockDisposable () +{ + void *_block; +} + +@end + +@implementation SBlockDisposable + +- (instancetype)initWithBlock:(void (^)())block +{ + self = [super init]; + if (self != nil) + { + _block = (__bridge_retained void *)[block copy]; + } + return self; +} + +- (void)dispose +{ + void *block = _block; + if (block != NULL) + { + if (OSAtomicCompareAndSwapPtr(block, 0, &_block)) + { + if (block != nil) + { + __strong id strongBlock = (__bridge_transfer id)block; + ((dispatch_block_t)strongBlock)(); + } + } + } +} + +@end diff --git a/SSignalKit/SCompositeDisposable.h b/SSignalKit/SCompositeDisposable.h new file mode 100644 index 0000000000..f0a2b25a9d --- /dev/null +++ b/SSignalKit/SCompositeDisposable.h @@ -0,0 +1,7 @@ +#import "SDisposable.h" + +@interface SCompositeDisposable : NSObject + +- (void)add:(id)disposable; + +@end diff --git a/SSignalKit/SCompositeDisposable.m b/SSignalKit/SCompositeDisposable.m new file mode 100644 index 0000000000..80f5a70737 --- /dev/null +++ b/SSignalKit/SCompositeDisposable.m @@ -0,0 +1,60 @@ +#import "SCompositeDisposable.h" + +#import +#import + +@interface SCompositeDisposable () +{ + //volatile OSSpinLock _lock; + pthread_mutex_t _mutex; + NSMutableArray *_disposables; +} + +@end + +@implementation SCompositeDisposable + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + pthread_mutex_init(&_mutex, NULL); + } + return self; +} + +- (void)add:(id)disposable +{ + if (disposable != nil) + { + //OSSpinLockLock(&_lock); + pthread_mutex_lock(&_mutex); + if (_disposables == nil) + _disposables = [[NSMutableArray alloc] init]; + [_disposables addObject:disposable]; + //OSSpinLockUnlock(&_lock); + pthread_mutex_unlock(&_mutex); + } +} + +- (void)dispose +{ + NSArray *disposables = nil; + //OSSpinLockLock(&_lock); + pthread_mutex_lock(&_mutex); + disposables = _disposables; + _disposables = nil; + //OSSpinLockUnlock(&_lock); + pthread_mutex_unlock(&_mutex); + + if (disposables != nil) + { + for (id disposable in disposables) + { + [disposable dispose]; + } + } +} + +@end diff --git a/SSignalKit/SDisposable.h b/SSignalKit/SDisposable.h new file mode 100644 index 0000000000..49d9762dae --- /dev/null +++ b/SSignalKit/SDisposable.h @@ -0,0 +1,7 @@ +#import + +@protocol SDisposable + +- (void)dispose; + +@end diff --git a/SSignalKit/SEvent.h b/SSignalKit/SEvent.h new file mode 100644 index 0000000000..7ff523b26b --- /dev/null +++ b/SSignalKit/SEvent.h @@ -0,0 +1,18 @@ +#import + +typedef enum { + SEventTypeNext, + SEventTypeError, + SEventTypeCompleted +} SEventType; + +@interface SEvent : NSObject + +@property (nonatomic, readonly) SEventType type; +@property (nonatomic, strong, readonly) id data; + +- (instancetype)initWithNext:(id)next; +- (instancetype)initWithError:(id)error; +- (instancetype)initWithCompleted; + +@end diff --git a/SSignalKit/SEvent.m b/SSignalKit/SEvent.m new file mode 100644 index 0000000000..c3d296633e --- /dev/null +++ b/SSignalKit/SEvent.m @@ -0,0 +1,37 @@ +#import "SEvent.h" + +@implementation SEvent + +- (instancetype)initWithNext:(id)next +{ + self = [super init]; + if (self != nil) + { + _type = SEventTypeNext; + _data = next; + } + return self; +} + +- (instancetype)initWithError:(id)error +{ + self = [super init]; + if (self != nil) + { + _type = SEventTypeError; + _data = error; + } + return self; +} + +- (instancetype)initWithCompleted +{ + self = [super init]; + if (self != nil) + { + _type = SEventTypeCompleted; + } + return self; +} + +@end diff --git a/SSignalKit/SMetaDisposable.h b/SSignalKit/SMetaDisposable.h new file mode 100644 index 0000000000..b0ce2ce5db --- /dev/null +++ b/SSignalKit/SMetaDisposable.h @@ -0,0 +1,7 @@ +#import "SDisposable.h" + +@interface SMetaDisposable : NSObject + +- (void)setDisposable:(id)disposable; + +@end diff --git a/SSignalKit/SMetaDisposable.m b/SSignalKit/SMetaDisposable.m new file mode 100644 index 0000000000..e989effe96 --- /dev/null +++ b/SSignalKit/SMetaDisposable.m @@ -0,0 +1,51 @@ +#import "SMetaDisposable.h" + +#import +#import + +@interface SMetaDisposable () +{ + //volatile OSSpinLock _lock; + pthread_mutex_t _mutex; + id _disposable; +} + +@end + +@implementation SMetaDisposable + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + pthread_mutex_init(&_mutex, NULL); + } + return self; +} + +- (void)setDisposable:(id)disposable +{ + id currentDisposable = nil; + //OSSpinLockLock(&_lock); + pthread_mutex_lock(&_mutex); + currentDisposable = _disposable; + _disposable = disposable; + //OSSpinLockUnlock(&lock); + pthread_mutex_unlock(&_mutex); + + [currentDisposable dispose]; +} + +- (void)dispose +{ + id disposable = nil; + pthread_mutex_lock(&_mutex); + disposable = _disposable; + _disposable = nil; + pthread_mutex_unlock(&_mutex); + + [disposable dispose]; +} + +@end diff --git a/SSignalKit/SMulticastSignalManager.h b/SSignalKit/SMulticastSignalManager.h new file mode 100644 index 0000000000..c5ebf674e4 --- /dev/null +++ b/SSignalKit/SMulticastSignalManager.h @@ -0,0 +1,7 @@ +#import "SSignal.h" + +@interface SMulticastSignalManager : NSObject + +- (SSignal *)multicastedSignalForKey:(NSString *)key producer:(SSignal *(^)())producer; + +@end diff --git a/SSignalKit/SMulticastSignalManager.m b/SSignalKit/SMulticastSignalManager.m new file mode 100644 index 0000000000..63b99ea4d1 --- /dev/null +++ b/SSignalKit/SMulticastSignalManager.m @@ -0,0 +1,66 @@ +#import "SMulticastSignalManager.h" + +#import "SSignal+Multicast.h" +#import "SSignal+SideEffects.h" + +#import + +@interface SMulticastSignalManager () +{ + NSMutableDictionary *_signals; + volatile OSSpinLock _lock; +} + +@end + +@implementation SMulticastSignalManager + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + _signals = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (SSignal *)multicastedSignalForKey:(NSString *)key producer:(SSignal *(^)())producer +{ + if (key == nil) + { + if (producer) + return producer(); + else + return nil; + } + + SSignal *signal = nil; + OSSpinLockLock(&_lock); + signal = _signals[key]; + if (signal == nil) + { + __weak SMulticastSignalManager *weakSelf = self; + if (producer) + signal = producer(); + if (signal != nil) + { + signal = [[signal multicast] onDispose:^ + { + __strong SMulticastSignalManager *strongSelf = weakSelf; + if (strongSelf != nil) + { + OSSpinLockLock(&strongSelf->_lock); + [strongSelf->_signals removeObjectForKey:key]; + OSSpinLockUnlock(&strongSelf->_lock); + } + }]; + _signals[key] = signal; + } + } + OSSpinLockUnlock(&_lock); + + return signal; +} + +@end diff --git a/SSignalKit/SQueue.h b/SSignalKit/SQueue.h new file mode 100644 index 0000000000..3e7ad59974 --- /dev/null +++ b/SSignalKit/SQueue.h @@ -0,0 +1,9 @@ +#import + +@interface SQueue : NSObject + +- (void)dispatch:(dispatch_block_t)block; + +- (dispatch_queue_t)_dispatch_queue; + +@end diff --git a/SSignalKit/SQueue.m b/SSignalKit/SQueue.m new file mode 100644 index 0000000000..0da661a5ec --- /dev/null +++ b/SSignalKit/SQueue.m @@ -0,0 +1,32 @@ +#import "SQueue.h" + +@interface SQueue () +{ + dispatch_queue_t _queue; +} + +@end + +@implementation SQueue + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + _queue = dispatch_queue_create(NULL, NULL); + } + return self; +} + +- (dispatch_queue_t)_dispatch_queue +{ + return _queue; +} + +- (void)dispatch:(dispatch_block_t)block +{ + dispatch_async(_queue, block); +} + +@end diff --git a/SSignalKit/SSignal+Accumulate.h b/SSignalKit/SSignal+Accumulate.h new file mode 100644 index 0000000000..55e534dbd5 --- /dev/null +++ b/SSignalKit/SSignal+Accumulate.h @@ -0,0 +1,7 @@ +#import "SSignal.h" + +@interface SSignal (Accumulate) + +- (SSignal *)reduceLeft:(id)value with:(id (^)(id, id))f; + +@end diff --git a/SSignalKit/SSignal+Accumulate.m b/SSignalKit/SSignal+Accumulate.m new file mode 100644 index 0000000000..8410e4890c --- /dev/null +++ b/SSignalKit/SSignal+Accumulate.m @@ -0,0 +1,28 @@ +#import "SSignal+Accumulate.h" + +@implementation SSignal (Accumulate) + +- (SSignal *)reduceLeft:(id)value with:(id (^)(id, id))f +{ + __block id intermediateResult = value; + + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + id disposable = [self startWithNext:^(id next) + { + intermediateResult = f(intermediateResult, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + if (intermediateResult != nil) + SSubscriber_putNext(subscriber, intermediateResult); + SSubscriber_putCompletion(subscriber); + }]; + + [subscriber addDisposable:disposable]; + }]; +} + +@end diff --git a/SSignalKit/SSignal+Catch.h b/SSignalKit/SSignal+Catch.h new file mode 100644 index 0000000000..4fe07654c6 --- /dev/null +++ b/SSignalKit/SSignal+Catch.h @@ -0,0 +1,7 @@ +#import "SSignal.h" + +@interface SSignal (Catch) + +- (SSignal *)catch:(SSignal *(^)(id error))f; + +@end diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m new file mode 100644 index 0000000000..ae0528d028 --- /dev/null +++ b/SSignalKit/SSignal+Catch.m @@ -0,0 +1,38 @@ +#import "SSignal+Catch.h" + +#import "SMetaDisposable.h" + +@implementation SSignal (Catch) + +- (SSignal *)catch:(SSignal *(^)(id error))f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; + + [subscriber addDisposable:disposable]; + + [subscriber addDisposable:[self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSignal *signal = f(error); + [subscriber addDisposable:[signal startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + }]; +} + +@end diff --git a/SSignalKit/SSignal+Combine.h b/SSignalKit/SSignal+Combine.h new file mode 100644 index 0000000000..45834a81cf --- /dev/null +++ b/SSignalKit/SSignal+Combine.h @@ -0,0 +1,8 @@ +#import "SSignal.h" + +@interface SSignal (Combine) + ++ (SSignal *)combineSignals:(NSArray *)signals; ++ (SSignal *)combineSignals:(NSArray *)signals withInitialStates:(NSArray *)initialStates; + +@end diff --git a/SSignalKit/SSignal+Combine.m b/SSignalKit/SSignal+Combine.m new file mode 100644 index 0000000000..5624aeb143 --- /dev/null +++ b/SSignalKit/SSignal+Combine.m @@ -0,0 +1,129 @@ +#import "SSignal+Combine.h" + +#import "SAtomic.h" + +@interface SSignalCombineState : NSObject + +@property (nonatomic, strong, readonly) NSDictionary *latestValues; +@property (nonatomic, strong, readonly) NSArray *completedStatuses; +@property (nonatomic) bool error; + +@end + +@implementation SSignalCombineState + +- (instancetype)initWithLatestValues:(NSDictionary *)latestValues completedStatuses:(NSArray *)completedStatuses error:(bool)error +{ + self = [super init]; + if (self != nil) + { + _latestValues = latestValues; + _completedStatuses = completedStatuses; + _error = error; + } + return self; +} + +@end + +@implementation SSignal (Combine) + ++ (SSignal *)combineSignals:(NSArray *)signals +{ + return [self combineSignals:signals withInitialStates:nil]; +} + ++ (SSignal *)combineSignals:(NSArray *)signals withInitialStates:(NSArray *)initialStates +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + NSMutableArray *completedStatuses = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < signals.count; i++) + { + [completedStatuses addObject:@false]; + } + NSMutableDictionary *initialLatestValues = [[NSMutableDictionary alloc] init]; + for (NSUInteger i = 0; i < initialStates.count; i++) + { + initialLatestValues[@(i)] = initialStates[i]; + } + SAtomic *combineState = [[SAtomic alloc] initWithValue:[[SSignalCombineState alloc] initWithLatestValues:initialLatestValues completedStatuses:completedStatuses error:false]]; + + NSUInteger index = 0; + NSUInteger count = signals.count; + for (SSignal *signal in signals) + { + id disposable = [signal startWithNext:^(id next) + { + SSignalCombineState *currentState = [combineState modify:^id(SSignalCombineState *state) + { + NSMutableDictionary *latestValues = [[NSMutableDictionary alloc] initWithDictionary:state.latestValues]; + latestValues[@(index)] = next; + return [[SSignalCombineState alloc] initWithLatestValues:latestValues completedStatuses:state.completedStatuses error:state.error]; + }]; + NSMutableArray *latestValues = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < count; i++) + { + id value = currentState.latestValues[@(i)]; + if (value == nil) + { + latestValues = nil; + break; + } + latestValues[i] = value; + } + if (latestValues != nil) + SSubscriber_putNext(subscriber, latestValues); + } + error:^(id error) + { + __block bool hadError = false; + [combineState modify:^id(SSignalCombineState *state) + { + hadError = state.error; + return [[SSignalCombineState alloc] initWithLatestValues:state.latestValues completedStatuses:state.completedStatuses error:true]; + }]; + if (!hadError) + SSubscriber_putError(subscriber, error); + } completed:^ + { + __block bool wasCompleted = false; + __block bool isCompleted = false; + [combineState modify:^id(SSignalCombineState *state) + { + NSMutableArray *completedStatuses = [[NSMutableArray alloc] initWithArray:state.completedStatuses]; + bool everyStatusWasCompleted = true; + for (NSNumber *nStatus in completedStatuses) + { + if (![nStatus boolValue]) + { + everyStatusWasCompleted = false; + break; + } + } + completedStatuses[index] = @true; + bool everyStatusIsCompleted = true; + for (NSNumber *nStatus in completedStatuses) + { + if (![nStatus boolValue]) + { + everyStatusIsCompleted = false; + break; + } + } + + wasCompleted = everyStatusWasCompleted; + isCompleted = everyStatusIsCompleted; + + return [[SSignalCombineState alloc] initWithLatestValues:state.latestValues completedStatuses:completedStatuses error:state.error]; + }]; + if (!wasCompleted && isCompleted) + SSubscriber_putCompletion(subscriber); + }]; + [subscriber addDisposable:disposable]; + index++; + } + }]; +} + +@end diff --git a/SSignalKit/SSignal+Concat.h b/SSignalKit/SSignal+Concat.h new file mode 100644 index 0000000000..356f80c213 --- /dev/null +++ b/SSignalKit/SSignal+Concat.h @@ -0,0 +1,5 @@ +#import "SSignal.h" + +@interface SSignal (Concat) + +@end diff --git a/SSignalKit/SSignal+Concat.m b/SSignalKit/SSignal+Concat.m new file mode 100644 index 0000000000..19bfc4da70 --- /dev/null +++ b/SSignalKit/SSignal+Concat.m @@ -0,0 +1,15 @@ +#import "SSignal+Concat.h" + +#import "SAtomic.h" +#import "SCompositeDisposable.h" + +@implementation SSignal (Concat) + +- (SSignal *)concat:(SSignal *)another +{ + NSAssert(false, @"123"); + + return nil; +} + +@end diff --git a/SSignalKit/SSignal+Dispatch.h b/SSignalKit/SSignal+Dispatch.h new file mode 100644 index 0000000000..17d74ab452 --- /dev/null +++ b/SSignalKit/SSignal+Dispatch.h @@ -0,0 +1,13 @@ +#import "SSignal.h" + +#import "SQueue.h" +#import "SThreadPool.h" + +@interface SSignal (Dispatch) + +- (SSignal *)deliverOn:(SQueue *)queue; +- (SSignal *)deliverOnThreadPool:(SThreadPool *)threadPool; +- (SSignal *)startOn:(SQueue *)queue; +- (SSignal *)startOnThreadPool:(SThreadPool *)threadPool; + +@end diff --git a/SSignalKit/SSignal+Dispatch.m b/SSignalKit/SSignal+Dispatch.m new file mode 100644 index 0000000000..1c9af779b1 --- /dev/null +++ b/SSignalKit/SSignal+Dispatch.m @@ -0,0 +1,127 @@ +#import "SSignal+Dispatch.h" +#import "SAtomic.h" +#import "SBlockDisposable.h" + +@implementation SSignal (Dispatch) + +- (SSignal *)deliverOn:(SQueue *)queue +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + [subscriber addDisposable:[self startWithNext:^(id next) + { + [queue dispatch:^ + { + SSubscriber_putNext(subscriber, next); + }]; + } error:^(id error) + { + [queue dispatch:^ + { + SSubscriber_putError(subscriber, error); + }]; + } completed:^ + { + [queue dispatch:^ + { + SSubscriber_putCompletion(subscriber); + }]; + }]]; + }]; +} + +- (SSignal *)deliverOnThreadPool:(SThreadPool *)threadPool +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + SAtomic *atomicLastTask = [[SAtomic alloc] initWithValue:nil]; + [subscriber addDisposable:[self startWithNext:^(id next) + { + SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) + { + if (!cancelled()) + SSubscriber_putNext(subscriber, next); + }]; + SThreadPoolTask *lastTask = [atomicLastTask swap:task]; + if (lastTask != nil) + [task addDependency:lastTask]; + [threadPool startTask:task]; + } error:^(id error) + { + SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) + { + if (!cancelled()) + SSubscriber_putError(subscriber, error); + }]; + SThreadPoolTask *lastTask = [atomicLastTask swap:task]; + if (lastTask != nil) + [task addDependency:lastTask]; + [threadPool startTask:task]; + } completed:^ + { + SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) + { + if (!cancelled()) + SSubscriber_putCompletion(subscriber); + }]; + SThreadPoolTask *lastTask = [atomicLastTask swap:task]; + if (lastTask != nil) + [task addDependency:lastTask]; + [threadPool startTask:task]; + }]]; + }]; +} + +- (SSignal *)startOn:(SQueue *)queue +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + [queue dispatch:^ + { + id disposable = [self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]; + + [subscriber addDisposable:disposable]; + }]; + }]; +} + +- (SSignal *)startOnThreadPool:(SThreadPool *)threadPool +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + id taskId = [threadPool addTask:^(bool (^cancelled)()) + { + if (cancelled && cancelled()) + return; + + [subscriber addDisposable:[self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + }]; + + __weak SThreadPool *weakThreadPool = threadPool; + [subscriber addDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + __strong SThreadPool *strongThreadPool = weakThreadPool; + [strongThreadPool cancelTask:taskId]; + }]]; + }]; +} + +@end diff --git a/SSignalKit/SSignal+Mapping.h b/SSignalKit/SSignal+Mapping.h new file mode 100644 index 0000000000..c6d516c1ef --- /dev/null +++ b/SSignalKit/SSignal+Mapping.h @@ -0,0 +1,8 @@ +#import "SSignal.h" + +@interface SSignal (Mapping) + +- (SSignal *)map:(id (^)(id))f; +- (SSignal *)filter:(bool (^)(id))f; + +@end diff --git a/SSignalKit/SSignal+Mapping.m b/SSignalKit/SSignal+Mapping.m new file mode 100644 index 0000000000..db34d31772 --- /dev/null +++ b/SSignalKit/SSignal+Mapping.m @@ -0,0 +1,42 @@ +#import "SSignal+Mapping.h" + +@implementation SSignal (Mapping) + +- (SSignal *)map:(id (^)(id))f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + id disposable = [self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, f(next)); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]; + [subscriber addDisposable:disposable]; + }]; +} + +- (SSignal *)filter:(bool (^)(id))f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + id disposable = [self startWithNext:^(id next) + { + if (f(next)) + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]; + [subscriber addDisposable:disposable]; + }]; +} + +@end diff --git a/SSignalKit/SSignal+Meta.h b/SSignalKit/SSignal+Meta.h new file mode 100644 index 0000000000..a9ab8c6a7c --- /dev/null +++ b/SSignalKit/SSignal+Meta.h @@ -0,0 +1,9 @@ +#import "SSignal.h" + +@interface SSignal (Meta) + +- (SSignal *)switchToLatest; +- (SSignal *)mapToSignal:(SSignal *(^)(id))f; +- (SSignal *)then:(SSignal *)signal; + +@end diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m new file mode 100644 index 0000000000..f811ea26d9 --- /dev/null +++ b/SSignalKit/SSignal+Meta.m @@ -0,0 +1,75 @@ +#import "SSignal+Meta.h" + +#import "SMetaDisposable.h" +#import "SSignal+Mapping.h" +#import "SAtomic.h" + +@implementation SSignal (Meta) + +- (SSignal *)switchToLatest +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + SMetaDisposable *currentDisposable = [[SMetaDisposable alloc] init]; + + SAtomic *didProduceNext = [[SAtomic alloc] initWithValue:nil]; + id disposable = [self startWithNext:^(SSignal *next) + { + [didProduceNext swap:@1]; + id innerDisposable = [next startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]; + [currentDisposable setDisposable:innerDisposable]; + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + if ([didProduceNext value] == nil) + SSubscriber_putCompletion(subscriber); + }]; + + [subscriber addDisposable:currentDisposable]; + [subscriber addDisposable:disposable]; + }]; +} + +- (SSignal *)mapToSignal:(SSignal *(^)(id))f +{ + return [[self map:f] switchToLatest]; +} + +- (SSignal *)then:(SSignal *)signal +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + [subscriber addDisposable:[self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + [subscriber addDisposable:[signal startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + }]]; + }]; +} + +@end diff --git a/SSignalKit/SSignal+Multicast.h b/SSignalKit/SSignal+Multicast.h new file mode 100644 index 0000000000..3d3c4fc4e5 --- /dev/null +++ b/SSignalKit/SSignal+Multicast.h @@ -0,0 +1,7 @@ +#import "SSignal.h" + +@interface SSignal (Multicast) + +- (SSignal *)multicast; + +@end diff --git a/SSignalKit/SSignal+Multicast.m b/SSignalKit/SSignal+Multicast.m new file mode 100644 index 0000000000..e3bb9d04cd --- /dev/null +++ b/SSignalKit/SSignal+Multicast.m @@ -0,0 +1,131 @@ +#import "SSignal+Multicast.h" + +#import +#import "SBag.h" +#import "SBlockDisposable.h" + +typedef enum { + SSignalMulticastStateReady, + SSignalMulticastStateStarted, + SSignalMulticastStateCompleted +} SSignalMulticastState; + +@interface SSignalMulticastSubscribers : NSObject +{ + volatile OSSpinLock _lock; + SBag *_subscribers; + SSignalMulticastState _state; + id _disposable; +} + +@end + +@implementation SSignalMulticastSubscribers + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + _subscribers = [[SBag alloc] init]; + } + return self; +} + +- (void)setDisposable:(id)disposable +{ + [_disposable dispose]; + _disposable = disposable; +} + +- (bool)addSubscriber:(SSubscriber *)subscriber +{ + bool start = false; + + OSSpinLockLock(&_lock); + NSInteger index = [_subscribers addItem:subscriber]; + switch (_state) { + case SSignalMulticastStateReady: + start = true; + _state = SSignalMulticastStateStarted; + break; + default: + break; + } + OSSpinLockUnlock(&_lock); + + [subscriber addDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + [self remove:index]; + }]]; + + return start; +} + +- (void)remove:(NSInteger)index +{ + id currentDisposable = nil; + + OSSpinLockLock(&_lock); + [_subscribers removeItem:index]; + switch (_state) { + case SSignalMulticastStateStarted: + if ([_subscribers isEmpty]) + { + currentDisposable = _disposable; + _disposable = nil; + } + break; + default: + break; + } + OSSpinLockUnlock(&_lock); + + [currentDisposable dispose]; +} + +- (void)notify:(SEvent *)event +{ + NSArray *currentSubscribers = nil; + OSSpinLockLock(&_lock); + currentSubscribers = [_subscribers copyItems]; + if (event.type != SEventTypeNext) + _state = SSignalMulticastStateCompleted; + OSSpinLockUnlock(&_lock); + + for (SSubscriber *subscriber in currentSubscribers) + { + SSubscriber_putEvent(subscriber, event); + } +} + +@end + +@implementation SSignal (Multicast) + +- (SSignal *)multicast +{ + SSignalMulticastSubscribers *subscribers = [[SSignalMulticastSubscribers alloc] init]; + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + if ([subscribers addSubscriber:subscriber]) + { + id disposable = [self startWithNext:^(id next) + { + [subscribers notify:[[SEvent alloc] initWithNext:next]]; + } error:^(id error) + { + [subscribers notify:[[SEvent alloc] initWithError:error]]; + } completed:^ + { + [subscribers notify:[[SEvent alloc] initWithCompleted]]; + }]; + [subscribers setDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + [disposable dispose]; + }]]; + } + }]; +} + +@end diff --git a/SSignalKit/SSignal+SideEffects.h b/SSignalKit/SSignal+SideEffects.h new file mode 100644 index 0000000000..66023f137c --- /dev/null +++ b/SSignalKit/SSignal+SideEffects.h @@ -0,0 +1,10 @@ +#import "SSignal.h" + +@interface SSignal (SideEffects) + +- (SSignal *)onNext:(void (^)(id next))f; +- (SSignal *)onError:(void (^)(id error))f; +- (SSignal *)onCompletion:(void (^)())f; +- (SSignal *)onDispose:(void (^)())f; + +@end diff --git a/SSignalKit/SSignal+SideEffects.m b/SSignalKit/SSignal+SideEffects.m new file mode 100644 index 0000000000..42234b5403 --- /dev/null +++ b/SSignalKit/SSignal+SideEffects.m @@ -0,0 +1,83 @@ +#import "SSignal+SideEffects.h" + +#import "SBlockDisposable.h" + +@implementation SSignal (SideEffects) + +- (SSignal *)onNext:(void (^)(id next))f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + [subscriber addDisposable:[self startWithNext:^(id next) + { + f(next); + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + }]; +} + +- (SSignal *)onError:(void (^)(id error))f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + [subscriber addDisposable:[self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + f(error); + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + }]; +} + +- (SSignal *)onCompletion:(void (^)())f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + [subscriber addDisposable:[self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + f(); + SSubscriber_putCompletion(subscriber); + }]]; + }]; +} + +- (SSignal *)onDispose:(void (^)())f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + [subscriber addDisposable:[self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + + [subscriber addDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + f(); + }]]; + }]; +} + +@end diff --git a/SSignalKit/SSignal+Single.h b/SSignalKit/SSignal+Single.h new file mode 100644 index 0000000000..8ce640da5e --- /dev/null +++ b/SSignalKit/SSignal+Single.h @@ -0,0 +1,10 @@ +#import "SSignal.h" + +@interface SSignal (Single) + ++ (SSignal *)single:(id)next; ++ (SSignal *)fail:(id)error; ++ (SSignal *)never; ++ (SSignal *)complete; + +@end diff --git a/SSignalKit/SSignal+Single.m b/SSignalKit/SSignal+Single.m new file mode 100644 index 0000000000..18bbf4c332 --- /dev/null +++ b/SSignalKit/SSignal+Single.m @@ -0,0 +1,63 @@ +#import "SSignal+Single.h" + +@interface SSignal_Single : SSignal +{ + id _next; +} + +@end + +@implementation SSignal_Single + +- (instancetype)initWithNext:(id)next +{ + self = [super init]; + if (self != nil) + { + _next = next; + } + return self; +} + +- (id)startWithNext:(void (^)(id))next error:(void (^)(id))__unused error completed:(void (^)())completed +{ + if (next) + next(_next); + if (completed) + completed(); + return nil; +} + +@end + +@implementation SSignal (Single) + ++ (SSignal *)single:(id)next +{ + return [[SSignal_Single alloc] initWithNext:next]; +} + ++ (SSignal *)fail:(id)error +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + SSubscriber_putError(subscriber, error); + }]; +} + ++ (SSignal *)never +{ + return [[SSignal alloc] initWithGenerator:^(__unused SSubscriber *subscriber) + { + }]; +} + ++ (SSignal *)complete +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + SSubscriber_putCompletion(subscriber); + }]; +} + +@end diff --git a/SSignalKit/SSignal+Timing.h b/SSignalKit/SSignal+Timing.h new file mode 100644 index 0000000000..0d07dbbcb1 --- /dev/null +++ b/SSignalKit/SSignal+Timing.h @@ -0,0 +1,9 @@ +#import "SSignal.h" + +#import "SQueue.h" + +@interface SSignal (Timing) + +- (SSignal *)delay:(NSTimeInterval)seconds onQueue:(SQueue *)queue; + +@end diff --git a/SSignalKit/SSignal+Timing.m b/SSignalKit/SSignal+Timing.m new file mode 100644 index 0000000000..858150f81b --- /dev/null +++ b/SSignalKit/SSignal+Timing.m @@ -0,0 +1,36 @@ +#import "SSignal+Timing.h" + +#import "SBlockDisposable.h" + +#import "STimer.h" + +@implementation SSignal (Timing) + +- (SSignal *)delay:(NSTimeInterval)seconds onQueue:(SQueue *)queue +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + STimer *timer = [[STimer alloc] initWithTimeout:seconds repeat:false completion:^ + { + [subscriber addDisposable:[self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + } queue:queue]; + + [subscriber addDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + [timer invalidate]; + }]]; + + [timer start]; + }]; +} + +@end diff --git a/SSignalKit/SSignal.h b/SSignalKit/SSignal.h new file mode 100644 index 0000000000..ee48ff62bc --- /dev/null +++ b/SSignalKit/SSignal.h @@ -0,0 +1,19 @@ +#import "SSubscriber.h" + +@interface SSignal : NSObject +{ +@public + void (^_generator)(SSubscriber *); +} + +- (instancetype)initWithGenerator:(void (^)(SSubscriber *))generator; +- (id)startWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; + +@end + +inline id SSignal_start(SSignal *signal, void (^next)(id), void (^error)(id), void (^completed)()) +{ + SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:error completed:completed]; + signal->_generator(subscriber); + return [subscriber _disposable]; +} diff --git a/SSignalKit/SSignal.m b/SSignalKit/SSignal.m new file mode 100644 index 0000000000..741b6cbb64 --- /dev/null +++ b/SSignalKit/SSignal.m @@ -0,0 +1,28 @@ +#import "SSignal.h" + +@interface SSignal () +{ +} + +@end + +@implementation SSignal + +- (instancetype)initWithGenerator:(void (^)(SSubscriber *))generator +{ + self = [super init]; + if (self != nil) + { + _generator = [generator copy]; + } + return self; +} + +- (id)startWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed +{ + SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:error completed:completed]; + _generator(subscriber); + return [subscriber _disposable]; +} + +@end diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h index dde27ab5b1..b4e9d19dcf 100644 --- a/SSignalKit/SSignalKit.h +++ b/SSignalKit/SSignalKit.h @@ -16,4 +16,25 @@ FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import - +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import \ No newline at end of file diff --git a/SSignalKit/SSubscriber.h b/SSignalKit/SSubscriber.h new file mode 100644 index 0000000000..34c2d974a2 --- /dev/null +++ b/SSignalKit/SSubscriber.h @@ -0,0 +1,30 @@ +#import "SCompositeDisposable.h" + +#import "SEvent.h" + +@interface SSubscriber : NSObject + +- (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; + +- (id)_disposable; +- (void)addDisposable:(id)disposable; + +- (void)putEvent:(SEvent *)event; +- (void)putNext:(id)next; +- (void)putError:(id)error; +- (void)putCompletion; + +@end + +#ifdef __cplusplus +extern "C" { +#endif + +void SSubscriber_putNext(SSubscriber *subscriber, id next); +void SSubscriber_putError(SSubscriber *subscriber, id error); +void SSubscriber_putCompletion(SSubscriber *subscriber); +void SSubscriber_putEvent(SSubscriber *subscriber, SEvent *event); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m new file mode 100644 index 0000000000..3256a3ca60 --- /dev/null +++ b/SSignalKit/SSubscriber.m @@ -0,0 +1,163 @@ +#import "SSubscriber.h" + +#import +#import + +#import "SEvent.h" + +#define lockSelf(x) pthread_mutex_lock(&x->_mutex) +#define unlockSelf(x) pthread_mutex_unlock(&x->_mutex) + +@interface SSubscriber () +{ + @public + //volatile OSSpinLock _lock; + pthread_mutex_t _mutex; + void (^_next)(id); + void (^_error)(id); + void (^_completed)(); + + SCompositeDisposable *_disposable; +} + +@end + +@implementation SSubscriber + +- (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed +{ + self = [super init]; + if (self != nil) + { + pthread_mutex_init(&_mutex, NULL); + _disposable = [[SCompositeDisposable alloc] init]; + _next = [next copy]; + _error = [error copy]; + _completed = [completed copy]; + } + return self; +} + +- (id)_disposable +{ + return _disposable; +} + +- (void)addDisposable:(id)disposable +{ + [_disposable add:disposable]; +} + +- (void)putEvent:(SEvent *)event +{ + SSubscriber_putEvent(self, event); +} + +- (void)putNext:(id)next +{ + [self putEvent:[[SEvent alloc] initWithNext:next]]; +} + +- (void)putError:(id)error +{ + [self putEvent:[[SEvent alloc] initWithError:error]]; +} + +- (void)putCompletion +{ + [self putEvent:[[SEvent alloc] initWithCompleted]]; +} + +void SSubscriber_putNext(SSubscriber *subscriber, id next) +{ + void (^fnext)(id) = nil; + + lockSelf(subscriber); + fnext = subscriber->_next; + unlockSelf(subscriber); + + if (fnext) + fnext(next); +} + +void SSubscriber_putError(SSubscriber *subscriber, id error) +{ + bool shouldDispose = false; + void (^ferror)(id) = nil; + + lockSelf(subscriber); + ferror = subscriber->_error; + shouldDispose = true; + subscriber->_next = nil; + subscriber->_error = nil; + subscriber->_completed = nil; + unlockSelf(subscriber); + + if (ferror) + ferror(error); + + if (shouldDispose) + [subscriber->_disposable dispose]; +} + +void SSubscriber_putCompletion(SSubscriber *subscriber) +{ + bool shouldDispose = false; + void (^completed)() = nil; + + lockSelf(subscriber); + completed = subscriber->_completed; + shouldDispose = true; + subscriber->_next = nil; + subscriber->_error = nil; + subscriber->_completed = nil; + unlockSelf(subscriber); + + if (completed) + completed(); + + if (shouldDispose) + [subscriber->_disposable dispose]; +} + +void SSubscriber_putEvent(SSubscriber *subscriber, SEvent *event) +{ + bool shouldDispose = false; + void (^next)(id) = nil; + void (^error)(id) = nil; + void (^completed)(id) = nil; + + lockSelf(subscriber); + next = subscriber->_next; + error = subscriber->_error; + completed = subscriber->_completed; + if (event.type != SEventTypeNext) + { + shouldDispose = true; + subscriber->_next = nil; + subscriber->_error = nil; + subscriber->_completed = nil; + } + unlockSelf(subscriber); + + switch (event.type) + { + case SEventTypeNext: + if (next) + next(event.data); + break; + case SEventTypeError: + if (error) + error(event.data); + break; + case SEventTypeCompleted: + if (completed) + completed(event.data); + break; + } + + if (shouldDispose) + [subscriber->_disposable dispose]; +} + +@end diff --git a/SSignalKit/SThreadPool.h b/SSignalKit/SThreadPool.h new file mode 100644 index 0000000000..f2342081f7 --- /dev/null +++ b/SSignalKit/SThreadPool.h @@ -0,0 +1,18 @@ +#import + +@interface SThreadPoolTask : NSObject + +- (void)addDependency:(SThreadPoolTask *)task; + +@end + +@interface SThreadPool : NSObject + +- (instancetype)initWithThreadCount:(NSUInteger)threadCount threadPriority:(double)threadPriority; + +- (id)addTask:(void (^)(bool (^)()))task; +- (SThreadPoolTask *)prepareTask:(void (^)(bool (^)()))task; +- (id)startTask:(SThreadPoolTask *)task; +- (void)cancelTask:(id)taskId; + +@end diff --git a/SSignalKit/SThreadPool.m b/SSignalKit/SThreadPool.m new file mode 100644 index 0000000000..b39ef64da3 --- /dev/null +++ b/SSignalKit/SThreadPool.m @@ -0,0 +1,227 @@ +#import "SThreadPool.h" + +#import +#import +#import "SQueue.h" + +@class SThreadPoolOperation; + +@interface SThreadPoolTask () + +@property (nonatomic, strong, readonly) SThreadPoolOperation *operation; + +- (instancetype)initWithOperation:(SThreadPoolOperation *)operation; + +@end + +@interface SThreadPoolOperationCanelledHolder : NSObject +{ + @public + volatile bool _cancelled; +} + +@property (nonatomic, weak) SThreadPoolOperation *operation; + +@end + +@implementation SThreadPoolOperationCanelledHolder + +@end + +@interface SThreadPoolOperation : NSOperation +{ + void (^_block)(bool (^)()); +} + +@property (nonatomic, strong, readonly) SThreadPoolOperationCanelledHolder *cancelledHolder; + +@end + +@implementation SThreadPoolOperation + +- (instancetype)initWithBlock:(void (^)(bool (^)()))block +{ + self = [super init]; + if (self != nil) + { + _block = [block copy]; + _cancelledHolder = [[SThreadPoolOperationCanelledHolder alloc] init]; + _cancelledHolder.operation = self; + } + return self; +} + +- (void)main +{ + if (!_cancelledHolder->_cancelled) + { + SThreadPoolOperationCanelledHolder *cancelledHolder = _cancelledHolder; + _block(^bool + { + return cancelledHolder->_cancelled; + }); + } +} + +- (void)cancel +{ + _cancelledHolder->_cancelled = true; +} + +- (BOOL)isCancelled +{ + return _cancelledHolder->_cancelled; +} + +@end + +@interface SThreadPool () +{ + SQueue *_managementQueue; + NSMutableArray *_threads; + NSMutableArray *_operations; + + pthread_mutex_t _mutex; + pthread_cond_t _cond; +} + +@end + +@implementation SThreadPool + ++ (void)threadEntryPoint:(SThreadPool *)threadPool +{ + while (true) + { + SThreadPoolOperation *operation = nil; + + pthread_mutex_lock(&threadPool->_mutex); + while (true) + { + while (threadPool->_operations.count == 0) + pthread_cond_wait(&threadPool->_cond, &threadPool->_mutex); + for (NSUInteger index = 0; index < threadPool->_operations.count; index++) + { + SThreadPoolOperation *maybeOperation = threadPool->_operations[index]; + if ([maybeOperation isCancelled]) + { + [threadPool->_operations removeObjectAtIndex:index]; + index--; + } + else if ([maybeOperation isReady]) + { + operation = maybeOperation; + [threadPool->_operations removeObjectAtIndex:index]; + break; + } + } + + if (operation != nil) + break; + } + pthread_mutex_unlock(&threadPool->_mutex); + + @autoreleasepool + { + [operation main]; + } + } +} + +- (instancetype)init +{ + return [self initWithThreadCount:2 threadPriority:0.5]; +} + +- (instancetype)initWithThreadCount:(NSUInteger)threadCount threadPriority:(double)threadPriority +{ + self = [super init]; + if (self != nil) + { + pthread_mutex_init(&_mutex, 0); + pthread_cond_init(&_cond, 0); + + _managementQueue = [[SQueue alloc] init]; + + [_managementQueue dispatch:^ + { + _threads = [[NSMutableArray alloc] init]; + _operations = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < threadCount; i++) + { + NSThread *thread = [[NSThread alloc] initWithTarget:[SThreadPool class] selector:@selector(threadEntryPoint:) object:self]; + thread.name = [[NSString alloc] initWithFormat:@"SThreadPool-%p-%d", self, (int)i]; + [thread setThreadPriority:threadPriority]; + [_threads addObject:thread]; + [thread start]; + } + }]; + } + return self; +} + +- (void)dealloc +{ + pthread_mutex_destroy(&_mutex); + pthread_cond_destroy(&_cond); +} + +- (void)_addOperation:(SThreadPoolOperation *)operation +{ + pthread_mutex_lock(&_mutex); + [_operations addObject:operation]; + pthread_cond_signal(&_cond); + pthread_mutex_unlock(&_mutex); +} + +- (id)addTask:(void (^)(bool (^)()))task +{ + SThreadPoolOperation *operation = [[SThreadPoolOperation alloc] initWithBlock:task]; + [_managementQueue dispatch:^ + { + [self _addOperation:operation]; + }]; + return operation.cancelledHolder; +} + +- (SThreadPoolTask *)prepareTask:(void (^)(bool (^)()))task +{ + SThreadPoolOperation *operation = [[SThreadPoolOperation alloc] initWithBlock:task]; + return [[SThreadPoolTask alloc] initWithOperation:operation]; +} + +- (id)startTask:(SThreadPoolTask *)task +{ + [_managementQueue dispatch:^ + { + [self _addOperation:task.operation]; + }]; + return task.operation.cancelledHolder; +} + +- (void)cancelTask:(id)taskId +{ + if (taskId != nil) + ((SThreadPoolOperationCanelledHolder *)taskId)->_cancelled = true; +} + +@end + +@implementation SThreadPoolTask + +- (instancetype)initWithOperation:(SThreadPoolOperation *)operation +{ + self = [super init]; + if (self != nil) + { + _operation = operation; + } + return self; +} + +- (void)addDependency:(SThreadPoolTask *)task +{ + [_operation addDependency:task->_operation]; +} + +@end diff --git a/SSignalKit/STimer.h b/SSignalKit/STimer.h new file mode 100644 index 0000000000..e0c4e7b81f --- /dev/null +++ b/SSignalKit/STimer.h @@ -0,0 +1,12 @@ +#import + +@class SQueue; + +@interface STimer : NSObject + +- (id)initWithTimeout:(NSTimeInterval)timeout repeat:(bool)repeat completion:(dispatch_block_t)completion queue:(SQueue *)queue; + +- (void)start; +- (void)invalidate; + +@end diff --git a/SSignalKit/STimer.m b/SSignalKit/STimer.m new file mode 100644 index 0000000000..0dec5c35e6 --- /dev/null +++ b/SSignalKit/STimer.m @@ -0,0 +1,79 @@ +#import "STimer.h" + +#import "SQueue.h" + +@interface STimer () +{ + dispatch_source_t _timer; + NSTimeInterval _timeout; + NSTimeInterval _timeoutDate; + bool _repeat; + dispatch_block_t _completion; + SQueue *_queue; +} + +@end + +@implementation STimer + +- (id)initWithTimeout:(NSTimeInterval)timeout repeat:(bool)repeat completion:(dispatch_block_t)completion queue:(SQueue *)queue +{ + self = [super init]; + if (self != nil) + { + _timeoutDate = INT_MAX; + + _timeout = timeout; + _repeat = repeat; + _completion = [completion copy]; + _queue = queue; + } + return self; +} + +- (void)dealloc +{ + if (_timer != nil) + { + dispatch_source_cancel(_timer); + _timer = nil; + } +} + +- (void)start +{ + _timeoutDate = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970 + _timeout; + + _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, [_queue _dispatch_queue]); + dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)), _repeat ? (int64_t)(_timeout * NSEC_PER_SEC) : DISPATCH_TIME_FOREVER, 0); + + dispatch_source_set_event_handler(_timer, ^ + { + if (_completion) + _completion(); + if (!_repeat) + [self invalidate]; + }); + dispatch_resume(_timer); +} + +- (void)fireAndInvalidate +{ + if (_completion) + _completion(); + + [self invalidate]; +} + +- (void)invalidate +{ + _timeoutDate = 0; + + if (_timer != nil) + { + dispatch_source_cancel(_timer); + _timer = nil; + } +} + +@end diff --git a/SSignalKitTests/SBlockDisposableTest.m b/SSignalKitTests/SBlockDisposableTest.m new file mode 100644 index 0000000000..fdc56d7af6 --- /dev/null +++ b/SSignalKitTests/SBlockDisposableTest.m @@ -0,0 +1,55 @@ +#import +#import + +#import + +@import SSignalKit; + +@interface SBlockDisposableTest : XCTestCase + +@end + +@implementation SBlockDisposableTest + +- (void)setUp +{ + [super setUp]; +} + +- (void)tearDown +{ + [super tearDown]; +} + +- (void)testBlockDisposable +{ +} + +- (void)testPerformanceExample +{ + [self measureBlock:^ + { + SSignal *signal = [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + //SSubscriber_putNext(subscriber, @1); + //SSubscriber_putCompletion(subscriber); + }]; + + for (int i = 0; i < 1000000; i++) + { + [signal startWithNext:^(id next) + { + + } error:^(id error) + { + + } completed:^ + { + + }]; + //SSignal_start(signal, ^(id next){}, ^(id error){}, ^{}); + } + }]; +} + +@end From 262b413f8fa8ac546e72432d9c018fa887632b3f Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 5 Feb 2015 15:37:52 +0300 Subject: [PATCH 004/122] Block disposable fix --- SSignalKit/SBlockDisposable.m | 17 ++++++ SSignalKitTests/SBlockDisposableTest.m | 77 ++++++++++++++++++-------- 2 files changed, 70 insertions(+), 24 deletions(-) diff --git a/SSignalKit/SBlockDisposable.m b/SSignalKit/SBlockDisposable.m index 05908db7f6..2bd19a5afc 100644 --- a/SSignalKit/SBlockDisposable.m +++ b/SSignalKit/SBlockDisposable.m @@ -23,6 +23,22 @@ return self; } +- (void)dealloc +{ + void *block = _block; + if (block != NULL) + { + if (OSAtomicCompareAndSwapPtr(block, 0, &_block)) + { + if (block != nil) + { + __strong id strongBlock = (__bridge_transfer id)block; + strongBlock = nil; + } + } + } +} + - (void)dispose { void *block = _block; @@ -34,6 +50,7 @@ { __strong id strongBlock = (__bridge_transfer id)block; ((dispatch_block_t)strongBlock)(); + strongBlock = nil; } } } diff --git a/SSignalKitTests/SBlockDisposableTest.m b/SSignalKitTests/SBlockDisposableTest.m index fdc56d7af6..eed55751ed 100644 --- a/SSignalKitTests/SBlockDisposableTest.m +++ b/SSignalKitTests/SBlockDisposableTest.m @@ -5,6 +5,32 @@ @import SSignalKit; +@interface TestObject : NSObject +{ + bool *_deallocated; +} + +@end + +@implementation TestObject + +- (instancetype)initWithDeallocated:(bool *)deallocated +{ + self = [super init]; + if (self != nil) + { + _deallocated = deallocated; + } + return self; +} + +- (void)dealloc +{ + *_deallocated = true; +} + +@end + @interface SBlockDisposableTest : XCTestCase @end @@ -21,35 +47,38 @@ [super tearDown]; } -- (void)testBlockDisposable +- (void)testBlockDisposableDisposed { + bool deallocated = false; + { + TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + dispatch_block_t block = ^{ + [object description]; + }; + SBlockDisposable *disposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; + object = nil; + block = nil; + [disposable dispose]; + } + + XCTAssertTrue(deallocated); } -- (void)testPerformanceExample +- (void)testBlockDisposableNotDisposed { - [self measureBlock:^ + bool deallocated = false; { - SSignal *signal = [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) - { - //SSubscriber_putNext(subscriber, @1); - //SSubscriber_putCompletion(subscriber); - }]; - - for (int i = 0; i < 1000000; i++) - { - [signal startWithNext:^(id next) - { - - } error:^(id error) - { - - } completed:^ - { - - }]; - //SSignal_start(signal, ^(id next){}, ^(id error){}, ^{}); - } - }]; + TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + dispatch_block_t block = ^{ + [object description]; + }; + SBlockDisposable *disposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; + object = nil; + block = nil; + disposable = nil; + } + + XCTAssertTrue(deallocated); } @end From 8a90fe2db6047468e4a301bc91583ce5c1e78587 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 5 Feb 2015 16:24:13 +0300 Subject: [PATCH 005/122] Tests, SCompositeDisposable refatoring --- SSignalKit.xcodeproj/project.pbxproj | 29 +-- SSignalKit/SBlockDisposable.m | 1 - SSignalKit/SCompositeDisposable.m | 60 ------ ...CompositeDisposable.h => SDisposableSet.h} | 2 +- SSignalKit/SDisposableSet.m | 64 ++++++ SSignalKit/SMetaDisposable.m | 56 +++--- SSignalKit/SSignal+Concat.m | 1 - SSignalKit/SSignalKit.h | 4 +- SSignalKit/SSubscriber.h | 3 +- SSignalKit/SSubscriber.m | 5 +- SSignalKitTests/SBlockDisposableTest.m | 190 +++++++++++++++++- 11 files changed, 305 insertions(+), 110 deletions(-) delete mode 100644 SSignalKit/SCompositeDisposable.m rename SSignalKit/{SCompositeDisposable.h => SDisposableSet.h} (56%) create mode 100644 SSignalKit/SDisposableSet.m diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 0a5c374660..95bf6088bd 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -16,8 +16,6 @@ D0445E251A7C2D7300267924 /* SBag.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DF91A7C2D7300267924 /* SBag.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445E261A7C2D7300267924 /* SBag.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFA1A7C2D7300267924 /* SBag.m */; }; D0445E271A7C2D7300267924 /* SBlockDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E281A7C2D7300267924 /* SCompositeDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFC1A7C2D7300267924 /* SCompositeDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E291A7C2D7300267924 /* SCompositeDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFD1A7C2D7300267924 /* SCompositeDisposable.m */; }; D0445E2A1A7C2D7300267924 /* SDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFE1A7C2D7300267924 /* SDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445E2B1A7C2D7300267924 /* SEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFF1A7C2D7300267924 /* SEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445E2C1A7C2D7300267924 /* SEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E001A7C2D7300267924 /* SEvent.m */; }; @@ -61,7 +59,6 @@ D0445E731A7C447D00267924 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF61A7C2D7300267924 /* SBlockDisposable.m */; }; D0445E741A7C447D00267924 /* SAtomic.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF81A7C2D7300267924 /* SAtomic.m */; }; D0445E751A7C447D00267924 /* SBag.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFA1A7C2D7300267924 /* SBag.m */; }; - D0445E761A7C447D00267924 /* SCompositeDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFD1A7C2D7300267924 /* SCompositeDisposable.m */; }; D0445E771A7C447D00267924 /* SEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E001A7C2D7300267924 /* SEvent.m */; }; D0445E781A7C447D00267924 /* SMetaDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E011A7C2D7300267924 /* SMetaDisposable.m */; }; D0445E791A7C447D00267924 /* SMulticastSignalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */; }; @@ -81,6 +78,9 @@ D0445E871A7C447D00267924 /* SThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1F1A7C2D7300267924 /* SThreadPool.m */; }; D0445E881A7C447D00267924 /* SQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E4D1A7C2D8A00267924 /* SQueue.m */; }; D0445E891A7C447D00267924 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E531A7C2E9D00267924 /* STimer.m */; }; + D087632A1A839EDC00632240 /* SDisposableSet.h in Headers */ = {isa = PBXBuildFile; fileRef = D08763281A839EDC00632240 /* SDisposableSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D08763291A839EDC00632240 /* SDisposableSet.m */; }; + D087632C1A839EE800632240 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D08763291A839EDC00632240 /* SDisposableSet.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -118,8 +118,6 @@ D0445DF91A7C2D7300267924 /* SBag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBag.h; sourceTree = ""; }; D0445DFA1A7C2D7300267924 /* SBag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBag.m; sourceTree = ""; }; D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBlockDisposable.h; sourceTree = ""; }; - D0445DFC1A7C2D7300267924 /* SCompositeDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCompositeDisposable.h; sourceTree = ""; }; - D0445DFD1A7C2D7300267924 /* SCompositeDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCompositeDisposable.m; sourceTree = ""; }; D0445DFE1A7C2D7300267924 /* SDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposable.h; sourceTree = ""; }; D0445DFF1A7C2D7300267924 /* SEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SEvent.h; sourceTree = ""; }; D0445E001A7C2D7300267924 /* SEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SEvent.m; sourceTree = ""; }; @@ -161,6 +159,8 @@ D0445E531A7C2E9D00267924 /* STimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STimer.m; sourceTree = ""; }; D0445E561A7C3FB400267924 /* SBlockDisposableTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBlockDisposableTest.m; sourceTree = ""; }; D0445E5C1A7C446000267924 /* libSSignalKitStatic.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSSignalKitStatic.a; sourceTree = BUILT_PRODUCTS_DIR; }; + D08763281A839EDC00632240 /* SDisposableSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposableSet.h; sourceTree = ""; }; + D08763291A839EDC00632240 /* SDisposableSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDisposableSet.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -211,19 +211,19 @@ D0445DDA1A7C2CA500267924 /* SSignalKit */ = { isa = PBXGroup; children = ( - D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */, - D0445DF61A7C2D7300267924 /* SBlockDisposable.m */, D0445DF71A7C2D7300267924 /* SAtomic.h */, D0445DF81A7C2D7300267924 /* SAtomic.m */, D0445DF91A7C2D7300267924 /* SBag.h */, D0445DFA1A7C2D7300267924 /* SBag.m */, - D0445DFC1A7C2D7300267924 /* SCompositeDisposable.h */, - D0445DFD1A7C2D7300267924 /* SCompositeDisposable.m */, - D0445DFE1A7C2D7300267924 /* SDisposable.h */, D0445DFF1A7C2D7300267924 /* SEvent.h */, D0445E001A7C2D7300267924 /* SEvent.m */, + D0445DFE1A7C2D7300267924 /* SDisposable.h */, + D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */, + D0445DF61A7C2D7300267924 /* SBlockDisposable.m */, D0445E501A7C2DBF00267924 /* SMetaDisposable.h */, D0445E011A7C2D7300267924 /* SMetaDisposable.m */, + D08763281A839EDC00632240 /* SDisposableSet.h */, + D08763291A839EDC00632240 /* SDisposableSet.m */, D0445E021A7C2D7300267924 /* SMulticastSignalManager.h */, D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */, D0445E041A7C2D7300267924 /* SSignal.h */, @@ -309,7 +309,6 @@ D0445E421A7C2D7300267924 /* SSignal+SideEffects.h in Headers */, D0445E3E1A7C2D7300267924 /* SSignal+Meta.h in Headers */, D0445E2B1A7C2D7300267924 /* SEvent.h in Headers */, - D0445E281A7C2D7300267924 /* SCompositeDisposable.h in Headers */, D0445E341A7C2D7300267924 /* SSignal+Catch.h in Headers */, D0445E4E1A7C2D8A00267924 /* SQueue.h in Headers */, D0445E441A7C2D7300267924 /* SSignal+Single.h in Headers */, @@ -318,6 +317,7 @@ D0445E401A7C2D7300267924 /* SSignal+Multicast.h in Headers */, D0445E511A7C2DBF00267924 /* SMetaDisposable.h in Headers */, D0445E231A7C2D7300267924 /* SAtomic.h in Headers */, + D087632A1A839EDC00632240 /* SDisposableSet.h in Headers */, D0445E461A7C2D7300267924 /* SSignal+Timing.h in Headers */, D0445E381A7C2D7300267924 /* SSignal+Concat.h in Headers */, D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */, @@ -456,8 +456,8 @@ D0445E261A7C2D7300267924 /* SBag.m in Sources */, D0445E331A7C2D7300267924 /* SSignal+Accumulate.m in Sources */, D0445E471A7C2D7300267924 /* SSignal+Timing.m in Sources */, - D0445E291A7C2D7300267924 /* SCompositeDisposable.m in Sources */, D0445E311A7C2D7300267924 /* SSignal.m in Sources */, + D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */, D0445E491A7C2D7300267924 /* SSubscriber.m in Sources */, D0445E391A7C2D7300267924 /* SSignal+Concat.m in Sources */, D0445E431A7C2D7300267924 /* SSignal+SideEffects.m in Sources */, @@ -495,8 +495,8 @@ D0445E751A7C447D00267924 /* SBag.m in Sources */, D0445E7B1A7C447D00267924 /* SSignal+Accumulate.m in Sources */, D0445E851A7C447D00267924 /* SSignal+Timing.m in Sources */, - D0445E761A7C447D00267924 /* SCompositeDisposable.m in Sources */, D0445E7A1A7C447D00267924 /* SSignal.m in Sources */, + D087632C1A839EE800632240 /* SDisposableSet.m in Sources */, D0445E861A7C447D00267924 /* SSubscriber.m in Sources */, D0445E7E1A7C447D00267924 /* SSignal+Concat.m in Sources */, D0445E831A7C447D00267924 /* SSignal+SideEffects.m in Sources */, @@ -705,6 +705,7 @@ D0445DF01A7C2CA500267924 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; D0445DF11A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKitTests" */ = { isa = XCConfigurationList; @@ -713,6 +714,7 @@ D0445DF31A7C2CA500267924 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; D0445E6D1A7C446000267924 /* Build configuration list for PBXNativeTarget "SSignalKitStatic" */ = { isa = XCConfigurationList; @@ -721,6 +723,7 @@ D0445E6F1A7C446000267924 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/SSignalKit/SBlockDisposable.m b/SSignalKit/SBlockDisposable.m index 2bd19a5afc..b8d1f989d4 100644 --- a/SSignalKit/SBlockDisposable.m +++ b/SSignalKit/SBlockDisposable.m @@ -1,7 +1,6 @@ #import "SBlockDisposable.h" #import -#import #import @interface SBlockDisposable () diff --git a/SSignalKit/SCompositeDisposable.m b/SSignalKit/SCompositeDisposable.m deleted file mode 100644 index 80f5a70737..0000000000 --- a/SSignalKit/SCompositeDisposable.m +++ /dev/null @@ -1,60 +0,0 @@ -#import "SCompositeDisposable.h" - -#import -#import - -@interface SCompositeDisposable () -{ - //volatile OSSpinLock _lock; - pthread_mutex_t _mutex; - NSMutableArray *_disposables; -} - -@end - -@implementation SCompositeDisposable - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - pthread_mutex_init(&_mutex, NULL); - } - return self; -} - -- (void)add:(id)disposable -{ - if (disposable != nil) - { - //OSSpinLockLock(&_lock); - pthread_mutex_lock(&_mutex); - if (_disposables == nil) - _disposables = [[NSMutableArray alloc] init]; - [_disposables addObject:disposable]; - //OSSpinLockUnlock(&_lock); - pthread_mutex_unlock(&_mutex); - } -} - -- (void)dispose -{ - NSArray *disposables = nil; - //OSSpinLockLock(&_lock); - pthread_mutex_lock(&_mutex); - disposables = _disposables; - _disposables = nil; - //OSSpinLockUnlock(&_lock); - pthread_mutex_unlock(&_mutex); - - if (disposables != nil) - { - for (id disposable in disposables) - { - [disposable dispose]; - } - } -} - -@end diff --git a/SSignalKit/SCompositeDisposable.h b/SSignalKit/SDisposableSet.h similarity index 56% rename from SSignalKit/SCompositeDisposable.h rename to SSignalKit/SDisposableSet.h index f0a2b25a9d..37924832e6 100644 --- a/SSignalKit/SCompositeDisposable.h +++ b/SSignalKit/SDisposableSet.h @@ -1,6 +1,6 @@ #import "SDisposable.h" -@interface SCompositeDisposable : NSObject +@interface SDisposableSet : NSObject - (void)add:(id)disposable; diff --git a/SSignalKit/SDisposableSet.m b/SSignalKit/SDisposableSet.m new file mode 100644 index 0000000000..caabf076ea --- /dev/null +++ b/SSignalKit/SDisposableSet.m @@ -0,0 +1,64 @@ +#import "SDisposableSet.h" + +#import + +@interface SDisposableSet () +{ + OSSpinLock _lock; + id _singleDisposable; + NSArray *_multipleDisposables; +} + +@end + +@implementation SDisposableSet + +- (void)add:(id)disposable +{ + if (disposable == nil) + return; + + OSSpinLockLock(&_lock); + if (_multipleDisposables != nil) + { + NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithArray:_multipleDisposables]; + [multipleDisposables addObject:disposable]; + _multipleDisposables = multipleDisposables; + } + else if (_singleDisposable != nil) + { + NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithObjects:_singleDisposable, disposable, nil]; + _multipleDisposables = multipleDisposables; + _singleDisposable = nil; + } + else + { + _singleDisposable = disposable; + } + OSSpinLockUnlock(&_lock); +} + +- (void)dispose +{ + id singleDisposable = nil; + NSArray *multipleDisposables = nil; + + OSSpinLockLock(&_lock); + singleDisposable = _singleDisposable; + multipleDisposables = _multipleDisposables; + _singleDisposable = nil; + _multipleDisposables = nil; + OSSpinLockUnlock(&_lock); + + if (singleDisposable != nil) + [singleDisposable dispose]; + if (multipleDisposables != nil) + { + for (id disposable in multipleDisposables) + { + [disposable dispose]; + } + } +} + +@end diff --git a/SSignalKit/SMetaDisposable.m b/SSignalKit/SMetaDisposable.m index e989effe96..4e461eed3f 100644 --- a/SSignalKit/SMetaDisposable.m +++ b/SSignalKit/SMetaDisposable.m @@ -1,51 +1,57 @@ #import "SMetaDisposable.h" #import -#import @interface SMetaDisposable () { - //volatile OSSpinLock _lock; - pthread_mutex_t _mutex; - id _disposable; + void *_disposable; } @end @implementation SMetaDisposable -- (instancetype)init +- (void)dealloc { - self = [super init]; - if (self != nil) + while (true) { - pthread_mutex_init(&_mutex, NULL); + void *previousDisposable = _disposable; + if (OSAtomicCompareAndSwapPtr(previousDisposable, NULL, &_disposable)) + { + if (previousDisposable != NULL) + { + __strong id strongPreviousDisposable = (__bridge_transfer id)previousDisposable; + strongPreviousDisposable = nil; + } + + break; + } } - return self; } - (void)setDisposable:(id)disposable { - id currentDisposable = nil; - //OSSpinLockLock(&_lock); - pthread_mutex_lock(&_mutex); - currentDisposable = _disposable; - _disposable = disposable; - //OSSpinLockUnlock(&lock); - pthread_mutex_unlock(&_mutex); - - [currentDisposable dispose]; + void *newDisposable = (__bridge_retained void *)disposable; + while (true) + { + void *previousDisposable = _disposable; + if (OSAtomicCompareAndSwapPtr(previousDisposable, newDisposable, &_disposable)) + { + if (previousDisposable != NULL) + { + __strong id strongPreviousDisposable = (__bridge_transfer id)previousDisposable; + [strongPreviousDisposable dispose]; + strongPreviousDisposable = nil; + } + + break; + } + } } - (void)dispose { - id disposable = nil; - pthread_mutex_lock(&_mutex); - disposable = _disposable; - _disposable = nil; - pthread_mutex_unlock(&_mutex); - - [disposable dispose]; + [self setDisposable:nil]; } @end diff --git a/SSignalKit/SSignal+Concat.m b/SSignalKit/SSignal+Concat.m index 19bfc4da70..8d76e5159d 100644 --- a/SSignalKit/SSignal+Concat.m +++ b/SSignalKit/SSignal+Concat.m @@ -1,7 +1,6 @@ #import "SSignal+Concat.h" #import "SAtomic.h" -#import "SCompositeDisposable.h" @implementation SSignal (Concat) diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h index b4e9d19dcf..8ff93bc31c 100644 --- a/SSignalKit/SSignalKit.h +++ b/SSignalKit/SSignalKit.h @@ -22,7 +22,7 @@ FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; #import #import #import -#import +#import #import #import #import @@ -37,4 +37,4 @@ FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; #import #import #import -#import \ No newline at end of file +#import diff --git a/SSignalKit/SSubscriber.h b/SSignalKit/SSubscriber.h index 34c2d974a2..26a7dce6a9 100644 --- a/SSignalKit/SSubscriber.h +++ b/SSignalKit/SSubscriber.h @@ -1,5 +1,4 @@ -#import "SCompositeDisposable.h" - +#import "SDisposable.h" #import "SEvent.h" @interface SSubscriber : NSObject diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index 3256a3ca60..c7dd424c78 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -4,6 +4,7 @@ #import #import "SEvent.h" +#import "SDisposableSet.h" #define lockSelf(x) pthread_mutex_lock(&x->_mutex) #define unlockSelf(x) pthread_mutex_unlock(&x->_mutex) @@ -17,7 +18,7 @@ void (^_error)(id); void (^_completed)(); - SCompositeDisposable *_disposable; + SDisposableSet *_disposable; } @end @@ -30,7 +31,7 @@ if (self != nil) { pthread_mutex_init(&_mutex, NULL); - _disposable = [[SCompositeDisposable alloc] init]; + _disposable = [[SDisposableSet alloc] init]; _next = [next copy]; _error = [error copy]; _completed = [completed copy]; diff --git a/SSignalKitTests/SBlockDisposableTest.m b/SSignalKitTests/SBlockDisposableTest.m index eed55751ed..c6c0982bc9 100644 --- a/SSignalKitTests/SBlockDisposableTest.m +++ b/SSignalKitTests/SBlockDisposableTest.m @@ -50,10 +50,12 @@ - (void)testBlockDisposableDisposed { bool deallocated = false; + __block bool disposed = false; { TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; dispatch_block_t block = ^{ [object description]; + disposed = true; }; SBlockDisposable *disposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; object = nil; @@ -62,23 +64,205 @@ } XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); } - (void)testBlockDisposableNotDisposed { bool deallocated = false; + __block bool disposed = false; { TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; dispatch_block_t block = ^{ [object description]; + disposed = true; }; SBlockDisposable *disposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; - object = nil; - block = nil; - disposable = nil; + [disposable description]; } XCTAssertTrue(deallocated); + XCTAssertFalse(disposed); +} + +- (void)testMetaDisposableDisposed +{ + bool deallocated = false; + __block bool disposed = false; + { + TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + dispatch_block_t block = ^{ + [object description]; + disposed = true; + }; + SBlockDisposable *blockDisposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; + + SMetaDisposable *metaDisposable = [[SMetaDisposable alloc] init]; + [metaDisposable setDisposable:blockDisposable]; + [metaDisposable dispose]; + } + + XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); +} + +- (void)testMetaDisposableDisposedMultipleTimes +{ + bool deallocated1 = false; + __block bool disposed1 = false; + bool deallocated2 = false; + __block bool disposed2 = false; + { + TestObject *object1 = [[TestObject alloc] initWithDeallocated:&deallocated1]; + dispatch_block_t block1 = ^{ + [object1 description]; + disposed1 = true; + }; + SBlockDisposable *blockDisposable1 = [[SBlockDisposable alloc] initWithBlock:[block1 copy]]; + + TestObject *object2 = [[TestObject alloc] initWithDeallocated:&deallocated2]; + dispatch_block_t block2 = ^{ + [object2 description]; + disposed2 = true; + }; + SBlockDisposable *blockDisposable2 = [[SBlockDisposable alloc] initWithBlock:[block2 copy]]; + + SMetaDisposable *metaDisposable = [[SMetaDisposable alloc] init]; + [metaDisposable setDisposable:blockDisposable1]; + [metaDisposable setDisposable:blockDisposable2]; + [metaDisposable dispose]; + } + + XCTAssertTrue(deallocated1); + XCTAssertTrue(disposed1); + XCTAssertTrue(deallocated2); + XCTAssertTrue(disposed2); +} + +- (void)testMetaDisposableNotDisposed +{ + bool deallocated = false; + __block bool disposed = false; + { + TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + dispatch_block_t block = ^{ + [object description]; + disposed = true; + }; + SBlockDisposable *blockDisposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; + + SMetaDisposable *metaDisposable = [[SMetaDisposable alloc] init]; + [metaDisposable setDisposable:blockDisposable]; + } + + XCTAssertTrue(deallocated); + XCTAssertFalse(disposed); +} + +- (void)testDisposableSetSingleDisposed +{ + bool deallocated = false; + __block bool disposed = false; + { + TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + dispatch_block_t block = ^{ + [object description]; + disposed = true; + }; + SBlockDisposable *blockDisposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; + + SDisposableSet *disposableSet = [[SDisposableSet alloc] init]; + [disposableSet add:blockDisposable]; + [disposableSet dispose]; + } + + XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); +} + +- (void)testDisposableSetMultipleDisposed +{ + bool deallocated1 = false; + __block bool disposed1 = false; + bool deallocated2 = false; + __block bool disposed2 = false; + { + TestObject *object1 = [[TestObject alloc] initWithDeallocated:&deallocated1]; + dispatch_block_t block1 = ^{ + [object1 description]; + disposed1 = true; + }; + SBlockDisposable *blockDisposable1 = [[SBlockDisposable alloc] initWithBlock:[block1 copy]]; + + TestObject *object2 = [[TestObject alloc] initWithDeallocated:&deallocated2]; + dispatch_block_t block2 = ^{ + [object2 description]; + disposed2 = true; + }; + SBlockDisposable *blockDisposable2 = [[SBlockDisposable alloc] initWithBlock:[block2 copy]]; + + SDisposableSet *disposableSet = [[SDisposableSet alloc] init]; + [disposableSet add:blockDisposable1]; + [disposableSet add:blockDisposable2]; + [disposableSet dispose]; + } + + XCTAssertTrue(deallocated1); + XCTAssertTrue(disposed1); + XCTAssertTrue(deallocated2); + XCTAssertTrue(disposed2); +} + +- (void)testDisposableSetSingleNotDisposed +{ + bool deallocated = false; + __block bool disposed = false; + { + TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + dispatch_block_t block = ^{ + [object description]; + disposed = true; + }; + SBlockDisposable *blockDisposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; + + SDisposableSet *disposableSet = [[SDisposableSet alloc] init]; + [disposableSet add:blockDisposable]; + } + + XCTAssertTrue(deallocated); + XCTAssertFalse(disposed); +} + +- (void)testDisposableSetMultipleNotDisposed +{ + bool deallocated1 = false; + __block bool disposed1 = false; + bool deallocated2 = false; + __block bool disposed2 = false; + { + TestObject *object1 = [[TestObject alloc] initWithDeallocated:&deallocated1]; + dispatch_block_t block1 = ^{ + [object1 description]; + disposed1 = true; + }; + SBlockDisposable *blockDisposable1 = [[SBlockDisposable alloc] initWithBlock:[block1 copy]]; + + TestObject *object2 = [[TestObject alloc] initWithDeallocated:&deallocated2]; + dispatch_block_t block2 = ^{ + [object2 description]; + disposed2 = true; + }; + SBlockDisposable *blockDisposable2 = [[SBlockDisposable alloc] initWithBlock:[block2 copy]]; + + SDisposableSet *disposableSet = [[SDisposableSet alloc] init]; + [disposableSet add:blockDisposable1]; + [disposableSet add:blockDisposable2]; + } + + XCTAssertTrue(deallocated1); + XCTAssertFalse(disposed1); + XCTAssertTrue(deallocated2); + XCTAssertFalse(disposed2); } @end From b14f28c089c46ca60a88071c02a06152e5a32007 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 5 Feb 2015 18:24:35 +0300 Subject: [PATCH 006/122] SQueue updates --- SSignalKit.xcodeproj/project.pbxproj | 1 + SSignalKit/SQueue.h | 4 ++ SSignalKit/SQueue.m | 61 +++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 95bf6088bd..9c587bcdf0 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -671,6 +671,7 @@ "DEBUG=1", "$(inherited)", ); + ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/SSignalKit/SQueue.h b/SSignalKit/SQueue.h index 3e7ad59974..85ac709ba6 100644 --- a/SSignalKit/SQueue.h +++ b/SSignalKit/SQueue.h @@ -2,6 +2,10 @@ @interface SQueue : NSObject ++ (SQueue *)mainQueue; ++ (SQueue *)concurrentDefaultQueue; ++ (SQueue *)concurrentBackgroundQueue; + - (void)dispatch:(dispatch_block_t)block; - (dispatch_queue_t)_dispatch_queue; diff --git a/SSignalKit/SQueue.m b/SSignalKit/SQueue.m index 0da661a5ec..80e24dd5b5 100644 --- a/SSignalKit/SQueue.m +++ b/SSignalKit/SQueue.m @@ -1,20 +1,69 @@ #import "SQueue.h" +static const void *SQueueSpecificKey = &SQueueSpecificKey; + @interface SQueue () { dispatch_queue_t _queue; + void *_queueSpecific; + bool _specialIsMainQueue; } @end @implementation SQueue ++ (SQueue *)mainQueue +{ + static SQueue *queue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^ + { + queue = [[SQueue alloc] initWithNativeQueue:dispatch_get_main_queue() queueSpecific:NULL]; + queue->_specialIsMainQueue = true; + }); + + return queue; +} + ++ (SQueue *)concurrentDefaultQueue +{ + static SQueue *queue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^ + { + queue = [[SQueue alloc] initWithNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) queueSpecific:NULL]; + }); + + return queue; +} + ++ (SQueue *)concurrentBackgroundQueue +{ + static SQueue *queue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^ + { + queue = [[SQueue alloc] initWithNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) queueSpecific:NULL]; + }); + + return queue; +} + - (instancetype)init +{ + dispatch_queue_t queue = dispatch_queue_create(NULL, NULL); + dispatch_queue_set_specific(queue, SQueueSpecificKey, (__bridge void *)self, NULL); + return [self initWithNativeQueue:queue queueSpecific:(__bridge void *)self]; +} + +- (instancetype)initWithNativeQueue:(dispatch_queue_t)queue queueSpecific:(void *)queueSpecific { self = [super init]; if (self != nil) { - _queue = dispatch_queue_create(NULL, NULL); + _queue = queue; + _queueSpecific = queueSpecific; } return self; } @@ -29,4 +78,14 @@ dispatch_async(_queue, block); } +- (void)dispatchSync:(dispatch_block_t)block +{ + if (_queueSpecific != NULL && dispatch_get_specific(SQueueSpecificKey) == _queueSpecific) + block(); + else if (_specialIsMainQueue && [NSThread isMainThread]) + block(); + else + dispatch_sync(_queue, block); +} + @end From 6dd75181a65defa3ab5294194696be3c179d619a Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 6 Feb 2015 23:04:51 +0300 Subject: [PATCH 007/122] Refactoring --- SSignalKit/SSignal+Accumulate.m | 8 ++--- SSignalKit/SSignal+Catch.m | 11 +++--- SSignalKit/SSignal+Combine.m | 7 +++- SSignalKit/SSignal+Dispatch.m | 61 +++++++++++++++++++------------- SSignalKit/SSignal+Mapping.h | 1 + SSignalKit/SSignal+Mapping.m | 26 ++++++++++---- SSignalKit/SSignal+Meta.m | 31 ++++++++++------ SSignalKit/SSignal+Multicast.m | 21 +++++------ SSignalKit/SSignal+SideEffects.m | 27 ++++++++------ SSignalKit/SSignal+Single.m | 9 +++-- SSignalKit/SSignal+Timing.m | 11 ++++-- SSignalKit/SSignal.h | 10 ++---- SSignalKit/SSignal.m | 5 ++- SSignalKit/SSubscriber.h | 9 +++-- SSignalKit/SSubscriber.m | 16 ++------- 15 files changed, 148 insertions(+), 105 deletions(-) diff --git a/SSignalKit/SSignal+Accumulate.m b/SSignalKit/SSignal+Accumulate.m index 8410e4890c..ad2e253c4c 100644 --- a/SSignalKit/SSignal+Accumulate.m +++ b/SSignalKit/SSignal+Accumulate.m @@ -4,11 +4,11 @@ - (SSignal *)reduceLeft:(id)value with:(id (^)(id, id))f { - __block id intermediateResult = value; - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) { - id disposable = [self startWithNext:^(id next) + __block id intermediateResult = value; + + return [self startWithNext:^(id next) { intermediateResult = f(intermediateResult, next); } error:^(id error) @@ -20,8 +20,6 @@ SSubscriber_putNext(subscriber, intermediateResult); SSubscriber_putCompletion(subscriber); }]; - - [subscriber addDisposable:disposable]; }]; } diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m index ae0528d028..5acd47d882 100644 --- a/SSignalKit/SSignal+Catch.m +++ b/SSignalKit/SSignal+Catch.m @@ -1,24 +1,23 @@ #import "SSignal+Catch.h" #import "SMetaDisposable.h" +#import "SDisposableSet.h" @implementation SSignal (Catch) - (SSignal *)catch:(SSignal *(^)(id error))f { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; - [subscriber addDisposable:disposable]; - - [subscriber addDisposable:[self startWithNext:^(id next) + [disposable setDisposable:[self startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) { SSignal *signal = f(error); - [subscriber addDisposable:[signal startWithNext:^(id next) + [disposable setDisposable:[signal startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -32,6 +31,8 @@ { SSubscriber_putCompletion(subscriber); }]]; + + return disposable; }]; } diff --git a/SSignalKit/SSignal+Combine.m b/SSignalKit/SSignal+Combine.m index 5624aeb143..c908947fbb 100644 --- a/SSignalKit/SSignal+Combine.m +++ b/SSignalKit/SSignal+Combine.m @@ -1,6 +1,7 @@ #import "SSignal+Combine.h" #import "SAtomic.h" +#import "SDisposableSet.h" @interface SSignalCombineState : NSObject @@ -49,6 +50,8 @@ } SAtomic *combineState = [[SAtomic alloc] initWithValue:[[SSignalCombineState alloc] initWithLatestValues:initialLatestValues completedStatuses:completedStatuses error:false]]; + SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + NSUInteger index = 0; NSUInteger count = signals.count; for (SSignal *signal in signals) @@ -120,9 +123,11 @@ if (!wasCompleted && isCompleted) SSubscriber_putCompletion(subscriber); }]; - [subscriber addDisposable:disposable]; + [compositeDisposable add:disposable]; index++; } + + return compositeDisposable; }]; } diff --git a/SSignalKit/SSignal+Dispatch.m b/SSignalKit/SSignal+Dispatch.m index 1c9af779b1..707afce8da 100644 --- a/SSignalKit/SSignal+Dispatch.m +++ b/SSignalKit/SSignal+Dispatch.m @@ -1,14 +1,15 @@ #import "SSignal+Dispatch.h" #import "SAtomic.h" #import "SBlockDisposable.h" +#import "SMetaDisposable.h" @implementation SSignal (Dispatch) - (SSignal *)deliverOn:(SQueue *)queue { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - [subscriber addDisposable:[self startWithNext:^(id next) + return [self startWithNext:^(id next) { [queue dispatch:^ { @@ -26,16 +27,16 @@ { SSubscriber_putCompletion(subscriber); }]; - }]]; + }]; }]; } - (SSignal *)deliverOnThreadPool:(SThreadPool *)threadPool { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { SAtomic *atomicLastTask = [[SAtomic alloc] initWithValue:nil]; - [subscriber addDisposable:[self startWithNext:^(id next) + return [self startWithNext:^(id next) { SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) { @@ -68,42 +69,54 @@ if (lastTask != nil) [task addDependency:lastTask]; [threadPool startTask:task]; - }]]; + }]; }]; } - (SSignal *)startOn:(SQueue *)queue { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { + __block bool isCancelled = false; + SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; + [disposable setDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + isCancelled = true; + }]]; + [queue dispatch:^ { - id disposable = [self startWithNext:^(id next) + if (!isCancelled) { - SSubscriber_putNext(subscriber, next); - } error:^(id error) - { - SSubscriber_putError(subscriber, error); - } completed:^ - { - SSubscriber_putCompletion(subscriber); - }]; - - [subscriber addDisposable:disposable]; + [disposable setDisposable:[self startWithNext:^(id next) + { + SSubscriber_putNext(subscriber, next); + } error:^(id error) + { + SSubscriber_putError(subscriber, error); + } completed:^ + { + SSubscriber_putCompletion(subscriber); + }]]; + } }]; + + return disposable; }]; } - (SSignal *)startOnThreadPool:(SThreadPool *)threadPool { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { + SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; + id taskId = [threadPool addTask:^(bool (^cancelled)()) { if (cancelled && cancelled()) return; - [subscriber addDisposable:[self startWithNext:^(id next) + [disposable setDisposable:[self startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -115,12 +128,12 @@ }]]; }]; - __weak SThreadPool *weakThreadPool = threadPool; - [subscriber addDisposable:[[SBlockDisposable alloc] initWithBlock:^ + [disposable setDisposable:[[SBlockDisposable alloc] initWithBlock:^ { - __strong SThreadPool *strongThreadPool = weakThreadPool; - [strongThreadPool cancelTask:taskId]; + [threadPool cancelTask:taskId]; }]]; + + return disposable; }]; } diff --git a/SSignalKit/SSignal+Mapping.h b/SSignalKit/SSignal+Mapping.h index c6d516c1ef..751f72a1e0 100644 --- a/SSignalKit/SSignal+Mapping.h +++ b/SSignalKit/SSignal+Mapping.h @@ -3,6 +3,7 @@ @interface SSignal (Mapping) - (SSignal *)map:(id (^)(id))f; +- (SSignal *)_mapInplace:(id (^)(id))f; - (SSignal *)filter:(bool (^)(id))f; @end diff --git a/SSignalKit/SSignal+Mapping.m b/SSignalKit/SSignal+Mapping.m index db34d31772..da50570389 100644 --- a/SSignalKit/SSignal+Mapping.m +++ b/SSignalKit/SSignal+Mapping.m @@ -4,9 +4,9 @@ - (SSignal *)map:(id (^)(id))f { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - id disposable = [self startWithNext:^(id next) + return [self startWithNext:^(id next) { SSubscriber_putNext(subscriber, f(next)); } error:^(id error) @@ -16,15 +16,30 @@ { SSubscriber_putCompletion(subscriber); }]; - [subscriber addDisposable:disposable]; }]; } +- (SSignal *)_mapInplace:(id (^)(id))f +{ + id (^generator)(SSubscriber *) = self->_generator; + self->_generator = [^id (SSubscriber *subscriber) + { + SSubscriber *mappedSubscriber = [[SSubscriber alloc] initWithNext:^(id next) + { + subscriber->_next(f(next)); + } error:subscriber->_error completed:subscriber->_completed]; + + return generator(mappedSubscriber); + } copy]; + + return self; +} + - (SSignal *)filter:(bool (^)(id))f { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - id disposable = [self startWithNext:^(id next) + return [self startWithNext:^(id next) { if (f(next)) SSubscriber_putNext(subscriber, next); @@ -35,7 +50,6 @@ { SSubscriber_putCompletion(subscriber); }]; - [subscriber addDisposable:disposable]; }]; } diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index f811ea26d9..208d6e7017 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -1,5 +1,6 @@ #import "SSignal+Meta.h" +#import "SDisposableSet.h" #import "SMetaDisposable.h" #import "SSignal+Mapping.h" #import "SAtomic.h" @@ -8,15 +9,18 @@ - (SSignal *)switchToLatest { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { + SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + SMetaDisposable *currentDisposable = [[SMetaDisposable alloc] init]; + [compositeDisposable add:currentDisposable]; SAtomic *didProduceNext = [[SAtomic alloc] initWithValue:nil]; - id disposable = [self startWithNext:^(SSignal *next) + [compositeDisposable add:[self startWithNext:^(SSignal *next) { [didProduceNext swap:@1]; - id innerDisposable = [next startWithNext:^(id next) + [currentDisposable setDisposable:[next startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -25,19 +29,17 @@ } completed:^ { SSubscriber_putCompletion(subscriber); - }]; - [currentDisposable setDisposable:innerDisposable]; + }]]; } error:^(id error) { SSubscriber_putError(subscriber, error); } completed:^ { - if ([didProduceNext value] == nil) + if ([didProduceNext swap:@1] == NULL) SSubscriber_putCompletion(subscriber); - }]; + }]]; - [subscriber addDisposable:currentDisposable]; - [subscriber addDisposable:disposable]; + return compositeDisposable; }]; } @@ -48,9 +50,14 @@ - (SSignal *)then:(SSignal *)signal { + SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + + SMetaDisposable *currentDisposable = [[SMetaDisposable alloc] init]; + [compositeDisposable add:currentDisposable]; + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) { - [subscriber addDisposable:[self startWithNext:^(id next) + [currentDisposable setDisposable:[self startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -58,7 +65,7 @@ SSubscriber_putError(subscriber, error); } completed:^ { - [subscriber addDisposable:[signal startWithNext:^(id next) + [compositeDisposable add:[signal startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -69,6 +76,8 @@ SSubscriber_putCompletion(subscriber); }]]; }]]; + + return compositeDisposable; }]; } diff --git a/SSignalKit/SSignal+Multicast.m b/SSignalKit/SSignal+Multicast.m index e3bb9d04cd..7b2ee7f79a 100644 --- a/SSignalKit/SSignal+Multicast.m +++ b/SSignalKit/SSignal+Multicast.m @@ -38,15 +38,13 @@ typedef enum { _disposable = disposable; } -- (bool)addSubscriber:(SSubscriber *)subscriber +- (id)addSubscriber:(SSubscriber *)subscriber start:(bool *)start { - bool start = false; - OSSpinLockLock(&_lock); NSInteger index = [_subscribers addItem:subscriber]; switch (_state) { case SSignalMulticastStateReady: - start = true; + *start = true; _state = SSignalMulticastStateStarted; break; default: @@ -54,12 +52,10 @@ typedef enum { } OSSpinLockUnlock(&_lock); - [subscriber addDisposable:[[SBlockDisposable alloc] initWithBlock:^ + return [[SBlockDisposable alloc] initWithBlock:^ { [self remove:index]; - }]]; - - return start; + }]; } - (void)remove:(NSInteger)index @@ -106,9 +102,11 @@ typedef enum { - (SSignal *)multicast { SSignalMulticastSubscribers *subscribers = [[SSignalMulticastSubscribers alloc] init]; - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - if ([subscribers addSubscriber:subscriber]) + bool start = false; + id currentDisposable = [subscribers addSubscriber:subscriber start:&start]; + if (start) { id disposable = [self startWithNext:^(id next) { @@ -120,11 +118,14 @@ typedef enum { { [subscribers notify:[[SEvent alloc] initWithCompleted]]; }]; + [subscribers setDisposable:[[SBlockDisposable alloc] initWithBlock:^ { [disposable dispose]; }]]; } + + return currentDisposable; }]; } diff --git a/SSignalKit/SSignal+SideEffects.m b/SSignalKit/SSignal+SideEffects.m index 42234b5403..332d7553df 100644 --- a/SSignalKit/SSignal+SideEffects.m +++ b/SSignalKit/SSignal+SideEffects.m @@ -1,14 +1,15 @@ #import "SSignal+SideEffects.h" #import "SBlockDisposable.h" +#import "SDisposableSet.h" @implementation SSignal (SideEffects) - (SSignal *)onNext:(void (^)(id next))f { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - [subscriber addDisposable:[self startWithNext:^(id next) + return [self startWithNext:^(id next) { f(next); SSubscriber_putNext(subscriber, next); @@ -18,15 +19,15 @@ } completed:^ { SSubscriber_putCompletion(subscriber); - }]]; + }]; }]; } - (SSignal *)onError:(void (^)(id error))f { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - [subscriber addDisposable:[self startWithNext:^(id next) + return [self startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -36,15 +37,15 @@ } completed:^ { SSubscriber_putCompletion(subscriber); - }]]; + }]; }]; } - (SSignal *)onCompletion:(void (^)())f { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - [subscriber addDisposable:[self startWithNext:^(id next) + return [self startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -54,7 +55,7 @@ { f(); SSubscriber_putCompletion(subscriber); - }]]; + }]; }]; } @@ -62,7 +63,9 @@ { return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) { - [subscriber addDisposable:[self startWithNext:^(id next) + SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + + [compositeDisposable add:[self startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -73,10 +76,12 @@ SSubscriber_putCompletion(subscriber); }]]; - [subscriber addDisposable:[[SBlockDisposable alloc] initWithBlock:^ + [compositeDisposable add:[[SBlockDisposable alloc] initWithBlock:^ { f(); }]]; + + return compositeDisposable; }]; } diff --git a/SSignalKit/SSignal+Single.m b/SSignalKit/SSignal+Single.m index 18bbf4c332..2ffd6b12e9 100644 --- a/SSignalKit/SSignal+Single.m +++ b/SSignalKit/SSignal+Single.m @@ -39,24 +39,27 @@ + (SSignal *)fail:(id)error { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { SSubscriber_putError(subscriber, error); + return nil; }]; } + (SSignal *)never { - return [[SSignal alloc] initWithGenerator:^(__unused SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (__unused SSubscriber *subscriber) { + return nil; }]; } + (SSignal *)complete { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { SSubscriber_putCompletion(subscriber); + return nil; }]; } diff --git a/SSignalKit/SSignal+Timing.m b/SSignalKit/SSignal+Timing.m index 858150f81b..4a5b6c82a8 100644 --- a/SSignalKit/SSignal+Timing.m +++ b/SSignalKit/SSignal+Timing.m @@ -1,5 +1,6 @@ #import "SSignal+Timing.h" +#import "SMetaDisposable.h" #import "SBlockDisposable.h" #import "STimer.h" @@ -8,11 +9,13 @@ - (SSignal *)delay:(NSTimeInterval)seconds onQueue:(SQueue *)queue { - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { + SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; + STimer *timer = [[STimer alloc] initWithTimeout:seconds repeat:false completion:^ { - [subscriber addDisposable:[self startWithNext:^(id next) + [disposable setDisposable:[self startWithNext:^(id next) { SSubscriber_putNext(subscriber, next); } error:^(id error) @@ -24,12 +27,14 @@ }]]; } queue:queue]; - [subscriber addDisposable:[[SBlockDisposable alloc] initWithBlock:^ + [disposable setDisposable:[[SBlockDisposable alloc] initWithBlock:^ { [timer invalidate]; }]]; [timer start]; + + return disposable; }]; } diff --git a/SSignalKit/SSignal.h b/SSignalKit/SSignal.h index ee48ff62bc..1af078500c 100644 --- a/SSignalKit/SSignal.h +++ b/SSignalKit/SSignal.h @@ -3,17 +3,11 @@ @interface SSignal : NSObject { @public - void (^_generator)(SSubscriber *); + id (^_generator)(SSubscriber *); } -- (instancetype)initWithGenerator:(void (^)(SSubscriber *))generator; +- (instancetype)initWithGenerator:(id (^)(SSubscriber *))generator; - (id)startWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; @end -inline id SSignal_start(SSignal *signal, void (^next)(id), void (^error)(id), void (^completed)()) -{ - SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:error completed:completed]; - signal->_generator(subscriber); - return [subscriber _disposable]; -} diff --git a/SSignalKit/SSignal.m b/SSignalKit/SSignal.m index 741b6cbb64..3bfa06cb0c 100644 --- a/SSignalKit/SSignal.m +++ b/SSignalKit/SSignal.m @@ -8,7 +8,7 @@ @implementation SSignal -- (instancetype)initWithGenerator:(void (^)(SSubscriber *))generator +- (instancetype)initWithGenerator:(id (^)(SSubscriber *))generator { self = [super init]; if (self != nil) @@ -21,8 +21,7 @@ - (id)startWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed { SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:error completed:completed]; - _generator(subscriber); - return [subscriber _disposable]; + return _generator(subscriber); } @end diff --git a/SSignalKit/SSubscriber.h b/SSignalKit/SSubscriber.h index 26a7dce6a9..a6450c9404 100644 --- a/SSignalKit/SSubscriber.h +++ b/SSignalKit/SSubscriber.h @@ -2,11 +2,16 @@ #import "SEvent.h" @interface SSubscriber : NSObject +{ + @public + void (^_next)(id); + void (^_error)(id); + void (^_completed)(); +} - (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; -- (id)_disposable; -- (void)addDisposable:(id)disposable; +- (void)_assignDisposable:(id)disposable; - (void)putEvent:(SEvent *)event; - (void)putNext:(id)next; diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index c7dd424c78..377349aa7a 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -4,7 +4,6 @@ #import #import "SEvent.h" -#import "SDisposableSet.h" #define lockSelf(x) pthread_mutex_lock(&x->_mutex) #define unlockSelf(x) pthread_mutex_unlock(&x->_mutex) @@ -14,11 +13,8 @@ @public //volatile OSSpinLock _lock; pthread_mutex_t _mutex; - void (^_next)(id); - void (^_error)(id); - void (^_completed)(); - SDisposableSet *_disposable; + id _disposable; } @end @@ -31,7 +27,6 @@ if (self != nil) { pthread_mutex_init(&_mutex, NULL); - _disposable = [[SDisposableSet alloc] init]; _next = [next copy]; _error = [error copy]; _completed = [completed copy]; @@ -39,14 +34,9 @@ return self; } -- (id)_disposable +- (void)_assignDisposable:(id)disposable { - return _disposable; -} - -- (void)addDisposable:(id)disposable -{ - [_disposable add:disposable]; + _disposable = disposable; } - (void)putEvent:(SEvent *)event From 1dee9081677c48d6d12c488a2c22b859a3452b26 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 9 Feb 2015 16:34:05 +0300 Subject: [PATCH 008/122] Refactoring --- SSignalKit.xcodeproj/project.pbxproj | 26 ++- SSignalKit/SSignal+Accumulate.m | 6 +- SSignalKit/SSignal+Catch.m | 11 +- SSignalKit/SSignal+Combine.m | 6 +- SSignalKit/SSignal+Dispatch.m | 24 +- SSignalKit/SSignal+Mapping.m | 21 +- SSignalKit/SSignal+Meta.m | 20 +- SSignalKit/SSignal+Multicast.m | 2 +- SSignalKit/SSignal+SideEffects.m | 24 +- SSignalKit/SSignal+Single.m | 40 +--- SSignalKit/SSignal+Timing.m | 6 +- SSignalKit/SSignal.h | 5 +- SSignalKit/SSignal.m | 22 +- SSignalKit/SSubscriber.h | 15 +- SSignalKit/SSubscriber.m | 150 ++++++------- SSignalKitTests/DeallocatingObject.h | 7 + SSignalKitTests/DeallocatingObject.m | 27 +++ ...ockDisposableTest.m => SDisposableTests.m} | 56 ++--- SSignalKitTests/SSignalBasicTests.m | 208 ++++++++++++++++++ SSignalKitTests/SSignalKitTests.m | 40 ---- SSignalKitTests/SSignalPerformanceTests.m | 125 +++++++++++ 21 files changed, 560 insertions(+), 281 deletions(-) create mode 100644 SSignalKitTests/DeallocatingObject.h create mode 100644 SSignalKitTests/DeallocatingObject.m rename SSignalKitTests/{SBlockDisposableTest.m => SDisposableTests.m} (81%) create mode 100644 SSignalKitTests/SSignalBasicTests.m delete mode 100644 SSignalKitTests/SSignalKitTests.m create mode 100644 SSignalKitTests/SSignalPerformanceTests.m diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 9c587bcdf0..3315b248d5 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DDD1A7C2CA500267924 /* SSignalKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445DE41A7C2CA500267924 /* SSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0445DD81A7C2CA500267924 /* SSignalKit.framework */; }; - D0445DEB1A7C2CA500267924 /* SSignalKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */; }; D0445E221A7C2D7300267924 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF61A7C2D7300267924 /* SBlockDisposable.m */; }; D0445E231A7C2D7300267924 /* SAtomic.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DF71A7C2D7300267924 /* SAtomic.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445E241A7C2D7300267924 /* SAtomic.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF81A7C2D7300267924 /* SAtomic.m */; }; @@ -55,7 +54,7 @@ D0445E511A7C2DBF00267924 /* SMetaDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E501A7C2DBF00267924 /* SMetaDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445E541A7C2E9D00267924 /* STimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E521A7C2E9D00267924 /* STimer.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445E551A7C2E9D00267924 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E531A7C2E9D00267924 /* STimer.m */; }; - D0445E571A7C3FB400267924 /* SBlockDisposableTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E561A7C3FB400267924 /* SBlockDisposableTest.m */; }; + D0445E571A7C3FB400267924 /* SDisposableTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E561A7C3FB400267924 /* SDisposableTests.m */; }; D0445E731A7C447D00267924 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF61A7C2D7300267924 /* SBlockDisposable.m */; }; D0445E741A7C447D00267924 /* SAtomic.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF81A7C2D7300267924 /* SAtomic.m */; }; D0445E751A7C447D00267924 /* SBag.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFA1A7C2D7300267924 /* SBag.m */; }; @@ -78,6 +77,9 @@ D0445E871A7C447D00267924 /* SThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1F1A7C2D7300267924 /* SThreadPool.m */; }; D0445E881A7C447D00267924 /* SQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E4D1A7C2D8A00267924 /* SQueue.m */; }; D0445E891A7C447D00267924 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E531A7C2E9D00267924 /* STimer.m */; }; + 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 */; }; D087632A1A839EDC00632240 /* SDisposableSet.h in Headers */ = {isa = PBXBuildFile; fileRef = D08763281A839EDC00632240 /* SDisposableSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D08763291A839EDC00632240 /* SDisposableSet.m */; }; D087632C1A839EE800632240 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D08763291A839EDC00632240 /* SDisposableSet.m */; }; @@ -111,7 +113,6 @@ D0445DDD1A7C2CA500267924 /* SSignalKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSignalKit.h; 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 = ""; }; - D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SSignalKitTests.m; sourceTree = ""; }; D0445DF61A7C2D7300267924 /* SBlockDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBlockDisposable.m; sourceTree = ""; }; D0445DF71A7C2D7300267924 /* SAtomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAtomic.h; sourceTree = ""; }; D0445DF81A7C2D7300267924 /* SAtomic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAtomic.m; sourceTree = ""; }; @@ -157,8 +158,12 @@ D0445E501A7C2DBF00267924 /* SMetaDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMetaDisposable.h; sourceTree = ""; }; D0445E521A7C2E9D00267924 /* STimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STimer.h; sourceTree = ""; }; D0445E531A7C2E9D00267924 /* STimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STimer.m; sourceTree = ""; }; - D0445E561A7C3FB400267924 /* SBlockDisposableTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBlockDisposableTest.m; sourceTree = ""; }; + D0445E561A7C3FB400267924 /* SDisposableTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDisposableTests.m; sourceTree = ""; }; D0445E5C1A7C446000267924 /* libSSignalKitStatic.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSSignalKitStatic.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 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 = ""; }; + D06F10721A85882000485185 /* SSignalPerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignalPerformanceTests.m; sourceTree = ""; }; D08763281A839EDC00632240 /* SDisposableSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposableSet.h; sourceTree = ""; }; D08763291A839EDC00632240 /* SDisposableSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDisposableSet.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -275,9 +280,12 @@ D0445DE71A7C2CA500267924 /* SSignalKitTests */ = { isa = PBXGroup; children = ( - D0445DEA1A7C2CA500267924 /* SSignalKitTests.m */, + D06F106F1A855E2D00485185 /* DeallocatingObject.h */, + D06F10701A855E2D00485185 /* DeallocatingObject.m */, D0445DE81A7C2CA500267924 /* Supporting Files */, - D0445E561A7C3FB400267924 /* SBlockDisposableTest.m */, + D0445E561A7C3FB400267924 /* SDisposableTests.m */, + D06F106B1A85561E00485185 /* SSignalBasicTests.m */, + D06F10721A85882000485185 /* SSignalPerformanceTests.m */, ); path = SSignalKitTests; sourceTree = ""; @@ -472,8 +480,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D0445DEB1A7C2CA500267924 /* SSignalKitTests.m in Sources */, - D0445E571A7C3FB400267924 /* SBlockDisposableTest.m in Sources */, + D06F106C1A85561E00485185 /* SSignalBasicTests.m in Sources */, + D06F10711A855E2D00485185 /* DeallocatingObject.m in Sources */, + D06F10731A85882000485185 /* SSignalPerformanceTests.m in Sources */, + D0445E571A7C3FB400267924 /* SDisposableTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SSignalKit/SSignal+Accumulate.m b/SSignalKit/SSignal+Accumulate.m index ad2e253c4c..e19eda98aa 100644 --- a/SSignalKit/SSignal+Accumulate.m +++ b/SSignalKit/SSignal+Accumulate.m @@ -13,12 +13,12 @@ intermediateResult = f(intermediateResult, next); } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { if (intermediateResult != nil) - SSubscriber_putNext(subscriber, intermediateResult); - SSubscriber_putCompletion(subscriber); + [subscriber putNext:intermediateResult]; + [subscriber putCompletion]; }]; }]; } diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m index 5acd47d882..6a43a0cac8 100644 --- a/SSignalKit/SSignal+Catch.m +++ b/SSignalKit/SSignal+Catch.m @@ -2,6 +2,7 @@ #import "SMetaDisposable.h" #import "SDisposableSet.h" +#import "SAtomic.h" @implementation SSignal (Catch) @@ -13,23 +14,23 @@ [disposable setDisposable:[self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { SSignal *signal = f(error); [disposable setDisposable:[signal startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; return disposable; diff --git a/SSignalKit/SSignal+Combine.m b/SSignalKit/SSignal+Combine.m index c908947fbb..60c7f40cff 100644 --- a/SSignalKit/SSignal+Combine.m +++ b/SSignalKit/SSignal+Combine.m @@ -76,7 +76,7 @@ latestValues[i] = value; } if (latestValues != nil) - SSubscriber_putNext(subscriber, latestValues); + [subscriber putNext:latestValues]; } error:^(id error) { @@ -87,7 +87,7 @@ return [[SSignalCombineState alloc] initWithLatestValues:state.latestValues completedStatuses:state.completedStatuses error:true]; }]; if (!hadError) - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { __block bool wasCompleted = false; @@ -121,7 +121,7 @@ return [[SSignalCombineState alloc] initWithLatestValues:state.latestValues completedStatuses:completedStatuses error:state.error]; }]; if (!wasCompleted && isCompleted) - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]; [compositeDisposable add:disposable]; index++; diff --git a/SSignalKit/SSignal+Dispatch.m b/SSignalKit/SSignal+Dispatch.m index 707afce8da..b23337e3fa 100644 --- a/SSignalKit/SSignal+Dispatch.m +++ b/SSignalKit/SSignal+Dispatch.m @@ -13,19 +13,19 @@ { [queue dispatch:^ { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; }]; } error:^(id error) { [queue dispatch:^ { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; }]; } completed:^ { [queue dispatch:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]; }]; }]; @@ -41,7 +41,7 @@ SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) { if (!cancelled()) - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; }]; SThreadPoolTask *lastTask = [atomicLastTask swap:task]; if (lastTask != nil) @@ -52,7 +52,7 @@ SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) { if (!cancelled()) - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; }]; SThreadPoolTask *lastTask = [atomicLastTask swap:task]; if (lastTask != nil) @@ -63,7 +63,7 @@ SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) { if (!cancelled()) - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]; SThreadPoolTask *lastTask = [atomicLastTask swap:task]; if (lastTask != nil) @@ -90,13 +90,13 @@ { [disposable setDisposable:[self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; } }]; @@ -118,13 +118,13 @@ [disposable setDisposable:[self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; }]; diff --git a/SSignalKit/SSignal+Mapping.m b/SSignalKit/SSignal+Mapping.m index da50570389..3b98a222b9 100644 --- a/SSignalKit/SSignal+Mapping.m +++ b/SSignalKit/SSignal+Mapping.m @@ -8,13 +8,13 @@ { return [self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, f(next)); + [subscriber putNext:f(next)]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]; }]; } @@ -24,12 +24,13 @@ id (^generator)(SSubscriber *) = self->_generator; self->_generator = [^id (SSubscriber *subscriber) { - SSubscriber *mappedSubscriber = [[SSubscriber alloc] initWithNext:^(id next) + void (^next)(id) = subscriber->_next; + subscriber->_next = ^(id value) { - subscriber->_next(f(next)); - } error:subscriber->_error completed:subscriber->_completed]; + next(f(value)); + }; - return generator(mappedSubscriber); + return generator(subscriber); } copy]; return self; @@ -42,13 +43,13 @@ return [self startWithNext:^(id next) { if (f(next)) - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]; }]; } diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 208d6e7017..0adc4846ab 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -22,21 +22,21 @@ [didProduceNext swap:@1]; [currentDisposable setDisposable:[next startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { if ([didProduceNext swap:@1] == NULL) - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; return compositeDisposable; @@ -59,21 +59,21 @@ { [currentDisposable setDisposable:[self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { [compositeDisposable add:[signal startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; }]]; diff --git a/SSignalKit/SSignal+Multicast.m b/SSignalKit/SSignal+Multicast.m index 7b2ee7f79a..6e08423750 100644 --- a/SSignalKit/SSignal+Multicast.m +++ b/SSignalKit/SSignal+Multicast.m @@ -91,7 +91,7 @@ typedef enum { for (SSubscriber *subscriber in currentSubscribers) { - SSubscriber_putEvent(subscriber, event); + [subscriber putEvent:event]; } } diff --git a/SSignalKit/SSignal+SideEffects.m b/SSignalKit/SSignal+SideEffects.m index 332d7553df..ae59f3f77a 100644 --- a/SSignalKit/SSignal+SideEffects.m +++ b/SSignalKit/SSignal+SideEffects.m @@ -12,13 +12,13 @@ return [self startWithNext:^(id next) { f(next); - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]; }]; } @@ -29,14 +29,14 @@ { return [self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { f(error); - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]; }]; } @@ -47,14 +47,14 @@ { return [self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { f(); - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]; }]; } @@ -67,13 +67,13 @@ [compositeDisposable add:[self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; [compositeDisposable add:[[SBlockDisposable alloc] initWithBlock:^ diff --git a/SSignalKit/SSignal+Single.m b/SSignalKit/SSignal+Single.m index 2ffd6b12e9..82c5a1570a 100644 --- a/SSignalKit/SSignal+Single.m +++ b/SSignalKit/SSignal+Single.m @@ -1,47 +1,21 @@ #import "SSignal+Single.h" -@interface SSignal_Single : SSignal -{ - id _next; -} - -@end - -@implementation SSignal_Single - -- (instancetype)initWithNext:(id)next -{ - self = [super init]; - if (self != nil) - { - _next = next; - } - return self; -} - -- (id)startWithNext:(void (^)(id))next error:(void (^)(id))__unused error completed:(void (^)())completed -{ - if (next) - next(_next); - if (completed) - completed(); - return nil; -} - -@end - @implementation SSignal (Single) + (SSignal *)single:(id)next { - return [[SSignal_Single alloc] initWithNext:next]; + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + [subscriber putNext:next]; + return nil; + }]; } + (SSignal *)fail:(id)error { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; return nil; }]; } @@ -58,7 +32,7 @@ { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; return nil; }]; } diff --git a/SSignalKit/SSignal+Timing.m b/SSignalKit/SSignal+Timing.m index 4a5b6c82a8..ee002fccf1 100644 --- a/SSignalKit/SSignal+Timing.m +++ b/SSignalKit/SSignal+Timing.m @@ -17,13 +17,13 @@ { [disposable setDisposable:[self startWithNext:^(id next) { - SSubscriber_putNext(subscriber, next); + [subscriber putNext:next]; } error:^(id error) { - SSubscriber_putError(subscriber, error); + [subscriber putError:error]; } completed:^ { - SSubscriber_putCompletion(subscriber); + [subscriber putCompletion]; }]]; } queue:queue]; diff --git a/SSignalKit/SSignal.h b/SSignalKit/SSignal.h index 1af078500c..c3e00ad9fb 100644 --- a/SSignalKit/SSignal.h +++ b/SSignalKit/SSignal.h @@ -7,7 +7,10 @@ } - (instancetype)initWithGenerator:(id (^)(SSubscriber *))generator; -- (id)startWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; + +- (id)startWithNext:(void (^)(id next))next error:(void (^)(id error))error completed:(void (^)())completed; +- (id)startWithNext:(void (^)(id next))next; +- (id)startWithNext:(void (^)(id next))next completed:(void (^)())completed; @end diff --git a/SSignalKit/SSignal.m b/SSignalKit/SSignal.m index 3bfa06cb0c..c86a9252fb 100644 --- a/SSignalKit/SSignal.m +++ b/SSignalKit/SSignal.m @@ -18,10 +18,28 @@ return self; } -- (id)startWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed +- (id)startWithNext:(void (^)(id next))next error:(void (^)(id error))error completed:(void (^)())completed { SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:error completed:completed]; - return _generator(subscriber); + id disposable = _generator(subscriber); + [subscriber _assignDisposable:disposable]; + return disposable; +} + +- (id)startWithNext:(void (^)(id next))next +{ + SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:nil completed:nil]; + id disposable = _generator(subscriber); + [subscriber _assignDisposable:disposable]; + return disposable; +} + +- (id)startWithNext:(void (^)(id next))next completed:(void (^)())completed +{ + SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:nil completed:completed]; + id disposable = _generator(subscriber); + [subscriber _assignDisposable:disposable]; + return disposable; } @end diff --git a/SSignalKit/SSubscriber.h b/SSignalKit/SSubscriber.h index a6450c9404..896917ded7 100644 --- a/SSignalKit/SSubscriber.h +++ b/SSignalKit/SSubscriber.h @@ -1,7 +1,7 @@ #import "SDisposable.h" #import "SEvent.h" -@interface SSubscriber : NSObject +@interface SSubscriber : NSObject { @public void (^_next)(id); @@ -19,16 +19,3 @@ - (void)putCompletion; @end - -#ifdef __cplusplus -extern "C" { -#endif - -void SSubscriber_putNext(SSubscriber *subscriber, id next); -void SSubscriber_putError(SSubscriber *subscriber, id error); -void SSubscriber_putCompletion(SSubscriber *subscriber); -void SSubscriber_putEvent(SSubscriber *subscriber, SEvent *event); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index 377349aa7a..43f6d3a6f4 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -1,6 +1,5 @@ #import "SSubscriber.h" -#import #import #import "SEvent.h" @@ -10,8 +9,6 @@ @interface SSubscriber () { - @public - //volatile OSSpinLock _lock; pthread_mutex_t _mutex; id _disposable; @@ -40,96 +37,24 @@ } - (void)putEvent:(SEvent *)event -{ - SSubscriber_putEvent(self, event); -} - -- (void)putNext:(id)next -{ - [self putEvent:[[SEvent alloc] initWithNext:next]]; -} - -- (void)putError:(id)error -{ - [self putEvent:[[SEvent alloc] initWithError:error]]; -} - -- (void)putCompletion -{ - [self putEvent:[[SEvent alloc] initWithCompleted]]; -} - -void SSubscriber_putNext(SSubscriber *subscriber, id next) -{ - void (^fnext)(id) = nil; - - lockSelf(subscriber); - fnext = subscriber->_next; - unlockSelf(subscriber); - - if (fnext) - fnext(next); -} - -void SSubscriber_putError(SSubscriber *subscriber, id error) -{ - bool shouldDispose = false; - void (^ferror)(id) = nil; - - lockSelf(subscriber); - ferror = subscriber->_error; - shouldDispose = true; - subscriber->_next = nil; - subscriber->_error = nil; - subscriber->_completed = nil; - unlockSelf(subscriber); - - if (ferror) - ferror(error); - - if (shouldDispose) - [subscriber->_disposable dispose]; -} - -void SSubscriber_putCompletion(SSubscriber *subscriber) -{ - bool shouldDispose = false; - void (^completed)() = nil; - - lockSelf(subscriber); - completed = subscriber->_completed; - shouldDispose = true; - subscriber->_next = nil; - subscriber->_error = nil; - subscriber->_completed = nil; - unlockSelf(subscriber); - - if (completed) - completed(); - - if (shouldDispose) - [subscriber->_disposable dispose]; -} - -void SSubscriber_putEvent(SSubscriber *subscriber, SEvent *event) { bool shouldDispose = false; void (^next)(id) = nil; void (^error)(id) = nil; void (^completed)(id) = nil; - lockSelf(subscriber); - next = subscriber->_next; - error = subscriber->_error; - completed = subscriber->_completed; + lockSelf(self); + next = self->_next; + error = self->_error; + completed = self->_completed; if (event.type != SEventTypeNext) { shouldDispose = true; - subscriber->_next = nil; - subscriber->_error = nil; - subscriber->_completed = nil; + self->_next = nil; + self->_error = nil; + self->_completed = nil; } - unlockSelf(subscriber); + unlockSelf(self); switch (event.type) { @@ -148,7 +73,64 @@ void SSubscriber_putEvent(SSubscriber *subscriber, SEvent *event) } if (shouldDispose) - [subscriber->_disposable dispose]; + [self->_disposable dispose]; +} + +- (void)putNext:(id)next +{ + void (^fnext)(id) = nil; + + lockSelf(self); + fnext = self->_next; + unlockSelf(self); + + if (fnext) + fnext(next); +} + +- (void)putError:(id)error +{ + bool shouldDispose = false; + void (^ferror)(id) = nil; + + lockSelf(self); + ferror = self->_error; + shouldDispose = true; + self->_next = nil; + self->_error = nil; + self->_completed = nil; + unlockSelf(self); + + if (ferror) + ferror(error); + + if (shouldDispose) + [self->_disposable dispose]; +} + +- (void)putCompletion +{ + bool shouldDispose = false; + void (^completed)() = nil; + + lockSelf(self); + completed = self->_completed; + shouldDispose = true; + self->_next = nil; + self->_error = nil; + self->_completed = nil; + unlockSelf(self); + + if (completed) + completed(); + + if (shouldDispose) + [self->_disposable dispose]; +} + +- (void)dispose +{ + [self->_disposable dispose]; } @end diff --git a/SSignalKitTests/DeallocatingObject.h b/SSignalKitTests/DeallocatingObject.h new file mode 100644 index 0000000000..00f3c9cc8b --- /dev/null +++ b/SSignalKitTests/DeallocatingObject.h @@ -0,0 +1,7 @@ +#import + +@interface DeallocatingObject : NSObject + +- (instancetype)initWithDeallocated:(bool *)deallocated; + +@end diff --git a/SSignalKitTests/DeallocatingObject.m b/SSignalKitTests/DeallocatingObject.m new file mode 100644 index 0000000000..38cff658e6 --- /dev/null +++ b/SSignalKitTests/DeallocatingObject.m @@ -0,0 +1,27 @@ +#import "DeallocatingObject.h" + +@interface DeallocatingObject () +{ + bool *_deallocated; +} + +@end + +@implementation DeallocatingObject + +- (instancetype)initWithDeallocated:(bool *)deallocated +{ + self = [super init]; + if (self != nil) + { + _deallocated = deallocated; + } + return self; +} + +- (void)dealloc +{ + *_deallocated = true; +} + +@end diff --git a/SSignalKitTests/SBlockDisposableTest.m b/SSignalKitTests/SDisposableTests.m similarity index 81% rename from SSignalKitTests/SBlockDisposableTest.m rename to SSignalKitTests/SDisposableTests.m index c6c0982bc9..f071376688 100644 --- a/SSignalKitTests/SBlockDisposableTest.m +++ b/SSignalKitTests/SDisposableTests.m @@ -5,37 +5,13 @@ @import SSignalKit; -@interface TestObject : NSObject -{ - bool *_deallocated; -} +#import "DeallocatingObject.h" + +@interface SDisposableTests : XCTestCase @end -@implementation TestObject - -- (instancetype)initWithDeallocated:(bool *)deallocated -{ - self = [super init]; - if (self != nil) - { - _deallocated = deallocated; - } - return self; -} - -- (void)dealloc -{ - *_deallocated = true; -} - -@end - -@interface SBlockDisposableTest : XCTestCase - -@end - -@implementation SBlockDisposableTest +@implementation SDisposableTests - (void)setUp { @@ -52,7 +28,7 @@ bool deallocated = false; __block bool disposed = false; { - TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; dispatch_block_t block = ^{ [object description]; disposed = true; @@ -72,7 +48,7 @@ bool deallocated = false; __block bool disposed = false; { - TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; dispatch_block_t block = ^{ [object description]; disposed = true; @@ -90,7 +66,7 @@ bool deallocated = false; __block bool disposed = false; { - TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; dispatch_block_t block = ^{ [object description]; disposed = true; @@ -113,14 +89,14 @@ bool deallocated2 = false; __block bool disposed2 = false; { - TestObject *object1 = [[TestObject alloc] initWithDeallocated:&deallocated1]; + DeallocatingObject *object1 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated1]; dispatch_block_t block1 = ^{ [object1 description]; disposed1 = true; }; SBlockDisposable *blockDisposable1 = [[SBlockDisposable alloc] initWithBlock:[block1 copy]]; - TestObject *object2 = [[TestObject alloc] initWithDeallocated:&deallocated2]; + DeallocatingObject *object2 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated2]; dispatch_block_t block2 = ^{ [object2 description]; disposed2 = true; @@ -144,7 +120,7 @@ bool deallocated = false; __block bool disposed = false; { - TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; dispatch_block_t block = ^{ [object description]; disposed = true; @@ -164,7 +140,7 @@ bool deallocated = false; __block bool disposed = false; { - TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; dispatch_block_t block = ^{ [object description]; disposed = true; @@ -187,14 +163,14 @@ bool deallocated2 = false; __block bool disposed2 = false; { - TestObject *object1 = [[TestObject alloc] initWithDeallocated:&deallocated1]; + DeallocatingObject *object1 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated1]; dispatch_block_t block1 = ^{ [object1 description]; disposed1 = true; }; SBlockDisposable *blockDisposable1 = [[SBlockDisposable alloc] initWithBlock:[block1 copy]]; - TestObject *object2 = [[TestObject alloc] initWithDeallocated:&deallocated2]; + DeallocatingObject *object2 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated2]; dispatch_block_t block2 = ^{ [object2 description]; disposed2 = true; @@ -218,7 +194,7 @@ bool deallocated = false; __block bool disposed = false; { - TestObject *object = [[TestObject alloc] initWithDeallocated:&deallocated]; + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; dispatch_block_t block = ^{ [object description]; disposed = true; @@ -240,14 +216,14 @@ bool deallocated2 = false; __block bool disposed2 = false; { - TestObject *object1 = [[TestObject alloc] initWithDeallocated:&deallocated1]; + DeallocatingObject *object1 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated1]; dispatch_block_t block1 = ^{ [object1 description]; disposed1 = true; }; SBlockDisposable *blockDisposable1 = [[SBlockDisposable alloc] initWithBlock:[block1 copy]]; - TestObject *object2 = [[TestObject alloc] initWithDeallocated:&deallocated2]; + DeallocatingObject *object2 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated2]; dispatch_block_t block2 = ^{ [object2 description]; disposed2 = true; diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m new file mode 100644 index 0000000000..90857ed6b1 --- /dev/null +++ b/SSignalKitTests/SSignalBasicTests.m @@ -0,0 +1,208 @@ +#import +#import + +@import SSignalKit; + +#import "DeallocatingObject.h" + +@interface SSignalBasicTests : XCTestCase + +@end + +@implementation SSignalBasicTests + +- (void)setUp +{ + [super setUp]; +} + +- (void)tearDown +{ + [super tearDown]; +} + +- (void)testSignalGenerated +{ + __block bool deallocated = false; + __block bool disposed = false; + __block bool generated = false; + + { + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; + SSignal *signal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + [object description]; + + return [[SBlockDisposable alloc] initWithBlock:^ + { + [object description]; + disposed = true; + }]; + }]; + id disposable = [signal startWithNext:^(__unused id next) + { + generated = true; + [object description]; + } error:nil completed:nil]; + [disposable dispose]; + } + + XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); + XCTAssertTrue(generated); +} + +- (void)testSignalGeneratedCompleted +{ + __block bool deallocated = false; + __block bool disposed = false; + __block bool generated = false; + __block bool completed = false; + + { + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; + SSignal *signal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + [subscriber putCompletion]; + [object description]; + + return [[SBlockDisposable alloc] initWithBlock:^ + { + [object description]; + disposed = true; + }]; + }]; + id disposable = [signal startWithNext:^(__unused id next) + { + [object description]; + generated = true; + } error:nil completed:^ + { + [object description]; + completed = true; + }]; + [disposable dispose]; + } + + XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); + XCTAssertTrue(generated); + XCTAssertTrue(completed); +} + +- (void)testSignalGeneratedError +{ + __block bool deallocated = false; + __block bool disposed = false; + __block bool generated = false; + __block bool error = false; + + { + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; + SSignal *signal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + [subscriber putError:@1]; + [object description]; + + return [[SBlockDisposable alloc] initWithBlock:^ + { + [object description]; + disposed = true; + }]; + }]; + id disposable = [signal startWithNext:^(__unused id next) + { + generated = true; + } error:^(__unused id value) + { + error = true; + } completed:nil]; + [disposable dispose]; + } + + XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); + XCTAssertTrue(generated); + XCTAssertTrue(error); +} + +- (void)testMap +{ + bool deallocated = false; + __block bool disposed = false; + __block bool generated = false; + + { + @autoreleasepool + { + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; + SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + [object description]; + return [[SBlockDisposable alloc] initWithBlock:^ + { + [object description]; + disposed = true; + }]; + }] map:^id(id value) + { + [object description]; + return @([value intValue] * 2); + }]; + + id disposable = [signal startWithNext:^(id value) + { + generated = [value isEqual:@2]; + } error:nil completed:nil]; + [disposable dispose]; + } + } + + XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); + XCTAssertTrue(generated); +} + +- (void)testInplaceMap +{ + bool deallocated = false; + __block bool disposed = false; + __block bool generated = false; + + { + @autoreleasepool + { + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; + SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + [object description]; + return [[SBlockDisposable alloc] initWithBlock:^ + { + [object description]; + disposed = true; + }]; + }] _mapInplace:^id(id value) + { + [object description]; + return @([value intValue] * 2); + }]; + + id disposable = [signal startWithNext:^(id value) + { + generated = [value isEqual:@2]; + } error:nil completed:nil]; + [disposable dispose]; + } + } + + XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); + XCTAssertTrue(generated); +} + +@end diff --git a/SSignalKitTests/SSignalKitTests.m b/SSignalKitTests/SSignalKitTests.m deleted file mode 100644 index d10930a863..0000000000 --- a/SSignalKitTests/SSignalKitTests.m +++ /dev/null @@ -1,40 +0,0 @@ -// -// SSignalKitTests.m -// SSignalKitTests -// -// Created by Peter on 31/01/15. -// Copyright (c) 2015 Telegram. All rights reserved. -// - -#import -#import - -@interface SSignalKitTests : XCTestCase - -@end - -@implementation SSignalKitTests - -- (void)setUp { - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testExample { - // This is an example of a functional test case. - XCTAssert(YES, @"Pass"); -} - -- (void)testPerformanceExample { - // This is an example of a performance test case. - [self measureBlock:^{ - // Put the code you want to measure the time of here. - }]; -} - -@end diff --git a/SSignalKitTests/SSignalPerformanceTests.m b/SSignalKitTests/SSignalPerformanceTests.m new file mode 100644 index 0000000000..b7948645ba --- /dev/null +++ b/SSignalKitTests/SSignalPerformanceTests.m @@ -0,0 +1,125 @@ +#import +#import + +@import SSignalKit; + +@interface SSignalPerformanceTests : XCTestCase + +@end + +@implementation SSignalPerformanceTests + +- (void)setUp +{ + [super setUp]; +} + +- (void)tearDown +{ + [super tearDown]; +} + +- (void)testMap +{ + [self measureBlock:^ + { + SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + [subscriber putCompletion]; + return nil; + }] map:^id (id value) + { + return value; + }]; + + for (int i = 0; i < 100000; i++) + { + [signal startWithNext:^(__unused id next) + { + + }]; + } + }]; +} + +- (void)testMapInplace +{ + [self measureBlock:^ + { + SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + [subscriber putCompletion]; + return nil; + }] _mapInplace:^id (id value) + { + return value; + }]; + + for (int i = 0; i < 100000; i++) + { + [signal startWithNext:^(__unused id next) + { + + }]; + } + }]; +} + +- (void)testMapInplaceWithDisposable +{ + [self measureBlock:^ + { + SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + return [[SBlockDisposable alloc] initWithBlock:^ + { + }]; + }] _mapInplace:^id (id value) + { + return value; + }]; + + for (int i = 0; i < 100000; i++) + { + [signal startWithNext:^(__unused id next) + { + + }]; + } + }]; +} + +- (void)testMapInplace2WithDisposable +{ + [self measureBlock:^ + { + SSignal *signal = [[[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@1]; + [subscriber putCompletion]; + + return [[SBlockDisposable alloc] initWithBlock:^ + { + }]; + }] _mapInplace:^id (id value) + { + return value; + }] _mapInplace:^id (id value) + { + return value; + }]; + + for (int i = 0; i < 100000; i++) + { + [signal startWithNext:^(__unused id next) + { + + }]; + } + }]; +} + +@end From 00ca6f5e0d7e06bc56b3ddcc883fdc11f7923aef Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 21 Feb 2015 22:41:56 +0300 Subject: [PATCH 009/122] no message --- SSignalKit/SQueue.h | 2 ++ SSignalKit/SQueue.m | 5 +++++ SSignalKit/SSignal+Catch.m | 6 +++--- SSignalKit/SSignal+Single.m | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/SSignalKit/SQueue.h b/SSignalKit/SQueue.h index 85ac709ba6..011aa333a1 100644 --- a/SSignalKit/SQueue.h +++ b/SSignalKit/SQueue.h @@ -6,6 +6,8 @@ + (SQueue *)concurrentDefaultQueue; + (SQueue *)concurrentBackgroundQueue; ++ (SQueue *)wrapConcurrentNativeQueue:(dispatch_queue_t)nativeQueue; + - (void)dispatch:(dispatch_block_t)block; - (dispatch_queue_t)_dispatch_queue; diff --git a/SSignalKit/SQueue.m b/SSignalKit/SQueue.m index 80e24dd5b5..91a7336c89 100644 --- a/SSignalKit/SQueue.m +++ b/SSignalKit/SQueue.m @@ -50,6 +50,11 @@ static const void *SQueueSpecificKey = &SQueueSpecificKey; return queue; } ++ (SQueue *)wrapConcurrentNativeQueue:(dispatch_queue_t)nativeQueue +{ + return [[SQueue alloc] initWithNativeQueue:nativeQueue queueSpecific:NULL]; +} + - (instancetype)init { dispatch_queue_t queue = dispatch_queue_create(NULL, NULL); diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m index 6a43a0cac8..61b97884d9 100644 --- a/SSignalKit/SSignal+Catch.m +++ b/SSignalKit/SSignal+Catch.m @@ -10,15 +10,15 @@ { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; + SDisposableSet *disposable = [[SDisposableSet alloc] init]; - [disposable setDisposable:[self startWithNext:^(id next) + [disposable add:[self startWithNext:^(id next) { [subscriber putNext:next]; } error:^(id error) { SSignal *signal = f(error); - [disposable setDisposable:[signal startWithNext:^(id next) + [disposable add:[signal startWithNext:^(id next) { [subscriber putNext:next]; } error:^(id error) diff --git a/SSignalKit/SSignal+Single.m b/SSignalKit/SSignal+Single.m index 82c5a1570a..6da5943459 100644 --- a/SSignalKit/SSignal+Single.m +++ b/SSignalKit/SSignal+Single.m @@ -7,6 +7,7 @@ return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { [subscriber putNext:next]; + [subscriber putCompletion]; return nil; }]; } From 5fa95f61455aba79520506cfe78b450794fb44bb Mon Sep 17 00:00:00 2001 From: Peter Date: Sun, 1 Mar 2015 18:29:25 +0100 Subject: [PATCH 010/122] More strict disposables --- SSignalKit.xcodeproj/project.pbxproj | 10 --- SSignalKit/SDisposableSet.m | 50 +++++++++----- SSignalKit/SMetaDisposable.m | 64 +++++++++--------- SSignalKit/SSignal+Concat.h | 5 -- SSignalKit/SSignal+Concat.m | 14 ---- SSignalKit/SSignal+Multicast.m | 13 +++- SSignalKit/SSignal.m | 12 +++- SSignalKit/SSubscriber.h | 2 +- SSignalKit/SSubscriber.m | 98 +++++++++++----------------- SSignalKitTests/SDisposableTests.m | 70 ++++++++++++++++++++ SSignalKitTests/SSignalBasicTests.m | 75 +++++++++++++++------ 11 files changed, 246 insertions(+), 167 deletions(-) delete mode 100644 SSignalKit/SSignal+Concat.h delete mode 100644 SSignalKit/SSignal+Concat.m diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 3315b248d5..0633d6faa2 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -29,8 +29,6 @@ D0445E351A7C2D7300267924 /* SSignal+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E091A7C2D7300267924 /* SSignal+Catch.m */; }; D0445E361A7C2D7300267924 /* SSignal+Combine.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445E371A7C2D7300267924 /* SSignal+Combine.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */; }; - D0445E381A7C2D7300267924 /* SSignal+Concat.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E0C1A7C2D7300267924 /* SSignal+Concat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E391A7C2D7300267924 /* SSignal+Concat.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0D1A7C2D7300267924 /* SSignal+Concat.m */; }; D0445E3A1A7C2D7300267924 /* SSignal+Dispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445E3B1A7C2D7300267924 /* SSignal+Dispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */; }; D0445E3C1A7C2D7300267924 /* SSignal+Mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E101A7C2D7300267924 /* SSignal+Mapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -65,7 +63,6 @@ D0445E7B1A7C447D00267924 /* SSignal+Accumulate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */; }; D0445E7C1A7C447D00267924 /* SSignal+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E091A7C2D7300267924 /* SSignal+Catch.m */; }; D0445E7D1A7C447D00267924 /* SSignal+Combine.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */; }; - D0445E7E1A7C447D00267924 /* SSignal+Concat.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0D1A7C2D7300267924 /* SSignal+Concat.m */; }; D0445E7F1A7C447D00267924 /* SSignal+Dispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */; }; D0445E801A7C447D00267924 /* SSignal+Mapping.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E111A7C2D7300267924 /* SSignal+Mapping.m */; }; D0445E811A7C447D00267924 /* SSignal+Meta.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E131A7C2D7300267924 /* SSignal+Meta.m */; }; @@ -133,8 +130,6 @@ D0445E091A7C2D7300267924 /* SSignal+Catch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Catch.m"; sourceTree = ""; }; D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Combine.h"; sourceTree = ""; }; D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Combine.m"; sourceTree = ""; }; - D0445E0C1A7C2D7300267924 /* SSignal+Concat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Concat.h"; sourceTree = ""; }; - D0445E0D1A7C2D7300267924 /* SSignal+Concat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Concat.m"; sourceTree = ""; }; D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Dispatch.h"; sourceTree = ""; }; D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Dispatch.m"; sourceTree = ""; }; D0445E101A7C2D7300267924 /* SSignal+Mapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Mapping.h"; sourceTree = ""; }; @@ -239,8 +234,6 @@ D0445E091A7C2D7300267924 /* SSignal+Catch.m */, D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */, D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */, - D0445E0C1A7C2D7300267924 /* SSignal+Concat.h */, - D0445E0D1A7C2D7300267924 /* SSignal+Concat.m */, D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */, D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */, D0445E101A7C2D7300267924 /* SSignal+Mapping.h */, @@ -327,7 +320,6 @@ D0445E231A7C2D7300267924 /* SAtomic.h in Headers */, D087632A1A839EDC00632240 /* SDisposableSet.h in Headers */, D0445E461A7C2D7300267924 /* SSignal+Timing.h in Headers */, - D0445E381A7C2D7300267924 /* SSignal+Concat.h in Headers */, D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */, D0445E3C1A7C2D7300267924 /* SSignal+Mapping.h in Headers */, ); @@ -467,7 +459,6 @@ D0445E311A7C2D7300267924 /* SSignal.m in Sources */, D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */, D0445E491A7C2D7300267924 /* SSubscriber.m in Sources */, - D0445E391A7C2D7300267924 /* SSignal+Concat.m in Sources */, D0445E431A7C2D7300267924 /* SSignal+SideEffects.m in Sources */, D0445E3F1A7C2D7300267924 /* SSignal+Meta.m in Sources */, D0445E371A7C2D7300267924 /* SSignal+Combine.m in Sources */, @@ -508,7 +499,6 @@ D0445E7A1A7C447D00267924 /* SSignal.m in Sources */, D087632C1A839EE800632240 /* SDisposableSet.m in Sources */, D0445E861A7C447D00267924 /* SSubscriber.m in Sources */, - D0445E7E1A7C447D00267924 /* SSignal+Concat.m in Sources */, D0445E831A7C447D00267924 /* SSignal+SideEffects.m in Sources */, D0445E811A7C447D00267924 /* SSignal+Meta.m in Sources */, D0445E7D1A7C447D00267924 /* SSignal+Combine.m in Sources */, diff --git a/SSignalKit/SDisposableSet.m b/SSignalKit/SDisposableSet.m index caabf076ea..469436ad99 100644 --- a/SSignalKit/SDisposableSet.m +++ b/SSignalKit/SDisposableSet.m @@ -5,6 +5,7 @@ @interface SDisposableSet () { OSSpinLock _lock; + bool _disposed; id _singleDisposable; NSArray *_multipleDisposables; } @@ -18,24 +19,33 @@ if (disposable == nil) return; + bool dispose = false; + OSSpinLockLock(&_lock); - if (_multipleDisposables != nil) + dispose = _disposed; + if (!dispose) { - NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithArray:_multipleDisposables]; - [multipleDisposables addObject:disposable]; - _multipleDisposables = multipleDisposables; - } - else if (_singleDisposable != nil) - { - NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithObjects:_singleDisposable, disposable, nil]; - _multipleDisposables = multipleDisposables; - _singleDisposable = nil; - } - else - { - _singleDisposable = disposable; + if (_multipleDisposables != nil) + { + NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithArray:_multipleDisposables]; + [multipleDisposables addObject:disposable]; + _multipleDisposables = multipleDisposables; + } + else if (_singleDisposable != nil) + { + NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithObjects:_singleDisposable, disposable, nil]; + _multipleDisposables = multipleDisposables; + _singleDisposable = nil; + } + else + { + _singleDisposable = disposable; + } } OSSpinLockUnlock(&_lock); + + if (dispose) + [disposable dispose]; } - (void)dispose @@ -44,10 +54,14 @@ NSArray *multipleDisposables = nil; OSSpinLockLock(&_lock); - singleDisposable = _singleDisposable; - multipleDisposables = _multipleDisposables; - _singleDisposable = nil; - _multipleDisposables = nil; + if (!_disposed) + { + _disposed = true; + singleDisposable = _singleDisposable; + multipleDisposables = _multipleDisposables; + _singleDisposable = nil; + _multipleDisposables = nil; + } OSSpinLockUnlock(&_lock); if (singleDisposable != nil) diff --git a/SSignalKit/SMetaDisposable.m b/SSignalKit/SMetaDisposable.m index 4e461eed3f..4e9c8e4fab 100644 --- a/SSignalKit/SMetaDisposable.m +++ b/SSignalKit/SMetaDisposable.m @@ -4,54 +4,50 @@ @interface SMetaDisposable () { - void *_disposable; + OSSpinLock _lock; + bool _disposed; + id _disposable; } @end @implementation SMetaDisposable -- (void)dealloc -{ - while (true) - { - void *previousDisposable = _disposable; - if (OSAtomicCompareAndSwapPtr(previousDisposable, NULL, &_disposable)) - { - if (previousDisposable != NULL) - { - __strong id strongPreviousDisposable = (__bridge_transfer id)previousDisposable; - strongPreviousDisposable = nil; - } - - break; - } - } -} - - (void)setDisposable:(id)disposable { - void *newDisposable = (__bridge_retained void *)disposable; - while (true) + id previousDisposable = nil; + bool dispose = false; + + OSSpinLockLock(&_lock); + dispose = _disposed; + if (!dispose) { - void *previousDisposable = _disposable; - if (OSAtomicCompareAndSwapPtr(previousDisposable, newDisposable, &_disposable)) - { - if (previousDisposable != NULL) - { - __strong id strongPreviousDisposable = (__bridge_transfer id)previousDisposable; - [strongPreviousDisposable dispose]; - strongPreviousDisposable = nil; - } - - break; - } + previousDisposable = _disposable; + _disposable = disposable; } + OSSpinLockUnlock(&_lock); + + if (previousDisposable != nil) + [previousDisposable dispose]; + + if (dispose) + [disposable dispose]; } - (void)dispose { - [self setDisposable:nil]; + id disposable = nil; + + OSSpinLockLock(&_lock); + if (!_disposed) + { + disposable = _disposable; + _disposed = true; + } + OSSpinLockUnlock(&_lock); + + if (disposable != nil) + [disposable dispose]; } @end diff --git a/SSignalKit/SSignal+Concat.h b/SSignalKit/SSignal+Concat.h deleted file mode 100644 index 356f80c213..0000000000 --- a/SSignalKit/SSignal+Concat.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "SSignal.h" - -@interface SSignal (Concat) - -@end diff --git a/SSignalKit/SSignal+Concat.m b/SSignalKit/SSignal+Concat.m deleted file mode 100644 index 8d76e5159d..0000000000 --- a/SSignalKit/SSignal+Concat.m +++ /dev/null @@ -1,14 +0,0 @@ -#import "SSignal+Concat.h" - -#import "SAtomic.h" - -@implementation SSignal (Concat) - -- (SSignal *)concat:(SSignal *)another -{ - NSAssert(false, @"123"); - - return nil; -} - -@end diff --git a/SSignalKit/SSignal+Multicast.m b/SSignalKit/SSignal+Multicast.m index 6e08423750..3fe3a6f789 100644 --- a/SSignalKit/SSignal+Multicast.m +++ b/SSignalKit/SSignal+Multicast.m @@ -91,7 +91,18 @@ typedef enum { for (SSubscriber *subscriber in currentSubscribers) { - [subscriber putEvent:event]; + switch (event.type) + { + case SEventTypeNext: + [subscriber putNext:event.data]; + break; + case SEventTypeError: + [subscriber putError:event.data]; + break; + case SEventTypeCompleted: + [subscriber putCompletion]; + break; + } } } diff --git a/SSignalKit/SSignal.m b/SSignalKit/SSignal.m index c86a9252fb..1cae763a69 100644 --- a/SSignalKit/SSignal.m +++ b/SSignalKit/SSignal.m @@ -1,5 +1,7 @@ #import "SSignal.h" +#import "SBlockDisposable.h" + @interface SSignal () { } @@ -23,7 +25,11 @@ SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:error completed:completed]; id disposable = _generator(subscriber); [subscriber _assignDisposable:disposable]; - return disposable; + return [[SBlockDisposable alloc] initWithBlock:^ + { + [subscriber _markTerminatedWithoutDisposal]; + [disposable dispose]; + }]; } - (id)startWithNext:(void (^)(id next))next @@ -31,7 +37,7 @@ SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:nil completed:nil]; id disposable = _generator(subscriber); [subscriber _assignDisposable:disposable]; - return disposable; + return subscriber; } - (id)startWithNext:(void (^)(id next))next completed:(void (^)())completed @@ -39,7 +45,7 @@ SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:nil completed:completed]; id disposable = _generator(subscriber); [subscriber _assignDisposable:disposable]; - return disposable; + return subscriber; } @end diff --git a/SSignalKit/SSubscriber.h b/SSignalKit/SSubscriber.h index 896917ded7..2689f6c566 100644 --- a/SSignalKit/SSubscriber.h +++ b/SSignalKit/SSubscriber.h @@ -12,8 +12,8 @@ - (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; - (void)_assignDisposable:(id)disposable; +- (void)_markTerminatedWithoutDisposal; -- (void)putEvent:(SEvent *)event; - (void)putNext:(id)next; - (void)putError:(id)error; - (void)putCompletion; diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index 43f6d3a6f4..ef5979d5db 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -1,16 +1,11 @@ #import "SSubscriber.h" -#import - -#import "SEvent.h" - -#define lockSelf(x) pthread_mutex_lock(&x->_mutex) -#define unlockSelf(x) pthread_mutex_unlock(&x->_mutex) +#import @interface SSubscriber () { - pthread_mutex_t _mutex; - + OSSpinLock _lock; + bool _terminated; id _disposable; } @@ -23,7 +18,6 @@ self = [super init]; if (self != nil) { - pthread_mutex_init(&_mutex, NULL); _next = [next copy]; _error = [error copy]; _completed = [completed copy]; @@ -36,53 +30,27 @@ _disposable = disposable; } -- (void)putEvent:(SEvent *)event +- (void)_markTerminatedWithoutDisposal { - bool shouldDispose = false; - void (^next)(id) = nil; - void (^error)(id) = nil; - void (^completed)(id) = nil; - - lockSelf(self); - next = self->_next; - error = self->_error; - completed = self->_completed; - if (event.type != SEventTypeNext) + OSSpinLockLock(&_lock); + if (!_terminated) { - shouldDispose = true; - self->_next = nil; - self->_error = nil; - self->_completed = nil; + _terminated = true; + _next = nil; + _error = nil; + _completed = nil; } - unlockSelf(self); - - switch (event.type) - { - case SEventTypeNext: - if (next) - next(event.data); - break; - case SEventTypeError: - if (error) - error(event.data); - break; - case SEventTypeCompleted: - if (completed) - completed(event.data); - break; - } - - if (shouldDispose) - [self->_disposable dispose]; + OSSpinLockUnlock(&_lock); } - (void)putNext:(id)next { void (^fnext)(id) = nil; - lockSelf(self); - fnext = self->_next; - unlockSelf(self); + OSSpinLockLock(&_lock); + if (!_terminated) + fnext = self->_next; + OSSpinLockUnlock(&_lock); if (fnext) fnext(next); @@ -93,13 +61,17 @@ bool shouldDispose = false; void (^ferror)(id) = nil; - lockSelf(self); - ferror = self->_error; - shouldDispose = true; - self->_next = nil; - self->_error = nil; - self->_completed = nil; - unlockSelf(self); + OSSpinLockLock(&_lock); + if (!_terminated) + { + ferror = self->_error; + shouldDispose = true; + self->_next = nil; + self->_error = nil; + self->_completed = nil; + _terminated = true; + } + OSSpinLockUnlock(&_lock); if (ferror) ferror(error); @@ -113,13 +85,17 @@ bool shouldDispose = false; void (^completed)() = nil; - lockSelf(self); - completed = self->_completed; - shouldDispose = true; - self->_next = nil; - self->_error = nil; - self->_completed = nil; - unlockSelf(self); + OSSpinLockLock(&_lock); + if (!_terminated) + { + completed = self->_completed; + shouldDispose = true; + self->_next = nil; + self->_error = nil; + self->_completed = nil; + _terminated = true; + } + OSSpinLockUnlock(&_lock); if (completed) completed(); diff --git a/SSignalKitTests/SDisposableTests.m b/SSignalKitTests/SDisposableTests.m index f071376688..e04fc32049 100644 --- a/SSignalKitTests/SDisposableTests.m +++ b/SSignalKitTests/SDisposableTests.m @@ -241,4 +241,74 @@ XCTAssertFalse(disposed2); } +- (void)testMetaDisposableAlreadyDisposed +{ + bool deallocated1 = false; + __block bool disposed1 = false; + bool deallocated2 = false; + __block bool disposed2 = false; + + @autoreleasepool + { + DeallocatingObject *object1 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated1]; + dispatch_block_t block1 = ^{ + [object1 description]; + disposed1 = true; + }; + SBlockDisposable *blockDisposable1 = [[SBlockDisposable alloc] initWithBlock:[block1 copy]]; + + DeallocatingObject *object2 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated2]; + dispatch_block_t block2 = ^{ + [object2 description]; + disposed2 = true; + }; + SBlockDisposable *blockDisposable2 = [[SBlockDisposable alloc] initWithBlock:[block2 copy]]; + + SMetaDisposable *metaDisposable = [[SMetaDisposable alloc] init]; + [metaDisposable setDisposable:blockDisposable1]; + [metaDisposable dispose]; + [metaDisposable setDisposable:blockDisposable2]; + } + + XCTAssertTrue(deallocated1); + XCTAssertTrue(disposed1); + XCTAssertTrue(deallocated2); + XCTAssertTrue(disposed2); +} + +- (void)testDisposableSetAlreadyDisposed +{ + bool deallocated1 = false; + __block bool disposed1 = false; + bool deallocated2 = false; + __block bool disposed2 = false; + + @autoreleasepool + { + DeallocatingObject *object1 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated1]; + dispatch_block_t block1 = ^{ + [object1 description]; + disposed1 = true; + }; + SBlockDisposable *blockDisposable1 = [[SBlockDisposable alloc] initWithBlock:[block1 copy]]; + + DeallocatingObject *object2 = [[DeallocatingObject alloc] initWithDeallocated:&deallocated2]; + dispatch_block_t block2 = ^{ + [object2 description]; + disposed2 = true; + }; + SBlockDisposable *blockDisposable2 = [[SBlockDisposable alloc] initWithBlock:[block2 copy]]; + + SMetaDisposable *metaDisposable = [[SMetaDisposable alloc] init]; + [metaDisposable setDisposable:blockDisposable1]; + [metaDisposable dispose]; + [metaDisposable setDisposable:blockDisposable2]; + } + + XCTAssertTrue(deallocated1); + XCTAssertTrue(disposed1); + XCTAssertTrue(deallocated2); + XCTAssertTrue(disposed2); +} + @end diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index 90857ed6b1..be66425d44 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -173,31 +173,29 @@ __block bool disposed = false; __block bool generated = false; + @autoreleasepool { - @autoreleasepool + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; + SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { - DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; - SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - [subscriber putNext:@1]; - [object description]; - return [[SBlockDisposable alloc] initWithBlock:^ - { - [object description]; - disposed = true; - }]; - }] _mapInplace:^id(id value) + [subscriber putNext:@1]; + [object description]; + return [[SBlockDisposable alloc] initWithBlock:^ { [object description]; - return @([value intValue] * 2); + disposed = true; }]; - - id disposable = [signal startWithNext:^(id value) - { - generated = [value isEqual:@2]; - } error:nil completed:nil]; - [disposable dispose]; - } + }] _mapInplace:^id(id value) + { + [object description]; + return @([value intValue] * 2); + }]; + + id disposable = [signal startWithNext:^(id value) + { + generated = [value isEqual:@2]; + } error:nil completed:nil]; + [disposable dispose]; } XCTAssertTrue(deallocated); @@ -205,4 +203,41 @@ XCTAssertTrue(generated); } +- (void)testSubscriberDisposal +{ + __block bool disposed = false; + __block bool generated = false; + + dispatch_queue_t queue = dispatch_queue_create(NULL, 0); + + @autoreleasepool + { + SSignal *signal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + dispatch_async(queue, ^ + { + [subscriber putNext:@1]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposed = true; + }]; + }]; + + id disposable = [signal startWithNext:^(id value) + { + generated = true; + } error:nil completed:nil]; + [disposable dispose]; + } + + dispatch_barrier_sync(queue, ^ + { + }); + + XCTAssertTrue(disposed); + XCTAssertFalse(generated); +} + @end From c41a6d09cc04f7b7ac7da9cec6042825e5a285c4 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 27 Mar 2015 13:14:50 +0300 Subject: [PATCH 011/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 16 +++ SSignalKit/SSignal+Dispatch.m | 29 ++--- SSignalKit/SSignal.m | 39 ++++-- SSignalKit/SThreadPool.h | 15 +-- SSignalKit/SThreadPool.m | 177 ++++++--------------------- SSignalKit/SThreadPoolQueue.h | 13 ++ SSignalKit/SThreadPoolQueue.m | 51 ++++++++ SSignalKit/SThreadPoolTask.h | 9 ++ SSignalKit/SThreadPoolTask.m | 53 ++++++++ SSignalKitTests/SSignalBasicTests.m | 2 + 10 files changed, 232 insertions(+), 172 deletions(-) create mode 100644 SSignalKit/SThreadPoolQueue.h create mode 100644 SSignalKit/SThreadPoolQueue.m create mode 100644 SSignalKit/SThreadPoolTask.h create mode 100644 SSignalKit/SThreadPoolTask.m diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 0633d6faa2..f9d10025eb 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -80,6 +80,10 @@ D087632A1A839EDC00632240 /* SDisposableSet.h in Headers */ = {isa = PBXBuildFile; fileRef = D08763281A839EDC00632240 /* SDisposableSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D08763291A839EDC00632240 /* SDisposableSet.m */; }; D087632C1A839EE800632240 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D08763291A839EDC00632240 /* SDisposableSet.m */; }; + D089E0311AC48EA7009A744B /* SThreadPoolTask.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */; }; + D089E0321AC48EA7009A744B /* SThreadPoolQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */; }; + D089E0331AC48EA7009A744B /* SThreadPoolQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D089E02F1AC48EA7009A744B /* SThreadPoolQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D089E0341AC48EA7009A744B /* SThreadPoolTask.h in Headers */ = {isa = PBXBuildFile; fileRef = D089E0301AC48EA7009A744B /* SThreadPoolTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -161,6 +165,10 @@ D06F10721A85882000485185 /* SSignalPerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignalPerformanceTests.m; sourceTree = ""; }; D08763281A839EDC00632240 /* SDisposableSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposableSet.h; sourceTree = ""; }; D08763291A839EDC00632240 /* SDisposableSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDisposableSet.m; sourceTree = ""; }; + D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPoolTask.m; sourceTree = ""; }; + D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPoolQueue.m; sourceTree = ""; }; + D089E02F1AC48EA7009A744B /* SThreadPoolQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPoolQueue.h; sourceTree = ""; }; + D089E0301AC48EA7009A744B /* SThreadPoolTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPoolTask.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -252,6 +260,10 @@ D0445E1D1A7C2D7300267924 /* SSubscriber.m */, D0445E1E1A7C2D7300267924 /* SThreadPool.h */, D0445E1F1A7C2D7300267924 /* SThreadPool.m */, + D089E02F1AC48EA7009A744B /* SThreadPoolQueue.h */, + D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */, + D089E0301AC48EA7009A744B /* SThreadPoolTask.h */, + D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */, D0445E4C1A7C2D8A00267924 /* SQueue.h */, D0445E4D1A7C2D8A00267924 /* SQueue.m */, D0445E521A7C2E9D00267924 /* STimer.h */, @@ -301,9 +313,11 @@ D0445E481A7C2D7300267924 /* SSubscriber.h in Headers */, D0445E2E1A7C2D7300267924 /* SMulticastSignalManager.h in Headers */, D0445E271A7C2D7300267924 /* SBlockDisposable.h in Headers */, + D089E0331AC48EA7009A744B /* SThreadPoolQueue.h in Headers */, D0445E4A1A7C2D7300267924 /* SThreadPool.h in Headers */, D0445E541A7C2E9D00267924 /* STimer.h in Headers */, D0445E301A7C2D7300267924 /* SSignal.h in Headers */, + D089E0341AC48EA7009A744B /* SThreadPoolTask.h in Headers */, D0445E321A7C2D7300267924 /* SSignal+Accumulate.h in Headers */, D0445E361A7C2D7300267924 /* SSignal+Combine.h in Headers */, D0445E2A1A7C2D7300267924 /* SDisposable.h in Headers */, @@ -449,6 +463,7 @@ D0445E241A7C2D7300267924 /* SAtomic.m in Sources */, D0445E4B1A7C2D7300267924 /* SThreadPool.m in Sources */, D0445E551A7C2E9D00267924 /* STimer.m in Sources */, + D089E0321AC48EA7009A744B /* SThreadPoolQueue.m in Sources */, D0445E3D1A7C2D7300267924 /* SSignal+Mapping.m in Sources */, D0445E351A7C2D7300267924 /* SSignal+Catch.m in Sources */, D0445E411A7C2D7300267924 /* SSignal+Multicast.m in Sources */, @@ -458,6 +473,7 @@ D0445E471A7C2D7300267924 /* SSignal+Timing.m in Sources */, D0445E311A7C2D7300267924 /* SSignal.m in Sources */, D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */, + D089E0311AC48EA7009A744B /* SThreadPoolTask.m in Sources */, D0445E491A7C2D7300267924 /* SSubscriber.m in Sources */, D0445E431A7C2D7300267924 /* SSignal+SideEffects.m in Sources */, D0445E3F1A7C2D7300267924 /* SSignal+Meta.m in Sources */, diff --git a/SSignalKit/SSignal+Dispatch.m b/SSignalKit/SSignal+Dispatch.m index b23337e3fa..2a72201ae4 100644 --- a/SSignalKit/SSignal+Dispatch.m +++ b/SSignalKit/SSignal+Dispatch.m @@ -35,40 +35,31 @@ { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - SAtomic *atomicLastTask = [[SAtomic alloc] initWithValue:nil]; + SThreadPoolQueue *queue = [threadPool nextQueue]; return [self startWithNext:^(id next) { - SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) + SThreadPoolTask *task = [[SThreadPoolTask alloc] initWithBlock:^(bool (^cancelled)()) { if (!cancelled()) [subscriber putNext:next]; }]; - SThreadPoolTask *lastTask = [atomicLastTask swap:task]; - if (lastTask != nil) - [task addDependency:lastTask]; - [threadPool startTask:task]; + [queue addTask:task]; } error:^(id error) { - SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) + SThreadPoolTask *task = [[SThreadPoolTask alloc] initWithBlock:^(bool (^cancelled)()) { if (!cancelled()) [subscriber putError:error]; }]; - SThreadPoolTask *lastTask = [atomicLastTask swap:task]; - if (lastTask != nil) - [task addDependency:lastTask]; - [threadPool startTask:task]; + [queue addTask:task]; } completed:^ { - SThreadPoolTask *task = [threadPool prepareTask:^(bool (^cancelled)()) + SThreadPoolTask *task = [[SThreadPoolTask alloc] initWithBlock:^(bool (^cancelled)()) { if (!cancelled()) [subscriber putCompletion]; }]; - SThreadPoolTask *lastTask = [atomicLastTask swap:task]; - if (lastTask != nil) - [task addDependency:lastTask]; - [threadPool startTask:task]; + [queue addTask:task]; }]; }]; } @@ -111,7 +102,7 @@ { SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; - id taskId = [threadPool addTask:^(bool (^cancelled)()) + SThreadPoolTask *task = [[SThreadPoolTask alloc] initWithBlock:^(bool (^cancelled)()) { if (cancelled && cancelled()) return; @@ -130,9 +121,11 @@ [disposable setDisposable:[[SBlockDisposable alloc] initWithBlock:^ { - [threadPool cancelTask:taskId]; + [task cancel]; }]]; + [threadPool addTask:task]; + return disposable; }]; } diff --git a/SSignalKit/SSignal.m b/SSignalKit/SSignal.m index 1cae763a69..8c7d52d877 100644 --- a/SSignalKit/SSignal.m +++ b/SSignalKit/SSignal.m @@ -2,6 +2,35 @@ #import "SBlockDisposable.h" +@interface SSubscriberDisposable : NSObject +{ + SSubscriber *_subscriber; + id _disposable; +} + +@end + +@implementation SSubscriberDisposable + +- (instancetype)initWithSubscriber:(SSubscriber *)subscriber disposable:(id)disposable +{ + self = [super init]; + if (self != nil) + { + _subscriber = subscriber; + _disposable = disposable; + } + return self; +} + +- (void)dispose +{ + [_subscriber _markTerminatedWithoutDisposal]; + [_disposable dispose]; +} + +@end + @interface SSignal () { } @@ -25,11 +54,7 @@ SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:error completed:completed]; id disposable = _generator(subscriber); [subscriber _assignDisposable:disposable]; - return [[SBlockDisposable alloc] initWithBlock:^ - { - [subscriber _markTerminatedWithoutDisposal]; - [disposable dispose]; - }]; + return [[SSubscriberDisposable alloc] initWithSubscriber:subscriber disposable:disposable]; } - (id)startWithNext:(void (^)(id next))next @@ -37,7 +62,7 @@ SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:nil completed:nil]; id disposable = _generator(subscriber); [subscriber _assignDisposable:disposable]; - return subscriber; + return [[SSubscriberDisposable alloc] initWithSubscriber:subscriber disposable:disposable]; } - (id)startWithNext:(void (^)(id next))next completed:(void (^)())completed @@ -45,7 +70,7 @@ SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:nil completed:completed]; id disposable = _generator(subscriber); [subscriber _assignDisposable:disposable]; - return subscriber; + return [[SSubscriberDisposable alloc] initWithSubscriber:subscriber disposable:disposable]; } @end diff --git a/SSignalKit/SThreadPool.h b/SSignalKit/SThreadPool.h index f2342081f7..69d0565938 100644 --- a/SSignalKit/SThreadPool.h +++ b/SSignalKit/SThreadPool.h @@ -1,18 +1,15 @@ #import -@interface SThreadPoolTask : NSObject - -- (void)addDependency:(SThreadPoolTask *)task; - -@end +#import +#import @interface SThreadPool : NSObject - (instancetype)initWithThreadCount:(NSUInteger)threadCount threadPriority:(double)threadPriority; -- (id)addTask:(void (^)(bool (^)()))task; -- (SThreadPoolTask *)prepareTask:(void (^)(bool (^)()))task; -- (id)startTask:(SThreadPoolTask *)task; -- (void)cancelTask:(id)taskId; +- (void)addTask:(SThreadPoolTask *)task; + +- (SThreadPoolQueue *)nextQueue; +- (void)_workOnQueue:(SThreadPoolQueue *)queue block:(void (^)())block; @end diff --git a/SSignalKit/SThreadPool.m b/SSignalKit/SThreadPool.m index b39ef64da3..060ee29c92 100644 --- a/SSignalKit/SThreadPool.m +++ b/SSignalKit/SThreadPool.m @@ -4,82 +4,13 @@ #import #import "SQueue.h" -@class SThreadPoolOperation; - -@interface SThreadPoolTask () - -@property (nonatomic, strong, readonly) SThreadPoolOperation *operation; - -- (instancetype)initWithOperation:(SThreadPoolOperation *)operation; - -@end - -@interface SThreadPoolOperationCanelledHolder : NSObject -{ - @public - volatile bool _cancelled; -} - -@property (nonatomic, weak) SThreadPoolOperation *operation; - -@end - -@implementation SThreadPoolOperationCanelledHolder - -@end - -@interface SThreadPoolOperation : NSOperation -{ - void (^_block)(bool (^)()); -} - -@property (nonatomic, strong, readonly) SThreadPoolOperationCanelledHolder *cancelledHolder; - -@end - -@implementation SThreadPoolOperation - -- (instancetype)initWithBlock:(void (^)(bool (^)()))block -{ - self = [super init]; - if (self != nil) - { - _block = [block copy]; - _cancelledHolder = [[SThreadPoolOperationCanelledHolder alloc] init]; - _cancelledHolder.operation = self; - } - return self; -} - -- (void)main -{ - if (!_cancelledHolder->_cancelled) - { - SThreadPoolOperationCanelledHolder *cancelledHolder = _cancelledHolder; - _block(^bool - { - return cancelledHolder->_cancelled; - }); - } -} - -- (void)cancel -{ - _cancelledHolder->_cancelled = true; -} - -- (BOOL)isCancelled -{ - return _cancelledHolder->_cancelled; -} - -@end - @interface SThreadPool () { SQueue *_managementQueue; NSMutableArray *_threads; - NSMutableArray *_operations; + + NSMutableArray *_queues; + NSMutableArray *_takenQueues; pthread_mutex_t _mutex; pthread_cond_t _cond; @@ -91,39 +22,42 @@ + (void)threadEntryPoint:(SThreadPool *)threadPool { + SThreadPoolQueue *queue = nil; + while (true) { - SThreadPoolOperation *operation = nil; + SThreadPoolTask *task = nil; pthread_mutex_lock(&threadPool->_mutex); + + if (queue != nil) + { + [threadPool->_takenQueues removeObject:queue]; + if ([queue _hasTasks]) + [threadPool->_queues addObject:queue]; + } + while (true) { - while (threadPool->_operations.count == 0) + while (threadPool->_queues.count == 0) pthread_cond_wait(&threadPool->_cond, &threadPool->_mutex); - for (NSUInteger index = 0; index < threadPool->_operations.count; index++) - { - SThreadPoolOperation *maybeOperation = threadPool->_operations[index]; - if ([maybeOperation isCancelled]) - { - [threadPool->_operations removeObjectAtIndex:index]; - index--; - } - else if ([maybeOperation isReady]) - { - operation = maybeOperation; - [threadPool->_operations removeObjectAtIndex:index]; - break; - } - } + + queue = threadPool->_queues.firstObject; + task = [queue _popFirstTask]; + + if (queue != nil) + { + [threadPool->_takenQueues addObject:queue]; + [threadPool->_queues removeObjectAtIndex:0]; - if (operation != nil) break; + } } pthread_mutex_unlock(&threadPool->_mutex); @autoreleasepool { - [operation main]; + [task execute]; } } } @@ -146,7 +80,8 @@ [_managementQueue dispatch:^ { _threads = [[NSMutableArray alloc] init]; - _operations = [[NSMutableArray alloc] init]; + _queues = [[NSMutableArray alloc] init]; + _takenQueues = [[NSMutableArray alloc] init]; for (NSUInteger i = 0; i < threadCount; i++) { NSThread *thread = [[NSThread alloc] initWithTarget:[SThreadPool class] selector:@selector(threadEntryPoint:) object:self]; @@ -166,62 +101,28 @@ pthread_cond_destroy(&_cond); } -- (void)_addOperation:(SThreadPoolOperation *)operation +- (void)addTask:(SThreadPoolTask *)task { - pthread_mutex_lock(&_mutex); - [_operations addObject:operation]; - pthread_cond_signal(&_cond); - pthread_mutex_unlock(&_mutex); + SThreadPoolQueue *tempQueue = [self nextQueue]; + [tempQueue addTask:task]; } -- (id)addTask:(void (^)(bool (^)()))task +- (SThreadPoolQueue *)nextQueue { - SThreadPoolOperation *operation = [[SThreadPoolOperation alloc] initWithBlock:task]; - [_managementQueue dispatch:^ - { - [self _addOperation:operation]; - }]; - return operation.cancelledHolder; + return [[SThreadPoolQueue alloc] initWithThreadPool:self]; } -- (SThreadPoolTask *)prepareTask:(void (^)(bool (^)()))task -{ - SThreadPoolOperation *operation = [[SThreadPoolOperation alloc] initWithBlock:task]; - return [[SThreadPoolTask alloc] initWithOperation:operation]; -} - -- (id)startTask:(SThreadPoolTask *)task +- (void)_workOnQueue:(SThreadPoolQueue *)queue block:(void (^)())block { [_managementQueue dispatch:^ { - [self _addOperation:task.operation]; + pthread_mutex_lock(&_mutex); + block(); + if (![_queues containsObject:queue] && ![_takenQueues containsObject:queue]) + [_queues addObject:queue]; + pthread_cond_broadcast(&_cond); + pthread_mutex_unlock(&_mutex); }]; - return task.operation.cancelledHolder; -} - -- (void)cancelTask:(id)taskId -{ - if (taskId != nil) - ((SThreadPoolOperationCanelledHolder *)taskId)->_cancelled = true; -} - -@end - -@implementation SThreadPoolTask - -- (instancetype)initWithOperation:(SThreadPoolOperation *)operation -{ - self = [super init]; - if (self != nil) - { - _operation = operation; - } - return self; -} - -- (void)addDependency:(SThreadPoolTask *)task -{ - [_operation addDependency:task->_operation]; } @end diff --git a/SSignalKit/SThreadPoolQueue.h b/SSignalKit/SThreadPoolQueue.h new file mode 100644 index 0000000000..3d8d53b00c --- /dev/null +++ b/SSignalKit/SThreadPoolQueue.h @@ -0,0 +1,13 @@ +#import + +@class SThreadPool; +@class SThreadPoolTask; + +@interface SThreadPoolQueue : NSObject + +- (instancetype)initWithThreadPool:(SThreadPool *)threadPool; +- (void)addTask:(SThreadPoolTask *)task; +- (SThreadPoolTask *)_popFirstTask; +- (bool)_hasTasks; + +@end diff --git a/SSignalKit/SThreadPoolQueue.m b/SSignalKit/SThreadPoolQueue.m new file mode 100644 index 0000000000..ff857e642d --- /dev/null +++ b/SSignalKit/SThreadPoolQueue.m @@ -0,0 +1,51 @@ +#import "SThreadPoolQueue.h" + +#import "SThreadPool.h" + +@interface SThreadPoolQueue () +{ + __weak SThreadPool *_threadPool; + NSMutableArray *_tasks; +} + +@end + +@implementation SThreadPoolQueue + +- (instancetype)initWithThreadPool:(SThreadPool *)threadPool +{ + self = [super init]; + if (self != nil) + { + _threadPool = threadPool; + _tasks = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)addTask:(SThreadPoolTask *)task +{ + SThreadPool *threadPool = _threadPool; + [threadPool _workOnQueue:self block:^ + { + [_tasks addObject:task]; + }]; +} + +- (SThreadPoolTask *)_popFirstTask +{ + if (_tasks.count != 0) + { + SThreadPoolTask *task = _tasks[0]; + [_tasks removeObjectAtIndex:0]; + return task; + } + return nil; +} + +- (bool)_hasTasks +{ + return _tasks.count != 0; +} + +@end diff --git a/SSignalKit/SThreadPoolTask.h b/SSignalKit/SThreadPoolTask.h new file mode 100644 index 0000000000..e8da985ca0 --- /dev/null +++ b/SSignalKit/SThreadPoolTask.h @@ -0,0 +1,9 @@ +#import + +@interface SThreadPoolTask : NSObject + +- (instancetype)initWithBlock:(void (^)(bool (^)()))block; +- (void)execute; +- (void)cancel; + +@end diff --git a/SSignalKit/SThreadPoolTask.m b/SSignalKit/SThreadPoolTask.m new file mode 100644 index 0000000000..c967022e01 --- /dev/null +++ b/SSignalKit/SThreadPoolTask.m @@ -0,0 +1,53 @@ +#import "SThreadPoolTask.h" + +@interface SThreadPoolTaskState : NSObject +{ + @public + bool _cancelled; +} + +@end + +@implementation SThreadPoolTaskState + +@end + +@interface SThreadPoolTask () +{ + void (^_block)(bool (^)()); + SThreadPoolTaskState *_state; +} + +@end + +@implementation SThreadPoolTask + +- (instancetype)initWithBlock:(void (^)(bool (^)()))block +{ + self = [super init]; + if (self != nil) + { + _block = [block copy]; + _state = [[SThreadPoolTaskState alloc] init]; + } + return self; +} + +- (void)execute +{ + if (_state->_cancelled) + return; + + SThreadPoolTaskState *state = _state; + _block(^bool + { + return state->_cancelled; + }); +} + +- (void)cancel +{ + _state->_cancelled = true; +} + +@end diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index be66425d44..abe09c87a1 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -216,6 +216,7 @@ { dispatch_async(queue, ^ { + usleep(100); [subscriber putNext:@1]; }); @@ -229,6 +230,7 @@ { generated = true; } error:nil completed:nil]; + NSLog(@"dispose"); [disposable dispose]; } From 3063af4af92c3c0bfb73df236dbfb76477ba3c0f Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 27 Mar 2015 13:24:26 +0300 Subject: [PATCH 012/122] no message --- SSignalKit/SSignalKit.h | 1 - 1 file changed, 1 deletion(-) diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h index 8ff93bc31c..3021283400 100644 --- a/SSignalKit/SSignalKit.h +++ b/SSignalKit/SSignalKit.h @@ -29,7 +29,6 @@ FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; #import #import #import -#import #import #import #import From a69c37fb74d32c01e713fb94d7b953847ef12424 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 27 Mar 2015 13:34:00 +0300 Subject: [PATCH 013/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index f9d10025eb..de10beaad9 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -84,6 +84,8 @@ D089E0321AC48EA7009A744B /* SThreadPoolQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */; }; D089E0331AC48EA7009A744B /* SThreadPoolQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D089E02F1AC48EA7009A744B /* SThreadPoolQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; D089E0341AC48EA7009A744B /* SThreadPoolTask.h in Headers */ = {isa = PBXBuildFile; fileRef = D089E0301AC48EA7009A744B /* SThreadPoolTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D089E0391AC56981009A744B /* SThreadPoolQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */; }; + D089E03A1AC56981009A744B /* SThreadPoolTask.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -502,6 +504,7 @@ D0445E781A7C447D00267924 /* SMetaDisposable.m in Sources */, D0445E7F1A7C447D00267924 /* SSignal+Dispatch.m in Sources */, D0445E881A7C447D00267924 /* SQueue.m in Sources */, + D089E03A1AC56981009A744B /* SThreadPoolTask.m in Sources */, D0445E741A7C447D00267924 /* SAtomic.m in Sources */, D0445E871A7C447D00267924 /* SThreadPool.m in Sources */, D0445E891A7C447D00267924 /* STimer.m in Sources */, @@ -510,6 +513,7 @@ D0445E821A7C447D00267924 /* SSignal+Multicast.m in Sources */, D0445E771A7C447D00267924 /* SEvent.m in Sources */, D0445E751A7C447D00267924 /* SBag.m in Sources */, + D089E0391AC56981009A744B /* SThreadPoolQueue.m in Sources */, D0445E7B1A7C447D00267924 /* SSignal+Accumulate.m in Sources */, D0445E851A7C447D00267924 /* SSignal+Timing.m in Sources */, D0445E7A1A7C447D00267924 /* SSignal.m in Sources */, From f94fc005a7df29d2d12c3242a046b522a5db91a6 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 3 Apr 2015 23:26:54 +0300 Subject: [PATCH 014/122] switchToLatest + tests --- SSignalKit/SSignal+Meta.m | 113 +++++++++++++++---- SSignalKit/SSubscriber.m | 5 +- SSignalKitTests/SSignalBasicTests.m | 167 +++++++++++++++++++++++++++- 3 files changed, 261 insertions(+), 24 deletions(-) diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 0adc4846ab..16ccfd7069 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -5,41 +5,114 @@ #import "SSignal+Mapping.h" #import "SAtomic.h" +#import + +@interface SSignalSwitchToLatestState : NSObject +{ + OSSpinLock _lock; + bool _didSwitch; + bool _terminated; + + id _disposable; + SMetaDisposable *_currentDisposable; + SSubscriber *_subscriber; +} + +@end + +@implementation SSignalSwitchToLatestState + +- (instancetype)initWithSubscriber:(SSubscriber *)subscriber +{ + self = [super init]; + if (self != nil) + { + _subscriber = subscriber; + _currentDisposable = [[SMetaDisposable alloc] init]; + } + return self; +} + +- (void)beginWithDisposable:(id)disposable +{ + _disposable = disposable; +} + +- (void)switchToSignal:(SSignal *)signal +{ + OSSpinLockLock(&_lock); + _didSwitch = true; + OSSpinLockUnlock(&_lock); + + id disposable = [signal startWithNext:^(id next) + { + [_subscriber putNext:next]; + } error:^(id error) + { + [_subscriber putError:error]; + } completed:^ + { + OSSpinLockLock(&_lock); + _didSwitch = false; + OSSpinLockUnlock(&_lock); + + [self maybeComplete]; + }]; + + [_currentDisposable setDisposable:disposable]; +} + +- (void)maybeComplete +{ + bool terminated = false; + OSSpinLockLock(&_lock); + terminated = _terminated; + OSSpinLockUnlock(&_lock); + + if (terminated) + [_subscriber putCompletion]; +} + +- (void)beginCompletion +{ + bool didSwitch = false; + OSSpinLockLock(&_lock); + didSwitch = _didSwitch; + _terminated = true; + OSSpinLockUnlock(&_lock); + + if (!didSwitch) + [_subscriber putCompletion]; +} + +- (void)dispose +{ + [_disposable dispose]; + [_currentDisposable dispose]; +} + +@end + @implementation SSignal (Meta) - (SSignal *)switchToLatest { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + SSignalSwitchToLatestState *state = [[SSignalSwitchToLatestState alloc] initWithSubscriber:subscriber]; - SMetaDisposable *currentDisposable = [[SMetaDisposable alloc] init]; - [compositeDisposable add:currentDisposable]; - - SAtomic *didProduceNext = [[SAtomic alloc] initWithValue:nil]; - [compositeDisposable add:[self startWithNext:^(SSignal *next) + [state beginWithDisposable:[self startWithNext:^(id next) { - [didProduceNext swap:@1]; - [currentDisposable setDisposable:[next startWithNext:^(id next) - { - [subscriber putNext:next]; - } error:^(id error) - { - [subscriber putError:error]; - } completed:^ - { - [subscriber putCompletion]; - }]]; + [state switchToSignal:next]; } error:^(id error) { [subscriber putError:error]; } completed:^ { - if ([didProduceNext swap:@1] == NULL) - [subscriber putCompletion]; + [state beginCompletion]; }]]; - return compositeDisposable; + return state; }]; } diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index ef5979d5db..9c0e26cb5a 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -27,7 +27,10 @@ - (void)_assignDisposable:(id)disposable { - _disposable = disposable; + if (_terminated) + [disposable dispose]; + else + _disposable = disposable; } - (void)_markTerminatedWithoutDisposal diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index abe09c87a1..e4d871b348 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -179,15 +179,15 @@ SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { [subscriber putNext:@1]; - [object description]; + __unused id a0 = [object description]; return [[SBlockDisposable alloc] initWithBlock:^ { - [object description]; + __unused id a1 = [object description]; disposed = true; }]; }] _mapInplace:^id(id value) { - [object description]; + __unused id a1 = [object description]; return @([value intValue] * 2); }]; @@ -242,4 +242,165 @@ XCTAssertFalse(generated); } +- (void)testThen +{ + __block bool generatedFirst = false; + __block bool disposedFirst = false; + __block bool generatedSecond = false; + __block bool disposedSecond = false; + __block int result = 0; + + SSignal *signal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + generatedFirst = true; + [subscriber putNext:@(1)]; + [subscriber putCompletion]; + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedFirst = true; + }]; + }]; + + signal = [signal then:[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + generatedSecond = true; + [subscriber putNext:@(2)]; + [subscriber putCompletion]; + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedSecond = true; + }]; + }]]; + + [signal startWithNext:^(id next) + { + result += [next intValue]; + }]; + + XCTAssertTrue(generatedFirst); + XCTAssertTrue(disposedFirst); + XCTAssertTrue(generatedSecond); + XCTAssertTrue(disposedSecond); + XCTAssert(result == 3); +} + +- (void)testSwitchToLatest +{ + __block int result = 0; + __block bool disposedOne = false; + __block bool disposedTwo = false; + __block bool disposedThree = false; + __block bool completedAll = false; + + bool deallocatedOne = false; + bool deallocatedTwo = false; + bool deallocatedThree = false; + + @autoreleasepool + { + DeallocatingObject *objectOne = [[DeallocatingObject alloc] initWithDeallocated:&deallocatedOne]; + DeallocatingObject *objectTwo = [[DeallocatingObject alloc] initWithDeallocated:&deallocatedTwo]; + DeallocatingObject *objectThree = [[DeallocatingObject alloc] initWithDeallocated:&deallocatedThree]; + + SSignal *one = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@(1)]; + [subscriber putCompletion]; + __unused id a0 = [objectOne description]; + return [[SBlockDisposable alloc] initWithBlock:^ + { + __unused id a0 = [objectOne description]; + disposedOne = true; + }]; + }]; + SSignal *two = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@(2)]; + [subscriber putCompletion]; + __unused id a1 = [objectTwo description]; + return [[SBlockDisposable alloc] initWithBlock:^ + { + __unused id a1 = [objectOne description]; + disposedTwo = true; + }]; + }]; + SSignal *three = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putNext:@(3)]; + [subscriber putCompletion]; + __unused id a0 = [objectThree description]; + return [[SBlockDisposable alloc] initWithBlock:^ + { + __unused id a1 = [objectOne description]; + disposedThree = true; + }]; + }]; + + SSignal *signal = [[[[SSignal single:one] then:[SSignal single:two]] then:[SSignal single:three]] switchToLatest]; + [signal startWithNext:^(id next) + { + result += [next intValue]; + } error:nil completed:^ + { + completedAll = true; + }]; + } + + XCTAssert(result == 6); + XCTAssertTrue(disposedOne); + XCTAssertTrue(disposedTwo); + XCTAssertTrue(disposedThree); + XCTAssertTrue(deallocatedOne); + XCTAssertTrue(deallocatedTwo); + XCTAssertTrue(deallocatedThree); + XCTAssertTrue(completedAll); +} + +- (void)testSwitchToLatestError +{ + __block bool errorGenerated = false; + + SSignal *one = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putError:nil]; + return nil; + }]; + + [one startWithNext:^(__unused id next) + { + + } error:^(__unused id error) + { + errorGenerated = true; + } completed:^ + { + + }]; + + XCTAssertTrue(errorGenerated); +} + +- (void)testSwitchToLatestCompleted +{ + __block bool completedAll = false; + + SSignal *one = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [subscriber putCompletion]; + return nil; + }]; + + [one startWithNext:^(__unused id next) + { + + } error:^(__unused id error) + { + } completed:^ + { + completedAll = true; + }]; + + XCTAssertTrue(completedAll); +} + @end From f277fa204d19d9d80d519bb8180fce2b5ebab66c Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 6 Apr 2015 16:48:20 +0200 Subject: [PATCH 015/122] Added timeout --- SSignalKit/SSignal+Timing.h | 1 + SSignalKit/SSignal+Timing.m | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/SSignalKit/SSignal+Timing.h b/SSignalKit/SSignal+Timing.h index 0d07dbbcb1..6bf464c8b7 100644 --- a/SSignalKit/SSignal+Timing.h +++ b/SSignalKit/SSignal+Timing.h @@ -5,5 +5,6 @@ @interface SSignal (Timing) - (SSignal *)delay:(NSTimeInterval)seconds onQueue:(SQueue *)queue; +- (SSignal *)timeout:(NSTimeInterval)seconds onQueue:(SQueue *)queue or:(SSignal *)signal; @end diff --git a/SSignalKit/SSignal+Timing.m b/SSignalKit/SSignal+Timing.m index ee002fccf1..f1a47fc155 100644 --- a/SSignalKit/SSignal+Timing.m +++ b/SSignalKit/SSignal+Timing.m @@ -1,6 +1,7 @@ #import "SSignal+Timing.h" #import "SMetaDisposable.h" +#import "SDisposableSet.h" #import "SBlockDisposable.h" #import "STimer.h" @@ -38,4 +39,43 @@ }]; } +- (SSignal *)timeout:(NSTimeInterval)seconds onQueue:(SQueue *)queue or:(SSignal *)signal +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; + + STimer *timer = [[STimer alloc] initWithTimeout:seconds repeat:false completion:^ + { + [disposable setDisposable:[signal startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]]; + } queue:queue]; + [timer start]; + + [disposable setDisposable:[self startWithNext:^(id next) + { + [timer invalidate]; + [subscriber putNext:next]; + } error:^(id error) + { + [timer invalidate]; + [subscriber putError:error]; + } completed:^ + { + [timer invalidate]; + [subscriber putCompletion]; + }]]; + + return disposable; + }]; +} + @end From 09f93bc4ee71ea6ab7759d018feac90d3032711a Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 6 Apr 2015 17:04:16 +0200 Subject: [PATCH 016/122] operator change --- SSignalKit/SSignal+Timing.h | 2 +- SSignalKit/SSignal+Timing.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SSignalKit/SSignal+Timing.h b/SSignalKit/SSignal+Timing.h index 6bf464c8b7..beadb39fd4 100644 --- a/SSignalKit/SSignal+Timing.h +++ b/SSignalKit/SSignal+Timing.h @@ -5,6 +5,6 @@ @interface SSignal (Timing) - (SSignal *)delay:(NSTimeInterval)seconds onQueue:(SQueue *)queue; -- (SSignal *)timeout:(NSTimeInterval)seconds onQueue:(SQueue *)queue or:(SSignal *)signal; +- (SSignal *)timeout:(NSTimeInterval)seconds onQueue:(SQueue *)queue orSignal:(SSignal *)signal; @end diff --git a/SSignalKit/SSignal+Timing.m b/SSignalKit/SSignal+Timing.m index f1a47fc155..0b15ea4f5a 100644 --- a/SSignalKit/SSignal+Timing.m +++ b/SSignalKit/SSignal+Timing.m @@ -39,7 +39,7 @@ }]; } -- (SSignal *)timeout:(NSTimeInterval)seconds onQueue:(SQueue *)queue or:(SSignal *)signal +- (SSignal *)timeout:(NSTimeInterval)seconds onQueue:(SQueue *)queue orSignal:(SSignal *)signal { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { From 9eb975aa472baf4d7ac88d7291b28549735301cf Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 7 Apr 2015 01:21:08 +0200 Subject: [PATCH 017/122] delay start fix --- SSignalKit/SSignal+Timing.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SSignalKit/SSignal+Timing.m b/SSignalKit/SSignal+Timing.m index 0b15ea4f5a..09e1bfad1e 100644 --- a/SSignalKit/SSignal+Timing.m +++ b/SSignalKit/SSignal+Timing.m @@ -28,13 +28,13 @@ }]]; } queue:queue]; + [timer start]; + [disposable setDisposable:[[SBlockDisposable alloc] initWithBlock:^ { [timer invalidate]; }]]; - [timer start]; - return disposable; }]; } From 6a06af76cbe0fc674bc7d0e0031a732d9da65c3b Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 10 Apr 2015 17:02:40 +0300 Subject: [PATCH 018/122] no message --- SSignalKit/SSignal+Meta.h | 3 + SSignalKit/SSignal+Meta.m | 120 ++++++++++--- SSignalKit/SSignal+Timing.h | 1 + SSignalKit/SSignal+Timing.m | 28 +++ SSignalKitTests/SSignalBasicTests.m | 254 +++++++++++++++++++++++++++- 5 files changed, 378 insertions(+), 28 deletions(-) diff --git a/SSignalKit/SSignal+Meta.h b/SSignalKit/SSignal+Meta.h index a9ab8c6a7c..2400695ad9 100644 --- a/SSignalKit/SSignal+Meta.h +++ b/SSignalKit/SSignal+Meta.h @@ -1,9 +1,12 @@ #import "SSignal.h" +@class SQueue; + @interface SSignal (Meta) - (SSignal *)switchToLatest; - (SSignal *)mapToSignal:(SSignal *(^)(id))f; - (SSignal *)then:(SSignal *)signal; +- (SSignal *)queue; @end diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 16ccfd7069..79c0652c92 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -7,28 +7,34 @@ #import -@interface SSignalSwitchToLatestState : NSObject +@interface SSignalQueueState : NSObject { OSSpinLock _lock; - bool _didSwitch; + bool _executingSignal; bool _terminated; id _disposable; SMetaDisposable *_currentDisposable; SSubscriber *_subscriber; + + NSMutableArray *_queuedSignals; + bool _queueMode; + } @end -@implementation SSignalSwitchToLatestState +@implementation SSignalQueueState -- (instancetype)initWithSubscriber:(SSubscriber *)subscriber +- (instancetype)initWithSubscriber:(SSubscriber *)subscriber queueMode:(bool)queueMode { self = [super init]; if (self != nil) { _subscriber = subscriber; _currentDisposable = [[SMetaDisposable alloc] init]; + _queuedSignals = queueMode ? [[NSMutableArray alloc] init] : nil; + _queueMode = queueMode; } return self; } @@ -38,50 +44,89 @@ _disposable = disposable; } -- (void)switchToSignal:(SSignal *)signal +- (void)enqueueSignal:(SSignal *)signal { + bool startSignal = false; OSSpinLockLock(&_lock); - _didSwitch = true; + if (_queueMode && _executingSignal) + { + [_queuedSignals addObject:signal]; + } + else + { + _executingSignal = true; + startSignal = true; + } OSSpinLockUnlock(&_lock); - id disposable = [signal startWithNext:^(id next) + if (startSignal) { - [_subscriber putNext:next]; - } error:^(id error) - { - [_subscriber putError:error]; - } completed:^ - { - OSSpinLockLock(&_lock); - _didSwitch = false; - OSSpinLockUnlock(&_lock); + id disposable = [signal startWithNext:^(id next) + { + [_subscriber putNext:next]; + } error:^(id error) + { + [_subscriber putError:error]; + } completed:^ + { + [self headCompleted]; + }]; - [self maybeComplete]; - }]; - - [_currentDisposable setDisposable:disposable]; + [_currentDisposable setDisposable:disposable]; + } } -- (void)maybeComplete +- (void)headCompleted { + SSignal *nextSignal = nil; + bool terminated = false; OSSpinLockLock(&_lock); - terminated = _terminated; + _executingSignal = false; + + if (_queueMode) + { + if (_queuedSignals.count != 0) + { + nextSignal = _queuedSignals[0]; + [_queuedSignals removeObjectAtIndex:0]; + _executingSignal = true; + } + else + terminated = _terminated; + } + else + terminated = _terminated; OSSpinLockUnlock(&_lock); if (terminated) [_subscriber putCompletion]; + else if (nextSignal != nil) + { + id disposable = [nextSignal startWithNext:^(id next) + { + [_subscriber putNext:next]; + } error:^(id error) + { + [_subscriber putError:error]; + } completed:^ + { + [self headCompleted]; + }]; + + [_currentDisposable setDisposable:disposable]; + } } - (void)beginCompletion { - bool didSwitch = false; + bool executingSignal = false; OSSpinLockLock(&_lock); - didSwitch = _didSwitch; + executingSignal = _executingSignal; _terminated = true; OSSpinLockUnlock(&_lock); - if (!didSwitch) + if (!executingSignal) [_subscriber putCompletion]; } @@ -99,11 +144,11 @@ { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) { - SSignalSwitchToLatestState *state = [[SSignalSwitchToLatestState alloc] initWithSubscriber:subscriber]; + SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:false]; [state beginWithDisposable:[self startWithNext:^(id next) { - [state switchToSignal:next]; + [state enqueueSignal:next]; } error:^(id error) { [subscriber putError:error]; @@ -154,4 +199,25 @@ }]; } +- (SSignal *)queue +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:true]; + + [state beginWithDisposable:[self startWithNext:^(id next) + { + [state enqueueSignal:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [state beginCompletion]; + }]]; + + return state; + }]; +} + @end diff --git a/SSignalKit/SSignal+Timing.h b/SSignalKit/SSignal+Timing.h index beadb39fd4..68c0fe6ca8 100644 --- a/SSignalKit/SSignal+Timing.h +++ b/SSignalKit/SSignal+Timing.h @@ -6,5 +6,6 @@ - (SSignal *)delay:(NSTimeInterval)seconds onQueue:(SQueue *)queue; - (SSignal *)timeout:(NSTimeInterval)seconds onQueue:(SQueue *)queue orSignal:(SSignal *)signal; +- (SSignal *)wait:(NSTimeInterval)seconds; @end diff --git a/SSignalKit/SSignal+Timing.m b/SSignalKit/SSignal+Timing.m index 09e1bfad1e..3d0dbc4a97 100644 --- a/SSignalKit/SSignal+Timing.m +++ b/SSignalKit/SSignal+Timing.m @@ -4,6 +4,8 @@ #import "SDisposableSet.h" #import "SBlockDisposable.h" +#import "SSignal+Dispatch.h" + #import "STimer.h" @implementation SSignal (Timing) @@ -78,4 +80,30 @@ }]; } +- (SSignal *)wait:(NSTimeInterval)seconds +{ + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + id disposable = [self startWithNext:^(id next) + { + dispatch_semaphore_signal(semaphore); + [subscriber putNext:next]; + } error:^(id error) + { + dispatch_semaphore_signal(semaphore); + [subscriber putError:error]; + } completed:^ + { + dispatch_semaphore_signal(semaphore); + [subscriber putCompletion]; + }]; + + dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(seconds * NSEC_PER_SEC))); + + return disposable; + }]; +} + @end diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index e4d871b348..acbef9e2d1 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -216,7 +216,7 @@ { dispatch_async(queue, ^ { - usleep(100); + usleep(200); [subscriber putNext:@1]; }); @@ -403,4 +403,256 @@ XCTAssertTrue(completedAll); } +- (void)testQueue +{ + dispatch_queue_t queue = dispatch_queue_create(NULL, 0); + + __block bool disposedFirst = false; + __block bool disposedSecond = false; + __block bool disposedThird = false; + __block int result = 0; + + SSignal *firstSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + dispatch_async(queue, ^ + { + usleep(100); + [subscriber putNext:@1]; + [subscriber putCompletion]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedFirst = true; + }]; + }]; + + SSignal *secondSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + dispatch_async(queue, ^ + { + usleep(100); + [subscriber putNext:@2]; + [subscriber putCompletion]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedSecond = true; + }]; + }]; + + SSignal *thirdSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + dispatch_async(queue, ^ + { + usleep(100); + [subscriber putNext:@3]; + [subscriber putCompletion]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedThird = true; + }]; + }]; + + SSignal *signal = [[[[SSignal single:firstSignal] then:[SSignal single:secondSignal]] then:[SSignal single:thirdSignal]] queue]; + [signal startWithNext:^(id next) + { + result += [next intValue]; + }]; + + usleep(1000); + + XCTAssertEqual(result, 6); + XCTAssertTrue(disposedFirst); + XCTAssertTrue(disposedSecond); + XCTAssertTrue(disposedThird); +} + +- (void)testQueueInterrupted +{ + dispatch_queue_t queue = dispatch_queue_create(NULL, 0); + + __block bool disposedFirst = false; + __block bool disposedSecond = false; + __block bool disposedThird = false; + __block bool startedThird = false; + __block int result = 0; + + SSignal *firstSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + dispatch_async(queue, ^ + { + usleep(100); + [subscriber putNext:@1]; + [subscriber putCompletion]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedFirst = true; + }]; + }]; + + SSignal *secondSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + dispatch_async(queue, ^ + { + usleep(100); + [subscriber putNext:@2]; + [subscriber putError:nil]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedSecond = true; + }]; + }]; + + SSignal *thirdSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + startedThird = true; + + dispatch_async(queue, ^ + { + usleep(100); + [subscriber putNext:@3]; + [subscriber putCompletion]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedThird = true; + }]; + }]; + + SSignal *signal = [[[[SSignal single:firstSignal] then:[SSignal single:secondSignal]] then:[SSignal single:thirdSignal]] queue]; + [signal startWithNext:^(id next) + { + result += [next intValue]; + }]; + + usleep(1000); + + XCTAssertEqual(result, 3); + XCTAssertTrue(disposedFirst); + XCTAssertTrue(disposedSecond); + XCTAssertFalse(startedThird); + XCTAssertFalse(disposedThird); +} + +- (void)testQueueDisposed +{ + dispatch_queue_t queue = dispatch_queue_create(NULL, 0); + + __block bool disposedFirst = false; + __block bool disposedSecond = false; + __block bool disposedThird = false; + __block bool startedFirst = false; + __block bool startedSecond = false; + __block bool startedThird = false; + __block int result = 0; + + SSignal *firstSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + startedFirst = true; + + __block bool cancelled = false; + dispatch_async(queue, ^ + { + if (!cancelled) + { + usleep(100); + [subscriber putNext:@1]; + [subscriber putCompletion]; + } + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + cancelled = true; + disposedFirst = true; + }]; + }]; + + SSignal *secondSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + startedSecond = true; + + __block bool cancelled = false; + dispatch_async(queue, ^ + { + if (!cancelled) + { + usleep(100); + [subscriber putNext:@2]; + [subscriber putError:nil]; + } + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + cancelled = true; + disposedSecond = true; + }]; + }]; + + SSignal *thirdSignal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + startedThird = true; + + dispatch_async(queue, ^ + { + usleep(100); + [subscriber putNext:@3]; + [subscriber putCompletion]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposedThird = true; + }]; + }]; + + SSignal *signal = [[[[SSignal single:firstSignal] then:[SSignal single:secondSignal]] then:[SSignal single:thirdSignal]] queue]; + [[signal startWithNext:^(id next) + { + result += [next intValue]; + }] dispose]; + + usleep(1000); + + XCTAssertEqual(result, 0); + XCTAssertTrue(disposedFirst); + XCTAssertFalse(disposedSecond); + XCTAssertFalse(disposedThird); + + XCTAssertTrue(startedFirst); + XCTAssertFalse(startedSecond); + XCTAssertFalse(startedThird); +} + +- (void)testWaitSameQueue +{ + SSignal *signal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + dispatch_async(dispatch_get_main_queue(), ^ + { + [subscriber putNext:@(1)]; + [subscriber putCompletion]; + }); + + return nil; + }]; + + CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent(); + [[signal wait:2.0 onQueue:[SQueue concurrentDefaultQueue]] startWithNext:^(__unused id next) + { + + }]; + XCTAssert(startTime < 0.5); +} + @end From 5cccba976ef62da0892a2ef3ab27526727ebc565 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 13 Apr 2015 19:04:33 +0300 Subject: [PATCH 019/122] no message --- SSignalKit/SSignal+Meta.h | 1 + SSignalKit/SSignal+Meta.m | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/SSignalKit/SSignal+Meta.h b/SSignalKit/SSignal+Meta.h index 2400695ad9..42c438622d 100644 --- a/SSignalKit/SSignal+Meta.h +++ b/SSignalKit/SSignal+Meta.h @@ -6,6 +6,7 @@ - (SSignal *)switchToLatest; - (SSignal *)mapToSignal:(SSignal *(^)(id))f; +- (SSignal *)mapToQueue:(SSignal *(^)(id))f; - (SSignal *)then:(SSignal *)signal; - (SSignal *)queue; diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 79c0652c92..76f411817b 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -132,8 +132,8 @@ - (void)dispose { - [_disposable dispose]; [_currentDisposable dispose]; + [_disposable dispose]; } @end @@ -166,6 +166,11 @@ return [[self map:f] switchToLatest]; } +- (SSignal *)mapToQueue:(SSignal *(^)(id))f +{ + return [[self map:f] queue]; +} + - (SSignal *)then:(SSignal *)signal { SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; From b154d7c312cbe3cba3f637e5124114b6c5f01f83 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 14 Apr 2015 02:49:00 +0300 Subject: [PATCH 020/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index de10beaad9..8d264f799c 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -633,6 +633,8 @@ 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; + ONLY_ACTIVE_ARCH = NO; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -649,6 +651,7 @@ 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_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; From 1ac3036c40f0993c24928beab561deda84e36823 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 16 Apr 2015 00:45:03 +0300 Subject: [PATCH 021/122] Added SQueue dispatchSync --- SSignalKit/SQueue.h | 1 + 1 file changed, 1 insertion(+) diff --git a/SSignalKit/SQueue.h b/SSignalKit/SQueue.h index 011aa333a1..bfc98fe157 100644 --- a/SSignalKit/SQueue.h +++ b/SSignalKit/SQueue.h @@ -9,6 +9,7 @@ + (SQueue *)wrapConcurrentNativeQueue:(dispatch_queue_t)nativeQueue; - (void)dispatch:(dispatch_block_t)block; +- (void)dispatchSync:(dispatch_block_t)block; - (dispatch_queue_t)_dispatch_queue; From bd297283cb3eaa727d4ea1b88df16743e8a7bfc8 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 17 Apr 2015 16:59:01 +0300 Subject: [PATCH 022/122] SQueue fixes reduceLeftWithPassthrough --- SSignalKit/SQueue.m | 7 ++++++- SSignalKit/SSignal+Accumulate.h | 1 + SSignalKit/SSignal+Accumulate.m | 26 ++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/SSignalKit/SQueue.m b/SSignalKit/SQueue.m index 91a7336c89..2d0c86296a 100644 --- a/SSignalKit/SQueue.m +++ b/SSignalKit/SQueue.m @@ -80,7 +80,12 @@ static const void *SQueueSpecificKey = &SQueueSpecificKey; - (void)dispatch:(dispatch_block_t)block { - dispatch_async(_queue, block); + if (_queueSpecific != NULL && dispatch_get_specific(SQueueSpecificKey) == _queueSpecific) + block(); + else if (_specialIsMainQueue && [NSThread isMainThread]) + block(); + else + dispatch_async(_queue, block); } - (void)dispatchSync:(dispatch_block_t)block diff --git a/SSignalKit/SSignal+Accumulate.h b/SSignalKit/SSignal+Accumulate.h index 55e534dbd5..9b0e8e9d47 100644 --- a/SSignalKit/SSignal+Accumulate.h +++ b/SSignalKit/SSignal+Accumulate.h @@ -3,5 +3,6 @@ @interface SSignal (Accumulate) - (SSignal *)reduceLeft:(id)value with:(id (^)(id, id))f; +- (SSignal *)reduceLeftWithPassthrough:(id)value with:(id (^)(id, id, void (^)(id)))f; @end diff --git a/SSignalKit/SSignal+Accumulate.m b/SSignalKit/SSignal+Accumulate.m index e19eda98aa..e237e204d0 100644 --- a/SSignalKit/SSignal+Accumulate.m +++ b/SSignalKit/SSignal+Accumulate.m @@ -23,4 +23,30 @@ }]; } +- (SSignal *)reduceLeftWithPassthrough:(id)value with:(id (^)(id, id, void (^)(id)))f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + __block id intermediateResult = value; + + void (^emit)(id) = ^(id next) + { + [subscriber putNext:next]; + }; + + return [self startWithNext:^(id next) + { + intermediateResult = f(intermediateResult, next, emit); + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + if (intermediateResult != nil) + [subscriber putNext:intermediateResult]; + [subscriber putCompletion]; + }]; + }]; +} + @end From a1056f70178e09acd87e96f2fc50d988feeed48a Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 29 Apr 2015 20:23:13 +0300 Subject: [PATCH 023/122] Added take --- SSignalKit.xcodeproj/project.pbxproj | 10 +++++++ SSignalKit/SSignal+Take.h | 7 +++++ SSignalKit/SSignal+Take.m | 40 ++++++++++++++++++++++++++++ SSignalKit/SSignalKit.h | 1 + 4 files changed, 58 insertions(+) create mode 100644 SSignalKit/SSignal+Take.h create mode 100644 SSignalKit/SSignal+Take.m diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 8d264f799c..f065ddfdbb 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -86,6 +86,9 @@ D089E0341AC48EA7009A744B /* SThreadPoolTask.h in Headers */ = {isa = PBXBuildFile; fileRef = D089E0301AC48EA7009A744B /* SThreadPoolTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; D089E0391AC56981009A744B /* SThreadPoolQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */; }; D089E03A1AC56981009A744B /* SThreadPoolTask.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */; }; + D0FC5B431AF140E600F353AB /* SSignal+Take.h in Headers */ = {isa = PBXBuildFile; fileRef = D0FC5B411AF140E600F353AB /* SSignal+Take.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0FC5B441AF140E600F353AB /* SSignal+Take.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FC5B421AF140E600F353AB /* SSignal+Take.m */; }; + D0FC5B451AF141F800F353AB /* SSignal+Take.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FC5B421AF140E600F353AB /* SSignal+Take.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -171,6 +174,8 @@ D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPoolQueue.m; sourceTree = ""; }; D089E02F1AC48EA7009A744B /* SThreadPoolQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPoolQueue.h; sourceTree = ""; }; D089E0301AC48EA7009A744B /* SThreadPoolTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPoolTask.h; sourceTree = ""; }; + D0FC5B411AF140E600F353AB /* SSignal+Take.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Take.h"; sourceTree = ""; }; + D0FC5B421AF140E600F353AB /* SSignal+Take.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Take.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -258,6 +263,8 @@ D0445E191A7C2D7300267924 /* SSignal+Single.m */, D0445E1A1A7C2D7300267924 /* SSignal+Timing.h */, D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */, + D0FC5B411AF140E600F353AB /* SSignal+Take.h */, + D0FC5B421AF140E600F353AB /* SSignal+Take.m */, D0445E1C1A7C2D7300267924 /* SSubscriber.h */, D0445E1D1A7C2D7300267924 /* SSubscriber.m */, D0445E1E1A7C2D7300267924 /* SThreadPool.h */, @@ -323,6 +330,7 @@ D0445E321A7C2D7300267924 /* SSignal+Accumulate.h in Headers */, D0445E361A7C2D7300267924 /* SSignal+Combine.h in Headers */, D0445E2A1A7C2D7300267924 /* SDisposable.h in Headers */, + D0FC5B431AF140E600F353AB /* SSignal+Take.h in Headers */, D0445E421A7C2D7300267924 /* SSignal+SideEffects.h in Headers */, D0445E3E1A7C2D7300267924 /* SSignal+Meta.h in Headers */, D0445E2B1A7C2D7300267924 /* SEvent.h in Headers */, @@ -475,6 +483,7 @@ D0445E471A7C2D7300267924 /* SSignal+Timing.m in Sources */, D0445E311A7C2D7300267924 /* SSignal.m in Sources */, D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */, + D0FC5B441AF140E600F353AB /* SSignal+Take.m in Sources */, D089E0311AC48EA7009A744B /* SThreadPoolTask.m in Sources */, D0445E491A7C2D7300267924 /* SSubscriber.m in Sources */, D0445E431A7C2D7300267924 /* SSignal+SideEffects.m in Sources */, @@ -517,6 +526,7 @@ D0445E7B1A7C447D00267924 /* SSignal+Accumulate.m in Sources */, D0445E851A7C447D00267924 /* SSignal+Timing.m in Sources */, D0445E7A1A7C447D00267924 /* SSignal.m in Sources */, + D0FC5B451AF141F800F353AB /* SSignal+Take.m in Sources */, D087632C1A839EE800632240 /* SDisposableSet.m in Sources */, D0445E861A7C447D00267924 /* SSubscriber.m in Sources */, D0445E831A7C447D00267924 /* SSignal+SideEffects.m in Sources */, diff --git a/SSignalKit/SSignal+Take.h b/SSignalKit/SSignal+Take.h new file mode 100644 index 0000000000..796db95af9 --- /dev/null +++ b/SSignalKit/SSignal+Take.h @@ -0,0 +1,7 @@ +#import + +@interface SSignal (Take) + +- (SSignal *)take:(NSUInteger)count; + +@end diff --git a/SSignalKit/SSignal+Take.m b/SSignalKit/SSignal+Take.m new file mode 100644 index 0000000000..af0a38d6f0 --- /dev/null +++ b/SSignalKit/SSignal+Take.m @@ -0,0 +1,40 @@ +#import "SSignal+Take.h" + +#import "SAtomic.h" + +@implementation SSignal (Take) + +- (SSignal *)take:(NSUInteger)count +{ + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + SAtomic *counter = [[SAtomic alloc] initWithValue:@(0)]; + return [self startWithNext:^(id next) + { + __block bool passthrough = false; + __block bool complete = false; + [counter modify:^id(NSNumber *currentCount) + { + NSUInteger updatedCount = [currentCount unsignedIntegerValue] + 1; + if (updatedCount <= count) + passthrough = true; + if (updatedCount == count) + complete = true; + return @(updatedCount); + }]; + + if (passthrough) + [subscriber putNext:next]; + if (complete) + [subscriber putCompletion]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + +@end diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h index 3021283400..f3910b50fb 100644 --- a/SSignalKit/SSignalKit.h +++ b/SSignalKit/SSignalKit.h @@ -35,5 +35,6 @@ FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; #import #import #import +#import #import #import From 1ba4881e9d22781d90ef2425807a267482c0c47e Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 5 May 2015 21:07:36 +0300 Subject: [PATCH 024/122] Added restart and standalone signals --- SSignalKit/SMulticastSignalManager.h | 1 + SSignalKit/SMulticastSignalManager.m | 72 +++++++++++++++++++++++++--- SSignalKit/SSignal+Catch.h | 1 + SSignalKit/SSignal+Catch.m | 54 +++++++++++++++++++++ 4 files changed, 122 insertions(+), 6 deletions(-) diff --git a/SSignalKit/SMulticastSignalManager.h b/SSignalKit/SMulticastSignalManager.h index c5ebf674e4..3dcd46b488 100644 --- a/SSignalKit/SMulticastSignalManager.h +++ b/SSignalKit/SMulticastSignalManager.h @@ -3,5 +3,6 @@ @interface SMulticastSignalManager : NSObject - (SSignal *)multicastedSignalForKey:(NSString *)key producer:(SSignal *(^)())producer; +- (void)startStandaloneSignalIfNotRunningForKey:(NSString *)key producer:(SSignal *(^)())producer; @end diff --git a/SSignalKit/SMulticastSignalManager.m b/SSignalKit/SMulticastSignalManager.m index 63b99ea4d1..875bee408e 100644 --- a/SSignalKit/SMulticastSignalManager.m +++ b/SSignalKit/SMulticastSignalManager.m @@ -2,13 +2,16 @@ #import "SSignal+Multicast.h" #import "SSignal+SideEffects.h" +#import "SBag.h" +#import "SMetaDisposable.h" #import @interface SMulticastSignalManager () { - NSMutableDictionary *_signals; - volatile OSSpinLock _lock; + OSSpinLock _lock; + NSMutableDictionary *_multicastSignals; + NSMutableDictionary *_standaloneSignalDisposables; } @end @@ -20,11 +23,25 @@ self = [super init]; if (self != nil) { - _signals = [[NSMutableDictionary alloc] init]; + _multicastSignals = [[NSMutableDictionary alloc] init]; + _standaloneSignalDisposables = [[NSMutableDictionary alloc] init]; } return self; } +- (void)dealloc +{ + NSArray *disposables = nil; + OSSpinLockLock(&_lock); + disposables = [_standaloneSignalDisposables allValues]; + OSSpinLockUnlock(&_lock); + + for (id disposable in disposables) + { + [disposable dispose]; + } +} + - (SSignal *)multicastedSignalForKey:(NSString *)key producer:(SSignal *(^)())producer { if (key == nil) @@ -37,7 +54,7 @@ SSignal *signal = nil; OSSpinLockLock(&_lock); - signal = _signals[key]; + signal = _multicastSignals[key]; if (signal == nil) { __weak SMulticastSignalManager *weakSelf = self; @@ -51,11 +68,11 @@ if (strongSelf != nil) { OSSpinLockLock(&strongSelf->_lock); - [strongSelf->_signals removeObjectForKey:key]; + [strongSelf->_multicastSignals removeObjectForKey:key]; OSSpinLockUnlock(&strongSelf->_lock); } }]; - _signals[key] = signal; + _multicastSignals[key] = signal; } } OSSpinLockUnlock(&_lock); @@ -63,4 +80,47 @@ return signal; } +- (void)startStandaloneSignalIfNotRunningForKey:(NSString *)key producer:(SSignal *(^)())producer +{ + if (key == nil) + return; + + bool produce = false; + OSSpinLockLock(&_lock); + if (_standaloneSignalDisposables[key] == nil) + { + _standaloneSignalDisposables[key] = [[SMetaDisposable alloc] init]; + produce = true; + } + OSSpinLockUnlock(&_lock); + + if (produce) + { + __weak SMulticastSignalManager *weakSelf = self; + id disposable = [producer() startWithNext:nil error:^(__unused id error) + { + __strong SMulticastSignalManager *strongSelf = weakSelf; + if (strongSelf != nil) + { + OSSpinLockLock(&strongSelf->_lock); + [strongSelf->_standaloneSignalDisposables removeObjectForKey:key]; + OSSpinLockUnlock(&strongSelf->_lock); + } + } completed:^ + { + __strong SMulticastSignalManager *strongSelf = weakSelf; + if (strongSelf != nil) + { + OSSpinLockLock(&strongSelf->_lock); + [strongSelf->_standaloneSignalDisposables removeObjectForKey:key]; + OSSpinLockUnlock(&strongSelf->_lock); + } + }]; + + OSSpinLockLock(&_lock); + [(SMetaDisposable *)_standaloneSignalDisposables[key] setDisposable:disposable]; + OSSpinLockUnlock(&_lock); + } +} + @end diff --git a/SSignalKit/SSignal+Catch.h b/SSignalKit/SSignal+Catch.h index 4fe07654c6..ced7b7e1db 100644 --- a/SSignalKit/SSignal+Catch.h +++ b/SSignalKit/SSignal+Catch.h @@ -3,5 +3,6 @@ @interface SSignal (Catch) - (SSignal *)catch:(SSignal *(^)(id error))f; +- (SSignal *)restart; @end diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m index 61b97884d9..5fc783483c 100644 --- a/SSignalKit/SSignal+Catch.m +++ b/SSignalKit/SSignal+Catch.m @@ -2,6 +2,7 @@ #import "SMetaDisposable.h" #import "SDisposableSet.h" +#import "SBlockDisposable.h" #import "SAtomic.h" @implementation SSignal (Catch) @@ -37,4 +38,57 @@ }]; } +static dispatch_block_t recursiveBlock(void (^block)(dispatch_block_t recurse)) +{ + return ^ + { + block(RecursiveBlock(block)); + }; +} + +- (SSignal *)restart +{ + 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) + { + [subscriber putError:error]; + } completed:^ + { + recurse(); + }]; + [currentDisposable setDisposable:disposable]; + } + }); + + start(); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + [currentDisposable dispose]; + + [shouldRestart modify:^id(__unused id current) + { + return @false; + }]; + }]; + }]; +} + @end From 14382c3244bddba158f73c711fd54b2afc011e72 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 5 May 2015 21:41:08 +0300 Subject: [PATCH 025/122] Bug fixes --- SSignalKit.xcodeproj/project.pbxproj | 12 ++++++++++++ SSignalKit/SSignal+Catch.m | 2 +- SSignalKitTests/SSignalBasicTests.m | 26 ++++++++++++++++++-------- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index f065ddfdbb..0161f605f1 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -680,6 +680,12 @@ ); INFOPLIST_FILE = SSignalKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + XCTest, + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -693,6 +699,12 @@ ); INFOPLIST_FILE = SSignalKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + XCTest, + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m index 5fc783483c..2387c88946 100644 --- a/SSignalKit/SSignal+Catch.m +++ b/SSignalKit/SSignal+Catch.m @@ -42,7 +42,7 @@ static dispatch_block_t recursiveBlock(void (^block)(dispatch_block_t recurse)) { return ^ { - block(RecursiveBlock(block)); + block(recursiveBlock(block)); }; } diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index acbef9e2d1..54ca309614 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -634,25 +634,35 @@ XCTAssertFalse(startedThird); } -- (void)testWaitSameQueue +- (void)testRestart { SSignal *signal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { - dispatch_async(dispatch_get_main_queue(), ^ + [[SQueue concurrentDefaultQueue] dispatch:^ { - [subscriber putNext:@(1)]; + [subscriber putNext:@1]; [subscriber putCompletion]; - }); + }]; - return nil; + return [[SBlockDisposable alloc] initWithBlock:^ + { + }]; }]; - CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent(); - [[signal wait:2.0 onQueue:[SQueue concurrentDefaultQueue]] startWithNext:^(__unused id next) + __block int result = 0; + + [[[signal restart] take:3] startWithNext:^(id next) { + result += [next intValue]; + } error:^(id error) { + + } completed:^{ }]; - XCTAssert(startTime < 0.5); + + usleep(100 * 1000); + + XCTAssertEqual(result, 3); } @end From 016f6e39e02c2ef90c469c3337239b3bafbb8eb0 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 6 May 2015 21:44:17 +0300 Subject: [PATCH 026/122] Multicast and side effects additions --- SSignalKit/SMulticastSignalManager.h | 3 ++ SSignalKit/SMulticastSignalManager.m | 41 ++++++++++++++++++++++++++++ SSignalKit/SSignal+SideEffects.h | 1 + SSignalKit/SSignal+SideEffects.m | 18 ++++++++++++ 4 files changed, 63 insertions(+) diff --git a/SSignalKit/SMulticastSignalManager.h b/SSignalKit/SMulticastSignalManager.h index 3dcd46b488..7d7391b8f2 100644 --- a/SSignalKit/SMulticastSignalManager.h +++ b/SSignalKit/SMulticastSignalManager.h @@ -5,4 +5,7 @@ - (SSignal *)multicastedSignalForKey:(NSString *)key producer:(SSignal *(^)())producer; - (void)startStandaloneSignalIfNotRunningForKey:(NSString *)key producer:(SSignal *(^)())producer; +- (SSignal *)multicastedPipeForKey:(NSString *)key; +- (void)putNext:(id)next toMulticastedPipeForKey:(NSString *)key; + @end diff --git a/SSignalKit/SMulticastSignalManager.m b/SSignalKit/SMulticastSignalManager.m index 875bee408e..74bfdf252f 100644 --- a/SSignalKit/SMulticastSignalManager.m +++ b/SSignalKit/SMulticastSignalManager.m @@ -4,6 +4,7 @@ #import "SSignal+SideEffects.h" #import "SBag.h" #import "SMetaDisposable.h" +#import "SBlockDisposable.h" #import @@ -12,6 +13,7 @@ OSSpinLock _lock; NSMutableDictionary *_multicastSignals; NSMutableDictionary *_standaloneSignalDisposables; + NSMutableDictionary *_pipeListeners; } @end @@ -25,6 +27,7 @@ { _multicastSignals = [[NSMutableDictionary alloc] init]; _standaloneSignalDisposables = [[NSMutableDictionary alloc] init]; + _pipeListeners = [[NSMutableDictionary alloc] init]; } return self; } @@ -123,4 +126,42 @@ } } +- (SSignal *)multicastedPipeForKey:(NSString *)key +{ + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + OSSpinLockLock(&_lock); + SBag *bag = _pipeListeners[key]; + if (bag == nil) + { + bag = [[SBag alloc] init]; + _pipeListeners[key] = bag; + } + NSInteger index = [bag addItem:[^(id next) + { + [subscriber putNext:next]; + } copy]]; + OSSpinLockUnlock(&_lock); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + OSSpinLockLock(&_lock); + [(SBag *)_pipeListeners[key] removeItem:index]; + OSSpinLockUnlock(&_lock); + }]; + }]; +} + +- (void)putNext:(id)next toMulticastedPipeForKey:(NSString *)key +{ + OSSpinLockLock(&_lock); + NSArray *pipeListeners = [(SBag *)_pipeListeners[key] copyItems]; + OSSpinLockUnlock(&_lock); + + for (void (^listener)(id) in pipeListeners) + { + listener(next); + } +} + @end diff --git a/SSignalKit/SSignal+SideEffects.h b/SSignalKit/SSignal+SideEffects.h index 66023f137c..7b58754062 100644 --- a/SSignalKit/SSignal+SideEffects.h +++ b/SSignalKit/SSignal+SideEffects.h @@ -3,6 +3,7 @@ @interface SSignal (SideEffects) - (SSignal *)onNext:(void (^)(id next))f; +- (SSignal *)afterNext:(void (^)(id next))f; - (SSignal *)onError:(void (^)(id error))f; - (SSignal *)onCompletion:(void (^)())f; - (SSignal *)onDispose:(void (^)())f; diff --git a/SSignalKit/SSignal+SideEffects.m b/SSignalKit/SSignal+SideEffects.m index ae59f3f77a..e5531ca67d 100644 --- a/SSignalKit/SSignal+SideEffects.m +++ b/SSignalKit/SSignal+SideEffects.m @@ -23,6 +23,24 @@ }]; } +- (SSignal *)afterNext:(void (^)(id next))f +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + return [self startWithNext:^(id next) + { + [subscriber putNext:next]; + f(next); + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + - (SSignal *)onError:(void (^)(id error))f { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) From 90cadb651daf5175492394da09c13fb668dbd4b1 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 23 May 2015 23:42:07 +0300 Subject: [PATCH 027/122] no message --- SSignalKit/SSignal+Combine.h | 2 ++ SSignalKit/SSignal+Combine.m | 40 ++++++++++++++++++++++++++ SSignalKit/SSignal+Pipe.h | 9 ++++++ SSignalKit/SSignal+Pipe.m | 56 ++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 SSignalKit/SSignal+Pipe.h create mode 100644 SSignalKit/SSignal+Pipe.m diff --git a/SSignalKit/SSignal+Combine.h b/SSignalKit/SSignal+Combine.h index 45834a81cf..95ddb7bd84 100644 --- a/SSignalKit/SSignal+Combine.h +++ b/SSignalKit/SSignal+Combine.h @@ -5,4 +5,6 @@ + (SSignal *)combineSignals:(NSArray *)signals; + (SSignal *)combineSignals:(NSArray *)signals withInitialStates:(NSArray *)initialStates; ++ (SSignal *)mergeSignals:(NSArray *)signals; + @end diff --git a/SSignalKit/SSignal+Combine.m b/SSignalKit/SSignal+Combine.m index 60c7f40cff..45660408a6 100644 --- a/SSignalKit/SSignal+Combine.m +++ b/SSignalKit/SSignal+Combine.m @@ -2,6 +2,7 @@ #import "SAtomic.h" #import "SDisposableSet.h" +#import "SSignal+Single.h" @interface SSignalCombineState : NSObject @@ -131,4 +132,43 @@ }]; } ++ (SSignal *)mergeSignals:(NSArray *)signals +{ + if (signals.count == 0) + return [SSignal complete]; + + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + SDisposableSet *disposables = [[SDisposableSet alloc] init]; + SAtomic *completedStates = [[SAtomic alloc] initWithValue:[[NSSet alloc] init]]; + + NSInteger index = -1; + NSUInteger count = signals.count; + for (SSignal *signal in signals) + { + index++; + + id disposable = [signal startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + NSSet *set = [completedStates modify:^id(NSSet *set) + { + return [set setByAddingObject:@(index)]; + }]; + if (set.count == count) + [subscriber putCompletion]; + }]; + + [disposables add:disposable]; + } + + return disposables; + }]; +}; + @end diff --git a/SSignalKit/SSignal+Pipe.h b/SSignalKit/SSignal+Pipe.h new file mode 100644 index 0000000000..24c408867f --- /dev/null +++ b/SSignalKit/SSignal+Pipe.h @@ -0,0 +1,9 @@ +#import + +@interface SPipe : NSObject + +@property (nonatomic, copy, readonly) SSignal *(^signalProducer)(); +@property (nonatomic, copy, readonly) void (^sink)(id); + +@end + diff --git a/SSignalKit/SSignal+Pipe.m b/SSignalKit/SSignal+Pipe.m new file mode 100644 index 0000000000..33446ef13a --- /dev/null +++ b/SSignalKit/SSignal+Pipe.m @@ -0,0 +1,56 @@ +#import "SSignal+Pipe.h" + +#import "SBlockDisposable.h" +#import "SAtomic.h" +#import "SBag.h" + +@implementation SPipe + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + SAtomic *subscribers = [[SAtomic alloc] initWithValue:[[SBag alloc] init]]; + + _signalProducer = [^SSignal * + { + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + __block NSUInteger index = 0; + [subscribers with:^id(SBag *bag) + { + index = [bag addItem:[^(id next) + { + [subscriber putNext:next]; + } copy]]; + return nil; + }]; + + return [[SBlockDisposable alloc] initWithBlock:^ + { + [subscribers with:^id(SBag *bag) + { + [bag removeItem:index]; + return nil; + }]; + }]; + }]; + } copy]; + + _sink = [^(id next) + { + NSArray *items = [subscribers with:^id(SBag *bag) + { + return [bag copyItems]; + }]; + for (void (^item)(id) in items) + { + item(next); + } + } copy]; + } + return self; +} + +@end From 8d5ce7899d144b23d8c76e4790fe97ded3d93206 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 23 May 2015 23:44:07 +0300 Subject: [PATCH 028/122] no message --- SSignalKit/SSignalKit.h | 1 + 1 file changed, 1 insertion(+) diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h index f3910b50fb..142eabd2f0 100644 --- a/SSignalKit/SSignalKit.h +++ b/SSignalKit/SSignalKit.h @@ -36,5 +36,6 @@ FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; #import #import #import +#import #import #import From 88ff04e011db619dfe47f81ce8ec9e5453c827c3 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 23 May 2015 23:56:59 +0300 Subject: [PATCH 029/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 0161f605f1..5e20cfe525 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + D02AD5CA1B1121010074F9C1 /* SSignal+Pipe.m in Sources */ = {isa = PBXBuildFile; fileRef = D02AD5C81B1121010074F9C1 /* SSignal+Pipe.m */; }; + D02AD5CB1B1121010074F9C1 /* SSignal+Pipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D02AD5C91B1121010074F9C1 /* SSignal+Pipe.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DDD1A7C2CA500267924 /* SSignalKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0445DE41A7C2CA500267924 /* SSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0445DD81A7C2CA500267924 /* SSignalKit.framework */; }; D0445E221A7C2D7300267924 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF61A7C2D7300267924 /* SBlockDisposable.m */; }; @@ -114,6 +116,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + D02AD5C81B1121010074F9C1 /* SSignal+Pipe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Pipe.m"; sourceTree = ""; }; + D02AD5C91B1121010074F9C1 /* SSignal+Pipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Pipe.h"; 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 = ""; }; D0445DDD1A7C2CA500267924 /* SSignalKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSignalKit.h; sourceTree = ""; }; @@ -226,6 +230,8 @@ D0445DDA1A7C2CA500267924 /* SSignalKit */ = { isa = PBXGroup; children = ( + D02AD5C81B1121010074F9C1 /* SSignal+Pipe.m */, + D02AD5C91B1121010074F9C1 /* SSignal+Pipe.h */, D0445DF71A7C2D7300267924 /* SAtomic.h */, D0445DF81A7C2D7300267924 /* SAtomic.m */, D0445DF91A7C2D7300267924 /* SBag.h */, @@ -337,6 +343,7 @@ D0445E341A7C2D7300267924 /* SSignal+Catch.h in Headers */, D0445E4E1A7C2D8A00267924 /* SQueue.h in Headers */, D0445E441A7C2D7300267924 /* SSignal+Single.h in Headers */, + D02AD5CB1B1121010074F9C1 /* SSignal+Pipe.h in Headers */, D0445E251A7C2D7300267924 /* SBag.h in Headers */, D0445E3A1A7C2D7300267924 /* SSignal+Dispatch.h in Headers */, D0445E401A7C2D7300267924 /* SSignal+Multicast.h in Headers */, @@ -469,6 +476,7 @@ D0445E451A7C2D7300267924 /* SSignal+Single.m in Sources */, D0445E2D1A7C2D7300267924 /* SMetaDisposable.m in Sources */, D0445E3B1A7C2D7300267924 /* SSignal+Dispatch.m in Sources */, + D02AD5CA1B1121010074F9C1 /* SSignal+Pipe.m in Sources */, D0445E4F1A7C2D8A00267924 /* SQueue.m in Sources */, D0445E241A7C2D7300267924 /* SAtomic.m in Sources */, D0445E4B1A7C2D7300267924 /* SThreadPool.m in Sources */, From babd3ca90097194721763d53e7c46413ddd96747 Mon Sep 17 00:00:00 2001 From: Peter Date: Sun, 24 May 2015 04:44:27 +0300 Subject: [PATCH 030/122] SPipe tests --- SSignalKitTests/SSignalBasicTests.m | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index 54ca309614..0cc3d5f317 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -665,4 +665,40 @@ XCTAssertEqual(result, 3); } +- (void)testPipe +{ + SPipe *pipe = [[SPipe alloc] init]; + + __block int result1 = 0; + id disposable1 = [pipe.signalProducer() startWithNext:^(id next) + { + result1 += [next intValue]; + }]; + + __block int result2 = 0; + id disposable2 = [pipe.signalProducer() startWithNext:^(id next) + { + result2 += [next intValue]; + }]; + + pipe.sink(@1); + + XCTAssertEqual(result1, 1); + XCTAssertEqual(result2, 1); + + [disposable1 dispose]; + + pipe.sink(@1); + + XCTAssertEqual(result1, 1); + XCTAssertEqual(result2, 2); + + [disposable2 dispose]; + + pipe.sink(@1); + + XCTAssertEqual(result1, 1); + XCTAssertEqual(result2, 2); +} + @end From 0db026e823a0a53f0c1cea1ccfd3910f6bf9cce7 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 10 Jun 2015 12:53:19 +0300 Subject: [PATCH 031/122] Swift version --- SSignalKit.xcodeproj/project.pbxproj | 893 +++++++++++------- SSignalKit/SBlockDisposable.h | 2 +- SSignalKit/SDisposableSet.h | 2 +- SSignalKit/SEvent.h | 18 - SSignalKit/SEvent.m | 37 - SSignalKit/SMetaDisposable.h | 2 +- SSignalKit/SMulticastSignalManager.h | 2 +- SSignalKit/SSignal+Accumulate.h | 2 +- SSignalKit/SSignal+Catch.h | 2 +- SSignalKit/SSignal+Combine.h | 2 +- SSignalKit/SSignal+Dispatch.h | 6 +- SSignalKit/SSignal+Mapping.h | 2 +- SSignalKit/SSignal+Meta.h | 2 +- SSignalKit/SSignal+Meta.m | 1 - SSignalKit/SSignal+Multicast.h | 2 +- SSignalKit/SSignal+Multicast.m | 51 +- SSignalKit/SSignal+SideEffects.h | 2 +- SSignalKit/SSignal+Single.h | 2 +- SSignalKit/SSignal+Timing.h | 4 +- SSignalKit/SSignal.h | 2 +- SSignalKit/SSignalKit.h | 1 - SSignalKit/SSubscriber.h | 3 +- SwiftSignalKit/Atomic.swift | 36 + SwiftSignalKit/Bag.swift | 33 + SwiftSignalKit/Disposable.swift | 129 +++ SwiftSignalKit/Info.plist | 26 + SwiftSignalKit/Pipe.swift | 40 + SwiftSignalKit/Queue.swift | 69 ++ SwiftSignalKit/Signal.swift | 43 + SwiftSignalKit/Signal_Catch.swift | 61 ++ SwiftSignalKit/Signal_Combine.swift | 91 ++ SwiftSignalKit/Signal_Dispatch.swift | 77 ++ SwiftSignalKit/Signal_Mapping.swift | 27 + SwiftSignalKit/Signal_Meta.swift | 153 +++ SwiftSignalKit/Signal_Reduce.swift | 34 + SwiftSignalKit/Signal_SideEffects.swift | 45 + SwiftSignalKit/Signal_Single.swift | 28 + SwiftSignalKit/Signal_Take.swift | 27 + SwiftSignalKit/Signal_Timing.swift | 56 ++ SwiftSignalKit/Subscriber.swift | 101 ++ SwiftSignalKit/SwiftSignalKit.h | 19 + SwiftSignalKit/ThreadPool.swift | 154 +++ SwiftSignalKit/Timer.swift | 41 + SwiftSignalKitTests/DeallocatingObject.swift | 19 + SwiftSignalKitTests/Info.plist | 24 + .../SwiftSignalKitBasicTests.swift | 259 +++++ .../SwiftSignalKitFunctionsTests.swift | 660 +++++++++++++ 47 files changed, 2850 insertions(+), 442 deletions(-) delete mode 100644 SSignalKit/SEvent.h delete mode 100644 SSignalKit/SEvent.m create mode 100644 SwiftSignalKit/Atomic.swift create mode 100644 SwiftSignalKit/Bag.swift create mode 100644 SwiftSignalKit/Disposable.swift create mode 100644 SwiftSignalKit/Info.plist create mode 100644 SwiftSignalKit/Pipe.swift create mode 100644 SwiftSignalKit/Queue.swift create mode 100644 SwiftSignalKit/Signal.swift create mode 100644 SwiftSignalKit/Signal_Catch.swift create mode 100644 SwiftSignalKit/Signal_Combine.swift create mode 100644 SwiftSignalKit/Signal_Dispatch.swift create mode 100644 SwiftSignalKit/Signal_Mapping.swift create mode 100644 SwiftSignalKit/Signal_Meta.swift create mode 100644 SwiftSignalKit/Signal_Reduce.swift create mode 100644 SwiftSignalKit/Signal_SideEffects.swift create mode 100644 SwiftSignalKit/Signal_Single.swift create mode 100644 SwiftSignalKit/Signal_Take.swift create mode 100644 SwiftSignalKit/Signal_Timing.swift create mode 100644 SwiftSignalKit/Subscriber.swift create mode 100644 SwiftSignalKit/SwiftSignalKit.h create mode 100644 SwiftSignalKit/ThreadPool.swift create mode 100644 SwiftSignalKit/Timer.swift create mode 100644 SwiftSignalKitTests/DeallocatingObject.swift create mode 100644 SwiftSignalKitTests/Info.plist create mode 100644 SwiftSignalKitTests/SwiftSignalKitBasicTests.swift create mode 100644 SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 5e20cfe525..baf70e3b61 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -7,93 +7,98 @@ objects = { /* Begin PBXBuildFile section */ - D02AD5CA1B1121010074F9C1 /* SSignal+Pipe.m in Sources */ = {isa = PBXBuildFile; fileRef = D02AD5C81B1121010074F9C1 /* SSignal+Pipe.m */; }; - D02AD5CB1B1121010074F9C1 /* SSignal+Pipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D02AD5C91B1121010074F9C1 /* SSignal+Pipe.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DDD1A7C2CA500267924 /* SSignalKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AE71B28285400EAF753 /* SSignal+Timing.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AB11B28285400EAF753 /* SSignal+Timing.m */; }; + D0085AE81B28285400EAF753 /* SThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AB21B28285400EAF753 /* SThreadPool.m */; }; + D0085AE91B28285400EAF753 /* SQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AB31B28285400EAF753 /* SQueue.m */; }; + D0085AEA1B28285400EAF753 /* SSignal+Take.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AB41B28285400EAF753 /* SSignal+Take.m */; }; + D0085AEB1B28285400EAF753 /* SSignal+Meta.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AB51B28285400EAF753 /* SSignal+Meta.m */; }; + D0085AEC1B28285400EAF753 /* SSignal+Accumulate.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AB61B28285400EAF753 /* SSignal+Accumulate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AED1B28285400EAF753 /* SSignal+Single.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AB71B28285400EAF753 /* SSignal+Single.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AEE1B28285400EAF753 /* SSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AB81B28285400EAF753 /* SSignal.m */; }; + D0085AEF1B28285400EAF753 /* SSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AB91B28285400EAF753 /* SSignalKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AF01B28285400EAF753 /* SMulticastSignalManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ABA1B28285400EAF753 /* SMulticastSignalManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AF11B28285400EAF753 /* SMulticastSignalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ABB1B28285400EAF753 /* SMulticastSignalManager.m */; }; + D0085AF21B28285400EAF753 /* SSignal+Combine.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ABC1B28285400EAF753 /* SSignal+Combine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AF31B28285400EAF753 /* SSignal+Combine.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ABD1B28285400EAF753 /* SSignal+Combine.m */; }; + D0085AF41B28285400EAF753 /* SSignal+Pipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ABE1B28285400EAF753 /* SSignal+Pipe.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AF51B28285400EAF753 /* SSignal+Pipe.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ABF1B28285400EAF753 /* SSignal+Pipe.m */; }; + D0085AF61B28285400EAF753 /* SSignal+SideEffects.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AC01B28285400EAF753 /* SSignal+SideEffects.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AF71B28285400EAF753 /* SSignal+SideEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AC11B28285400EAF753 /* SSignal+SideEffects.m */; }; + D0085AF81B28285400EAF753 /* SSignal+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AC21B28285400EAF753 /* SSignal+Catch.m */; }; + D0085AF91B28285400EAF753 /* SSignal+Catch.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AC31B28285400EAF753 /* SSignal+Catch.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AFA1B28285400EAF753 /* SSignal+Take.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AC41B28285400EAF753 /* SSignal+Take.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AFB1B28285400EAF753 /* SSignal+Accumulate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AC51B28285400EAF753 /* SSignal+Accumulate.m */; }; + D0085AFC1B28285400EAF753 /* SQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AC61B28285400EAF753 /* SQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AFD1B28285400EAF753 /* SSignal+Meta.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AC71B28285400EAF753 /* SSignal+Meta.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AFE1B28285400EAF753 /* SSignal+Timing.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AC81B28285400EAF753 /* SSignal+Timing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085AFF1B28285400EAF753 /* SSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AC91B28285400EAF753 /* SSubscriber.m */; }; + D0085B001B28285400EAF753 /* SSignal+Dispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ACA1B28285400EAF753 /* SSignal+Dispatch.m */; }; + D0085B011B28285400EAF753 /* SThreadPoolTask.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ACB1B28285400EAF753 /* SThreadPoolTask.m */; }; + D0085B021B28285400EAF753 /* SThreadPoolQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ACC1B28285400EAF753 /* SThreadPoolQueue.m */; }; + D0085B031B28285400EAF753 /* SThreadPoolQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ACD1B28285400EAF753 /* SThreadPoolQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B041B28285400EAF753 /* SThreadPool.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ACE1B28285400EAF753 /* SThreadPool.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B051B28285400EAF753 /* SThreadPoolTask.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ACF1B28285400EAF753 /* SThreadPoolTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B061B28285400EAF753 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AD01B28285400EAF753 /* SDisposableSet.m */; }; + D0085B071B28285400EAF753 /* SMetaDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AD11B28285400EAF753 /* SMetaDisposable.m */; }; + D0085B081B28285400EAF753 /* SSignal+Multicast.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AD21B28285400EAF753 /* SSignal+Multicast.m */; }; + D0085B091B28285400EAF753 /* SSubscriber.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AD31B28285400EAF753 /* SSubscriber.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B0A1B28285400EAF753 /* SDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AD41B28285400EAF753 /* SDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B0B1B28285400EAF753 /* SSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AD51B28285400EAF753 /* SSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B0C1B28285400EAF753 /* SSignal+Mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AD61B28285400EAF753 /* SSignal+Mapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B0D1B28285400EAF753 /* SSignal+Mapping.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AD71B28285400EAF753 /* SSignal+Mapping.m */; }; + D0085B0E1B28285400EAF753 /* SSignal+Single.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AD81B28285400EAF753 /* SSignal+Single.m */; }; + D0085B0F1B28285400EAF753 /* SAtomic.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AD91B28285400EAF753 /* SAtomic.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B101B28285400EAF753 /* SAtomic.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ADA1B28285400EAF753 /* SAtomic.m */; }; + D0085B111B28285400EAF753 /* SBag.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ADB1B28285400EAF753 /* SBag.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B121B28285400EAF753 /* SBag.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ADC1B28285400EAF753 /* SBag.m */; }; + D0085B131B28285400EAF753 /* SBlockDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ADD1B28285400EAF753 /* SBlockDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B141B28285400EAF753 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085ADE1B28285400EAF753 /* SBlockDisposable.m */; }; + D0085B151B28285400EAF753 /* SDisposableSet.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085ADF1B28285400EAF753 /* SDisposableSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B181B28285400EAF753 /* SMetaDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AE21B28285400EAF753 /* SMetaDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B191B28285400EAF753 /* SSignal+Dispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AE31B28285400EAF753 /* SSignal+Dispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B1A1B28285400EAF753 /* SSignal+Multicast.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AE41B28285400EAF753 /* SSignal+Multicast.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B1B1B28285400EAF753 /* STimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085AE51B28285400EAF753 /* STimer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B1C1B28285400EAF753 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AE61B28285400EAF753 /* STimer.m */; }; + D0085B271B282B9800EAF753 /* SwiftSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085B261B282B9800EAF753 /* SwiftSignalKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0085B2D1B282B9800EAF753 /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0085B221B282B9800EAF753 /* SwiftSignalKit.framework */; }; + D0085B4F1B282BEE00EAF753 /* SwiftSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085B3B1B282BEE00EAF753 /* SwiftSignalKit.h */; }; + D0085B501B282BEE00EAF753 /* Signal_Timing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3C1B282BEE00EAF753 /* Signal_Timing.swift */; }; + D0085B511B282BEE00EAF753 /* Signal_SideEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3D1B282BEE00EAF753 /* Signal_SideEffects.swift */; }; + D0085B521B282BEE00EAF753 /* Signal_Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3E1B282BEE00EAF753 /* Signal_Dispatch.swift */; }; + 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 */; }; + 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 */; }; + D0085B5A1B282BEE00EAF753 /* Signal_Single.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B461B282BEE00EAF753 /* Signal_Single.swift */; }; + D0085B5B1B282BEE00EAF753 /* Signal_Meta.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B471B282BEE00EAF753 /* Signal_Meta.swift */; }; + D0085B5C1B282BEE00EAF753 /* Signal_Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B481B282BEE00EAF753 /* Signal_Combine.swift */; }; + D0085B5D1B282BEE00EAF753 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B491B282BEE00EAF753 /* Atomic.swift */; }; + D0085B5E1B282BEE00EAF753 /* Signal_Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4A1B282BEE00EAF753 /* Signal_Reduce.swift */; }; + D0085B5F1B282BEE00EAF753 /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4B1B282BEE00EAF753 /* Signal.swift */; }; + D0085B601B282BEE00EAF753 /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4C1B282BEE00EAF753 /* Disposable.swift */; }; + D0085B611B282BEE00EAF753 /* Signal_Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4D1B282BEE00EAF753 /* Signal_Mapping.swift */; }; + D0085B621B282BEE00EAF753 /* Subscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B4E1B282BEE00EAF753 /* Subscriber.swift */; }; + 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 */; }; D0445DE41A7C2CA500267924 /* SSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0445DD81A7C2CA500267924 /* SSignalKit.framework */; }; - D0445E221A7C2D7300267924 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF61A7C2D7300267924 /* SBlockDisposable.m */; }; - D0445E231A7C2D7300267924 /* SAtomic.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DF71A7C2D7300267924 /* SAtomic.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E241A7C2D7300267924 /* SAtomic.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF81A7C2D7300267924 /* SAtomic.m */; }; - D0445E251A7C2D7300267924 /* SBag.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DF91A7C2D7300267924 /* SBag.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E261A7C2D7300267924 /* SBag.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFA1A7C2D7300267924 /* SBag.m */; }; - D0445E271A7C2D7300267924 /* SBlockDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E2A1A7C2D7300267924 /* SDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFE1A7C2D7300267924 /* SDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E2B1A7C2D7300267924 /* SEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445DFF1A7C2D7300267924 /* SEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E2C1A7C2D7300267924 /* SEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E001A7C2D7300267924 /* SEvent.m */; }; - D0445E2D1A7C2D7300267924 /* SMetaDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E011A7C2D7300267924 /* SMetaDisposable.m */; }; - D0445E2E1A7C2D7300267924 /* SMulticastSignalManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E021A7C2D7300267924 /* SMulticastSignalManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E2F1A7C2D7300267924 /* SMulticastSignalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */; }; - D0445E301A7C2D7300267924 /* SSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E041A7C2D7300267924 /* SSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E311A7C2D7300267924 /* SSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E051A7C2D7300267924 /* SSignal.m */; }; - D0445E321A7C2D7300267924 /* SSignal+Accumulate.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E061A7C2D7300267924 /* SSignal+Accumulate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E331A7C2D7300267924 /* SSignal+Accumulate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */; }; - D0445E341A7C2D7300267924 /* SSignal+Catch.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E081A7C2D7300267924 /* SSignal+Catch.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E351A7C2D7300267924 /* SSignal+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E091A7C2D7300267924 /* SSignal+Catch.m */; }; - D0445E361A7C2D7300267924 /* SSignal+Combine.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E371A7C2D7300267924 /* SSignal+Combine.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */; }; - D0445E3A1A7C2D7300267924 /* SSignal+Dispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E3B1A7C2D7300267924 /* SSignal+Dispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */; }; - D0445E3C1A7C2D7300267924 /* SSignal+Mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E101A7C2D7300267924 /* SSignal+Mapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E3D1A7C2D7300267924 /* SSignal+Mapping.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E111A7C2D7300267924 /* SSignal+Mapping.m */; }; - D0445E3E1A7C2D7300267924 /* SSignal+Meta.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E121A7C2D7300267924 /* SSignal+Meta.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E3F1A7C2D7300267924 /* SSignal+Meta.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E131A7C2D7300267924 /* SSignal+Meta.m */; }; - D0445E401A7C2D7300267924 /* SSignal+Multicast.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E141A7C2D7300267924 /* SSignal+Multicast.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E411A7C2D7300267924 /* SSignal+Multicast.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E151A7C2D7300267924 /* SSignal+Multicast.m */; }; - D0445E421A7C2D7300267924 /* SSignal+SideEffects.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E161A7C2D7300267924 /* SSignal+SideEffects.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E431A7C2D7300267924 /* SSignal+SideEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E171A7C2D7300267924 /* SSignal+SideEffects.m */; }; - D0445E441A7C2D7300267924 /* SSignal+Single.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E181A7C2D7300267924 /* SSignal+Single.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E451A7C2D7300267924 /* SSignal+Single.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E191A7C2D7300267924 /* SSignal+Single.m */; }; - D0445E461A7C2D7300267924 /* SSignal+Timing.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E1A1A7C2D7300267924 /* SSignal+Timing.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E471A7C2D7300267924 /* SSignal+Timing.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */; }; - D0445E481A7C2D7300267924 /* SSubscriber.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E1C1A7C2D7300267924 /* SSubscriber.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E491A7C2D7300267924 /* SSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1D1A7C2D7300267924 /* SSubscriber.m */; }; - D0445E4A1A7C2D7300267924 /* SThreadPool.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E1E1A7C2D7300267924 /* SThreadPool.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E4B1A7C2D7300267924 /* SThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1F1A7C2D7300267924 /* SThreadPool.m */; }; - D0445E4E1A7C2D8A00267924 /* SQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E4C1A7C2D8A00267924 /* SQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E4F1A7C2D8A00267924 /* SQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E4D1A7C2D8A00267924 /* SQueue.m */; }; - D0445E511A7C2DBF00267924 /* SMetaDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E501A7C2DBF00267924 /* SMetaDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E541A7C2E9D00267924 /* STimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D0445E521A7C2E9D00267924 /* STimer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0445E551A7C2E9D00267924 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E531A7C2E9D00267924 /* STimer.m */; }; D0445E571A7C3FB400267924 /* SDisposableTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E561A7C3FB400267924 /* SDisposableTests.m */; }; - D0445E731A7C447D00267924 /* SBlockDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF61A7C2D7300267924 /* SBlockDisposable.m */; }; - D0445E741A7C447D00267924 /* SAtomic.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DF81A7C2D7300267924 /* SAtomic.m */; }; - D0445E751A7C447D00267924 /* SBag.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445DFA1A7C2D7300267924 /* SBag.m */; }; - D0445E771A7C447D00267924 /* SEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E001A7C2D7300267924 /* SEvent.m */; }; - D0445E781A7C447D00267924 /* SMetaDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E011A7C2D7300267924 /* SMetaDisposable.m */; }; - D0445E791A7C447D00267924 /* SMulticastSignalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */; }; - D0445E7A1A7C447D00267924 /* SSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E051A7C2D7300267924 /* SSignal.m */; }; - D0445E7B1A7C447D00267924 /* SSignal+Accumulate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */; }; - D0445E7C1A7C447D00267924 /* SSignal+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E091A7C2D7300267924 /* SSignal+Catch.m */; }; - D0445E7D1A7C447D00267924 /* SSignal+Combine.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */; }; - D0445E7F1A7C447D00267924 /* SSignal+Dispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */; }; - D0445E801A7C447D00267924 /* SSignal+Mapping.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E111A7C2D7300267924 /* SSignal+Mapping.m */; }; - D0445E811A7C447D00267924 /* SSignal+Meta.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E131A7C2D7300267924 /* SSignal+Meta.m */; }; - D0445E821A7C447D00267924 /* SSignal+Multicast.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E151A7C2D7300267924 /* SSignal+Multicast.m */; }; - D0445E831A7C447D00267924 /* SSignal+SideEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E171A7C2D7300267924 /* SSignal+SideEffects.m */; }; - D0445E841A7C447D00267924 /* SSignal+Single.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E191A7C2D7300267924 /* SSignal+Single.m */; }; - D0445E851A7C447D00267924 /* SSignal+Timing.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */; }; - D0445E861A7C447D00267924 /* SSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1D1A7C2D7300267924 /* SSubscriber.m */; }; - D0445E871A7C447D00267924 /* SThreadPool.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E1F1A7C2D7300267924 /* SThreadPool.m */; }; - D0445E881A7C447D00267924 /* SQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E4D1A7C2D8A00267924 /* SQueue.m */; }; - D0445E891A7C447D00267924 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0445E531A7C2E9D00267924 /* STimer.m */; }; 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 */; }; - D087632A1A839EDC00632240 /* SDisposableSet.h in Headers */ = {isa = PBXBuildFile; fileRef = D08763281A839EDC00632240 /* SDisposableSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D08763291A839EDC00632240 /* SDisposableSet.m */; }; - D087632C1A839EE800632240 /* SDisposableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D08763291A839EDC00632240 /* SDisposableSet.m */; }; - D089E0311AC48EA7009A744B /* SThreadPoolTask.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */; }; - D089E0321AC48EA7009A744B /* SThreadPoolQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */; }; - D089E0331AC48EA7009A744B /* SThreadPoolQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D089E02F1AC48EA7009A744B /* SThreadPoolQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D089E0341AC48EA7009A744B /* SThreadPoolTask.h in Headers */ = {isa = PBXBuildFile; fileRef = D089E0301AC48EA7009A744B /* SThreadPoolTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D089E0391AC56981009A744B /* SThreadPoolQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */; }; - D089E03A1AC56981009A744B /* SThreadPoolTask.m in Sources */ = {isa = PBXBuildFile; fileRef = D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */; }; - D0FC5B431AF140E600F353AB /* SSignal+Take.h in Headers */ = {isa = PBXBuildFile; fileRef = D0FC5B411AF140E600F353AB /* SSignal+Take.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D0FC5B441AF140E600F353AB /* SSignal+Take.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FC5B421AF140E600F353AB /* SSignal+Take.m */; }; - D0FC5B451AF141F800F353AB /* SSignal+Take.m in Sources */ = {isa = PBXBuildFile; fileRef = D0FC5B421AF140E600F353AB /* SSignal+Take.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + D0085B2E1B282B9800EAF753 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D0445DCF1A7C2CA500267924 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0085B211B282B9800EAF753; + remoteInfo = SwiftSignalKit; + }; D0445DE51A7C2CA500267924 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D0445DCF1A7C2CA500267924 /* Project object */; @@ -103,86 +108,114 @@ }; /* End PBXContainerItemProxy section */ -/* Begin PBXCopyFilesBuildPhase section */ - D0445E5A1A7C446000267924 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "include/$(PRODUCT_NAME)"; - dstSubfolderSpec = 16; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ - D02AD5C81B1121010074F9C1 /* SSignal+Pipe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Pipe.m"; sourceTree = ""; }; - D02AD5C91B1121010074F9C1 /* SSignal+Pipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Pipe.h"; sourceTree = ""; }; + D0085AB11B28285400EAF753 /* SSignal+Timing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Timing.m"; sourceTree = ""; }; + D0085AB21B28285400EAF753 /* SThreadPool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPool.m; sourceTree = ""; }; + D0085AB31B28285400EAF753 /* SQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQueue.m; sourceTree = ""; }; + D0085AB41B28285400EAF753 /* SSignal+Take.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Take.m"; sourceTree = ""; }; + D0085AB51B28285400EAF753 /* SSignal+Meta.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Meta.m"; sourceTree = ""; }; + D0085AB61B28285400EAF753 /* SSignal+Accumulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Accumulate.h"; sourceTree = ""; }; + D0085AB71B28285400EAF753 /* SSignal+Single.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Single.h"; sourceTree = ""; }; + D0085AB81B28285400EAF753 /* SSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignal.m; sourceTree = ""; }; + D0085AB91B28285400EAF753 /* SSignalKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSignalKit.h; sourceTree = ""; }; + D0085ABA1B28285400EAF753 /* SMulticastSignalManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMulticastSignalManager.h; sourceTree = ""; }; + D0085ABB1B28285400EAF753 /* SMulticastSignalManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMulticastSignalManager.m; sourceTree = ""; }; + D0085ABC1B28285400EAF753 /* SSignal+Combine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Combine.h"; sourceTree = ""; }; + D0085ABD1B28285400EAF753 /* SSignal+Combine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Combine.m"; sourceTree = ""; }; + D0085ABE1B28285400EAF753 /* SSignal+Pipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Pipe.h"; sourceTree = ""; }; + D0085ABF1B28285400EAF753 /* SSignal+Pipe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Pipe.m"; sourceTree = ""; }; + D0085AC01B28285400EAF753 /* SSignal+SideEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+SideEffects.h"; sourceTree = ""; }; + D0085AC11B28285400EAF753 /* SSignal+SideEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+SideEffects.m"; sourceTree = ""; }; + D0085AC21B28285400EAF753 /* SSignal+Catch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Catch.m"; sourceTree = ""; }; + D0085AC31B28285400EAF753 /* SSignal+Catch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Catch.h"; sourceTree = ""; }; + D0085AC41B28285400EAF753 /* SSignal+Take.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Take.h"; sourceTree = ""; }; + D0085AC51B28285400EAF753 /* SSignal+Accumulate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Accumulate.m"; sourceTree = ""; }; + D0085AC61B28285400EAF753 /* SQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQueue.h; sourceTree = ""; }; + D0085AC71B28285400EAF753 /* SSignal+Meta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Meta.h"; sourceTree = ""; }; + D0085AC81B28285400EAF753 /* SSignal+Timing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Timing.h"; sourceTree = ""; }; + D0085AC91B28285400EAF753 /* SSubscriber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSubscriber.m; sourceTree = ""; }; + D0085ACA1B28285400EAF753 /* SSignal+Dispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Dispatch.m"; sourceTree = ""; }; + D0085ACB1B28285400EAF753 /* SThreadPoolTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPoolTask.m; sourceTree = ""; }; + D0085ACC1B28285400EAF753 /* SThreadPoolQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPoolQueue.m; sourceTree = ""; }; + D0085ACD1B28285400EAF753 /* SThreadPoolQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPoolQueue.h; sourceTree = ""; }; + D0085ACE1B28285400EAF753 /* SThreadPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPool.h; sourceTree = ""; }; + D0085ACF1B28285400EAF753 /* SThreadPoolTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPoolTask.h; sourceTree = ""; }; + D0085AD01B28285400EAF753 /* SDisposableSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDisposableSet.m; sourceTree = ""; }; + D0085AD11B28285400EAF753 /* SMetaDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMetaDisposable.m; sourceTree = ""; }; + D0085AD21B28285400EAF753 /* SSignal+Multicast.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Multicast.m"; sourceTree = ""; }; + D0085AD31B28285400EAF753 /* SSubscriber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSubscriber.h; sourceTree = ""; }; + D0085AD41B28285400EAF753 /* SDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposable.h; sourceTree = ""; }; + D0085AD51B28285400EAF753 /* SSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSignal.h; sourceTree = ""; }; + D0085AD61B28285400EAF753 /* SSignal+Mapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Mapping.h"; sourceTree = ""; }; + D0085AD71B28285400EAF753 /* SSignal+Mapping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Mapping.m"; sourceTree = ""; }; + D0085AD81B28285400EAF753 /* SSignal+Single.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Single.m"; sourceTree = ""; }; + D0085AD91B28285400EAF753 /* SAtomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAtomic.h; sourceTree = ""; }; + D0085ADA1B28285400EAF753 /* SAtomic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAtomic.m; sourceTree = ""; }; + D0085ADB1B28285400EAF753 /* SBag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBag.h; sourceTree = ""; }; + D0085ADC1B28285400EAF753 /* SBag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBag.m; sourceTree = ""; }; + D0085ADD1B28285400EAF753 /* SBlockDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBlockDisposable.h; sourceTree = ""; }; + D0085ADE1B28285400EAF753 /* SBlockDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBlockDisposable.m; sourceTree = ""; }; + D0085ADF1B28285400EAF753 /* SDisposableSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposableSet.h; sourceTree = ""; }; + D0085AE21B28285400EAF753 /* SMetaDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMetaDisposable.h; sourceTree = ""; }; + D0085AE31B28285400EAF753 /* SSignal+Dispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Dispatch.h"; sourceTree = ""; }; + D0085AE41B28285400EAF753 /* SSignal+Multicast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Multicast.h"; sourceTree = ""; }; + D0085AE51B28285400EAF753 /* STimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STimer.h; sourceTree = ""; }; + D0085AE61B28285400EAF753 /* STimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STimer.m; sourceTree = ""; }; + D0085B221B282B9800EAF753 /* SwiftSignalKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0085B251B282B9800EAF753 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D0085B261B282B9800EAF753 /* SwiftSignalKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftSignalKit.h; sourceTree = ""; }; + D0085B2C1B282B9800EAF753 /* SwiftSignalKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftSignalKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D0085B321B282B9800EAF753 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D0085B3B1B282BEE00EAF753 /* SwiftSignalKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftSignalKit.h; sourceTree = ""; }; + D0085B3C1B282BEE00EAF753 /* Signal_Timing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Timing.swift; sourceTree = ""; }; + D0085B3D1B282BEE00EAF753 /* Signal_SideEffects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_SideEffects.swift; sourceTree = ""; }; + D0085B3E1B282BEE00EAF753 /* Signal_Dispatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Dispatch.swift; sourceTree = ""; }; + 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 = ""; }; + 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 = ""; }; + D0085B461B282BEE00EAF753 /* Signal_Single.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Single.swift; sourceTree = ""; }; + D0085B471B282BEE00EAF753 /* Signal_Meta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Meta.swift; sourceTree = ""; }; + D0085B481B282BEE00EAF753 /* Signal_Combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Combine.swift; sourceTree = ""; }; + D0085B491B282BEE00EAF753 /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; + D0085B4A1B282BEE00EAF753 /* Signal_Reduce.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Reduce.swift; sourceTree = ""; }; + D0085B4B1B282BEE00EAF753 /* Signal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal.swift; sourceTree = ""; }; + D0085B4C1B282BEE00EAF753 /* Disposable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Disposable.swift; sourceTree = ""; }; + D0085B4D1B282BEE00EAF753 /* Signal_Mapping.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Mapping.swift; sourceTree = ""; }; + D0085B4E1B282BEE00EAF753 /* Subscriber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Subscriber.swift; sourceTree = ""; }; + 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 = ""; }; 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 = ""; }; - D0445DDD1A7C2CA500267924 /* SSignalKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SSignalKit.h; 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 = ""; }; - D0445DF61A7C2D7300267924 /* SBlockDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBlockDisposable.m; sourceTree = ""; }; - D0445DF71A7C2D7300267924 /* SAtomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAtomic.h; sourceTree = ""; }; - D0445DF81A7C2D7300267924 /* SAtomic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAtomic.m; sourceTree = ""; }; - D0445DF91A7C2D7300267924 /* SBag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBag.h; sourceTree = ""; }; - D0445DFA1A7C2D7300267924 /* SBag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBag.m; sourceTree = ""; }; - D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBlockDisposable.h; sourceTree = ""; }; - D0445DFE1A7C2D7300267924 /* SDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposable.h; sourceTree = ""; }; - D0445DFF1A7C2D7300267924 /* SEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SEvent.h; sourceTree = ""; }; - D0445E001A7C2D7300267924 /* SEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SEvent.m; sourceTree = ""; }; - D0445E011A7C2D7300267924 /* SMetaDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMetaDisposable.m; sourceTree = ""; }; - D0445E021A7C2D7300267924 /* SMulticastSignalManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMulticastSignalManager.h; sourceTree = ""; }; - D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMulticastSignalManager.m; sourceTree = ""; }; - D0445E041A7C2D7300267924 /* SSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSignal.h; sourceTree = ""; }; - D0445E051A7C2D7300267924 /* SSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignal.m; sourceTree = ""; }; - D0445E061A7C2D7300267924 /* SSignal+Accumulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Accumulate.h"; sourceTree = ""; }; - D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Accumulate.m"; sourceTree = ""; }; - D0445E081A7C2D7300267924 /* SSignal+Catch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Catch.h"; sourceTree = ""; }; - D0445E091A7C2D7300267924 /* SSignal+Catch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Catch.m"; sourceTree = ""; }; - D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Combine.h"; sourceTree = ""; }; - D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Combine.m"; sourceTree = ""; }; - D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Dispatch.h"; sourceTree = ""; }; - D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Dispatch.m"; sourceTree = ""; }; - D0445E101A7C2D7300267924 /* SSignal+Mapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Mapping.h"; sourceTree = ""; }; - D0445E111A7C2D7300267924 /* SSignal+Mapping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Mapping.m"; sourceTree = ""; }; - D0445E121A7C2D7300267924 /* SSignal+Meta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Meta.h"; sourceTree = ""; }; - D0445E131A7C2D7300267924 /* SSignal+Meta.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Meta.m"; sourceTree = ""; }; - D0445E141A7C2D7300267924 /* SSignal+Multicast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Multicast.h"; sourceTree = ""; }; - D0445E151A7C2D7300267924 /* SSignal+Multicast.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Multicast.m"; sourceTree = ""; }; - D0445E161A7C2D7300267924 /* SSignal+SideEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+SideEffects.h"; sourceTree = ""; }; - D0445E171A7C2D7300267924 /* SSignal+SideEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+SideEffects.m"; sourceTree = ""; }; - D0445E181A7C2D7300267924 /* SSignal+Single.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Single.h"; sourceTree = ""; }; - D0445E191A7C2D7300267924 /* SSignal+Single.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Single.m"; sourceTree = ""; }; - D0445E1A1A7C2D7300267924 /* SSignal+Timing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Timing.h"; sourceTree = ""; }; - D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Timing.m"; sourceTree = ""; }; - D0445E1C1A7C2D7300267924 /* SSubscriber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSubscriber.h; sourceTree = ""; }; - D0445E1D1A7C2D7300267924 /* SSubscriber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSubscriber.m; sourceTree = ""; }; - D0445E1E1A7C2D7300267924 /* SThreadPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPool.h; sourceTree = ""; }; - D0445E1F1A7C2D7300267924 /* SThreadPool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPool.m; sourceTree = ""; }; - D0445E4C1A7C2D8A00267924 /* SQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQueue.h; sourceTree = ""; }; - D0445E4D1A7C2D8A00267924 /* SQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQueue.m; sourceTree = ""; }; - D0445E501A7C2DBF00267924 /* SMetaDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMetaDisposable.h; sourceTree = ""; }; - D0445E521A7C2E9D00267924 /* STimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STimer.h; sourceTree = ""; }; - D0445E531A7C2E9D00267924 /* STimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STimer.m; sourceTree = ""; }; D0445E561A7C3FB400267924 /* SDisposableTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDisposableTests.m; sourceTree = ""; }; - D0445E5C1A7C446000267924 /* libSSignalKitStatic.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSSignalKitStatic.a; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = ""; }; D06F10721A85882000485185 /* SSignalPerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignalPerformanceTests.m; sourceTree = ""; }; - D08763281A839EDC00632240 /* SDisposableSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDisposableSet.h; sourceTree = ""; }; - D08763291A839EDC00632240 /* SDisposableSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDisposableSet.m; sourceTree = ""; }; - D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPoolTask.m; sourceTree = ""; }; - D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SThreadPoolQueue.m; sourceTree = ""; }; - D089E02F1AC48EA7009A744B /* SThreadPoolQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPoolQueue.h; sourceTree = ""; }; - D089E0301AC48EA7009A744B /* SThreadPoolTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SThreadPoolTask.h; sourceTree = ""; }; - D0FC5B411AF140E600F353AB /* SSignal+Take.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SSignal+Take.h"; sourceTree = ""; }; - D0FC5B421AF140E600F353AB /* SSignal+Take.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SSignal+Take.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + D0085B1E1B282B9800EAF753 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0085B291B282B9800EAF753 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D0085B2D1B282B9800EAF753 /* SwiftSignalKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D0445DD41A7C2CA500267924 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -198,21 +231,72 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - D0445E591A7C446000267924 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + D0085B231B282B9800EAF753 /* SwiftSignalKit */ = { + isa = PBXGroup; + children = ( + D0085B3B1B282BEE00EAF753 /* SwiftSignalKit.h */, + D0085B3C1B282BEE00EAF753 /* Signal_Timing.swift */, + D0085B3D1B282BEE00EAF753 /* Signal_SideEffects.swift */, + D0085B3E1B282BEE00EAF753 /* Signal_Dispatch.swift */, + D0085B3F1B282BEE00EAF753 /* ThreadPool.swift */, + D0085B401B282BEE00EAF753 /* Timer.swift */, + D0085B411B282BEE00EAF753 /* Queue.swift */, + D0085B421B282BEE00EAF753 /* Pipe.swift */, + D0085B431B282BEE00EAF753 /* Bag.swift */, + D0085B441B282BEE00EAF753 /* Signal_Take.swift */, + D0085B451B282BEE00EAF753 /* Signal_Catch.swift */, + D0085B461B282BEE00EAF753 /* Signal_Single.swift */, + D0085B471B282BEE00EAF753 /* Signal_Meta.swift */, + D0085B481B282BEE00EAF753 /* Signal_Combine.swift */, + D0085B491B282BEE00EAF753 /* Atomic.swift */, + D0085B4A1B282BEE00EAF753 /* Signal_Reduce.swift */, + D0085B4B1B282BEE00EAF753 /* Signal.swift */, + D0085B4C1B282BEE00EAF753 /* Disposable.swift */, + D0085B4D1B282BEE00EAF753 /* Signal_Mapping.swift */, + D0085B4E1B282BEE00EAF753 /* Subscriber.swift */, + D0085B261B282B9800EAF753 /* SwiftSignalKit.h */, + D0085B241B282B9800EAF753 /* Supporting Files */, + ); + path = SwiftSignalKit; + sourceTree = ""; + }; + D0085B241B282B9800EAF753 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + D0085B251B282B9800EAF753 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + D0085B301B282B9800EAF753 /* SwiftSignalKitTests */ = { + isa = PBXGroup; + children = ( + D0085B631B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift */, + D0085B641B282C2800EAF753 /* DeallocatingObject.swift */, + D0085B651B282C2800EAF753 /* SwiftSignalKitBasicTests.swift */, + D0085B311B282B9800EAF753 /* Supporting Files */, + ); + path = SwiftSignalKitTests; + sourceTree = ""; + }; + D0085B311B282B9800EAF753 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + D0085B321B282B9800EAF753 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; D0445DCE1A7C2CA500267924 = { isa = PBXGroup; children = ( D0445DDA1A7C2CA500267924 /* SSignalKit */, D0445DE71A7C2CA500267924 /* SSignalKitTests */, + D0085B231B282B9800EAF753 /* SwiftSignalKit */, + D0085B301B282B9800EAF753 /* SwiftSignalKitTests */, D0445DD91A7C2CA500267924 /* Products */, ); sourceTree = ""; @@ -222,7 +306,8 @@ children = ( D0445DD81A7C2CA500267924 /* SSignalKit.framework */, D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */, - D0445E5C1A7C446000267924 /* libSSignalKitStatic.a */, + D0085B221B282B9800EAF753 /* SwiftSignalKit.framework */, + D0085B2C1B282B9800EAF753 /* SwiftSignalKitTests.xctest */, ); name = Products; sourceTree = ""; @@ -230,60 +315,58 @@ D0445DDA1A7C2CA500267924 /* SSignalKit */ = { isa = PBXGroup; children = ( - D02AD5C81B1121010074F9C1 /* SSignal+Pipe.m */, - D02AD5C91B1121010074F9C1 /* SSignal+Pipe.h */, - D0445DF71A7C2D7300267924 /* SAtomic.h */, - D0445DF81A7C2D7300267924 /* SAtomic.m */, - D0445DF91A7C2D7300267924 /* SBag.h */, - D0445DFA1A7C2D7300267924 /* SBag.m */, - D0445DFF1A7C2D7300267924 /* SEvent.h */, - D0445E001A7C2D7300267924 /* SEvent.m */, - D0445DFE1A7C2D7300267924 /* SDisposable.h */, - D0445DFB1A7C2D7300267924 /* SBlockDisposable.h */, - D0445DF61A7C2D7300267924 /* SBlockDisposable.m */, - D0445E501A7C2DBF00267924 /* SMetaDisposable.h */, - D0445E011A7C2D7300267924 /* SMetaDisposable.m */, - D08763281A839EDC00632240 /* SDisposableSet.h */, - D08763291A839EDC00632240 /* SDisposableSet.m */, - D0445E021A7C2D7300267924 /* SMulticastSignalManager.h */, - D0445E031A7C2D7300267924 /* SMulticastSignalManager.m */, - D0445E041A7C2D7300267924 /* SSignal.h */, - D0445E051A7C2D7300267924 /* SSignal.m */, - D0445E061A7C2D7300267924 /* SSignal+Accumulate.h */, - D0445E071A7C2D7300267924 /* SSignal+Accumulate.m */, - D0445E081A7C2D7300267924 /* SSignal+Catch.h */, - D0445E091A7C2D7300267924 /* SSignal+Catch.m */, - D0445E0A1A7C2D7300267924 /* SSignal+Combine.h */, - D0445E0B1A7C2D7300267924 /* SSignal+Combine.m */, - D0445E0E1A7C2D7300267924 /* SSignal+Dispatch.h */, - D0445E0F1A7C2D7300267924 /* SSignal+Dispatch.m */, - D0445E101A7C2D7300267924 /* SSignal+Mapping.h */, - D0445E111A7C2D7300267924 /* SSignal+Mapping.m */, - D0445E121A7C2D7300267924 /* SSignal+Meta.h */, - D0445E131A7C2D7300267924 /* SSignal+Meta.m */, - D0445E141A7C2D7300267924 /* SSignal+Multicast.h */, - D0445E151A7C2D7300267924 /* SSignal+Multicast.m */, - D0445E161A7C2D7300267924 /* SSignal+SideEffects.h */, - D0445E171A7C2D7300267924 /* SSignal+SideEffects.m */, - D0445E181A7C2D7300267924 /* SSignal+Single.h */, - D0445E191A7C2D7300267924 /* SSignal+Single.m */, - D0445E1A1A7C2D7300267924 /* SSignal+Timing.h */, - D0445E1B1A7C2D7300267924 /* SSignal+Timing.m */, - D0FC5B411AF140E600F353AB /* SSignal+Take.h */, - D0FC5B421AF140E600F353AB /* SSignal+Take.m */, - D0445E1C1A7C2D7300267924 /* SSubscriber.h */, - D0445E1D1A7C2D7300267924 /* SSubscriber.m */, - D0445E1E1A7C2D7300267924 /* SThreadPool.h */, - D0445E1F1A7C2D7300267924 /* SThreadPool.m */, - D089E02F1AC48EA7009A744B /* SThreadPoolQueue.h */, - D089E02E1AC48EA7009A744B /* SThreadPoolQueue.m */, - D089E0301AC48EA7009A744B /* SThreadPoolTask.h */, - D089E02D1AC48EA7009A744B /* SThreadPoolTask.m */, - D0445E4C1A7C2D8A00267924 /* SQueue.h */, - D0445E4D1A7C2D8A00267924 /* SQueue.m */, - D0445E521A7C2E9D00267924 /* STimer.h */, - D0445E531A7C2E9D00267924 /* STimer.m */, - D0445DDD1A7C2CA500267924 /* SSignalKit.h */, + D0085AD91B28285400EAF753 /* SAtomic.h */, + D0085ADA1B28285400EAF753 /* SAtomic.m */, + D0085ADB1B28285400EAF753 /* SBag.h */, + D0085ADC1B28285400EAF753 /* SBag.m */, + D0085AD31B28285400EAF753 /* SSubscriber.h */, + D0085AC91B28285400EAF753 /* SSubscriber.m */, + D0085AD41B28285400EAF753 /* SDisposable.h */, + D0085ADF1B28285400EAF753 /* SDisposableSet.h */, + D0085AD01B28285400EAF753 /* SDisposableSet.m */, + D0085AE21B28285400EAF753 /* SMetaDisposable.h */, + D0085AD11B28285400EAF753 /* SMetaDisposable.m */, + D0085ADD1B28285400EAF753 /* SBlockDisposable.h */, + D0085ADE1B28285400EAF753 /* SBlockDisposable.m */, + D0085ACE1B28285400EAF753 /* SThreadPool.h */, + D0085AB21B28285400EAF753 /* SThreadPool.m */, + D0085ACF1B28285400EAF753 /* SThreadPoolTask.h */, + D0085ACB1B28285400EAF753 /* SThreadPoolTask.m */, + D0085ACD1B28285400EAF753 /* SThreadPoolQueue.h */, + D0085ACC1B28285400EAF753 /* SThreadPoolQueue.m */, + D0085AC61B28285400EAF753 /* SQueue.h */, + D0085AB31B28285400EAF753 /* SQueue.m */, + D0085AE51B28285400EAF753 /* STimer.h */, + D0085AE61B28285400EAF753 /* STimer.m */, + D0085AD51B28285400EAF753 /* SSignal.h */, + D0085AB81B28285400EAF753 /* SSignal.m */, + D0085AB71B28285400EAF753 /* SSignal+Single.h */, + D0085AD81B28285400EAF753 /* SSignal+Single.m */, + D0085AD61B28285400EAF753 /* SSignal+Mapping.h */, + D0085AD71B28285400EAF753 /* SSignal+Mapping.m */, + D0085ABC1B28285400EAF753 /* SSignal+Combine.h */, + D0085ABD1B28285400EAF753 /* SSignal+Combine.m */, + D0085AB61B28285400EAF753 /* SSignal+Accumulate.h */, + D0085AC51B28285400EAF753 /* SSignal+Accumulate.m */, + D0085AC01B28285400EAF753 /* SSignal+SideEffects.h */, + D0085AC11B28285400EAF753 /* SSignal+SideEffects.m */, + D0085AC41B28285400EAF753 /* SSignal+Take.h */, + D0085AB41B28285400EAF753 /* SSignal+Take.m */, + D0085AC81B28285400EAF753 /* SSignal+Timing.h */, + D0085AB11B28285400EAF753 /* SSignal+Timing.m */, + D0085AC71B28285400EAF753 /* SSignal+Meta.h */, + D0085AB51B28285400EAF753 /* SSignal+Meta.m */, + D0085ABE1B28285400EAF753 /* SSignal+Pipe.h */, + D0085ABF1B28285400EAF753 /* SSignal+Pipe.m */, + D0085AC31B28285400EAF753 /* SSignal+Catch.h */, + D0085AC21B28285400EAF753 /* SSignal+Catch.m */, + D0085AE31B28285400EAF753 /* SSignal+Dispatch.h */, + D0085ACA1B28285400EAF753 /* SSignal+Dispatch.m */, + D0085AE41B28285400EAF753 /* SSignal+Multicast.h */, + D0085AD21B28285400EAF753 /* SSignal+Multicast.m */, + D0085ABA1B28285400EAF753 /* SMulticastSignalManager.h */, + D0085ABB1B28285400EAF753 /* SMulticastSignalManager.m */, + D0085AB91B28285400EAF753 /* SSignalKit.h */, D0445DDB1A7C2CA500267924 /* Supporting Files */, ); path = SSignalKit; @@ -321,44 +404,88 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + D0085B1F1B282B9800EAF753 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D0085B271B282B9800EAF753 /* SwiftSignalKit.h in Headers */, + D0085B4F1B282BEE00EAF753 /* SwiftSignalKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D0445DD51A7C2CA500267924 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - D0445E481A7C2D7300267924 /* SSubscriber.h in Headers */, - D0445E2E1A7C2D7300267924 /* SMulticastSignalManager.h in Headers */, - D0445E271A7C2D7300267924 /* SBlockDisposable.h in Headers */, - D089E0331AC48EA7009A744B /* SThreadPoolQueue.h in Headers */, - D0445E4A1A7C2D7300267924 /* SThreadPool.h in Headers */, - D0445E541A7C2E9D00267924 /* STimer.h in Headers */, - D0445E301A7C2D7300267924 /* SSignal.h in Headers */, - D089E0341AC48EA7009A744B /* SThreadPoolTask.h in Headers */, - D0445E321A7C2D7300267924 /* SSignal+Accumulate.h in Headers */, - D0445E361A7C2D7300267924 /* SSignal+Combine.h in Headers */, - D0445E2A1A7C2D7300267924 /* SDisposable.h in Headers */, - D0FC5B431AF140E600F353AB /* SSignal+Take.h in Headers */, - D0445E421A7C2D7300267924 /* SSignal+SideEffects.h in Headers */, - D0445E3E1A7C2D7300267924 /* SSignal+Meta.h in Headers */, - D0445E2B1A7C2D7300267924 /* SEvent.h in Headers */, - D0445E341A7C2D7300267924 /* SSignal+Catch.h in Headers */, - D0445E4E1A7C2D8A00267924 /* SQueue.h in Headers */, - D0445E441A7C2D7300267924 /* SSignal+Single.h in Headers */, - D02AD5CB1B1121010074F9C1 /* SSignal+Pipe.h in Headers */, - D0445E251A7C2D7300267924 /* SBag.h in Headers */, - D0445E3A1A7C2D7300267924 /* SSignal+Dispatch.h in Headers */, - D0445E401A7C2D7300267924 /* SSignal+Multicast.h in Headers */, - D0445E511A7C2DBF00267924 /* SMetaDisposable.h in Headers */, - D0445E231A7C2D7300267924 /* SAtomic.h in Headers */, - D087632A1A839EDC00632240 /* SDisposableSet.h in Headers */, - D0445E461A7C2D7300267924 /* SSignal+Timing.h in Headers */, - D0445DDE1A7C2CA500267924 /* SSignalKit.h in Headers */, - D0445E3C1A7C2D7300267924 /* SSignal+Mapping.h in Headers */, + D0085AF61B28285400EAF753 /* SSignal+SideEffects.h in Headers */, + D0085AFD1B28285400EAF753 /* SSignal+Meta.h in Headers */, + D0085AFE1B28285400EAF753 /* SSignal+Timing.h in Headers */, + D0085B0A1B28285400EAF753 /* SDisposable.h in Headers */, + D0085B111B28285400EAF753 /* SBag.h in Headers */, + D0085AF21B28285400EAF753 /* SSignal+Combine.h in Headers */, + D0085AFA1B28285400EAF753 /* SSignal+Take.h in Headers */, + D0085B0B1B28285400EAF753 /* SSignal.h in Headers */, + D0085AED1B28285400EAF753 /* SSignal+Single.h in Headers */, + D0085AF01B28285400EAF753 /* SMulticastSignalManager.h in Headers */, + D0085AF91B28285400EAF753 /* SSignal+Catch.h in Headers */, + D0085B151B28285400EAF753 /* SDisposableSet.h in Headers */, + D0085B0C1B28285400EAF753 /* SSignal+Mapping.h in Headers */, + D0085AFC1B28285400EAF753 /* SQueue.h in Headers */, + D0085B031B28285400EAF753 /* SThreadPoolQueue.h in Headers */, + D0085B091B28285400EAF753 /* SSubscriber.h in Headers */, + D0085B041B28285400EAF753 /* SThreadPool.h in Headers */, + D0085AEC1B28285400EAF753 /* SSignal+Accumulate.h in Headers */, + D0085B1B1B28285400EAF753 /* STimer.h in Headers */, + D0085AF41B28285400EAF753 /* SSignal+Pipe.h in Headers */, + D0085B181B28285400EAF753 /* SMetaDisposable.h in Headers */, + D0085B051B28285400EAF753 /* SThreadPoolTask.h in Headers */, + D0085B1A1B28285400EAF753 /* SSignal+Multicast.h in Headers */, + D0085B191B28285400EAF753 /* SSignal+Dispatch.h in Headers */, + D0085AEF1B28285400EAF753 /* SSignalKit.h in Headers */, + D0085B131B28285400EAF753 /* SBlockDisposable.h in Headers */, + D0085B0F1B28285400EAF753 /* SAtomic.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + D0085B211B282B9800EAF753 /* SwiftSignalKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0085B351B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKit" */; + buildPhases = ( + D0085B1D1B282B9800EAF753 /* Sources */, + D0085B1E1B282B9800EAF753 /* Frameworks */, + D0085B1F1B282B9800EAF753 /* Headers */, + D0085B201B282B9800EAF753 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftSignalKit; + productName = SwiftSignalKit; + productReference = D0085B221B282B9800EAF753 /* SwiftSignalKit.framework */; + productType = "com.apple.product-type.framework"; + }; + D0085B2B1B282B9800EAF753 /* SwiftSignalKitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0085B381B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKitTests" */; + buildPhases = ( + D0085B281B282B9800EAF753 /* Sources */, + D0085B291B282B9800EAF753 /* Frameworks */, + D0085B2A1B282B9800EAF753 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D0085B2F1B282B9800EAF753 /* PBXTargetDependency */, + ); + name = SwiftSignalKitTests; + productName = SwiftSignalKitTests; + productReference = D0085B2C1B282B9800EAF753 /* SwiftSignalKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; D0445DD71A7C2CA500267924 /* SSignalKit */ = { isa = PBXNativeTarget; buildConfigurationList = D0445DEE1A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKit" */; @@ -395,23 +522,6 @@ productReference = D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - D0445E5B1A7C446000267924 /* SSignalKitStatic */ = { - isa = PBXNativeTarget; - buildConfigurationList = D0445E6D1A7C446000267924 /* Build configuration list for PBXNativeTarget "SSignalKitStatic" */; - buildPhases = ( - D0445E581A7C446000267924 /* Sources */, - D0445E591A7C446000267924 /* Frameworks */, - D0445E5A1A7C446000267924 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SSignalKitStatic; - productName = SSignalKitStatic; - productReference = D0445E5C1A7C446000267924 /* libSSignalKitStatic.a */; - productType = "com.apple.product-type.library.static"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -421,15 +531,18 @@ LastUpgradeCheck = 0610; ORGANIZATIONNAME = Telegram; TargetAttributes = { + D0085B211B282B9800EAF753 = { + CreatedOnToolsVersion = 6.3.1; + }; + D0085B2B1B282B9800EAF753 = { + CreatedOnToolsVersion = 6.3.1; + }; D0445DD71A7C2CA500267924 = { CreatedOnToolsVersion = 6.1.1; }; D0445DE21A7C2CA500267924 = { CreatedOnToolsVersion = 6.1.1; }; - D0445E5B1A7C446000267924 = { - CreatedOnToolsVersion = 6.1.1; - }; }; }; buildConfigurationList = D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */; @@ -445,13 +558,28 @@ projectRoot = ""; targets = ( D0445DD71A7C2CA500267924 /* SSignalKit */, - D0445E5B1A7C446000267924 /* SSignalKitStatic */, D0445DE21A7C2CA500267924 /* SSignalKitTests */, + D0085B211B282B9800EAF753 /* SwiftSignalKit */, + D0085B2B1B282B9800EAF753 /* SwiftSignalKitTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + D0085B201B282B9800EAF753 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0085B2A1B282B9800EAF753 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D0445DD61A7C2CA500267924 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -469,36 +597,71 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + D0085B1D1B282B9800EAF753 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0085B521B282BEE00EAF753 /* Signal_Dispatch.swift in Sources */, + D0085B561B282BEE00EAF753 /* Pipe.swift in Sources */, + D0085B551B282BEE00EAF753 /* Queue.swift in Sources */, + D0085B591B282BEE00EAF753 /* Signal_Catch.swift in Sources */, + D0085B601B282BEE00EAF753 /* Disposable.swift in Sources */, + D0085B531B282BEE00EAF753 /* ThreadPool.swift in Sources */, + D0085B5F1B282BEE00EAF753 /* Signal.swift in Sources */, + D0085B5E1B282BEE00EAF753 /* Signal_Reduce.swift in Sources */, + D0085B621B282BEE00EAF753 /* Subscriber.swift in Sources */, + D0085B581B282BEE00EAF753 /* Signal_Take.swift in Sources */, + D0085B501B282BEE00EAF753 /* Signal_Timing.swift in Sources */, + D0085B541B282BEE00EAF753 /* Timer.swift in Sources */, + D0085B5B1B282BEE00EAF753 /* Signal_Meta.swift in Sources */, + D0085B571B282BEE00EAF753 /* Bag.swift in Sources */, + D0085B5A1B282BEE00EAF753 /* Signal_Single.swift in Sources */, + D0085B611B282BEE00EAF753 /* Signal_Mapping.swift in Sources */, + D0085B5C1B282BEE00EAF753 /* Signal_Combine.swift in Sources */, + D0085B5D1B282BEE00EAF753 /* Atomic.swift in Sources */, + D0085B511B282BEE00EAF753 /* Signal_SideEffects.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0085B281B282B9800EAF753 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0085B671B282C2800EAF753 /* DeallocatingObject.swift in Sources */, + D0085B681B282C2800EAF753 /* SwiftSignalKitBasicTests.swift in Sources */, + D0085B661B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D0445DD31A7C2CA500267924 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D0445E451A7C2D7300267924 /* SSignal+Single.m in Sources */, - D0445E2D1A7C2D7300267924 /* SMetaDisposable.m in Sources */, - D0445E3B1A7C2D7300267924 /* SSignal+Dispatch.m in Sources */, - D02AD5CA1B1121010074F9C1 /* SSignal+Pipe.m in Sources */, - D0445E4F1A7C2D8A00267924 /* SQueue.m in Sources */, - D0445E241A7C2D7300267924 /* SAtomic.m in Sources */, - D0445E4B1A7C2D7300267924 /* SThreadPool.m in Sources */, - D0445E551A7C2E9D00267924 /* STimer.m in Sources */, - D089E0321AC48EA7009A744B /* SThreadPoolQueue.m in Sources */, - D0445E3D1A7C2D7300267924 /* SSignal+Mapping.m in Sources */, - D0445E351A7C2D7300267924 /* SSignal+Catch.m in Sources */, - D0445E411A7C2D7300267924 /* SSignal+Multicast.m in Sources */, - D0445E2C1A7C2D7300267924 /* SEvent.m in Sources */, - D0445E261A7C2D7300267924 /* SBag.m in Sources */, - D0445E331A7C2D7300267924 /* SSignal+Accumulate.m in Sources */, - D0445E471A7C2D7300267924 /* SSignal+Timing.m in Sources */, - D0445E311A7C2D7300267924 /* SSignal.m in Sources */, - D087632B1A839EDC00632240 /* SDisposableSet.m in Sources */, - D0FC5B441AF140E600F353AB /* SSignal+Take.m in Sources */, - D089E0311AC48EA7009A744B /* SThreadPoolTask.m in Sources */, - D0445E491A7C2D7300267924 /* SSubscriber.m in Sources */, - D0445E431A7C2D7300267924 /* SSignal+SideEffects.m in Sources */, - D0445E3F1A7C2D7300267924 /* SSignal+Meta.m in Sources */, - D0445E371A7C2D7300267924 /* SSignal+Combine.m in Sources */, - D0445E2F1A7C2D7300267924 /* SMulticastSignalManager.m in Sources */, - D0445E221A7C2D7300267924 /* SBlockDisposable.m in Sources */, + D0085AE91B28285400EAF753 /* SQueue.m in Sources */, + D0085B141B28285400EAF753 /* SBlockDisposable.m in Sources */, + D0085B001B28285400EAF753 /* SSignal+Dispatch.m in Sources */, + D0085AE71B28285400EAF753 /* SSignal+Timing.m in Sources */, + D0085AEB1B28285400EAF753 /* SSignal+Meta.m in Sources */, + D0085B0D1B28285400EAF753 /* SSignal+Mapping.m in Sources */, + D0085AF81B28285400EAF753 /* SSignal+Catch.m in Sources */, + D0085AF11B28285400EAF753 /* SMulticastSignalManager.m in Sources */, + D0085B071B28285400EAF753 /* SMetaDisposable.m in Sources */, + D0085B101B28285400EAF753 /* SAtomic.m in Sources */, + D0085B121B28285400EAF753 /* SBag.m in Sources */, + D0085AEE1B28285400EAF753 /* SSignal.m in Sources */, + D0085B021B28285400EAF753 /* SThreadPoolQueue.m in Sources */, + D0085AFF1B28285400EAF753 /* SSubscriber.m in Sources */, + D0085B081B28285400EAF753 /* SSignal+Multicast.m in Sources */, + D0085B1C1B28285400EAF753 /* STimer.m in Sources */, + D0085AF51B28285400EAF753 /* SSignal+Pipe.m in Sources */, + D0085AF31B28285400EAF753 /* SSignal+Combine.m in Sources */, + D0085AF71B28285400EAF753 /* SSignal+SideEffects.m in Sources */, + D0085AEA1B28285400EAF753 /* SSignal+Take.m in Sources */, + D0085B061B28285400EAF753 /* SDisposableSet.m in Sources */, + D0085AE81B28285400EAF753 /* SThreadPool.m in Sources */, + D0085B011B28285400EAF753 /* SThreadPoolTask.m in Sources */, + D0085B0E1B28285400EAF753 /* SSignal+Single.m in Sources */, + D0085AFB1B28285400EAF753 /* SSignal+Accumulate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -513,41 +676,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - D0445E581A7C446000267924 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D0445E841A7C447D00267924 /* SSignal+Single.m in Sources */, - D0445E781A7C447D00267924 /* SMetaDisposable.m in Sources */, - D0445E7F1A7C447D00267924 /* SSignal+Dispatch.m in Sources */, - D0445E881A7C447D00267924 /* SQueue.m in Sources */, - D089E03A1AC56981009A744B /* SThreadPoolTask.m in Sources */, - D0445E741A7C447D00267924 /* SAtomic.m in Sources */, - D0445E871A7C447D00267924 /* SThreadPool.m in Sources */, - D0445E891A7C447D00267924 /* STimer.m in Sources */, - D0445E801A7C447D00267924 /* SSignal+Mapping.m in Sources */, - D0445E7C1A7C447D00267924 /* SSignal+Catch.m in Sources */, - D0445E821A7C447D00267924 /* SSignal+Multicast.m in Sources */, - D0445E771A7C447D00267924 /* SEvent.m in Sources */, - D0445E751A7C447D00267924 /* SBag.m in Sources */, - D089E0391AC56981009A744B /* SThreadPoolQueue.m in Sources */, - D0445E7B1A7C447D00267924 /* SSignal+Accumulate.m in Sources */, - D0445E851A7C447D00267924 /* SSignal+Timing.m in Sources */, - D0445E7A1A7C447D00267924 /* SSignal.m in Sources */, - D0FC5B451AF141F800F353AB /* SSignal+Take.m in Sources */, - D087632C1A839EE800632240 /* SDisposableSet.m in Sources */, - D0445E861A7C447D00267924 /* SSubscriber.m in Sources */, - D0445E831A7C447D00267924 /* SSignal+SideEffects.m in Sources */, - D0445E811A7C447D00267924 /* SSignal+Meta.m in Sources */, - D0445E7D1A7C447D00267924 /* SSignal+Combine.m in Sources */, - D0445E791A7C447D00267924 /* SMulticastSignalManager.m in Sources */, - D0445E731A7C447D00267924 /* SBlockDisposable.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + D0085B2F1B282B9800EAF753 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D0085B211B282B9800EAF753 /* SwiftSignalKit */; + targetProxy = D0085B2E1B282B9800EAF753 /* PBXContainerItemProxy */; + }; D0445DE61A7C2CA500267924 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D0445DD71A7C2CA500267924 /* SSignalKit */; @@ -556,6 +692,85 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + D0085B361B282B9800EAF753 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = SwiftSignalKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + D0085B371B282B9800EAF753 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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"; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SwiftSignalKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + D0085B391B282B9800EAF753 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = SwiftSignalKitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + D0085B3A1B282B9800EAF753 /* Release */ = { + 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_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; D0445DEC1A7C2CA500267924 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -717,32 +932,25 @@ }; name = Release; }; - D0445E6E1A7C446000267924 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - ONLY_ACTIVE_ARCH = NO; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - D0445E6F1A7C446000267924 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + D0085B351B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0085B361B282B9800EAF753 /* Debug */, + D0085B371B282B9800EAF753 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + D0085B381B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0085B391B282B9800EAF753 /* Debug */, + D0085B3A1B282B9800EAF753 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -770,15 +978,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - D0445E6D1A7C446000267924 /* Build configuration list for PBXNativeTarget "SSignalKitStatic" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - D0445E6E1A7C446000267924 /* Debug */, - D0445E6F1A7C446000267924 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = D0445DCF1A7C2CA500267924 /* Project object */; diff --git a/SSignalKit/SBlockDisposable.h b/SSignalKit/SBlockDisposable.h index 0d130881dd..2914604cba 100644 --- a/SSignalKit/SBlockDisposable.h +++ b/SSignalKit/SBlockDisposable.h @@ -1,4 +1,4 @@ -#import "SDisposable.h" +#import @interface SBlockDisposable : NSObject diff --git a/SSignalKit/SDisposableSet.h b/SSignalKit/SDisposableSet.h index 37924832e6..9cade19504 100644 --- a/SSignalKit/SDisposableSet.h +++ b/SSignalKit/SDisposableSet.h @@ -1,4 +1,4 @@ -#import "SDisposable.h" +#import @interface SDisposableSet : NSObject diff --git a/SSignalKit/SEvent.h b/SSignalKit/SEvent.h deleted file mode 100644 index 7ff523b26b..0000000000 --- a/SSignalKit/SEvent.h +++ /dev/null @@ -1,18 +0,0 @@ -#import - -typedef enum { - SEventTypeNext, - SEventTypeError, - SEventTypeCompleted -} SEventType; - -@interface SEvent : NSObject - -@property (nonatomic, readonly) SEventType type; -@property (nonatomic, strong, readonly) id data; - -- (instancetype)initWithNext:(id)next; -- (instancetype)initWithError:(id)error; -- (instancetype)initWithCompleted; - -@end diff --git a/SSignalKit/SEvent.m b/SSignalKit/SEvent.m deleted file mode 100644 index c3d296633e..0000000000 --- a/SSignalKit/SEvent.m +++ /dev/null @@ -1,37 +0,0 @@ -#import "SEvent.h" - -@implementation SEvent - -- (instancetype)initWithNext:(id)next -{ - self = [super init]; - if (self != nil) - { - _type = SEventTypeNext; - _data = next; - } - return self; -} - -- (instancetype)initWithError:(id)error -{ - self = [super init]; - if (self != nil) - { - _type = SEventTypeError; - _data = error; - } - return self; -} - -- (instancetype)initWithCompleted -{ - self = [super init]; - if (self != nil) - { - _type = SEventTypeCompleted; - } - return self; -} - -@end diff --git a/SSignalKit/SMetaDisposable.h b/SSignalKit/SMetaDisposable.h index b0ce2ce5db..8938f9eacb 100644 --- a/SSignalKit/SMetaDisposable.h +++ b/SSignalKit/SMetaDisposable.h @@ -1,4 +1,4 @@ -#import "SDisposable.h" +#import @interface SMetaDisposable : NSObject diff --git a/SSignalKit/SMulticastSignalManager.h b/SSignalKit/SMulticastSignalManager.h index 7d7391b8f2..243f015a52 100644 --- a/SSignalKit/SMulticastSignalManager.h +++ b/SSignalKit/SMulticastSignalManager.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @interface SMulticastSignalManager : NSObject diff --git a/SSignalKit/SSignal+Accumulate.h b/SSignalKit/SSignal+Accumulate.h index 9b0e8e9d47..1ea8a51ed0 100644 --- a/SSignalKit/SSignal+Accumulate.h +++ b/SSignalKit/SSignal+Accumulate.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @interface SSignal (Accumulate) diff --git a/SSignalKit/SSignal+Catch.h b/SSignalKit/SSignal+Catch.h index ced7b7e1db..5cbdad90c9 100644 --- a/SSignalKit/SSignal+Catch.h +++ b/SSignalKit/SSignal+Catch.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @interface SSignal (Catch) diff --git a/SSignalKit/SSignal+Combine.h b/SSignalKit/SSignal+Combine.h index 95ddb7bd84..d84e065311 100644 --- a/SSignalKit/SSignal+Combine.h +++ b/SSignalKit/SSignal+Combine.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @interface SSignal (Combine) diff --git a/SSignalKit/SSignal+Dispatch.h b/SSignalKit/SSignal+Dispatch.h index 17d74ab452..4b23e0d38a 100644 --- a/SSignalKit/SSignal+Dispatch.h +++ b/SSignalKit/SSignal+Dispatch.h @@ -1,7 +1,7 @@ -#import "SSignal.h" +#import -#import "SQueue.h" -#import "SThreadPool.h" +#import +#import @interface SSignal (Dispatch) diff --git a/SSignalKit/SSignal+Mapping.h b/SSignalKit/SSignal+Mapping.h index 751f72a1e0..d9e810b78a 100644 --- a/SSignalKit/SSignal+Mapping.h +++ b/SSignalKit/SSignal+Mapping.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @interface SSignal (Mapping) diff --git a/SSignalKit/SSignal+Meta.h b/SSignalKit/SSignal+Meta.h index 42c438622d..0aca7db8d7 100644 --- a/SSignalKit/SSignal+Meta.h +++ b/SSignalKit/SSignal+Meta.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @class SQueue; diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 76f411817b..2f0ca89633 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -19,7 +19,6 @@ NSMutableArray *_queuedSignals; bool _queueMode; - } @end diff --git a/SSignalKit/SSignal+Multicast.h b/SSignalKit/SSignal+Multicast.h index 3d3c4fc4e5..e0720cc103 100644 --- a/SSignalKit/SSignal+Multicast.h +++ b/SSignalKit/SSignal+Multicast.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @interface SSignal (Multicast) diff --git a/SSignalKit/SSignal+Multicast.m b/SSignalKit/SSignal+Multicast.m index 3fe3a6f789..92976cff4a 100644 --- a/SSignalKit/SSignal+Multicast.m +++ b/SSignalKit/SSignal+Multicast.m @@ -80,29 +80,44 @@ typedef enum { [currentDisposable dispose]; } -- (void)notify:(SEvent *)event +- (void)notifyNext:(id)next { NSArray *currentSubscribers = nil; OSSpinLockLock(&_lock); currentSubscribers = [_subscribers copyItems]; - if (event.type != SEventTypeNext) - _state = SSignalMulticastStateCompleted; OSSpinLockUnlock(&_lock); for (SSubscriber *subscriber in currentSubscribers) { - switch (event.type) - { - case SEventTypeNext: - [subscriber putNext:event.data]; - break; - case SEventTypeError: - [subscriber putError:event.data]; - break; - case SEventTypeCompleted: - [subscriber putCompletion]; - break; - } + [subscriber putNext:next]; + } +} + +- (void)notifyError:(id)error +{ + NSArray *currentSubscribers = nil; + OSSpinLockLock(&_lock); + currentSubscribers = [_subscribers copyItems]; + _state = SSignalMulticastStateCompleted; + OSSpinLockUnlock(&_lock); + + for (SSubscriber *subscriber in currentSubscribers) + { + [subscriber putError:error]; + } +} + +- (void)notifyCompleted +{ + NSArray *currentSubscribers = nil; + OSSpinLockLock(&_lock); + currentSubscribers = [_subscribers copyItems]; + _state = SSignalMulticastStateCompleted; + OSSpinLockUnlock(&_lock); + + for (SSubscriber *subscriber in currentSubscribers) + { + [subscriber putCompletion]; } } @@ -121,13 +136,13 @@ typedef enum { { id disposable = [self startWithNext:^(id next) { - [subscribers notify:[[SEvent alloc] initWithNext:next]]; + [subscribers notifyNext:next]; } error:^(id error) { - [subscribers notify:[[SEvent alloc] initWithError:error]]; + [subscribers notifyError:error]; } completed:^ { - [subscribers notify:[[SEvent alloc] initWithCompleted]]; + [subscribers notifyCompleted]; }]; [subscribers setDisposable:[[SBlockDisposable alloc] initWithBlock:^ diff --git a/SSignalKit/SSignal+SideEffects.h b/SSignalKit/SSignal+SideEffects.h index 7b58754062..0eead9dcd5 100644 --- a/SSignalKit/SSignal+SideEffects.h +++ b/SSignalKit/SSignal+SideEffects.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @interface SSignal (SideEffects) diff --git a/SSignalKit/SSignal+Single.h b/SSignalKit/SSignal+Single.h index 8ce640da5e..75f48ff569 100644 --- a/SSignalKit/SSignal+Single.h +++ b/SSignalKit/SSignal+Single.h @@ -1,4 +1,4 @@ -#import "SSignal.h" +#import @interface SSignal (Single) diff --git a/SSignalKit/SSignal+Timing.h b/SSignalKit/SSignal+Timing.h index 68c0fe6ca8..4b5d50c90e 100644 --- a/SSignalKit/SSignal+Timing.h +++ b/SSignalKit/SSignal+Timing.h @@ -1,6 +1,6 @@ -#import "SSignal.h" +#import -#import "SQueue.h" +#import @interface SSignal (Timing) diff --git a/SSignalKit/SSignal.h b/SSignalKit/SSignal.h index c3e00ad9fb..d85fa9d3ea 100644 --- a/SSignalKit/SSignal.h +++ b/SSignalKit/SSignal.h @@ -1,4 +1,4 @@ -#import "SSubscriber.h" +#import @interface SSignal : NSObject { diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h index 142eabd2f0..fd17f141ad 100644 --- a/SSignalKit/SSignalKit.h +++ b/SSignalKit/SSignalKit.h @@ -19,7 +19,6 @@ FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; #import #import #import -#import #import #import #import diff --git a/SSignalKit/SSubscriber.h b/SSignalKit/SSubscriber.h index 2689f6c566..37d3368c67 100644 --- a/SSignalKit/SSubscriber.h +++ b/SSignalKit/SSubscriber.h @@ -1,5 +1,4 @@ -#import "SDisposable.h" -#import "SEvent.h" +#import @interface SSubscriber : NSObject { diff --git a/SwiftSignalKit/Atomic.swift b/SwiftSignalKit/Atomic.swift new file mode 100644 index 0000000000..ae7dd94ab4 --- /dev/null +++ b/SwiftSignalKit/Atomic.swift @@ -0,0 +1,36 @@ +import Foundation + +public final class Atomic { + private var lock: OSSpinLock = 0 + private var value: T + + public init(value: T) { + self.value = value + } + + public func with(f: T -> R) -> R { + OSSpinLockLock(&self.lock) + let result = f(self.value) + OSSpinLockUnlock(&self.lock) + + return result + } + + public func modify(f: T -> T) -> T { + OSSpinLockLock(&self.lock) + let result = f(self.value) + self.value = result + OSSpinLockUnlock(&self.lock) + + return result + } + + public func swap(value: T) -> T { + OSSpinLockLock(&self.lock) + let previous = self.value + self.value = value + OSSpinLockUnlock(&self.lock) + + return previous + } +} diff --git a/SwiftSignalKit/Bag.swift b/SwiftSignalKit/Bag.swift new file mode 100644 index 0000000000..b3906960c4 --- /dev/null +++ b/SwiftSignalKit/Bag.swift @@ -0,0 +1,33 @@ +import Foundation + +public final class Bag { + public typealias Index = Int + private var nextIndex: Index = 0 + private var items: [T] = [] + private var itemKeys: [Index] = [] + + public func add(item: T) -> Index { + let key = self.nextIndex + self.nextIndex++ + self.items.append(item) + self.itemKeys.append(key) + + return key + } + + public func remove(index: Index) { + var i = 0 + for key in self.itemKeys { + if key == index { + self.items.removeAtIndex(i) + self.itemKeys.removeAtIndex(i) + break + } + i++ + } + } + + public func copyItems() -> [T] { + return self.items + } +} diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift new file mode 100644 index 0000000000..2efd074979 --- /dev/null +++ b/SwiftSignalKit/Disposable.swift @@ -0,0 +1,129 @@ +import Foundation + +public protocol Disposable +{ + func dispose() +} + +internal struct _EmptyDisposable : Disposable { + internal func dispose() { + } +} + +public let EmptyDisposable: Disposable = _EmptyDisposable() + +public final class ActionDisposable : Disposable +{ + private var action: () -> Void + private var lock: OSSpinLock = 0 + + public init(action: () -> Void) { + self.action = action + } + + public func dispose() { + var action = doNothing + OSSpinLockLock(&self.lock) + action = self.action + self.action = doNothing + OSSpinLockUnlock(&self.lock) + action() + } +} + +public final class MetaDisposable : Disposable +{ + private var lock: OSSpinLock = 0 + private var disposed = false + private var disposable: Disposable! = nil + + public init() { + } + + public func set(disposable: Disposable?) { + var previousDisposable: Disposable! = nil + var disposeImmediately = false + + OSSpinLockLock(&self.lock) + disposeImmediately = self.disposed + if !disposeImmediately { + previousDisposable = self.disposable + if let disposable = disposable { + self.disposable = disposable + } else { + self.disposable = nil + } + } + OSSpinLockUnlock(&self.lock) + + if previousDisposable != nil { + previousDisposable.dispose() + } + + if disposeImmediately { + if let disposable = disposable { + disposable.dispose() + } + } + } + + public func dispose() + { + var disposable: Disposable! = nil + + OSSpinLockLock(&self.lock) + if !self.disposed { + self.disposed = true + disposable = self.disposable + self.disposable = nil + } + OSSpinLockUnlock(&self.lock) + + if disposable != nil { + disposable.dispose() + } + } +} + +public final class DisposableSet : Disposable { + private var lock: OSSpinLock = 0 + private var disposed = false + private var disposables: [Disposable] = [] + + public init() { + + } + + public func add(disposable: Disposable) { + var disposeImmediately = false + + OSSpinLockLock(&self.lock) + if self.disposed { + disposeImmediately = true + } else { + self.disposables.append(disposable) + } + OSSpinLockUnlock(&self.lock) + + if disposeImmediately { + disposable.dispose() + } + } + + public func dispose() { + var disposables: [Disposable] = [] + OSSpinLockLock(&self.lock) + if !self.disposed { + self.disposed = true + disposables = self.disposables + self.disposables = [] + } + OSSpinLockUnlock(&self.lock) + + if disposables.count != 0 { + for disposable in disposables { + disposable.dispose() + } + } + } +} diff --git a/SwiftSignalKit/Info.plist b/SwiftSignalKit/Info.plist new file mode 100644 index 0000000000..f6228f96e7 --- /dev/null +++ b/SwiftSignalKit/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.telegram.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/SwiftSignalKit/Pipe.swift b/SwiftSignalKit/Pipe.swift new file mode 100644 index 0000000000..c5d8d7b376 --- /dev/null +++ b/SwiftSignalKit/Pipe.swift @@ -0,0 +1,40 @@ +import Foundation + +public final class Pipe { + let subscribers = Atomic(value: Bag Void>()) + + public init() { + + } + + public func signal() -> Signal { + return Signal { [weak self] subscriber in + if let strongSelf = self { + var index = strongSelf.subscribers.with { value -> Bag.Index in + return value.add { next in + subscriber.putNext(next) + } + } + + return ActionDisposable { [weak strongSelf] in + if let strongSelf = strongSelf { + strongSelf.subscribers.with { value -> Void in + value.remove(index) + } + } + } + } else { + return EmptyDisposable + } + } + } + + public func putNext(next: T) { + let items = self.subscribers.with { value -> [T -> Void] in + return value.copyItems() + } + for f in items { + f(next) + } + } +} diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift new file mode 100644 index 0000000000..9245ce58cc --- /dev/null +++ b/SwiftSignalKit/Queue.swift @@ -0,0 +1,69 @@ +import Foundation + +private let _QueueSpecificKey = NSObject() +private let QueueSpecificKey: UnsafePointer = UnsafePointer(Unmanaged.passUnretained(_QueueSpecificKey).toOpaque()) + +public final class Queue { + private let nativeQueue: dispatch_queue_t + private var specific: UnsafeMutablePointer + private let specialIsMainQueue: Bool + + public var queue: dispatch_queue_t { + get { + return self.nativeQueue + } + } + + public class func mainQueue() -> Queue { + return Queue(queue: dispatch_get_main_queue(), specialIsMainQueue: true) + } + + public class func concurrentDefaultQueue() -> Queue { + return Queue(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), specialIsMainQueue: false) + } + + public class func concurrentBackgroundQueue() -> Queue { + return Queue(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), specialIsMainQueue: false) + } + + public init(queue: dispatch_queue_t) { + self.nativeQueue = queue + self.specific = nil + self.specialIsMainQueue = false + } + + private init(queue: dispatch_queue_t, specialIsMainQueue: Bool) { + self.nativeQueue = queue + self.specific = nil + self.specialIsMainQueue = specialIsMainQueue + } + + public init() { + self.nativeQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) + self.specific = nil + self.specialIsMainQueue = false + + self.specific = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()) + dispatch_queue_set_specific(self.nativeQueue, QueueSpecificKey, self.specific, nil) + } + + public func async(f: Void -> Void) { + if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { + f() + } else if self.specialIsMainQueue && NSThread.isMainThread() { + f() + } else { + dispatch_async(self.nativeQueue, f) + } + } + + public func dispatch(f: Void -> Void) { + if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { + f() + } else if self.specialIsMainQueue && NSThread.isMainThread() { + f() + } else { + dispatch_async(self.nativeQueue, f) + } + } +} diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift new file mode 100644 index 0000000000..14de82b28e --- /dev/null +++ b/SwiftSignalKit/Signal.swift @@ -0,0 +1,43 @@ +import Foundation + +internal let doNothing: () -> Void = { _ in } + +public func identity(a: A) -> A { + return a; +} + +infix operator |> { associativity left precedence 95 } + +public func |> (value: T, function: (T -> U)) -> U { + return function(value) +} + +private final class SubscriberDisposable : Disposable { + private let subscriber: Subscriber + private let disposable: Disposable + + init(subscriber: Subscriber, disposable: Disposable) { + self.subscriber = subscriber + self.disposable = disposable + } + + func dispose() { + subscriber.markTerminatedWithoutDisposal() + disposable.dispose() + } +} + +public struct Signal { + private let generator: Subscriber -> Disposable + + public init(_ generator: Subscriber -> Disposable) { + self.generator = generator + } + + 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) + } +} diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift new file mode 100644 index 0000000000..3aa10366b7 --- /dev/null +++ b/SwiftSignalKit/Signal_Catch.swift @@ -0,0 +1,61 @@ +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) + + disposable.add(anotherSignal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + }, completed: { + subscriber.putCompletion() + })) + + return disposable + } +} + +private func recursiveFunction(f: (Void -> Void) -> Void) -> (Void -> Void) { + return { + f(recursiveFunction(f)) + } +} + +public func restart(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 + } + if currentShouldRestart { + let disposable = signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + recurse() + }) + currentDisposable.set(disposable) + } + } + + start() + + return ActionDisposable { + currentDisposable.dispose() + shouldRestart.swap(false) + } + } +} diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift new file mode 100644 index 0000000000..e73d881fdd --- /dev/null +++ b/SwiftSignalKit/Signal_Combine.swift @@ -0,0 +1,91 @@ +import Foundation + +private struct SignalCombineState { + let values: [Int : Any] + let completed: Set + let error: Bool +} + +private func combineLatestAny(signals: [Signal], combine: [Any] -> R) -> Signal { + return Signal { subscriber in + + let state = Atomic(value: SignalCombineState(values: [:], completed: Set(), error: false)) + let disposable = DisposableSet() + + let count = signals.count + for index in 0 ..< count { + let signalDisposable = signals[index].start(next: { next in + let currentState = state.modify { current in + var values = current.values + values[index] = next + return SignalCombineState(values: values, completed: current.completed, error: current.error) + } + if currentState.values.count == count { + var values: [Any] = [] + for i in 0 ..< count { + values.append(currentState.values[i]!) + } + subscriber.putNext(combine(values)) + } + }, error: { error in + var emitError = false + state.modify { current in + if !current.error { + emitError = true + return SignalCombineState(values: current.values, completed: current.completed, error: true) + } else { + return current + } + } + }, completed: { + var emitCompleted = false + state.modify { current in + if !current.completed.contains(index) { + var completed = current.completed + completed.insert(index) + emitCompleted = completed.count == count + return SignalCombineState(values: current.values, completed: completed, error: current.error) + } + return current + } + if emitCompleted { + subscriber.putCompletion() + } + }) + + disposable.add(signalDisposable) + } + + return disposable; + } +} + +private func signalOfAny(signal: Signal) -> Signal { + return Signal { subscriber in + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } +} + +public func combineLatest(s1: Signal, s2: Signal) -> Signal<(T1, T2), E> { + return combineLatestAny([signalOfAny(s1), signalOfAny(s2)], { values in + return (values[0] as! T1, values[1] as! T2) + }) +} + +public func combineLatest(s1: Signal, s2: Signal, s3: Signal) -> Signal<(T1, T2, T3), E> { + return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3)], { values in + return (values[0] as! T1, values[1] as! T2, values[2] as! T3) + }) +} + +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)], { values in + return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4) + }) +} diff --git a/SwiftSignalKit/Signal_Dispatch.swift b/SwiftSignalKit/Signal_Dispatch.swift new file mode 100644 index 0000000000..f9cbf2f67a --- /dev/null +++ b/SwiftSignalKit/Signal_Dispatch.swift @@ -0,0 +1,77 @@ +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 { + 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(threadPool: ThreadPool)(signal: Signal) -> Signal { + return Signal { subscriber in + var 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(ActionDisposable { + task.cancel() + }) + + threadPool.addTask(task) + + return disposable + } +} diff --git a/SwiftSignalKit/Signal_Mapping.swift b/SwiftSignalKit/Signal_Mapping.swift new file mode 100644 index 0000000000..abde9df344 --- /dev/null +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -0,0 +1,27 @@ +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 filter(f: T -> Bool)(signal: Signal) -> Signal { + 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() + }) + } +} diff --git a/SwiftSignalKit/Signal_Meta.swift b/SwiftSignalKit/Signal_Meta.swift new file mode 100644 index 0000000000..20ef3a5fde --- /dev/null +++ b/SwiftSignalKit/Signal_Meta.swift @@ -0,0 +1,153 @@ +import Foundation + +private final class SignalQueueState : Disposable { + var lock: OSSpinLock = 0 + var executingSignal = false + var terminated = false + + var disposable: Disposable = EmptyDisposable + let currentDisposable = MetaDisposable() + let subscriber: Subscriber + + var queuedSignals: [Signal] = [] + let queueMode: Bool + + init(subscriber: Subscriber, queueMode: Bool) { + self.subscriber = subscriber + self.queueMode = queueMode + } + + func beginWithDisposable(disposable: Disposable) { + self.disposable = disposable + } + + func enqueueSignal(signal: Signal) { + var startSignal = false + OSSpinLockLock(&self.lock) + if self.queueMode && self.executingSignal { + self.queuedSignals.append(signal) + } else { + self.executingSignal = true + startSignal = true + } + OSSpinLockUnlock(&self.lock) + + if startSignal { + let disposable = signal.start(next: { next in + self.subscriber.putNext(next) + }, error: { error in + self.subscriber.putError(error) + }, completed: { + self.headCompleted() + }) + self.currentDisposable.set(disposable) + } + } + + func headCompleted() { + var nextSignal: Signal! = nil + + var terminated = false + OSSpinLockLock(&self.lock) + self.executingSignal = false + if self.queueMode { + if self.queuedSignals.count != 0 { + nextSignal = self.queuedSignals[0] + self.queuedSignals.removeAtIndex(0) + self.executingSignal = true + } else { + terminated = self.terminated + } + } else { + terminated = self.terminated + } + OSSpinLockUnlock(&self.lock) + + if terminated { + self.subscriber.putCompletion() + } else if nextSignal != nil { + let disposable = nextSignal.start(next: { next in + self.subscriber.putNext(next) + }, error: { error in + self.subscriber.putError(error) + }, completed: { + self.headCompleted() + }) + } + } + + func beginCompletion() { + var executingSignal = false + OSSpinLockLock(&self.lock) + executingSignal = self.executingSignal + self.terminated = true + OSSpinLockUnlock(&self.lock) + + if !executingSignal { + self.subscriber.putCompletion() + } + } + + func dispose() { + self.currentDisposable.dispose() + self.disposable.dispose() + } +} + +public func switchToLatest(signal: Signal, E>) -> Signal { + return Signal { subscriber in + let state = SignalQueueState(subscriber: subscriber, queueMode: false) + state.beginWithDisposable(signal.start(next: { next in + state.enqueueSignal(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + state.beginCompletion() + })) + return state + } +} + +public func queue(signal: Signal, E>) -> Signal { + return Signal { subscriber in + let state = SignalQueueState(subscriber: subscriber, queueMode: true) + state.beginWithDisposable(signal.start(next: { next in + state.enqueueSignal(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + state.beginCompletion() + })) + return state + } +} + +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) + }, 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 + } +} diff --git a/SwiftSignalKit/Signal_Reduce.swift b/SwiftSignalKit/Signal_Reduce.swift new file mode 100644 index 0000000000..e5a4671b84 --- /dev/null +++ b/SwiftSignalKit/Signal_Reduce.swift @@ -0,0 +1,34 @@ +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) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putNext(currentValue) + subscriber.putCompletion() + }) + } +} diff --git a/SwiftSignalKit/Signal_SideEffects.swift b/SwiftSignalKit/Signal_SideEffects.swift new file mode 100644 index 0000000000..53989606ab --- /dev/null +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -0,0 +1,45 @@ +import Foundation + +public func beforeNext(f: T -> R)(signal: Signal) -> Signal { + return Signal { subscriber in + return signal.start(next: { next in + let unused = 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 unused = 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 unused = f() + }) + + return disposable + } +} \ No newline at end of file diff --git a/SwiftSignalKit/Signal_Single.swift b/SwiftSignalKit/Signal_Single.swift new file mode 100644 index 0000000000..8adc2d8b53 --- /dev/null +++ b/SwiftSignalKit/Signal_Single.swift @@ -0,0 +1,28 @@ +import Foundation + +extension Signal { + public static func single(value: T) -> Signal { + return Signal { subscriber in + subscriber.putNext(value) + subscriber.putCompletion() + + return EmptyDisposable + } + } + + public static func fail(error: E) -> Signal { + return Signal { subscriber in + subscriber.putError(error) + + return EmptyDisposable + } + } + + public static func complete() -> Signal { + return Signal { subscriber in + subscriber.putCompletion() + + return EmptyDisposable + } + } +} diff --git a/SwiftSignalKit/Signal_Take.swift b/SwiftSignalKit/Signal_Take.swift new file mode 100644 index 0000000000..d2e11c1a2f --- /dev/null +++ b/SwiftSignalKit/Signal_Take.swift @@ -0,0 +1,27 @@ +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 { + subscriber.putCompletion() + } + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } +} diff --git a/SwiftSignalKit/Signal_Timing.swift b/SwiftSignalKit/Signal_Timing.swift new file mode 100644 index 0000000000..6d1eb39ede --- /dev/null +++ b/SwiftSignalKit/Signal_Timing.swift @@ -0,0 +1,56 @@ +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 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 + 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() + })) + 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 new file mode 100644 index 0000000000..2b74e2f57c --- /dev/null +++ b/SwiftSignalKit/Subscriber.swift @@ -0,0 +1,101 @@ +import Foundation + +public final class Subscriber { + private var next: (T -> Void)! + private var error: (E -> Void)! + private var completed: (() -> Void)! + + private var lock: OSSpinLock = 0 + private var terminated = false + internal var disposable: Disposable! + + public init(next: (T -> Void)! = nil, error: (E -> Void)! = nil, completed: (() -> Void)! = nil) { + self.next = next + self.error = error + self.completed = completed + } + + internal func assignDisposable(disposable: Disposable) { + if self.terminated { + disposable.dispose() + } else { + self.disposable = disposable + } + } + + internal func markTerminatedWithoutDisposal() { + OSSpinLockLock(&self.lock) + if !self.terminated { + self.terminated = true + self.next = nil + self.error = nil + self.completed = nil + } + OSSpinLockUnlock(&self.lock) + } + + public func putNext(next: T) { + var action: (T -> Void)! = nil + OSSpinLockLock(&self.lock) + if !self.terminated { + action = self.next + } + OSSpinLockUnlock(&self.lock) + + if action != nil { + action(next) + } + } + + public func putError(error: E) { + var shouldDispose = false + var action: (E -> Void)! = nil + + OSSpinLockLock(&self.lock); + if !self.terminated { + action = self.error + shouldDispose = true; + self.next = nil + self.error = nil + self.completed = nil; + self.terminated = true + } + OSSpinLockUnlock(&self.lock); + + if action != nil { + action(error) + } + + if shouldDispose && self.disposable != nil { + let disposable = self.disposable + disposable.dispose() + self.disposable = nil + } + } + + public func putCompletion() { + var shouldDispose = false + var action: (() -> Void)! = nil + + OSSpinLockLock(&self.lock); + if !self.terminated { + action = self.completed + shouldDispose = true; + self.next = nil + self.error = nil + self.completed = nil; + self.terminated = true + } + OSSpinLockUnlock(&self.lock); + + if action != nil { + action() + } + + if shouldDispose && self.disposable != nil { + let disposable = self.disposable + disposable.dispose() + self.disposable = nil + } + } +} diff --git a/SwiftSignalKit/SwiftSignalKit.h b/SwiftSignalKit/SwiftSignalKit.h new file mode 100644 index 0000000000..e78eb85e84 --- /dev/null +++ b/SwiftSignalKit/SwiftSignalKit.h @@ -0,0 +1,19 @@ +// +// SwiftSignalKit.h +// SwiftSignalKit +// +// Created by Peter on 10/06/15. +// Copyright (c) 2015 Telegram. All rights reserved. +// + +#import + +//! Project version number for SwiftSignalKit. +FOUNDATION_EXPORT double SwiftSignalKitVersionNumber; + +//! Project version string for SwiftSignalKit. +FOUNDATION_EXPORT const unsigned char SwiftSignalKitVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/SwiftSignalKit/ThreadPool.swift b/SwiftSignalKit/ThreadPool.swift new file mode 100644 index 0000000000..295f87c5d1 --- /dev/null +++ b/SwiftSignalKit/ThreadPool.swift @@ -0,0 +1,154 @@ +import Foundation + +public final class ThreadPoolTaskState { + public var cancelled = false +} + +public final class ThreadPoolTask { + private let state = ThreadPoolTaskState() + private let action: ThreadPoolTaskState -> () + + public init(_ action: ThreadPoolTaskState -> ()) { + self.action = action + } + + internal func execute() { + if !state.cancelled { + self.action(self.state) + } + } + + public func cancel() { + self.state.cancelled = true + } +} + +public final class ThreadPoolQueue : Equatable { + private weak var threadPool: ThreadPool? + private var tasks: [ThreadPoolTask] = [] + + public init(threadPool: ThreadPool) { + self.threadPool = threadPool + } + + public func addTask(task: ThreadPoolTask) { + if let threadPool = self.threadPool { + threadPool.workOnQueue(self, action: { + self.tasks.append(task) + }) + } + } + + private func popFirstTask() -> ThreadPoolTask? { + if self.tasks.count != 0 { + let task = self.tasks[0]; + self.tasks.removeAtIndex(0) + return task + } else { + return nil + } + } + + private func hasTasks() -> Bool { + return self.tasks.count != 0 + } +} + +public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { + return lhs === rhs +} + +@objc public final class ThreadPool { + private var threads: [NSThread] = [] + private var queues: [ThreadPoolQueue] = [] + private var takenQueues: [ThreadPoolQueue] = [] + private var mutex: pthread_mutex_t + private var condition: pthread_cond_t + + private class func threadEntryPoint(threadPool: ThreadPool) { + var queue: ThreadPoolQueue! + + while (true) { + var task: ThreadPoolTask! + + pthread_mutex_lock(&threadPool.mutex); + + if queue != nil { + if let index = find(threadPool.takenQueues, queue) { + threadPool.takenQueues.removeAtIndex(index) + } + + if queue.hasTasks() { + threadPool.queues.append(queue); + } + } + + while (true) + { + while threadPool.queues.count == 0 { + pthread_cond_wait(&threadPool.condition, &threadPool.mutex); + } + + if threadPool.queues.count != 0 { + queue = threadPool.queues[0] + } + + if queue != nil { + task = queue.popFirstTask() + threadPool.takenQueues.append(queue) + + if let index = find(threadPool.queues, queue) { + threadPool.queues.removeAtIndex(index) + } + + break + } + } + pthread_mutex_unlock(&threadPool.mutex); + + if task != nil { + task.execute() + } + } + } + + public init(threadCount: Int, threadPriority: Double) { + assert(threadCount > 0, "threadCount < 0") + + self.mutex = pthread_mutex_t() + self.condition = pthread_cond_t() + pthread_mutex_init(&self.mutex, nil) + pthread_cond_init(&self.condition, nil) + + for i in 0 ..< threadCount { + var thread = NSThread(target: ThreadPool.self, selector: Selector("threadEntryPoint"), object: self) + thread.threadPriority = threadPriority + self.threads.append(thread) + thread.start() + } + } + + deinit { + pthread_mutex_destroy(&self.mutex) + pthread_cond_destroy(&self.condition) + } + + public func addTask(task: ThreadPoolTask) { + let tempQueue = self.nextQueue() + tempQueue.addTask(task) + } + + private func workOnQueue(queue: ThreadPoolQueue, action: () -> ()) { + pthread_mutex_lock(&self.mutex) + action() + if !contains(self.queues, queue) && !contains(self.takenQueues, queue) { + self.queues.append(queue) + } + pthread_cond_broadcast(&self.condition) + pthread_mutex_unlock(&self.mutex) + } + + public func nextQueue() -> ThreadPoolQueue { + return ThreadPoolQueue(threadPool: self) + } +} \ No newline at end of file diff --git a/SwiftSignalKit/Timer.swift b/SwiftSignalKit/Timer.swift new file mode 100644 index 0000000000..c4acfbcb6b --- /dev/null +++ b/SwiftSignalKit/Timer.swift @@ -0,0 +1,41 @@ +import Foundation + +public final class Timer { + private var timer: dispatch_source_t! + private var timeout: NSTimeInterval + private var repeat: Bool + private var completion: Void -> Void + private var queue: Queue + + public init(timeout: NSTimeInterval, repeat: Bool, completion: Void -> Void, queue: Queue) { + self.timeout = timeout + self.repeat = repeat + self.completion = completion + self.queue = queue + } + + deinit { + self.invalidate() + } + + 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 + if let strongSelf = self { + strongSelf.completion() + if !strongSelf.repeat { + strongSelf.invalidate() + } + } + }) + dispatch_resume(self.timer) + } + + public func invalidate() { + if self.timer != nil { + dispatch_source_cancel(self.timer) + self.timer = nil + } + } +} diff --git a/SwiftSignalKitTests/DeallocatingObject.swift b/SwiftSignalKitTests/DeallocatingObject.swift new file mode 100644 index 0000000000..c4d12389b2 --- /dev/null +++ b/SwiftSignalKitTests/DeallocatingObject.swift @@ -0,0 +1,19 @@ +import Foundation + +internal class DeallocatingObject : Printable { + private var deallocated: UnsafeMutablePointer + + init(deallocated: UnsafeMutablePointer) { + self.deallocated = deallocated + } + + deinit { + self.deallocated.memory = true + } + + public var description: String { + get { + return "" + } + } +} diff --git a/SwiftSignalKitTests/Info.plist b/SwiftSignalKitTests/Info.plist new file mode 100644 index 0000000000..29dacae6b5 --- /dev/null +++ b/SwiftSignalKitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.telegram.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift new file mode 100644 index 0000000000..91ed5ac9fa --- /dev/null +++ b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift @@ -0,0 +1,259 @@ +import UIKit +import XCTest +import SwiftSignalKit + +class SwiftSignalKitTests: XCTestCase { + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testActionDisposableDisposed() { + var deallocated = false + var disposed = false + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + object.debugDescription + disposed = true + }) + object = nil + XCTAssertFalse(deallocated, "deallocated != false") + disposable.dispose() + } + + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertTrue(disposed, "disposed != true") + } + + func testActionDisposableNotDisposed() { + var deallocated = false + var disposed = false + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + object.debugDescription + disposed = true + }) + } + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertFalse(disposed, "disposed != false") + } + + func testMetaDisposableDisposed() { + var deallocated = false + var disposed = false + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + object.debugDescription + disposed = true + }) + + let metaDisposable = MetaDisposable() + metaDisposable.set(disposable) + metaDisposable.dispose() + } + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertTrue(disposed, "disposed != true") + } + + func testMetaDisposableDisposedMultipleTimes() { + var deallocated1 = false + var disposed1 = false + var deallocated2 = false + var disposed2 = false + if true { + var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + object1.debugDescription + disposed1 = true + }) + + var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + object2.debugDescription + disposed2 = true + }) + + let metaDisposable = MetaDisposable() + metaDisposable.set(actionDisposable1) + metaDisposable.set(actionDisposable2) + metaDisposable.dispose() + } + XCTAssertTrue(deallocated1, "deallocated1 != true") + XCTAssertTrue(disposed1, "disposed1 != true") + XCTAssertTrue(deallocated2, "deallocated2 != true") + XCTAssertTrue(disposed2, "disposed2 != true") + } + + func testMetaDisposableNotDisposed() { + var deallocated = false + var disposed = false + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + object.debugDescription + disposed = true + }) + + let metaDisposable = MetaDisposable() + metaDisposable.set(disposable) + } + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertFalse(disposed, "disposed != false") + } + + func testDisposableSetSingleDisposed() { + var deallocated = false + var disposed = false + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + object.debugDescription + disposed = true + }) + + let disposableSet = DisposableSet() + disposableSet.add(disposable) + disposableSet.dispose() + } + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertTrue(disposed, "disposed != true") + } + + func testDisposableSetMultipleDisposed() { + var deallocated1 = false + var disposed1 = false + var deallocated2 = false + var disposed2 = false + if true { + var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + object1.debugDescription + disposed1 = true + }) + + var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + object2.debugDescription + disposed2 = true + }) + + let disposableSet = DisposableSet() + disposableSet.add(actionDisposable1) + disposableSet.add(actionDisposable2) + disposableSet.dispose() + } + XCTAssertTrue(deallocated1, "deallocated1 != true") + XCTAssertTrue(disposed1, "disposed1 != true") + XCTAssertTrue(deallocated2, "deallocated2 != true") + XCTAssertTrue(disposed2, "disposed2 != true") + } + + func testDisposableSetSingleNotDisposed() { + var deallocated = false + var disposed = false + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + object.debugDescription + disposed = true + }) + + let disposableSet = DisposableSet() + disposableSet.add(disposable) + } + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertFalse(disposed, "disposed != false") + } + + func testDisposableSetMultipleNotDisposed() { + var deallocated1 = false + var disposed1 = false + var deallocated2 = false + var disposed2 = false + if true { + var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + object1.debugDescription + disposed1 = true + }) + + var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + object2.debugDescription + disposed2 = true + }) + + let disposableSet = DisposableSet() + disposableSet.add(actionDisposable1) + disposableSet.add(actionDisposable2) + } + XCTAssertTrue(deallocated1, "deallocated1 != true") + XCTAssertFalse(disposed1, "disposed1 != false") + XCTAssertTrue(deallocated2, "deallocated2 != true") + XCTAssertFalse(disposed2, "disposed2 != false") + } + + func testMetaDisposableAlreadyDisposed() { + var deallocated1 = false + var disposed1 = false + var deallocated2 = false + var disposed2 = false + if true { + var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + object1.debugDescription + disposed1 = true + }) + + var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + object2.debugDescription + disposed2 = true + }) + + let metaDisposable = MetaDisposable() + metaDisposable.set(actionDisposable1) + metaDisposable.dispose() + metaDisposable.set(actionDisposable2) + } + XCTAssertTrue(deallocated1, "deallocated1 != true") + XCTAssertTrue(disposed1, "disposed1 != true") + XCTAssertTrue(deallocated2, "deallocated2 != true") + XCTAssertTrue(disposed2, "disposed2 != true") + } + + func testDisposableSetAlreadyDisposed() { + var deallocated1 = false + var disposed1 = false + var deallocated2 = false + var disposed2 = false + if true { + var object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + object1.debugDescription + disposed1 = true + }) + + var object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + object2.debugDescription + disposed2 = true + }) + + let disposableSet = DisposableSet() + disposableSet.add(actionDisposable1) + disposableSet.dispose() + disposableSet.add(actionDisposable2) + } + XCTAssertTrue(deallocated1, "deallocated1 != true") + XCTAssertTrue(disposed1, "disposed1 != true") + XCTAssertTrue(deallocated2, "deallocated2 != true") + XCTAssertTrue(disposed2, "disposed2 != true") + } +} diff --git a/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift b/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift new file mode 100644 index 0000000000..80f276cb8c --- /dev/null +++ b/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift @@ -0,0 +1,660 @@ +import UIKit +import XCTest +import SwiftSignalKit + +func singleSignalInt(value: Signal) -> Signal, Void> { + return Signal { subscriber in + subscriber.putNext(value) + subscriber.putCompletion() + return EmptyDisposable + } +} + +class SwiftSignalKitFunctionsTests: XCTestCase { + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testSignalGenerated() { + var deallocated = false + var disposed = false + var generated = false + + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let signal = Signal { [object] subscriber in + subscriber.putNext(1) + return ActionDisposable { + object?.description + disposed = true + } + } + + let disposable = signal.start(next: { [object] next in + generated = true + object?.description + }) + + object = nil + + XCTAssertFalse(deallocated, "deallocated != false") + + disposable.dispose() + } + + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertTrue(disposed, "disposed != true") + XCTAssertTrue(generated, "generated != true") + } + + func testSignalGeneratedCompleted() { + var deallocated = false + var disposed = false + var generated = false + var completed = false + + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let signal = Signal { [object] subscriber in + subscriber.putNext(1) + subscriber.putCompletion() + + return ActionDisposable { + object?.description + disposed = true + } + } + + let disposable = signal.start(next: { [object] next in + generated = true + object?.description + }, completed: { [object] + completed = true + object?.description + }) + + object = nil + + XCTAssertFalse(deallocated, "deallocated != false") + + disposable.dispose() + } + + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertTrue(disposed, "disposed != true") + XCTAssertTrue(generated, "generated != true") + XCTAssertTrue(completed, "completed != true") + } + + func testSignalGeneratedError() { + var deallocated = false + var disposed = false + var generated = false + var completed = false + var error = false + + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let signal = Signal { [object] subscriber in + subscriber.putError() + subscriber.putNext(1) + + return ActionDisposable { + object?.description + disposed = true + } + } + + let disposable = signal.start(next: { [object] next in + generated = true + object?.description + }, error: { [object] _ in + error = true + object?.description + }, + completed: { [object] + completed = true + object?.description + }) + + object = nil + + XCTAssertFalse(deallocated, "deallocated != false") + + disposable.dispose() + } + + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertTrue(disposed, "disposed != true") + XCTAssertFalse(generated, "generated != false") + XCTAssertFalse(completed, "completed != false") + XCTAssertTrue(error, "error != true") + } + + func testMap() { + var deallocated = false + var disposed = false + var generated = false + + if true { + var object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + var signal = Signal { [object] subscriber in + subscriber.putNext(1) + + return ActionDisposable { + object?.description + disposed = true + } + } + signal = signal |> map { $0 * 2} + + let disposable = signal.start(next: { [object] next in + generated = next == 2 + object?.description + }) + + object = nil + + XCTAssertFalse(deallocated, "deallocated != false") + + disposable.dispose() + } + + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertTrue(disposed, "disposed != true") + XCTAssertTrue(generated, "generated != true") + } + + func testCatch() { + let failingSignal = Signal { subscriber in + subscriber.putNext(1) + subscriber.putError(1) + return EmptyDisposable + } + + let catchSignal = failingSignal |> catch { error in + return Signal { subscriber in + subscriber.putNext(error * 2) + return EmptyDisposable + } + } + + var result = 0 + catchSignal.start(next: { next in + result += next + }) + + XCTAssertTrue(result == 3, "result != 2") + } + + func testSubscriberDisposal() { + var disposed = false + var generated = false + var queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); + + if true { + let signal = Signal { subscriber in + dispatch_async(queue, { + usleep(200) + subscriber.putNext(1) + }) + return ActionDisposable { + disposed = true + } + } + + let disposable = signal.start(next: { next in + generated = true + }) + disposable.dispose() + + dispatch_barrier_sync(queue, {}) + + XCTAssertTrue(disposed, "disposed != true") + XCTAssertFalse(generated, "generated != false") + } + } + + func testThen() { + var generatedFirst = false + var disposedFirst = false + var generatedSecond = false + var disposedSecond = false + var result = 0 + + var signal = Signal { subscriber in + generatedFirst = true + subscriber.putNext(1) + subscriber.putCompletion() + return ActionDisposable { + disposedFirst = true + } + } + + signal = signal |> then (Signal { subscriber in + generatedSecond = true + subscriber.putNext(2) + subscriber.putCompletion() + return ActionDisposable { + disposedSecond = true + } + }) + + signal.start(next: { next in + result += next + }) + + XCTAssertTrue(generatedFirst, "generatedFirst != true"); + XCTAssertTrue(disposedFirst, "disposedFirst != true"); + XCTAssertTrue(generatedSecond, "generatedSecond !+ true"); + XCTAssertTrue(disposedSecond, "disposedSecond != true"); + XCTAssertTrue(result == 3, "result != 3"); + } + + func testCombineLatest2() { + let s1 = Signal { subscriber in + subscriber.putNext(1) + subscriber.putCompletion() + return EmptyDisposable + } + let s2 = Signal { subscriber in + subscriber.putNext(2) + subscriber.putCompletion() + return EmptyDisposable + } + + let signal = combineLatest(s1, s2) + + var completed = false + signal.start(next: { next in + XCTAssert(next.0 == 1 && next.1 == 2, "next != (1, 2)") + return + }, completed: { + completed = true + }) + XCTAssert(completed == true, "completed != true") + } + + func testCombineLatest3() { + let s1 = Signal { subscriber in + subscriber.putNext(1) + subscriber.putCompletion() + return EmptyDisposable + } + let s2 = Signal { subscriber in + subscriber.putNext(2) + subscriber.putCompletion() + return EmptyDisposable + } + let s3 = Signal { subscriber in + subscriber.putNext(3) + subscriber.putCompletion() + return EmptyDisposable + } + + let signal = combineLatest(s1, s2, s3) + + var completed = false + signal.start(next: { next in + XCTAssert(next.0 == 1 && next.1 == 2 && next.2 == 3, "next != (1, 2, 3)") + return + }, completed: { + completed = true + }) + XCTAssert(completed == true, "completed != true") + } + + /*func testSingle() { + let s1 = Signal.single(1) + let s2 = Signal.fail(Void()) + let s3 = Signal.complete() + + var singleEmitted = false + s1.start(next: { next in + singleEmitted = next == 1 + }) + XCTAssert(singleEmitted == true, "singleEmitted != true") + + var errorEmitted = false + s2.start(error: { error in + errorEmitted = true + }) + XCTAssert(errorEmitted == true, "errorEmitted != true") + + var completedEmitted = false + s3.start(completed: { + completedEmitted = true + }) + XCTAssert(completedEmitted == true, "errorEmitted != true") + }*/ + + func testSwitchToLatest() { + var result: [Int] = [] + var disposedOne = false + var disposedTwo = false + var disposedThree = false + var completedAll = false + + var deallocatedOne = false + var deallocatedTwo = false + var deallocatedThree = false + + if true { + var objectOne: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedOne) + var objectTwo: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedTwo) + var objectThree: DeallocatingObject? = DeallocatingObject(deallocated: &deallocatedThree) + + let one = Signal { subscriber in + subscriber.putNext(1) + subscriber.putCompletion() + return ActionDisposable { [objectOne] in + objectOne?.description + disposedOne = true + } + } + + let two = Signal { subscriber in + subscriber.putNext(2) + subscriber.putCompletion() + return ActionDisposable { [objectTwo] in + objectTwo?.description + disposedTwo = true + } + } + + let three = Signal { subscriber in + subscriber.putNext(3) + subscriber.putCompletion() + return ActionDisposable { [objectThree] in + objectThree?.description + disposedThree = true + } + } + + let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> switchToLatest + + signal.start(next: { next in + result.append(next) + }, completed: { + completedAll = true + }) + } + + XCTAssert(result.count == 3 && result[0] == 1 && result[1] == 2 && result[2] == 3, "result != [1, 2, 3]"); + XCTAssert(disposedOne == true, "disposedOne != true"); + XCTAssert(disposedTwo == true, "disposedTwo != true"); + XCTAssert(disposedThree == true, "disposedThree != true"); + XCTAssert(deallocatedOne == true, "deallocatedOne != true"); + XCTAssert(deallocatedTwo == true, "deallocatedTwo != true"); + XCTAssert(deallocatedThree == true, "deallocatedThree != true"); + XCTAssert(completedAll == true, "completedAll != true"); + } + + func testSwitchToLatestError() { + var errorGenerated = false + + let one = Signal { subscriber in + subscriber.putError(Void()) + return EmptyDisposable + } + + let signal = singleSignalInt(one) |> switchToLatest + + signal.start(error: { error in + errorGenerated = true + }) + + XCTAssert(errorGenerated == true, "errorGenerated != true") + } + + func testQueue() { + let q = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) + + var disposedOne = false + var disposedTwo = false + var disposedThree = false + var completedAll = false + var result: [Int] = [] + + let one = Signal { subscriber in + dispatch_async(q, { + subscriber.putNext(1) + subscriber.putCompletion() + }) + return ActionDisposable { + disposedOne = true + } + } + + let two = Signal { subscriber in + dispatch_async(q, { + subscriber.putNext(2) + subscriber.putCompletion() + }) + return ActionDisposable { + disposedTwo = true + } + } + + let three = Signal { subscriber in + dispatch_async(q, { + subscriber.putNext(3) + subscriber.putCompletion() + }) + return ActionDisposable { + disposedThree = true + } + } + + let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue + + signal.start(next: { next in + println("next: \(next)") + result.append(next) + }, completed: { + completedAll = true + }) + + usleep(1000 * 200) + + XCTAssert(result.count == 3 && result[0] == 1 && result[1] == 2 && result[2] == 3, "result != [1, 2, 3]"); + XCTAssert(disposedOne == true, "disposedOne != true"); + XCTAssert(disposedTwo == true, "disposedTwo != true"); + XCTAssert(disposedThree == true, "disposedThree != true"); + XCTAssert(completedAll == true, "completedAll != true"); + } + + func testQueueInterrupted() { + let q = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) + + var disposedOne = false + var disposedTwo = false + var disposedThree = false + var startedThird = false + var completedAll = false + var result: [Int] = [] + + let one = Signal { subscriber in + dispatch_async(q, { + subscriber.putNext(1) + subscriber.putCompletion() + }) + return ActionDisposable { + disposedOne = true + } + } + + let two = Signal { subscriber in + dispatch_async(q, { + subscriber.putNext(2) + subscriber.putError(Void()) + }) + return ActionDisposable { + disposedTwo = true + } + } + + let three = Signal { subscriber in + startedThird = true + dispatch_async(q, { + subscriber.putNext(3) + subscriber.putCompletion() + }) + return ActionDisposable { + disposedThree = true + } + } + + let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue + + signal.start(next: { next in + result.append(next) + }, completed: { + completedAll = true + }) + + usleep(1000 * 200) + + XCTAssert(result.count == 2 && result[0] == 1 && result[1] == 2, "result != [1, 2]"); + XCTAssert(disposedOne == true, "disposedOne != true"); + XCTAssert(disposedTwo == true, "disposedTwo != true"); + XCTAssert(disposedThree == false, "disposedThree != false"); + XCTAssert(startedThird == false, "startedThird != false"); + XCTAssert(completedAll == false, "completedAll != false"); + } + + func testQueueDisposed() { + let q = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) + + var disposedOne = false + var disposedTwo = false + var disposedThree = false + var startedFirst = false + var startedSecond = false + var startedThird = false + var result: [Int] = [] + + let one = Signal { subscriber in + startedFirst = true + var cancelled = false + dispatch_async(q, { + if !cancelled { + usleep(100 * 1000) + subscriber.putNext(1) + subscriber.putCompletion() + } + }) + return ActionDisposable { + cancelled = true + disposedOne = true + } + } + + let two = Signal { subscriber in + startedSecond = true + var cancelled = false + dispatch_async(q, { + if !cancelled { + usleep(100 * 1000) + subscriber.putNext(2) + subscriber.putError(Void()) + } + }) + return ActionDisposable { + cancelled = true + disposedTwo = true + } + } + + let three = Signal { subscriber in + startedThird = true + var cancelled = false + dispatch_async(q, { + if !cancelled { + usleep(100 * 1000) + subscriber.putNext(3) + subscriber.putCompletion() + } + }) + return ActionDisposable { + cancelled = true + disposedThree = true + } + } + + let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue + + signal.start(next: { next in + result.append(next) + }).dispose() + + usleep(1000 * 200) + + XCTAssert(result.count == 0, "result != []"); + XCTAssert(disposedOne == true, "disposedOne != true"); + XCTAssert(disposedTwo == false, "disposedTwo != false"); + XCTAssert(disposedThree == false, "disposedThree != false"); + XCTAssert(startedFirst == true, "startedFirst != false"); + XCTAssert(startedSecond == false, "startedSecond != false"); + XCTAssert(startedThird == false, "startedThird != false"); + } + + func testRestart() { + let q = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT) + let signal = Signal { subscriber in + dispatch_async(q, { + subscriber.putNext(1) + subscriber.putCompletion() + }) + return EmptyDisposable + } + + var result = 0 + + (signal |> restart |> take(3)).start(next: { next in + result += next + }) + + usleep(100 * 1000) + + XCTAssert(result == 3, "result != 3") + } + + func testPipe() { + let pipe = Pipe() + + var result1 = 0 + let disposable1 = pipe.signal().start(next: { next in + result1 += next + }) + + var result2 = 0 + let disposable2 = pipe.signal().start(next: { next in + result2 += next + }) + + pipe.putNext(1) + + XCTAssert(result1 == 1, "result1 != 1") + XCTAssert(result2 == 1, "result2 != 1") + + disposable1.dispose() + + pipe.putNext(1) + + XCTAssert(result1 == 1, "result1 != 1") + XCTAssert(result2 == 2, "result2 != 2") + + disposable2.dispose() + + pipe.putNext(1) + + XCTAssert(result1 == 1, "result1 != 1") + XCTAssert(result2 == 2, "result2 != 2") + } +} From 263d384523a7e2e6159655a5ceb7676a789eae7a Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 10 Jun 2015 14:05:29 +0300 Subject: [PATCH 032/122] Deployment target --- SSignalKit.xcodeproj/project.pbxproj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index baf70e3b61..9045ecf9b1 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -707,7 +707,7 @@ ); INFOPLIST_FILE = SwiftSignalKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -727,7 +727,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SwiftSignalKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -942,6 +942,7 @@ D0085B371B282B9800EAF753 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; D0085B381B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKitTests" */ = { isa = XCConfigurationList; @@ -950,6 +951,7 @@ D0085B3A1B282B9800EAF753 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */ = { isa = XCConfigurationList; From bc475498284b63b50942e89e919380393319c518 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 10 Jun 2015 14:10:34 +0300 Subject: [PATCH 033/122] Introduce NoError --- SwiftSignalKit/Signal.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index 14de82b28e..e17eec20c9 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -2,6 +2,8 @@ import Foundation internal let doNothing: () -> Void = { _ in } +typealias NoError = Void + public func identity(a: A) -> A { return a; } From b98fe45d230d2adb0cee23459374cc28f7578dbd Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 10 Jun 2015 14:13:20 +0300 Subject: [PATCH 034/122] Fix NoError --- SwiftSignalKit/Signal.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index e17eec20c9..e06b37b391 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -2,7 +2,7 @@ import Foundation internal let doNothing: () -> Void = { _ in } -typealias NoError = Void +public typealias NoError = Void public func identity(a: A) -> A { return a; From 0b3b270fe8cd30f5ce2b81d89a2a921012dd15b6 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 10 Jun 2015 14:33:26 +0300 Subject: [PATCH 035/122] Single --- SwiftSignalKit/Signal_Single.swift | 46 +++++++++---------- .../SwiftSignalKitFunctionsTests.swift | 10 ++-- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/SwiftSignalKit/Signal_Single.swift b/SwiftSignalKit/Signal_Single.swift index 8adc2d8b53..d465e35416 100644 --- a/SwiftSignalKit/Signal_Single.swift +++ b/SwiftSignalKit/Signal_Single.swift @@ -1,28 +1,26 @@ import Foundation -extension Signal { - public static func single(value: T) -> Signal { - return Signal { subscriber in - subscriber.putNext(value) - subscriber.putCompletion() - - return EmptyDisposable - } - } - - public static func fail(error: E) -> Signal { - return Signal { subscriber in - subscriber.putError(error) - - return EmptyDisposable - } - } - - public static func complete() -> Signal { - return Signal { subscriber in - subscriber.putCompletion() - - return EmptyDisposable - } +public func single(value: T, errorRype: E.Type) -> Signal { + return Signal { subscriber in + subscriber.putNext(value) + subscriber.putCompletion() + + return EmptyDisposable + } +} + +public func fail(valueType: T.Type, error: E) -> Signal { + return Signal { subscriber in + subscriber.putError(error) + + return EmptyDisposable + } +} + +public func complete(valueType: T.Type, error: E.Type) -> Signal { + return Signal { subscriber in + subscriber.putCompletion() + + return EmptyDisposable } } diff --git a/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift b/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift index 80f276cb8c..f1699d4159 100644 --- a/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift +++ b/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift @@ -309,10 +309,10 @@ class SwiftSignalKitFunctionsTests: XCTestCase { XCTAssert(completed == true, "completed != true") } - /*func testSingle() { - let s1 = Signal.single(1) - let s2 = Signal.fail(Void()) - let s3 = Signal.complete() + func testSingle() { + let s1 = single(1, Void.self) + let s2 = fail(Int.self, Void()) + let s3 = complete(Int.self, Void.self) var singleEmitted = false s1.start(next: { next in @@ -331,7 +331,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { completedEmitted = true }) XCTAssert(completedEmitted == true, "errorEmitted != true") - }*/ + } func testSwitchToLatest() { var result: [Int] = [] From 23913bbd28cf180fe8251eff3143717290800f20 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 10 Jun 2015 23:44:18 +0300 Subject: [PATCH 036/122] no message --- SSignalKit/SSignalKit.h | 4 ++++ SSignalKitTests/SDisposableTests.m | 4 ++++ SSignalKitTests/SSignalBasicTests.m | 4 ++++ SSignalKitTests/SSignalPerformanceTests.m | 4 ++++ SwiftSignalKit/SwiftSignalKit.h | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h index fd17f141ad..cd1b6d541e 100644 --- a/SSignalKit/SSignalKit.h +++ b/SSignalKit/SSignalKit.h @@ -6,7 +6,11 @@ // Copyright (c) 2015 Telegram. All rights reserved. // +#if __IPHONE_OS_VERSION_MIN_REQUIRED #import +#else +#import +#endif //! Project version number for SSignalKit. FOUNDATION_EXPORT double SSignalKitVersionNumber; diff --git a/SSignalKitTests/SDisposableTests.m b/SSignalKitTests/SDisposableTests.m index e04fc32049..3c71105e4e 100644 --- a/SSignalKitTests/SDisposableTests.m +++ b/SSignalKitTests/SDisposableTests.m @@ -1,4 +1,8 @@ +#if __IPHONE_OS_VERSION_MIN_REQUIRED #import +#else +#import +#endif #import #import diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index 0cc3d5f317..e88b8faf45 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -1,4 +1,8 @@ +#if __IPHONE_OS_VERSION_MIN_REQUIRED #import +#else +#import +#endif #import @import SSignalKit; diff --git a/SSignalKitTests/SSignalPerformanceTests.m b/SSignalKitTests/SSignalPerformanceTests.m index b7948645ba..9fa8f5aa2c 100644 --- a/SSignalKitTests/SSignalPerformanceTests.m +++ b/SSignalKitTests/SSignalPerformanceTests.m @@ -1,4 +1,8 @@ +#if __IPHONE_OS_VERSION_MIN_REQUIRED #import +#else +#import +#endif #import @import SSignalKit; diff --git a/SwiftSignalKit/SwiftSignalKit.h b/SwiftSignalKit/SwiftSignalKit.h index e78eb85e84..d30da27eb3 100644 --- a/SwiftSignalKit/SwiftSignalKit.h +++ b/SwiftSignalKit/SwiftSignalKit.h @@ -6,7 +6,11 @@ // Copyright (c) 2015 Telegram. All rights reserved. // +#if __IPHONE_OS_VERSION_MIN_REQUIRED #import +#else +#import +#endif //! Project version number for SwiftSignalKit. FOUNDATION_EXPORT double SwiftSignalKitVersionNumber; From 270bf0278d0e8c5f5c832d86515d86f740466d69 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 13 Jun 2015 02:21:22 +0300 Subject: [PATCH 037/122] no message --- SSignalKit/SSignal+Mapping.h | 1 - SSignalKit/SSignal+Mapping.m | 17 ----- SSignalKit/SSignal.h | 2 + SSignalKit/SSignal.m | 29 +++++++++ SSignalKit/SSubscriber.h | 6 ++ SSignalKit/SSubscriber.m | 122 +++++++++++++++++++++++++++++++++++ 6 files changed, 159 insertions(+), 18 deletions(-) diff --git a/SSignalKit/SSignal+Mapping.h b/SSignalKit/SSignal+Mapping.h index d9e810b78a..42446ddb2a 100644 --- a/SSignalKit/SSignal+Mapping.h +++ b/SSignalKit/SSignal+Mapping.h @@ -3,7 +3,6 @@ @interface SSignal (Mapping) - (SSignal *)map:(id (^)(id))f; -- (SSignal *)_mapInplace:(id (^)(id))f; - (SSignal *)filter:(bool (^)(id))f; @end diff --git a/SSignalKit/SSignal+Mapping.m b/SSignalKit/SSignal+Mapping.m index 3b98a222b9..7dc47cf4c3 100644 --- a/SSignalKit/SSignal+Mapping.m +++ b/SSignalKit/SSignal+Mapping.m @@ -19,23 +19,6 @@ }]; } -- (SSignal *)_mapInplace:(id (^)(id))f -{ - id (^generator)(SSubscriber *) = self->_generator; - self->_generator = [^id (SSubscriber *subscriber) - { - void (^next)(id) = subscriber->_next; - subscriber->_next = ^(id value) - { - next(f(value)); - }; - - return generator(subscriber); - } copy]; - - return self; -} - - (SSignal *)filter:(bool (^)(id))f { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) diff --git a/SSignalKit/SSignal.h b/SSignalKit/SSignal.h index d85fa9d3ea..46b7385d36 100644 --- a/SSignalKit/SSignal.h +++ b/SSignalKit/SSignal.h @@ -12,5 +12,7 @@ - (id)startWithNext:(void (^)(id next))next; - (id)startWithNext:(void (^)(id next))next completed:(void (^)())completed; +- (SSignal *)trace:(NSString *)name; + @end diff --git a/SSignalKit/SSignal.m b/SSignalKit/SSignal.m index 8c7d52d877..00014b0861 100644 --- a/SSignalKit/SSignal.m +++ b/SSignalKit/SSignal.m @@ -49,6 +49,14 @@ return self; } +- (id)startWithNext:(void (^)(id next))next error:(void (^)(id error))error completed:(void (^)())completed traceName:(NSString *)traceName +{ + STracingSubscriber *subscriber = [[STracingSubscriber alloc] initWithName:traceName next:next error:error completed:completed]; + id disposable = _generator(subscriber); + [subscriber _assignDisposable:disposable]; + return [[SSubscriberDisposable alloc] initWithSubscriber:subscriber disposable:disposable]; +} + - (id)startWithNext:(void (^)(id next))next error:(void (^)(id error))error completed:(void (^)())completed { SSubscriber *subscriber = [[SSubscriber alloc] initWithNext:next error:error completed:completed]; @@ -73,4 +81,25 @@ return [[SSubscriberDisposable alloc] initWithSubscriber:subscriber disposable:disposable]; } +- (SSignal *)trace:(NSString *)name +{ +#ifdef DEBUG + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + return [self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + } traceName:name]; + }]; +#else + return self; +#endif +} + @end diff --git a/SSignalKit/SSubscriber.h b/SSignalKit/SSubscriber.h index 37d3368c67..2c635279d7 100644 --- a/SSignalKit/SSubscriber.h +++ b/SSignalKit/SSubscriber.h @@ -18,3 +18,9 @@ - (void)putCompletion; @end + +@interface STracingSubscriber : SSubscriber + +- (instancetype)initWithName:(NSString *)name next:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; + +@end \ No newline at end of file diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index 9c0e26cb5a..988c83cb7d 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -4,6 +4,7 @@ @interface SSubscriber () { + @protected OSSpinLock _lock; bool _terminated; id _disposable; @@ -113,3 +114,124 @@ } @end + +@interface STracingSubscriber () +{ + NSString *_name; +} + +@end + +@implementation STracingSubscriber + +- (instancetype)initWithName:(NSString *)name next:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed +{ + self = [super init]; + if (self != nil) + { + _name = name; + _next = [next copy]; + _error = [error copy]; + _completed = [completed copy]; + } + return self; +} + +- (void)_assignDisposable:(id)disposable +{ + if (_terminated) + [disposable dispose]; + else + _disposable = disposable; +} + +- (void)_markTerminatedWithoutDisposal +{ + OSSpinLockLock(&_lock); + if (!_terminated) + { + _terminated = true; + _next = nil; + _error = nil; + _completed = nil; + } + OSSpinLockUnlock(&_lock); +} + +- (void)putNext:(id)next +{ + void (^fnext)(id) = nil; + + OSSpinLockLock(&_lock); + if (!_terminated) + fnext = self->_next; + OSSpinLockUnlock(&_lock); + + if (fnext) + { + NSLog(@"(%@ next: %@)", _name, next); + fnext(next); + } +} + +- (void)putError:(id)error +{ + bool shouldDispose = false; + void (^ferror)(id) = nil; + + OSSpinLockLock(&_lock); + if (!_terminated) + { + ferror = self->_error; + shouldDispose = true; + self->_next = nil; + self->_error = nil; + self->_completed = nil; + _terminated = true; + } + OSSpinLockUnlock(&_lock); + + if (ferror) + { + NSLog(@"(%@ error: %@)", _name, error); + ferror(error); + } + + if (shouldDispose) + [self->_disposable dispose]; +} + +- (void)putCompletion +{ + bool shouldDispose = false; + void (^completed)() = nil; + + OSSpinLockLock(&_lock); + if (!_terminated) + { + completed = self->_completed; + shouldDispose = true; + self->_next = nil; + self->_error = nil; + self->_completed = nil; + _terminated = true; + } + OSSpinLockUnlock(&_lock); + + if (completed) + { + NSLog(@"(%@ completed)", _name); + completed(); + } + + if (shouldDispose) + [self->_disposable dispose]; +} + +- (void)dispose +{ + NSLog(@"(%@ dispose)", _name); + [self->_disposable dispose]; +} + +@end From 2bf7e85910f64a01fac31f929b552b94a95d2fcd Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 13 Jun 2015 17:20:53 +0300 Subject: [PATCH 038/122] no message --- SSignalKit/SSignal+Catch.m | 1 + SSignalKit/SSignal+Meta.m | 10 +++++----- SSignalKit/SSignal+SideEffects.h | 1 + SSignalKit/SSignal+SideEffects.m | 18 ++++++++++++++++++ SSignalKit/SSignal.m | 4 +++- SSignalKit/SSubscriber.m | 19 +++++++++++++++---- 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m index 2387c88946..c25a973412 100644 --- a/SSignalKit/SSignal+Catch.m +++ b/SSignalKit/SSignal+Catch.m @@ -63,6 +63,7 @@ static dispatch_block_t recursiveBlock(void (^block)(dispatch_block_t recurse)) if ([currentShouldRestart boolValue]) { + [currentDisposable setDisposable:nil]; id disposable = [self startWithNext:^(id next) { [subscriber putNext:next]; diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 2f0ca89633..ffc7f37e17 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -172,13 +172,13 @@ - (SSignal *)then:(SSignal *)signal { - SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; - - SMetaDisposable *currentDisposable = [[SMetaDisposable alloc] init]; - [compositeDisposable add:currentDisposable]; - return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) { + SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + + SMetaDisposable *currentDisposable = [[SMetaDisposable alloc] init]; + [compositeDisposable add:currentDisposable]; + [currentDisposable setDisposable:[self startWithNext:^(id next) { [subscriber putNext:next]; diff --git a/SSignalKit/SSignal+SideEffects.h b/SSignalKit/SSignal+SideEffects.h index 0eead9dcd5..9d47d3a49b 100644 --- a/SSignalKit/SSignal+SideEffects.h +++ b/SSignalKit/SSignal+SideEffects.h @@ -2,6 +2,7 @@ @interface SSignal (SideEffects) +- (SSignal *)onStart:(void (^)())f; - (SSignal *)onNext:(void (^)(id next))f; - (SSignal *)afterNext:(void (^)(id next))f; - (SSignal *)onError:(void (^)(id error))f; diff --git a/SSignalKit/SSignal+SideEffects.m b/SSignalKit/SSignal+SideEffects.m index e5531ca67d..4a7e992826 100644 --- a/SSignalKit/SSignal+SideEffects.m +++ b/SSignalKit/SSignal+SideEffects.m @@ -5,6 +5,24 @@ @implementation SSignal (SideEffects) +- (SSignal *)onStart:(void (^)())f +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + f(); + return [self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + - (SSignal *)onNext:(void (^)(id next))f { return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) diff --git a/SSignalKit/SSignal.m b/SSignalKit/SSignal.m index 00014b0861..6bf3ff4dde 100644 --- a/SSignalKit/SSignal.m +++ b/SSignalKit/SSignal.m @@ -86,6 +86,8 @@ #ifdef DEBUG return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { + NSString *traceName = [[NSString alloc] initWithFormat:@"%@#0x%x", name, (int)random()]; + NSLog(@"trace(%@ start)", traceName); return [self startWithNext:^(id next) { [subscriber putNext:next]; @@ -95,7 +97,7 @@ } completed:^ { [subscriber putCompletion]; - } traceName:name]; + } traceName:traceName]; }]; #else return self; diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index 988c83cb7d..2f75ea1cc0 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -150,6 +150,11 @@ OSSpinLockLock(&_lock); if (!_terminated) { + NSLog(@"trace(%@ terminated)", _name); + if ([_name hasPrefix:@"bestTcp4Signals"]) + { + int bp = 1; + } _terminated = true; _next = nil; _error = nil; @@ -169,9 +174,11 @@ if (fnext) { - NSLog(@"(%@ next: %@)", _name, next); + NSLog(@"trace(%@ next: %@)", _name, next); fnext(next); } + else + NSLog(@"trace(%@ next: %@, not accepted)", _name, next); } - (void)putError:(id)error @@ -193,9 +200,11 @@ if (ferror) { - NSLog(@"(%@ error: %@)", _name, error); + NSLog(@"trace(%@ error: %@)", _name, error); ferror(error); } + else + NSLog(@"trace(%@ error: %@, not accepted)", _name, error); if (shouldDispose) [self->_disposable dispose]; @@ -220,9 +229,11 @@ if (completed) { - NSLog(@"(%@ completed)", _name); + NSLog(@"trace(%@ completed)", _name); completed(); } + else + NSLog(@"trace(%@ completed, not accepted)", _name); if (shouldDispose) [self->_disposable dispose]; @@ -230,7 +241,7 @@ - (void)dispose { - NSLog(@"(%@ dispose)", _name); + NSLog(@"trace(%@ dispose)", _name); [self->_disposable dispose]; } From 80c4254b207fc674c55711bf6f2d3ae25e7a3c36 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 13 Jun 2015 17:22:23 +0300 Subject: [PATCH 039/122] no message --- SSignalKit/SSignal+Catch.m | 1 - SSignalKit/SSubscriber.m | 4 ---- 2 files changed, 5 deletions(-) diff --git a/SSignalKit/SSignal+Catch.m b/SSignalKit/SSignal+Catch.m index c25a973412..2387c88946 100644 --- a/SSignalKit/SSignal+Catch.m +++ b/SSignalKit/SSignal+Catch.m @@ -63,7 +63,6 @@ static dispatch_block_t recursiveBlock(void (^block)(dispatch_block_t recurse)) if ([currentShouldRestart boolValue]) { - [currentDisposable setDisposable:nil]; id disposable = [self startWithNext:^(id next) { [subscriber putNext:next]; diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index 2f75ea1cc0..bed29f9193 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -151,10 +151,6 @@ if (!_terminated) { NSLog(@"trace(%@ terminated)", _name); - if ([_name hasPrefix:@"bestTcp4Signals"]) - { - int bp = 1; - } _terminated = true; _next = nil; _error = nil; From 67bae10549f0db16e1715adfcfa7fecedaf93771 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 15 Jun 2015 17:51:14 +0300 Subject: [PATCH 040/122] SPipe replay --- SSignalKit/SSignal+Pipe.h | 2 ++ SSignalKit/SSignal+Pipe.m | 47 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/SSignalKit/SSignal+Pipe.h b/SSignalKit/SSignal+Pipe.h index 24c408867f..2a21ee4cf7 100644 --- a/SSignalKit/SSignal+Pipe.h +++ b/SSignalKit/SSignal+Pipe.h @@ -5,5 +5,7 @@ @property (nonatomic, copy, readonly) SSignal *(^signalProducer)(); @property (nonatomic, copy, readonly) void (^sink)(id); +- (instancetype)initWithReplay:(bool)replay; + @end diff --git a/SSignalKit/SSignal+Pipe.m b/SSignalKit/SSignal+Pipe.m index 33446ef13a..ab9496a2d2 100644 --- a/SSignalKit/SSignal+Pipe.m +++ b/SSignalKit/SSignal+Pipe.m @@ -4,14 +4,42 @@ #import "SAtomic.h" #import "SBag.h" +@interface SPipeReplayState : NSObject + +@property (nonatomic, readonly) bool hasReceivedValue; +@property (nonatomic, strong, readonly) id recentValue; + +@end + +@implementation SPipeReplayState + +- (instancetype)initWithReceivedValue:(bool)receivedValue recentValue:(id)recentValue +{ + self = [super init]; + if (self != nil) + { + _hasReceivedValue = receivedValue; + _recentValue = recentValue; + } + return self; +} + +@end + @implementation SPipe - (instancetype)init +{ + return [self initWithReplay:false]; +} + +- (instancetype)initWithReplay:(bool)replay { self = [super init]; if (self != nil) { SAtomic *subscribers = [[SAtomic alloc] initWithValue:[[SBag alloc] init]]; + SAtomic *replayState = replay ? [[SAtomic alloc] initWithValue:[[SPipeReplayState alloc] initWithReceivedValue:false recentValue:nil]] : nil; _signalProducer = [^SSignal * { @@ -27,6 +55,16 @@ return nil; }]; + if (replay) + { + [replayState with:^id(SPipeReplayState *state) + { + if (state.hasReceivedValue) + [subscriber putNext:state.recentValue]; + return nil; + }]; + } + return [[SBlockDisposable alloc] initWithBlock:^ { [subscribers with:^id(SBag *bag) @@ -44,10 +82,19 @@ { return [bag copyItems]; }]; + for (void (^item)(id) in items) { item(next); } + + if (replay) + { + [replayState modify:^id(__unused SPipeReplayState *state) + { + return [[SPipeReplayState alloc] initWithReceivedValue:true recentValue:next]; + }]; + } } copy]; } return self; From 724d79a076ded4bfc950bbf6a1a1b73eaadc266f Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 22 Jun 2015 21:17:15 +0300 Subject: [PATCH 041/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 1 + SSignalKit/SSignal+Combine.m | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 9045ecf9b1..1f8ac2e82d 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -528,6 +528,7 @@ D0445DCF1A7C2CA500267924 /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0610; ORGANIZATIONNAME = Telegram; TargetAttributes = { diff --git a/SSignalKit/SSignal+Combine.m b/SSignalKit/SSignal+Combine.m index 45660408a6..5c636bba99 100644 --- a/SSignalKit/SSignal+Combine.m +++ b/SSignalKit/SSignal+Combine.m @@ -32,7 +32,10 @@ + (SSignal *)combineSignals:(NSArray *)signals { - return [self combineSignals:signals withInitialStates:nil]; + if (signals.count == 0) + return [SSignal single:@[]]; + else + return [self combineSignals:signals withInitialStates:nil]; } + (SSignal *)combineSignals:(NSArray *)signals withInitialStates:(NSArray *)initialStates From d44354d26e1a1bb65513b23deb5054284f12f713 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 23 Jun 2015 04:03:44 +0300 Subject: [PATCH 042/122] Defer --- SwiftSignalKit/Signal_Meta.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/SwiftSignalKit/Signal_Meta.swift b/SwiftSignalKit/Signal_Meta.swift index 20ef3a5fde..1c916bc017 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -151,3 +151,15 @@ public func then(nextSignal: Signal)(signal: Signal) -> Signal return disposable } } + +public func defer(generator: () -> Signal) -> Signal { + return Signal { subscriber in + return generator().start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } +} From 5d21fb2685ae1fb9ab5a0d4c7301be7333b8247d Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 8 Jul 2015 18:42:18 +0300 Subject: [PATCH 043/122] Defer for ObjC and other tweaks --- SSignalKit/SSignal+Meta.h | 1 + SSignalKit/SSignal+Meta.m | 17 +++++++++++++++++ SwiftSignalKit/Bag.swift | 3 +++ SwiftSignalKit/Queue.swift | 10 ++++++++++ 4 files changed, 31 insertions(+) diff --git a/SSignalKit/SSignal+Meta.h b/SSignalKit/SSignal+Meta.h index 0aca7db8d7..c8d4b0102a 100644 --- a/SSignalKit/SSignal+Meta.h +++ b/SSignalKit/SSignal+Meta.h @@ -9,5 +9,6 @@ - (SSignal *)mapToQueue:(SSignal *(^)(id))f; - (SSignal *)then:(SSignal *)signal; - (SSignal *)queue; ++ (SSignal *)defer:(SSignal *(^)())generator; @end diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index ffc7f37e17..662c3c3e86 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -224,4 +224,21 @@ }]; } ++ (SSignal *)defer:(SSignal *(^)())generator +{ + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + return [generator() startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + @end diff --git a/SwiftSignalKit/Bag.swift b/SwiftSignalKit/Bag.swift index b3906960c4..2cc8a26ace 100644 --- a/SwiftSignalKit/Bag.swift +++ b/SwiftSignalKit/Bag.swift @@ -6,6 +6,9 @@ public final class Bag { private var items: [T] = [] private var itemKeys: [Index] = [] + public Bag() { + } + public func add(item: T) -> Index { let key = self.nextIndex self.nextIndex++ diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 9245ce58cc..8408822ba5 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -57,6 +57,16 @@ public final class Queue { } } + public func sync(f: Void -> Void) { + if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { + f() + } else if self.specialIsMainQueue && NSThread.isMainThread() { + f() + } else { + dispatch_sync(self.nativeQueue, f) + } + } + public func dispatch(f: Void -> Void) { if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { f() From c9618f5009a56f55534b1632717617262d6801e1 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 8 Jul 2015 18:48:42 +0300 Subject: [PATCH 044/122] no message --- SwiftSignalKit/Bag.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftSignalKit/Bag.swift b/SwiftSignalKit/Bag.swift index 2cc8a26ace..a4ec0c84b9 100644 --- a/SwiftSignalKit/Bag.swift +++ b/SwiftSignalKit/Bag.swift @@ -6,7 +6,7 @@ public final class Bag { private var items: [T] = [] private var itemKeys: [Index] = [] - public Bag() { + public init() { } public func add(item: T) -> Index { From e4ad18f645c5ed61a533c59240e9cf48283f0ee6 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 8 Jul 2015 19:02:43 +0300 Subject: [PATCH 045/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 4 +- SSignalKitTests/SSignalBasicTests.m | 36 ----------- SSignalKitTests/SSignalPerformanceTests.m | 79 ----------------------- 3 files changed, 1 insertion(+), 118 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 1f8ac2e82d..a50e6d59a6 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -61,7 +61,6 @@ D0085B1C1B28285400EAF753 /* STimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0085AE61B28285400EAF753 /* STimer.m */; }; D0085B271B282B9800EAF753 /* SwiftSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085B261B282B9800EAF753 /* SwiftSignalKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0085B2D1B282B9800EAF753 /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0085B221B282B9800EAF753 /* SwiftSignalKit.framework */; }; - D0085B4F1B282BEE00EAF753 /* SwiftSignalKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0085B3B1B282BEE00EAF753 /* SwiftSignalKit.h */; }; D0085B501B282BEE00EAF753 /* Signal_Timing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3C1B282BEE00EAF753 /* Signal_Timing.swift */; }; D0085B511B282BEE00EAF753 /* Signal_SideEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3D1B282BEE00EAF753 /* Signal_SideEffects.swift */; }; D0085B521B282BEE00EAF753 /* Signal_Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B3E1B282BEE00EAF753 /* Signal_Dispatch.swift */; }; @@ -409,7 +408,6 @@ buildActionMask = 2147483647; files = ( D0085B271B282B9800EAF753 /* SwiftSignalKit.h in Headers */, - D0085B4F1B282BEE00EAF753 /* SwiftSignalKit.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -529,7 +527,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0610; + LastUpgradeCheck = 0640; ORGANIZATIONNAME = Telegram; TargetAttributes = { D0085B211B282B9800EAF753 = { diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index e88b8faf45..099abfd207 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -171,42 +171,6 @@ XCTAssertTrue(generated); } -- (void)testInplaceMap -{ - bool deallocated = false; - __block bool disposed = false; - __block bool generated = false; - - @autoreleasepool - { - DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; - SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - [subscriber putNext:@1]; - __unused id a0 = [object description]; - return [[SBlockDisposable alloc] initWithBlock:^ - { - __unused id a1 = [object description]; - disposed = true; - }]; - }] _mapInplace:^id(id value) - { - __unused id a1 = [object description]; - return @([value intValue] * 2); - }]; - - id disposable = [signal startWithNext:^(id value) - { - generated = [value isEqual:@2]; - } error:nil completed:nil]; - [disposable dispose]; - } - - XCTAssertTrue(deallocated); - XCTAssertTrue(disposed); - XCTAssertTrue(generated); -} - - (void)testSubscriberDisposal { __block bool disposed = false; diff --git a/SSignalKitTests/SSignalPerformanceTests.m b/SSignalKitTests/SSignalPerformanceTests.m index 9fa8f5aa2c..f5384d75bd 100644 --- a/SSignalKitTests/SSignalPerformanceTests.m +++ b/SSignalKitTests/SSignalPerformanceTests.m @@ -47,83 +47,4 @@ }]; } -- (void)testMapInplace -{ - [self measureBlock:^ - { - SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - [subscriber putNext:@1]; - [subscriber putCompletion]; - return nil; - }] _mapInplace:^id (id value) - { - return value; - }]; - - for (int i = 0; i < 100000; i++) - { - [signal startWithNext:^(__unused id next) - { - - }]; - } - }]; -} - -- (void)testMapInplaceWithDisposable -{ - [self measureBlock:^ - { - SSignal *signal = [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - [subscriber putNext:@1]; - return [[SBlockDisposable alloc] initWithBlock:^ - { - }]; - }] _mapInplace:^id (id value) - { - return value; - }]; - - for (int i = 0; i < 100000; i++) - { - [signal startWithNext:^(__unused id next) - { - - }]; - } - }]; -} - -- (void)testMapInplace2WithDisposable -{ - [self measureBlock:^ - { - SSignal *signal = [[[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - [subscriber putNext:@1]; - [subscriber putCompletion]; - - return [[SBlockDisposable alloc] initWithBlock:^ - { - }]; - }] _mapInplace:^id (id value) - { - return value; - }] _mapInplace:^id (id value) - { - return value; - }]; - - for (int i = 0; i < 100000; i++) - { - [signal startWithNext:^(__unused id next) - { - - }]; - } - }]; -} - @end From 38272e9c360434c16c2207394ad0c8d2f968d75f Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 27 Jul 2015 15:05:50 +0300 Subject: [PATCH 046/122] Swift upgrades --- SSignalKit.xcodeproj/project.pbxproj | 1 + SwiftSignalKit/Pipe.swift | 2 +- SwiftSignalKit/Signal.swift | 2 +- SwiftSignalKit/Signal_Catch.swift | 41 ++++- SwiftSignalKit/Signal_Combine.swift | 16 +- SwiftSignalKit/Signal_Dispatch.swift | 2 +- SwiftSignalKit/Signal_Mapping.swift | 12 ++ SwiftSignalKit/Signal_Meta.swift | 64 +++++--- SwiftSignalKit/Signal_Reduce.swift | 149 ++++++++++++++++++ SwiftSignalKit/Signal_SideEffects.swift | 6 +- SwiftSignalKit/Signal_Single.swift | 12 +- SwiftSignalKit/Signal_Timing.swift | 4 +- SwiftSignalKit/ThreadPool.swift | 14 +- SwiftSignalKit/Timer.swift | 10 +- SwiftSignalKitTests/DeallocatingObject.swift | 4 +- .../SwiftSignalKitFunctionsTests.swift | 65 +++++++- 16 files changed, 344 insertions(+), 60 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index a50e6d59a6..e314ebb740 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -526,6 +526,7 @@ D0445DCF1A7C2CA500267924 /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0640; ORGANIZATIONNAME = Telegram; diff --git a/SwiftSignalKit/Pipe.swift b/SwiftSignalKit/Pipe.swift index c5d8d7b376..883b9c3071 100644 --- a/SwiftSignalKit/Pipe.swift +++ b/SwiftSignalKit/Pipe.swift @@ -10,7 +10,7 @@ public final class Pipe { public func signal() -> Signal { return Signal { [weak self] subscriber in if let strongSelf = self { - var index = strongSelf.subscribers.with { value -> Bag.Index in + let index = strongSelf.subscribers.with { value -> Bag.Index in return value.add { next in subscriber.putNext(next) } diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index e06b37b391..1f8ab3d127 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -36,7 +36,7 @@ public struct Signal { self.generator = generator } - public func start(next: (T -> Void)! = nil, error: (E -> Void)! = nil, completed: (() -> Void)! = nil) -> Disposable { + public func start(next 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) diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index 3aa10366b7..c59b40eab4 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -1,6 +1,6 @@ import Foundation -public func catch(f: E -> Signal)(signal: Signal) -> Signal { +public func `catch`(f: E -> Signal)(signal: Signal) -> Signal { return Signal { subscriber in let disposable = DisposableSet() @@ -59,3 +59,42 @@ public func restart(signal: Signal) -> Signal { } } } + +public func retry(exponentialDecay: 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 value + } + + 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 e73d881fdd..d77fccc6a9 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -8,7 +8,6 @@ private struct SignalCombineState { private func combineLatestAny(signals: [Signal], combine: [Any] -> R) -> Signal { return Signal { subscriber in - let state = Atomic(value: SignalCombineState(values: [:], completed: Set(), error: false)) let disposable = DisposableSet() @@ -37,6 +36,9 @@ private func combineLatestAny(signals: [Signal], combine: [Any] -> return current } } + if emitError { + subscriber.putError(error) + } }, completed: { var emitCompleted = false state.modify { current in @@ -72,20 +74,20 @@ private func signalOfAny(signal: Signal) -> Signal { } } -public func combineLatest(s1: Signal, s2: Signal) -> Signal<(T1, T2), E> { - return combineLatestAny([signalOfAny(s1), signalOfAny(s2)], { values in +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) }) } -public func combineLatest(s1: Signal, s2: Signal, s3: Signal) -> Signal<(T1, T2, T3), E> { - return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3)], { values in +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) }) } -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)], { values in +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) }) } diff --git a/SwiftSignalKit/Signal_Dispatch.swift b/SwiftSignalKit/Signal_Dispatch.swift index f9cbf2f67a..7934e3eeab 100644 --- a/SwiftSignalKit/Signal_Dispatch.swift +++ b/SwiftSignalKit/Signal_Dispatch.swift @@ -49,7 +49,7 @@ public func deliverOn(threadPool: ThreadPool)(signal: Signal) -> Sig public func runOn(threadPool: ThreadPool)(signal: Signal) -> Signal { return Signal { subscriber in - var cancelled = false + let cancelled = false let disposable = MetaDisposable() let task = ThreadPoolTask { state in diff --git a/SwiftSignalKit/Signal_Mapping.swift b/SwiftSignalKit/Signal_Mapping.swift index abde9df344..fdec5584f9 100644 --- a/SwiftSignalKit/Signal_Mapping.swift +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -25,3 +25,15 @@ 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() + }) + } +} diff --git a/SwiftSignalKit/Signal_Meta.swift b/SwiftSignalKit/Signal_Meta.swift index 1c916bc017..34b275e30f 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -45,34 +45,46 @@ private final class SignalQueueState : Disposable { } func headCompleted() { - var nextSignal: Signal! = nil - - var terminated = false - OSSpinLockLock(&self.lock) - self.executingSignal = false - if self.queueMode { - if self.queuedSignals.count != 0 { - nextSignal = self.queuedSignals[0] - self.queuedSignals.removeAtIndex(0) - self.executingSignal = true + while true { + let leftFunction = Atomic(value: false) + + var nextSignal: Signal! = nil + + var terminated = false + OSSpinLockLock(&self.lock) + self.executingSignal = false + if self.queueMode { + if self.queuedSignals.count != 0 { + nextSignal = self.queuedSignals[0] + self.queuedSignals.removeAtIndex(0) + self.executingSignal = true + } else { + terminated = self.terminated + } } else { terminated = self.terminated } - } else { - terminated = self.terminated - } - OSSpinLockUnlock(&self.lock) - - if terminated { - self.subscriber.putCompletion() - } else if nextSignal != nil { - let disposable = nextSignal.start(next: { next in - self.subscriber.putNext(next) - }, error: { error in - self.subscriber.putError(error) - }, completed: { - self.headCompleted() - }) + OSSpinLockUnlock(&self.lock) + + if terminated { + self.subscriber.putCompletion() + } else if nextSignal != nil { + let disposable = nextSignal.start(next: { next in + self.subscriber.putNext(next) + }, error: { error in + self.subscriber.putError(error) + }, completed: { + if leftFunction.swap(true) == true { + self.headCompleted() + } + }) + + currentDisposable.set(disposable) + } + + if leftFunction.swap(true) == false { + break + } } } @@ -152,7 +164,7 @@ public func then(nextSignal: Signal)(signal: Signal) -> Signal } } -public func defer(generator: () -> Signal) -> Signal { +public func `defer`(generator: () -> 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 e5a4671b84..b2623d06cc 100644 --- a/SwiftSignalKit/Signal_Reduce.swift +++ b/SwiftSignalKit/Signal_Reduce.swift @@ -32,3 +32,152 @@ public func reduceLeft(value: T, f: (T, T, T -> Void) -> T)(signal: Signal }) } } + +public enum Passthrough { + case None + case Some(T) +} + +private final class ReduceQueueState : Disposable { + var lock: OSSpinLock = 0 + var executingSignal = false + var terminated = false + + var disposable: Disposable = EmptyDisposable + let currentDisposable = MetaDisposable() + let subscriber: Subscriber + + var queuedValues: [T] = [] + var generator: (T, T) -> Signal<(T, Passthrough), E> + var value: T + + init(subscriber: Subscriber, value: T, generator: (T, T) -> Signal<(T, Passthrough), E>) { + self.subscriber = subscriber + self.generator = generator + self.value = value + } + + func beginWithDisposable(disposable: Disposable) { + self.disposable = disposable + } + + func enqueueNext(next: T) { + var startSignal = false + var currentValue: T + OSSpinLockLock(&self.lock) + currentValue = self.value + if self.executingSignal { + self.queuedValues.append(next) + } else { + self.executingSignal = true + startSignal = true + } + OSSpinLockUnlock(&self.lock) + + if startSignal { + let disposable = generator(currentValue, next).start(next: { next in + self.updateValue(next.0) + switch next.1 { + case let .Some(value): + self.subscriber.putNext(value) + case .None: + break + } + }, error: { error in + self.subscriber.putError(error) + }, completed: { + self.headCompleted() + }) + self.currentDisposable.set(disposable) + } + } + + func updateValue(value: T) { + OSSpinLockLock(&self.lock) + self.value = value + OSSpinLockUnlock(&self.lock) + } + + func headCompleted() { + while true { + let leftFunction = Atomic(value: false) + + var nextSignal: Signal<(T, Passthrough), E>! = nil + + var terminated = false + var currentValue: T! + OSSpinLockLock(&self.lock) + self.executingSignal = false + if self.queuedValues.count != 0 { + nextSignal = self.generator(self.value, self.queuedValues[0]) + self.queuedValues.removeAtIndex(0) + self.executingSignal = true + } else { + currentValue = self.value + terminated = self.terminated + } + OSSpinLockUnlock(&self.lock) + + if terminated { + self.subscriber.putNext(currentValue) + self.subscriber.putCompletion() + } else if nextSignal != nil { + let disposable = nextSignal.start(next: { next in + self.updateValue(next.0) + switch next.1 { + case let .Some(value): + self.subscriber.putNext(value) + case .None: + break + } + }, error: { error in + self.subscriber.putError(error) + }, completed: { + if leftFunction.swap(true) == true { + self.headCompleted() + } + }) + + currentDisposable.set(disposable) + } + + if leftFunction.swap(true) == false { + break + } + } + } + + func beginCompletion() { + var executingSignal = false + let currentValue: T + OSSpinLockLock(&self.lock) + executingSignal = self.executingSignal + self.terminated = true + currentValue = self.value + OSSpinLockUnlock(&self.lock) + + if !executingSignal { + self.subscriber.putNext(currentValue) + self.subscriber.putCompletion() + } + } + + func dispose() { + self.currentDisposable.dispose() + self.disposable.dispose() + } +} + +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 + } +} diff --git a/SwiftSignalKit/Signal_SideEffects.swift b/SwiftSignalKit/Signal_SideEffects.swift index 53989606ab..9b8904c849 100644 --- a/SwiftSignalKit/Signal_SideEffects.swift +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -3,7 +3,7 @@ import Foundation public func beforeNext(f: T -> R)(signal: Signal) -> Signal { return Signal { subscriber in return signal.start(next: { next in - let unused = f(next) + let _ = f(next) subscriber.putNext(next) }, error: { error in subscriber.putError(error) @@ -17,7 +17,7 @@ public func afterNext(f: T -> R)(signal: Signal) -> Signal return Signal { subscriber in return signal.start(next: { next in subscriber.putNext(next) - let unused = f(next) + let _ = f(next) }, error: { error in subscriber.putError(error) }, completed: { @@ -37,7 +37,7 @@ public func afterDisposed(f: Void -> R)(signal: Signal) -> Signal subscriber.putCompletion() })) disposable.add(ActionDisposable { - let unused = f() + let _ = f() }) return disposable diff --git a/SwiftSignalKit/Signal_Single.swift b/SwiftSignalKit/Signal_Single.swift index d465e35416..a17dde6db4 100644 --- a/SwiftSignalKit/Signal_Single.swift +++ b/SwiftSignalKit/Signal_Single.swift @@ -1,6 +1,6 @@ import Foundation -public func single(value: T, errorRype: 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, errorRype: 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,10 +17,16 @@ 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() return EmptyDisposable } } + +public func never(valueType: T.Type, _ error: E.Type) -> Signal { + return Signal { _ in + return EmptyDisposable + } +} diff --git a/SwiftSignalKit/Signal_Timing.swift b/SwiftSignalKit/Signal_Timing.swift index 6d1eb39ede..ae483dbab9 100644 --- a/SwiftSignalKit/Signal_Timing.swift +++ b/SwiftSignalKit/Signal_Timing.swift @@ -3,7 +3,7 @@ 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: { + let timer = Timer(timeout: timeout, `repeat`: false, completion: { disposable.set(signal.start(next: { next in subscriber.putNext(next) }, error: { error in @@ -23,7 +23,7 @@ public func delay(timeout: NSTimeInterval, queue: Queue)(signal: Signal(timeout: NSTimeInterval, queue: Queue, alternate: Signal)(signal: Signal) -> Signal { return Signal { subscriber in let disposable = MetaDisposable() - let timer = Timer(timeout: timeout, repeat: false, completion: { + let timer = Timer(timeout: timeout, `repeat`: false, completion: { disposable.set(alternate.start(next: { next in subscriber.putNext(next) }, error: { error in diff --git a/SwiftSignalKit/ThreadPool.swift b/SwiftSignalKit/ThreadPool.swift index 295f87c5d1..acecd357aa 100644 --- a/SwiftSignalKit/ThreadPool.swift +++ b/SwiftSignalKit/ThreadPool.swift @@ -58,7 +58,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { return lhs === rhs } -@objc public final class ThreadPool { +@objc public final class ThreadPool: NSObject { private var threads: [NSThread] = [] private var queues: [ThreadPoolQueue] = [] private var takenQueues: [ThreadPoolQueue] = [] @@ -74,7 +74,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { pthread_mutex_lock(&threadPool.mutex); if queue != nil { - if let index = find(threadPool.takenQueues, queue) { + if let index = threadPool.takenQueues.indexOf(queue) { threadPool.takenQueues.removeAtIndex(index) } @@ -97,7 +97,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { task = queue.popFirstTask() threadPool.takenQueues.append(queue) - if let index = find(threadPool.queues, queue) { + if let index = threadPool.queues.indexOf(queue) { threadPool.queues.removeAtIndex(index) } @@ -120,8 +120,10 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { pthread_mutex_init(&self.mutex, nil) pthread_cond_init(&self.condition, nil) - for i in 0 ..< threadCount { - var thread = NSThread(target: ThreadPool.self, selector: Selector("threadEntryPoint"), object: self) + super.init() + + for _ in 0 ..< threadCount { + let thread = NSThread(target: ThreadPool.self, selector: Selector("threadEntryPoint"), object: self) thread.threadPriority = threadPriority self.threads.append(thread) thread.start() @@ -141,7 +143,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { private func workOnQueue(queue: ThreadPoolQueue, action: () -> ()) { pthread_mutex_lock(&self.mutex) action() - if !contains(self.queues, queue) && !contains(self.takenQueues, queue) { + if !self.queues.contains(queue) && !self.takenQueues.contains(queue) { self.queues.append(queue) } pthread_cond_broadcast(&self.condition) diff --git a/SwiftSignalKit/Timer.swift b/SwiftSignalKit/Timer.swift index c4acfbcb6b..965ca96747 100644 --- a/SwiftSignalKit/Timer.swift +++ b/SwiftSignalKit/Timer.swift @@ -3,13 +3,13 @@ import Foundation public final class Timer { private var timer: dispatch_source_t! private var timeout: NSTimeInterval - private var repeat: Bool + private var `repeat`: Bool private var completion: Void -> Void private var queue: Queue - public init(timeout: NSTimeInterval, repeat: Bool, completion: Void -> Void, queue: Queue) { + public init(timeout: NSTimeInterval, `repeat`: Bool, completion: Void -> Void, queue: Queue) { self.timeout = timeout - self.repeat = repeat + self.`repeat` = `repeat` self.completion = completion self.queue = queue } @@ -20,11 +20,11 @@ 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_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 if let strongSelf = self { strongSelf.completion() - if !strongSelf.repeat { + if !strongSelf.`repeat` { strongSelf.invalidate() } } diff --git a/SwiftSignalKitTests/DeallocatingObject.swift b/SwiftSignalKitTests/DeallocatingObject.swift index c4d12389b2..1b759b9cdd 100644 --- a/SwiftSignalKitTests/DeallocatingObject.swift +++ b/SwiftSignalKitTests/DeallocatingObject.swift @@ -1,6 +1,6 @@ import Foundation -internal class DeallocatingObject : Printable { +internal class DeallocatingObject : CustomStringConvertible { private var deallocated: UnsafeMutablePointer init(deallocated: UnsafeMutablePointer) { @@ -11,7 +11,7 @@ internal class DeallocatingObject : Printable { self.deallocated.memory = true } - public var description: String { + var description: String { get { return "" } diff --git a/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift b/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift index f1699d4159..76752847ca 100644 --- a/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift +++ b/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift @@ -177,7 +177,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { return EmptyDisposable } - let catchSignal = failingSignal |> catch { error in + let catchSignal = failingSignal |> `catch` { error in return Signal { subscriber in subscriber.putNext(error * 2) return EmptyDisposable @@ -454,7 +454,7 @@ class SwiftSignalKitFunctionsTests: XCTestCase { let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue signal.start(next: { next in - println("next: \(next)") + print("next: \(next)") result.append(next) }, completed: { completedAll = true @@ -657,4 +657,65 @@ class SwiftSignalKitFunctionsTests: XCTestCase { XCTAssert(result1 == 1, "result1 != 1") XCTAssert(result2 == 2, "result2 != 2") } + + func testQueueRecursive() { + let q = Queue() + + let signal = Signal { subscriber in + for _ in 0 ..< 1000 { + subscriber.putNext(1) + } + subscriber.putCompletion() + return EmptyDisposable + } + + let queued = signal + |> mapToQueue { _ -> Signal in + return complete(Void.self, NoError.self) |> deliverOn(q) + } + + queued.start() + } + + func testReduceSignal() { + let q = Queue() + + let signal = Signal { subscriber in + for i in 0 ..< 1000 { + subscriber.putNext(i) + } + subscriber.putCompletion() + return EmptyDisposable + } + + let reduced = signal + |> reduceLeft(0, generator: { current, next -> Signal<(Int, Passthrough), NoError> in + return Signal { subscriber in + subscriber.putNext((current + next, Passthrough.Some(current + next))) + subscriber.putCompletion() + return EmptyDisposable + } |> deliverOn(q) + }) + + var values: [Int] = [] + reduced.start(next: { next in + values.append(next) + }) + + q.sync { } + + XCTAssert(values.count == 1001, "count \(values.count) != 1001") + var previous = 0 + for i in 0 ..< 1001 { + let value: Int + if i >= 1000 { + value = previous + } else { + value = previous + i + previous = value + } + previous = value + XCTAssert(values[i] == value, "at \(i): \(values[i]) != \(value)") + } + } } From 66c107f0c3985e56e62fc8eadaa28ee6cba3badf Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 29 Jul 2015 18:03:41 +0300 Subject: [PATCH 047/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 3 +++ SwiftSignalKit/Signal_Catch.swift | 30 ++++++++++++++++++++++++++++ SwiftSignalKit/Signal_Dispatch.swift | 15 ++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index e314ebb740..1fd3e0de6e 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -731,6 +731,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -791,6 +792,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -836,6 +838,7 @@ "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; diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index c59b40eab4..f84789e844 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -60,6 +60,36 @@ public func restart(signal: Signal) -> Signal { } } +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 + } + if currentShouldRestart { + let disposable = signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + recurse() + }) + currentDisposable.set(disposable) + } + } + + start() + + return ActionDisposable { + currentDisposable.dispose() + shouldRestart.swap(false) + } + } +} + public func retry(exponentialDecay: Double, onQueue queue: Queue)(signal: Signal) -> Signal { return Signal { subscriber in let shouldRetry = Atomic(value: true) diff --git a/SwiftSignalKit/Signal_Dispatch.swift b/SwiftSignalKit/Signal_Dispatch.swift index 7934e3eeab..f25cb7761d 100644 --- a/SwiftSignalKit/Signal_Dispatch.swift +++ b/SwiftSignalKit/Signal_Dispatch.swift @@ -75,3 +75,18 @@ public func runOn(threadPool: ThreadPool)(signal: Signal) -> Signal< 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: { + + }) + } +} From cf3c02015668525cb2c85980367e6ca2ad61552d Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 10 Aug 2015 12:02:55 +0200 Subject: [PATCH 048/122] Combine latest with initial values --- SwiftSignalKit/Signal_Combine.swift | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index d77fccc6a9..c9d455b033 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -6,11 +6,19 @@ private struct SignalCombineState { let error: Bool } -private func combineLatestAny(signals: [Signal], combine: [Any] -> R) -> Signal { +private func combineLatestAny(signals: [Signal], combine: [Any] -> R, initialValues: [Int : Any]) -> Signal { return Signal { subscriber in - let state = Atomic(value: SignalCombineState(values: [:], completed: Set(), error: false)) + let state = Atomic(value: SignalCombineState(values: initialValues, completed: Set(), error: false)) let disposable = DisposableSet() + if initialValues.count == signals.count { + var values: [Any] = [] + for i in 0 ..< initialValues.count { + values.append(initialValues[i]!) + } + subscriber.putNext(combine(values)) + } + let count = signals.count for index in 0 ..< count { let signalDisposable = signals[index].start(next: { next in @@ -77,17 +85,23 @@ private func signalOfAny(signal: Signal) -> Signal { 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> { + 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> { 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> { 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: [:]) } From 3f52eefb17299f6ea9e002d0751d976b3dcdfb65 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 3 Sep 2015 19:57:35 +0300 Subject: [PATCH 049/122] no message --- SwiftSignalKit/Queue.swift | 8 ++++++-- SwiftSignalKit/Signal_Catch.swift | 4 ++-- SwiftSignalKit/Signal_Take.swift | 14 ++++++++++++++ SwiftSignalKit/ThreadPool.swift | 18 +++++++++++++++--- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 8408822ba5..fa46930ae6 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -38,8 +38,12 @@ public final class Queue { self.specialIsMainQueue = specialIsMainQueue } - public init() { - self.nativeQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL) + 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.specialIsMainQueue = false diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index f84789e844..80733ba4e6 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -90,7 +90,7 @@ public func recurse(latestValue: T?)(signal: Signal) -> Signal } } -public func retry(exponentialDecay: Double, onQueue queue: Queue)(signal: Signal) -> Signal { +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) @@ -105,7 +105,7 @@ public func retry(exponentialDecay: Double, onQueue queue: Queue)(signal: subscriber.putNext(next) }, error: { error in let delay = currentDelay.modify { value in - return value + return min(maxDelay, value + delayIncrement) } let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))) diff --git a/SwiftSignalKit/Signal_Take.swift b/SwiftSignalKit/Signal_Take.swift index d2e11c1a2f..a7a9b563c4 100644 --- a/SwiftSignalKit/Signal_Take.swift +++ b/SwiftSignalKit/Signal_Take.swift @@ -25,3 +25,17 @@ public func take(count: Int)(signal: Signal) -> Signal { }) } } + +public func last(signal: Signal) -> Signal { + return Signal { subscriber in + let value = Atomic(value: nil) + return signal.start(next: { next in + value.swap(next) + }, error: { error in + subscriber.putError(error) + }, completed: { completed in + subscriber.putNext(value.with({ $0 })) + subscriber.putCompletion() + }) + } +} diff --git a/SwiftSignalKit/ThreadPool.swift b/SwiftSignalKit/ThreadPool.swift index acecd357aa..74b86e8c30 100644 --- a/SwiftSignalKit/ThreadPool.swift +++ b/SwiftSignalKit/ThreadPool.swift @@ -65,7 +65,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { private var mutex: pthread_mutex_t private var condition: pthread_cond_t - private class func threadEntryPoint(threadPool: ThreadPool) { + @objc class func threadEntryPoint(threadPool: ThreadPool) { var queue: ThreadPoolQueue! while (true) { @@ -107,7 +107,9 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { pthread_mutex_unlock(&threadPool.mutex); if task != nil { - task.execute() + autoreleasepool { + task.execute() + } } } } @@ -123,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 = NSThread(target: ThreadPool.self, selector: Selector("threadEntryPoint:"), object: self) thread.threadPriority = threadPriority self.threads.append(thread) thread.start() @@ -153,4 +155,14 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { public func nextQueue() -> ThreadPoolQueue { return ThreadPoolQueue(threadPool: self) } + + public func isCurrentThreadInPool() -> Bool { + let currentThread = NSThread.currentThread() + for thread in self.threads { + if currentThread.isEqual(thread) { + return true + } + } + return false + } } \ No newline at end of file From 008ad99279d3fbf6c476574a2e2f7f765ac2fa5e Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 17 Sep 2015 15:01:12 +0300 Subject: [PATCH 050/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 8 +++ SSignalKit/SDisposableSet.h | 3 + SSignalKit/SDisposableSet.m | 17 +++++ SSignalKit/SMulticastSignalManager.m | 10 ++- SSignalKit/SQueue.h | 2 + SSignalKit/SQueue.m | 9 +++ SSignalKit/SSignalKit.h | 1 + SSignalKit/SVariable.h | 12 ++++ SSignalKit/SVariable.m | 93 ++++++++++++++++++++++++++++ 9 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 SSignalKit/SVariable.h create mode 100644 SSignalKit/SVariable.m diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 1fd3e0de6e..25f58f1b89 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -88,6 +88,8 @@ 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 */; }; + 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 */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -197,6 +199,8 @@ 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 = ""; }; D06F10721A85882000485185 /* SSignalPerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignalPerformanceTests.m; 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -365,6 +369,8 @@ D0085AD21B28285400EAF753 /* SSignal+Multicast.m */, D0085ABA1B28285400EAF753 /* SMulticastSignalManager.h */, D0085ABB1B28285400EAF753 /* SMulticastSignalManager.m */, + D09FD73C1BA9BAB900FF0A4F /* SVariable.h */, + D09FD73D1BA9BAB900FF0A4F /* SVariable.m */, D0085AB91B28285400EAF753 /* SSignalKit.h */, D0445DDB1A7C2CA500267924 /* Supporting Files */, ); @@ -417,6 +423,7 @@ files = ( D0085AF61B28285400EAF753 /* SSignal+SideEffects.h in Headers */, D0085AFD1B28285400EAF753 /* SSignal+Meta.h in Headers */, + D09FD73E1BA9BAB900FF0A4F /* SVariable.h in Headers */, D0085AFE1B28285400EAF753 /* SSignal+Timing.h in Headers */, D0085B0A1B28285400EAF753 /* SDisposable.h in Headers */, D0085B111B28285400EAF753 /* SBag.h in Headers */, @@ -638,6 +645,7 @@ buildActionMask = 2147483647; files = ( D0085AE91B28285400EAF753 /* SQueue.m in Sources */, + D09FD73F1BA9BAB900FF0A4F /* SVariable.m in Sources */, D0085B141B28285400EAF753 /* SBlockDisposable.m in Sources */, D0085B001B28285400EAF753 /* SSignal+Dispatch.m in Sources */, D0085AE71B28285400EAF753 /* SSignal+Timing.m in Sources */, diff --git a/SSignalKit/SDisposableSet.h b/SSignalKit/SDisposableSet.h index 9cade19504..7d7515c968 100644 --- a/SSignalKit/SDisposableSet.h +++ b/SSignalKit/SDisposableSet.h @@ -1,7 +1,10 @@ #import +@class SSignal; + @interface SDisposableSet : NSObject - (void)add:(id)disposable; +- (void)remove:(id)disposable; @end diff --git a/SSignalKit/SDisposableSet.m b/SSignalKit/SDisposableSet.m index 469436ad99..18cb3be965 100644 --- a/SSignalKit/SDisposableSet.m +++ b/SSignalKit/SDisposableSet.m @@ -1,5 +1,7 @@ #import "SDisposableSet.h" +#import "SSignal.h" + #import @interface SDisposableSet () @@ -48,6 +50,21 @@ [disposable dispose]; } +- (void)remove:(id)disposable { + OSSpinLockLock(&_lock); + if (_multipleDisposables != nil) + { + NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithArray:_multipleDisposables]; + [multipleDisposables removeObject:disposable]; + _multipleDisposables = multipleDisposables; + } + else if (_singleDisposable == disposable) + { + _singleDisposable = nil; + } + OSSpinLockUnlock(&_lock); +} + - (void)dispose { id singleDisposable = nil; diff --git a/SSignalKit/SMulticastSignalManager.m b/SSignalKit/SMulticastSignalManager.m index 74bfdf252f..1094852dd5 100644 --- a/SSignalKit/SMulticastSignalManager.m +++ b/SSignalKit/SMulticastSignalManager.m @@ -65,7 +65,7 @@ signal = producer(); if (signal != nil) { - signal = [[signal multicast] onDispose:^ + signal = [[signal onDispose:^ { __strong SMulticastSignalManager *strongSelf = weakSelf; if (strongSelf != nil) @@ -74,7 +74,7 @@ [strongSelf->_multicastSignals removeObjectForKey:key]; OSSpinLockUnlock(&strongSelf->_lock); } - }]; + }] multicast]; _multicastSignals[key] = signal; } } @@ -146,7 +146,11 @@ return [[SBlockDisposable alloc] initWithBlock:^ { OSSpinLockLock(&_lock); - [(SBag *)_pipeListeners[key] removeItem:index]; + SBag *bag = _pipeListeners[key]; + [bag removeItem:index]; + if ([bag isEmpty]) { + [_pipeListeners removeObjectForKey:key]; + } OSSpinLockUnlock(&_lock); }]; }]; diff --git a/SSignalKit/SQueue.h b/SSignalKit/SQueue.h index bfc98fe157..a1782b2112 100644 --- a/SSignalKit/SQueue.h +++ b/SSignalKit/SQueue.h @@ -13,4 +13,6 @@ - (dispatch_queue_t)_dispatch_queue; +- (bool)isCurrentQueue; + @end diff --git a/SSignalKit/SQueue.m b/SSignalKit/SQueue.m index 2d0c86296a..ed0b4463bd 100644 --- a/SSignalKit/SQueue.m +++ b/SSignalKit/SQueue.m @@ -98,4 +98,13 @@ static const void *SQueueSpecificKey = &SQueueSpecificKey; dispatch_sync(_queue, block); } +- (bool)isCurrentQueue +{ + if (_queueSpecific != NULL && dispatch_get_specific(SQueueSpecificKey) == _queueSpecific) + return true; + else if (_specialIsMainQueue && [NSThread isMainThread]) + return true; + return false; +} + @end diff --git a/SSignalKit/SSignalKit.h b/SSignalKit/SSignalKit.h index cd1b6d541e..9842a184e1 100644 --- a/SSignalKit/SSignalKit.h +++ b/SSignalKit/SSignalKit.h @@ -42,3 +42,4 @@ FOUNDATION_EXPORT const unsigned char SSignalKitVersionString[]; #import #import #import +#import diff --git a/SSignalKit/SVariable.h b/SSignalKit/SVariable.h new file mode 100644 index 0000000000..47d51a1608 --- /dev/null +++ b/SSignalKit/SVariable.h @@ -0,0 +1,12 @@ +#import + +@class SSignal; + +@interface SVariable : NSObject + +- (instancetype)init; + +- (void)set:(SSignal *)signal; +- (SSignal *)signal; + +@end diff --git a/SSignalKit/SVariable.m b/SSignalKit/SVariable.m new file mode 100644 index 0000000000..45eea46a2c --- /dev/null +++ b/SSignalKit/SVariable.m @@ -0,0 +1,93 @@ +#import "SVariable.h" + +#import + +#import "SSignal.h" +#import "SBag.h" +#import "SBlockDisposable.h" +#import "SMetaDisposable.h" + +@interface SVariable () +{ + OSSpinLock _lock; + id _value; + bool _hasValue; + SBag *_subscribers; + SMetaDisposable *_disposable; +} + +@end + +@implementation SVariable + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + _subscribers = [[SBag alloc] init]; + _disposable = [[SMetaDisposable alloc] init]; + } + return self; +} + +- (void)dealloc +{ + [_disposable dispose]; +} + +- (SSignal *)signal +{ + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + OSSpinLockLock(&self->_lock); + id currentValue = _value; + bool hasValue = _hasValue; + NSInteger index = [self->_subscribers addItem:[^(id value) + { + [subscriber putNext:value]; + } copy]]; + OSSpinLockUnlock(&self->_lock); + + if (hasValue) + { + [subscriber putNext:currentValue]; + } + + return [[SBlockDisposable alloc] initWithBlock:^ + { + OSSpinLockLock(&self->_lock); + [self->_subscribers removeItem:index]; + OSSpinLockUnlock(&self->_lock); + }]; + }]; +} + +- (void)set:(SSignal *)signal +{ + OSSpinLockLock(&_lock); + _hasValue = false; + OSSpinLockUnlock(&_lock); + + __weak SVariable *weakSelf = self; + [_disposable setDisposable:[signal startWithNext:^(id next) + { + __strong SVariable *strongSelf = weakSelf; + if (strongSelf != nil) + { + NSArray *subscribers = nil; + OSSpinLockLock(&strongSelf->_lock); + strongSelf->_value = next; + strongSelf->_hasValue = true; + subscribers = [strongSelf->_subscribers copyItems]; + OSSpinLockUnlock(&strongSelf->_lock); + + for (void (^subscriber)(id) in subscribers) + { + subscriber(next); + } + } + }]]; +} + +@end From 92651bf1ee07331dd9144b9ff7389ca23a570ad8 Mon Sep 17 00:00:00 2001 From: Peter Date: Sun, 20 Sep 2015 13:12:25 +0300 Subject: [PATCH 051/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 25f58f1b89..197f216e99 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -873,6 +873,7 @@ 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; @@ -891,6 +892,7 @@ 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; From d82a44303d75822f2df891c8e2bd0b3c488cb282 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 22 Sep 2015 20:59:04 +0300 Subject: [PATCH 052/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 11 ++++++++++- SSignalKit/Info.plist | 2 +- SSignalKitTests/Info.plist | 2 +- SwiftSignalKit/Info.plist | 2 +- SwiftSignalKitTests/Info.plist | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 197f216e99..39fd44186c 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -535,7 +535,7 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0640; + LastUpgradeCheck = 0710; ORGANIZATIONNAME = Telegram; TargetAttributes = { D0085B211B282B9800EAF753 = { @@ -717,6 +717,7 @@ 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)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -737,6 +738,7 @@ 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)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -759,6 +761,7 @@ 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)"; }; name = Debug; @@ -776,6 +779,7 @@ 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)"; }; name = Release; @@ -802,6 +806,7 @@ CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -880,6 +885,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; ONLY_ACTIVE_ARCH = NO; + PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -898,6 +904,7 @@ 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)"; SKIP_INSTALL = YES; }; @@ -922,6 +929,7 @@ XCTest, "-ObjC", ); + PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -941,6 +949,7 @@ XCTest, "-ObjC", ); + PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/SSignalKit/Info.plist b/SSignalKit/Info.plist index f6228f96e7..d3de8eefb6 100644 --- a/SSignalKit/Info.plist +++ b/SSignalKit/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.telegram.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/SSignalKitTests/Info.plist b/SSignalKitTests/Info.plist index 29dacae6b5..ba72822e87 100644 --- a/SSignalKitTests/Info.plist +++ b/SSignalKitTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.telegram.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/SwiftSignalKit/Info.plist b/SwiftSignalKit/Info.plist index f6228f96e7..d3de8eefb6 100644 --- a/SwiftSignalKit/Info.plist +++ b/SwiftSignalKit/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.telegram.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/SwiftSignalKitTests/Info.plist b/SwiftSignalKitTests/Info.plist index 29dacae6b5..ba72822e87 100644 --- a/SwiftSignalKitTests/Info.plist +++ b/SwiftSignalKitTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.telegram.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName From c935b130abe09491194dec839aeefd6f5cab9b44 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 15 Oct 2015 19:44:01 +0300 Subject: [PATCH 053/122] no message --- SSignalKit/SSignal+Dispatch.h | 1 + SSignalKit/SSignal+Dispatch.m | 79 +++++++++++++++++++++++++++++++++++ SSignalKit/SSignal+Take.h | 1 + SSignalKit/SSignal+Take.m | 43 +++++++++++++++++++ SSignalKit/STimer.h | 1 + 5 files changed, 125 insertions(+) diff --git a/SSignalKit/SSignal+Dispatch.h b/SSignalKit/SSignal+Dispatch.h index 4b23e0d38a..a22679b372 100644 --- a/SSignalKit/SSignal+Dispatch.h +++ b/SSignalKit/SSignal+Dispatch.h @@ -9,5 +9,6 @@ - (SSignal *)deliverOnThreadPool:(SThreadPool *)threadPool; - (SSignal *)startOn:(SQueue *)queue; - (SSignal *)startOnThreadPool:(SThreadPool *)threadPool; +- (SSignal *)throttleOn:(SQueue *)queue delay:(NSTimeInterval)delay; @end diff --git a/SSignalKit/SSignal+Dispatch.m b/SSignalKit/SSignal+Dispatch.m index 2a72201ae4..3929f07eff 100644 --- a/SSignalKit/SSignal+Dispatch.m +++ b/SSignalKit/SSignal+Dispatch.m @@ -1,8 +1,31 @@ #import "SSignal+Dispatch.h" #import "SAtomic.h" +#import "STimer.h" #import "SBlockDisposable.h" #import "SMetaDisposable.h" +@interface SSignal_ThrottleContainer : NSObject + +@property (nonatomic, strong, readonly) id value; +@property (nonatomic, readonly) bool committed; +@property (nonatomic, readonly) bool last; + +@end + +@implementation SSignal_ThrottleContainer + +- (instancetype)initWithValue:(id)value committed:(bool)committed last:(bool)last { + self = [super init]; + if (self != nil) { + _value = value; + _committed = committed; + _last = last; + } + return self; +} + +@end + @implementation SSignal (Dispatch) - (SSignal *)deliverOn:(SQueue *)queue @@ -130,4 +153,60 @@ }]; } +- (SSignal *)throttleOn:(SQueue *)queue delay:(NSTimeInterval)delay +{ + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { + SAtomic *value = [[SAtomic alloc] initWithValue:nil]; + STimer *timer = [[STimer alloc] initWithTimeout:delay repeat:false completion:^{ + [value modify:^id(SSignal_ThrottleContainer *container) { + if (container != nil) { + if (!container.committed) { + [subscriber putNext:container.value]; + container = [[SSignal_ThrottleContainer alloc] initWithValue:container.value committed:true last:container.last]; + } + + if (container.last) { + [subscriber putCompletion]; + } + } + return container; + }]; + } queue:queue]; + + return [[self deliverOn:queue] startWithNext:^(id next) { + [value modify:^id(SSignal_ThrottleContainer *container) { + if (container == nil) { + container = [[SSignal_ThrottleContainer alloc] initWithValue:next committed:false last:false]; + } + return container; + }]; + [timer invalidate]; + [timer start]; + } error:^(id error) { + [timer invalidate]; + [subscriber putError:error]; + } completed:^{ + [timer invalidate]; + __block bool start = false; + [value modify:^id(SSignal_ThrottleContainer *container) { + bool wasCommitted = false; + if (container == nil) { + wasCommitted = true; + container = [[SSignal_ThrottleContainer alloc] initWithValue:nil committed:true last:true]; + } else { + wasCommitted = container.committed; + container = [[SSignal_ThrottleContainer alloc] initWithValue:container.value committed:container.committed last:true]; + } + start = wasCommitted; + return container; + }]; + if (start) { + [timer start]; + } else { + [timer fireAndInvalidate]; + } + }]; + }]; +} + @end diff --git a/SSignalKit/SSignal+Take.h b/SSignalKit/SSignal+Take.h index 796db95af9..58c8932858 100644 --- a/SSignalKit/SSignal+Take.h +++ b/SSignalKit/SSignal+Take.h @@ -3,5 +3,6 @@ @interface SSignal (Take) - (SSignal *)take:(NSUInteger)count; +- (SSignal *)takeLast; @end diff --git a/SSignalKit/SSignal+Take.m b/SSignalKit/SSignal+Take.m index af0a38d6f0..f670099d51 100644 --- a/SSignalKit/SSignal+Take.m +++ b/SSignalKit/SSignal+Take.m @@ -2,6 +2,24 @@ #import "SAtomic.h" +@interface SSignal_ValueContainer : NSObject + +@property (nonatomic, strong, readonly) id value; + +@end + +@implementation SSignal_ValueContainer + +- (instancetype)initWithValue:(id)value { + self = [super init]; + if (self != nil) { + _value = value; + } + return self; +} + +@end + @implementation SSignal (Take) - (SSignal *)take:(NSUInteger)count @@ -37,4 +55,29 @@ }]; } +- (SSignal *)takeLast +{ + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + SAtomic *last = [[SAtomic alloc] initWithValue:nil]; + return [self startWithNext:^(id next) + { + [last swap:[[SSignal_ValueContainer alloc] initWithValue:next]]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + SSignal_ValueContainer *value = [last with:^id(id value) { + return value; + }]; + if (value != nil) + { + [subscriber putNext:value.value]; + } + [subscriber putCompletion]; + }]; + }]; +} + @end diff --git a/SSignalKit/STimer.h b/SSignalKit/STimer.h index e0c4e7b81f..55420e25f5 100644 --- a/SSignalKit/STimer.h +++ b/SSignalKit/STimer.h @@ -8,5 +8,6 @@ - (void)start; - (void)invalidate; +- (void)fireAndInvalidate; @end From bb0fedc001ce8a6be6359e6cdb37022c060b79ac Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 30 Nov 2015 15:35:15 +0300 Subject: [PATCH 054/122] no message --- SSignalKit/SSignal+SideEffects.h | 1 + SSignalKit/SSignal+SideEffects.m | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/SSignalKit/SSignal+SideEffects.h b/SSignalKit/SSignal+SideEffects.h index 9d47d3a49b..8107fcf4cb 100644 --- a/SSignalKit/SSignal+SideEffects.h +++ b/SSignalKit/SSignal+SideEffects.h @@ -7,6 +7,7 @@ - (SSignal *)afterNext:(void (^)(id next))f; - (SSignal *)onError:(void (^)(id error))f; - (SSignal *)onCompletion:(void (^)())f; +- (SSignal *)afterCompletion:(void (^)())f; - (SSignal *)onDispose:(void (^)())f; @end diff --git a/SSignalKit/SSignal+SideEffects.m b/SSignalKit/SSignal+SideEffects.m index 4a7e992826..3d78102d2d 100644 --- a/SSignalKit/SSignal+SideEffects.m +++ b/SSignalKit/SSignal+SideEffects.m @@ -95,6 +95,23 @@ }]; } +- (SSignal *)afterCompletion:(void (^)())f { + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + return [self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + f(); + }]; + }]; +} + - (SSignal *)onDispose:(void (^)())f { return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) From 7b4eb2c703b7582ab3fb3d5a7494aa024a7b9e2b Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 30 Dec 2015 04:43:06 +0300 Subject: [PATCH 055/122] Subscriber deadlock fix --- SSignalKit/SSignal+Meta.m | 16 +++++- SSignalKit/SSubscriber.h | 4 -- SSignalKit/SSubscriber.m | 87 +++++++++++++++++++---------- SSignalKitTests/SSignalBasicTests.m | 33 +++++++++++ 4 files changed, 103 insertions(+), 37 deletions(-) diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 662c3c3e86..bf054904c6 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -38,6 +38,10 @@ return self; } +- (void)dealloc { + int bp = 1; +} + - (void)beginWithDisposable:(id)disposable { _disposable = disposable; @@ -60,6 +64,7 @@ if (startSignal) { + __weak SSignalQueueState *weakSelf = self; id disposable = [signal startWithNext:^(id next) { [_subscriber putNext:next]; @@ -68,7 +73,10 @@ [_subscriber putError:error]; } completed:^ { - [self headCompleted]; + __strong SSignalQueueState *strongSelf = weakSelf; + if (strongSelf != nil) { + [strongSelf headCompleted]; + } }]; [_currentDisposable setDisposable:disposable]; @@ -102,6 +110,7 @@ [_subscriber putCompletion]; else if (nextSignal != nil) { + __weak SSignalQueueState *weakSelf = self; id disposable = [nextSignal startWithNext:^(id next) { [_subscriber putNext:next]; @@ -110,7 +119,10 @@ [_subscriber putError:error]; } completed:^ { - [self headCompleted]; + __strong SSignalQueueState *strongSelf = weakSelf; + if (strongSelf != nil) { + [strongSelf headCompleted]; + } }]; [_currentDisposable setDisposable:disposable]; diff --git a/SSignalKit/SSubscriber.h b/SSignalKit/SSubscriber.h index 2c635279d7..ce4fee5678 100644 --- a/SSignalKit/SSubscriber.h +++ b/SSignalKit/SSubscriber.h @@ -2,10 +2,6 @@ @interface SSubscriber : NSObject { - @public - void (^_next)(id); - void (^_error)(id); - void (^_completed)(); } - (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index bed29f9193..376bbfdddb 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -2,12 +2,36 @@ #import +@interface SSubscriberBlocks : NSObject { + @public + void (^_next)(id); + void (^_error)(id); + void (^_completed)(); +} + +@end + +@implementation SSubscriberBlocks + +- (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed { + self = [super init]; + if (self != nil) { + _next = [next copy]; + _error = [error copy]; + _completed = [completed copy]; + } + return self; +} + +@end + @interface SSubscriber () { @protected OSSpinLock _lock; bool _terminated; id _disposable; + SSubscriberBlocks *_blocks; } @end @@ -19,9 +43,7 @@ self = [super init]; if (self != nil) { - _next = [next copy]; - _error = [error copy]; - _completed = [completed copy]; + _blocks = [[SSubscriberBlocks alloc] initWithNext:next error:error completed:completed]; } return self; } @@ -37,48 +59,55 @@ - (void)_markTerminatedWithoutDisposal { OSSpinLockLock(&_lock); + SSubscriberBlocks *blocks = nil; if (!_terminated) { + blocks = _blocks; + _blocks = nil; + _terminated = true; - _next = nil; - _error = nil; - _completed = nil; } OSSpinLockUnlock(&_lock); + + if (blocks) { + blocks = nil; + } } - (void)putNext:(id)next { - void (^fnext)(id) = nil; + SSubscriberBlocks *blocks = nil; OSSpinLockLock(&_lock); - if (!_terminated) - fnext = self->_next; + if (!_terminated) { + blocks = _blocks; + } OSSpinLockUnlock(&_lock); - if (fnext) - fnext(next); + if (blocks && blocks->_next) { + blocks->_next(next); + } } - (void)putError:(id)error { bool shouldDispose = false; - void (^ferror)(id) = nil; + SSubscriberBlocks *blocks = nil; OSSpinLockLock(&_lock); if (!_terminated) { - ferror = self->_error; + blocks = _blocks; + _blocks = nil; + shouldDispose = true; - self->_next = nil; - self->_error = nil; - self->_completed = nil; _terminated = true; } OSSpinLockUnlock(&_lock); - if (ferror) - ferror(error); + if (blocks && blocks->_error) { + blocks->_error(error); + } if (shouldDispose) [self->_disposable dispose]; @@ -87,22 +116,21 @@ - (void)putCompletion { bool shouldDispose = false; - void (^completed)() = nil; + SSubscriberBlocks *blocks = nil; OSSpinLockLock(&_lock); if (!_terminated) { - completed = self->_completed; + blocks = _blocks; + _blocks = nil; + shouldDispose = true; - self->_next = nil; - self->_error = nil; - self->_completed = nil; _terminated = true; } OSSpinLockUnlock(&_lock); - if (completed) - completed(); + if (blocks && blocks->_completed) + blocks->_completed(); if (shouldDispose) [self->_disposable dispose]; @@ -126,18 +154,15 @@ - (instancetype)initWithName:(NSString *)name next:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed { - self = [super init]; + self = [super initWithNext:next error:error completed:completed]; if (self != nil) { _name = name; - _next = [next copy]; - _error = [error copy]; - _completed = [completed copy]; } return self; } -- (void)_assignDisposable:(id)disposable +/*- (void)_assignDisposable:(id)disposable { if (_terminated) [disposable dispose]; @@ -239,6 +264,6 @@ { NSLog(@"trace(%@ dispose)", _name); [self->_disposable dispose]; -} +}*/ @end diff --git a/SSignalKitTests/SSignalBasicTests.m b/SSignalKitTests/SSignalBasicTests.m index 099abfd207..cb5a986af6 100644 --- a/SSignalKitTests/SSignalBasicTests.m +++ b/SSignalKitTests/SSignalBasicTests.m @@ -9,6 +9,31 @@ #import "DeallocatingObject.h" +@interface DisposableHolder : NSObject { +} + +@property (nonatomic, strong) id disposable; + +@end + +@implementation DisposableHolder + +- (instancetype)init { + self = [super init]; + if (self != nil) { + _disposable = [[[SSignal single:nil] delay:1.0 onQueue:[SQueue concurrentDefaultQueue]] startWithNext:^(__unused id next){ + [self description]; + }]; + } + return self; +} + +- (void)dealloc { + [_disposable dispose]; +} + +@end + @interface SSignalBasicTests : XCTestCase @end @@ -669,4 +694,12 @@ XCTAssertEqual(result2, 2); } +- (void)testDisposableDeadlock { + @autoreleasepool { + DisposableHolder *holder = [[DisposableHolder alloc] init]; + holder = nil; + sleep(10); + } +} + @end From 9f750b75ba931b360cba7c69fb7ecbd6f7a9b60e Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 30 Dec 2015 23:49:28 +0300 Subject: [PATCH 056/122] Cleanup --- SSignalKit/SSignal+Meta.m | 4 ---- 1 file changed, 4 deletions(-) diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index bf054904c6..7ee351df3a 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -38,10 +38,6 @@ return self; } -- (void)dealloc { - int bp = 1; -} - - (void)beginWithDisposable:(id)disposable { _disposable = disposable; From c584b6bf6bee4f17e9b63f68fc4ffb043665677a Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 31 Dec 2015 04:27:02 +0300 Subject: [PATCH 057/122] no message --- SSignalKit/SSignal+Meta.h | 6 +++++ SSignalKit/SSignal+Meta.m | 47 +++++++++++++++++++++++++++++++++++++++ SSignalKit/SSignal+Take.h | 1 + SSignalKit/SSignal+Take.m | 39 ++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+) diff --git a/SSignalKit/SSignal+Meta.h b/SSignalKit/SSignal+Meta.h index c8d4b0102a..8a1dd0d48f 100644 --- a/SSignalKit/SSignal+Meta.h +++ b/SSignalKit/SSignal+Meta.h @@ -12,3 +12,9 @@ + (SSignal *)defer:(SSignal *(^)())generator; @end + +@interface SSignalQueue : NSObject + +- (SSignal *)enqueue:(SSignal *)signal; + +@end diff --git a/SSignalKit/SSignal+Meta.m b/SSignalKit/SSignal+Meta.m index 7ee351df3a..43e2d93c10 100644 --- a/SSignalKit/SSignal+Meta.m +++ b/SSignalKit/SSignal+Meta.m @@ -4,6 +4,7 @@ #import "SMetaDisposable.h" #import "SSignal+Mapping.h" #import "SAtomic.h" +#import "SSignal+Pipe.h" #import @@ -250,3 +251,49 @@ } @end + +@interface SSignalQueue () { + SPipe *_pipe; + id _disposable; +} + +@end + +@implementation SSignalQueue + +- (instancetype)init { + self = [super init]; + if (self != nil) { + _pipe = [[SPipe alloc] init]; + _disposable = [[_pipe.signalProducer() queue] startWithNext:nil]; + } + return self; +} + +- (void)dealloc { + [_disposable dispose]; +} + +- (SSignal *)enqueue:(SSignal *)signal { + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { + SPipe *disposePipe = [[SPipe alloc] init]; + + SSignal *proxy = [[[[signal onNext:^(id next) { + [subscriber putNext:next]; + }] onError:^(id error) { + [subscriber putError:error]; + }] onCompletion:^{ + [subscriber putCompletion]; + }] catch:^SSignal *(__unused id error) { + return [SSignal complete]; + }]; + + _pipe.sink([proxy takeUntilReplacement:disposePipe.signalProducer()]); + + return [[SBlockDisposable alloc] initWithBlock:^{ + disposePipe.sink([SSignal complete]); + }]; + }]; +} + +@end diff --git a/SSignalKit/SSignal+Take.h b/SSignalKit/SSignal+Take.h index 58c8932858..a4d1ff23eb 100644 --- a/SSignalKit/SSignal+Take.h +++ b/SSignalKit/SSignal+Take.h @@ -4,5 +4,6 @@ - (SSignal *)take:(NSUInteger)count; - (SSignal *)takeLast; +- (SSignal *)takeUntilReplacement:(SSignal *)replacement; @end diff --git a/SSignalKit/SSignal+Take.m b/SSignalKit/SSignal+Take.m index f670099d51..e5db9fa034 100644 --- a/SSignalKit/SSignal+Take.m +++ b/SSignalKit/SSignal+Take.m @@ -80,4 +80,43 @@ }]; } +- (SSignal *)takeUntilReplacement:(SSignal *)replacement { + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { + SDisposableSet *disposable = [[SDisposableSet alloc] init]; + + SMetaDisposable *selfDisposable = [[SMetaDisposable alloc] init]; + SMetaDisposable *replacementDisposable = [[SMetaDisposable alloc] init]; + + [disposable add:selfDisposable]; + [disposable add:replacementDisposable]; + + [disposable add:[replacement startWithNext:^(SSignal *next) { + [selfDisposable dispose]; + + [replacementDisposable setDisposable:[next startWithNext:^(id next) { + [subscriber putNext:next]; + } error:^(id error) { + [subscriber putError:error]; + } completed:^{ + [subscriber putCompletion]; + }]]; + } error:^(id error) { + [subscriber putError:error]; + } completed:^{ + }]]; + + [selfDisposable setDisposable:[self startWithNext:^(id next) { + [subscriber putNext:next]; + } error:^(id error) { + [replacementDisposable dispose]; + [subscriber putError:error]; + } completed:^{ + [replacementDisposable dispose]; + [subscriber putCompletion]; + }]]; + + return disposable; + }]; +} + @end From e5d77e950cb6ef199bf0ac5f219da9a306ebdfd4 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 26 Jan 2016 16:20:49 +0300 Subject: [PATCH 058/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 4 ++ SwiftSignalKit/Promise.swift | 60 ++++++++++++++++++++++++++++ SwiftSignalKit/Queue.swift | 4 +- 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 SwiftSignalKit/Promise.swift diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 39fd44186c..9d389f62c6 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -88,6 +88,7 @@ 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 */; }; /* End PBXBuildFile section */ @@ -199,6 +200,7 @@ 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 = ""; }; D06F10721A85882000485185 /* SSignalPerformanceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSignalPerformanceTests.m; sourceTree = ""; }; + 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 = ""; }; /* End PBXFileReference section */ @@ -260,6 +262,7 @@ D0085B4C1B282BEE00EAF753 /* Disposable.swift */, D0085B4D1B282BEE00EAF753 /* Signal_Mapping.swift */, D0085B4E1B282BEE00EAF753 /* Subscriber.swift */, + D07A5CFC1BBDE6E400451791 /* Promise.swift */, D0085B261B282B9800EAF753 /* SwiftSignalKit.h */, D0085B241B282B9800EAF753 /* Supporting Files */, ); @@ -615,6 +618,7 @@ D0085B601B282BEE00EAF753 /* Disposable.swift in Sources */, D0085B531B282BEE00EAF753 /* ThreadPool.swift in Sources */, D0085B5F1B282BEE00EAF753 /* Signal.swift in Sources */, + D07A5CFD1BBDE6E400451791 /* Promise.swift in Sources */, D0085B5E1B282BEE00EAF753 /* Signal_Reduce.swift in Sources */, D0085B621B282BEE00EAF753 /* Subscriber.swift in Sources */, D0085B581B282BEE00EAF753 /* Signal_Take.swift in Sources */, diff --git a/SwiftSignalKit/Promise.swift b/SwiftSignalKit/Promise.swift new file mode 100644 index 0000000000..00e96b9649 --- /dev/null +++ b/SwiftSignalKit/Promise.swift @@ -0,0 +1,60 @@ +import Foundation + +public class Promise { + private var value: T? + private var lock: OSSpinLock = 0 + private let disposable = MetaDisposable() + private let subscribers = Bag Void>() + + public init(_ value: T) { + self.value = value + } + + public init() { + } + + deinit { + self.disposable.dispose() + } + + public func set(signal: Signal) { + OSSpinLockLock(&self.lock) + self.value = nil + OSSpinLockUnlock(&self.lock) + + self.disposable.set(signal.start(next: { [weak self] next in + if let strongSelf = self { + OSSpinLockLock(&strongSelf.lock) + strongSelf.value = next + let subscribers = strongSelf.subscribers.copyItems() + OSSpinLockUnlock(&strongSelf.lock); + + for subscriber in subscribers { + subscriber(next) + } + } + })) + } + + public func get() -> Signal { + return Signal { subscriber in + OSSpinLockLock(&self.lock) + let currentValue = self.value + let index = self.subscribers.add({ next in + subscriber.putNext(next) + }) + OSSpinLockUnlock(&self.lock) + + + if let currentValue = currentValue { + subscriber.putNext(currentValue) + } + + return ActionDisposable { + OSSpinLockLock(&self.lock) + self.subscribers.remove(index) + OSSpinLockUnlock(&self.lock) + } + } + } +} diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index fa46930ae6..178903b22d 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -3,6 +3,8 @@ import Foundation private let _QueueSpecificKey = NSObject() private let QueueSpecificKey: UnsafePointer = UnsafePointer(Unmanaged.passUnretained(_QueueSpecificKey).toOpaque()) +private let globalMainQueue = Queue(queue: dispatch_get_main_queue(), specialIsMainQueue: true) + public final class Queue { private let nativeQueue: dispatch_queue_t private var specific: UnsafeMutablePointer @@ -15,7 +17,7 @@ public final class Queue { } public class func mainQueue() -> Queue { - return Queue(queue: dispatch_get_main_queue(), specialIsMainQueue: true) + return globalMainQueue } public class func concurrentDefaultQueue() -> Queue { From 3cc232e378eef056ab6d07a298257342b9aaca9f Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 9 Mar 2016 01:27:33 +0300 Subject: [PATCH 059/122] no message --- SSignalKit/SSignal+Mapping.h | 1 + SSignalKit/SSignal+Mapping.m | 42 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) 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..8bc0ef3e7d 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,33 @@ }]; } +- (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; + } + return @true; + }] boolValue]; + + if (shouldPassthrough) { + [subscriber putNext:next]; + } + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + @end From f9620a013c2b8f35a206b917c58c0634062bfbf5 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 10 Mar 2016 00:08:04 +0300 Subject: [PATCH 060/122] no message --- SSignalKit/SSignal+Mapping.m | 1 + 1 file changed, 1 insertion(+) diff --git a/SSignalKit/SSignal+Mapping.m b/SSignalKit/SSignal+Mapping.m index 8bc0ef3e7d..cd3a3ece0a 100644 --- a/SSignalKit/SSignal+Mapping.m +++ b/SSignalKit/SSignal+Mapping.m @@ -63,6 +63,7 @@ } else if ((state.value == nil && next == nil) || [(id)state.value isEqual:next]) { return @false; } + state.value = next; return @true; }] boolValue]; From d86ec040193be9d9d8c1c9b4026663e411abacee Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 28 Mar 2016 17:24:31 +0300 Subject: [PATCH 061/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 12 ++ SwiftSignalKit/Bag.swift | 32 ++++- SwiftSignalKit/Lock.swift | 19 +++ SwiftSignalKit/Multicast.swift | 88 ++++++++++++ SwiftSignalKit/Queue.swift | 4 + SwiftSignalKit/Signal.swift | 31 +++++ SwiftSignalKit/Signal_Catch.swift | 4 +- SwiftSignalKit/Signal_Combine.swift | 14 ++ SwiftSignalKit/Signal_Dispatch.swift | 27 ++++ SwiftSignalKit/Signal_Mapping.swift | 28 ++++ SwiftSignalKit/Signal_Merge.swift | 7 + SwiftSignalKit/Signal_Meta.swift | 118 +++++++++++++++++ SwiftSignalKit/Signal_SideEffects.swift | 26 ++++ .../SwiftSignalKitBasicTests.swift | 125 ++++++++++++++++++ 14 files changed, 531 insertions(+), 4 deletions(-) create mode 100644 SwiftSignalKit/Lock.swift create mode 100644 SwiftSignalKit/Multicast.swift create mode 100644 SwiftSignalKit/Signal_Merge.swift diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 9d389f62c6..ae6e1df8a7 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -85,12 +85,15 @@ D0085B681B282C2800EAF753 /* SwiftSignalKitBasicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0085B651B282C2800EAF753 /* SwiftSignalKitBasicTests.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 */; }; + D0FC1A3A1CA3284F0056AE9A /* Signal_Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FC1A391CA3284F0056AE9A /* Signal_Merge.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -196,6 +199,8 @@ 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 +208,7 @@ 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 = ""; }; + D0FC1A391CA3284F0056AE9A /* Signal_Merge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal_Merge.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -256,6 +262,7 @@ D0085B461B282BEE00EAF753 /* Signal_Single.swift */, D0085B471B282BEE00EAF753 /* Signal_Meta.swift */, D0085B481B282BEE00EAF753 /* Signal_Combine.swift */, + D0FC1A391CA3284F0056AE9A /* Signal_Merge.swift */, D0085B491B282BEE00EAF753 /* Atomic.swift */, D0085B4A1B282BEE00EAF753 /* Signal_Reduce.swift */, D0085B4B1B282BEE00EAF753 /* Signal.swift */, @@ -263,6 +270,8 @@ D0085B4D1B282BEE00EAF753 /* Signal_Mapping.swift */, D0085B4E1B282BEE00EAF753 /* Subscriber.swift */, D07A5CFC1BBDE6E400451791 /* Promise.swift */, + D05F09A71C9EF77100BB6F96 /* Multicast.swift */, + D066BD091C7FE06700D7A576 /* Lock.swift */, D0085B261B282B9800EAF753 /* SwiftSignalKit.h */, D0085B241B282B9800EAF753 /* Supporting Files */, ); @@ -616,12 +625,15 @@ 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 */, 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 */, diff --git a/SwiftSignalKit/Bag.swift b/SwiftSignalKit/Bag.swift index a4ec0c84b9..1240fd1057 100644 --- a/SwiftSignalKit/Bag.swift +++ b/SwiftSignalKit/Bag.swift @@ -11,13 +11,24 @@ public final class Bag { 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 get(index: Index) -> T? { + var i = 0 + for key in self.itemKeys { + if key == index { + return self.items[i] + } + i += 1 + } + return nil + } + public func remove(index: Index) { var i = 0 for key in self.itemKeys { @@ -26,11 +37,28 @@ public final class Bag { self.itemKeys.removeAtIndex(i) break } - i++ + i += 1 } } + public func removeAll() { + self.items.removeAll() + self.itemKeys.removeAll() + } + public func copyItems() -> [T] { return self.items } + + 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/Lock.swift b/SwiftSignalKit/Lock.swift new file mode 100644 index 0000000000..8e61f3ba96 --- /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(@noescape 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..e19025e363 --- /dev/null +++ b/SwiftSignalKit/Multicast.swift @@ -0,0 +1,88 @@ +import Foundation + +private final class MulticastInstance { + let disposable: Disposable + var subscribers = Bag 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 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 { + self.instances.removeValueForKey(key) + } + }, completed: { + self.lock.locked { + self.instances.removeValueForKey(key) + } + })) + } + + return ActionDisposable { + var remove = false + instance.lock.locked { + instance.subscribers.remove(index) + if instance.subscribers.isEmpty { + remove = true + } + } + + if remove { + self.lock.locked { + self.instances.removeValueForKey(key) + } + } + } + } + } +} + +public final class MulticastPromise { + public let subscribers = Bag Void>() + public let lock = Lock() + public var value: T? + + public init() { + + } +} diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 178903b22d..18ad9db064 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -82,4 +82,8 @@ public final class Queue { dispatch_async(self.nativeQueue, f) } } + + public func after(delay: Double, _ f: Void -> Void) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), self.queue, f) + } } diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index 1f8ab3d127..c296627a18 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -42,4 +42,35 @@ public struct Signal { 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..ecc7ac0c77 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -1,7 +1,7 @@ import Foundation -public func `catch`(f: E -> Signal)(signal: Signal) -> Signal { - return Signal { subscriber in +public func `catch`(f: E -> Signal)(signal: Signal) -> Signal { + return Signal { subscriber in let disposable = DisposableSet() disposable.add(signal.start(next: { next in diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index c9d455b033..04bd40cc13 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -105,3 +105,17 @@ public func combineLatest(s1: Signal, _ s2: Signal(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..5cf6f51e6f 100644 --- a/SwiftSignalKit/Signal_Dispatch.swift +++ b/SwiftSignalKit/Signal_Dispatch.swift @@ -47,6 +47,33 @@ public func deliverOn(threadPool: ThreadPool)(signal: Signal) -> Sig } } +public func runOn(queue: Queue)(signal: Signal) -> Signal { + return Signal { subscriber in + var cancelled = false + let disposable = MetaDisposable() + + disposable.set(ActionDisposable { + cancelled = true + }) + + queue.dispatch { + 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) -> Signal { return Signal { subscriber in let cancelled = false diff --git a/SwiftSignalKit/Signal_Mapping.swift b/SwiftSignalKit/Signal_Mapping.swift index fdec5584f9..303c7f7856 100644 --- a/SwiftSignalKit/Signal_Mapping.swift +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -37,3 +37,31 @@ public func mapError(f: E -> R)(signal: Signal) -> Signal { }) } } + +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 + let pass = context.with { context -> Bool in + if let value = context.value where 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_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..b29288c4da 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -175,3 +175,121 @@ public func `defer`(generator: () -> Signal) -> Signal { }) } } + +public class SignalQueue { + private let lock = Lock() + + private var queuedSignals = Bag<() -> Disposable>() + private var currentIndex: Bag<() -> Disposable>.Index? + private var currentDisposable = MetaDisposable() + + public init() { + + } + + deinit { + self.currentDisposable.dispose() + } + + public func enqueued(signal: Signal) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + + let activate = { () -> Disposable in + disposable.set(signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + return disposable + } + + var dequeue = false + var index: Bag>.Index! + self.lock.locked { + dequeue = self.queuedSignals.isEmpty + index = self.queuedSignals.add(activate) + } + + if dequeue { + self.dequeue() + } + + return ActionDisposable { + var dequeue = false + self.lock.locked { + self.queuedSignals.remove(index) + if let currentIndex = self.currentIndex where currentIndex == index { + self.currentDisposable.set(nil) + dequeue = true + } + } + if dequeue { + self.dequeue() + } + } + } + } + + private func dequeue() { + var activate: (() -> Disposable)? + self.lock.locked { + if let (index, value) = self.queuedSignals.first { + activate = value + self.currentIndex = index + } + } + + if let activate = activate { + self.currentDisposable.set(activate()) + } + } +} + +/*@interface SSignalQueue () { + SPipe *_pipe; + id _disposable; +} + +@end + +@implementation SSignalQueue + +- (instancetype)init { + self = [super init]; + if (self != nil) { + _pipe = [[SPipe alloc] init]; + _disposable = [[_pipe.signalProducer() queue] startWithNext:nil]; + } + return self; +} + +- (void)dealloc { + [_disposable dispose]; + } + + - (SSignal *)enqueue:(SSignal *)signal { + return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { + SPipe *disposePipe = [[SPipe alloc] init]; + + SSignal *proxy = [[[[signal onNext:^(id next) { + [subscriber putNext:next]; + }] onError:^(id error) { + [subscriber putError:error]; + }] onCompletion:^{ + [subscriber putCompletion]; + }] catch:^SSignal *(__unused id error) { + return [SSignal complete]; + }]; + + _pipe.sink([proxy takeUntilReplacement:disposePipe.signalProducer()]); + + return [[SBlockDisposable alloc] initWithBlock:^{ + disposePipe.sink([SSignal complete]); + }]; + }]; +} + +@end*/ diff --git a/SwiftSignalKit/Signal_SideEffects.swift b/SwiftSignalKit/Signal_SideEffects.swift index 9b8904c849..f791496e2d 100644 --- a/SwiftSignalKit/Signal_SideEffects.swift +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -26,6 +26,32 @@ public func afterNext(f: T -> R)(signal: Signal) -> Signal } } +public func beforeCompleted(f: () -> Void)(signal: Signal) -> Signal { + 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: () -> Void)(signal: Signal) -> Signal { + 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: Void -> R)(signal: Signal) -> Signal { return Signal { subscriber in let disposable = DisposableSet() diff --git a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift index 91ed5ac9fa..6138f0a258 100644 --- a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift +++ b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift @@ -256,4 +256,129 @@ class SwiftSignalKitTests: XCTestCase { XCTAssertTrue(deallocated2, "deallocated2 != true") XCTAssertTrue(disposed2, "disposed2 != true") } + + func testSignalQueue1() { + let queue = SignalQueue() + + var disposed1 = false + let queued1 = queue.enqueued(Signal { subscriber in + subscriber.putNext(1) + subscriber.putCompletion() + + return ActionDisposable { + disposed1 = true + } + }) + + var disposed2 = false + let queued2 = queue.enqueued(Signal { subscriber in + subscriber.putNext(2) + subscriber.putCompletion() + + return ActionDisposable { + disposed2 = true + } + }) + + var next1Called = false + var completed1Called = false + queued1.start(next: { next in + XCTAssert(!next1Called) + next1Called = true + XCTAssert(next == 1) + }, error: { _ in + XCTFail() + }, completed: { + XCTAssert(!completed1Called) + completed1Called = true + }) + + var next2Called = false + var completed2Called = false + queued2.start(next: { next in + XCTAssert(!next2Called) + next2Called = true + XCTAssert(next == 2) + }, error: { _ in + XCTFail() + }, completed: { + XCTAssert(!completed2Called) + completed2Called = true + }) + + XCTAssert(next1Called) + XCTAssert(completed1Called) + XCTAssert(disposed1) + + XCTAssert(next2Called) + XCTAssert(completed2Called) + XCTAssert(disposed2) + } + + func testSignalQueue2() { + let q = Queue() + let queue = SignalQueue() + + var disposed1 = false + let queued1 = queue.enqueued(Signal { subscriber in + q.after(0.4, { + subscriber.putNext(1) + subscriber.putCompletion() + }) + + return ActionDisposable { + disposed1 = true + } + }) + + var disposed2 = false + let queued2 = queue.enqueued(Signal { subscriber in + q.after(0.2, { + subscriber.putNext(2) + subscriber.putCompletion() + }) + + return ActionDisposable { + disposed2 = true + } + }) + + var next1Called = false + var completed1Called = false + queued1.start(next: { next in + XCTAssert(!next1Called) + next1Called = true + XCTAssert(next == 1) + }, error: { _ in + XCTFail() + }, completed: { + XCTAssert(!completed1Called) + completed1Called = true + }) + + var next2Called = false + var completed2Called = false + queued2.start(next: { next in + XCTAssert(next1Called) + XCTAssert(!next2Called) + next2Called = true + XCTAssert(next == 2) + }, error: { _ in + XCTFail() + }, completed: { + XCTAssert(completed1Called) + XCTAssert(!completed2Called) + completed2Called = true + }) + + sleep(1) + + XCTAssert(next1Called) + XCTAssert(completed1Called) + XCTAssert(disposed1) + + XCTAssert(next2Called) + XCTAssert(completed2Called) + XCTAssert(disposed2) + } } From fd960fea04b85766ce454d10319af7a197de6457 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 18 Apr 2016 01:03:38 +0300 Subject: [PATCH 062/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 130 +++++++++++++++ SwiftSignalKit/Signal_Materialize.swift | 26 +++ SwiftSignalKit/Signal_Meta.swift | 213 ++++++++---------------- 3 files changed, 229 insertions(+), 140 deletions(-) create mode 100644 SwiftSignalKit/Signal_Materialize.swift diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index ae6e1df8a7..c2e27aa25b 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -93,6 +93,7 @@ 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 */; }; + 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 */ @@ -208,6 +209,7 @@ 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 = ""; }; + 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 */ @@ -265,6 +267,7 @@ 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 */, @@ -627,6 +630,7 @@ 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 */, @@ -724,6 +728,7 @@ 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", @@ -749,6 +754,7 @@ 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"; @@ -970,6 +976,125 @@ }; 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_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 = { + 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)"; + 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 = { + 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)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + 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)"; + }; + name = Hockeyapp; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -978,6 +1103,7 @@ buildConfigurations = ( D0085B361B282B9800EAF753 /* Debug */, D0085B371B282B9800EAF753 /* Release */, + D086A5771CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -987,6 +1113,7 @@ buildConfigurations = ( D0085B391B282B9800EAF753 /* Debug */, D0085B3A1B282B9800EAF753 /* Release */, + D086A5781CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -996,6 +1123,7 @@ buildConfigurations = ( D0445DEC1A7C2CA500267924 /* Debug */, D0445DED1A7C2CA500267924 /* Release */, + D086A5741CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -1005,6 +1133,7 @@ buildConfigurations = ( D0445DEF1A7C2CA500267924 /* Debug */, D0445DF01A7C2CA500267924 /* Release */, + D086A5751CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -1014,6 +1143,7 @@ buildConfigurations = ( D0445DF21A7C2CA500267924 /* Debug */, D0445DF31A7C2CA500267924 /* Release */, + D086A5761CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/SwiftSignalKit/Signal_Materialize.swift b/SwiftSignalKit/Signal_Materialize.swift new file mode 100644 index 0000000000..63a6196b0d --- /dev/null +++ b/SwiftSignalKit/Signal_Materialize.swift @@ -0,0 +1,26 @@ +import Foundation + +public enum SignalEvent { + case Next(T) + case Error(E) + case Completion +} + +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_Meta.swift b/SwiftSignalKit/Signal_Meta.swift index b29288c4da..46620ea117 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -11,10 +11,12 @@ 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) { @@ -25,6 +27,9 @@ private final class SignalQueueState : Disposable { 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 @@ -108,7 +113,7 @@ private final class SignalQueueState : Disposable { 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 @@ -122,7 +127,7 @@ public func switchToLatest(signal: Signal, E>) -> Signal(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,33 +139,79 @@ 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: T -> Signal) -> (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() + }) + } |> switchToLatest + } +} + +public func mapToSignalPromotingError(f: T -> Signal) -> (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: T -> Signal) -> (signal: Signal) -> Signal { + return { signal -> Signal in + return signal |> map { f($0) } |> queue + } +} + +public func mapToThrottled(f: T -> Signal) -> (signal: Signal) -> Signal { + return { signal -> Signal in + return signal |> map { f($0) } |> throttled + } +} + +public func then(nextSignal: Signal) -> (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 + + return disposable + } } } @@ -175,121 +226,3 @@ public func `defer`(generator: () -> Signal) -> Signal { }) } } - -public class SignalQueue { - private let lock = Lock() - - private var queuedSignals = Bag<() -> Disposable>() - private var currentIndex: Bag<() -> Disposable>.Index? - private var currentDisposable = MetaDisposable() - - public init() { - - } - - deinit { - self.currentDisposable.dispose() - } - - public func enqueued(signal: Signal) -> Signal { - return Signal { subscriber in - let disposable = MetaDisposable() - - let activate = { () -> Disposable in - disposable.set(signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - })) - return disposable - } - - var dequeue = false - var index: Bag>.Index! - self.lock.locked { - dequeue = self.queuedSignals.isEmpty - index = self.queuedSignals.add(activate) - } - - if dequeue { - self.dequeue() - } - - return ActionDisposable { - var dequeue = false - self.lock.locked { - self.queuedSignals.remove(index) - if let currentIndex = self.currentIndex where currentIndex == index { - self.currentDisposable.set(nil) - dequeue = true - } - } - if dequeue { - self.dequeue() - } - } - } - } - - private func dequeue() { - var activate: (() -> Disposable)? - self.lock.locked { - if let (index, value) = self.queuedSignals.first { - activate = value - self.currentIndex = index - } - } - - if let activate = activate { - self.currentDisposable.set(activate()) - } - } -} - -/*@interface SSignalQueue () { - SPipe *_pipe; - id _disposable; -} - -@end - -@implementation SSignalQueue - -- (instancetype)init { - self = [super init]; - if (self != nil) { - _pipe = [[SPipe alloc] init]; - _disposable = [[_pipe.signalProducer() queue] startWithNext:nil]; - } - return self; -} - -- (void)dealloc { - [_disposable dispose]; - } - - - (SSignal *)enqueue:(SSignal *)signal { - return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { - SPipe *disposePipe = [[SPipe alloc] init]; - - SSignal *proxy = [[[[signal onNext:^(id next) { - [subscriber putNext:next]; - }] onError:^(id error) { - [subscriber putError:error]; - }] onCompletion:^{ - [subscriber putCompletion]; - }] catch:^SSignal *(__unused id error) { - return [SSignal complete]; - }]; - - _pipe.sink([proxy takeUntilReplacement:disposePipe.signalProducer()]); - - return [[SBlockDisposable alloc] initWithBlock:^{ - disposePipe.sink([SSignal complete]); - }]; - }]; -} - -@end*/ From 3550e0101025ff13285d3aed44778da559bf875a Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 30 May 2016 18:16:04 +0300 Subject: [PATCH 063/122] no message --- SSignalKit/SSignal+Catch.h | 1 + SSignalKit/SSignal+Catch.m | 53 ++++++++++++++++++++++++++ SSignalKitTests/SSignalBasicTests.m | 59 +++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) 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/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 From 9d80df492df84a291070ba49cdc3ab8db90903ef Mon Sep 17 00:00:00 2001 From: Peter Date: Sun, 5 Jun 2016 00:30:47 +0300 Subject: [PATCH 064/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 4 + SwiftSignalKit/Disposable.swift | 25 ++-- SwiftSignalKit/Queue.swift | 33 +++++ SwiftSignalKit/Signal_Dispatch.swift | 42 +++--- SwiftSignalKit/Signal_Materialize.swift | 16 ++- SwiftSignalKit/Subscriber.swift | 8 +- SwiftSignalKitTests/PerformanceTests.swift | 114 ++++++++++++++++ .../SwiftSignalKitBasicTests.swift | 125 ------------------ 8 files changed, 206 insertions(+), 161 deletions(-) create mode 100644 SwiftSignalKitTests/PerformanceTests.swift diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index c2e27aa25b..be4f159158 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -83,6 +83,7 @@ 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 */; }; @@ -195,6 +196,7 @@ 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; }; @@ -295,6 +297,7 @@ D0085B631B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift */, D0085B641B282C2800EAF753 /* DeallocatingObject.swift */, D0085B651B282C2800EAF753 /* SwiftSignalKitBasicTests.swift */, + D02720B01CD0E005006F1506 /* PerformanceTests.swift */, D0085B311B282B9800EAF753 /* Supporting Files */, ); path = SwiftSignalKitTests; @@ -656,6 +659,7 @@ files = ( D0085B671B282C2800EAF753 /* DeallocatingObject.swift in Sources */, D0085B681B282C2800EAF753 /* SwiftSignalKitBasicTests.swift in Sources */, + D02720B11CD0E005006F1506 /* PerformanceTests.swift in Sources */, D0085B661B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift index 2efd074979..cb8253609f 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -1,38 +1,33 @@ 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) { 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 -{ +public final class MetaDisposable : Disposable { private var lock: OSSpinLock = 0 private var disposed = false private var disposable: Disposable! = nil diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 18ad9db064..4c43ca3ab5 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -51,6 +51,17 @@ public final class Queue { self.specific = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()) dispatch_queue_set_specific(self.nativeQueue, QueueSpecificKey, self.specific, nil) + dispatch_set_target_queue(self.nativeQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) + } + + func isCurrent() -> Bool { + if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { + return true + } else if self.specialIsMainQueue && NSThread.isMainThread() { + return true + } else { + return false + } } public func async(f: Void -> Void) { @@ -83,6 +94,28 @@ public final class Queue { } } + public func justDispatch(f: Void -> Void) { + dispatch_async(self.nativeQueue, f) + } + + public func dispatchWithHighQoS(f: () -> Void) { + let block = dispatch_block_create_with_qos_class(DISPATCH_BLOCK_ENFORCE_QOS_CLASS, QOS_CLASS_USER_INTERACTIVE, 0, { + f() + }) + dispatch_async(self.nativeQueue, block) + } + + public func dispatchTiming(f: Void -> Void, _ file: String = #file, _ line: Int = #line) { + self.justDispatch { + let startTime = CFAbsoluteTimeGetCurrent() + f() + let delta = CFAbsoluteTimeGetCurrent() - startTime + if delta > 0.002 { + print("dispatchTiming \(delta * 1000.0) ms \(file):\(line)") + } + } + } + public func after(delay: Double, _ f: Void -> Void) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), self.queue, f) } diff --git a/SwiftSignalKit/Signal_Dispatch.swift b/SwiftSignalKit/Signal_Dispatch.swift index 5cf6f51e6f..bde55c13c2 100644 --- a/SwiftSignalKit/Signal_Dispatch.swift +++ b/SwiftSignalKit/Signal_Dispatch.swift @@ -49,28 +49,38 @@ public func deliverOn(threadPool: ThreadPool)(signal: Signal) -> Sig public func runOn(queue: Queue)(signal: Signal) -> Signal { return Signal { subscriber in - var cancelled = false - let disposable = MetaDisposable() - - disposable.set(ActionDisposable { - cancelled = true - }) - - queue.dispatch { - if cancelled { - return - } - - disposable.set(signal.start(next: { next 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.dispatch { + if cancelled { + return + } + + disposable.set(signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + } + + return disposable } - - return disposable } } diff --git a/SwiftSignalKit/Signal_Materialize.swift b/SwiftSignalKit/Signal_Materialize.swift index 63a6196b0d..92e7a9b3c9 100644 --- a/SwiftSignalKit/Signal_Materialize.swift +++ b/SwiftSignalKit/Signal_Materialize.swift @@ -6,7 +6,21 @@ public enum SignalEvent { case Completion } -public func materialize(signal: Signal, NoError>) -> Signal { +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 { diff --git a/SwiftSignalKit/Subscriber.swift b/SwiftSignalKit/Subscriber.swift index 2b74e2f57c..90a918feb4 100644 --- a/SwiftSignalKit/Subscriber.swift +++ b/SwiftSignalKit/Subscriber.swift @@ -51,7 +51,7 @@ public final class Subscriber { var shouldDispose = false var action: (E -> Void)! = nil - OSSpinLockLock(&self.lock); + OSSpinLockLock(&self.lock) if !self.terminated { action = self.error shouldDispose = true; @@ -60,7 +60,7 @@ public final class Subscriber { self.completed = nil; self.terminated = true } - OSSpinLockUnlock(&self.lock); + OSSpinLockUnlock(&self.lock) if action != nil { action(error) @@ -77,7 +77,7 @@ public final class Subscriber { var shouldDispose = false var action: (() -> Void)! = nil - OSSpinLockLock(&self.lock); + OSSpinLockLock(&self.lock) if !self.terminated { action = self.completed shouldDispose = true; @@ -86,7 +86,7 @@ public final class Subscriber { self.completed = nil; self.terminated = true } - OSSpinLockUnlock(&self.lock); + OSSpinLockUnlock(&self.lock) if action != nil { action() diff --git a/SwiftSignalKitTests/PerformanceTests.swift b/SwiftSignalKitTests/PerformanceTests.swift new file mode 100644 index 0000000000..786afa0f04 --- /dev/null +++ b/SwiftSignalKitTests/PerformanceTests.swift @@ -0,0 +1,114 @@ +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() { + measureBlock { + for _ in 0 ..< 1000000 { + let disposable = DisposableLock(action: {}) + disposable.dispose() + } + } + } + + func testMeasureSpinlock() { + measureBlock { + for _ in 0 ..< 1000000 { + let disposable = DisposableSpinLock(action: {}) + disposable.dispose() + } + } + } + + func testMeasureAtomic() { + measureBlock { + for _ in 0 ..< 1000000 { + let disposable = DisposableAtomic(action: {}) + disposable.dispose() + } + } + } +} \ No newline at end of file diff --git a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift index 6138f0a258..91ed5ac9fa 100644 --- a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift +++ b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift @@ -256,129 +256,4 @@ class SwiftSignalKitTests: XCTestCase { XCTAssertTrue(deallocated2, "deallocated2 != true") XCTAssertTrue(disposed2, "disposed2 != true") } - - func testSignalQueue1() { - let queue = SignalQueue() - - var disposed1 = false - let queued1 = queue.enqueued(Signal { subscriber in - subscriber.putNext(1) - subscriber.putCompletion() - - return ActionDisposable { - disposed1 = true - } - }) - - var disposed2 = false - let queued2 = queue.enqueued(Signal { subscriber in - subscriber.putNext(2) - subscriber.putCompletion() - - return ActionDisposable { - disposed2 = true - } - }) - - var next1Called = false - var completed1Called = false - queued1.start(next: { next in - XCTAssert(!next1Called) - next1Called = true - XCTAssert(next == 1) - }, error: { _ in - XCTFail() - }, completed: { - XCTAssert(!completed1Called) - completed1Called = true - }) - - var next2Called = false - var completed2Called = false - queued2.start(next: { next in - XCTAssert(!next2Called) - next2Called = true - XCTAssert(next == 2) - }, error: { _ in - XCTFail() - }, completed: { - XCTAssert(!completed2Called) - completed2Called = true - }) - - XCTAssert(next1Called) - XCTAssert(completed1Called) - XCTAssert(disposed1) - - XCTAssert(next2Called) - XCTAssert(completed2Called) - XCTAssert(disposed2) - } - - func testSignalQueue2() { - let q = Queue() - let queue = SignalQueue() - - var disposed1 = false - let queued1 = queue.enqueued(Signal { subscriber in - q.after(0.4, { - subscriber.putNext(1) - subscriber.putCompletion() - }) - - return ActionDisposable { - disposed1 = true - } - }) - - var disposed2 = false - let queued2 = queue.enqueued(Signal { subscriber in - q.after(0.2, { - subscriber.putNext(2) - subscriber.putCompletion() - }) - - return ActionDisposable { - disposed2 = true - } - }) - - var next1Called = false - var completed1Called = false - queued1.start(next: { next in - XCTAssert(!next1Called) - next1Called = true - XCTAssert(next == 1) - }, error: { _ in - XCTFail() - }, completed: { - XCTAssert(!completed1Called) - completed1Called = true - }) - - var next2Called = false - var completed2Called = false - queued2.start(next: { next in - XCTAssert(next1Called) - XCTAssert(!next2Called) - next2Called = true - XCTAssert(next == 2) - }, error: { _ in - XCTFail() - }, completed: { - XCTAssert(completed1Called) - XCTAssert(!completed2Called) - completed2Called = true - }) - - sleep(1) - - XCTAssert(next1Called) - XCTAssert(completed1Called) - XCTAssert(disposed1) - - XCTAssert(next2Called) - XCTAssert(completed2Called) - XCTAssert(disposed2) - } } From 3cd09dd036477ddb035ddbebd6c4399f738bfc55 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 14 Jun 2016 18:12:48 +0300 Subject: [PATCH 065/122] no message --- SwiftSignalKit/Signal_SideEffects.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/SwiftSignalKit/Signal_SideEffects.swift b/SwiftSignalKit/Signal_SideEffects.swift index f791496e2d..1661794e60 100644 --- a/SwiftSignalKit/Signal_SideEffects.swift +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -26,6 +26,19 @@ public func afterNext(f: T -> R)(signal: Signal) -> Signal } } +public func beforeStarted(f: () -> Void)(signal: Signal) -> Signal { + return Signal { subscriber in + f() + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } +} + public func beforeCompleted(f: () -> Void)(signal: Signal) -> Signal { return Signal { subscriber in return signal.start(next: { next in From 586d105aadac082a27fc4c2b0dc66c214a3e8580 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 17 Jun 2016 01:00:07 +0300 Subject: [PATCH 066/122] no message --- SwiftSignalKit/Signal_SideEffects.swift | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/SwiftSignalKit/Signal_SideEffects.swift b/SwiftSignalKit/Signal_SideEffects.swift index 1661794e60..7755585e92 100644 --- a/SwiftSignalKit/Signal_SideEffects.swift +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -81,4 +81,24 @@ public func afterDisposed(f: Void -> R)(signal: Signal) -> Signal return disposable } -} \ No newline at end of file +} + +public func withState(signal: Signal, _ initialState: () -> S, next: (T, S) -> Void = { _ in }, error: (E, S) -> Void = { _ in }, completed: (S) -> Void = { _ in }, disposed: (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) + } + } +} From bb9062c684f97ffcde7bf910889877a4fb1ce8a1 Mon Sep 17 00:00:00 2001 From: Peter Date: Sun, 19 Jun 2016 15:19:00 +0300 Subject: [PATCH 067/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 14 +- SwiftSignalKit/Atomic.swift | 6 +- SwiftSignalKit/Bag.swift | 10 +- SwiftSignalKit/Disposable.swift | 4 +- SwiftSignalKit/Lock.swift | 2 +- SwiftSignalKit/Multicast.swift | 14 +- SwiftSignalKit/Promise.swift | 4 +- SwiftSignalKit/Queue.swift | 90 +++------ SwiftSignalKit/Signal.swift | 12 +- SwiftSignalKit/Signal_Catch.swift | 164 ++++++++-------- SwiftSignalKit/Signal_Combine.swift | 18 +- SwiftSignalKit/Signal_Dispatch.swift | 183 +++++++++--------- SwiftSignalKit/Signal_Mapping.swift | 70 ++++--- SwiftSignalKit/Signal_Meta.swift | 24 +-- SwiftSignalKit/Signal_Reduce.swift | 86 ++++---- SwiftSignalKit/Signal_SideEffects.swift | 148 +++++++------- SwiftSignalKit/Signal_Single.swift | 8 +- SwiftSignalKit/Signal_Take.swift | 48 ++--- SwiftSignalKit/Signal_Timing.swift | 90 +++++---- SwiftSignalKit/Subscriber.swift | 20 +- SwiftSignalKit/ThreadPool.swift | 32 +-- SwiftSignalKit/Timer.swift | 29 ++- .../{Pipe.swift => ValuePipe.swift} | 9 +- SwiftSignalKitTests/DeallocatingObject.swift | 2 +- SwiftSignalKitTests/PerformanceTests.swift | 8 +- .../SwiftSignalKitBasicTests.swift | 64 +++--- .../SwiftSignalKitFunctionsTests.swift | 134 +++++++------ 27 files changed, 653 insertions(+), 640 deletions(-) rename SwiftSignalKit/{Pipe.swift => ValuePipe.swift} (81%) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index be4f159158..70cd35c0cb 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 */; }; @@ -180,7 +180,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 = ""; }; @@ -259,7 +259,7 @@ 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 */, @@ -553,7 +553,7 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0710; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Telegram; TargetAttributes = { D0085B211B282B9800EAF753 = { @@ -627,7 +627,7 @@ 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 */, @@ -807,6 +807,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_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -835,6 +836,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", @@ -881,6 +883,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; @@ -1004,6 +1007,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; diff --git a/SwiftSignalKit/Atomic.swift b/SwiftSignalKit/Atomic.swift index ae7dd94ab4..402816c894 100644 --- a/SwiftSignalKit/Atomic.swift +++ b/SwiftSignalKit/Atomic.swift @@ -8,7 +8,7 @@ public final class Atomic { self.value = value } - public func with(f: T -> R) -> R { + public func with(_ f: (T) -> R) -> R { OSSpinLockLock(&self.lock) let result = f(self.value) OSSpinLockUnlock(&self.lock) @@ -16,7 +16,7 @@ public final class Atomic { return result } - public func modify(f: T -> T) -> T { + public func modify(_ f: (T) -> T) -> T { OSSpinLockLock(&self.lock) let result = f(self.value) self.value = result @@ -25,7 +25,7 @@ public final class Atomic { return result } - public func swap(value: T) -> T { + public func swap(_ value: T) -> T { OSSpinLockLock(&self.lock) let previous = self.value self.value = value diff --git a/SwiftSignalKit/Bag.swift b/SwiftSignalKit/Bag.swift index 1240fd1057..d154372dee 100644 --- a/SwiftSignalKit/Bag.swift +++ b/SwiftSignalKit/Bag.swift @@ -9,7 +9,7 @@ public final class Bag { public init() { } - public func add(item: T) -> Index { + public func add(_ item: T) -> Index { let key = self.nextIndex self.nextIndex += 1 self.items.append(item) @@ -18,7 +18,7 @@ public final class Bag { return key } - public func get(index: Index) -> T? { + public func get(_ index: Index) -> T? { var i = 0 for key in self.itemKeys { if key == index { @@ -29,12 +29,12 @@ public final class Bag { return nil } - public func remove(index: Index) { + public func remove(_ index: Index) { var i = 0 for key in self.itemKeys { if key == index { - self.items.removeAtIndex(i) - self.itemKeys.removeAtIndex(i) + self.items.remove(at: i) + self.itemKeys.remove(at: i) break } i += 1 diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift index cb8253609f..9d4570285c 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -35,7 +35,7 @@ public final class MetaDisposable : Disposable { public init() { } - public func set(disposable: Disposable?) { + public func set(_ disposable: Disposable?) { var previousDisposable: Disposable! = nil var disposeImmediately = false @@ -89,7 +89,7 @@ public final class DisposableSet : Disposable { } - public func add(disposable: Disposable) { + public func add(_ disposable: Disposable) { var disposeImmediately = false OSSpinLockLock(&self.lock) diff --git a/SwiftSignalKit/Lock.swift b/SwiftSignalKit/Lock.swift index 8e61f3ba96..8eb15a90f9 100644 --- a/SwiftSignalKit/Lock.swift +++ b/SwiftSignalKit/Lock.swift @@ -11,7 +11,7 @@ public final class Lock { pthread_mutex_destroy(&self.mutex) } - public func locked(@noescape f: () -> ()) { + public func locked(_ f: @noescape() -> ()) { pthread_mutex_lock(&self.mutex) f() pthread_mutex_unlock(&self.mutex) diff --git a/SwiftSignalKit/Multicast.swift b/SwiftSignalKit/Multicast.swift index e19025e363..b1ddec5a3c 100644 --- a/SwiftSignalKit/Multicast.swift +++ b/SwiftSignalKit/Multicast.swift @@ -2,7 +2,7 @@ import Foundation private final class MulticastInstance { let disposable: Disposable - var subscribers = Bag Void>() + var subscribers = Bag<(T) -> Void>() var lock = Lock() init(disposable: Disposable) { @@ -31,7 +31,7 @@ public final class Multicast { } } - var index: Bag Void>.Index! + var index: Bag<(T) -> Void>.Index! instance.lock.locked { index = instance.subscribers.add({ next in subscriber.putNext(next) @@ -40,7 +40,7 @@ public final class Multicast { if let beginDisposable = beginDisposable { beginDisposable.set(signal.start(next: { next in - var subscribers: [T -> Void]! + var subscribers: [(T) -> Void]! instance.lock.locked { subscribers = instance.subscribers.copyItems() } @@ -49,11 +49,11 @@ public final class Multicast { } }, error: { _ in self.lock.locked { - self.instances.removeValueForKey(key) + let _ = self.instances.removeValue(forKey: key) } }, completed: { self.lock.locked { - self.instances.removeValueForKey(key) + self.instances.removeValue(forKey: key) } })) } @@ -69,7 +69,7 @@ public final class Multicast { if remove { self.lock.locked { - self.instances.removeValueForKey(key) + let _ = self.instances.removeValue(forKey: key) } } } @@ -78,7 +78,7 @@ public final class Multicast { } public final class MulticastPromise { - public let subscribers = Bag Void>() + public let subscribers = Bag<(T) -> Void>() public let lock = Lock() public var value: T? diff --git a/SwiftSignalKit/Promise.swift b/SwiftSignalKit/Promise.swift index 00e96b9649..3db0dc86a2 100644 --- a/SwiftSignalKit/Promise.swift +++ b/SwiftSignalKit/Promise.swift @@ -4,7 +4,7 @@ public class Promise { private var value: T? private var lock: OSSpinLock = 0 private let disposable = MetaDisposable() - private let subscribers = Bag Void>() + private let subscribers = Bag<(T) -> Void>() public init(_ value: T) { self.value = value @@ -17,7 +17,7 @@ public class Promise { self.disposable.dispose() } - public func set(signal: Signal) { + public func set(_ signal: Signal) { OSSpinLockLock(&self.lock) self.value = nil OSSpinLockUnlock(&self.lock) diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 4c43ca3ab5..cf7e3573af 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -1,16 +1,15 @@ 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) 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,102 +20,63 @@ public final class Queue { } public class func concurrentDefaultQueue() -> Queue { - return Queue(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), specialIsMainQueue: false) + return Queue(queue: DispatchQueue.global(attributes: [.qosDefault]), specialIsMainQueue: false) } public class func concurrentBackgroundQueue() -> Queue { - return Queue(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), specialIsMainQueue: false) + return Queue(queue: DispatchQueue.global(attributes: [.qosBackground]), specialIsMainQueue: false) } - 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) { + private 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 ?? "", attributes: [.serial], target: nil) + self.specialIsMainQueue = false - self.specific = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()) - dispatch_queue_set_specific(self.nativeQueue, QueueSpecificKey, self.specific, nil) - dispatch_set_target_queue(self.nativeQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) + self.nativeQueue.setSpecific(key: QueueSpecificKey, value: self.specific) } func isCurrent() -> Bool { - if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { + if DispatchQueue.getSpecific(key: QueueSpecificKey) === self.specific { return true - } else if self.specialIsMainQueue && NSThread.isMainThread() { + } else if self.specialIsMainQueue && Thread.isMainThread() { return true } else { return false } } - public func async(f: Void -> Void) { - if self.specific != nil && dispatch_get_specific(QueueSpecificKey) == self.specific { - f() - } else if self.specialIsMainQueue && NSThread.isMainThread() { + public func async(_ f: (Void) -> Void) { + if self.isCurrent() { f() } else { - dispatch_async(self.nativeQueue, f) + self.nativeQueue.async(execute: f) } } - 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 sync(_ f: (Void) -> Void) { + if self.isCurrent() { f() } else { - dispatch_sync(self.nativeQueue, f) + self.nativeQueue.sync(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() { - f() - } else { - dispatch_async(self.nativeQueue, f) - } + public func justDispatch(_ f: (Void) -> Void) { + self.nativeQueue.async(execute: f) } - public func justDispatch(f: Void -> Void) { - dispatch_async(self.nativeQueue, f) - } - - public func dispatchWithHighQoS(f: () -> Void) { - let block = dispatch_block_create_with_qos_class(DISPATCH_BLOCK_ENFORCE_QOS_CLASS, QOS_CLASS_USER_INTERACTIVE, 0, { - f() - }) - dispatch_async(self.nativeQueue, block) - } - - public func dispatchTiming(f: Void -> Void, _ file: String = #file, _ line: Int = #line) { - self.justDispatch { - let startTime = CFAbsoluteTimeGetCurrent() - f() - let delta = CFAbsoluteTimeGetCurrent() - startTime - if delta > 0.002 { - print("dispatchTiming \(delta * 1000.0) ms \(file):\(line)") - } - } - } - - public func after(delay: Double, _ f: Void -> Void) { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), self.queue, f) + public func after(_ delay: Double, _ f: (Void) -> Void) { + let time: DispatchTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) + self.nativeQueue.after(when: time, execute: f) } } diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index c296627a18..ae0830ffe6 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -10,7 +10,7 @@ public func identity(a: A) -> A { infix operator |> { associativity left precedence 95 } -public func |> (value: T, function: (T -> U)) -> U { +public func |> (value: T, function: ((T) -> U)) -> U { return function(value) } @@ -30,20 +30,20 @@ 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: (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 { + public static func single(_ value: T) -> Signal { return Signal { subscriber in subscriber.putNext(value) subscriber.putCompletion() @@ -60,7 +60,7 @@ public struct Signal { } } - public static func fail(error: E) -> Signal { + public static func fail(_ error: E) -> Signal { return Signal { subscriber in subscriber.putError(error) diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index ecc7ac0c77..8ee7d92e3f 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: (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: ((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.after(when: 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 04bd40cc13..50f58fa847 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: ([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,31 +82,31 @@ 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> { +public func combineLatest(_ signals: [Signal]) -> Signal<[T], E> { if signals.count == 0 { return single([T](), E.self) } diff --git a/SwiftSignalKit/Signal_Dispatch.swift b/SwiftSignalKit/Signal_Dispatch.swift index bde55c13c2..c5ed6daaaa 100644 --- a/SwiftSignalKit/Signal_Dispatch.swift +++ b/SwiftSignalKit/Signal_Dispatch.swift @@ -1,72 +1,103 @@ 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(queue: Queue)(signal: Signal) -> Signal { - return Signal { subscriber in - if queue.isCurrent() { +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 - subscriber.putNext(next) + queue.addTask(ThreadPoolTask { state in + if !state.cancelled { + subscriber.putNext(next) + } + }) }, error: { error in - subscriber.putError(error) + queue.addTask(ThreadPoolTask { state in + if !state.cancelled { + subscriber.putError(error) + } + }) }, completed: { - subscriber.putCompletion() + queue.addTask(ThreadPoolTask { state in + if !state.cancelled { + subscriber.putCompletion() + } + }) }) - } else { - var cancelled = false + } + } +} + +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() - disposable.set(ActionDisposable { - cancelled = true - }) - - queue.dispatch { - if cancelled { + let task = ThreadPoolTask { state in + if cancelled || state.cancelled { return } @@ -79,51 +110,13 @@ public func runOn(queue: Queue)(signal: Signal) -> Signal { })) } + disposable.set(ActionDisposable { + task.cancel() + }) + + threadPool.addTask(task) + return disposable } } } - -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 - } - - 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 - } -} - -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 303c7f7856..addea7a6a1 100644 --- a/SwiftSignalKit/Signal_Mapping.swift +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -1,40 +1,46 @@ 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: (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 - return signal.start(next: { next in - if f(next) { +public func filter(_ f: (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: (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(error) - }, completed: { - subscriber.putCompletion() - }) - } -} - -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() - }) + }, error: { error in + subscriber.putError(f(error)) + }, completed: { + subscriber.putCompletion() + }) + } } } @@ -42,7 +48,7 @@ private class DistinctUntilChangedContext { var value: T? } -public func distinctUntilChanged(signal: Signal) -> Signal { +public func distinctUntilChanged(_ signal: Signal) -> Signal { return Signal { subscriber in let context = Atomic(value: DistinctUntilChangedContext()) diff --git a/SwiftSignalKit/Signal_Meta.swift b/SwiftSignalKit/Signal_Meta.swift index 46620ea117..7bbc50b3e3 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -19,11 +19,11 @@ private final class SignalQueueState : Disposable { 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 { @@ -61,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 @@ -111,7 +111,7 @@ 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, throttleMode: false) state.beginWithDisposable(signal.start(next: { next in @@ -125,7 +125,7 @@ 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, throttleMode: false) state.beginWithDisposable(signal.start(next: { next in @@ -139,7 +139,7 @@ public func queue(signal: Signal, E>) -> Signal { } } -public func throttled(signal: Signal, E>) -> Signal { +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 @@ -153,7 +153,7 @@ public func throttled(signal: Signal, E>) -> Signal { } } -public func mapToSignal(f: T -> Signal) -> (signal: Signal) -> Signal { +public func mapToSignal(_ f: (T) -> Signal) -> (Signal) -> Signal { return { signal -> Signal in return Signal, E> { subscriber in return signal.start(next: { next in @@ -167,7 +167,7 @@ public func mapToSignal(f: T -> Signal) -> (signal: Signal) } } -public func mapToSignalPromotingError(f: T -> Signal) -> (signal: Signal) -> Signal { +public func mapToSignalPromotingError(_ f: (T) -> Signal) -> (Signal) -> Signal { return { signal -> Signal in return Signal, E> { subscriber in return signal.start(next: { next in @@ -179,19 +179,19 @@ public func mapToSignalPromotingError(f: T -> Signal) -> (signal: } } -public func mapToQueue(f: T -> Signal) -> (signal: Signal) -> Signal { +public func mapToQueue(_ f: (T) -> Signal) -> (Signal) -> Signal { return { signal -> Signal in return signal |> map { f($0) } |> queue } } -public func mapToThrottled(f: T -> Signal) -> (signal: Signal) -> Signal { +public func mapToThrottled(_ f: (T) -> Signal) -> (Signal) -> Signal { return { signal -> Signal in return signal |> map { f($0) } |> throttled } } -public func then(nextSignal: Signal) -> (signal: Signal) -> Signal { +public func then(_ nextSignal: Signal) -> (Signal) -> Signal { return { signal -> Signal in return Signal { subscriber in let disposable = DisposableSet() @@ -215,7 +215,7 @@ public func then(nextSignal: Signal) -> (signal: Signal) -> Si } } -public func `defer`(generator: () -> Signal) -> Signal { +public func deferred(_ generator: () -> 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..e42341db1c 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: (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: (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() + }) + } } } @@ -57,11 +61,11 @@ private final class ReduceQueueState : Disposable { 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: (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 7755585e92..a50885e374 100644 --- a/SwiftSignalKit/Signal_SideEffects.swift +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -1,89 +1,101 @@ 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: (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: (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 beforeStarted(f: () -> Void)(signal: Signal) -> Signal { - return Signal { subscriber in - f() - return signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - subscriber.putError(error) - }, completed: { - subscriber.putCompletion() - }) - } -} - -public func beforeCompleted(f: () -> Void)(signal: Signal) -> Signal { - return Signal { subscriber in - return signal.start(next: { next in - subscriber.putNext(next) - }, error: { error in - subscriber.putError(error) - }, completed: { +public func beforeStarted(_ f: () -> Void) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in f() - subscriber.putCompletion() - }) + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } } } -public func afterCompleted(f: () -> Void)(signal: Signal) -> Signal { - 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 beforeCompleted(_ f: () -> 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 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 afterCompleted(_ f: () -> 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 withState(signal: Signal, _ initialState: () -> S, next: (T, S) -> Void = { _ in }, error: (E, S) -> Void = { _ in }, completed: (S) -> Void = { _ in }, disposed: (S) -> Void = { _ in }) -> Signal { +public func afterDisposed(_ f: (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: () -> S, next: (T, S) -> Void = { _ in }, error: (E, S) -> Void = { _ in }, completed: (S) -> Void = { _ in }, disposed: (S) -> Void = { _ in }) -> Signal { return Signal { subscriber in let state = initialState() let disposable = signal.start(next: { vNext in 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..818d702c2a 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 90a918feb4..4c2dfefc83 100644 --- a/SwiftSignalKit/Subscriber.swift +++ b/SwiftSignalKit/Subscriber.swift @@ -1,21 +1,21 @@ 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 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 } - internal func assignDisposable(disposable: Disposable) { + internal func assignDisposable(_ disposable: Disposable) { if self.terminated { disposable.dispose() } else { @@ -34,8 +34,8 @@ public final class Subscriber { OSSpinLockUnlock(&self.lock) } - public func putNext(next: T) { - var action: (T -> Void)! = nil + public func putNext(_ next: T) { + var action: ((T) -> Void)! = nil OSSpinLockLock(&self.lock) if !self.terminated { action = self.next @@ -47,9 +47,9 @@ public final class Subscriber { } } - 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) if !self.terminated { @@ -67,7 +67,7 @@ public final class Subscriber { } if shouldDispose && self.disposable != nil { - let disposable = self.disposable + let disposable = self.disposable! disposable.dispose() self.disposable = nil } @@ -93,7 +93,7 @@ public final class Subscriber { } 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..5ab73fa364 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: (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) @@ -42,7 +42,7 @@ public final class ThreadPoolQueue : Equatable { private 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 @@ -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: () -> ()) { + private 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..83c00f0446 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: (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.timer(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/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 index 786afa0f04..aa325d5934 100644 --- a/SwiftSignalKitTests/PerformanceTests.swift +++ b/SwiftSignalKitTests/PerformanceTests.swift @@ -86,7 +86,7 @@ class PerformanceTests: XCTestCase { } func testMeasureLock() { - measureBlock { + measure { for _ in 0 ..< 1000000 { let disposable = DisposableLock(action: {}) disposable.dispose() @@ -95,7 +95,7 @@ class PerformanceTests: XCTestCase { } func testMeasureSpinlock() { - measureBlock { + measure { for _ in 0 ..< 1000000 { let disposable = DisposableSpinLock(action: {}) disposable.dispose() @@ -104,11 +104,11 @@ class PerformanceTests: XCTestCase { } func testMeasureAtomic() { - measureBlock { + measure { for _ in 0 ..< 1000000 { let disposable = DisposableAtomic(action: {}) disposable.dispose() } } } -} \ No newline at end of file +} 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) + } } From c1f7dadd0ba2d03f639fc2cbd853b6d907468aa0 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 6 Jul 2016 15:42:18 +0300 Subject: [PATCH 068/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 15 +++++++ SwiftSignalKitTests/PerformanceTests.swift | 52 ++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 70cd35c0cb..8863abc666 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -558,12 +558,14 @@ 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; @@ -727,6 +729,7 @@ D0085B361B282B9800EAF753 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -744,6 +747,7 @@ 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; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -752,6 +756,8 @@ D0085B371B282B9800EAF753 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; @@ -766,6 +772,7 @@ 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; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; @@ -916,6 +923,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; @@ -923,6 +931,7 @@ D0445DF01A7C2CA500267924 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -935,6 +944,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; @@ -1027,6 +1037,7 @@ D086A5751CC0117500F08284 /* Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1039,6 +1050,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 = Hockeyapp; @@ -1066,6 +1078,8 @@ D086A5771CC0117500F08284 /* Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; @@ -1080,6 +1094,7 @@ 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; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; diff --git a/SwiftSignalKitTests/PerformanceTests.swift b/SwiftSignalKitTests/PerformanceTests.swift index aa325d5934..041c3b8654 100644 --- a/SwiftSignalKitTests/PerformanceTests.swift +++ b/SwiftSignalKitTests/PerformanceTests.swift @@ -111,4 +111,56 @@ class PerformanceTests: XCTestCase { } } } + + 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)") + } } From cd0eb7f756110e01c0a5e0ae7a1d9dbf8ea0cff2 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 9 Aug 2016 00:23:25 +0300 Subject: [PATCH 069/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 6 ++++++ SwiftSignalKit/Atomic.swift | 4 ++-- SwiftSignalKit/Queue.swift | 14 +++++++------- SwiftSignalKit/Signal_Catch.swift | 2 +- SwiftSignalKit/ThreadPool.swift | 2 +- SwiftSignalKit/Timer.swift | 2 +- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 8863abc666..4e665b0747 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -750,6 +750,7 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -775,6 +776,7 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -796,6 +798,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; }; @@ -815,6 +818,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -1097,6 +1101,7 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Hockeyapp; }; @@ -1115,6 +1120,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 = Hockeyapp; }; diff --git a/SwiftSignalKit/Atomic.swift b/SwiftSignalKit/Atomic.swift index 402816c894..5ad59cbecc 100644 --- a/SwiftSignalKit/Atomic.swift +++ b/SwiftSignalKit/Atomic.swift @@ -8,7 +8,7 @@ public final class Atomic { self.value = value } - public func with(_ f: (T) -> R) -> R { + public func with(_ f: @noescape(T) -> R) -> R { OSSpinLockLock(&self.lock) let result = f(self.value) OSSpinLockUnlock(&self.lock) @@ -16,7 +16,7 @@ public final class Atomic { return result } - public func modify(_ f: (T) -> T) -> T { + public func modify(_ f: @noescape(T) -> T) -> T { OSSpinLockLock(&self.lock) let result = f(self.value) self.value = result diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index cf7e3573af..5648bcb373 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -20,11 +20,11 @@ public final class Queue { } public class func concurrentDefaultQueue() -> Queue { - return Queue(queue: DispatchQueue.global(attributes: [.qosDefault]), specialIsMainQueue: false) + return Queue(queue: DispatchQueue.global(qos: .default), specialIsMainQueue: false) } public class func concurrentBackgroundQueue() -> Queue { - return Queue(queue: DispatchQueue.global(attributes: [.qosBackground]), specialIsMainQueue: false) + return Queue(queue: DispatchQueue.global(qos: .background), specialIsMainQueue: false) } public init(queue: DispatchQueue) { @@ -38,17 +38,17 @@ public final class Queue { } public init(name: String? = nil) { - self.nativeQueue = DispatchQueue(label: name ?? "", attributes: [.serial], target: nil) + self.nativeQueue = DispatchQueue(label: name ?? "", qos: .default) self.specialIsMainQueue = false self.nativeQueue.setSpecific(key: QueueSpecificKey, value: self.specific) } - func isCurrent() -> Bool { + public func isCurrent() -> Bool { if DispatchQueue.getSpecific(key: QueueSpecificKey) === self.specific { return true - } else if self.specialIsMainQueue && Thread.isMainThread() { + } else if self.specialIsMainQueue && Thread.isMainThread { return true } else { return false @@ -63,7 +63,7 @@ public final class Queue { } } - public func sync(_ f: (Void) -> Void) { + public func sync(_ f: @noescape(Void) -> Void) { if self.isCurrent() { f() } else { @@ -77,6 +77,6 @@ public final class Queue { public func after(_ delay: Double, _ f: (Void) -> Void) { let time: DispatchTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) - self.nativeQueue.after(when: time, execute: f) + self.nativeQueue.asyncAfter(deadline: time, execute: f) } } diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index 8ee7d92e3f..d98563bddd 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -114,7 +114,7 @@ public func retry(_ delayIncrement: Double, maxDelay: Double, onQueue queu } let time: DispatchTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) - queue.queue.after(when: time, execute: { + queue.queue.asyncAfter(deadline: time, execute: { recurse() }) }, completed: { diff --git a/SwiftSignalKit/ThreadPool.swift b/SwiftSignalKit/ThreadPool.swift index 5ab73fa364..3922f76026 100644 --- a/SwiftSignalKit/ThreadPool.swift +++ b/SwiftSignalKit/ThreadPool.swift @@ -157,7 +157,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { } public func isCurrentThreadInPool() -> Bool { - let currentThread = Thread.current() + let currentThread = Thread.current for thread in self.threads { if currentThread.isEqual(thread) { return true diff --git a/SwiftSignalKit/Timer.swift b/SwiftSignalKit/Timer.swift index 83c00f0446..551c004aa1 100644 --- a/SwiftSignalKit/Timer.swift +++ b/SwiftSignalKit/Timer.swift @@ -19,7 +19,7 @@ public final class Timer { } public func start() { - let timer = DispatchSource.timer(queue: self.queue.queue) + let timer = DispatchSource.makeTimerSource(queue: self.queue.queue) timer.setEventHandler(handler: { [weak self] in if let strongSelf = self { strongSelf.completion() From 48b6f08a475bff26c75e542d3d5025a42ed3a6ca Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 16 Aug 2016 14:06:01 +0300 Subject: [PATCH 070/122] no message --- SwiftSignalKit/Queue.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 5648bcb373..f5496f7404 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -3,6 +3,8 @@ import Foundation private let QueueSpecificKey = DispatchSpecificKey() 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: DispatchQueue @@ -20,11 +22,11 @@ public final class Queue { } public class func concurrentDefaultQueue() -> Queue { - return Queue(queue: DispatchQueue.global(qos: .default), specialIsMainQueue: false) + return globalDefaultQueue } public class func concurrentBackgroundQueue() -> Queue { - return Queue(queue: DispatchQueue.global(qos: .background), specialIsMainQueue: false) + return globalBackgroundQueue } public init(queue: DispatchQueue) { From 7cad465acf6484982efd822bcb006f30b5ae8d9c Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 19 Aug 2016 16:19:48 +0300 Subject: [PATCH 071/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 4e665b0747..933d430c4e 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -914,6 +914,7 @@ D0445DEF1A7C2CA500267924 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -935,6 +936,7 @@ D0445DF01A7C2CA500267924 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1041,6 +1043,7 @@ D086A5751CC0117500F08284 /* Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; From 642cb9ae2f45b90a2a06bd24500d977bbf034633 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 23 Aug 2016 16:19:36 +0300 Subject: [PATCH 072/122] no message --- SwiftSignalKit/Disposable.swift | 2 +- SwiftSignalKit/Queue.swift | 10 +++++----- SwiftSignalKit/Signal.swift | 9 +++++++-- SwiftSignalKit/Signal_Catch.swift | 6 +++--- SwiftSignalKit/Signal_Combine.swift | 2 +- SwiftSignalKit/Signal_Mapping.swift | 8 ++++---- SwiftSignalKit/Signal_Meta.swift | 10 +++++----- SwiftSignalKit/Signal_Reduce.swift | 8 ++++---- SwiftSignalKit/Signal_SideEffects.swift | 14 +++++++------- SwiftSignalKit/Signal_Timing.swift | 2 +- SwiftSignalKit/ThreadPool.swift | 8 ++++---- SwiftSignalKit/Timer.swift | 2 +- 12 files changed, 43 insertions(+), 38 deletions(-) diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift index 9d4570285c..82bcd65f53 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -15,7 +15,7 @@ public final class ActionDisposable : Disposable { private var action: () -> Void private var lock: Int32 = 0 - public init(action: () -> Void) { + public init(action: @escaping() -> Void) { self.action = action } diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index f5496f7404..ac052d2ef3 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -34,7 +34,7 @@ public final class Queue { self.specialIsMainQueue = false } - private init(queue: DispatchQueue, specialIsMainQueue: Bool) { + fileprivate init(queue: DispatchQueue, specialIsMainQueue: Bool) { self.nativeQueue = queue self.specialIsMainQueue = specialIsMainQueue } @@ -57,7 +57,7 @@ public final class Queue { } } - public func async(_ f: (Void) -> Void) { + public func async(_ f: @escaping(Void) -> Void) { if self.isCurrent() { f() } else { @@ -65,7 +65,7 @@ public final class Queue { } } - public func sync(_ f: @noescape(Void) -> Void) { + public func sync(_ f: (Void) -> Void) { if self.isCurrent() { f() } else { @@ -73,11 +73,11 @@ public final class Queue { } } - public func justDispatch(_ f: (Void) -> Void) { + public func justDispatch(_ f: @escaping(Void) -> Void) { self.nativeQueue.async(execute: f) } - public func after(_ delay: Double, _ f: (Void) -> Void) { + public func after(_ delay: Double, _ f: @escaping(Void) -> Void) { let time: DispatchTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) self.nativeQueue.asyncAfter(deadline: time, execute: f) } diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index ae0830ffe6..ea59ccd763 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -8,7 +8,12 @@ public func identity(a: A) -> A { return a; } -infix operator |> { associativity left precedence 95 } +precedencegroup PipeRight { + associativity: left + higherThan: DefaultPrecedence +} + +infix operator |> : PipeRight public func |> (value: T, function: ((T) -> U)) -> U { return function(value) @@ -32,7 +37,7 @@ private final class SubscriberDisposable : Disposable { public struct Signal { private let generator: (Subscriber) -> Disposable - public init(_ generator: (Subscriber) -> Disposable) { + public init(_ generator: @escaping(Subscriber) -> Disposable) { self.generator = generator } diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index d98563bddd..b7b4a320a1 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -1,6 +1,6 @@ import Foundation -public func `catch`(_ f: (E) -> Signal) -> (Signal) -> Signal { +public func `catch`(_ f: @escaping(E) -> Signal) -> (Signal) -> Signal { return { signal in return Signal { subscriber in let disposable = DisposableSet() @@ -26,7 +26,7 @@ public func `catch`(_ f: (E) -> Signal) -> (Signal) -> Sign } } -private func recursiveFunction(_ f: ((Void) -> Void) -> Void) -> ((Void) -> Void) { +private func recursiveFunction(_ f: @escaping(@escaping(Void) -> Void) -> Void) -> ((Void) -> Void) { return { f(recursiveFunction(f)) } @@ -94,7 +94,7 @@ public func recurse(_ latestValue: T?) -> (Signal) -> Signal { } } -public func retry(_ delayIncrement: Double, maxDelay: Double, onQueue queue: Queue) -> (signal: Signal) -> Signal { +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) diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index 50f58fa847..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() diff --git a/SwiftSignalKit/Signal_Mapping.swift b/SwiftSignalKit/Signal_Mapping.swift index addea7a6a1..29c11607d0 100644 --- a/SwiftSignalKit/Signal_Mapping.swift +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -1,6 +1,6 @@ import Foundation -public func map(_ f: (T) -> R) -> (Signal) -> Signal { +public func map(_ f: @escaping(T) -> R) -> (Signal) -> Signal { return { signal in return Signal { subscriber in return signal.start(next: { next in @@ -14,7 +14,7 @@ public func map(_ f: (T) -> R) -> (Signal) -> Signal { } } -public func filter(_ f: (T) -> Bool) -> (Signal) -> Signal { +public func filter(_ f: @escaping(T) -> Bool) -> (Signal) -> Signal { return { signal in return Signal { subscriber in return signal.start(next: { next in @@ -30,7 +30,7 @@ public func filter(_ f: (T) -> Bool) -> (Signal) -> Signal { } } -public func mapError(_ f: (E) -> R) -> (Signal) -> Signal { +public func mapError(_ f: @escaping(E) -> R) -> (Signal) -> Signal { return { signal in return Signal { subscriber in return signal.start(next: { next in @@ -54,7 +54,7 @@ public func distinctUntilChanged(_ signal: Signal) -> Sig return signal.start(next: { next in let pass = context.with { context -> Bool in - if let value = context.value where value == next { + if let value = context.value, value == next { return false } else { context.value = next diff --git a/SwiftSignalKit/Signal_Meta.swift b/SwiftSignalKit/Signal_Meta.swift index 7bbc50b3e3..3534359b90 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -153,7 +153,7 @@ public func throttled(_ signal: Signal, E>) -> Signal { } } -public func mapToSignal(_ f: (T) -> Signal) -> (Signal) -> Signal { +public func mapToSignal(_ f: @escaping(T) -> Signal) -> (Signal) -> Signal { return { signal -> Signal in return Signal, E> { subscriber in return signal.start(next: { next in @@ -167,7 +167,7 @@ public func mapToSignal(_ f: (T) -> Signal) -> (Signal) -> } } -public func mapToSignalPromotingError(_ f: (T) -> Signal) -> (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 @@ -179,13 +179,13 @@ public func mapToSignalPromotingError(_ f: (T) -> Signal) -> (Sig } } -public func mapToQueue(_ f: (T) -> Signal) -> (Signal) -> Signal { +public func mapToQueue(_ f: @escaping(T) -> Signal) -> (Signal) -> Signal { return { signal -> Signal in return signal |> map { f($0) } |> queue } } -public func mapToThrottled(_ f: (T) -> Signal) -> (Signal) -> Signal { +public func mapToThrottled(_ f: @escaping(T) -> Signal) -> (Signal) -> Signal { return { signal -> Signal in return signal |> map { f($0) } |> throttled } @@ -215,7 +215,7 @@ public func then(_ nextSignal: Signal) -> (Signal) -> Signal(_ generator: () -> Signal) -> Signal { +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 e42341db1c..d42ad64f5b 100644 --- a/SwiftSignalKit/Signal_Reduce.swift +++ b/SwiftSignalKit/Signal_Reduce.swift @@ -1,6 +1,6 @@ import Foundation -public func reduceLeft(value: T, f: (T, T) -> T) -> (signal: Signal) -> Signal { +public func reduceLeft(value: T, f: @escaping(T, T) -> T) -> (_ signal: Signal) -> Signal { return { signal in return Signal { subscriber in var currentValue = value @@ -17,7 +17,7 @@ public func reduceLeft(value: T, f: (T, T) -> T) -> (signal: Signal) } } -public func reduceLeft(value: T, f: (T, T, (T) -> Void) -> T) -> (signal: Signal) -> Signal { +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 @@ -55,7 +55,7 @@ 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 @@ -172,7 +172,7 @@ private final class ReduceQueueState : Disposable { } } -public func reduceLeft(_ value: T, generator: (T, T) -> Signal<(T, Passthrough), E>) -> (signal: Signal) -> Signal { +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) diff --git a/SwiftSignalKit/Signal_SideEffects.swift b/SwiftSignalKit/Signal_SideEffects.swift index a50885e374..f3f480f6a2 100644 --- a/SwiftSignalKit/Signal_SideEffects.swift +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -1,6 +1,6 @@ import Foundation -public func beforeNext(_ f: (T) -> R) -> (Signal) -> Signal { +public func beforeNext(_ f: @escaping(T) -> R) -> (Signal) -> Signal { return { signal in return Signal { subscriber in return signal.start(next: { next in @@ -15,7 +15,7 @@ public func beforeNext(_ f: (T) -> R) -> (Signal) -> Signal } } -public func afterNext(_ f: (T) -> R) -> (Signal) -> Signal { +public func afterNext(_ f: @escaping(T) -> R) -> (Signal) -> Signal { return { signal in return Signal { subscriber in return signal.start(next: { next in @@ -30,7 +30,7 @@ public func afterNext(_ f: (T) -> R) -> (Signal) -> Signal } } -public func beforeStarted(_ f: () -> Void) -> (Signal) -> Signal { +public func beforeStarted(_ f: @escaping() -> Void) -> (Signal) -> Signal { return { signal in return Signal { subscriber in f() @@ -45,7 +45,7 @@ public func beforeStarted(_ f: () -> Void) -> (Signal) -> Signal(_ f: () -> Void) -> (Signal) -> Signal { +public func beforeCompleted(_ f: @escaping() -> Void) -> (Signal) -> Signal { return { signal in return Signal { subscriber in return signal.start(next: { next in @@ -60,7 +60,7 @@ public func beforeCompleted(_ f: () -> Void) -> (Signal) -> Signal(_ f: () -> Void) -> (Signal) -> Signal { +public func afterCompleted(_ f: @escaping() -> Void) -> (Signal) -> Signal { return { signal in return Signal { subscriber in return signal.start(next: { next in @@ -75,7 +75,7 @@ public func afterCompleted(_ f: () -> Void) -> (Signal) -> Signal(_ f: (Void) -> R) -> (Signal) -> Signal { +public func afterDisposed(_ f: @escaping(Void) -> R) -> (Signal) -> Signal { return { signal in return Signal { subscriber in let disposable = DisposableSet() @@ -95,7 +95,7 @@ public func afterDisposed(_ f: (Void) -> R) -> (Signal) -> Signal } } -public func withState(_ signal: Signal, _ initialState: () -> S, next: (T, S) -> Void = { _ in }, error: (E, S) -> Void = { _ in }, completed: (S) -> Void = { _ in }, disposed: (S) -> Void = { _ in }) -> Signal { +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 diff --git a/SwiftSignalKit/Signal_Timing.swift b/SwiftSignalKit/Signal_Timing.swift index 818d702c2a..ad1c7bc82c 100644 --- a/SwiftSignalKit/Signal_Timing.swift +++ b/SwiftSignalKit/Signal_Timing.swift @@ -1,6 +1,6 @@ import Foundation -public func delay(_ timeout: Double, queue: Queue) -> (signal: Signal) -> Signal { +public func delay(_ timeout: Double, queue: Queue) -> (_ signal: Signal) -> Signal { return { signal in return Signal { subscriber in let disposable = MetaDisposable() diff --git a/SwiftSignalKit/ThreadPool.swift b/SwiftSignalKit/ThreadPool.swift index 3922f76026..eb149f6446 100644 --- a/SwiftSignalKit/ThreadPool.swift +++ b/SwiftSignalKit/ThreadPool.swift @@ -8,7 +8,7 @@ public final class ThreadPoolTask { private let state = ThreadPoolTaskState() private let action: (ThreadPoolTaskState) -> () - public init(_ action: (ThreadPoolTaskState) -> ()) { + public init(_ action: @escaping(ThreadPoolTaskState) -> ()) { self.action = action } @@ -39,7 +39,7 @@ 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.remove(at: 0) @@ -49,7 +49,7 @@ public final class ThreadPoolQueue : Equatable { } } - private func hasTasks() -> Bool { + fileprivate func hasTasks() -> Bool { return self.tasks.count != 0 } } @@ -142,7 +142,7 @@ public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { 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) { diff --git a/SwiftSignalKit/Timer.swift b/SwiftSignalKit/Timer.swift index 551c004aa1..e88379b0fe 100644 --- a/SwiftSignalKit/Timer.swift +++ b/SwiftSignalKit/Timer.swift @@ -7,7 +7,7 @@ public final class Timer { private var completion: (Void) -> Void private var queue: Queue - public init(timeout: Double, `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 From 7d8e299bc6c0554920c780a4555347bc2ffb6947 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 5 Sep 2016 23:20:27 +0300 Subject: [PATCH 073/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 225 ++++++++++++++++++++++++++ SwiftSignalKit copy-Info.plist | 26 +++ SwiftSignalKit/Atomic.swift | 4 +- SwiftSignalKit/Disposable.swift | 8 + SwiftSignalKit/Lock.swift | 2 +- SwiftSignalKitMac/Info.plist | 26 +++ SwiftSignalKitMac/SwiftSignalKitMac.h | 19 +++ 7 files changed, 307 insertions(+), 3 deletions(-) create mode 100644 SwiftSignalKit copy-Info.plist create mode 100644 SwiftSignalKitMac/Info.plist create mode 100644 SwiftSignalKitMac/SwiftSignalKitMac.h diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 933d430c4e..272b51c88c 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -94,6 +94,31 @@ 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 */ @@ -211,6 +236,10 @@ 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 */ @@ -246,6 +275,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D0B417E91D7DFA63004562A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -318,7 +354,9 @@ D0445DE71A7C2CA500267924 /* SSignalKitTests */, D0085B231B282B9800EAF753 /* SwiftSignalKit */, D0085B301B282B9800EAF753 /* SwiftSignalKitTests */, + D0B417EE1D7DFA63004562A4 /* SwiftSignalKitMac */, D0445DD91A7C2CA500267924 /* Products */, + D0B417E71D7DFA40004562A4 /* SwiftSignalKit copy-Info.plist */, ); sourceTree = ""; }; @@ -329,6 +367,7 @@ D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */, D0085B221B282B9800EAF753 /* SwiftSignalKit.framework */, D0085B2C1B282B9800EAF753 /* SwiftSignalKitTests.xctest */, + D0B417ED1D7DFA63004562A4 /* SwiftSignalKitMac.framework */, ); name = Products; sourceTree = ""; @@ -424,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 */ @@ -470,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 */ @@ -545,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 */ @@ -570,6 +644,10 @@ D0445DE21A7C2CA500267924 = { CreatedOnToolsVersion = 6.1.1; }; + D0B417EC1D7DFA63004562A4 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Manual; + }; }; }; buildConfigurationList = D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */; @@ -588,6 +666,7 @@ D0445DE21A7C2CA500267924 /* SSignalKitTests */, D0085B211B282B9800EAF753 /* SwiftSignalKit */, D0085B2B1B282B9800EAF753 /* SwiftSignalKitTests */, + D0B417EC1D7DFA63004562A4 /* SwiftSignalKitMac */, ); }; /* End PBXProject section */ @@ -621,6 +700,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D0B417EB1D7DFA63004562A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -710,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 */ @@ -730,6 +847,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + ARCHS = "$(ARCHS_STANDARD)"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -749,6 +867,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 3.0; }; @@ -758,6 +877,7 @@ 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"; @@ -775,6 +895,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; @@ -1086,6 +1207,7 @@ 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"; @@ -1103,6 +1225,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; @@ -1127,6 +1250,99 @@ }; 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 */ @@ -1180,6 +1396,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D0B417F21D7DFA63004562A4 /* Build configuration list for PBXNativeTarget "SwiftSignalKitMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0B417F31D7DFA63004562A4 /* Debug */, + D0B417F41D7DFA63004562A4 /* Release */, + D0B417F51D7DFA63004562A4 /* Hockeyapp */, + ); + defaultConfigurationIsVisible = 0; + }; /* End XCConfigurationList section */ }; rootObject = D0445DCF1A7C2CA500267924 /* Project object */; 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 5ad59cbecc..402816c894 100644 --- a/SwiftSignalKit/Atomic.swift +++ b/SwiftSignalKit/Atomic.swift @@ -8,7 +8,7 @@ public final class Atomic { self.value = value } - public func with(_ f: @noescape(T) -> R) -> R { + public func with(_ f: (T) -> R) -> R { OSSpinLockLock(&self.lock) let result = f(self.value) OSSpinLockUnlock(&self.lock) @@ -16,7 +16,7 @@ public final class Atomic { return result } - public func modify(_ f: @noescape(T) -> T) -> T { + public func modify(_ f: (T) -> T) -> T { OSSpinLockLock(&self.lock) let result = f(self.value) self.value = result diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift index 82bcd65f53..af4894355d 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -105,6 +105,14 @@ public final class DisposableSet : Disposable { } } + public func remove(_ disposable: Disposable) { + OSSpinLockLock(&self.lock) + if let index = self.disposables.index(where: { $0 === disposable }) { + self.disposables.remove(at: index) + } + OSSpinLockUnlock(&self.lock) + } + public func dispose() { var disposables: [Disposable] = [] OSSpinLockLock(&self.lock) diff --git a/SwiftSignalKit/Lock.swift b/SwiftSignalKit/Lock.swift index 8eb15a90f9..42847f2579 100644 --- a/SwiftSignalKit/Lock.swift +++ b/SwiftSignalKit/Lock.swift @@ -11,7 +11,7 @@ public final class Lock { pthread_mutex_destroy(&self.mutex) } - public func locked(_ f: @noescape() -> ()) { + public func locked(_ f: () -> ()) { pthread_mutex_lock(&self.mutex) f() pthread_mutex_unlock(&self.mutex) 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 + + From 95f4342defba323d037e8a8e83a0487212213ec3 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 2 Nov 2016 03:14:28 +0300 Subject: [PATCH 074/122] no message --- SwiftSignalKit/Promise.swift | 56 +++++++++++++++++++++++++++++++++++- SwiftSignalKit/Queue.swift | 12 +++++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/SwiftSignalKit/Promise.swift b/SwiftSignalKit/Promise.swift index 3db0dc86a2..93e9631af7 100644 --- a/SwiftSignalKit/Promise.swift +++ b/SwiftSignalKit/Promise.swift @@ -1,6 +1,6 @@ import Foundation -public class Promise { +public final class Promise { private var value: T? private var lock: OSSpinLock = 0 private let disposable = MetaDisposable() @@ -58,3 +58,57 @@ public class Promise { } } } + +public final class ValuePromise { + private var value: T? + private var lock: OSSpinLock = 0 + private let subscribers = Bag<(T) -> Void>() + public let ignoreRepeated: Bool + + public init(_ value: T, ignoreRepeated: Bool = false) { + self.value = value + self.ignoreRepeated = ignoreRepeated + } + + public init(ignoreRepeated: Bool = false) { + self.ignoreRepeated = ignoreRepeated + } + + public func set(_ value: T) { + OSSpinLockLock(&self.lock) + let subscribers: [(T) -> Void] + if !self.ignoreRepeated || self.value != value { + self.value = value + subscribers = self.subscribers.copyItems() + } else { + subscribers = [] + } + OSSpinLockUnlock(&self.lock); + + for subscriber in subscribers { + subscriber(value) + } + } + + public func get() -> Signal { + return Signal { subscriber in + OSSpinLockLock(&self.lock) + let currentValue = self.value + let index = self.subscribers.add({ next in + subscriber.putNext(next) + }) + OSSpinLockUnlock(&self.lock) + + + if let currentValue = currentValue { + subscriber.putNext(currentValue) + } + + return ActionDisposable { + OSSpinLockLock(&self.lock) + self.subscribers.remove(index) + OSSpinLockUnlock(&self.lock) + } + } + } +} diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index ac052d2ef3..30d6f65e8c 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -57,7 +57,7 @@ public final class Queue { } } - public func async(_ f: @escaping(Void) -> Void) { + public func async(_ f: @escaping () -> Void) { if self.isCurrent() { f() } else { @@ -65,7 +65,7 @@ public final class Queue { } } - public func sync(_ f: (Void) -> Void) { + public func sync(_ f: () -> Void) { if self.isCurrent() { f() } else { @@ -73,12 +73,16 @@ public final class Queue { } } - public func justDispatch(_ f: @escaping(Void) -> Void) { + 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() + Double(Int64(delay * Double(NSEC_PER_SEC))) + let time: DispatchTime = DispatchTime.now() + delay self.nativeQueue.asyncAfter(deadline: time, execute: f) } } From ee18c4d3f1cf61131565482ca4b33620df454998 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 8 Nov 2016 12:40:31 +0300 Subject: [PATCH 075/122] no message --- SSignalKit/SSignal+Meta.h | 2 ++ SSignalKit/SSignal+Meta.m | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) 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) From 9b88e5d46d98e2ad335c2f5a6e5612e7dccce01e Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 14 Nov 2016 22:45:48 +0300 Subject: [PATCH 076/122] no message --- SSignalKit/SQueue.h | 1 + SSignalKit/SQueue.m | 14 ++++++++++++++ 2 files changed, 15 insertions(+) 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) From 55ea86d5d5c02139072762074b9aab3402c8781b Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 17 Nov 2016 22:17:05 +0300 Subject: [PATCH 077/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 13 +++++---- SwiftSignalKit/Atomic.swift | 21 +++++++++----- SwiftSignalKit/Disposable.swift | 35 ++++++++++++++--------- SwiftSignalKit/Promise.swift | 42 +++++++++++++++++----------- SwiftSignalKit/Subscriber.swift | 23 +++++++++------ 5 files changed, 82 insertions(+), 52 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 272b51c88c..e2eb1b2fed 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -869,7 +869,7 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 3.0.1; }; name = Debug; }; @@ -897,7 +897,7 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 3.0.1; }; name = Release; }; @@ -1227,7 +1227,7 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 3.0.1; }; name = Hockeyapp; }; @@ -1277,7 +1277,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 3.0.1; }; name = Debug; }; @@ -1308,7 +1308,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 3.0.1; }; name = Release; }; @@ -1339,7 +1339,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 3.0.1; }; name = Hockeyapp; }; @@ -1404,6 +1404,7 @@ D0B417F51D7DFA63004562A4 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/SwiftSignalKit/Atomic.swift b/SwiftSignalKit/Atomic.swift index 402816c894..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) + } + + deinit { + pthread_mutex_destroy(&self.lock) } public func with(_ f: (T) -> R) -> R { - OSSpinLockLock(&self.lock) + 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) + 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) + 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/Disposable.swift b/SwiftSignalKit/Disposable.swift index af4894355d..4b38627a8e 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -28,18 +28,23 @@ public final class ActionDisposable : Disposable { } public final class MetaDisposable : Disposable { - private var lock: OSSpinLock = 0 + private var lock = pthread_mutex_t() private var disposed = false private var disposable: Disposable! = nil public init() { + pthread_mutex_init(&self.lock, nil) + } + + 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 @@ -49,7 +54,7 @@ public final class MetaDisposable : Disposable { self.disposable = nil } } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if previousDisposable != nil { previousDisposable.dispose() @@ -66,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() @@ -81,24 +86,28 @@ 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) + } + + 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() @@ -106,22 +115,22 @@ public final class DisposableSet : Disposable { } public func remove(_ disposable: Disposable) { - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) if let index = self.disposables.index(where: { $0 === disposable }) { self.disposables.remove(at: index) } - OSSpinLockUnlock(&self.lock) + 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/Promise.swift b/SwiftSignalKit/Promise.swift index 93e9631af7..036e6f4fe4 100644 --- a/SwiftSignalKit/Promise.swift +++ b/SwiftSignalKit/Promise.swift @@ -2,32 +2,35 @@ import Foundation 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<(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) + 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 final 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,9 @@ public final class Promise { } return ActionDisposable { - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) self.subscribers.remove(index) - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) } } } @@ -61,21 +64,27 @@ public final class Promise { public final class ValuePromise { private var value: T? - private var lock: OSSpinLock = 0 + 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) { - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) let subscribers: [(T) -> Void] if !self.ignoreRepeated || self.value != value { self.value = value @@ -83,7 +92,7 @@ public final class ValuePromise { } else { subscribers = [] } - OSSpinLockUnlock(&self.lock); + pthread_mutex_unlock(&self.lock); for subscriber in subscribers { subscriber(value) @@ -92,22 +101,21 @@ public final class ValuePromise { 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 { subscriber.putNext(currentValue) } return ActionDisposable { - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) self.subscribers.remove(index) - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) } } } diff --git a/SwiftSignalKit/Subscriber.swift b/SwiftSignalKit/Subscriber.swift index 4c2dfefc83..65626a9af6 100644 --- a/SwiftSignalKit/Subscriber.swift +++ b/SwiftSignalKit/Subscriber.swift @@ -5,7 +5,7 @@ public final class Subscriber { 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! @@ -13,6 +13,11 @@ public final class Subscriber { self.next = next self.error = error self.completed = completed + pthread_mutex_init(&self.lock, nil) + } + + deinit { + pthread_mutex_destroy(&self.lock) } internal func assignDisposable(_ disposable: Disposable) { @@ -24,23 +29,23 @@ 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) + pthread_mutex_lock(&self.lock) if !self.terminated { action = self.next } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if action != nil { action(next) @@ -51,7 +56,7 @@ public final class Subscriber { var shouldDispose = false var action: ((E) -> Void)! = nil - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) if !self.terminated { action = self.error shouldDispose = true; @@ -60,7 +65,7 @@ public final class Subscriber { self.completed = nil; self.terminated = true } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if action != nil { action(error) @@ -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,7 +91,7 @@ public final class Subscriber { self.completed = nil; self.terminated = true } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if action != nil { action() From 72cbe5da9e6b3be54ffa68a89b9613ed8fd8999e Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 9 Dec 2016 23:17:21 +0300 Subject: [PATCH 078/122] No message --- SSignalKit.xcodeproj/project.pbxproj | 15 +++++++++------ SwiftSignalKit/Bag.swift | 10 ++++++++++ SwiftSignalKit/Signal_Mapping.swift | 26 ++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index e2eb1b2fed..878cb2b0b2 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -869,7 +869,8 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0.1; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -897,7 +898,8 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0.1; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -1227,7 +1229,8 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0.1; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 3.0; }; name = Hockeyapp; }; @@ -1277,7 +1280,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0.1; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -1308,7 +1311,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0.1; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -1339,7 +1342,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0.1; + SWIFT_VERSION = 3.0; }; name = Hockeyapp; }; diff --git a/SwiftSignalKit/Bag.swift b/SwiftSignalKit/Bag.swift index d154372dee..cb3d771446 100644 --- a/SwiftSignalKit/Bag.swift +++ b/SwiftSignalKit/Bag.swift @@ -50,6 +50,16 @@ public final class Bag { 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 } diff --git a/SwiftSignalKit/Signal_Mapping.swift b/SwiftSignalKit/Signal_Mapping.swift index 29c11607d0..c67a4ae44f 100644 --- a/SwiftSignalKit/Signal_Mapping.swift +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -71,3 +71,29 @@ public func distinctUntilChanged(_ signal: Signal) -> Sig }) } } + +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() + }) + } + } +} From c8ec89bae0d10dc287547dba3e29963ec5c6eeb4 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 2 Feb 2017 18:59:18 +0300 Subject: [PATCH 079/122] 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) + } } From 2b4a17a83f229ffdd560f5b2c2149ec32327afcb Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 7 Feb 2017 23:10:16 +0300 Subject: [PATCH 080/122] no message --- SwiftSignalKit/Disposable.swift | 46 ++++++++++++++++++++++++----- SwiftSignalKit/Signal_Combine.swift | 8 ++++- SwiftSignalKit/Signal_Meta.swift | 40 +++++++++++++++---------- SwiftSignalKit/Signal_Timing.swift | 32 ++++++++++++-------- SwiftSignalKit/Subscriber.swift | 46 ++++++++++++++++++++--------- SwiftSignalKit/Timer.swift | 20 +++++++------ 6 files changed, 133 insertions(+), 59 deletions(-) diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift index 4b38627a8e..eb22eb4ffa 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -12,18 +12,37 @@ final class _EmptyDisposable: Disposable { public let EmptyDisposable: Disposable = _EmptyDisposable() public final class ActionDisposable : Disposable { - private var action: () -> Void - private var lock: Int32 = 0 + private var lock = pthread_mutex_t() + + private var action: (() -> Void)? public init(action: @escaping() -> Void) { self.action = action + + pthread_mutex_init(&self.lock, nil) } - public func dispose() { - if OSAtomicCompareAndSwap32(0, 1, &self.lock) { - self.action() - self.action = doNothing - } + deinit { + var freeAction: (() -> Void)? + pthread_mutex_lock(&self.lock) + freeAction = self.action + self.action = nil + pthread_mutex_unlock(&self.lock) + + freeAction = nil + + pthread_mutex_destroy(&self.lock) + } + + public func dispose() {var disposable: Disposable! = nil + let disposeAction: (() -> Void)? + + pthread_mutex_lock(&self.lock) + disposeAction = self.action + self.action = nil + pthread_mutex_unlock(&self.lock) + + disposeAction?() } } @@ -37,6 +56,15 @@ public final class MetaDisposable : Disposable { } deinit { + var freeDisposable: Disposable? + pthread_mutex_lock(&self.lock) + if let disposable = self.disposable { + freeDisposable = disposable + self.disposable = nil + } + pthread_mutex_unlock(&self.lock) + freeDisposable = nil + pthread_mutex_destroy(&self.lock) } @@ -95,6 +123,10 @@ public final class DisposableSet : Disposable { } deinit { + pthread_mutex_lock(&self.lock) + self.disposables.removeAll() + pthread_mutex_unlock(&self.lock) + pthread_mutex_destroy(&self.lock) } diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index ff32728c75..28605ac3ef 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -100,12 +100,18 @@ public func combineLatest(_ s1: Signal, _ s2: Signal(_ 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(_ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal) -> Signal<(T1, T2, T3, T4, T5), E> { + return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5)], combine: { values in + return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5) + }, initialValues: [:]) +} + public func combineLatest(_ signals: [Signal]) -> Signal<[T], E> { if signals.count == 0 { return single([T](), E.self) diff --git a/SwiftSignalKit/Signal_Meta.swift b/SwiftSignalKit/Signal_Meta.swift index 3534359b90..5d4c61b04e 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -1,31 +1,37 @@ import Foundation -private final class SignalQueueState : Disposable { - var lock: OSSpinLock = 0 +private final class SignalQueueState: Disposable { + var lock = pthread_mutex_t() var executingSignal = false var terminated = false var disposable: Disposable = EmptyDisposable let currentDisposable = MetaDisposable() - let subscriber: Subscriber + var subscriber: Subscriber? var queuedSignals: [Signal] = [] let queueMode: Bool let throttleMode: Bool init(subscriber: Subscriber, queueMode: Bool, throttleMode: Bool) { + pthread_mutex_init(&self.lock, nil) + self.subscriber = subscriber self.queueMode = queueMode self.throttleMode = throttleMode } + deinit { + pthread_mutex_destroy(&self.lock) + } + func beginWithDisposable(_ disposable: Disposable) { self.disposable = disposable } func enqueueSignal(_ signal: Signal) { var startSignal = false - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) if self.queueMode && self.executingSignal { if self.throttleMode { self.queuedSignals.removeAll() @@ -35,13 +41,15 @@ private final class SignalQueueState : Disposable { self.executingSignal = true startSignal = true } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if startSignal { let disposable = signal.start(next: { next in - self.subscriber.putNext(next) + assert(self.subscriber != nil) + self.subscriber?.putNext(next) }, error: { error in - self.subscriber.putError(error) + assert(self.subscriber != nil) + self.subscriber?.putError(error) }, completed: { self.headCompleted() }) @@ -56,7 +64,7 @@ private final class SignalQueueState : Disposable { var nextSignal: Signal! = nil var terminated = false - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) self.executingSignal = false if self.queueMode { if self.queuedSignals.count != 0 { @@ -69,15 +77,17 @@ private final class SignalQueueState : Disposable { } else { terminated = self.terminated } - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if terminated { - self.subscriber.putCompletion() + self.subscriber?.putCompletion() } else if nextSignal != nil { let disposable = nextSignal.start(next: { next in - self.subscriber.putNext(next) + assert(self.subscriber != nil) + self.subscriber?.putNext(next) }, error: { error in - self.subscriber.putError(error) + assert(self.subscriber != nil) + self.subscriber?.putError(error) }, completed: { if leftFunction.swap(true) == true { self.headCompleted() @@ -95,13 +105,13 @@ private final class SignalQueueState : Disposable { func beginCompletion() { var executingSignal = false - OSSpinLockLock(&self.lock) + pthread_mutex_lock(&self.lock) executingSignal = self.executingSignal self.terminated = true - OSSpinLockUnlock(&self.lock) + pthread_mutex_unlock(&self.lock) if !executingSignal { - self.subscriber.putCompletion() + self.subscriber?.putCompletion() } } diff --git a/SwiftSignalKit/Signal_Timing.swift b/SwiftSignalKit/Signal_Timing.swift index ad1c7bc82c..dc5316be60 100644 --- a/SwiftSignalKit/Signal_Timing.swift +++ b/SwiftSignalKit/Signal_Timing.swift @@ -4,19 +4,25 @@ public func delay(_ timeout: Double, queue: Queue) -> (_ signal: 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() + queue.async { + 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 { + queue.async { + timer.invalidate() + } + }) + + timer.start() + } return disposable } } diff --git a/SwiftSignalKit/Subscriber.swift b/SwiftSignalKit/Subscriber.swift index 65626a9af6..70d5ed832d 100644 --- a/SwiftSignalKit/Subscriber.swift +++ b/SwiftSignalKit/Subscriber.swift @@ -17,15 +17,31 @@ public final class Subscriber { } deinit { + var freeDisposable: Disposable? + pthread_mutex_lock(&self.lock) + if let disposable = self.disposable { + freeDisposable = disposable + self.disposable = nil + } + pthread_mutex_unlock(&self.lock) + freeDisposable = nil + pthread_mutex_destroy(&self.lock) } internal func assignDisposable(_ disposable: Disposable) { + var dispose = false + pthread_mutex_lock(&self.lock) if self.terminated { - disposable.dispose() + dispose = true } else { self.disposable = disposable } + pthread_mutex_unlock(&self.lock) + + if dispose { + disposable.dispose() + } } internal func markTerminatedWithoutDisposal() { @@ -53,17 +69,20 @@ public final class Subscriber { } public func putError(_ error: E) { - var shouldDispose = false var action: ((E) -> Void)! = nil + var disposeDisposable: Disposable? + pthread_mutex_lock(&self.lock) if !self.terminated { action = self.error - shouldDispose = true; self.next = nil self.error = nil self.completed = nil; self.terminated = true + disposeDisposable = self.disposable + self.disposable = nil + } pthread_mutex_unlock(&self.lock) @@ -71,25 +90,26 @@ public final class Subscriber { action(error) } - if shouldDispose && self.disposable != nil { - let disposable = self.disposable! - disposable.dispose() - self.disposable = nil + if let disposeDisposable = disposeDisposable { + disposeDisposable.dispose() } } public func putCompletion() { - var shouldDispose = false var action: (() -> Void)! = nil + var disposeDisposable: Disposable? = nil + pthread_mutex_lock(&self.lock) if !self.terminated { action = self.completed - shouldDispose = true; self.next = nil self.error = nil - self.completed = nil; + self.completed = nil self.terminated = true + + disposeDisposable = self.disposable + self.disposable = nil } pthread_mutex_unlock(&self.lock) @@ -97,10 +117,8 @@ public final class Subscriber { action() } - if shouldDispose && self.disposable != nil { - let disposable = self.disposable! - disposable.dispose() - self.disposable = nil + if let disposeDisposable = disposeDisposable { + disposeDisposable.dispose() } } } diff --git a/SwiftSignalKit/Timer.swift b/SwiftSignalKit/Timer.swift index e88379b0fe..08e495ec7e 100644 --- a/SwiftSignalKit/Timer.swift +++ b/SwiftSignalKit/Timer.swift @@ -1,11 +1,11 @@ import Foundation public final class Timer { - private var timer: DispatchSourceTimer? - private var timeout: Double - private var `repeat`: Bool - private var completion: (Void) -> Void - private var queue: Queue + private let timer = Atomic(value: nil) + private let timeout: Double + private let `repeat`: Bool + private let completion: (Void) -> Void + private let queue: Queue public init(timeout: Double, `repeat`: Bool, completion: @escaping(Void) -> Void, queue: Queue) { self.timeout = timeout @@ -28,7 +28,9 @@ public final class Timer { } } }) - self.timer = timer + self.timer.modify { _ in + return timer + } if self.`repeat` { let time: DispatchTime = DispatchTime.now() + self.timeout @@ -42,9 +44,9 @@ public final class Timer { } public func invalidate() { - if let timer = self.timer { - timer.cancel() - self.timer = nil + self.timer.modify { timer in + timer?.cancel() + return nil } } } From 615652b8f84d641b5898193b06d119e198f57190 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 9 Feb 2017 20:49:10 +0300 Subject: [PATCH 081/122] no message --- SSignalKit/SAtomic.h | 1 + SSignalKit/SAtomic.m | 49 ++++++++++++++++++++++++++++++++-------- SSignalKit/SSubscriber.m | 13 ++++++++--- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/SSignalKit/SAtomic.h b/SSignalKit/SAtomic.h index 98aa4da05a..6d3e35b4dc 100644 --- a/SSignalKit/SAtomic.h +++ b/SSignalKit/SAtomic.h @@ -3,6 +3,7 @@ @interface SAtomic : NSObject - (instancetype)initWithValue:(id)value; +- (instancetype)initWithValue:(id)value recursive:(bool)recursive; - (id)swap:(id)newValue; - (id)value; - (id)modify:(id (^)(id))f; diff --git a/SSignalKit/SAtomic.m b/SSignalKit/SAtomic.m index b52e580a82..5f7f3d1032 100644 --- a/SSignalKit/SAtomic.m +++ b/SSignalKit/SAtomic.m @@ -1,10 +1,12 @@ #import "SAtomic.h" -#import +#import @interface SAtomic () { - volatile OSSpinLock _lock; + pthread_mutex_t _lock; + pthread_mutexattr_t _attr; + bool _isRecursive; id _value; } @@ -17,27 +19,54 @@ self = [super init]; if (self != nil) { + pthread_mutex_init(&_lock, NULL); _value = value; } return self; } +- (instancetype)initWithValue:(id)value recursive:(bool)recursive { + self = [super init]; + if (self != nil) + { + _isRecursive = recursive; + + if (recursive) { + pthread_mutexattr_init(&_attr); + pthread_mutexattr_settype(&_attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_lock, &_attr); + } else { + pthread_mutex_init(&_lock, NULL); + } + + _value = value; + } + return self; +} + +- (void)dealloc { + if (_isRecursive) { + pthread_mutexattr_destroy(&_attr); + } + pthread_mutex_destroy(&_lock); +} + - (id)swap:(id)newValue { id previousValue = nil; - OSSpinLockLock(&_lock); + pthread_mutex_lock(&_lock); previousValue = _value; _value = newValue; - OSSpinLockUnlock(&_lock); + pthread_mutex_unlock(&_lock); return previousValue; } - (id)value { id previousValue = nil; - OSSpinLockLock(&_lock); + pthread_mutex_lock(&_lock); previousValue = _value; - OSSpinLockUnlock(&_lock); + pthread_mutex_unlock(&_lock); return previousValue; } @@ -45,19 +74,19 @@ - (id)modify:(id (^)(id))f { id newValue = nil; - OSSpinLockLock(&_lock); + pthread_mutex_lock(&_lock); newValue = f(_value); _value = newValue; - OSSpinLockUnlock(&_lock); + pthread_mutex_unlock(&_lock); return newValue; } - (id)with:(id (^)(id))f { id result = nil; - OSSpinLockLock(&_lock); + pthread_mutex_lock(&_lock); result = f(_value); - OSSpinLockUnlock(&_lock); + pthread_mutex_unlock(&_lock); return result; } diff --git a/SSignalKit/SSubscriber.m b/SSignalKit/SSubscriber.m index 376bbfdddb..e565b7748d 100644 --- a/SSignalKit/SSubscriber.m +++ b/SSignalKit/SSubscriber.m @@ -50,10 +50,17 @@ - (void)_assignDisposable:(id)disposable { - if (_terminated) - [disposable dispose]; - else + bool dispose = false; + OSSpinLockLock(&_lock); + if (_terminated) { + dispose = true; + } else { _disposable = disposable; + } + OSSpinLockUnlock(&_lock); + if (dispose) { + [disposable dispose]; + } } - (void)_markTerminatedWithoutDisposal From f1bd3236ba68d55c3ebd94c43c3bb4bc4cf08d6f Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 23 Feb 2017 00:06:58 +0300 Subject: [PATCH 082/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 184 +++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 878cb2b0b2..27aef6c1cc 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -1346,6 +1346,184 @@ }; name = Hockeyapp; }; + D0DB57B61E5C4B7A0071854C /* Debug AppStore */ = { + 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 = NO; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + 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", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + 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 = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = "Debug AppStore"; + }; + D0DB57B71E5C4B7A0071854C /* Debug AppStore */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + 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; + 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 AppStore"; + }; + D0DB57B81E5C4B7A0071854C /* Debug AppStore */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(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 = "Debug AppStore"; + }; + D0DB57B91E5C4B7A0071854C /* Debug AppStore */ = { + 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", + "$(inherited)", + ); + 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 = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 3.0; + }; + name = "Debug AppStore"; + }; + D0DB57BA1E5C4B7A0071854C /* Debug AppStore */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + 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 = "Debug AppStore"; + }; + D0DB57BB1E5C4B7A0071854C /* Debug AppStore */ = { + 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 AppStore"; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1353,6 +1531,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0085B361B282B9800EAF753 /* Debug */, + D0DB57B91E5C4B7A0071854C /* Debug AppStore */, D0085B371B282B9800EAF753 /* Release */, D086A5771CC0117500F08284 /* Hockeyapp */, ); @@ -1363,6 +1542,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0085B391B282B9800EAF753 /* Debug */, + D0DB57BA1E5C4B7A0071854C /* Debug AppStore */, D0085B3A1B282B9800EAF753 /* Release */, D086A5781CC0117500F08284 /* Hockeyapp */, ); @@ -1373,6 +1553,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0445DEC1A7C2CA500267924 /* Debug */, + D0DB57B61E5C4B7A0071854C /* Debug AppStore */, D0445DED1A7C2CA500267924 /* Release */, D086A5741CC0117500F08284 /* Hockeyapp */, ); @@ -1383,6 +1564,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0445DEF1A7C2CA500267924 /* Debug */, + D0DB57B71E5C4B7A0071854C /* Debug AppStore */, D0445DF01A7C2CA500267924 /* Release */, D086A5751CC0117500F08284 /* Hockeyapp */, ); @@ -1393,6 +1575,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0445DF21A7C2CA500267924 /* Debug */, + D0DB57B81E5C4B7A0071854C /* Debug AppStore */, D0445DF31A7C2CA500267924 /* Release */, D086A5761CC0117500F08284 /* Hockeyapp */, ); @@ -1403,6 +1586,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0B417F31D7DFA63004562A4 /* Debug */, + D0DB57BB1E5C4B7A0071854C /* Debug AppStore */, D0B417F41D7DFA63004562A4 /* Release */, D0B417F51D7DFA63004562A4 /* Hockeyapp */, ); From a65ac6b5fb1fdef03d067612c2291e47d0f9f10f Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 6 Mar 2017 02:09:37 +0300 Subject: [PATCH 083/122] no message --- SwiftSignalKit/Disposable.swift | 58 ++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift index eb22eb4ffa..a333eae4e2 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -34,7 +34,7 @@ public final class ActionDisposable : Disposable { pthread_mutex_destroy(&self.lock) } - public func dispose() {var disposable: Disposable! = nil + public func dispose() { let disposeAction: (() -> Void)? pthread_mutex_lock(&self.lock) @@ -171,3 +171,59 @@ public final class DisposableSet : Disposable { } } } + +public final class DisposableDict : Disposable { + private var lock = pthread_mutex_t() + private var disposed = false + private var disposables: [T: Disposable] = [:] + + public init() { + pthread_mutex_init(&self.lock, nil) + } + + deinit { + pthread_mutex_lock(&self.lock) + self.disposables.removeAll() + pthread_mutex_unlock(&self.lock) + + pthread_mutex_destroy(&self.lock) + } + + public func set(_ disposable: Disposable?, forKey key: T) { + var disposeImmediately = false + var disposePrevious: Disposable? + + pthread_mutex_lock(&self.lock) + if self.disposed { + disposeImmediately = true + } else { + disposePrevious = self.disposables[key] + if let disposable = disposable { + self.disposables[key] = disposable + } + } + pthread_mutex_unlock(&self.lock) + + if disposeImmediately { + disposable?.dispose() + } + disposePrevious?.dispose() + } + + public func dispose() { + var disposables: [T: Disposable] = [:] + pthread_mutex_lock(&self.lock) + if !self.disposed { + self.disposed = true + disposables = self.disposables + self.disposables = [:] + } + pthread_mutex_unlock(&self.lock) + + if disposables.count != 0 { + for disposable in disposables.values { + disposable.dispose() + } + } + } +} From 3fb612596fa5cff1f59ac99bae426e656d623b8a Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 7 Mar 2017 01:38:03 +0300 Subject: [PATCH 084/122] no message --- SwiftSignalKit/Queue.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 30d6f65e8c..2adaf89c7a 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -39,12 +39,16 @@ public final class Queue { self.specialIsMainQueue = specialIsMainQueue } - public init(name: String? = nil) { + public init(name: String? = nil, target: Queue? = nil) { self.nativeQueue = DispatchQueue(label: name ?? "", qos: .default) self.specialIsMainQueue = false self.nativeQueue.setSpecific(key: QueueSpecificKey, value: self.specific) + + if let target = target { + //self.nativeQueue.setTarget(queue: target.nativeQueue) + } } public func isCurrent() -> Bool { From b9b25953bc2163dfeccb004a13ee73ad64b0bf90 Mon Sep 17 00:00:00 2001 From: overtake Date: Sun, 2 Apr 2017 21:53:00 +0300 Subject: [PATCH 085/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 169 +++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 27aef6c1cc..6212bd13f3 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -843,6 +843,169 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + C22069CC1E8EB4CA00E82730 /* AppStore */ = { + 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 = AppStore; + }; + C22069CD1E8EB4CA00E82730 /* AppStore */ = { + 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 = AppStore; + }; + C22069CE1E8EB4CA00E82730 /* AppStore */ = { + 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 = AppStore; + }; + C22069CF1E8EB4CA00E82730 /* AppStore */ = { + 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 = AppStore; + }; + C22069D01E8EB4CA00E82730 /* AppStore */ = { + 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_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + }; + name = AppStore; + }; + C22069D11E8EB4CA00E82730 /* AppStore */ = { + 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 = AppStore; + }; D0085B361B282B9800EAF753 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1533,6 +1696,7 @@ D0085B361B282B9800EAF753 /* Debug */, D0DB57B91E5C4B7A0071854C /* Debug AppStore */, D0085B371B282B9800EAF753 /* Release */, + C22069CF1E8EB4CA00E82730 /* AppStore */, D086A5771CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; @@ -1544,6 +1708,7 @@ D0085B391B282B9800EAF753 /* Debug */, D0DB57BA1E5C4B7A0071854C /* Debug AppStore */, D0085B3A1B282B9800EAF753 /* Release */, + C22069D01E8EB4CA00E82730 /* AppStore */, D086A5781CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; @@ -1555,6 +1720,7 @@ D0445DEC1A7C2CA500267924 /* Debug */, D0DB57B61E5C4B7A0071854C /* Debug AppStore */, D0445DED1A7C2CA500267924 /* Release */, + C22069CC1E8EB4CA00E82730 /* AppStore */, D086A5741CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; @@ -1566,6 +1732,7 @@ D0445DEF1A7C2CA500267924 /* Debug */, D0DB57B71E5C4B7A0071854C /* Debug AppStore */, D0445DF01A7C2CA500267924 /* Release */, + C22069CD1E8EB4CA00E82730 /* AppStore */, D086A5751CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; @@ -1577,6 +1744,7 @@ D0445DF21A7C2CA500267924 /* Debug */, D0DB57B81E5C4B7A0071854C /* Debug AppStore */, D0445DF31A7C2CA500267924 /* Release */, + C22069CE1E8EB4CA00E82730 /* AppStore */, D086A5761CC0117500F08284 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; @@ -1588,6 +1756,7 @@ D0B417F31D7DFA63004562A4 /* Debug */, D0DB57BB1E5C4B7A0071854C /* Debug AppStore */, D0B417F41D7DFA63004562A4 /* Release */, + C22069D11E8EB4CA00E82730 /* AppStore */, D0B417F51D7DFA63004562A4 /* Hockeyapp */, ); defaultConfigurationIsVisible = 0; From 43e190dafd56dc9a9ff529c44a3a928b38b01117 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 26 May 2017 13:23:49 +0300 Subject: [PATCH 086/122] no message --- SwiftSignalKit/Disposable.swift | 8 ++++++-- SwiftSignalKit/Queue.swift | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/SwiftSignalKit/Disposable.swift b/SwiftSignalKit/Disposable.swift index a333eae4e2..5287ac158b 100644 --- a/SwiftSignalKit/Disposable.swift +++ b/SwiftSignalKit/Disposable.swift @@ -29,7 +29,9 @@ public final class ActionDisposable : Disposable { self.action = nil pthread_mutex_unlock(&self.lock) - freeAction = nil + if let freeAction = freeAction { + withExtendedLifetime(freeAction, {}) + } pthread_mutex_destroy(&self.lock) } @@ -63,7 +65,9 @@ public final class MetaDisposable : Disposable { self.disposable = nil } pthread_mutex_unlock(&self.lock) - freeDisposable = nil + if let freeDisposable = freeDisposable { + withExtendedLifetime(freeDisposable, { }) + } pthread_mutex_destroy(&self.lock) } diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 2adaf89c7a..99e81ad66d 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -39,8 +39,8 @@ public final class Queue { self.specialIsMainQueue = specialIsMainQueue } - public init(name: String? = nil, target: Queue? = nil) { - self.nativeQueue = DispatchQueue(label: name ?? "", qos: .default) + public init(name: String? = nil, target: Queue? = nil, qos: DispatchQoS = .default) { + self.nativeQueue = DispatchQueue(label: name ?? "", qos: qos) self.specialIsMainQueue = false From 645e4f0c0325cf681a28ab752a77b961cc154149 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 14 Jul 2017 15:30:49 +0300 Subject: [PATCH 087/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 126 ++++++++++++++------------ SwiftSignalKit/QueueLocalObject.swift | 31 +++++++ 2 files changed, 97 insertions(+), 60 deletions(-) create mode 100644 SwiftSignalKit/QueueLocalObject.swift diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 27aef6c1cc..dd98306bdd 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -86,6 +86,8 @@ 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 */; }; + D053B4001F16881000E2D58A /* QueueLocalObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FF1F16881000E2D58A /* QueueLocalObject.swift */; }; + D053B4011F16881000E2D58A /* QueueLocalObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FF1F16881000E2D58A /* QueueLocalObject.swift */; }; 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 */; }; @@ -227,6 +229,7 @@ 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 = ""; }; + D053B3FF1F16881000E2D58A /* QueueLocalObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueueLocalObject.swift; 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 = ""; }; @@ -313,6 +316,7 @@ D07A5CFC1BBDE6E400451791 /* Promise.swift */, D05F09A71C9EF77100BB6F96 /* Multicast.swift */, D066BD091C7FE06700D7A576 /* Lock.swift */, + D053B3FF1F16881000E2D58A /* QueueLocalObject.swift */, D0085B261B282B9800EAF753 /* SwiftSignalKit.h */, D0085B241B282B9800EAF753 /* Supporting Files */, ); @@ -734,6 +738,7 @@ D0085B5B1B282BEE00EAF753 /* Signal_Meta.swift in Sources */, D0085B571B282BEE00EAF753 /* Bag.swift in Sources */, D0085B5A1B282BEE00EAF753 /* Signal_Single.swift in Sources */, + D053B4001F16881000E2D58A /* QueueLocalObject.swift in Sources */, D0085B611B282BEE00EAF753 /* Signal_Mapping.swift in Sources */, D0085B5C1B282BEE00EAF753 /* Signal_Combine.swift in Sources */, D0085B5D1B282BEE00EAF753 /* Atomic.swift in Sources */, @@ -820,6 +825,7 @@ D0B418071D7DFAAB004562A4 /* Signal.swift in Sources */, D0B418081D7DFAAB004562A4 /* Disposable.swift in Sources */, D0B418091D7DFAAB004562A4 /* Signal_Mapping.swift in Sources */, + D053B4011F16881000E2D58A /* QueueLocalObject.swift in Sources */, D0B4180A1D7DFAAB004562A4 /* Subscriber.swift in Sources */, D0B4180B1D7DFAAB004562A4 /* Promise.swift in Sources */, D0B4180C1D7DFAAB004562A4 /* Multicast.swift in Sources */, @@ -843,7 +849,7 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - D0085B361B282B9800EAF753 /* Debug */ = { + D0085B361B282B9800EAF753 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -872,9 +878,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 3.0; }; - name = Debug; + name = "Debug Hockeyapp"; }; - D0085B371B282B9800EAF753 /* Release */ = { + D0085B371B282B9800EAF753 /* Release Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -901,9 +907,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 3.0; }; - name = Release; + name = "Release Hockeyapp"; }; - D0085B391B282B9800EAF753 /* Debug */ = { + D0085B391B282B9800EAF753 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -923,9 +929,9 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; - name = Debug; + name = "Debug Hockeyapp"; }; - D0085B3A1B282B9800EAF753 /* Release */ = { + D0085B3A1B282B9800EAF753 /* Release Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; @@ -943,9 +949,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; - name = Release; + name = "Release Hockeyapp"; }; - D0445DEC1A7C2CA500267924 /* Debug */ = { + D0445DEC1A7C2CA500267924 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -991,9 +997,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Debug; + name = "Debug Hockeyapp"; }; - D0445DED1A7C2CA500267924 /* Release */ = { + D0445DED1A7C2CA500267924 /* Release Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1032,9 +1038,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Release; + name = "Release Hockeyapp"; }; - D0445DEF1A7C2CA500267924 /* Debug */ = { + D0445DEF1A7C2CA500267924 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1054,9 +1060,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = Debug; + name = "Debug Hockeyapp"; }; - D0445DF01A7C2CA500267924 /* Release */ = { + D0445DF01A7C2CA500267924 /* Release Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1076,9 +1082,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = Release; + name = "Release Hockeyapp"; }; - D0445DF21A7C2CA500267924 /* Debug */ = { + D0445DF21A7C2CA500267924 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1100,9 +1106,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = Debug; + name = "Debug Hockeyapp"; }; - D0445DF31A7C2CA500267924 /* Release */ = { + D0445DF31A7C2CA500267924 /* Release Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1120,9 +1126,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = Release; + name = "Release Hockeyapp"; }; - D086A5741CC0117500F08284 /* Hockeyapp */ = { + D086A5741CC0117500F08284 /* Release AppStore */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1161,9 +1167,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Hockeyapp; + name = "Release AppStore"; }; - D086A5751CC0117500F08284 /* Hockeyapp */ = { + D086A5751CC0117500F08284 /* Release AppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1183,9 +1189,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = Hockeyapp; + name = "Release AppStore"; }; - D086A5761CC0117500F08284 /* Hockeyapp */ = { + D086A5761CC0117500F08284 /* Release AppStore */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1203,9 +1209,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = Hockeyapp; + name = "Release AppStore"; }; - D086A5771CC0117500F08284 /* Hockeyapp */ = { + D086A5771CC0117500F08284 /* Release AppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1232,9 +1238,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 3.0; }; - name = Hockeyapp; + name = "Release AppStore"; }; - D086A5781CC0117500F08284 /* Hockeyapp */ = { + D086A5781CC0117500F08284 /* Release AppStore */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; @@ -1251,9 +1257,9 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; - name = Hockeyapp; + name = "Release AppStore"; }; - D0B417F31D7DFA63004562A4 /* Debug */ = { + D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1282,9 +1288,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 3.0; }; - name = Debug; + name = "Debug Hockeyapp"; }; - D0B417F41D7DFA63004562A4 /* Release */ = { + D0B417F41D7DFA63004562A4 /* Release Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1313,9 +1319,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; - name = Release; + name = "Release Hockeyapp"; }; - D0B417F51D7DFA63004562A4 /* Hockeyapp */ = { + D0B417F51D7DFA63004562A4 /* Release AppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1344,7 +1350,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; - name = Hockeyapp; + name = "Release AppStore"; }; D0DB57B61E5C4B7A0071854C /* Debug AppStore */ = { isa = XCBuildConfiguration; @@ -1530,68 +1536,68 @@ D0085B351B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKit" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0085B361B282B9800EAF753 /* Debug */, + D0085B361B282B9800EAF753 /* Debug Hockeyapp */, D0DB57B91E5C4B7A0071854C /* Debug AppStore */, - D0085B371B282B9800EAF753 /* Release */, - D086A5771CC0117500F08284 /* Hockeyapp */, + D0085B371B282B9800EAF753 /* Release Hockeyapp */, + D086A5771CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = "Release Hockeyapp"; }; D0085B381B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKitTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0085B391B282B9800EAF753 /* Debug */, + D0085B391B282B9800EAF753 /* Debug Hockeyapp */, D0DB57BA1E5C4B7A0071854C /* Debug AppStore */, - D0085B3A1B282B9800EAF753 /* Release */, - D086A5781CC0117500F08284 /* Hockeyapp */, + D0085B3A1B282B9800EAF753 /* Release Hockeyapp */, + D086A5781CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = "Release Hockeyapp"; }; D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0445DEC1A7C2CA500267924 /* Debug */, + D0445DEC1A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B61E5C4B7A0071854C /* Debug AppStore */, - D0445DED1A7C2CA500267924 /* Release */, - D086A5741CC0117500F08284 /* Hockeyapp */, + D0445DED1A7C2CA500267924 /* Release Hockeyapp */, + D086A5741CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = "Release Hockeyapp"; }; D0445DEE1A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKit" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0445DEF1A7C2CA500267924 /* Debug */, + D0445DEF1A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B71E5C4B7A0071854C /* Debug AppStore */, - D0445DF01A7C2CA500267924 /* Release */, - D086A5751CC0117500F08284 /* Hockeyapp */, + D0445DF01A7C2CA500267924 /* Release Hockeyapp */, + D086A5751CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = "Release Hockeyapp"; }; D0445DF11A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKitTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0445DF21A7C2CA500267924 /* Debug */, + D0445DF21A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B81E5C4B7A0071854C /* Debug AppStore */, - D0445DF31A7C2CA500267924 /* Release */, - D086A5761CC0117500F08284 /* Hockeyapp */, + D0445DF31A7C2CA500267924 /* Release Hockeyapp */, + D086A5761CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = "Release Hockeyapp"; }; D0B417F21D7DFA63004562A4 /* Build configuration list for PBXNativeTarget "SwiftSignalKitMac" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0B417F31D7DFA63004562A4 /* Debug */, + D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */, D0DB57BB1E5C4B7A0071854C /* Debug AppStore */, - D0B417F41D7DFA63004562A4 /* Release */, - D0B417F51D7DFA63004562A4 /* Hockeyapp */, + D0B417F41D7DFA63004562A4 /* Release Hockeyapp */, + D0B417F51D7DFA63004562A4 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = "Release Hockeyapp"; }; /* End XCConfigurationList section */ }; diff --git a/SwiftSignalKit/QueueLocalObject.swift b/SwiftSignalKit/QueueLocalObject.swift new file mode 100644 index 0000000000..c542d2979d --- /dev/null +++ b/SwiftSignalKit/QueueLocalObject.swift @@ -0,0 +1,31 @@ +import Foundation + +public final class QueueLocalObject { + private let queue: Queue + private var valueRef: Unmanaged? + + public init(queue: Queue, generate: @escaping () -> T) { + self.queue = queue + + self.queue.async { + let value = generate() + self.valueRef = Unmanaged.passRetained(value) + } + } + + deinit { + let valueRef = self.valueRef + self.queue.async { + valueRef?.release() + } + } + + public func with(_ f: @escaping (T) -> Void) { + self.queue.async { + if let valueRef = self.valueRef { + let value = valueRef.takeUnretainedValue() + f(value) + } + } + } +} From 99b1dfb46e10c47e36646df4ce63c484ab7980f0 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 28 Jul 2017 16:56:18 +0300 Subject: [PATCH 088/122] no message --- SSignalKit/STimer.h | 1 + SSignalKit/STimer.m | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/SSignalKit/STimer.h b/SSignalKit/STimer.h index 55420e25f5..621e4232b2 100644 --- a/SSignalKit/STimer.h +++ b/SSignalKit/STimer.h @@ -5,6 +5,7 @@ @interface STimer : NSObject - (id)initWithTimeout:(NSTimeInterval)timeout repeat:(bool)repeat completion:(dispatch_block_t)completion queue:(SQueue *)queue; +- (id)initWithTimeout:(NSTimeInterval)timeout repeat:(bool)repeat completion:(dispatch_block_t)completion nativeQueue:(dispatch_queue_t)nativeQueue; - (void)start; - (void)invalidate; diff --git a/SSignalKit/STimer.m b/SSignalKit/STimer.m index 0dec5c35e6..235c2f883a 100644 --- a/SSignalKit/STimer.m +++ b/SSignalKit/STimer.m @@ -9,14 +9,18 @@ NSTimeInterval _timeoutDate; bool _repeat; dispatch_block_t _completion; - SQueue *_queue; + dispatch_queue_t _nativeQueue; } @end @implementation STimer -- (id)initWithTimeout:(NSTimeInterval)timeout repeat:(bool)repeat completion:(dispatch_block_t)completion queue:(SQueue *)queue +- (id)initWithTimeout:(NSTimeInterval)timeout repeat:(bool)repeat completion:(dispatch_block_t)completion queue:(SQueue *)queue { + return [self initWithTimeout:timeout repeat:repeat completion:completion nativeQueue:queue._dispatch_queue]; +} + +- (id)initWithTimeout:(NSTimeInterval)timeout repeat:(bool)repeat completion:(dispatch_block_t)completion nativeQueue:(dispatch_queue_t)nativeQueue { self = [super init]; if (self != nil) @@ -26,7 +30,7 @@ _timeout = timeout; _repeat = repeat; _completion = [completion copy]; - _queue = queue; + _nativeQueue = nativeQueue; } return self; } @@ -44,7 +48,7 @@ { _timeoutDate = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970 + _timeout; - _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, [_queue _dispatch_queue]); + _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _nativeQueue); dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)), _repeat ? (int64_t)(_timeout * NSEC_PER_SEC) : DISPATCH_TIME_FOREVER, 0); dispatch_source_set_event_handler(_timer, ^ From fad51507f1198beb74b554fc17ba05d31e0062a6 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 11 Sep 2017 00:07:16 +0300 Subject: [PATCH 089/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 20 ++++++++++++-------- SwiftSignalKit/Queue.swift | 2 +- SwiftSignalKit/Signal.swift | 2 +- SwiftSignalKit/Signal_Catch.swift | 2 +- SwiftSignalKit/Signal_SideEffects.swift | 4 ++-- SwiftSignalKit/Signal_Take.swift | 2 +- SwiftSignalKit/Timer.swift | 4 ++-- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index dd98306bdd..d5427bb3e7 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -869,6 +869,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; @@ -876,7 +877,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_REFLECTION_METADATA_LEVEL = none; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = "Debug Hockeyapp"; }; @@ -898,6 +899,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; @@ -905,7 +907,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_REFLECTION_METADATA_LEVEL = none; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = "Release Hockeyapp"; }; @@ -1229,6 +1231,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; @@ -1236,7 +1239,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_REFLECTION_METADATA_LEVEL = none; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = "Release AppStore"; }; @@ -1286,7 +1289,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = "Debug Hockeyapp"; }; @@ -1317,7 +1320,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = "Release Hockeyapp"; }; @@ -1348,7 +1351,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = "Release AppStore"; }; @@ -1466,6 +1469,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; @@ -1473,7 +1477,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_REFLECTION_METADATA_LEVEL = none; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = "Debug AppStore"; }; @@ -1526,7 +1530,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = "Debug AppStore"; }; diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index 99e81ad66d..a527058bdf 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -85,7 +85,7 @@ public final class Queue { self.nativeQueue.async(group: nil, qos: qos, flags: [.enforceQoS], execute: f) } - public func after(_ delay: Double, _ f: @escaping(Void) -> Void) { + public func after(_ delay: Double, _ f: @escaping() -> 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 ea59ccd763..940ecc66c0 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -1,6 +1,6 @@ import Foundation -internal let doNothing: () -> Void = { _ in } +let doNothing: () -> Void = { } public typealias NoError = Void diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index b7b4a320a1..970145ca76 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -26,7 +26,7 @@ public func `catch`(_ f: @escaping(E) -> Signal) -> (Signal } } -private func recursiveFunction(_ f: @escaping(@escaping(Void) -> Void) -> Void) -> ((Void) -> Void) { +private func recursiveFunction(_ f: @escaping(@escaping() -> Void) -> Void) -> (() -> Void) { return { f(recursiveFunction(f)) } diff --git a/SwiftSignalKit/Signal_SideEffects.swift b/SwiftSignalKit/Signal_SideEffects.swift index f3f480f6a2..ca4987081a 100644 --- a/SwiftSignalKit/Signal_SideEffects.swift +++ b/SwiftSignalKit/Signal_SideEffects.swift @@ -75,7 +75,7 @@ public func afterCompleted(_ f: @escaping() -> Void) -> (Signal) -> } } -public func afterDisposed(_ f: @escaping(Void) -> R) -> (Signal) -> Signal { +public func afterDisposed(_ f: @escaping() -> R) -> (Signal) -> Signal { return { signal in return Signal { subscriber in let disposable = DisposableSet() @@ -95,7 +95,7 @@ public func afterDisposed(_ f: @escaping(Void) -> R) -> (Signal) } } -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 { +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 diff --git a/SwiftSignalKit/Signal_Take.swift b/SwiftSignalKit/Signal_Take.swift index 3a4eda1cee..a9f7edc8ca 100644 --- a/SwiftSignalKit/Signal_Take.swift +++ b/SwiftSignalKit/Signal_Take.swift @@ -35,7 +35,7 @@ public func last(signal: Signal) -> Signal { let _ = value.swap(next) }, error: { error in subscriber.putError(error) - }, completed: { completed in + }, completed: { subscriber.putNext(value.with({ $0 })) subscriber.putCompletion() }) diff --git a/SwiftSignalKit/Timer.swift b/SwiftSignalKit/Timer.swift index 08e495ec7e..83ae00e619 100644 --- a/SwiftSignalKit/Timer.swift +++ b/SwiftSignalKit/Timer.swift @@ -4,10 +4,10 @@ public final class Timer { private let timer = Atomic(value: nil) private let timeout: Double private let `repeat`: Bool - private let completion: (Void) -> Void + private let completion: () -> Void private let queue: Queue - public init(timeout: Double, `repeat`: Bool, completion: @escaping(Void) -> Void, queue: Queue) { + public init(timeout: Double, `repeat`: Bool, completion: @escaping() -> Void, queue: Queue) { self.timeout = timeout self.`repeat` = `repeat` self.completion = completion From 7d1ae890a0f95707b2acea641a57a91de538b2b7 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 26 Sep 2017 03:00:31 +0300 Subject: [PATCH 090/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index d5427bb3e7..5350accee7 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -869,7 +869,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; @@ -899,7 +899,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; @@ -1231,7 +1231,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; @@ -1469,7 +1469,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; From f9905d961d754e6f7c00b7738bdde4642bb7a00d Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 14 Nov 2017 20:40:02 +0300 Subject: [PATCH 091/122] no message --- SwiftSignalKit/Subscriber.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/SwiftSignalKit/Subscriber.swift b/SwiftSignalKit/Subscriber.swift index 70d5ed832d..956af6e8cc 100644 --- a/SwiftSignalKit/Subscriber.swift +++ b/SwiftSignalKit/Subscriber.swift @@ -100,11 +100,18 @@ public final class Subscriber { var disposeDisposable: Disposable? = nil + var next: ((T) -> Void)? + var error: ((E) -> Void)? + var completed: (() -> Void)? + pthread_mutex_lock(&self.lock) if !self.terminated { action = self.completed + next = self.next self.next = nil + error = self.error self.error = nil + completed = self.completed self.completed = nil self.terminated = true @@ -113,6 +120,16 @@ public final class Subscriber { } pthread_mutex_unlock(&self.lock) + if let next = next { + withExtendedLifetime(next, {}) + } + if let error = error { + withExtendedLifetime(error, {}) + } + if let completed = completed { + withExtendedLifetime(completed, {}) + } + if action != nil { action() } From de7493574377829286d0d5aee2f9468f80f72bad Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 9 Jan 2018 13:23:51 +0400 Subject: [PATCH 092/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 170 ++++++++++++++++++ SwiftSignalKit/Promise.swift | 3 + SwiftSignalKitTests/PerformanceTests.swift | 8 +- .../SwiftSignalKitBasicTests.swift | 22 +++ 4 files changed, 199 insertions(+), 4 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 5350accee7..bf3d47f44d 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -1262,6 +1262,170 @@ }; name = "Release AppStore"; }; + D0924FE21FE52C0A003F693F /* Release Hockeyapp Internal */ = { + 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 = "Release Hockeyapp Internal"; + }; + D0924FE31FE52C0A003F693F /* Release Hockeyapp Internal */ = { + 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 = "Release Hockeyapp Internal"; + }; + D0924FE41FE52C0A003F693F /* Release Hockeyapp Internal */ = { + 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 = "Release Hockeyapp Internal"; + }; + D0924FE51FE52C0A003F693F /* Release Hockeyapp Internal */ = { + 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"; + OTHER_SWIFT_FLAGS = ""; + 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 = 4.0; + }; + name = "Release Hockeyapp Internal"; + }; + D0924FE61FE52C0A003F693F /* Release Hockeyapp Internal */ = { + 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_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + }; + name = "Release Hockeyapp Internal"; + }; + D0924FE71FE52C0A003F693F /* Release Hockeyapp Internal */ = { + 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 = 4.0; + }; + name = "Release Hockeyapp Internal"; + }; D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1543,6 +1707,7 @@ D0085B361B282B9800EAF753 /* Debug Hockeyapp */, D0DB57B91E5C4B7A0071854C /* Debug AppStore */, D0085B371B282B9800EAF753 /* Release Hockeyapp */, + D0924FE51FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5771CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; @@ -1554,6 +1719,7 @@ D0085B391B282B9800EAF753 /* Debug Hockeyapp */, D0DB57BA1E5C4B7A0071854C /* Debug AppStore */, D0085B3A1B282B9800EAF753 /* Release Hockeyapp */, + D0924FE61FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5781CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; @@ -1565,6 +1731,7 @@ D0445DEC1A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B61E5C4B7A0071854C /* Debug AppStore */, D0445DED1A7C2CA500267924 /* Release Hockeyapp */, + D0924FE21FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5741CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; @@ -1576,6 +1743,7 @@ D0445DEF1A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B71E5C4B7A0071854C /* Debug AppStore */, D0445DF01A7C2CA500267924 /* Release Hockeyapp */, + D0924FE31FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5751CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; @@ -1587,6 +1755,7 @@ D0445DF21A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B81E5C4B7A0071854C /* Debug AppStore */, D0445DF31A7C2CA500267924 /* Release Hockeyapp */, + D0924FE41FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5761CC0117500F08284 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; @@ -1598,6 +1767,7 @@ D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */, D0DB57BB1E5C4B7A0071854C /* Debug AppStore */, D0B417F41D7DFA63004562A4 /* Release Hockeyapp */, + D0924FE71FE52C0A003F693F /* Release Hockeyapp Internal */, D0B417F51D7DFA63004562A4 /* Release AppStore */, ); defaultConfigurationIsVisible = 0; diff --git a/SwiftSignalKit/Promise.swift b/SwiftSignalKit/Promise.swift index 036e6f4fe4..6b3797a426 100644 --- a/SwiftSignalKit/Promise.swift +++ b/SwiftSignalKit/Promise.swift @@ -6,6 +6,8 @@ public final class Promise { private let disposable = MetaDisposable() private let subscribers = Bag<(T) -> Void>() + public var onDeinit: (() -> Void)? + public init(_ value: T) { self.value = value pthread_mutex_init(&self.lock, nil) @@ -16,6 +18,7 @@ public final class Promise { } deinit { + self.onDeinit?() pthread_mutex_destroy(&self.lock) self.disposable.dispose() } diff --git a/SwiftSignalKitTests/PerformanceTests.swift b/SwiftSignalKitTests/PerformanceTests.swift index 041c3b8654..313d02aacc 100644 --- a/SwiftSignalKitTests/PerformanceTests.swift +++ b/SwiftSignalKitTests/PerformanceTests.swift @@ -7,7 +7,7 @@ final class DisposableLock { private var action: (() -> Void)? private var lock = pthread_mutex_t() - init(action: () -> Void) { + init(action: @escaping () -> Void) { self.action = action pthread_mutex_init(&self.lock, nil) } @@ -28,7 +28,7 @@ final class DisposableSpinLock { private var action: (() -> Void)? private var lock = OSSpinLock() - init(action: () -> Void) { + init(action: @escaping () -> Void) { self.action = action } @@ -47,7 +47,7 @@ final class DisposableSpinLock { final class DisposableNoLock { private var action: (() -> Void)? - init(action: () -> Void) { + init(action: @escaping () -> Void) { self.action = action } @@ -65,7 +65,7 @@ final class DisposableAtomic { private var action: () -> Void private var disposed: Int32 = 0 - init(action: () -> Void) { + init(action: @escaping () -> Void) { self.action = action } diff --git a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift index 813e89f007..210a969ff9 100644 --- a/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift +++ b/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift @@ -256,4 +256,26 @@ class SwiftSignalKitTests: XCTestCase { XCTAssertTrue(deallocated2, "deallocated2 != true") XCTAssertTrue(disposed2, "disposed2 != true") } + + func testDelayed1() { + var flag = false + let signal = Signal, NoError> { subscriber in + Queue.concurrentDefaultQueue().after(0.1, { + subscriber.putNext(Signal { susbcriber2 in + return ActionDisposable { + flag = true + } + }) + }) + + return EmptyDisposable + } |> switchToLatest + + let disposable = signal.start() + disposable.dispose() + + usleep(1000000 * 20) + + XCTAssert(flag == true) + } } From d5f0e968029909c6f220fdb676a82218ad00e142 Mon Sep 17 00:00:00 2001 From: Peter Iakovlev Date: Fri, 2 Mar 2018 20:54:35 +0400 Subject: [PATCH 093/122] no message --- SwiftSignalKit/Signal_Dispatch.swift | 8 ++++---- SwiftSignalKit/ThreadPool.swift | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SwiftSignalKit/Signal_Dispatch.swift b/SwiftSignalKit/Signal_Dispatch.swift index c5ed6daaaa..2a921b2e37 100644 --- a/SwiftSignalKit/Signal_Dispatch.swift +++ b/SwiftSignalKit/Signal_Dispatch.swift @@ -30,19 +30,19 @@ public func deliverOn(_ threadPool: ThreadPool) -> (Signal) -> Signa let queue = threadPool.nextQueue() return signal.start(next: { next in queue.addTask(ThreadPoolTask { state in - if !state.cancelled { + if !state.cancelled.with { $0 } { subscriber.putNext(next) } }) }, error: { error in queue.addTask(ThreadPoolTask { state in - if !state.cancelled { + if !state.cancelled.with { $0 } { subscriber.putError(error) } }) }, completed: { queue.addTask(ThreadPoolTask { state in - if !state.cancelled { + if !state.cancelled.with { $0 } { subscriber.putCompletion() } }) @@ -97,7 +97,7 @@ public func runOn(_ threadPool: ThreadPool) -> (Signal) -> Signal(value: false) } public final class ThreadPoolTask { @@ -13,13 +13,13 @@ public final class ThreadPoolTask { } func execute() { - if !state.cancelled { + if !state.cancelled.with { $0 } { self.action(self.state) } } public func cancel() { - self.state.cancelled = true + let _ = self.state.cancelled.swap(true) } } From f999d178b0de65592c3a328c9076e1b76bac30e9 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 12 Mar 2018 22:52:52 +0400 Subject: [PATCH 094/122] no message --- SwiftSignalKit/Queue.swift | 6 +----- SwiftSignalKit/Subscriber.swift | 6 +++++- SwiftSignalKit/Timer.swift | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SwiftSignalKit/Queue.swift b/SwiftSignalKit/Queue.swift index a527058bdf..ba94f82405 100644 --- a/SwiftSignalKit/Queue.swift +++ b/SwiftSignalKit/Queue.swift @@ -39,16 +39,12 @@ public final class Queue { self.specialIsMainQueue = specialIsMainQueue } - public init(name: String? = nil, target: Queue? = nil, qos: DispatchQoS = .default) { + public init(name: String? = nil, qos: DispatchQoS = .default) { self.nativeQueue = DispatchQueue(label: name ?? "", qos: qos) self.specialIsMainQueue = false self.nativeQueue.setSpecific(key: QueueSpecificKey, value: self.specific) - - if let target = target { - //self.nativeQueue.setTarget(queue: target.nativeQueue) - } } public func isCurrent() -> Bool { diff --git a/SwiftSignalKit/Subscriber.swift b/SwiftSignalKit/Subscriber.swift index 956af6e8cc..bb5a68a08f 100644 --- a/SwiftSignalKit/Subscriber.swift +++ b/SwiftSignalKit/Subscriber.swift @@ -24,7 +24,11 @@ public final class Subscriber { self.disposable = nil } pthread_mutex_unlock(&self.lock) - freeDisposable = nil + if let freeDisposableValue = freeDisposable { + withExtendedLifetime(freeDisposableValue, { + }) + freeDisposable = nil + } pthread_mutex_destroy(&self.lock) } diff --git a/SwiftSignalKit/Timer.swift b/SwiftSignalKit/Timer.swift index 83ae00e619..d52aaae3ea 100644 --- a/SwiftSignalKit/Timer.swift +++ b/SwiftSignalKit/Timer.swift @@ -28,7 +28,7 @@ public final class Timer { } } }) - self.timer.modify { _ in + let _ = self.timer.modify { _ in return timer } @@ -44,7 +44,7 @@ public final class Timer { } public func invalidate() { - self.timer.modify { timer in + let _ = self.timer.modify { timer in timer?.cancel() return nil } From 9bf6dd191a9e82c7ef4a6b84947b18c41d0fa9e0 Mon Sep 17 00:00:00 2001 From: Peter Iakovlev Date: Wed, 4 Apr 2018 11:02:46 +0400 Subject: [PATCH 095/122] no message --- SwiftSignalKit/Signal.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index 940ecc66c0..1fbdf681e2 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -5,7 +5,7 @@ let doNothing: () -> Void = { } public typealias NoError = Void public func identity(a: A) -> A { - return a; + return a } precedencegroup PipeRight { From 405551472d88df2067d44fba976da0009301677d Mon Sep 17 00:00:00 2001 From: Mikhail Filimonov Date: Wed, 4 Apr 2018 12:07:30 +0400 Subject: [PATCH 096/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 2 +- SwiftSignalKit/Signal_Catch.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 5350accee7..10c5441a00 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -1288,7 +1288,7 @@ SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.0; }; name = "Debug Hockeyapp"; diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index 970145ca76..24a453a717 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -112,8 +112,8 @@ public func retry(_ delayIncrement: Double, maxDelay: Double, onQueue queu let delay = currentDelay.modify { value in return min(maxDelay, value + delayIncrement) } - - let time: DispatchTime = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) + + let time: DispatchTime = DispatchTime.now() + Double(delay) queue.queue.asyncAfter(deadline: time, execute: { recurse() }) From 3fc7e7357890dc0d6228ef4496598568515a9846 Mon Sep 17 00:00:00 2001 From: Peter Iakovlev Date: Sat, 21 Apr 2018 00:19:03 +0400 Subject: [PATCH 097/122] no message --- SSignalKit/SSignal+Combine.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SSignalKit/SSignal+Combine.m b/SSignalKit/SSignal+Combine.m index 5c636bba99..4df70c113d 100644 --- a/SSignalKit/SSignal+Combine.m +++ b/SSignalKit/SSignal+Combine.m @@ -172,6 +172,6 @@ return disposables; }]; -}; +} @end From 1ecaf8cf5f25b3d8c285cf1e20fde121d7f618c1 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 16 Jun 2018 20:02:35 +0300 Subject: [PATCH 098/122] no message --- SwiftSignalKit/QueueLocalObject.swift | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/SwiftSignalKit/QueueLocalObject.swift b/SwiftSignalKit/QueueLocalObject.swift index c542d2979d..c30d0f4bee 100644 --- a/SwiftSignalKit/QueueLocalObject.swift +++ b/SwiftSignalKit/QueueLocalObject.swift @@ -28,4 +28,26 @@ public final class QueueLocalObject { } } } + + public func syncWith(_ f: @escaping (T) -> R) -> R? { + var result: R? + self.queue.sync { + if let valueRef = self.valueRef { + let value = valueRef.takeUnretainedValue() + result = f(value) + } + } + return result + } + + public func signalWith(_ f: @escaping (T, Subscriber) -> Disposable) -> Signal { + return Signal { [weak self] subscriber in + if let strongSelf = self, let valueRef = strongSelf.valueRef { + let value = valueRef.takeUnretainedValue() + return f(value, subscriber) + } else { + return EmptyDisposable + } + } |> runOn(self.queue) + } } From bb0c514735aa3f1c82cf6e948cb6b21da5305a99 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 20 Jul 2018 17:55:32 +0300 Subject: [PATCH 099/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 6 ++++ SwiftSignalKit/Bag.swift | 23 ++++++++++++++ SwiftSignalKit/Signal_Loop.swift | 46 ++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 SwiftSignalKit/Signal_Loop.swift diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index bf3d47f44d..3b442447f6 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -86,6 +86,8 @@ 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 */; }; + D0467D1820D7F7BC0055C28F /* Signal_Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D1720D7F7BC0055C28F /* Signal_Loop.swift */; }; + D0467D1920D7F7BC0055C28F /* Signal_Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D1720D7F7BC0055C28F /* Signal_Loop.swift */; }; D053B4001F16881000E2D58A /* QueueLocalObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FF1F16881000E2D58A /* QueueLocalObject.swift */; }; D053B4011F16881000E2D58A /* QueueLocalObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D053B3FF1F16881000E2D58A /* QueueLocalObject.swift */; }; D05F09A81C9EF77100BB6F96 /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05F09A71C9EF77100BB6F96 /* Multicast.swift */; }; @@ -229,6 +231,7 @@ 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 = ""; }; + D0467D1720D7F7BC0055C28F /* Signal_Loop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signal_Loop.swift; sourceTree = ""; }; D053B3FF1F16881000E2D58A /* QueueLocalObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueueLocalObject.swift; 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 = ""; }; @@ -312,6 +315,7 @@ D0085B4B1B282BEE00EAF753 /* Signal.swift */, D0085B4C1B282BEE00EAF753 /* Disposable.swift */, D0085B4D1B282BEE00EAF753 /* Signal_Mapping.swift */, + D0467D1720D7F7BC0055C28F /* Signal_Loop.swift */, D0085B4E1B282BEE00EAF753 /* Subscriber.swift */, D07A5CFC1BBDE6E400451791 /* Promise.swift */, D05F09A71C9EF77100BB6F96 /* Multicast.swift */, @@ -737,6 +741,7 @@ D0085B541B282BEE00EAF753 /* Timer.swift in Sources */, D0085B5B1B282BEE00EAF753 /* Signal_Meta.swift in Sources */, D0085B571B282BEE00EAF753 /* Bag.swift in Sources */, + D0467D1820D7F7BC0055C28F /* Signal_Loop.swift in Sources */, D0085B5A1B282BEE00EAF753 /* Signal_Single.swift in Sources */, D053B4001F16881000E2D58A /* QueueLocalObject.swift in Sources */, D0085B611B282BEE00EAF753 /* Signal_Mapping.swift in Sources */, @@ -824,6 +829,7 @@ D0B418061D7DFAAB004562A4 /* Signal_Materialize.swift in Sources */, D0B418071D7DFAAB004562A4 /* Signal.swift in Sources */, D0B418081D7DFAAB004562A4 /* Disposable.swift in Sources */, + D0467D1920D7F7BC0055C28F /* Signal_Loop.swift in Sources */, D0B418091D7DFAAB004562A4 /* Signal_Mapping.swift in Sources */, D053B4011F16881000E2D58A /* QueueLocalObject.swift in Sources */, D0B4180A1D7DFAAB004562A4 /* Subscriber.swift in Sources */, diff --git a/SwiftSignalKit/Bag.swift b/SwiftSignalKit/Bag.swift index cb3d771446..08d5aef3a4 100644 --- a/SwiftSignalKit/Bag.swift +++ b/SwiftSignalKit/Bag.swift @@ -72,3 +72,26 @@ public final class Bag { } } } + +public final class CounterBag { + private var nextIndex: Int = 1 + private var items = Set() + + public init() { + } + + public func add() -> Int { + let index = self.nextIndex + self.nextIndex += 1 + self.items.insert(index) + return index + } + + public func remove(_ index: Int) { + self.items.remove(index) + } + + public var isEmpty: Bool { + return self.items.isEmpty + } +} diff --git a/SwiftSignalKit/Signal_Loop.swift b/SwiftSignalKit/Signal_Loop.swift new file mode 100644 index 0000000000..3ae92898a8 --- /dev/null +++ b/SwiftSignalKit/Signal_Loop.swift @@ -0,0 +1,46 @@ +import Foundation + +public enum SignalFeedbackLoopState { + case initial + case loop(T) +} + +public func feedbackLoop(once: @escaping (SignalFeedbackLoopState) -> Signal?, reduce: @escaping (R1, R1) -> R1) -> Signal { + return Signal { subscriber in + let currentDisposable = MetaDisposable() + + let state = Atomic(value: nil) + + var loopAgain: (() -> Void)? + + let loopOnce: (MetaDisposable?) -> Void = { disposable in + if let signal = once(.initial) { + disposable?.set(signal.start(next: { next in + let _ = state.modify { value in + if let value = value { + return reduce(value, next) + } else { + return value + } + } + }, error: { error in + subscriber.putError(error) + }, completed: { + loopAgain?() + })) + } else { + subscriber.putCompletion() + } + } + + loopAgain = { [weak currentDisposable] in + loopOnce(currentDisposable) + } + + loopOnce(currentDisposable) + + return ActionDisposable { + currentDisposable.dispose() + } + } +} From 247c0ba62181727a2fd1028ec1ba6f8334007ac8 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 14 Aug 2018 14:06:54 +0300 Subject: [PATCH 100/122] no message --- SwiftSignalKit/Signal.swift | 6 +++++- SwiftSignalKit/Signal_Mapping.swift | 13 +++++++++++++ SwiftSignalKit/ValuePipe.swift | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/SwiftSignalKit/Signal.swift b/SwiftSignalKit/Signal.swift index 1fbdf681e2..1bedb501ce 100644 --- a/SwiftSignalKit/Signal.swift +++ b/SwiftSignalKit/Signal.swift @@ -2,7 +2,11 @@ import Foundation let doNothing: () -> Void = { } -public typealias NoError = Void +public enum NoValue { +} + +public enum NoError { +} public func identity(a: A) -> A { return a diff --git a/SwiftSignalKit/Signal_Mapping.swift b/SwiftSignalKit/Signal_Mapping.swift index c67a4ae44f..6ea8f10fa7 100644 --- a/SwiftSignalKit/Signal_Mapping.swift +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -44,6 +44,19 @@ public func mapError(_ f: @escaping(E) -> R) -> (Signal) -> Signa } } +public func introduceError(_ type: E.Type) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { _ in + }, completed: { + subscriber.putCompletion() + }) + } + } +} + private class DistinctUntilChangedContext { var value: T? } diff --git a/SwiftSignalKit/ValuePipe.swift b/SwiftSignalKit/ValuePipe.swift index f36f56ee70..31b157435d 100644 --- a/SwiftSignalKit/ValuePipe.swift +++ b/SwiftSignalKit/ValuePipe.swift @@ -6,7 +6,7 @@ public final class ValuePipe { public init() { } - public func signal() -> Signal { + public func signal() -> Signal { return Signal { [weak self] subscriber in if let strongSelf = self { let index = strongSelf.subscribers.with { value -> Bag.Index in From d18eae793605a0a85d31ce5f972d802c2252ea78 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 31 Aug 2018 04:25:51 +0300 Subject: [PATCH 101/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 185 +++++++++++++++++++++++++++ SwiftSignalKit/Signal_Meta.swift | 10 ++ 2 files changed, 195 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 3b442447f6..fb2183c3c7 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -1432,6 +1432,185 @@ }; name = "Release Hockeyapp Internal"; }; + D0ADF92E212B3AD400310BBC /* Debug AppStore LLC */ = { + 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 = NO; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + 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", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + 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 = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = "Debug AppStore LLC"; + }; + D0ADF92F212B3AD400310BBC /* Debug AppStore LLC */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + 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; + 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 AppStore LLC"; + }; + D0ADF930212B3AD400310BBC /* Debug AppStore LLC */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(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 = "Debug AppStore LLC"; + }; + D0ADF931212B3AD400310BBC /* Debug AppStore LLC */ = { + 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", + "$(inherited)", + ); + 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"; + OTHER_SWIFT_FLAGS = ""; + 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 = 4.0; + }; + name = "Debug AppStore LLC"; + }; + D0ADF932212B3AD400310BBC /* Debug AppStore LLC */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + 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 = "Debug AppStore LLC"; + }; + D0ADF933212B3AD400310BBC /* Debug AppStore LLC */ = { + 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 = 4.0; + }; + name = "Debug AppStore LLC"; + }; D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1712,6 +1891,7 @@ buildConfigurations = ( D0085B361B282B9800EAF753 /* Debug Hockeyapp */, D0DB57B91E5C4B7A0071854C /* Debug AppStore */, + D0ADF931212B3AD400310BBC /* Debug AppStore LLC */, D0085B371B282B9800EAF753 /* Release Hockeyapp */, D0924FE51FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5771CC0117500F08284 /* Release AppStore */, @@ -1724,6 +1904,7 @@ buildConfigurations = ( D0085B391B282B9800EAF753 /* Debug Hockeyapp */, D0DB57BA1E5C4B7A0071854C /* Debug AppStore */, + D0ADF932212B3AD400310BBC /* Debug AppStore LLC */, D0085B3A1B282B9800EAF753 /* Release Hockeyapp */, D0924FE61FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5781CC0117500F08284 /* Release AppStore */, @@ -1736,6 +1917,7 @@ buildConfigurations = ( D0445DEC1A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B61E5C4B7A0071854C /* Debug AppStore */, + D0ADF92E212B3AD400310BBC /* Debug AppStore LLC */, D0445DED1A7C2CA500267924 /* Release Hockeyapp */, D0924FE21FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5741CC0117500F08284 /* Release AppStore */, @@ -1748,6 +1930,7 @@ buildConfigurations = ( D0445DEF1A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B71E5C4B7A0071854C /* Debug AppStore */, + D0ADF92F212B3AD400310BBC /* Debug AppStore LLC */, D0445DF01A7C2CA500267924 /* Release Hockeyapp */, D0924FE31FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5751CC0117500F08284 /* Release AppStore */, @@ -1760,6 +1943,7 @@ buildConfigurations = ( D0445DF21A7C2CA500267924 /* Debug Hockeyapp */, D0DB57B81E5C4B7A0071854C /* Debug AppStore */, + D0ADF930212B3AD400310BBC /* Debug AppStore LLC */, D0445DF31A7C2CA500267924 /* Release Hockeyapp */, D0924FE41FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5761CC0117500F08284 /* Release AppStore */, @@ -1772,6 +1956,7 @@ buildConfigurations = ( D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */, D0DB57BB1E5C4B7A0071854C /* Debug AppStore */, + D0ADF933212B3AD400310BBC /* Debug AppStore LLC */, D0B417F41D7DFA63004562A4 /* Release Hockeyapp */, D0924FE71FE52C0A003F693F /* Release Hockeyapp Internal */, D0B417F51D7DFA63004562A4 /* Release AppStore */, diff --git a/SwiftSignalKit/Signal_Meta.swift b/SwiftSignalKit/Signal_Meta.swift index 5d4c61b04e..78c511eb10 100644 --- a/SwiftSignalKit/Signal_Meta.swift +++ b/SwiftSignalKit/Signal_Meta.swift @@ -177,6 +177,16 @@ public func mapToSignal(_ f: @escaping(T) -> Signal) -> (Signal(_ signal: Signal) -> Signal { + return Signal { subscriber in + return signal.start(error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } +} + public func mapToSignalPromotingError(_ f: @escaping(T) -> Signal) -> (Signal) -> Signal { return { signal -> Signal in return Signal, E> { subscriber in From 6863422e3b249d1eb1a6f8c480a146c585cd7377 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 5 Sep 2018 00:29:52 +0300 Subject: [PATCH 102/122] no message --- SSignalKit.xcodeproj/project.pbxproj | 169 +++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index fb2183c3c7..ad17edf295 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -1704,6 +1704,169 @@ }; name = "Release AppStore"; }; + D0CE6EEF213DC30100BCD44B /* Release AppStore LLC */ = { + 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 = "Release AppStore LLC"; + }; + D0CE6EF0213DC30100BCD44B /* Release AppStore LLC */ = { + 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 = "Release AppStore LLC"; + }; + D0CE6EF1213DC30100BCD44B /* Release AppStore LLC */ = { + 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 = "Release AppStore LLC"; + }; + D0CE6EF2213DC30100BCD44B /* Release AppStore LLC */ = { + 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"; + OTHER_SWIFT_FLAGS = ""; + 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 = 4.0; + }; + name = "Release AppStore LLC"; + }; + D0CE6EF3213DC30100BCD44B /* Release AppStore LLC */ = { + 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 = "Release AppStore LLC"; + }; + D0CE6EF4213DC30100BCD44B /* Release AppStore LLC */ = { + 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 = 4.0; + }; + name = "Release AppStore LLC"; + }; D0DB57B61E5C4B7A0071854C /* Debug AppStore */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1895,6 +2058,7 @@ D0085B371B282B9800EAF753 /* Release Hockeyapp */, D0924FE51FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5771CC0117500F08284 /* Release AppStore */, + D0CE6EF2213DC30100BCD44B /* Release AppStore LLC */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "Release Hockeyapp"; @@ -1908,6 +2072,7 @@ D0085B3A1B282B9800EAF753 /* Release Hockeyapp */, D0924FE61FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5781CC0117500F08284 /* Release AppStore */, + D0CE6EF3213DC30100BCD44B /* Release AppStore LLC */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "Release Hockeyapp"; @@ -1921,6 +2086,7 @@ D0445DED1A7C2CA500267924 /* Release Hockeyapp */, D0924FE21FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5741CC0117500F08284 /* Release AppStore */, + D0CE6EEF213DC30100BCD44B /* Release AppStore LLC */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "Release Hockeyapp"; @@ -1934,6 +2100,7 @@ D0445DF01A7C2CA500267924 /* Release Hockeyapp */, D0924FE31FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5751CC0117500F08284 /* Release AppStore */, + D0CE6EF0213DC30100BCD44B /* Release AppStore LLC */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "Release Hockeyapp"; @@ -1947,6 +2114,7 @@ D0445DF31A7C2CA500267924 /* Release Hockeyapp */, D0924FE41FE52C0A003F693F /* Release Hockeyapp Internal */, D086A5761CC0117500F08284 /* Release AppStore */, + D0CE6EF1213DC30100BCD44B /* Release AppStore LLC */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "Release Hockeyapp"; @@ -1960,6 +2128,7 @@ D0B417F41D7DFA63004562A4 /* Release Hockeyapp */, D0924FE71FE52C0A003F693F /* Release Hockeyapp Internal */, D0B417F51D7DFA63004562A4 /* Release AppStore */, + D0CE6EF4213DC30100BCD44B /* Release AppStore LLC */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = "Release Hockeyapp"; From 3727d4176a0a47953889638a1f9a78aa5e0573df Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 11 Sep 2018 00:43:08 +0300 Subject: [PATCH 103/122] no message --- SwiftSignalKit/Signal_Combine.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index 28605ac3ef..e73897e549 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -112,6 +112,12 @@ public func combineLatest(_ s1: Signal, _ s2: Sign }, initialValues: [:]) } +public func combineLatest(_ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal, _ s6: Signal) -> Signal<(T1, T2, T3, T4, T5, T6), E> { + return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6)], combine: { values in + return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6) + }, initialValues: [:]) +} + public func combineLatest(_ signals: [Signal]) -> Signal<[T], E> { if signals.count == 0 { return single([T](), E.self) From 7c9b33e112f0205a00ac03cba35f9919d5549af7 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 20 Sep 2018 00:12:02 +0100 Subject: [PATCH 104/122] no message --- SwiftSignalKit/Signal_Mapping.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/SwiftSignalKit/Signal_Mapping.swift b/SwiftSignalKit/Signal_Mapping.swift index 6ea8f10fa7..d8a1b3cc5b 100644 --- a/SwiftSignalKit/Signal_Mapping.swift +++ b/SwiftSignalKit/Signal_Mapping.swift @@ -30,6 +30,22 @@ public func filter(_ f: @escaping(T) -> Bool) -> (Signal) -> Signal< } } +public func flatMap(_ f: @escaping (T) -> R?) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + if let value = f(next) { + subscriber.putNext(value) + } + }, 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 From 2018787b8f81902ff3561ebf08a0422e06e8e687 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Sat, 6 Oct 2018 01:17:32 +0400 Subject: [PATCH 105/122] no message --- SwiftSignalKit/Signal_Combine.swift | 40 +++++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index e73897e549..3dadd8cb12 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: @escaping([Any]) -> R, initialValues: [Int : Any]) -> Signal { +private func combineLatestAny(_ signals: [Signal], combine: @escaping([Any]) -> R, initialValues: [Int : Any], queue: Queue?) -> Signal { return Signal { subscriber in let state = Atomic(value: SignalCombineState(values: initialValues, completed: Set(), error: false)) let disposable = DisposableSet() @@ -20,8 +20,14 @@ private func combineLatestAny(_ signals: [Signal], combine: @escap } let count = signals.count - for index in 0 ..< count { - let signalDisposable = signals[index].start(next: { next in + for iterationIndex in 0 ..< count { + let index = iterationIndex + var signal = signals[index] + if let queue = queue { + signal = signal + |> deliverOn(queue) + } + let signalDisposable = signal.start(next: { next in let currentState = state.modify { current in var values = current.values values[index] = next @@ -82,43 +88,43 @@ private func signalOfAny(_ signal: Signal) -> Signal { } } -public func combineLatest(_ s1: Signal, _ s2: Signal) -> Signal<(T1, T2), E> { +public func combineLatest(queue: Queue? = nil, _ 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: [:]) + }, initialValues: [:], queue: queue) } -public func combineLatest(_ s1: Signal, _ v1: T1, _ s2: Signal, _ v2: T2) -> Signal<(T1, T2), E> { +public func combineLatest(queue: Queue? = nil, _ 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]) + }, initialValues: [0: v1, 1: v2], queue: queue) } -public func combineLatest(_ s1: Signal, _ s2: Signal, _ s3: Signal) -> Signal<(T1, T2, T3), E> { +public func combineLatest(queue: Queue? = nil, _ 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: [:]) + }, initialValues: [:], queue: queue) } -public func combineLatest(_ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal) -> Signal<(T1, T2, T3, T4), E> { +public func combineLatest(queue: Queue? = nil, _ 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: [:]) + }, initialValues: [:], queue: queue) } -public func combineLatest(_ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal) -> Signal<(T1, T2, T3, T4, T5), E> { +public func combineLatest(queue: Queue? = nil, _ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal) -> Signal<(T1, T2, T3, T4, T5), E> { return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5)], combine: { values in return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5) - }, initialValues: [:]) + }, initialValues: [:], queue: queue) } -public func combineLatest(_ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal, _ s6: Signal) -> Signal<(T1, T2, T3, T4, T5, T6), E> { +public func combineLatest(queue: Queue? = nil, _ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal, _ s6: Signal) -> Signal<(T1, T2, T3, T4, T5, T6), E> { return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6)], combine: { values in return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6) - }, initialValues: [:]) + }, initialValues: [:], queue: queue) } -public func combineLatest(_ signals: [Signal]) -> Signal<[T], E> { +public func combineLatest(queue: Queue? = nil, _ signals: [Signal]) -> Signal<[T], E> { if signals.count == 0 { return single([T](), E.self) } @@ -129,5 +135,5 @@ public func combineLatest(_ signals: [Signal]) -> Signal<[T], E> { combined.append(value as! T) } return combined - }, initialValues: [:]) + }, initialValues: [:], queue: queue) } From 6ee7fd329774283f6949e31d4024835cc1e91de7 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 16 Oct 2018 20:18:17 +0300 Subject: [PATCH 106/122] no message --- SwiftSignalKit/Signal_Timing.swift | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/SwiftSignalKit/Signal_Timing.swift b/SwiftSignalKit/Signal_Timing.swift index dc5316be60..a96fbbae6f 100644 --- a/SwiftSignalKit/Signal_Timing.swift +++ b/SwiftSignalKit/Signal_Timing.swift @@ -28,6 +28,58 @@ public func delay(_ timeout: Double, queue: Queue) -> (_ signal: Signal(_ timeout: Double, granularity: Double = 4.0, queue: Queue) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + let disposable = MetaDisposable() + queue.async { + let beginTimestamp = CFAbsoluteTimeGetCurrent() + + let startFinalTimer: () -> Void = { + let finalTimeout = beginTimestamp + timeout - CFAbsoluteTimeGetCurrent() + let timer = Timer(timeout: max(0.0, finalTimeout), 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 { + queue.async { + timer.invalidate() + } + }) + timer.start() + } + + var invalidateImpl: (() -> Void)? + let timer = Timer(timeout: granularity, repeat: true, completion: { + let currentTimestamp = CFAbsoluteTimeGetCurrent() + if beginTimestamp + timeout >= currentTimestamp - granularity * 1.1 { + invalidateImpl?() + startFinalTimer() + } + }, queue: queue) + + invalidateImpl = { + queue.async { + timer.invalidate() + } + } + + disposable.set(ActionDisposable { + invalidateImpl?() + }) + + timer.start() + } + return disposable + } + } +} + public func timeout(_ timeout: Double, queue: Queue, alternate: Signal) -> (Signal) -> Signal { return { signal in return Signal { subscriber in From f1b83b806916bfb498f3bf8321ddf971fa9b1732 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 18 Oct 2018 20:40:43 +0300 Subject: [PATCH 107/122] no message --- SwiftSignalKit/Promise.swift | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/SwiftSignalKit/Promise.swift b/SwiftSignalKit/Promise.swift index 6b3797a426..4888ec34d7 100644 --- a/SwiftSignalKit/Promise.swift +++ b/SwiftSignalKit/Promise.swift @@ -1,6 +1,7 @@ import Foundation public final class Promise { + private var initializeOnFirstAccess: Signal? private var value: T? private var lock = pthread_mutex_t() private let disposable = MetaDisposable() @@ -8,6 +9,11 @@ public final class Promise { public var onDeinit: (() -> Void)? + public init(initializeOnFirstAccess: Signal?) { + self.initializeOnFirstAccess = initializeOnFirstAccess + pthread_mutex_init(&self.lock, nil) + } + public init(_ value: T) { self.value = value pthread_mutex_init(&self.lock, nil) @@ -45,16 +51,24 @@ public final class Promise { public func get() -> Signal { return Signal { subscriber in pthread_mutex_lock(&self.lock) + var initializeOnFirstAccessNow: Signal? + if let initializeOnFirstAccess = self.initializeOnFirstAccess { + initializeOnFirstAccessNow = initializeOnFirstAccess + self.initializeOnFirstAccess = nil + } 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) } + + if let initializeOnFirstAccessNow = initializeOnFirstAccessNow { + self.set(initializeOnFirstAccessNow) + } return ActionDisposable { pthread_mutex_lock(&self.lock) From 4e14104f3c8015d490c255a47a247e1b65272aa6 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Fri, 19 Oct 2018 20:29:41 +0300 Subject: [PATCH 108/122] Fixed background aware timer --- SwiftSignalKit/Signal_Timing.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftSignalKit/Signal_Timing.swift b/SwiftSignalKit/Signal_Timing.swift index a96fbbae6f..a74b536808 100644 --- a/SwiftSignalKit/Signal_Timing.swift +++ b/SwiftSignalKit/Signal_Timing.swift @@ -57,7 +57,7 @@ public func suspendAwareDelay(_ timeout: Double, granularity: Double = 4.0 var invalidateImpl: (() -> Void)? let timer = Timer(timeout: granularity, repeat: true, completion: { let currentTimestamp = CFAbsoluteTimeGetCurrent() - if beginTimestamp + timeout >= currentTimestamp - granularity * 1.1 { + if beginTimestamp + timeout - granularity * 1.1 <= currentTimestamp { invalidateImpl?() startFinalTimer() } From 4dcea52369531aff1fc16a5bf67cb1a79037df66 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Wed, 7 Nov 2018 02:00:58 +0400 Subject: [PATCH 109/122] Added take(until:) --- SwiftSignalKit/Signal_Take.swift | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/SwiftSignalKit/Signal_Take.swift b/SwiftSignalKit/Signal_Take.swift index a9f7edc8ca..99ac5bbce1 100644 --- a/SwiftSignalKit/Signal_Take.swift +++ b/SwiftSignalKit/Signal_Take.swift @@ -28,6 +28,36 @@ public func take(_ count: Int) -> (Signal) -> Signal { } } +public struct SignalTakeAction { + public let passthrough: Bool + public let complete: Bool + + public init(passthrough: Bool, complete: Bool) { + self.passthrough = passthrough + self.complete = complete + } +} + +public func take(until: @escaping (T) -> SignalTakeAction) -> (Signal) -> Signal { + return { signal in + return Signal { subscriber in + return signal.start(next: { next in + let action = until(next) + if action.passthrough { + subscriber.putNext(next) + } + if action.complete { + subscriber.putCompletion() + } + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } + } +} + public func last(signal: Signal) -> Signal { return Signal { subscriber in let value = Atomic(value: nil) From 0d11d05e0c35fd61ee34fc3ec4c51834dd6897d5 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Mon, 12 Nov 2018 22:59:27 +0400 Subject: [PATCH 110/122] no message --- SwiftSignalKit/Signal_Timing.swift | 40 ++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/SwiftSignalKit/Signal_Timing.swift b/SwiftSignalKit/Signal_Timing.swift index a74b536808..427205f8b6 100644 --- a/SwiftSignalKit/Signal_Timing.swift +++ b/SwiftSignalKit/Signal_Timing.swift @@ -54,26 +54,30 @@ public func suspendAwareDelay(_ timeout: Double, granularity: Double = 4.0 timer.start() } - var invalidateImpl: (() -> Void)? - let timer = Timer(timeout: granularity, repeat: true, completion: { - let currentTimestamp = CFAbsoluteTimeGetCurrent() - if beginTimestamp + timeout - granularity * 1.1 <= currentTimestamp { + if timeout <= granularity * 1.1 { + startFinalTimer() + } else { + var invalidateImpl: (() -> Void)? + let timer = Timer(timeout: granularity, repeat: true, completion: { + let currentTimestamp = CFAbsoluteTimeGetCurrent() + if beginTimestamp + timeout - granularity * 1.1 <= currentTimestamp { + invalidateImpl?() + startFinalTimer() + } + }, queue: queue) + + invalidateImpl = { + queue.async { + timer.invalidate() + } + } + + disposable.set(ActionDisposable { invalidateImpl?() - startFinalTimer() - } - }, queue: queue) - - invalidateImpl = { - queue.async { - timer.invalidate() - } + }) + + timer.start() } - - disposable.set(ActionDisposable { - invalidateImpl?() - }) - - timer.start() } return disposable } From 2c2da8f6113fef7f69eb929980f332c35bf5d877 Mon Sep 17 00:00:00 2001 From: Peter Iakovlev Date: Wed, 14 Nov 2018 23:00:20 +0400 Subject: [PATCH 111/122] Added .gitignore --- .gitignore | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index f86224615d..249d3670f3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -# Xcode -# -build/ +fastlane/README.md +fastlane/report.xml +fastlane/test_output/* *.pbxuser !default.pbxuser *.mode1v3 @@ -11,9 +11,14 @@ build/ !default.perspectivev3 xcuserdata *.xccheckout +*.xcscmblueprint *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate - +.DS_Store +*.dSYM +*.dSYM.zip +*.ipa +*/xcuserdata/* From 3e1a2d11905e58e12d91100d0aea2944b6804f53 Mon Sep 17 00:00:00 2001 From: Peter Iakovlev Date: Wed, 14 Nov 2018 23:57:25 +0400 Subject: [PATCH 112/122] Updated project --- SSignalKit.xcodeproj/project.pbxproj | 185 +++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index ad17edf295..500ee69658 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -959,6 +959,185 @@ }; name = "Release Hockeyapp"; }; + D021D502219CB1D90064BEBA /* Debug Fork */ = { + 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 = NO; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + 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", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + 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 = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = "Debug Fork"; + }; + D021D503219CB1D90064BEBA /* Debug Fork */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + 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; + 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 Fork"; + }; + D021D504219CB1D90064BEBA /* Debug Fork */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(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 = "Debug Fork"; + }; + D021D505219CB1D90064BEBA /* Debug Fork */ = { + 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", + "$(inherited)", + ); + 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"; + OTHER_SWIFT_FLAGS = ""; + 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 = 4.0; + }; + name = "Debug Fork"; + }; + D021D506219CB1D90064BEBA /* Debug Fork */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + 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 = "Debug Fork"; + }; + D021D507219CB1D90064BEBA /* Debug Fork */ = { + 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 = 4.0; + }; + name = "Debug Fork"; + }; D0445DEC1A7C2CA500267924 /* Debug Hockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2053,6 +2232,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0085B361B282B9800EAF753 /* Debug Hockeyapp */, + D021D505219CB1D90064BEBA /* Debug Fork */, D0DB57B91E5C4B7A0071854C /* Debug AppStore */, D0ADF931212B3AD400310BBC /* Debug AppStore LLC */, D0085B371B282B9800EAF753 /* Release Hockeyapp */, @@ -2067,6 +2247,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0085B391B282B9800EAF753 /* Debug Hockeyapp */, + D021D506219CB1D90064BEBA /* Debug Fork */, D0DB57BA1E5C4B7A0071854C /* Debug AppStore */, D0ADF932212B3AD400310BBC /* Debug AppStore LLC */, D0085B3A1B282B9800EAF753 /* Release Hockeyapp */, @@ -2081,6 +2262,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0445DEC1A7C2CA500267924 /* Debug Hockeyapp */, + D021D502219CB1D90064BEBA /* Debug Fork */, D0DB57B61E5C4B7A0071854C /* Debug AppStore */, D0ADF92E212B3AD400310BBC /* Debug AppStore LLC */, D0445DED1A7C2CA500267924 /* Release Hockeyapp */, @@ -2095,6 +2277,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0445DEF1A7C2CA500267924 /* Debug Hockeyapp */, + D021D503219CB1D90064BEBA /* Debug Fork */, D0DB57B71E5C4B7A0071854C /* Debug AppStore */, D0ADF92F212B3AD400310BBC /* Debug AppStore LLC */, D0445DF01A7C2CA500267924 /* Release Hockeyapp */, @@ -2109,6 +2292,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0445DF21A7C2CA500267924 /* Debug Hockeyapp */, + D021D504219CB1D90064BEBA /* Debug Fork */, D0DB57B81E5C4B7A0071854C /* Debug AppStore */, D0ADF930212B3AD400310BBC /* Debug AppStore LLC */, D0445DF31A7C2CA500267924 /* Release Hockeyapp */, @@ -2123,6 +2307,7 @@ isa = XCConfigurationList; buildConfigurations = ( D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */, + D021D507219CB1D90064BEBA /* Debug Fork */, D0DB57BB1E5C4B7A0071854C /* Debug AppStore */, D0ADF933212B3AD400310BBC /* Debug AppStore LLC */, D0B417F41D7DFA63004562A4 /* Release Hockeyapp */, From f5cb1bb7ec6afc3aff73cd4927a7db4212b79b95 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 11 Dec 2018 21:58:41 +0400 Subject: [PATCH 113/122] Update project --- SSignalKit.xcodeproj/project.pbxproj | 300 +++++++++++++-------------- 1 file changed, 150 insertions(+), 150 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index 500ee69658..ec4eff682d 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -855,7 +855,7 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - D0085B361B282B9800EAF753 /* Debug Hockeyapp */ = { + D0085B361B282B9800EAF753 /* DebugHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -885,9 +885,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 4.0; }; - name = "Debug Hockeyapp"; + name = DebugHockeyapp; }; - D0085B371B282B9800EAF753 /* Release Hockeyapp */ = { + D0085B371B282B9800EAF753 /* ReleaseHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -915,9 +915,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 4.0; }; - name = "Release Hockeyapp"; + name = ReleaseHockeyapp; }; - D0085B391B282B9800EAF753 /* Debug Hockeyapp */ = { + D0085B391B282B9800EAF753 /* DebugHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -937,9 +937,9 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; - name = "Debug Hockeyapp"; + name = DebugHockeyapp; }; - D0085B3A1B282B9800EAF753 /* Release Hockeyapp */ = { + D0085B3A1B282B9800EAF753 /* ReleaseHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; @@ -957,9 +957,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; - name = "Release Hockeyapp"; + name = ReleaseHockeyapp; }; - D021D502219CB1D90064BEBA /* Debug Fork */ = { + D021D502219CB1D90064BEBA /* DebugFork */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1005,9 +1005,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = "Debug Fork"; + name = DebugFork; }; - D021D503219CB1D90064BEBA /* Debug Fork */ = { + D021D503219CB1D90064BEBA /* DebugFork */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1027,9 +1027,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = "Debug Fork"; + name = DebugFork; }; - D021D504219CB1D90064BEBA /* Debug Fork */ = { + D021D504219CB1D90064BEBA /* DebugFork */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1051,9 +1051,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = "Debug Fork"; + name = DebugFork; }; - D021D505219CB1D90064BEBA /* Debug Fork */ = { + D021D505219CB1D90064BEBA /* DebugFork */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1083,9 +1083,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 4.0; }; - name = "Debug Fork"; + name = DebugFork; }; - D021D506219CB1D90064BEBA /* Debug Fork */ = { + D021D506219CB1D90064BEBA /* DebugFork */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -1105,9 +1105,9 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; - name = "Debug Fork"; + name = DebugFork; }; - D021D507219CB1D90064BEBA /* Debug Fork */ = { + D021D507219CB1D90064BEBA /* DebugFork */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1136,9 +1136,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; }; - name = "Debug Fork"; + name = DebugFork; }; - D0445DEC1A7C2CA500267924 /* Debug Hockeyapp */ = { + D0445DEC1A7C2CA500267924 /* DebugHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1184,9 +1184,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = "Debug Hockeyapp"; + name = DebugHockeyapp; }; - D0445DED1A7C2CA500267924 /* Release Hockeyapp */ = { + D0445DED1A7C2CA500267924 /* ReleaseHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1225,9 +1225,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = "Release Hockeyapp"; + name = ReleaseHockeyapp; }; - D0445DEF1A7C2CA500267924 /* Debug Hockeyapp */ = { + D0445DEF1A7C2CA500267924 /* DebugHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1247,9 +1247,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = "Debug Hockeyapp"; + name = DebugHockeyapp; }; - D0445DF01A7C2CA500267924 /* Release Hockeyapp */ = { + D0445DF01A7C2CA500267924 /* ReleaseHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1269,9 +1269,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = "Release Hockeyapp"; + name = ReleaseHockeyapp; }; - D0445DF21A7C2CA500267924 /* Debug Hockeyapp */ = { + D0445DF21A7C2CA500267924 /* DebugHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1293,9 +1293,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = "Debug Hockeyapp"; + name = DebugHockeyapp; }; - D0445DF31A7C2CA500267924 /* Release Hockeyapp */ = { + D0445DF31A7C2CA500267924 /* ReleaseHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1313,9 +1313,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = "Release Hockeyapp"; + name = ReleaseHockeyapp; }; - D086A5741CC0117500F08284 /* Release AppStore */ = { + D086A5741CC0117500F08284 /* ReleaseAppStore */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1354,9 +1354,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = "Release AppStore"; + name = ReleaseAppStore; }; - D086A5751CC0117500F08284 /* Release AppStore */ = { + D086A5751CC0117500F08284 /* ReleaseAppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1376,9 +1376,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = "Release AppStore"; + name = ReleaseAppStore; }; - D086A5761CC0117500F08284 /* Release AppStore */ = { + D086A5761CC0117500F08284 /* ReleaseAppStore */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1396,9 +1396,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = "Release AppStore"; + name = ReleaseAppStore; }; - D086A5771CC0117500F08284 /* Release AppStore */ = { + D086A5771CC0117500F08284 /* ReleaseAppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1426,9 +1426,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 4.0; }; - name = "Release AppStore"; + name = ReleaseAppStore; }; - D086A5781CC0117500F08284 /* Release AppStore */ = { + D086A5781CC0117500F08284 /* ReleaseAppStore */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; @@ -1445,9 +1445,9 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; - name = "Release AppStore"; + name = ReleaseAppStore; }; - D0924FE21FE52C0A003F693F /* Release Hockeyapp Internal */ = { + D0924FE21FE52C0A003F693F /* ReleaseHockeyappInternal */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1486,9 +1486,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = "Release Hockeyapp Internal"; + name = ReleaseHockeyappInternal; }; - D0924FE31FE52C0A003F693F /* Release Hockeyapp Internal */ = { + D0924FE31FE52C0A003F693F /* ReleaseHockeyappInternal */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1508,9 +1508,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = "Release Hockeyapp Internal"; + name = ReleaseHockeyappInternal; }; - D0924FE41FE52C0A003F693F /* Release Hockeyapp Internal */ = { + D0924FE41FE52C0A003F693F /* ReleaseHockeyappInternal */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1528,9 +1528,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = "Release Hockeyapp Internal"; + name = ReleaseHockeyappInternal; }; - D0924FE51FE52C0A003F693F /* Release Hockeyapp Internal */ = { + D0924FE51FE52C0A003F693F /* ReleaseHockeyappInternal */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1558,9 +1558,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 4.0; }; - name = "Release Hockeyapp Internal"; + name = ReleaseHockeyappInternal; }; - D0924FE61FE52C0A003F693F /* Release Hockeyapp Internal */ = { + D0924FE61FE52C0A003F693F /* ReleaseHockeyappInternal */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; @@ -1578,9 +1578,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; - name = "Release Hockeyapp Internal"; + name = ReleaseHockeyappInternal; }; - D0924FE71FE52C0A003F693F /* Release Hockeyapp Internal */ = { + D0924FE71FE52C0A003F693F /* ReleaseHockeyappInternal */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1609,9 +1609,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.0; }; - name = "Release Hockeyapp Internal"; + name = ReleaseHockeyappInternal; }; - D0ADF92E212B3AD400310BBC /* Debug AppStore LLC */ = { + D0ADF92E212B3AD400310BBC /* DebugAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1657,9 +1657,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = "Debug AppStore LLC"; + name = DebugAppStoreLLC; }; - D0ADF92F212B3AD400310BBC /* Debug AppStore LLC */ = { + D0ADF92F212B3AD400310BBC /* DebugAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1679,9 +1679,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = "Debug AppStore LLC"; + name = DebugAppStoreLLC; }; - D0ADF930212B3AD400310BBC /* Debug AppStore LLC */ = { + D0ADF930212B3AD400310BBC /* DebugAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1703,9 +1703,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = "Debug AppStore LLC"; + name = DebugAppStoreLLC; }; - D0ADF931212B3AD400310BBC /* Debug AppStore LLC */ = { + D0ADF931212B3AD400310BBC /* DebugAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1735,9 +1735,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 4.0; }; - name = "Debug AppStore LLC"; + name = DebugAppStoreLLC; }; - D0ADF932212B3AD400310BBC /* Debug AppStore LLC */ = { + D0ADF932212B3AD400310BBC /* DebugAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -1757,9 +1757,9 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; - name = "Debug AppStore LLC"; + name = DebugAppStoreLLC; }; - D0ADF933212B3AD400310BBC /* Debug AppStore LLC */ = { + D0ADF933212B3AD400310BBC /* DebugAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1788,9 +1788,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; }; - name = "Debug AppStore LLC"; + name = DebugAppStoreLLC; }; - D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */ = { + D0B417F31D7DFA63004562A4 /* DebugHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1819,9 +1819,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; }; - name = "Debug Hockeyapp"; + name = DebugHockeyapp; }; - D0B417F41D7DFA63004562A4 /* Release Hockeyapp */ = { + D0B417F41D7DFA63004562A4 /* ReleaseHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1850,9 +1850,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.0; }; - name = "Release Hockeyapp"; + name = ReleaseHockeyapp; }; - D0B417F51D7DFA63004562A4 /* Release AppStore */ = { + D0B417F51D7DFA63004562A4 /* ReleaseAppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1881,9 +1881,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.0; }; - name = "Release AppStore"; + name = ReleaseAppStore; }; - D0CE6EEF213DC30100BCD44B /* Release AppStore LLC */ = { + D0CE6EEF213DC30100BCD44B /* ReleaseAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -1922,9 +1922,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = "Release AppStore LLC"; + name = ReleaseAppStoreLLC; }; - D0CE6EF0213DC30100BCD44B /* Release AppStore LLC */ = { + D0CE6EF0213DC30100BCD44B /* ReleaseAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1944,9 +1944,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = "Release AppStore LLC"; + name = ReleaseAppStoreLLC; }; - D0CE6EF1213DC30100BCD44B /* Release AppStore LLC */ = { + D0CE6EF1213DC30100BCD44B /* ReleaseAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -1964,9 +1964,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = "Release AppStore LLC"; + name = ReleaseAppStoreLLC; }; - D0CE6EF2213DC30100BCD44B /* Release AppStore LLC */ = { + D0CE6EF2213DC30100BCD44B /* ReleaseAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -1994,9 +1994,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 4.0; }; - name = "Release AppStore LLC"; + name = ReleaseAppStoreLLC; }; - D0CE6EF3213DC30100BCD44B /* Release AppStore LLC */ = { + D0CE6EF3213DC30100BCD44B /* ReleaseAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; @@ -2013,9 +2013,9 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; - name = "Release AppStore LLC"; + name = ReleaseAppStoreLLC; }; - D0CE6EF4213DC30100BCD44B /* Release AppStore LLC */ = { + D0CE6EF4213DC30100BCD44B /* ReleaseAppStoreLLC */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -2044,9 +2044,9 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.0; }; - name = "Release AppStore LLC"; + name = ReleaseAppStoreLLC; }; - D0DB57B61E5C4B7A0071854C /* Debug AppStore */ = { + D0DB57B61E5C4B7A0071854C /* DebugAppStore */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -2092,9 +2092,9 @@ VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = "Debug AppStore"; + name = DebugAppStore; }; - D0DB57B71E5C4B7A0071854C /* Debug AppStore */ = { + D0DB57B71E5C4B7A0071854C /* DebugAppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -2114,9 +2114,9 @@ PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; SKIP_INSTALL = YES; }; - name = "Debug AppStore"; + name = DebugAppStore; }; - D0DB57B81E5C4B7A0071854C /* Debug AppStore */ = { + D0DB57B81E5C4B7A0071854C /* DebugAppStore */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( @@ -2138,9 +2138,9 @@ PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; - name = "Debug AppStore"; + name = DebugAppStore; }; - D0DB57B91E5C4B7A0071854C /* Debug AppStore */ = { + D0DB57B91E5C4B7A0071854C /* DebugAppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -2170,9 +2170,9 @@ SWIFT_REFLECTION_METADATA_LEVEL = none; SWIFT_VERSION = 4.0; }; - name = "Debug AppStore"; + name = DebugAppStore; }; - D0DB57BA1E5C4B7A0071854C /* Debug AppStore */ = { + D0DB57BA1E5C4B7A0071854C /* DebugAppStore */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -2192,9 +2192,9 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; }; - name = "Debug AppStore"; + name = DebugAppStore; }; - D0DB57BB1E5C4B7A0071854C /* Debug AppStore */ = { + D0DB57BB1E5C4B7A0071854C /* DebugAppStore */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; @@ -2223,7 +2223,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; }; - name = "Debug AppStore"; + name = DebugAppStore; }; /* End XCBuildConfiguration section */ @@ -2231,92 +2231,92 @@ D0085B351B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKit" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0085B361B282B9800EAF753 /* Debug Hockeyapp */, - D021D505219CB1D90064BEBA /* Debug Fork */, - D0DB57B91E5C4B7A0071854C /* Debug AppStore */, - D0ADF931212B3AD400310BBC /* Debug AppStore LLC */, - D0085B371B282B9800EAF753 /* Release Hockeyapp */, - D0924FE51FE52C0A003F693F /* Release Hockeyapp Internal */, - D086A5771CC0117500F08284 /* Release AppStore */, - D0CE6EF2213DC30100BCD44B /* Release AppStore LLC */, + D0085B361B282B9800EAF753 /* DebugHockeyapp */, + D021D505219CB1D90064BEBA /* DebugFork */, + D0DB57B91E5C4B7A0071854C /* DebugAppStore */, + D0ADF931212B3AD400310BBC /* DebugAppStoreLLC */, + D0085B371B282B9800EAF753 /* ReleaseHockeyapp */, + D0924FE51FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5771CC0117500F08284 /* ReleaseAppStore */, + D0CE6EF2213DC30100BCD44B /* ReleaseAppStoreLLC */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = "Release Hockeyapp"; + defaultConfigurationName = ReleaseHockeyapp; }; D0085B381B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKitTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0085B391B282B9800EAF753 /* Debug Hockeyapp */, - D021D506219CB1D90064BEBA /* Debug Fork */, - D0DB57BA1E5C4B7A0071854C /* Debug AppStore */, - D0ADF932212B3AD400310BBC /* Debug AppStore LLC */, - D0085B3A1B282B9800EAF753 /* Release Hockeyapp */, - D0924FE61FE52C0A003F693F /* Release Hockeyapp Internal */, - D086A5781CC0117500F08284 /* Release AppStore */, - D0CE6EF3213DC30100BCD44B /* Release AppStore LLC */, + D0085B391B282B9800EAF753 /* DebugHockeyapp */, + D021D506219CB1D90064BEBA /* DebugFork */, + D0DB57BA1E5C4B7A0071854C /* DebugAppStore */, + D0ADF932212B3AD400310BBC /* DebugAppStoreLLC */, + D0085B3A1B282B9800EAF753 /* ReleaseHockeyapp */, + D0924FE61FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5781CC0117500F08284 /* ReleaseAppStore */, + D0CE6EF3213DC30100BCD44B /* ReleaseAppStoreLLC */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = "Release Hockeyapp"; + defaultConfigurationName = ReleaseHockeyapp; }; D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0445DEC1A7C2CA500267924 /* Debug Hockeyapp */, - D021D502219CB1D90064BEBA /* Debug Fork */, - D0DB57B61E5C4B7A0071854C /* Debug AppStore */, - D0ADF92E212B3AD400310BBC /* Debug AppStore LLC */, - D0445DED1A7C2CA500267924 /* Release Hockeyapp */, - D0924FE21FE52C0A003F693F /* Release Hockeyapp Internal */, - D086A5741CC0117500F08284 /* Release AppStore */, - D0CE6EEF213DC30100BCD44B /* Release AppStore LLC */, + D0445DEC1A7C2CA500267924 /* DebugHockeyapp */, + D021D502219CB1D90064BEBA /* DebugFork */, + D0DB57B61E5C4B7A0071854C /* DebugAppStore */, + D0ADF92E212B3AD400310BBC /* DebugAppStoreLLC */, + D0445DED1A7C2CA500267924 /* ReleaseHockeyapp */, + D0924FE21FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5741CC0117500F08284 /* ReleaseAppStore */, + D0CE6EEF213DC30100BCD44B /* ReleaseAppStoreLLC */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = "Release Hockeyapp"; + defaultConfigurationName = ReleaseHockeyapp; }; D0445DEE1A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKit" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0445DEF1A7C2CA500267924 /* Debug Hockeyapp */, - D021D503219CB1D90064BEBA /* Debug Fork */, - D0DB57B71E5C4B7A0071854C /* Debug AppStore */, - D0ADF92F212B3AD400310BBC /* Debug AppStore LLC */, - D0445DF01A7C2CA500267924 /* Release Hockeyapp */, - D0924FE31FE52C0A003F693F /* Release Hockeyapp Internal */, - D086A5751CC0117500F08284 /* Release AppStore */, - D0CE6EF0213DC30100BCD44B /* Release AppStore LLC */, + D0445DEF1A7C2CA500267924 /* DebugHockeyapp */, + D021D503219CB1D90064BEBA /* DebugFork */, + D0DB57B71E5C4B7A0071854C /* DebugAppStore */, + D0ADF92F212B3AD400310BBC /* DebugAppStoreLLC */, + D0445DF01A7C2CA500267924 /* ReleaseHockeyapp */, + D0924FE31FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5751CC0117500F08284 /* ReleaseAppStore */, + D0CE6EF0213DC30100BCD44B /* ReleaseAppStoreLLC */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = "Release Hockeyapp"; + defaultConfigurationName = ReleaseHockeyapp; }; D0445DF11A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKitTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0445DF21A7C2CA500267924 /* Debug Hockeyapp */, - D021D504219CB1D90064BEBA /* Debug Fork */, - D0DB57B81E5C4B7A0071854C /* Debug AppStore */, - D0ADF930212B3AD400310BBC /* Debug AppStore LLC */, - D0445DF31A7C2CA500267924 /* Release Hockeyapp */, - D0924FE41FE52C0A003F693F /* Release Hockeyapp Internal */, - D086A5761CC0117500F08284 /* Release AppStore */, - D0CE6EF1213DC30100BCD44B /* Release AppStore LLC */, + D0445DF21A7C2CA500267924 /* DebugHockeyapp */, + D021D504219CB1D90064BEBA /* DebugFork */, + D0DB57B81E5C4B7A0071854C /* DebugAppStore */, + D0ADF930212B3AD400310BBC /* DebugAppStoreLLC */, + D0445DF31A7C2CA500267924 /* ReleaseHockeyapp */, + D0924FE41FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5761CC0117500F08284 /* ReleaseAppStore */, + D0CE6EF1213DC30100BCD44B /* ReleaseAppStoreLLC */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = "Release Hockeyapp"; + defaultConfigurationName = ReleaseHockeyapp; }; D0B417F21D7DFA63004562A4 /* Build configuration list for PBXNativeTarget "SwiftSignalKitMac" */ = { isa = XCConfigurationList; buildConfigurations = ( - D0B417F31D7DFA63004562A4 /* Debug Hockeyapp */, - D021D507219CB1D90064BEBA /* Debug Fork */, - D0DB57BB1E5C4B7A0071854C /* Debug AppStore */, - D0ADF933212B3AD400310BBC /* Debug AppStore LLC */, - D0B417F41D7DFA63004562A4 /* Release Hockeyapp */, - D0924FE71FE52C0A003F693F /* Release Hockeyapp Internal */, - D0B417F51D7DFA63004562A4 /* Release AppStore */, - D0CE6EF4213DC30100BCD44B /* Release AppStore LLC */, + D0B417F31D7DFA63004562A4 /* DebugHockeyapp */, + D021D507219CB1D90064BEBA /* DebugFork */, + D0DB57BB1E5C4B7A0071854C /* DebugAppStore */, + D0ADF933212B3AD400310BBC /* DebugAppStoreLLC */, + D0B417F41D7DFA63004562A4 /* ReleaseHockeyapp */, + D0924FE71FE52C0A003F693F /* ReleaseHockeyappInternal */, + D0B417F51D7DFA63004562A4 /* ReleaseAppStore */, + D0CE6EF4213DC30100BCD44B /* ReleaseAppStoreLLC */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = "Release Hockeyapp"; + defaultConfigurationName = ReleaseHockeyapp; }; /* End XCConfigurationList section */ }; From 1a4d2ae68067d781baaaa235ec6ac8fcd91ae13b Mon Sep 17 00:00:00 2001 From: Peter Iakovlev Date: Fri, 18 Jan 2019 17:34:50 +0400 Subject: [PATCH 114/122] Add more combineLatest implementations --- SwiftSignalKit/Signal_Combine.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index 3dadd8cb12..0f981ed1e8 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -124,6 +124,18 @@ public func combineLatest(queue: Queue? = nil, _ s1: }, initialValues: [:], queue: queue) } +public func combineLatest(queue: Queue? = nil, _ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal, _ s6: Signal, _ s7: Signal) -> Signal<(T1, T2, T3, T4, T5, T6, T7), E> { + return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6), signalOfAny(s7)], combine: { values in + return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6, values[6] as! T7) + }, initialValues: [:], queue: queue) +} + +public func combineLatest(queue: Queue? = nil, _ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal, _ s6: Signal, _ s7: Signal, _ s8: Signal) -> Signal<(T1, T2, T3, T4, T5, T6, T7, T8), E> { + return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6), signalOfAny(s7), signalOfAny(s8)], combine: { values in + return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6, values[6] as! T7, values[7] as! T8) + }, initialValues: [:], queue: queue) +} + public func combineLatest(queue: Queue? = nil, _ signals: [Signal]) -> Signal<[T], E> { if signals.count == 0 { return single([T](), E.self) From 796552703ada04403a3f4f8422c5c4696fd9c066 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 26 Feb 2019 23:00:49 +0300 Subject: [PATCH 115/122] Update project --- SSignalKit.xcodeproj/project.pbxproj | 56 ++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit.xcodeproj/project.pbxproj index eb7a33603b..4218275f47 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit.xcodeproj/project.pbxproj @@ -860,6 +860,8 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -878,7 +880,7 @@ OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -892,7 +894,8 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; ARCHS = "$(ARCHS_STANDARD)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; @@ -908,7 +911,7 @@ OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -1011,6 +1014,8 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1058,6 +1063,8 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1076,7 +1083,7 @@ OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -1231,6 +1238,8 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1253,7 +1262,8 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1360,7 +1370,8 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1403,7 +1414,8 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; ARCHS = "$(ARCHS_STANDARD)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; @@ -1419,7 +1431,7 @@ OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -1492,7 +1504,8 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1535,7 +1548,8 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; ARCHS = "$(ARCHS_STANDARD)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; @@ -1551,7 +1565,7 @@ OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -1663,6 +1677,8 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1710,6 +1726,8 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1728,7 +1746,7 @@ OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -1928,7 +1946,8 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1971,7 +1990,8 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; ARCHS = "$(ARCHS_STANDARD)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; @@ -1987,7 +2007,7 @@ OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -2098,6 +2118,8 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -2145,6 +2167,8 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2163,7 +2187,7 @@ OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = X834Q8SBVP/; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; From 2deb9c75411eb395d1864da81978da2c3c95f07b Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 2 Apr 2019 16:32:52 +0400 Subject: [PATCH 116/122] Added restartIfError --- SwiftSignalKit/Signal_Catch.swift | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/SwiftSignalKit/Signal_Catch.swift b/SwiftSignalKit/Signal_Catch.swift index 24a453a717..896b41b5ac 100644 --- a/SwiftSignalKit/Signal_Catch.swift +++ b/SwiftSignalKit/Signal_Catch.swift @@ -134,3 +134,35 @@ public func retry(_ delayIncrement: Double, maxDelay: Double, onQueue queu } } } + +public func restartIfError(_ signal: Signal) -> Signal { + return Signal { subscriber in + let shouldRetry = Atomic(value: true) + 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 + recurse() + }, completed: { + let _ = shouldRetry.swap(false) + subscriber.putCompletion() + }) + currentDisposable.set(disposable) + } + } + + start() + + return ActionDisposable { + currentDisposable.dispose() + let _ = shouldRetry.swap(false) + } + } +} + From 5461c128d345d73a00d90c7edda04f2dcd78a964 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 21 May 2019 15:51:39 +0200 Subject: [PATCH 117/122] Added combineLatest with 9 signals --- SwiftSignalKit/Signal_Combine.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index 0f981ed1e8..16cd38347f 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -136,6 +136,12 @@ public func combineLatest(queue: Queue? = nil }, initialValues: [:], queue: queue) } +public func combineLatest(queue: Queue? = nil, _ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal, _ s6: Signal, _ s7: Signal, _ s8: Signal, _ s9: Signal) -> Signal<(T1, T2, T3, T4, T5, T6, T7, T8, T9), E> { + return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6), signalOfAny(s7), signalOfAny(s8), signalOfAny(s9)], combine: { values in + return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6, values[6] as! T7, values[7] as! T8, values[8] as! T9) + }, initialValues: [:], queue: queue) +} + public func combineLatest(queue: Queue? = nil, _ signals: [Signal]) -> Signal<[T], E> { if signals.count == 0 { return single([T](), E.self) From 09c1d8049d38fdbe9ba829d6c07ee85a9338308f Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 21 May 2019 20:10:08 +0200 Subject: [PATCH 118/122] Added combineLatest for 10 signals --- SwiftSignalKit/Signal_Combine.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SwiftSignalKit/Signal_Combine.swift b/SwiftSignalKit/Signal_Combine.swift index 16cd38347f..b0d0b97d6b 100644 --- a/SwiftSignalKit/Signal_Combine.swift +++ b/SwiftSignalKit/Signal_Combine.swift @@ -142,6 +142,12 @@ public func combineLatest(queue: Queue? = }, initialValues: [:], queue: queue) } +public func combineLatest(queue: Queue? = nil, _ s1: Signal, _ s2: Signal, _ s3: Signal, _ s4: Signal, _ s5: Signal, _ s6: Signal, _ s7: Signal, _ s8: Signal, _ s9: Signal, _ s10: Signal) -> Signal<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), E> { + return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6), signalOfAny(s7), signalOfAny(s8), signalOfAny(s9), signalOfAny(s10)], combine: { values in + return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6, values[6] as! T7, values[7] as! T8, values[8] as! T9, values[9] as! T10) + }, initialValues: [:], queue: queue) +} + public func combineLatest(queue: Queue? = nil, _ signals: [Signal]) -> Signal<[T], E> { if signals.count == 0 { return single([T](), E.self) From bbf43c967cd7b87e00f18f7fd16b4a66a26c0513 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Thu, 6 Jun 2019 00:15:07 +0100 Subject: [PATCH 119/122] BUCK configuration --- BUCK | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 BUCK diff --git a/BUCK b/BUCK new file mode 100644 index 0000000000..b1d82986b6 --- /dev/null +++ b/BUCK @@ -0,0 +1,37 @@ +load('//tools:buck_utils.bzl', 'config_with_updated_linker_flags', 'configs_with_config') +load('//tools:buck_defs.bzl', 'SHARED_CONFIGS') + +apple_library( + name = 'SwiftSignalKit', + srcs = glob([ + 'SwiftSignalKit/*.swift' + ]), + modular = True, + configs = configs_with_config({}), + visibility = ['PUBLIC'], + frameworks = [ + '$SDKROOT/System/Library/Frameworks/Foundation.framework', + ], +) + +apple_library( + name = 'SSignalKit', + srcs = glob([ + 'SSignalKit/*.m', + ]), + headers = glob([ + 'SSignalKit/*.h', + ]), + header_namespace = 'SSignalKit', + exported_headers = glob([ + 'SSignalKit/*.h', + ]), + modular = True, + configs = configs_with_config({}), + compiler_flags = ['-w'], + preprocessor_flags = ['-fobjc-arc'], + visibility = ['PUBLIC'], + frameworks = [ + '$SDKROOT/System/Library/Frameworks/Foundation.framework', + ], +) From bc6f1e2be62fcfefc8090b5899728e9f8e5432f5 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Sun, 9 Jun 2019 19:44:37 +0100 Subject: [PATCH 120/122] Rename project --- .../project.pbxproj | 4 ++-- .../project.xcworkspace/contents.xcworkspacedata | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename {SSignalKit.xcodeproj => SSignalKit_Xcode.xcodeproj}/project.pbxproj (99%) rename {SSignalKit.xcodeproj => SSignalKit_Xcode.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) diff --git a/SSignalKit.xcodeproj/project.pbxproj b/SSignalKit_Xcode.xcodeproj/project.pbxproj similarity index 99% rename from SSignalKit.xcodeproj/project.pbxproj rename to SSignalKit_Xcode.xcodeproj/project.pbxproj index 4218275f47..9eeafa5aba 100644 --- a/SSignalKit.xcodeproj/project.pbxproj +++ b/SSignalKit_Xcode.xcodeproj/project.pbxproj @@ -658,7 +658,7 @@ }; }; }; - buildConfigurationList = D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */; + buildConfigurationList = D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit_Xcode" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -2282,7 +2282,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = ReleaseHockeyapp; }; - D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit" */ = { + D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit_Xcode" */ = { isa = XCConfigurationList; buildConfigurations = ( D0445DEC1A7C2CA500267924 /* DebugHockeyapp */, diff --git a/SSignalKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SSignalKit_Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from SSignalKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to SSignalKit_Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata From b3cbbf58a13341e09c7183bc41fb7cf23341d741 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Sun, 9 Jun 2019 20:22:42 +0100 Subject: [PATCH 121/122] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 249d3670f3..3d0bd32fb5 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ DerivedData *.dSYM.zip *.ipa */xcuserdata/* +SSignalKit.xcodeproj/* From 359b2ee7c9f20f99f221f78e307369ef5ad0ece2 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Mon, 10 Jun 2019 20:20:30 +0100 Subject: [PATCH 122/122] Update build configuration --- BUCK | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BUCK b/BUCK index b1d82986b6..415648422d 100644 --- a/BUCK +++ b/BUCK @@ -1,13 +1,13 @@ -load('//tools:buck_utils.bzl', 'config_with_updated_linker_flags', 'configs_with_config') -load('//tools:buck_defs.bzl', 'SHARED_CONFIGS') +load('//tools:buck_utils.bzl', 'config_with_updated_linker_flags', 'configs_with_config', 'combined_config') +load('//tools:buck_defs.bzl', 'SHARED_CONFIGS', 'EXTENSION_LIB_SPECIFIC_CONFIG') apple_library( name = 'SwiftSignalKit', srcs = glob([ 'SwiftSignalKit/*.swift' ]), + configs = configs_with_config(combined_config([SHARED_CONFIGS, EXTENSION_LIB_SPECIFIC_CONFIG])), modular = True, - configs = configs_with_config({}), visibility = ['PUBLIC'], frameworks = [ '$SDKROOT/System/Library/Frameworks/Foundation.framework', @@ -19,6 +19,7 @@ apple_library( srcs = glob([ 'SSignalKit/*.m', ]), + configs = configs_with_config(combined_config([SHARED_CONFIGS, EXTENSION_LIB_SPECIFIC_CONFIG])), headers = glob([ 'SSignalKit/*.h', ]), @@ -27,7 +28,6 @@ apple_library( 'SSignalKit/*.h', ]), modular = True, - configs = configs_with_config({}), compiler_flags = ['-w'], preprocessor_flags = ['-fobjc-arc'], visibility = ['PUBLIC'],