RACStream.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. //
  2. // RACStream.h
  3. // ReactiveObjC
  4. //
  5. // Created by Justin Spahr-Summers on 2012-10-31.
  6. // Copyright (c) 2012 GitHub, Inc. All rights reserved.
  7. //
  8. #import <Foundation/Foundation.h>
  9. @class RACStream;
  10. NS_ASSUME_NONNULL_BEGIN
  11. /// An abstract class representing any stream of values.
  12. ///
  13. /// This class represents a monad, upon which many stream-based operations can
  14. /// be built.
  15. ///
  16. /// When subclassing RACStream, only the methods in the main @interface body need
  17. /// to be overridden.
  18. @interface RACStream<__covariant ValueType> : NSObject
  19. /// Returns an empty stream.
  20. + (__kindof RACStream<ValueType> *)empty;
  21. /// Lifts `value` into the stream monad.
  22. ///
  23. /// Returns a stream containing only the given value.
  24. + (__kindof RACStream<ValueType> *)return:(nullable ValueType)value;
  25. /// A block which accepts a value from a RACStream and returns a new instance
  26. /// of the same stream class.
  27. ///
  28. /// Setting `stop` to `YES` will cause the bind to terminate after the returned
  29. /// value. Returning `nil` will result in immediate termination.
  30. typedef RACStream * _Nullable (^RACStreamBindBlock)(ValueType _Nullable value, BOOL *stop);
  31. /// Lazily binds a block to the values in the receiver.
  32. ///
  33. /// This should only be used if you need to terminate the bind early, or close
  34. /// over some state. -flattenMap: is more appropriate for all other cases.
  35. ///
  36. /// block - A block returning a RACStreamBindBlock. This block will be invoked
  37. /// each time the bound stream is re-evaluated. This block must not be
  38. /// nil or return nil.
  39. ///
  40. /// Returns a new stream which represents the combined result of all lazy
  41. /// applications of `block`.
  42. - (__kindof RACStream *)bind:(RACStreamBindBlock (^)(void))block;
  43. /// Appends the values of `stream` to the values in the receiver.
  44. ///
  45. /// stream - A stream to concatenate. This must be an instance of the same
  46. /// concrete class as the receiver, and should not be `nil`.
  47. ///
  48. /// Returns a new stream representing the receiver followed by `stream`.
  49. - (__kindof RACStream *)concat:(RACStream *)stream;
  50. /// Zips the values in the receiver with those of the given stream to create
  51. /// RACTuples.
  52. ///
  53. /// The first value of each stream will be combined, then the second value, and
  54. /// so forth, until at least one of the streams is exhausted.
  55. ///
  56. /// stream - The stream to zip with. This must be an instance of the same
  57. /// concrete class as the receiver, and should not be `nil`.
  58. ///
  59. /// Returns a new stream of RACTuples, representing the zipped values of the
  60. /// two streams.
  61. - (__kindof RACStream *)zipWith:(RACStream *)stream;
  62. @end
  63. /// This extension contains functionality to support naming streams for
  64. /// debugging.
  65. ///
  66. /// Subclasses do not need to override the methods here.
  67. @interface RACStream ()
  68. /// The name of the stream. This is for debugging/human purposes only.
  69. @property (copy) NSString *name;
  70. /// Sets the name of the receiver to the given format string.
  71. ///
  72. /// This is for debugging purposes only, and won't do anything unless the
  73. /// RAC_DEBUG_SIGNAL_NAMES environment variable is set.
  74. ///
  75. /// Returns the receiver, for easy method chaining.
  76. - (instancetype)setNameWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
  77. @end
  78. /// Operations built on the RACStream primitives.
  79. ///
  80. /// These methods do not need to be overridden, although subclasses may
  81. /// occasionally gain better performance from doing so.
  82. @interface RACStream<__covariant ValueType> (Operations)
  83. /// Maps `block` across the values in the receiver and flattens the result.
  84. ///
  85. /// Note that operators applied _after_ -flattenMap: behave differently from
  86. /// operators _within_ -flattenMap:. See the Examples section below.
  87. ///
  88. /// This corresponds to the `SelectMany` method in Rx.
  89. ///
  90. /// block - A block which accepts the values in the receiver and returns a new
  91. /// instance of the receiver's class. Returning `nil` from this block is
  92. /// equivalent to returning an empty signal.
  93. ///
  94. /// Examples
  95. ///
  96. /// [signal flattenMap:^(id x) {
  97. /// // Logs each time a returned signal completes.
  98. /// return [[RACSignal return:x] logCompleted];
  99. /// }];
  100. ///
  101. /// [[signal
  102. /// flattenMap:^(id x) {
  103. /// return [RACSignal return:x];
  104. /// }]
  105. /// // Logs only once, when all of the signals complete.
  106. /// logCompleted];
  107. ///
  108. /// Returns a new stream which represents the combined streams resulting from
  109. /// mapping `block`.
  110. - (__kindof RACStream *)flattenMap:(__kindof RACStream * _Nullable (^)(ValueType _Nullable value))block;
  111. /// Flattens a stream of streams.
  112. ///
  113. /// This corresponds to the `Merge` method in Rx.
  114. ///
  115. /// Returns a stream consisting of the combined streams obtained from the
  116. /// receiver.
  117. - (__kindof RACStream *)flatten;
  118. /// Maps `block` across the values in the receiver.
  119. ///
  120. /// This corresponds to the `Select` method in Rx.
  121. ///
  122. /// Returns a new stream with the mapped values.
  123. - (__kindof RACStream *)map:(id _Nullable (^)(ValueType _Nullable value))block;
  124. /// Replaces each value in the receiver with the given object.
  125. ///
  126. /// Returns a new stream which includes the given object once for each value in
  127. /// the receiver.
  128. - (__kindof RACStream *)mapReplace:(nullable id)object;
  129. /// Filters out values in the receiver that don't pass the given test.
  130. ///
  131. /// This corresponds to the `Where` method in Rx.
  132. ///
  133. /// Returns a new stream with only those values that passed.
  134. - (__kindof RACStream<ValueType> *)filter:(BOOL (^)(ValueType _Nullable value))block;
  135. /// Filters out values in the receiver that equal (via -isEqual:) the provided value.
  136. ///
  137. /// value - The value can be `nil`, in which case it ignores `nil` values.
  138. ///
  139. /// Returns a new stream containing only the values which did not compare equal
  140. /// to `value`.
  141. - (__kindof RACStream<ValueType> *)ignore:(nullable ValueType)value;
  142. /// Unpacks each RACTuple in the receiver and maps the values to a new value.
  143. ///
  144. /// reduceBlock - The block which reduces each RACTuple's values into one value.
  145. /// It must take as many arguments as the number of tuple elements
  146. /// to process. Each argument will be an object argument. The
  147. /// return value must be an object. This argument cannot be nil.
  148. ///
  149. /// Returns a new stream of reduced tuple values.
  150. - (__kindof RACStream *)reduceEach:(id _Nullable (^)())reduceBlock;
  151. /// Returns a stream consisting of `value`, followed by the values in the
  152. /// receiver.
  153. - (__kindof RACStream<ValueType> *)startWith:(nullable ValueType)value;
  154. /// Skips the first `skipCount` values in the receiver.
  155. ///
  156. /// Returns the receiver after skipping the first `skipCount` values. If
  157. /// `skipCount` is greater than the number of values in the stream, an empty
  158. /// stream is returned.
  159. - (__kindof RACStream<ValueType> *)skip:(NSUInteger)skipCount;
  160. /// Returns a stream of the first `count` values in the receiver. If `count` is
  161. /// greater than or equal to the number of values in the stream, a stream
  162. /// equivalent to the receiver is returned.
  163. - (__kindof RACStream<ValueType> *)take:(NSUInteger)count;
  164. /// Zips the values in the given streams to create RACTuples.
  165. ///
  166. /// The first value of each stream will be combined, then the second value, and
  167. /// so forth, until at least one of the streams is exhausted.
  168. ///
  169. /// streams - The streams to combine. These must all be instances of the same
  170. /// concrete class implementing the protocol. If this collection is
  171. /// empty, the returned stream will be empty.
  172. ///
  173. /// Returns a new stream containing RACTuples of the zipped values from the
  174. /// streams.
  175. + (__kindof RACStream<ValueType> *)zip:(id<NSFastEnumeration>)streams;
  176. /// Zips streams using +zip:, then reduces the resulting tuples into a single
  177. /// value using -reduceEach:
  178. ///
  179. /// streams - The streams to combine. These must all be instances of the
  180. /// same concrete class implementing the protocol. If this
  181. /// collection is empty, the returned stream will be empty.
  182. /// reduceBlock - The block which reduces the values from all the streams
  183. /// into one value. It must take as many arguments as the
  184. /// number of streams given. Each argument will be an object
  185. /// argument. The return value must be an object. This argument
  186. /// must not be nil.
  187. ///
  188. /// Example:
  189. ///
  190. /// [RACStream zip:@[ stringSignal, intSignal ] reduce:^(NSString *string, NSNumber *number) {
  191. /// return [NSString stringWithFormat:@"%@: %@", string, number];
  192. /// }];
  193. ///
  194. /// Returns a new stream containing the results from each invocation of
  195. /// `reduceBlock`.
  196. + (__kindof RACStream<ValueType> *)zip:(id<NSFastEnumeration>)streams reduce:(id _Nullable (^)())reduceBlock;
  197. /// Returns a stream obtained by concatenating `streams` in order.
  198. + (__kindof RACStream<ValueType> *)concat:(id<NSFastEnumeration>)streams;
  199. /// Combines values in the receiver from left to right using the given block.
  200. ///
  201. /// The algorithm proceeds as follows:
  202. ///
  203. /// 1. `startingValue` is passed into the block as the `running` value, and the
  204. /// first element of the receiver is passed into the block as the `next` value.
  205. /// 2. The result of the invocation is added to the returned stream.
  206. /// 3. The result of the invocation (`running`) and the next element of the
  207. /// receiver (`next`) is passed into `block`.
  208. /// 4. Steps 2 and 3 are repeated until all values have been processed.
  209. ///
  210. /// startingValue - The value to be combined with the first element of the
  211. /// receiver. This value may be `nil`.
  212. /// reduceBlock - The block that describes how to combine values of the
  213. /// receiver. If the receiver is empty, this block will never be
  214. /// invoked. Cannot be nil.
  215. ///
  216. /// Examples
  217. ///
  218. /// RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
  219. ///
  220. /// // Contains 1, 3, 6, 10
  221. /// RACSequence *sums = [numbers scanWithStart:@0 reduce:^(NSNumber *sum, NSNumber *next) {
  222. /// return @(sum.integerValue + next.integerValue);
  223. /// }];
  224. ///
  225. /// Returns a new stream that consists of each application of `reduceBlock`. If the
  226. /// receiver is empty, an empty stream is returned.
  227. - (__kindof RACStream *)scanWithStart:(nullable id)startingValue reduce:(id _Nullable (^)(id _Nullable running, ValueType _Nullable next))reduceBlock;
  228. /// Combines values in the receiver from left to right using the given block
  229. /// which also takes zero-based index of the values.
  230. ///
  231. /// startingValue - The value to be combined with the first element of the
  232. /// receiver. This value may be `nil`.
  233. /// reduceBlock - The block that describes how to combine values of the
  234. /// receiver. This block takes zero-based index value as the last
  235. /// parameter. If the receiver is empty, this block will never
  236. /// be invoked. Cannot be nil.
  237. ///
  238. /// Returns a new stream that consists of each application of `reduceBlock`. If the
  239. /// receiver is empty, an empty stream is returned.
  240. - (__kindof RACStream *)scanWithStart:(nullable id)startingValue reduceWithIndex:(id _Nullable (^)(id _Nullable running, ValueType _Nullable next, NSUInteger index))reduceBlock;
  241. /// Combines each previous and current value into one object.
  242. ///
  243. /// This method is similar to -scanWithStart:reduce:, but only ever operates on
  244. /// the previous and current values (instead of the whole stream), and does not
  245. /// pass the return value of `reduceBlock` into the next invocation of it.
  246. ///
  247. /// start - The value passed into `reduceBlock` as `previous` for the
  248. /// first value.
  249. /// reduceBlock - The block that combines the previous value and the current
  250. /// value to create the reduced value. Cannot be nil.
  251. ///
  252. /// Examples
  253. ///
  254. /// RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
  255. ///
  256. /// // Contains 1, 3, 5, 7
  257. /// RACSequence *sums = [numbers combinePreviousWithStart:@0 reduce:^(NSNumber *previous, NSNumber *next) {
  258. /// return @(previous.integerValue + next.integerValue);
  259. /// }];
  260. ///
  261. /// Returns a new stream consisting of the return values from each application of
  262. /// `reduceBlock`.
  263. - (__kindof RACStream *)combinePreviousWithStart:(nullable ValueType)start reduce:(id _Nullable (^)(ValueType _Nullable previous, ValueType _Nullable current))reduceBlock;
  264. /// Takes values until the given block returns `YES`.
  265. ///
  266. /// Returns a stream of the initial values in the receiver that fail `predicate`.
  267. /// If `predicate` never returns `YES`, a stream equivalent to the receiver is
  268. /// returned.
  269. - (__kindof RACStream<ValueType> *)takeUntilBlock:(BOOL (^)(ValueType _Nullable x))predicate;
  270. /// Takes values until the given block returns `NO`.
  271. ///
  272. /// Returns a stream of the initial values in the receiver that pass `predicate`.
  273. /// If `predicate` never returns `NO`, a stream equivalent to the receiver is
  274. /// returned.
  275. - (__kindof RACStream<ValueType> *)takeWhileBlock:(BOOL (^)(ValueType _Nullable x))predicate;
  276. /// Skips values until the given block returns `YES`.
  277. ///
  278. /// Returns a stream containing the values of the receiver that follow any
  279. /// initial values failing `predicate`. If `predicate` never returns `YES`,
  280. /// an empty stream is returned.
  281. - (__kindof RACStream<ValueType> *)skipUntilBlock:(BOOL (^)(ValueType _Nullable x))predicate;
  282. /// Skips values until the given block returns `NO`.
  283. ///
  284. /// Returns a stream containing the values of the receiver that follow any
  285. /// initial values passing `predicate`. If `predicate` never returns `NO`, an
  286. /// empty stream is returned.
  287. - (__kindof RACStream<ValueType> *)skipWhileBlock:(BOOL (^)(ValueType _Nullable x))predicate;
  288. /// Returns a stream of values for which -isEqual: returns NO when compared to the
  289. /// previous value.
  290. - (__kindof RACStream<ValueType> *)distinctUntilChanged;
  291. @end
  292. NS_ASSUME_NONNULL_END