diff --git a/submodules/SSignalKit/.gitignore b/submodules/SSignalKit/.gitignore new file mode 100644 index 0000000000..3d0bd32fb5 --- /dev/null +++ b/submodules/SSignalKit/.gitignore @@ -0,0 +1,25 @@ +fastlane/README.md +fastlane/report.xml +fastlane/test_output/* +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.xcscmblueprint +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +.DS_Store +*.dSYM +*.dSYM.zip +*.ipa +*/xcuserdata/* +SSignalKit.xcodeproj/* diff --git a/submodules/SSignalKit/BUCK b/submodules/SSignalKit/BUCK new file mode 100644 index 0000000000..415648422d --- /dev/null +++ b/submodules/SSignalKit/BUCK @@ -0,0 +1,37 @@ +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, + visibility = ['PUBLIC'], + frameworks = [ + '$SDKROOT/System/Library/Frameworks/Foundation.framework', + ], +) + +apple_library( + name = 'SSignalKit', + srcs = glob([ + 'SSignalKit/*.m', + ]), + configs = configs_with_config(combined_config([SHARED_CONFIGS, EXTENSION_LIB_SPECIFIC_CONFIG])), + headers = glob([ + 'SSignalKit/*.h', + ]), + header_namespace = 'SSignalKit', + exported_headers = glob([ + 'SSignalKit/*.h', + ]), + modular = True, + compiler_flags = ['-w'], + preprocessor_flags = ['-fobjc-arc'], + visibility = ['PUBLIC'], + frameworks = [ + '$SDKROOT/System/Library/Frameworks/Foundation.framework', + ], +) diff --git a/submodules/SSignalKit/SSignalKit/Info.plist b/submodules/SSignalKit/SSignalKit/Info.plist new file mode 100644 index 0000000000..d3de8eefb6 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/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/submodules/SSignalKit/SSignalKit/SAtomic.h b/submodules/SSignalKit/SSignalKit/SAtomic.h new file mode 100644 index 0000000000..6d3e35b4dc --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SAtomic.h @@ -0,0 +1,12 @@ +#import + +@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; +- (id)with:(id (^)(id))f; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SAtomic.m b/submodules/SSignalKit/SSignalKit/SAtomic.m new file mode 100644 index 0000000000..5f7f3d1032 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SAtomic.m @@ -0,0 +1,93 @@ +#import "SAtomic.h" + +#import + +@interface SAtomic () +{ + pthread_mutex_t _lock; + pthread_mutexattr_t _attr; + bool _isRecursive; + id _value; +} + +@end + +@implementation SAtomic + +- (instancetype)initWithValue:(id)value +{ + 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; + pthread_mutex_lock(&_lock); + previousValue = _value; + _value = newValue; + pthread_mutex_unlock(&_lock); + return previousValue; +} + +- (id)value +{ + id previousValue = nil; + pthread_mutex_lock(&_lock); + previousValue = _value; + pthread_mutex_unlock(&_lock); + + return previousValue; +} + +- (id)modify:(id (^)(id))f +{ + id newValue = nil; + pthread_mutex_lock(&_lock); + newValue = f(_value); + _value = newValue; + pthread_mutex_unlock(&_lock); + return newValue; +} + +- (id)with:(id (^)(id))f +{ + id result = nil; + pthread_mutex_lock(&_lock); + result = f(_value); + pthread_mutex_unlock(&_lock); + return result; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SBag.h b/submodules/SSignalKit/SSignalKit/SBag.h new file mode 100644 index 0000000000..7b79ead30f --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SSignalKit/SBag.m b/submodules/SSignalKit/SSignalKit/SBag.m new file mode 100644 index 0000000000..c83f206235 --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SSignalKit/SBlockDisposable.h b/submodules/SSignalKit/SSignalKit/SBlockDisposable.h new file mode 100644 index 0000000000..2914604cba --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SBlockDisposable.h @@ -0,0 +1,7 @@ +#import + +@interface SBlockDisposable : NSObject + +- (instancetype)initWithBlock:(void (^)())block; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SBlockDisposable.m b/submodules/SSignalKit/SSignalKit/SBlockDisposable.m new file mode 100644 index 0000000000..b8d1f989d4 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SBlockDisposable.m @@ -0,0 +1,58 @@ +#import "SBlockDisposable.h" + +#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)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; + if (block != NULL) + { + if (OSAtomicCompareAndSwapPtr(block, 0, &_block)) + { + if (block != nil) + { + __strong id strongBlock = (__bridge_transfer id)block; + ((dispatch_block_t)strongBlock)(); + strongBlock = nil; + } + } + } +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SDisposable.h b/submodules/SSignalKit/SSignalKit/SDisposable.h new file mode 100644 index 0000000000..49d9762dae --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SDisposable.h @@ -0,0 +1,7 @@ +#import + +@protocol SDisposable + +- (void)dispose; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SDisposableSet.h b/submodules/SSignalKit/SSignalKit/SDisposableSet.h new file mode 100644 index 0000000000..7d7515c968 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SDisposableSet.h @@ -0,0 +1,10 @@ +#import + +@class SSignal; + +@interface SDisposableSet : NSObject + +- (void)add:(id)disposable; +- (void)remove:(id)disposable; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SDisposableSet.m b/submodules/SSignalKit/SSignalKit/SDisposableSet.m new file mode 100644 index 0000000000..18cb3be965 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SDisposableSet.m @@ -0,0 +1,95 @@ +#import "SDisposableSet.h" + +#import "SSignal.h" + +#import + +@interface SDisposableSet () +{ + OSSpinLock _lock; + bool _disposed; + id _singleDisposable; + NSArray *_multipleDisposables; +} + +@end + +@implementation SDisposableSet + +- (void)add:(id)disposable +{ + if (disposable == nil) + return; + + bool dispose = false; + + OSSpinLockLock(&_lock); + dispose = _disposed; + if (!dispose) + { + 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)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; + NSArray *multipleDisposables = nil; + + OSSpinLockLock(&_lock); + if (!_disposed) + { + _disposed = true; + 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/submodules/SSignalKit/SSignalKit/SMetaDisposable.h b/submodules/SSignalKit/SSignalKit/SMetaDisposable.h new file mode 100644 index 0000000000..8938f9eacb --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SMetaDisposable.h @@ -0,0 +1,7 @@ +#import + +@interface SMetaDisposable : NSObject + +- (void)setDisposable:(id)disposable; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SMetaDisposable.m b/submodules/SSignalKit/SSignalKit/SMetaDisposable.m new file mode 100644 index 0000000000..4e9c8e4fab --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SMetaDisposable.m @@ -0,0 +1,53 @@ +#import "SMetaDisposable.h" + +#import + +@interface SMetaDisposable () +{ + OSSpinLock _lock; + bool _disposed; + id _disposable; +} + +@end + +@implementation SMetaDisposable + +- (void)setDisposable:(id)disposable +{ + id previousDisposable = nil; + bool dispose = false; + + OSSpinLockLock(&_lock); + dispose = _disposed; + if (!dispose) + { + previousDisposable = _disposable; + _disposable = disposable; + } + OSSpinLockUnlock(&_lock); + + if (previousDisposable != nil) + [previousDisposable dispose]; + + if (dispose) + [disposable dispose]; +} + +- (void)dispose +{ + id disposable = nil; + + OSSpinLockLock(&_lock); + if (!_disposed) + { + disposable = _disposable; + _disposed = true; + } + OSSpinLockUnlock(&_lock); + + if (disposable != nil) + [disposable dispose]; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SMulticastSignalManager.h b/submodules/SSignalKit/SSignalKit/SMulticastSignalManager.h new file mode 100644 index 0000000000..243f015a52 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SMulticastSignalManager.h @@ -0,0 +1,11 @@ +#import + +@interface SMulticastSignalManager : NSObject + +- (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/submodules/SSignalKit/SSignalKit/SMulticastSignalManager.m b/submodules/SSignalKit/SSignalKit/SMulticastSignalManager.m new file mode 100644 index 0000000000..1094852dd5 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SMulticastSignalManager.m @@ -0,0 +1,171 @@ +#import "SMulticastSignalManager.h" + +#import "SSignal+Multicast.h" +#import "SSignal+SideEffects.h" +#import "SBag.h" +#import "SMetaDisposable.h" +#import "SBlockDisposable.h" + +#import + +@interface SMulticastSignalManager () +{ + OSSpinLock _lock; + NSMutableDictionary *_multicastSignals; + NSMutableDictionary *_standaloneSignalDisposables; + NSMutableDictionary *_pipeListeners; +} + +@end + +@implementation SMulticastSignalManager + +- (instancetype)init +{ + self = [super init]; + if (self != nil) + { + _multicastSignals = [[NSMutableDictionary alloc] init]; + _standaloneSignalDisposables = [[NSMutableDictionary alloc] init]; + _pipeListeners = [[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) + { + if (producer) + return producer(); + else + return nil; + } + + SSignal *signal = nil; + OSSpinLockLock(&_lock); + signal = _multicastSignals[key]; + if (signal == nil) + { + __weak SMulticastSignalManager *weakSelf = self; + if (producer) + signal = producer(); + if (signal != nil) + { + signal = [[signal onDispose:^ + { + __strong SMulticastSignalManager *strongSelf = weakSelf; + if (strongSelf != nil) + { + OSSpinLockLock(&strongSelf->_lock); + [strongSelf->_multicastSignals removeObjectForKey:key]; + OSSpinLockUnlock(&strongSelf->_lock); + } + }] multicast]; + _multicastSignals[key] = signal; + } + } + OSSpinLockUnlock(&_lock); + + 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); + } +} + +- (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 *bag = _pipeListeners[key]; + [bag removeItem:index]; + if ([bag isEmpty]) { + [_pipeListeners removeObjectForKey:key]; + } + 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/submodules/SSignalKit/SSignalKit/SQueue.h b/submodules/SSignalKit/SSignalKit/SQueue.h new file mode 100644 index 0000000000..228334c888 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SQueue.h @@ -0,0 +1,19 @@ +#import + +@interface SQueue : NSObject + ++ (SQueue *)mainQueue; ++ (SQueue *)concurrentDefaultQueue; ++ (SQueue *)concurrentBackgroundQueue; + ++ (SQueue *)wrapConcurrentNativeQueue:(dispatch_queue_t)nativeQueue; + +- (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; + +- (bool)isCurrentQueue; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SQueue.m b/submodules/SSignalKit/SSignalKit/SQueue.m new file mode 100644 index 0000000000..d5b5553af8 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SQueue.m @@ -0,0 +1,124 @@ +#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; +} + ++ (SQueue *)wrapConcurrentNativeQueue:(dispatch_queue_t)nativeQueue +{ + return [[SQueue alloc] initWithNativeQueue:nativeQueue queueSpecific:NULL]; +} + +- (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 = queue; + _queueSpecific = queueSpecific; + } + return self; +} + +- (dispatch_queue_t)_dispatch_queue +{ + return _queue; +} + +- (void)dispatch:(dispatch_block_t)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 +{ + if (_queueSpecific != NULL && dispatch_get_specific(SQueueSpecificKey) == _queueSpecific) + block(); + else if (_specialIsMainQueue && [NSThread isMainThread]) + block(); + else + 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) + return true; + else if (_specialIsMainQueue && [NSThread isMainThread]) + return true; + return false; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Accumulate.h b/submodules/SSignalKit/SSignalKit/SSignal+Accumulate.h new file mode 100644 index 0000000000..1ea8a51ed0 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Accumulate.h @@ -0,0 +1,8 @@ +#import + +@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/submodules/SSignalKit/SSignalKit/SSignal+Accumulate.m b/submodules/SSignalKit/SSignalKit/SSignal+Accumulate.m new file mode 100644 index 0000000000..e237e204d0 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Accumulate.m @@ -0,0 +1,52 @@ +#import "SSignal+Accumulate.h" + +@implementation SSignal (Accumulate) + +- (SSignal *)reduceLeft:(id)value with:(id (^)(id, id))f +{ + return [[SSignal alloc] initWithGenerator:^(SSubscriber *subscriber) + { + __block id intermediateResult = value; + + return [self startWithNext:^(id next) + { + intermediateResult = f(intermediateResult, next); + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + if (intermediateResult != nil) + [subscriber putNext:intermediateResult]; + [subscriber putCompletion]; + }]; + }]; +} + +- (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 diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Catch.h b/submodules/SSignalKit/SSignalKit/SSignal+Catch.h new file mode 100644 index 0000000000..dc8898c062 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Catch.h @@ -0,0 +1,9 @@ +#import + +@interface SSignal (Catch) + +- (SSignal *)catch:(SSignal *(^)(id error))f; +- (SSignal *)restart; +- (SSignal *)retryIf:(bool (^)(id error))predicate; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Catch.m b/submodules/SSignalKit/SSignalKit/SSignal+Catch.m new file mode 100644 index 0000000000..f61e277750 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Catch.m @@ -0,0 +1,147 @@ +#import "SSignal+Catch.h" + +#import "SMetaDisposable.h" +#import "SDisposableSet.h" +#import "SBlockDisposable.h" +#import "SAtomic.h" + +@implementation SSignal (Catch) + +- (SSignal *)catch:(SSignal *(^)(id error))f +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SDisposableSet *disposable = [[SDisposableSet alloc] init]; + + [disposable add:[self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + SSignal *signal = f(error); + [disposable add:[signal startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]]; + } completed:^ + { + [subscriber putCompletion]; + }]]; + + return disposable; + }]; +} + +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; + }]; + }]; + }]; +} + +- (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/submodules/SSignalKit/SSignalKit/SSignal+Combine.h b/submodules/SSignalKit/SSignalKit/SSignal+Combine.h new file mode 100644 index 0000000000..d84e065311 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Combine.h @@ -0,0 +1,10 @@ +#import + +@interface SSignal (Combine) + ++ (SSignal *)combineSignals:(NSArray *)signals; ++ (SSignal *)combineSignals:(NSArray *)signals withInitialStates:(NSArray *)initialStates; + ++ (SSignal *)mergeSignals:(NSArray *)signals; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Combine.m b/submodules/SSignalKit/SSignalKit/SSignal+Combine.m new file mode 100644 index 0000000000..4df70c113d --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Combine.m @@ -0,0 +1,177 @@ +#import "SSignal+Combine.h" + +#import "SAtomic.h" +#import "SDisposableSet.h" +#import "SSignal+Single.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 +{ + if (signals.count == 0) + return [SSignal single:@[]]; + else + 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]]; + + SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + + 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) + [subscriber putNext: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) + [subscriber putError: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) + [subscriber putCompletion]; + }]; + [compositeDisposable add:disposable]; + index++; + } + + return compositeDisposable; + }]; +} + ++ (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/submodules/SSignalKit/SSignalKit/SSignal+Dispatch.h b/submodules/SSignalKit/SSignalKit/SSignal+Dispatch.h new file mode 100644 index 0000000000..a22679b372 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Dispatch.h @@ -0,0 +1,14 @@ +#import + +#import +#import + +@interface SSignal (Dispatch) + +- (SSignal *)deliverOn:(SQueue *)queue; +- (SSignal *)deliverOnThreadPool:(SThreadPool *)threadPool; +- (SSignal *)startOn:(SQueue *)queue; +- (SSignal *)startOnThreadPool:(SThreadPool *)threadPool; +- (SSignal *)throttleOn:(SQueue *)queue delay:(NSTimeInterval)delay; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Dispatch.m b/submodules/SSignalKit/SSignalKit/SSignal+Dispatch.m new file mode 100644 index 0000000000..3929f07eff --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Dispatch.m @@ -0,0 +1,212 @@ +#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 +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + return [self startWithNext:^(id next) + { + [queue dispatch:^ + { + [subscriber putNext:next]; + }]; + } error:^(id error) + { + [queue dispatch:^ + { + [subscriber putError:error]; + }]; + } completed:^ + { + [queue dispatch:^ + { + [subscriber putCompletion]; + }]; + }]; + }]; +} + +- (SSignal *)deliverOnThreadPool:(SThreadPool *)threadPool +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SThreadPoolQueue *queue = [threadPool nextQueue]; + return [self startWithNext:^(id next) + { + SThreadPoolTask *task = [[SThreadPoolTask alloc] initWithBlock:^(bool (^cancelled)()) + { + if (!cancelled()) + [subscriber putNext:next]; + }]; + [queue addTask:task]; + } error:^(id error) + { + SThreadPoolTask *task = [[SThreadPoolTask alloc] initWithBlock:^(bool (^cancelled)()) + { + if (!cancelled()) + [subscriber putError:error]; + }]; + [queue addTask:task]; + } completed:^ + { + SThreadPoolTask *task = [[SThreadPoolTask alloc] initWithBlock:^(bool (^cancelled)()) + { + if (!cancelled()) + [subscriber putCompletion]; + }]; + [queue addTask:task]; + }]; + }]; +} + +- (SSignal *)startOn:(SQueue *)queue +{ + 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:^ + { + if (!isCancelled) + { + [disposable setDisposable:[self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]]; + } + }]; + + return disposable; + }]; +} + +- (SSignal *)startOnThreadPool:(SThreadPool *)threadPool +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; + + SThreadPoolTask *task = [[SThreadPoolTask alloc] initWithBlock:^(bool (^cancelled)()) + { + if (cancelled && cancelled()) + return; + + [disposable setDisposable:[self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]]; + }]; + + [disposable setDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + [task cancel]; + }]]; + + [threadPool addTask:task]; + + return disposable; + }]; +} + +- (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/submodules/SSignalKit/SSignalKit/SSignal+Mapping.h b/submodules/SSignalKit/SSignalKit/SSignal+Mapping.h new file mode 100644 index 0000000000..81a16816e2 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Mapping.h @@ -0,0 +1,9 @@ +#import + +@interface SSignal (Mapping) + +- (SSignal *)map:(id (^)(id))f; +- (SSignal *)filter:(bool (^)(id))f; +- (SSignal *)ignoreRepeated; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Mapping.m b/submodules/SSignalKit/SSignalKit/SSignal+Mapping.m new file mode 100644 index 0000000000..cd3a3ece0a --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Mapping.m @@ -0,0 +1,83 @@ +#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 +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + return [self startWithNext:^(id next) + { + [subscriber putNext:f(next)]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + +- (SSignal *)filter:(bool (^)(id))f +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + return [self startWithNext:^(id next) + { + if (f(next)) + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + +- (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/submodules/SSignalKit/SSignalKit/SSignal+Meta.h b/submodules/SSignalKit/SSignalKit/SSignal+Meta.h new file mode 100644 index 0000000000..2d90df13f8 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Meta.h @@ -0,0 +1,22 @@ +#import + +@class SQueue; + +@interface SSignal (Meta) + +- (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 + +@interface SSignalQueue : NSObject + +- (SSignal *)enqueue:(SSignal *)signal; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Meta.m b/submodules/SSignalKit/SSignalKit/SSignal+Meta.m new file mode 100644 index 0000000000..f6ad4124e6 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Meta.m @@ -0,0 +1,325 @@ +#import "SSignal+Meta.h" + +#import "SDisposableSet.h" +#import "SMetaDisposable.h" +#import "SSignal+Mapping.h" +#import "SAtomic.h" +#import "SSignal+Pipe.h" + +#import + +@interface SSignalQueueState : NSObject +{ + OSSpinLock _lock; + bool _executingSignal; + bool _terminated; + + id _disposable; + SMetaDisposable *_currentDisposable; + SSubscriber *_subscriber; + + NSMutableArray *_queuedSignals; + bool _queueMode; + bool _throttleMode; +} + +@end + +@implementation SSignalQueueState + +- (instancetype)initWithSubscriber:(SSubscriber *)subscriber queueMode:(bool)queueMode throttleMode:(bool)throttleMode +{ + self = [super init]; + if (self != nil) + { + _subscriber = subscriber; + _currentDisposable = [[SMetaDisposable alloc] init]; + _queuedSignals = queueMode ? [[NSMutableArray alloc] init] : nil; + _queueMode = queueMode; + _throttleMode = throttleMode; + } + return self; +} + +- (void)beginWithDisposable:(id)disposable +{ + _disposable = disposable; +} + +- (void)enqueueSignal:(SSignal *)signal +{ + bool startSignal = false; + OSSpinLockLock(&_lock); + if (_queueMode && _executingSignal) { + if (_throttleMode) { + [_queuedSignals removeAllObjects]; + } + [_queuedSignals addObject:signal]; + } + else + { + _executingSignal = true; + startSignal = true; + } + OSSpinLockUnlock(&_lock); + + if (startSignal) + { + __weak SSignalQueueState *weakSelf = self; + id disposable = [signal startWithNext:^(id next) + { + [_subscriber putNext:next]; + } error:^(id error) + { + [_subscriber putError:error]; + } completed:^ + { + __strong SSignalQueueState *strongSelf = weakSelf; + if (strongSelf != nil) { + [strongSelf headCompleted]; + } + }]; + + [_currentDisposable setDisposable:disposable]; + } +} + +- (void)headCompleted +{ + SSignal *nextSignal = nil; + + bool terminated = false; + OSSpinLockLock(&_lock); + _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) + { + __weak SSignalQueueState *weakSelf = self; + id disposable = [nextSignal startWithNext:^(id next) + { + [_subscriber putNext:next]; + } error:^(id error) + { + [_subscriber putError:error]; + } completed:^ + { + __strong SSignalQueueState *strongSelf = weakSelf; + if (strongSelf != nil) { + [strongSelf headCompleted]; + } + }]; + + [_currentDisposable setDisposable:disposable]; + } +} + +- (void)beginCompletion +{ + bool executingSignal = false; + OSSpinLockLock(&_lock); + executingSignal = _executingSignal; + _terminated = true; + OSSpinLockUnlock(&_lock); + + if (!executingSignal) + [_subscriber putCompletion]; +} + +- (void)dispose +{ + [_currentDisposable dispose]; + [_disposable dispose]; +} + +@end + +@implementation SSignal (Meta) + +- (SSignal *)switchToLatest +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:false throttleMode:false]; + + [state beginWithDisposable:[self startWithNext:^(id next) + { + [state enqueueSignal:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [state beginCompletion]; + }]]; + + return state; + }]; +} + +- (SSignal *)mapToSignal:(SSignal *(^)(id))f +{ + return [[self map:f] switchToLatest]; +} + +- (SSignal *)mapToQueue:(SSignal *(^)(id))f +{ + 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) + { + SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + + SMetaDisposable *currentDisposable = [[SMetaDisposable alloc] init]; + [compositeDisposable add:currentDisposable]; + + [currentDisposable setDisposable:[self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [compositeDisposable add:[signal startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]]; + }]]; + + return compositeDisposable; + }]; +} + +- (SSignal *)queue +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SSignalQueueState *state = [[SSignalQueueState alloc] initWithSubscriber:subscriber queueMode:true throttleMode:false]; + + [state beginWithDisposable:[self startWithNext:^(id next) + { + [state enqueueSignal:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [state beginCompletion]; + }]]; + + return state; + }]; +} + +- (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) + { + return [generator() startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + +@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/submodules/SSignalKit/SSignalKit/SSignal+Multicast.h b/submodules/SSignalKit/SSignalKit/SSignal+Multicast.h new file mode 100644 index 0000000000..e0720cc103 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Multicast.h @@ -0,0 +1,7 @@ +#import + +@interface SSignal (Multicast) + +- (SSignal *)multicast; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Multicast.m b/submodules/SSignalKit/SSignalKit/SSignal+Multicast.m new file mode 100644 index 0000000000..92976cff4a --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Multicast.m @@ -0,0 +1,158 @@ +#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; +} + +- (id)addSubscriber:(SSubscriber *)subscriber start:(bool *)start +{ + OSSpinLockLock(&_lock); + NSInteger index = [_subscribers addItem:subscriber]; + switch (_state) { + case SSignalMulticastStateReady: + *start = true; + _state = SSignalMulticastStateStarted; + break; + default: + break; + } + OSSpinLockUnlock(&_lock); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + [self remove:index]; + }]; +} + +- (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)notifyNext:(id)next +{ + NSArray *currentSubscribers = nil; + OSSpinLockLock(&_lock); + currentSubscribers = [_subscribers copyItems]; + OSSpinLockUnlock(&_lock); + + for (SSubscriber *subscriber in currentSubscribers) + { + [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]; + } +} + +@end + +@implementation SSignal (Multicast) + +- (SSignal *)multicast +{ + SSignalMulticastSubscribers *subscribers = [[SSignalMulticastSubscribers alloc] init]; + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + bool start = false; + id currentDisposable = [subscribers addSubscriber:subscriber start:&start]; + if (start) + { + id disposable = [self startWithNext:^(id next) + { + [subscribers notifyNext:next]; + } error:^(id error) + { + [subscribers notifyError:error]; + } completed:^ + { + [subscribers notifyCompleted]; + }]; + + [subscribers setDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + [disposable dispose]; + }]]; + } + + return currentDisposable; + }]; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Pipe.h b/submodules/SSignalKit/SSignalKit/SSignal+Pipe.h new file mode 100644 index 0000000000..2a21ee4cf7 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Pipe.h @@ -0,0 +1,11 @@ +#import + +@interface SPipe : NSObject + +@property (nonatomic, copy, readonly) SSignal *(^signalProducer)(); +@property (nonatomic, copy, readonly) void (^sink)(id); + +- (instancetype)initWithReplay:(bool)replay; + +@end + diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Pipe.m b/submodules/SSignalKit/SSignalKit/SSignal+Pipe.m new file mode 100644 index 0000000000..ab9496a2d2 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Pipe.m @@ -0,0 +1,103 @@ +#import "SSignal+Pipe.h" + +#import "SBlockDisposable.h" +#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 * + { + 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; + }]; + + 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) + { + [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); + } + + if (replay) + { + [replayState modify:^id(__unused SPipeReplayState *state) + { + return [[SPipeReplayState alloc] initWithReceivedValue:true recentValue:next]; + }]; + } + } copy]; + } + return self; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+SideEffects.h b/submodules/SSignalKit/SSignalKit/SSignal+SideEffects.h new file mode 100644 index 0000000000..8107fcf4cb --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+SideEffects.h @@ -0,0 +1,13 @@ +#import + +@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; +- (SSignal *)onCompletion:(void (^)())f; +- (SSignal *)afterCompletion:(void (^)())f; +- (SSignal *)onDispose:(void (^)())f; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+SideEffects.m b/submodules/SSignalKit/SSignalKit/SSignal+SideEffects.m new file mode 100644 index 0000000000..3d78102d2d --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+SideEffects.m @@ -0,0 +1,141 @@ +#import "SSignal+SideEffects.h" + +#import "SBlockDisposable.h" +#import "SDisposableSet.h" + +@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) + { + return [self startWithNext:^(id next) + { + f(next); + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + +- (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) + { + return [self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + f(error); + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]; + }]; +} + +- (SSignal *)onCompletion:(void (^)())f +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + return [self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + f(); + [subscriber putCompletion]; + }]; + }]; +} + +- (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) + { + SDisposableSet *compositeDisposable = [[SDisposableSet alloc] init]; + + [compositeDisposable add:[self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]]; + + [compositeDisposable add:[[SBlockDisposable alloc] initWithBlock:^ + { + f(); + }]]; + + return compositeDisposable; + }]; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Single.h b/submodules/SSignalKit/SSignalKit/SSignal+Single.h new file mode 100644 index 0000000000..75f48ff569 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Single.h @@ -0,0 +1,10 @@ +#import + +@interface SSignal (Single) + ++ (SSignal *)single:(id)next; ++ (SSignal *)fail:(id)error; ++ (SSignal *)never; ++ (SSignal *)complete; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Single.m b/submodules/SSignalKit/SSignalKit/SSignal+Single.m new file mode 100644 index 0000000000..6da5943459 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Single.m @@ -0,0 +1,41 @@ +#import "SSignal+Single.h" + +@implementation SSignal (Single) + ++ (SSignal *)single:(id)next +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + [subscriber putNext:next]; + [subscriber putCompletion]; + return nil; + }]; +} + ++ (SSignal *)fail:(id)error +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + [subscriber putError:error]; + return nil; + }]; +} + ++ (SSignal *)never +{ + return [[SSignal alloc] initWithGenerator:^id (__unused SSubscriber *subscriber) + { + return nil; + }]; +} + ++ (SSignal *)complete +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + [subscriber putCompletion]; + return nil; + }]; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Take.h b/submodules/SSignalKit/SSignalKit/SSignal+Take.h new file mode 100644 index 0000000000..a4d1ff23eb --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Take.h @@ -0,0 +1,9 @@ +#import + +@interface SSignal (Take) + +- (SSignal *)take:(NSUInteger)count; +- (SSignal *)takeLast; +- (SSignal *)takeUntilReplacement:(SSignal *)replacement; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Take.m b/submodules/SSignalKit/SSignalKit/SSignal+Take.m new file mode 100644 index 0000000000..e5db9fa034 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Take.m @@ -0,0 +1,122 @@ +#import "SSignal+Take.h" + +#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 +{ + 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]; + }]; + }]; +} + +- (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]; + }]; + }]; +} + +- (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 diff --git a/submodules/SSignalKit/SSignalKit/SSignal+Timing.h b/submodules/SSignalKit/SSignalKit/SSignal+Timing.h new file mode 100644 index 0000000000..4b5d50c90e --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Timing.h @@ -0,0 +1,11 @@ +#import + +#import + +@interface SSignal (Timing) + +- (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/submodules/SSignalKit/SSignalKit/SSignal+Timing.m b/submodules/SSignalKit/SSignalKit/SSignal+Timing.m new file mode 100644 index 0000000000..3d0dbc4a97 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal+Timing.m @@ -0,0 +1,109 @@ +#import "SSignal+Timing.h" + +#import "SMetaDisposable.h" +#import "SDisposableSet.h" +#import "SBlockDisposable.h" + +#import "SSignal+Dispatch.h" + +#import "STimer.h" + +@implementation SSignal (Timing) + +- (SSignal *)delay:(NSTimeInterval)seconds onQueue:(SQueue *)queue +{ + return [[SSignal alloc] initWithGenerator:^id (SSubscriber *subscriber) + { + SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; + + STimer *timer = [[STimer alloc] initWithTimeout:seconds repeat:false completion:^ + { + [disposable setDisposable:[self startWithNext:^(id next) + { + [subscriber putNext:next]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + }]]; + } queue:queue]; + + [timer start]; + + [disposable setDisposable:[[SBlockDisposable alloc] initWithBlock:^ + { + [timer invalidate]; + }]]; + + return disposable; + }]; +} + +- (SSignal *)timeout:(NSTimeInterval)seconds onQueue:(SQueue *)queue orSignal:(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; + }]; +} + +- (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/submodules/SSignalKit/SSignalKit/SSignal.h b/submodules/SSignalKit/SSignalKit/SSignal.h new file mode 100644 index 0000000000..46b7385d36 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal.h @@ -0,0 +1,18 @@ +#import + +@interface SSignal : NSObject +{ +@public + id (^_generator)(SSubscriber *); +} + +- (instancetype)initWithGenerator:(id (^)(SSubscriber *))generator; + +- (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; + +- (SSignal *)trace:(NSString *)name; + +@end + diff --git a/submodules/SSignalKit/SSignalKit/SSignal.m b/submodules/SSignalKit/SSignalKit/SSignal.m new file mode 100644 index 0000000000..6bf3ff4dde --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignal.m @@ -0,0 +1,107 @@ +#import "SSignal.h" + +#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 () +{ +} + +@end + +@implementation SSignal + +- (instancetype)initWithGenerator:(id (^)(SSubscriber *))generator +{ + self = [super init]; + if (self != nil) + { + _generator = [generator copy]; + } + 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]; + id disposable = _generator(subscriber); + [subscriber _assignDisposable:disposable]; + return [[SSubscriberDisposable alloc] initWithSubscriber:subscriber disposable: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 [[SSubscriberDisposable alloc] initWithSubscriber:subscriber disposable: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 [[SSubscriberDisposable alloc] initWithSubscriber:subscriber disposable:disposable]; +} + +- (SSignal *)trace:(NSString *)name +{ +#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]; + } error:^(id error) + { + [subscriber putError:error]; + } completed:^ + { + [subscriber putCompletion]; + } traceName:traceName]; + }]; +#else + return self; +#endif +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SSignalKit.h b/submodules/SSignalKit/SSignalKit/SSignalKit.h new file mode 100644 index 0000000000..9842a184e1 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSignalKit.h @@ -0,0 +1,45 @@ +// +// SSignalKit.h +// SSignalKit +// +// Created by Peter on 31/01/15. +// 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; + +//! 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 + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/submodules/SSignalKit/SSignalKit/SSubscriber.h b/submodules/SSignalKit/SSignalKit/SSubscriber.h new file mode 100644 index 0000000000..ce4fee5678 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSubscriber.h @@ -0,0 +1,22 @@ +#import + +@interface SSubscriber : NSObject +{ +} + +- (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed; + +- (void)_assignDisposable:(id)disposable; +- (void)_markTerminatedWithoutDisposal; + +- (void)putNext:(id)next; +- (void)putError:(id)error; +- (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/submodules/SSignalKit/SSignalKit/SSubscriber.m b/submodules/SSignalKit/SSignalKit/SSubscriber.m new file mode 100644 index 0000000000..e565b7748d --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SSubscriber.m @@ -0,0 +1,276 @@ +#import "SSubscriber.h" + +#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 + +@implementation SSubscriber + +- (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed +{ + self = [super init]; + if (self != nil) + { + _blocks = [[SSubscriberBlocks alloc] initWithNext:next error:error completed:completed]; + } + return self; +} + +- (void)_assignDisposable:(id)disposable +{ + bool dispose = false; + OSSpinLockLock(&_lock); + if (_terminated) { + dispose = true; + } else { + _disposable = disposable; + } + OSSpinLockUnlock(&_lock); + if (dispose) { + [disposable dispose]; + } +} + +- (void)_markTerminatedWithoutDisposal +{ + OSSpinLockLock(&_lock); + SSubscriberBlocks *blocks = nil; + if (!_terminated) + { + blocks = _blocks; + _blocks = nil; + + _terminated = true; + } + OSSpinLockUnlock(&_lock); + + if (blocks) { + blocks = nil; + } +} + +- (void)putNext:(id)next +{ + SSubscriberBlocks *blocks = nil; + + OSSpinLockLock(&_lock); + if (!_terminated) { + blocks = _blocks; + } + OSSpinLockUnlock(&_lock); + + if (blocks && blocks->_next) { + blocks->_next(next); + } +} + +- (void)putError:(id)error +{ + bool shouldDispose = false; + SSubscriberBlocks *blocks = nil; + + OSSpinLockLock(&_lock); + if (!_terminated) + { + blocks = _blocks; + _blocks = nil; + + shouldDispose = true; + _terminated = true; + } + OSSpinLockUnlock(&_lock); + + if (blocks && blocks->_error) { + blocks->_error(error); + } + + if (shouldDispose) + [self->_disposable dispose]; +} + +- (void)putCompletion +{ + bool shouldDispose = false; + SSubscriberBlocks *blocks = nil; + + OSSpinLockLock(&_lock); + if (!_terminated) + { + blocks = _blocks; + _blocks = nil; + + shouldDispose = true; + _terminated = true; + } + OSSpinLockUnlock(&_lock); + + if (blocks && blocks->_completed) + blocks->_completed(); + + if (shouldDispose) + [self->_disposable dispose]; +} + +- (void)dispose +{ + [self->_disposable dispose]; +} + +@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 initWithNext:next error:error completed:completed]; + if (self != nil) + { + _name = name; + } + return self; +} + +/*- (void)_assignDisposable:(id)disposable +{ + if (_terminated) + [disposable dispose]; + else + _disposable = disposable; +} + +- (void)_markTerminatedWithoutDisposal +{ + OSSpinLockLock(&_lock); + if (!_terminated) + { + NSLog(@"trace(%@ terminated)", _name); + _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(@"trace(%@ next: %@)", _name, next); + fnext(next); + } + else + NSLog(@"trace(%@ next: %@, not accepted)", _name, 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(@"trace(%@ error: %@)", _name, error); + ferror(error); + } + else + NSLog(@"trace(%@ error: %@, not accepted)", _name, 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(@"trace(%@ completed)", _name); + completed(); + } + else + NSLog(@"trace(%@ completed, not accepted)", _name); + + if (shouldDispose) + [self->_disposable dispose]; +} + +- (void)dispose +{ + NSLog(@"trace(%@ dispose)", _name); + [self->_disposable dispose]; +}*/ + +@end diff --git a/submodules/SSignalKit/SSignalKit/SThreadPool.h b/submodules/SSignalKit/SSignalKit/SThreadPool.h new file mode 100644 index 0000000000..69d0565938 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SThreadPool.h @@ -0,0 +1,15 @@ +#import + +#import +#import + +@interface SThreadPool : NSObject + +- (instancetype)initWithThreadCount:(NSUInteger)threadCount threadPriority:(double)threadPriority; + +- (void)addTask:(SThreadPoolTask *)task; + +- (SThreadPoolQueue *)nextQueue; +- (void)_workOnQueue:(SThreadPoolQueue *)queue block:(void (^)())block; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SThreadPool.m b/submodules/SSignalKit/SSignalKit/SThreadPool.m new file mode 100644 index 0000000000..060ee29c92 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SThreadPool.m @@ -0,0 +1,128 @@ +#import "SThreadPool.h" + +#import +#import +#import "SQueue.h" + +@interface SThreadPool () +{ + SQueue *_managementQueue; + NSMutableArray *_threads; + + NSMutableArray *_queues; + NSMutableArray *_takenQueues; + + pthread_mutex_t _mutex; + pthread_cond_t _cond; +} + +@end + +@implementation SThreadPool + ++ (void)threadEntryPoint:(SThreadPool *)threadPool +{ + SThreadPoolQueue *queue = nil; + + while (true) + { + 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->_queues.count == 0) + pthread_cond_wait(&threadPool->_cond, &threadPool->_mutex); + + queue = threadPool->_queues.firstObject; + task = [queue _popFirstTask]; + + if (queue != nil) + { + [threadPool->_takenQueues addObject:queue]; + [threadPool->_queues removeObjectAtIndex:0]; + + break; + } + } + pthread_mutex_unlock(&threadPool->_mutex); + + @autoreleasepool + { + [task execute]; + } + } +} + +- (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]; + _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]; + 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)addTask:(SThreadPoolTask *)task +{ + SThreadPoolQueue *tempQueue = [self nextQueue]; + [tempQueue addTask:task]; +} + +- (SThreadPoolQueue *)nextQueue +{ + return [[SThreadPoolQueue alloc] initWithThreadPool:self]; +} + +- (void)_workOnQueue:(SThreadPoolQueue *)queue block:(void (^)())block +{ + [_managementQueue dispatch:^ + { + pthread_mutex_lock(&_mutex); + block(); + if (![_queues containsObject:queue] && ![_takenQueues containsObject:queue]) + [_queues addObject:queue]; + pthread_cond_broadcast(&_cond); + pthread_mutex_unlock(&_mutex); + }]; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit/SThreadPoolQueue.h b/submodules/SSignalKit/SSignalKit/SThreadPoolQueue.h new file mode 100644 index 0000000000..3d8d53b00c --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SSignalKit/SThreadPoolQueue.m b/submodules/SSignalKit/SSignalKit/SThreadPoolQueue.m new file mode 100644 index 0000000000..ff857e642d --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SSignalKit/SThreadPoolTask.h b/submodules/SSignalKit/SSignalKit/SThreadPoolTask.h new file mode 100644 index 0000000000..e8da985ca0 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/SThreadPoolTask.h @@ -0,0 +1,9 @@ +#import + +@interface SThreadPoolTask : NSObject + +- (instancetype)initWithBlock:(void (^)(bool (^)()))block; +- (void)execute; +- (void)cancel; + +@end diff --git a/submodules/SSignalKit/SSignalKit/SThreadPoolTask.m b/submodules/SSignalKit/SSignalKit/SThreadPoolTask.m new file mode 100644 index 0000000000..c967022e01 --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SSignalKit/STimer.h b/submodules/SSignalKit/SSignalKit/STimer.h new file mode 100644 index 0000000000..621e4232b2 --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/STimer.h @@ -0,0 +1,14 @@ +#import + +@class SQueue; + +@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; +- (void)fireAndInvalidate; + +@end diff --git a/submodules/SSignalKit/SSignalKit/STimer.m b/submodules/SSignalKit/SSignalKit/STimer.m new file mode 100644 index 0000000000..235c2f883a --- /dev/null +++ b/submodules/SSignalKit/SSignalKit/STimer.m @@ -0,0 +1,83 @@ +#import "STimer.h" + +#import "SQueue.h" + +@interface STimer () +{ + dispatch_source_t _timer; + NSTimeInterval _timeout; + NSTimeInterval _timeoutDate; + bool _repeat; + dispatch_block_t _completion; + dispatch_queue_t _nativeQueue; +} + +@end + +@implementation STimer + +- (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) + { + _timeoutDate = INT_MAX; + + _timeout = timeout; + _repeat = repeat; + _completion = [completion copy]; + _nativeQueue = nativeQueue; + } + 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, _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, ^ + { + 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/submodules/SSignalKit/SSignalKit/SVariable.h b/submodules/SSignalKit/SSignalKit/SVariable.h new file mode 100644 index 0000000000..47d51a1608 --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SSignalKit/SVariable.m b/submodules/SSignalKit/SSignalKit/SVariable.m new file mode 100644 index 0000000000..45eea46a2c --- /dev/null +++ b/submodules/SSignalKit/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 diff --git a/submodules/SSignalKit/SSignalKitTests/DeallocatingObject.h b/submodules/SSignalKit/SSignalKitTests/DeallocatingObject.h new file mode 100644 index 0000000000..00f3c9cc8b --- /dev/null +++ b/submodules/SSignalKit/SSignalKitTests/DeallocatingObject.h @@ -0,0 +1,7 @@ +#import + +@interface DeallocatingObject : NSObject + +- (instancetype)initWithDeallocated:(bool *)deallocated; + +@end diff --git a/submodules/SSignalKit/SSignalKitTests/DeallocatingObject.m b/submodules/SSignalKit/SSignalKitTests/DeallocatingObject.m new file mode 100644 index 0000000000..38cff658e6 --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SSignalKitTests/Info.plist b/submodules/SSignalKit/SSignalKitTests/Info.plist new file mode 100644 index 0000000000..ba72822e87 --- /dev/null +++ b/submodules/SSignalKit/SSignalKitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/submodules/SSignalKit/SSignalKitTests/SDisposableTests.m b/submodules/SSignalKit/SSignalKitTests/SDisposableTests.m new file mode 100644 index 0000000000..3c71105e4e --- /dev/null +++ b/submodules/SSignalKit/SSignalKitTests/SDisposableTests.m @@ -0,0 +1,318 @@ +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#else +#import +#endif +#import + +#import + +@import SSignalKit; + +#import "DeallocatingObject.h" + +@interface SDisposableTests : XCTestCase + +@end + +@implementation SDisposableTests + +- (void)setUp +{ + [super setUp]; +} + +- (void)tearDown +{ + [super tearDown]; +} + +- (void)testBlockDisposableDisposed +{ + bool deallocated = false; + __block bool disposed = false; + { + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; + dispatch_block_t block = ^{ + [object description]; + disposed = true; + }; + SBlockDisposable *disposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; + object = nil; + block = nil; + [disposable dispose]; + } + + XCTAssertTrue(deallocated); + XCTAssertTrue(disposed); +} + +- (void)testBlockDisposableNotDisposed +{ + bool deallocated = false; + __block bool disposed = false; + { + DeallocatingObject *object = [[DeallocatingObject alloc] initWithDeallocated:&deallocated]; + dispatch_block_t block = ^{ + [object description]; + disposed = true; + }; + SBlockDisposable *disposable = [[SBlockDisposable alloc] initWithBlock:[block copy]]; + [disposable description]; + } + + XCTAssertTrue(deallocated); + XCTAssertFalse(disposed); +} + +- (void)testMetaDisposableDisposed +{ + bool deallocated = false; + __block bool disposed = false; + { + DeallocatingObject *object = [[DeallocatingObject 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; + { + 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 setDisposable:blockDisposable2]; + [metaDisposable dispose]; + } + + XCTAssertTrue(deallocated1); + XCTAssertTrue(disposed1); + XCTAssertTrue(deallocated2); + XCTAssertTrue(disposed2); +} + +- (void)testMetaDisposableNotDisposed +{ + bool deallocated = false; + __block bool disposed = false; + { + DeallocatingObject *object = [[DeallocatingObject 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; + { + DeallocatingObject *object = [[DeallocatingObject 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; + { + 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]]; + + 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; + { + DeallocatingObject *object = [[DeallocatingObject 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; + { + 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]]; + + SDisposableSet *disposableSet = [[SDisposableSet alloc] init]; + [disposableSet add:blockDisposable1]; + [disposableSet add:blockDisposable2]; + } + + XCTAssertTrue(deallocated1); + XCTAssertFalse(disposed1); + XCTAssertTrue(deallocated2); + 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/submodules/SSignalKit/SSignalKitTests/SSignalBasicTests.m b/submodules/SSignalKit/SSignalKitTests/SSignalBasicTests.m new file mode 100644 index 0000000000..56ca98337c --- /dev/null +++ b/submodules/SSignalKit/SSignalKitTests/SSignalBasicTests.m @@ -0,0 +1,764 @@ +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#else +#import +#endif +#import + +@import SSignalKit; + +#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 + +@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)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, ^ + { + usleep(200); + [subscriber putNext:@1]; + }); + + return [[SBlockDisposable alloc] initWithBlock:^ + { + disposed = true; + }]; + }]; + + id disposable = [signal startWithNext:^(id value) + { + generated = true; + } error:nil completed:nil]; + NSLog(@"dispose"); + [disposable dispose]; + } + + dispatch_barrier_sync(queue, ^ + { + }); + + XCTAssertTrue(disposed); + 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); +} + +- (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)testRestart +{ + SSignal *signal = [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) + { + [[SQueue concurrentDefaultQueue] dispatch:^ + { + [subscriber putNext:@1]; + [subscriber putCompletion]; + }]; + + return [[SBlockDisposable alloc] initWithBlock:^ + { + }]; + }]; + + __block int result = 0; + + [[[signal restart] take:3] startWithNext:^(id next) + { + result += [next intValue]; + } error:^(id error) { + + } completed:^{ + + }]; + + usleep(100 * 1000); + + 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); +} + +- (void)testDisposableDeadlock { + @autoreleasepool { + DisposableHolder *holder = [[DisposableHolder alloc] init]; + holder = nil; + sleep(10); + } +} + +- (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/submodules/SSignalKit/SSignalKitTests/SSignalPerformanceTests.m b/submodules/SSignalKit/SSignalKitTests/SSignalPerformanceTests.m new file mode 100644 index 0000000000..f5384d75bd --- /dev/null +++ b/submodules/SSignalKit/SSignalKitTests/SSignalPerformanceTests.m @@ -0,0 +1,50 @@ +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#else +#import +#endif +#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) + { + + }]; + } + }]; +} + +@end diff --git a/submodules/SSignalKit/SSignalKit_Xcode.xcodeproj/project.pbxproj b/submodules/SSignalKit/SSignalKit_Xcode.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..9eeafa5aba --- /dev/null +++ b/submodules/SSignalKit/SSignalKit_Xcode.xcodeproj/project.pbxproj @@ -0,0 +1,2348 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 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 */; }; + 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 /* 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 */; }; + 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 */; }; + 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 */; }; + 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 */ + D0085B2E1B282B9800EAF753 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D0445DCF1A7C2CA500267924 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0085B211B282B9800EAF753; + remoteInfo = SwiftSignalKit; + }; + D0445DE51A7C2CA500267924 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D0445DCF1A7C2CA500267924 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0445DD71A7C2CA500267924; + remoteInfo = SSignalKit; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 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 /* 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 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 */ + 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; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0445DE01A7C2CA500267924 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D0445DE41A7C2CA500267924 /* SSignalKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0B417E91D7DFA63004562A4 /* 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 /* 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 */, + D0467D1720D7F7BC0055C28F /* Signal_Loop.swift */, + D0085B4E1B282BEE00EAF753 /* Subscriber.swift */, + D07A5CFC1BBDE6E400451791 /* Promise.swift */, + D05F09A71C9EF77100BB6F96 /* Multicast.swift */, + D066BD091C7FE06700D7A576 /* Lock.swift */, + D053B3FF1F16881000E2D58A /* QueueLocalObject.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 */, + D02720B01CD0E005006F1506 /* PerformanceTests.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 */, + D0B417EE1D7DFA63004562A4 /* SwiftSignalKitMac */, + D0445DD91A7C2CA500267924 /* Products */, + D0B417E71D7DFA40004562A4 /* SwiftSignalKit copy-Info.plist */, + ); + sourceTree = ""; + }; + D0445DD91A7C2CA500267924 /* Products */ = { + isa = PBXGroup; + children = ( + D0445DD81A7C2CA500267924 /* SSignalKit.framework */, + D0445DE31A7C2CA500267924 /* SSignalKitTests.xctest */, + D0085B221B282B9800EAF753 /* SwiftSignalKit.framework */, + D0085B2C1B282B9800EAF753 /* SwiftSignalKitTests.xctest */, + D0B417ED1D7DFA63004562A4 /* SwiftSignalKitMac.framework */, + ); + name = Products; + sourceTree = ""; + }; + D0445DDA1A7C2CA500267924 /* SSignalKit */ = { + isa = PBXGroup; + children = ( + 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 */, + D09FD73C1BA9BAB900FF0A4F /* SVariable.h */, + D09FD73D1BA9BAB900FF0A4F /* SVariable.m */, + D0085AB91B28285400EAF753 /* 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 = ( + D06F106F1A855E2D00485185 /* DeallocatingObject.h */, + D06F10701A855E2D00485185 /* DeallocatingObject.m */, + D0445DE81A7C2CA500267924 /* Supporting Files */, + D0445E561A7C3FB400267924 /* SDisposableTests.m */, + D06F106B1A85561E00485185 /* SSignalBasicTests.m */, + D06F10721A85882000485185 /* SSignalPerformanceTests.m */, + ); + path = SSignalKitTests; + sourceTree = ""; + }; + D0445DE81A7C2CA500267924 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + D0445DE91A7C2CA500267924 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + D0B417EE1D7DFA63004562A4 /* SwiftSignalKitMac */ = { + isa = PBXGroup; + children = ( + D0B417EF1D7DFA63004562A4 /* SwiftSignalKitMac.h */, + D0B417F01D7DFA63004562A4 /* Info.plist */, + ); + path = SwiftSignalKitMac; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + D0085B1F1B282B9800EAF753 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D0085B271B282B9800EAF753 /* SwiftSignalKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0445DD51A7C2CA500267924 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + 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 */, + 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; + }; + D0B417EA1D7DFA63004562A4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D0B417F11D7DFA63004562A4 /* SwiftSignalKitMac.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" */; + 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"; + }; + 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 */ + D0445DCF1A7C2CA500267924 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftMigration = 0700; + LastSwiftUpdateCheck = 0700; + 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_Xcode" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = D0445DCE1A7C2CA500267924; + productRefGroup = D0445DD91A7C2CA500267924 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D0445DD71A7C2CA500267924 /* SSignalKit */, + D0445DE21A7C2CA500267924 /* SSignalKitTests */, + D0085B211B282B9800EAF753 /* SwiftSignalKit */, + D0085B2B1B282B9800EAF753 /* SwiftSignalKitTests */, + D0B417EC1D7DFA63004562A4 /* SwiftSignalKitMac */, + ); + }; +/* 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; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0445DE11A7C2CA500267924 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0B417EB1D7DFA63004562A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D0085B1D1B282B9800EAF753 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0085B521B282BEE00EAF753 /* Signal_Dispatch.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 */, + 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 */, + 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 */, + D02720B11CD0E005006F1506 /* PerformanceTests.swift in Sources */, + D0085B661B282C2800EAF753 /* SwiftSignalKitFunctionsTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0445DD31A7C2CA500267924 /* Sources */ = { + isa = PBXSourcesBuildPhase; + 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 */, + 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; + }; + D0445DDF1A7C2CA500267924 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D06F106C1A85561E00485185 /* SSignalBasicTests.m in Sources */, + D06F10711A855E2D00485185 /* DeallocatingObject.m in Sources */, + D06F10731A85882000485185 /* SSignalPerformanceTests.m in Sources */, + D0445E571A7C3FB400267924 /* SDisposableTests.m in Sources */, + ); + 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 */, + D0467D1920D7F7BC0055C28F /* Signal_Loop.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 */, + D0B4180D1D7DFAAB004562A4 /* Lock.swift 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 */; + targetProxy = D0445DE51A7C2CA500267924 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + D0085B361B282B9800EAF753 /* DebugHockeyapp */ = { + isa = XCBuildConfiguration; + 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; + 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 = ""; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 4.0; + }; + name = DebugHockeyapp; + }; + D0085B371B282B9800EAF753 /* ReleaseHockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + 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 = ""; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 4.0; + }; + name = ReleaseHockeyapp; + }; + D0085B391B282B9800EAF753 /* DebugHockeyapp */ = { + 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 = DebugHockeyapp; + }; + D0085B3A1B282B9800EAF753 /* ReleaseHockeyapp */ = { + 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 = ReleaseHockeyapp; + }; + D021D502219CB1D90064BEBA /* DebugFork */ = { + 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 = DebugFork; + }; + D021D503219CB1D90064BEBA /* DebugFork */ = { + 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; + 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 = DebugFork; + }; + D021D504219CB1D90064BEBA /* DebugFork */ = { + 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 = DebugFork; + }; + D021D505219CB1D90064BEBA /* DebugFork */ = { + isa = XCBuildConfiguration; + 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; + 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 = ""; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 4.0; + }; + name = DebugFork; + }; + D021D506219CB1D90064BEBA /* DebugFork */ = { + 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 = DebugFork; + }; + D021D507219CB1D90064BEBA /* DebugFork */ = { + 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 = DebugFork; + }; + D0445DEC1A7C2CA500267924 /* DebugHockeyapp */ = { + 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 = DebugHockeyapp; + }; + D0445DED1A7C2CA500267924 /* ReleaseHockeyapp */ = { + 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 = ReleaseHockeyapp; + }; + D0445DEF1A7C2CA500267924 /* DebugHockeyapp */ = { + 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; + 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 = DebugHockeyapp; + }; + D0445DF01A7C2CA500267924 /* ReleaseHockeyapp */ = { + 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; + 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 = ReleaseHockeyapp; + }; + D0445DF21A7C2CA500267924 /* DebugHockeyapp */ = { + 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 = DebugHockeyapp; + }; + D0445DF31A7C2CA500267924 /* ReleaseHockeyapp */ = { + 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 = ReleaseHockeyapp; + }; + D086A5741CC0117500F08284 /* ReleaseAppStore */ = { + 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 = ReleaseAppStore; + }; + D086A5751CC0117500F08284 /* ReleaseAppStore */ = { + 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; + 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 = ReleaseAppStore; + }; + D086A5761CC0117500F08284 /* ReleaseAppStore */ = { + 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 = ReleaseAppStore; + }; + D086A5771CC0117500F08284 /* ReleaseAppStore */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + 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 = ""; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 4.0; + }; + name = ReleaseAppStore; + }; + D086A5781CC0117500F08284 /* ReleaseAppStore */ = { + 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 = ReleaseAppStore; + }; + D0924FE21FE52C0A003F693F /* ReleaseHockeyappInternal */ = { + 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 = ReleaseHockeyappInternal; + }; + D0924FE31FE52C0A003F693F /* ReleaseHockeyappInternal */ = { + 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; + 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 = ReleaseHockeyappInternal; + }; + D0924FE41FE52C0A003F693F /* ReleaseHockeyappInternal */ = { + 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 = ReleaseHockeyappInternal; + }; + D0924FE51FE52C0A003F693F /* ReleaseHockeyappInternal */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + 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 = ""; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 4.0; + }; + name = ReleaseHockeyappInternal; + }; + D0924FE61FE52C0A003F693F /* ReleaseHockeyappInternal */ = { + 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 = ReleaseHockeyappInternal; + }; + D0924FE71FE52C0A003F693F /* ReleaseHockeyappInternal */ = { + 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 = ReleaseHockeyappInternal; + }; + D0ADF92E212B3AD400310BBC /* DebugAppStoreLLC */ = { + 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 = DebugAppStoreLLC; + }; + D0ADF92F212B3AD400310BBC /* DebugAppStoreLLC */ = { + 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; + 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 = DebugAppStoreLLC; + }; + D0ADF930212B3AD400310BBC /* DebugAppStoreLLC */ = { + 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 = DebugAppStoreLLC; + }; + D0ADF931212B3AD400310BBC /* DebugAppStoreLLC */ = { + isa = XCBuildConfiguration; + 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; + 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 = ""; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 4.0; + }; + name = DebugAppStoreLLC; + }; + D0ADF932212B3AD400310BBC /* DebugAppStoreLLC */ = { + 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 = DebugAppStoreLLC; + }; + D0ADF933212B3AD400310BBC /* DebugAppStoreLLC */ = { + 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 = DebugAppStoreLLC; + }; + D0B417F31D7DFA63004562A4 /* DebugHockeyapp */ = { + 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 = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = DebugHockeyapp; + }; + D0B417F41D7DFA63004562A4 /* ReleaseHockeyapp */ = { + 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 = ReleaseHockeyapp; + }; + D0B417F51D7DFA63004562A4 /* ReleaseAppStore */ = { + 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 = ReleaseAppStore; + }; + D0CE6EEF213DC30100BCD44B /* ReleaseAppStoreLLC */ = { + 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 = ReleaseAppStoreLLC; + }; + D0CE6EF0213DC30100BCD44B /* ReleaseAppStoreLLC */ = { + 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; + 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 = ReleaseAppStoreLLC; + }; + D0CE6EF1213DC30100BCD44B /* ReleaseAppStoreLLC */ = { + 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 = ReleaseAppStoreLLC; + }; + D0CE6EF2213DC30100BCD44B /* ReleaseAppStoreLLC */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + ARCHS = "$(ARCHS_STANDARD)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_STYLE = Manual; + 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 = ""; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 4.0; + }; + name = ReleaseAppStoreLLC; + }; + D0CE6EF3213DC30100BCD44B /* ReleaseAppStoreLLC */ = { + 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 = ReleaseAppStoreLLC; + }; + D0CE6EF4213DC30100BCD44B /* ReleaseAppStoreLLC */ = { + 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 = ReleaseAppStoreLLC; + }; + D0DB57B61E5C4B7A0071854C /* DebugAppStore */ = { + 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 = DebugAppStore; + }; + D0DB57B71E5C4B7A0071854C /* DebugAppStore */ = { + 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; + 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 = DebugAppStore; + }; + D0DB57B81E5C4B7A0071854C /* DebugAppStore */ = { + 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 = DebugAppStore; + }; + D0DB57B91E5C4B7A0071854C /* DebugAppStore */ = { + isa = XCBuildConfiguration; + 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; + 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 = ""; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_REFLECTION_METADATA_LEVEL = none; + SWIFT_VERSION = 4.0; + }; + name = DebugAppStore; + }; + D0DB57BA1E5C4B7A0071854C /* DebugAppStore */ = { + 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 = DebugAppStore; + }; + D0DB57BB1E5C4B7A0071854C /* DebugAppStore */ = { + 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 = DebugAppStore; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D0085B351B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0085B361B282B9800EAF753 /* DebugHockeyapp */, + D021D505219CB1D90064BEBA /* DebugFork */, + D0DB57B91E5C4B7A0071854C /* DebugAppStore */, + D0ADF931212B3AD400310BBC /* DebugAppStoreLLC */, + D0085B371B282B9800EAF753 /* ReleaseHockeyapp */, + D0924FE51FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5771CC0117500F08284 /* ReleaseAppStore */, + D0CE6EF2213DC30100BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = ReleaseHockeyapp; + }; + D0085B381B282B9800EAF753 /* Build configuration list for PBXNativeTarget "SwiftSignalKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0085B391B282B9800EAF753 /* DebugHockeyapp */, + D021D506219CB1D90064BEBA /* DebugFork */, + D0DB57BA1E5C4B7A0071854C /* DebugAppStore */, + D0ADF932212B3AD400310BBC /* DebugAppStoreLLC */, + D0085B3A1B282B9800EAF753 /* ReleaseHockeyapp */, + D0924FE61FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5781CC0117500F08284 /* ReleaseAppStore */, + D0CE6EF3213DC30100BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = ReleaseHockeyapp; + }; + D0445DD21A7C2CA500267924 /* Build configuration list for PBXProject "SSignalKit_Xcode" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0445DEC1A7C2CA500267924 /* DebugHockeyapp */, + D021D502219CB1D90064BEBA /* DebugFork */, + D0DB57B61E5C4B7A0071854C /* DebugAppStore */, + D0ADF92E212B3AD400310BBC /* DebugAppStoreLLC */, + D0445DED1A7C2CA500267924 /* ReleaseHockeyapp */, + D0924FE21FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5741CC0117500F08284 /* ReleaseAppStore */, + D0CE6EEF213DC30100BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = ReleaseHockeyapp; + }; + D0445DEE1A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0445DEF1A7C2CA500267924 /* DebugHockeyapp */, + D021D503219CB1D90064BEBA /* DebugFork */, + D0DB57B71E5C4B7A0071854C /* DebugAppStore */, + D0ADF92F212B3AD400310BBC /* DebugAppStoreLLC */, + D0445DF01A7C2CA500267924 /* ReleaseHockeyapp */, + D0924FE31FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5751CC0117500F08284 /* ReleaseAppStore */, + D0CE6EF0213DC30100BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = ReleaseHockeyapp; + }; + D0445DF11A7C2CA500267924 /* Build configuration list for PBXNativeTarget "SSignalKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0445DF21A7C2CA500267924 /* DebugHockeyapp */, + D021D504219CB1D90064BEBA /* DebugFork */, + D0DB57B81E5C4B7A0071854C /* DebugAppStore */, + D0ADF930212B3AD400310BBC /* DebugAppStoreLLC */, + D0445DF31A7C2CA500267924 /* ReleaseHockeyapp */, + D0924FE41FE52C0A003F693F /* ReleaseHockeyappInternal */, + D086A5761CC0117500F08284 /* ReleaseAppStore */, + D0CE6EF1213DC30100BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = ReleaseHockeyapp; + }; + D0B417F21D7DFA63004562A4 /* Build configuration list for PBXNativeTarget "SwiftSignalKitMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0B417F31D7DFA63004562A4 /* DebugHockeyapp */, + D021D507219CB1D90064BEBA /* DebugFork */, + D0DB57BB1E5C4B7A0071854C /* DebugAppStore */, + D0ADF933212B3AD400310BBC /* DebugAppStoreLLC */, + D0B417F41D7DFA63004562A4 /* ReleaseHockeyapp */, + D0924FE71FE52C0A003F693F /* ReleaseHockeyappInternal */, + D0B417F51D7DFA63004562A4 /* ReleaseAppStore */, + D0CE6EF4213DC30100BCD44B /* ReleaseAppStoreLLC */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = ReleaseHockeyapp; + }; +/* End XCConfigurationList section */ + }; + rootObject = D0445DCF1A7C2CA500267924 /* Project object */; +} diff --git a/submodules/SSignalKit/SSignalKit_Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/submodules/SSignalKit/SSignalKit_Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..2141ad337b --- /dev/null +++ b/submodules/SSignalKit/SSignalKit_Xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/submodules/SSignalKit/SwiftSignalKit copy-Info.plist b/submodules/SSignalKit/SwiftSignalKit copy-Info.plist new file mode 100644 index 0000000000..d3de8eefb6 --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SwiftSignalKit/Atomic.swift b/submodules/SSignalKit/SwiftSignalKit/Atomic.swift new file mode 100644 index 0000000000..e6afddf50b --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Atomic.swift @@ -0,0 +1,43 @@ +import Foundation + +public final class Atomic { + 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 { + pthread_mutex_lock(&self.lock) + let result = f(self.value) + pthread_mutex_unlock(&self.lock) + + return result + } + + public func modify(_ f: (T) -> T) -> T { + pthread_mutex_lock(&self.lock) + let result = f(self.value) + self.value = result + pthread_mutex_unlock(&self.lock) + + return result + } + + public func swap(_ value: T) -> T { + pthread_mutex_lock(&self.lock) + let previous = self.value + self.value = value + pthread_mutex_unlock(&self.lock) + + return previous + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Bag.swift b/submodules/SSignalKit/SwiftSignalKit/Bag.swift new file mode 100644 index 0000000000..08d5aef3a4 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Bag.swift @@ -0,0 +1,97 @@ +import Foundation + +public final class Bag { + public typealias Index = Int + private var nextIndex: Index = 0 + private var items: [T] = [] + private var itemKeys: [Index] = [] + + public init() { + } + + public func add(_ item: T) -> Index { + let key = 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 { + if key == index { + self.items.remove(at: i) + self.itemKeys.remove(at: i) + break + } + 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 + } + } +} + +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/submodules/SSignalKit/SwiftSignalKit/Disposable.swift b/submodules/SSignalKit/SwiftSignalKit/Disposable.swift new file mode 100644 index 0000000000..5287ac158b --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Disposable.swift @@ -0,0 +1,233 @@ +import Foundation + +public protocol Disposable: class { + func dispose() +} + +final class _EmptyDisposable: Disposable { + func dispose() { + } +} + +public let EmptyDisposable: Disposable = _EmptyDisposable() + +public final class ActionDisposable : Disposable { + private var lock = pthread_mutex_t() + + private var action: (() -> Void)? + + public init(action: @escaping() -> Void) { + self.action = action + + pthread_mutex_init(&self.lock, nil) + } + + deinit { + var freeAction: (() -> Void)? + pthread_mutex_lock(&self.lock) + freeAction = self.action + self.action = nil + pthread_mutex_unlock(&self.lock) + + if let freeAction = freeAction { + withExtendedLifetime(freeAction, {}) + } + + pthread_mutex_destroy(&self.lock) + } + + public func dispose() { + let disposeAction: (() -> Void)? + + pthread_mutex_lock(&self.lock) + disposeAction = self.action + self.action = nil + pthread_mutex_unlock(&self.lock) + + disposeAction?() + } +} + +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) + } + + deinit { + var freeDisposable: Disposable? + pthread_mutex_lock(&self.lock) + if let disposable = self.disposable { + freeDisposable = disposable + self.disposable = nil + } + pthread_mutex_unlock(&self.lock) + if let freeDisposable = freeDisposable { + withExtendedLifetime(freeDisposable, { }) + } + + pthread_mutex_destroy(&self.lock) + } + + public func set(_ disposable: Disposable?) { + var previousDisposable: Disposable! = nil + var disposeImmediately = false + + pthread_mutex_lock(&self.lock) + disposeImmediately = self.disposed + if !disposeImmediately { + previousDisposable = self.disposable + if let disposable = disposable { + self.disposable = disposable + } else { + self.disposable = nil + } + } + pthread_mutex_unlock(&self.lock) + + if previousDisposable != nil { + previousDisposable.dispose() + } + + if disposeImmediately { + if let disposable = disposable { + disposable.dispose() + } + } + } + + public func dispose() + { + var disposable: Disposable! = nil + + pthread_mutex_lock(&self.lock) + if !self.disposed { + self.disposed = true + disposable = self.disposable + self.disposable = nil + } + pthread_mutex_unlock(&self.lock) + + if disposable != nil { + disposable.dispose() + } + } +} + +public final class DisposableSet : Disposable { + 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_lock(&self.lock) + self.disposables.removeAll() + pthread_mutex_unlock(&self.lock) + + pthread_mutex_destroy(&self.lock) + } + + public func add(_ disposable: Disposable) { + var disposeImmediately = false + + pthread_mutex_lock(&self.lock) + if self.disposed { + disposeImmediately = true + } else { + self.disposables.append(disposable) + } + 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] = [] + 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 { + disposable.dispose() + } + } + } +} + +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() + } + } + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Info.plist b/submodules/SSignalKit/SwiftSignalKit/Info.plist new file mode 100644 index 0000000000..d3de8eefb6 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/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/submodules/SSignalKit/SwiftSignalKit/Lock.swift b/submodules/SSignalKit/SwiftSignalKit/Lock.swift new file mode 100644 index 0000000000..42847f2579 --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SwiftSignalKit/Multicast.swift b/submodules/SSignalKit/SwiftSignalKit/Multicast.swift new file mode 100644 index 0000000000..b1ddec5a3c --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SwiftSignalKit/Promise.swift b/submodules/SSignalKit/SwiftSignalKit/Promise.swift new file mode 100644 index 0000000000..4888ec34d7 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Promise.swift @@ -0,0 +1,139 @@ +import Foundation + +public final class Promise { + private var initializeOnFirstAccess: Signal? + private var value: T? + private var lock = pthread_mutex_t() + private let disposable = MetaDisposable() + private let subscribers = Bag<(T) -> Void>() + + 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) + } + + public init() { + pthread_mutex_init(&self.lock, nil) + } + + deinit { + self.onDeinit?() + pthread_mutex_destroy(&self.lock) + self.disposable.dispose() + } + + public func set(_ signal: Signal) { + pthread_mutex_lock(&self.lock) + self.value = nil + pthread_mutex_unlock(&self.lock) + + self.disposable.set(signal.start(next: { [weak self] next in + if let strongSelf = self { + pthread_mutex_lock(&strongSelf.lock) + strongSelf.value = next + let subscribers = strongSelf.subscribers.copyItems() + pthread_mutex_unlock(&strongSelf.lock) + + for subscriber in subscribers { + subscriber(next) + } + } + })) + } + + 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) + self.subscribers.remove(index) + 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/submodules/SSignalKit/SwiftSignalKit/Queue.swift b/submodules/SSignalKit/SwiftSignalKit/Queue.swift new file mode 100644 index 0000000000..ba94f82405 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Queue.swift @@ -0,0 +1,88 @@ +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 + private var specific = NSObject() + private let specialIsMainQueue: Bool + + public var queue: DispatchQueue { + get { + return self.nativeQueue + } + } + + public class func mainQueue() -> Queue { + return globalMainQueue + } + + public class func concurrentDefaultQueue() -> Queue { + return globalDefaultQueue + } + + public class func concurrentBackgroundQueue() -> Queue { + return globalBackgroundQueue + } + + public init(queue: DispatchQueue) { + self.nativeQueue = queue + self.specialIsMainQueue = false + } + + fileprivate init(queue: DispatchQueue, specialIsMainQueue: Bool) { + self.nativeQueue = queue + self.specialIsMainQueue = specialIsMainQueue + } + + 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) + } + + public func isCurrent() -> Bool { + if DispatchQueue.getSpecific(key: QueueSpecificKey) === self.specific { + return true + } else if self.specialIsMainQueue && Thread.isMainThread { + return true + } else { + return false + } + } + + public func async(_ f: @escaping () -> Void) { + if self.isCurrent() { + f() + } else { + self.nativeQueue.async(execute: f) + } + } + + public func sync(_ f: () -> Void) { + if self.isCurrent() { + f() + } else { + 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) { + let time: DispatchTime = DispatchTime.now() + delay + self.nativeQueue.asyncAfter(deadline: time, execute: f) + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/QueueLocalObject.swift b/submodules/SSignalKit/SwiftSignalKit/QueueLocalObject.swift new file mode 100644 index 0000000000..c30d0f4bee --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/QueueLocalObject.swift @@ -0,0 +1,53 @@ +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) + } + } + } + + 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) + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Signal.swift b/submodules/SSignalKit/SwiftSignalKit/Signal.swift new file mode 100644 index 0000000000..1bedb501ce --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal.swift @@ -0,0 +1,85 @@ +import Foundation + +let doNothing: () -> Void = { } + +public enum NoValue { +} + +public enum NoError { +} + +public func identity(a: A) -> A { + return a +} + +precedencegroup PipeRight { + associativity: left + higherThan: DefaultPrecedence +} + +infix operator |> : PipeRight + +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: @escaping(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) + } + + 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/submodules/SSignalKit/SwiftSignalKit/Signal_Catch.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Catch.swift new file mode 100644 index 0000000000..896b41b5ac --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Catch.swift @@ -0,0 +1,168 @@ +import Foundation + +public func `catch`(_ f: @escaping(E) -> Signal) -> (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 + 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: @escaping(@escaping() -> 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() + let _ = shouldRestart.swap(false) + } + } +} + +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) + } + } + + 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 + let delay = currentDelay.modify { value in + return min(maxDelay, value + delayIncrement) + } + + let time: DispatchTime = DispatchTime.now() + Double(delay) + queue.queue.asyncAfter(deadline: time, execute: { + recurse() + }) + }, completed: { + let _ = shouldRetry.swap(false) + subscriber.putCompletion() + }) + currentDisposable.set(disposable) + } + } + + start() + + return ActionDisposable { + currentDisposable.dispose() + let _ = shouldRetry.swap(false) + } + } + } +} + +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) + } + } +} + diff --git a/submodules/SSignalKit/SwiftSignalKit/Signal_Combine.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Combine.swift new file mode 100644 index 0000000000..b0d0b97d6b --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Combine.swift @@ -0,0 +1,163 @@ +import Foundation + +private struct SignalCombineState { + let values: [Int : Any] + let completed: Set + let error: Bool +} + +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() + + 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 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 + 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 + let _ = state.modify { current in + if !current.error { + emitError = true + return SignalCombineState(values: current.values, completed: current.completed, error: true) + } else { + return current + } + } + if emitError { + subscriber.putError(error) + } + }, completed: { + var emitCompleted = false + let _ = 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(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: [:], queue: queue) +} + +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], queue: queue) +} + +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: [:], queue: queue) +} + +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: [:], queue: queue) +} + +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: [:], queue: queue) +} + +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: [:], 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, _ 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, _ 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) + } + + return combineLatestAny(signals.map({signalOfAny($0)}), combine: { values in + var combined: [T] = [] + for value in values { + combined.append(value as! T) + } + return combined + }, initialValues: [:], queue: queue) +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Signal_Dispatch.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Dispatch.swift new file mode 100644 index 0000000000..2a921b2e37 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Dispatch.swift @@ -0,0 +1,122 @@ +import Foundation + +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.async { + subscriber.putError(error) + } + }, completed: { + queue.async { + subscriber.putCompletion() + } + }) + } + } +} + +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.with { $0 } { + subscriber.putNext(next) + } + }) + }, error: { error in + queue.addTask(ThreadPoolTask { state in + if !state.cancelled.with { $0 } { + subscriber.putError(error) + } + }) + }, completed: { + queue.addTask(ThreadPoolTask { state in + if !state.cancelled.with { $0 } { + 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.with { $0 } { + 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/submodules/SSignalKit/SwiftSignalKit/Signal_Loop.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Loop.swift new file mode 100644 index 0000000000..3ae92898a8 --- /dev/null +++ b/submodules/SSignalKit/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() + } + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Signal_Mapping.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Mapping.swift new file mode 100644 index 0000000000..d8a1b3cc5b --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Mapping.swift @@ -0,0 +1,128 @@ +import Foundation + +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: @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 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 + return signal.start(next: { next in + subscriber.putNext(next) + }, error: { error in + subscriber.putError(f(error)) + }, completed: { + subscriber.putCompletion() + }) + } + } +} + +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? +} + +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, value == next { + return false + } else { + context.value = next + return true + } + } + if pass { + subscriber.putNext(next) + } + }, error: { error in + subscriber.putError(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/submodules/SSignalKit/SwiftSignalKit/Signal_Materialize.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Materialize.swift new file mode 100644 index 0000000000..92e7a9b3c9 --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SwiftSignalKit/Signal_Merge.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Merge.swift new file mode 100644 index 0000000000..df0dac256a --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SwiftSignalKit/Signal_Meta.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Meta.swift new file mode 100644 index 0000000000..78c511eb10 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Meta.swift @@ -0,0 +1,248 @@ +import Foundation + +private final class SignalQueueState: Disposable { + var lock = pthread_mutex_t() + var executingSignal = false + var terminated = false + + var disposable: Disposable = EmptyDisposable + let currentDisposable = MetaDisposable() + 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 + pthread_mutex_lock(&self.lock) + if self.queueMode && self.executingSignal { + if self.throttleMode { + self.queuedSignals.removeAll() + } + self.queuedSignals.append(signal) + } else { + self.executingSignal = true + startSignal = true + } + pthread_mutex_unlock(&self.lock) + + if startSignal { + let disposable = signal.start(next: { next in + assert(self.subscriber != nil) + self.subscriber?.putNext(next) + }, error: { error in + assert(self.subscriber != nil) + self.subscriber?.putError(error) + }, completed: { + self.headCompleted() + }) + self.currentDisposable.set(disposable) + } + } + + func headCompleted() { + while true { + let leftFunction = Atomic(value: false) + + var nextSignal: Signal! = nil + + var terminated = false + pthread_mutex_lock(&self.lock) + self.executingSignal = false + if self.queueMode { + if self.queuedSignals.count != 0 { + nextSignal = self.queuedSignals[0] + self.queuedSignals.remove(at: 0) + self.executingSignal = true + } else { + terminated = self.terminated + } + } else { + terminated = self.terminated + } + pthread_mutex_unlock(&self.lock) + + if terminated { + self.subscriber?.putCompletion() + } else if nextSignal != nil { + let disposable = nextSignal.start(next: { next in + assert(self.subscriber != nil) + self.subscriber?.putNext(next) + }, error: { error in + assert(self.subscriber != nil) + 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 + pthread_mutex_lock(&self.lock) + executingSignal = self.executingSignal + self.terminated = true + pthread_mutex_unlock(&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, throttleMode: 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, throttleMode: false) + state.beginWithDisposable(signal.start(next: { next in + state.enqueueSignal(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + state.beginCompletion() + })) + return state + } +} + +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: { + 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() + }) + } |> switchToLatest + } +} + +public func ignoreValues(_ 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 + 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) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Signal_Reduce.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Reduce.swift new file mode 100644 index 0000000000..d42ad64f5b --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Reduce.swift @@ -0,0 +1,189 @@ +import Foundation + +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() + }) + } + } +} + +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: @escaping(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.remove(at: 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: @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/submodules/SSignalKit/SwiftSignalKit/Signal_SideEffects.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_SideEffects.swift new file mode 100644 index 0000000000..ca4987081a --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_SideEffects.swift @@ -0,0 +1,116 @@ +import Foundation + +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: @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 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() + }) + } + } +} + +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() -> 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/submodules/SSignalKit/SwiftSignalKit/Signal_Single.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Single.swift new file mode 100644 index 0000000000..c2d658dbb2 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Single.swift @@ -0,0 +1,32 @@ +import Foundation + +public func single(_ value: T, _ errorType: 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 + } +} + +public func never(_ valueType: T.Type, _ error: E.Type) -> Signal { + return Signal { _ in + return EmptyDisposable + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Signal_Take.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Take.swift new file mode 100644 index 0000000000..99ac5bbce1 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Take.swift @@ -0,0 +1,73 @@ +import Foundation + +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() + }) + } + } +} + +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) + return signal.start(next: { next in + let _ = value.swap(next) + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putNext(value.with({ $0 })) + subscriber.putCompletion() + }) + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Signal_Timing.swift b/submodules/SSignalKit/SwiftSignalKit/Signal_Timing.swift new file mode 100644 index 0000000000..427205f8b6 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Signal_Timing.swift @@ -0,0 +1,122 @@ +import Foundation + +public func delay(_ timeout: Double, queue: Queue) -> (_ signal: Signal) -> Signal { + return { signal in + return Signal { subscriber in + let disposable = MetaDisposable() + 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 + } + } +} + +public func suspendAwareDelay(_ 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() + } + + 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?() + }) + + timer.start() + } + } + return disposable + } + } +} + +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() + })) + timer.start() + + let disposableSet = DisposableSet() + disposableSet.add(ActionDisposable { + timer.invalidate() + }) + disposableSet.add(disposable) + + return disposableSet + } + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Subscriber.swift b/submodules/SSignalKit/SwiftSignalKit/Subscriber.swift new file mode 100644 index 0000000000..bb5a68a08f --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Subscriber.swift @@ -0,0 +1,145 @@ +import Foundation + +public final class Subscriber { + private var next: ((T) -> Void)! + private var error: ((E) -> Void)! + private var completed: (() -> Void)! + + 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) { + self.next = next + self.error = error + self.completed = completed + pthread_mutex_init(&self.lock, nil) + } + + deinit { + var freeDisposable: Disposable? + pthread_mutex_lock(&self.lock) + if let disposable = self.disposable { + freeDisposable = disposable + self.disposable = nil + } + pthread_mutex_unlock(&self.lock) + if let freeDisposableValue = freeDisposable { + withExtendedLifetime(freeDisposableValue, { + }) + freeDisposable = nil + } + + pthread_mutex_destroy(&self.lock) + } + + internal func assignDisposable(_ disposable: Disposable) { + var dispose = false + pthread_mutex_lock(&self.lock) + if self.terminated { + dispose = true + } else { + self.disposable = disposable + } + pthread_mutex_unlock(&self.lock) + + if dispose { + disposable.dispose() + } + } + + internal func markTerminatedWithoutDisposal() { + pthread_mutex_lock(&self.lock) + if !self.terminated { + self.terminated = true + self.next = nil + self.error = nil + self.completed = nil + } + pthread_mutex_unlock(&self.lock) + } + + public func putNext(_ next: T) { + var action: ((T) -> Void)! = nil + pthread_mutex_lock(&self.lock) + if !self.terminated { + action = self.next + } + pthread_mutex_unlock(&self.lock) + + if action != nil { + action(next) + } + } + + public func putError(_ error: E) { + var action: ((E) -> Void)! = nil + + var disposeDisposable: Disposable? + + pthread_mutex_lock(&self.lock) + if !self.terminated { + action = self.error + self.next = nil + self.error = nil + self.completed = nil; + self.terminated = true + disposeDisposable = self.disposable + self.disposable = nil + + } + pthread_mutex_unlock(&self.lock) + + if action != nil { + action(error) + } + + if let disposeDisposable = disposeDisposable { + disposeDisposable.dispose() + } + } + + public func putCompletion() { + var action: (() -> Void)! = nil + + 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 + + disposeDisposable = self.disposable + self.disposable = nil + } + 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() + } + + if let disposeDisposable = disposeDisposable { + disposeDisposable.dispose() + } + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit.h b/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit.h new file mode 100644 index 0000000000..d30da27eb3 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/SwiftSignalKit.h @@ -0,0 +1,23 @@ +// +// SwiftSignalKit.h +// SwiftSignalKit +// +// Created by Peter on 10/06/15. +// 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; + +//! 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/submodules/SSignalKit/SwiftSignalKit/ThreadPool.swift b/submodules/SSignalKit/SwiftSignalKit/ThreadPool.swift new file mode 100644 index 0000000000..ec586a89fc --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/ThreadPool.swift @@ -0,0 +1,168 @@ +import Foundation + +public final class ThreadPoolTaskState { + public let cancelled = Atomic(value: false) +} + +public final class ThreadPoolTask { + private let state = ThreadPoolTaskState() + private let action: (ThreadPoolTaskState) -> () + + public init(_ action: @escaping(ThreadPoolTaskState) -> ()) { + self.action = action + } + + func execute() { + if !state.cancelled.with { $0 } { + self.action(self.state) + } + } + + public func cancel() { + let _ = self.state.cancelled.swap(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) + }) + } + } + + fileprivate func popFirstTask() -> ThreadPoolTask? { + if self.tasks.count != 0 { + let task = self.tasks[0]; + self.tasks.remove(at: 0) + return task + } else { + return nil + } + } + + fileprivate func hasTasks() -> Bool { + return self.tasks.count != 0 + } +} + +public func ==(lhs: ThreadPoolQueue, rhs: ThreadPoolQueue) -> Bool { + return lhs === rhs +} + +@objc public final class ThreadPool: NSObject { + 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) { + var queue: ThreadPoolQueue! + + while (true) { + var task: ThreadPoolTask! + + pthread_mutex_lock(&threadPool.mutex); + + if queue != nil { + if let index = threadPool.takenQueues.index(of: queue) { + threadPool.takenQueues.remove(at: 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 = threadPool.queues.index(of: queue) { + threadPool.queues.remove(at: index) + } + + break + } + } + pthread_mutex_unlock(&threadPool.mutex); + + if task != nil { + autoreleasepool { + 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) + + super.init() + + for _ in 0 ..< threadCount { + let thread = Thread(target: ThreadPool.self, selector: #selector(ThreadPool.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) + } + + fileprivate func workOnQueue(_ queue: ThreadPoolQueue, action: () -> ()) { + pthread_mutex_lock(&self.mutex) + action() + if !self.queues.contains(queue) && !self.takenQueues.contains(queue) { + self.queues.append(queue) + } + pthread_cond_broadcast(&self.condition) + pthread_mutex_unlock(&self.mutex) + } + + public func nextQueue() -> ThreadPoolQueue { + return ThreadPoolQueue(threadPool: self) + } + + public func isCurrentThreadInPool() -> Bool { + let currentThread = Thread.current + for thread in self.threads { + if currentThread.isEqual(thread) { + return true + } + } + return false + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/Timer.swift b/submodules/SSignalKit/SwiftSignalKit/Timer.swift new file mode 100644 index 0000000000..d52aaae3ea --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/Timer.swift @@ -0,0 +1,52 @@ +import Foundation + +public final class Timer { + private let timer = Atomic(value: nil) + private let timeout: Double + private let `repeat`: Bool + private let completion: () -> Void + private let queue: Queue + + public init(timeout: Double, `repeat`: Bool, completion: @escaping() -> Void, queue: Queue) { + self.timeout = timeout + self.`repeat` = `repeat` + self.completion = completion + self.queue = queue + } + + deinit { + self.invalidate() + } + + public func start() { + let timer = DispatchSource.makeTimerSource(queue: self.queue.queue) + timer.setEventHandler(handler: { [weak self] in + if let strongSelf = self { + strongSelf.completion() + if !strongSelf.`repeat` { + strongSelf.invalidate() + } + } + }) + let _ = self.timer.modify { _ in + return 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() { + let _ = self.timer.modify { timer in + timer?.cancel() + return nil + } + } +} diff --git a/submodules/SSignalKit/SwiftSignalKit/ValuePipe.swift b/submodules/SSignalKit/SwiftSignalKit/ValuePipe.swift new file mode 100644 index 0000000000..31b157435d --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKit/ValuePipe.swift @@ -0,0 +1,39 @@ +import Foundation + +public final class ValuePipe { + private let subscribers = Atomic(value: Bag<(T) -> Void>()) + + public init() { + } + + public func signal() -> Signal { + return Signal { [weak self] subscriber in + if let strongSelf = self { + let 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/submodules/SSignalKit/SwiftSignalKitMac/Info.plist b/submodules/SSignalKit/SwiftSignalKitMac/Info.plist new file mode 100644 index 0000000000..ab41b55afe --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SwiftSignalKitMac/SwiftSignalKitMac.h b/submodules/SSignalKit/SwiftSignalKitMac/SwiftSignalKitMac.h new file mode 100644 index 0000000000..eef45f9dd5 --- /dev/null +++ b/submodules/SSignalKit/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/submodules/SSignalKit/SwiftSignalKitTests/DeallocatingObject.swift b/submodules/SSignalKit/SwiftSignalKitTests/DeallocatingObject.swift new file mode 100644 index 0000000000..840ca1075b --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKitTests/DeallocatingObject.swift @@ -0,0 +1,19 @@ +import Foundation + +internal class DeallocatingObject : CustomStringConvertible { + private var deallocated: UnsafeMutablePointer + + init(deallocated: UnsafeMutablePointer) { + self.deallocated = deallocated + } + + deinit { + self.deallocated.pointee = true + } + + var description: String { + get { + return "" + } + } +} diff --git a/submodules/SSignalKit/SwiftSignalKitTests/Info.plist b/submodules/SSignalKit/SwiftSignalKitTests/Info.plist new file mode 100644 index 0000000000..ba72822e87 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/submodules/SSignalKit/SwiftSignalKitTests/PerformanceTests.swift b/submodules/SSignalKit/SwiftSignalKitTests/PerformanceTests.swift new file mode 100644 index 0000000000..313d02aacc --- /dev/null +++ b/submodules/SSignalKit/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: @escaping () -> 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: @escaping () -> 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: @escaping () -> 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: @escaping () -> 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/submodules/SSignalKit/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift b/submodules/SSignalKit/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift new file mode 100644 index 0000000000..210a969ff9 --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKitTests/SwiftSignalKitBasicTests.swift @@ -0,0 +1,281 @@ +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 + let _ = 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 { + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let _ = ActionDisposable(action: { [object] () -> Void in + let _ = object.debugDescription + disposed = true + }) + } + XCTAssertTrue(deallocated, "deallocated != true") + XCTAssertFalse(disposed, "disposed != false") + } + + func testMetaDisposableDisposed() { + var deallocated = false + var disposed = false + if true { + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + let _ = 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 { + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + let _ = object1.debugDescription + disposed1 = true + }) + + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + let _ = 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 { + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + let _ = 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 { + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + let _ = 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 { + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + let _ = object1.debugDescription + disposed1 = true + }) + + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + let _ = 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 { + let object: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated) + let disposable = ActionDisposable(action: { [object] () -> Void in + let _ = 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 { + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + let _ = object1.debugDescription + disposed1 = true + }) + + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + let _ = 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 { + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + let _ = object1.debugDescription + disposed1 = true + }) + + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + let _ = 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 { + let object1: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated1) + let actionDisposable1 = ActionDisposable(action: { [object1] () -> Void in + let _ = object1.debugDescription + disposed1 = true + }) + + let object2: DeallocatingObject? = DeallocatingObject(deallocated: &deallocated2) + let actionDisposable2 = ActionDisposable(action: { [object2] () -> Void in + let _ = 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") + } + + 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) + } +} diff --git a/submodules/SSignalKit/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift b/submodules/SSignalKit/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift new file mode 100644 index 0000000000..a7c418579d --- /dev/null +++ b/submodules/SSignalKit/SwiftSignalKitTests/SwiftSignalKitFunctionsTests.swift @@ -0,0 +1,733 @@ +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 { + let _ = object?.description + disposed = true + } + } + + let disposable = signal.start(next: { [object] next in + generated = true + let _ = 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 { + let _ = object?.description + disposed = true + } + } + + let disposable = signal.start(next: { [object] next in + generated = true + let _ = object?.description + }, completed: { [object] + completed = true + let _ = 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 { + let _ = object?.description + disposed = true + } + } + + let disposable = signal.start(next: { [object] next in + generated = true + let _ = object?.description + }, error: { [object] _ in + error = true + let _ = object?.description + }, + completed: { [object] + completed = true + let _ = 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 { + let _ = object?.description + disposed = true + } + } + signal = signal |> map { $0 * 2} + + let disposable = signal.start(next: { [object] next in + generated = next == 2 + let _ = 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 + let _ = catchSignal.start(next: { next in + result += next + }) + + XCTAssertTrue(result == 3, "result != 2") + } + + func testSubscriberDisposal() { + var disposed = false + var generated = false + let queue = DispatchQueue(label: "") + + if true { + let signal = Signal { subscriber in + queue.async { + usleep(200) + subscriber.putNext(1) + } + return ActionDisposable { + disposed = true + } + } + + let disposable = signal.start(next: { next in + generated = true + }) + disposable.dispose() + + queue.sync(flags: [.barrier], execute: {}) + + 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 + } + }) + + let _ = 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 + let _ = 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 + let _ = 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 = single(1, Void.self) + let s2 = fail(Int.self, Void()) + let s3 = complete(Int.self, Void.self) + + var singleEmitted = false + let _ = s1.start(next: { next in + singleEmitted = next == 1 + }) + XCTAssert(singleEmitted == true, "singleEmitted != true") + + var errorEmitted = false + let _ = s2.start(error: { error in + errorEmitted = true + }) + XCTAssert(errorEmitted == true, "errorEmitted != true") + + var completedEmitted = false + let _ = 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 { + 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 + let _ = objectOne?.description + disposedOne = true + } + } + + let two = Signal { subscriber in + subscriber.putNext(2) + subscriber.putCompletion() + return ActionDisposable { [objectTwo] in + let _ = objectTwo?.description + disposedTwo = true + } + } + + let three = Signal { subscriber in + subscriber.putNext(3) + subscriber.putCompletion() + return ActionDisposable { [objectThree] in + let _ = objectThree?.description + disposedThree = true + } + } + + let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> switchToLatest + + let _ = 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 + + let _ = signal.start(error: { error in + errorGenerated = true + }) + + XCTAssert(errorGenerated == true, "errorGenerated != true") + } + + func testQueue() { + let q = DispatchQueue(label: "") + + var disposedOne = false + var disposedTwo = false + var disposedThree = false + var completedAll = false + var result: [Int] = [] + + let one = Signal { subscriber in + q.async { + subscriber.putNext(1) + subscriber.putCompletion() + } + return ActionDisposable { + disposedOne = true + } + } + + let two = Signal { subscriber in + q.async { + subscriber.putNext(2) + subscriber.putCompletion() + } + return ActionDisposable { + disposedTwo = true + } + } + + let three = Signal { subscriber in + q.async { + subscriber.putNext(3) + subscriber.putCompletion() + } + return ActionDisposable { + disposedThree = true + } + } + + let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue + + let _ = signal.start(next: { next in + print("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 = DispatchQueue(label: "") + + var disposedOne = false + var disposedTwo = false + var disposedThree = false + var startedThird = false + var completedAll = false + var result: [Int] = [] + + let one = Signal { subscriber in + q.async { + subscriber.putNext(1) + subscriber.putCompletion() + } + return ActionDisposable { + disposedOne = true + } + } + + let two = Signal { subscriber in + q.async { + subscriber.putNext(2) + subscriber.putError(Void()) + } + return ActionDisposable { + disposedTwo = true + } + } + + let three = Signal { subscriber in + startedThird = true + q.async { + subscriber.putNext(3) + subscriber.putCompletion() + } + return ActionDisposable { + disposedThree = true + } + } + + let signal = singleSignalInt(one) |> then(singleSignalInt(two)) |> then(singleSignalInt(three)) |> queue + + let _ = 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 = DispatchQueue(label: "") + + 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 + q.async { + 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 + q.async { + 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 + q.async { + 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 = DispatchQueue(label: "", attributes: [.concurrent]) + let signal = Signal { subscriber in + q.async { + subscriber.putNext(1) + subscriber.putCompletion() + } + return EmptyDisposable + } + + var result = 0 + + let _ = (signal |> restart |> take(3)).start(next: { next in + result += next + }) + + usleep(100 * 1000) + + XCTAssert(result == 3, "result != 3") + } + + func testPipe() { + let pipe = ValuePipe() + + 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") + } + + 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) + } + + let _ = 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] = [] + let _ = 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)") + } + } + + func testMainQueueReentrant() { + let q = Queue.mainQueue() + + var a = 1 + q.async { + usleep(150 * 1000) + a = 2 + } + + XCTAssert(a == 2) + } +}