forked from ReactiveCocoa/ReactiveObjC
/
RACSequence.h
419 lines (368 loc) · 17.8 KB
/
RACSequence.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
//
// RACSequence.h
// ReactiveObjC
//
// Created by Justin Spahr-Summers on 2012-10-29.
// Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACStream.h"
@class RACTuple;
@class RACScheduler;
@class RACSignal<__covariant ValueType>;
NS_ASSUME_NONNULL_BEGIN
/// Represents an immutable sequence of values. Unless otherwise specified, the
/// sequences' values are evaluated lazily on demand. Like Cocoa collections,
/// sequences cannot contain nil.
///
/// Most inherited RACStream methods that accept a block will execute the block
/// _at most_ once for each value that is evaluated in the returned sequence.
/// Side effects are subject to the behavior described in
/// +sequenceWithHeadBlock:tailBlock:.
///
/// Implemented as a class cluster. A minimal implementation for a subclass
/// consists simply of -head and -tail.
@interface RACSequence<__covariant ValueType> : RACStream <NSCoding, NSCopying, NSFastEnumeration>
/// The first object in the sequence, or nil if the sequence is empty.
///
/// Subclasses must provide an implementation of this method.
@property (nonatomic, strong, readonly, nullable) ValueType head;
/// All but the first object in the sequence, or nil if there are no other
/// objects.
///
/// Subclasses must provide an implementation of this method.
@property (nonatomic, strong, readonly, nullable) RACSequence<ValueType> *tail;
/// Evaluates the full sequence to produce an equivalently-sized array.
@property (nonatomic, copy, readonly) NSArray<ValueType> *array;
/// Returns an enumerator of all objects in the sequence.
@property (nonatomic, copy, readonly) NSEnumerator<ValueType> *objectEnumerator;
/// Converts a sequence into an eager sequence.
///
/// An eager sequence fully evaluates all of its values immediately. Sequences
/// derived from an eager sequence will also be eager.
///
/// Returns a new eager sequence, or the receiver if the sequence is already
/// eager.
@property (nonatomic, copy, readonly) RACSequence<ValueType> *eagerSequence;
/// Converts a sequence into a lazy sequence.
///
/// A lazy sequence evaluates its values on demand, as they are accessed.
/// Sequences derived from a lazy sequence will also be lazy.
///
/// Returns a new lazy sequence, or the receiver if the sequence is already lazy.
@property (nonatomic, copy, readonly) RACSequence<ValueType> *lazySequence;
/// Invokes -signalWithScheduler: with a new RACScheduler.
- (RACSignal<ValueType> *)signal;
/// Evaluates the full sequence on the given scheduler.
///
/// Each item is evaluated in its own scheduled block, such that control of the
/// scheduler is yielded between each value.
///
/// Returns a signal which sends the receiver's values on the given scheduler as
/// they're evaluated.
- (RACSignal<ValueType> *)signalWithScheduler:(RACScheduler *)scheduler;
/// Applies a left fold to the sequence.
///
/// This is the same as iterating the sequence along with a provided start value.
/// This uses a constant amount of memory. A left fold is left-associative so in
/// the sequence [1,2,3] the block would applied in the following order:
/// reduce(reduce(reduce(start, 1), 2), 3)
///
/// start - The starting value for the fold. Used as `accumulator` for the
/// first fold.
/// reduce - The block used to combine the accumulated value and the next value.
/// Cannot be nil.
///
/// Returns a reduced value.
- (id)foldLeftWithStart:(nullable id)start reduce:(id _Nullable (^)(id _Nullable accumulator, ValueType _Nullable value))reduce;
/// Applies a right fold to the sequence.
///
/// A right fold is equivalent to recursion on the list. The block is evaluated
/// from the right to the left in list. It is right associative so it's applied
/// to the rightmost elements first. For example, in the sequence [1,2,3] the
/// block is applied in the order:
/// reduce(1, reduce(2, reduce(3, start)))
///
/// start - The starting value for the fold.
/// reduce - The block used to combine the accumulated value and the next head.
/// The block is given the accumulated value and the value of the rest
/// of the computation (result of the recursion). This is computed when
/// you retrieve its value using `rest.head`. This allows you to
/// prevent unnecessary computation by not accessing `rest.head` if you
/// don't need to.
///
/// Returns a reduced value.
- (id)foldRightWithStart:(nullable id)start reduce:(id _Nullable (^)(id _Nullable first, RACSequence *rest))reduce;
/// Check if any value in sequence passes the block.
///
/// block - The block predicate used to check each item. Cannot be nil.
///
/// Returns a boolean indiciating if any value in the sequence passed.
- (BOOL)any:(BOOL (^)(ValueType _Nullable value))block;
/// Check if all values in the sequence pass the block.
///
/// block - The block predicate used to check each item. Cannot be nil.
///
/// Returns a boolean indicating if all values in the sequence passed.
- (BOOL)all:(BOOL (^)(ValueType _Nullable value))block;
/// Returns the first object that passes the block.
///
/// block - The block predicate used to check each item. Cannot be nil.
///
/// Returns an object that passes the block or nil if no objects passed.
- (nullable ValueType)objectPassingTest:(BOOL (^)(ValueType _Nullable value))block;
/// Creates a sequence that dynamically generates its values.
///
/// headBlock - Invoked the first time -head is accessed.
/// tailBlock - Invoked the first time -tail is accessed.
///
/// The results from each block are memoized, so each block will be invoked at
/// most once, no matter how many times the head and tail properties of the
/// sequence are accessed.
///
/// Any side effects in `headBlock` or `tailBlock` should be thread-safe, since
/// the sequence may be evaluated at any time from any thread. Not only that, but
/// -tail may be accessed before -head, or both may be accessed simultaneously.
/// As noted above, side effects will only be triggered the _first_ time -head or
/// -tail is invoked.
///
/// Returns a sequence that lazily invokes the given blocks to provide head and
/// tail. `headBlock` must not be nil.
+ (RACSequence<ValueType> *)sequenceWithHeadBlock:(ValueType _Nullable (^)(void))headBlock tailBlock:(nullable RACSequence<ValueType> *(^)(void))tailBlock;
@end
@interface RACSequence<__covariant ValueType> (RACStream)
/// Returns a sequence that immediately sends the given value and then completes.
+ (RACSequence<ValueType> *)return:(nullable ValueType)value;
/// Returns a sequence that immediately completes.
+ (RACSequence<ValueType> *)empty;
/// A block which accepts a value from a RACSequence and returns a new sequence.
///
/// Setting `stop` to `YES` will cause the bind to terminate after the returned
/// value. Returning `nil` will result in immediate termination.
typedef RACSequence * _Nullable (^RACSequenceBindBlock)(ValueType _Nullable value, BOOL *stop);
/// Lazily binds a block to the values in the receiver.
///
/// This should only be used if you need to terminate the bind early, or close
/// over some state. -flattenMap: is more appropriate for all other cases.
///
/// block - A block returning a RACSequenceBindBlock. This block will be invoked
/// each time the bound sequence is re-evaluated. This block must not be
/// nil or return nil.
///
/// Returns a new sequence which represents the combined result of all lazy
/// applications of `block`.
- (RACSequence *)bind:(RACSequenceBindBlock (^)(void))block;
/// Subscribes to `sequence` when the source sequence completes.
- (RACSequence *)concat:(RACSequence *)sequence;
/// Zips the values in the receiver with those of the given sequence to create
/// RACTuples.
///
/// The first `next` of each sequence will be combined, then the second `next`,
/// and so forth, until either sequence completes or errors.
///
/// sequence - The sequence to zip with. This must not be `nil`.
///
/// Returns a new sequence of RACTuples, representing the combined values of the
/// two sequences. Any error from one of the original sequence will be forwarded
/// on the returned sequence.
- (RACSequence<RACTuple *> *)zipWith:(RACSequence *)sequence;
@end
/// Redeclarations of operations built on the RACStream primitives with more
/// precise type information.
@interface RACSequence<__covariant ValueType> (RACStreamOperations)
/// Maps `block` across the values in the receiver and flattens the result.
///
/// Note that operators applied _after_ -flattenMap: behave differently from
/// operators _within_ -flattenMap:. See the Examples section below.
///
/// This corresponds to the `SelectMany` method in Rx.
///
/// block - A block which accepts the values in the receiver and returns a new
/// instance of the receiver's class. Returning `nil` from this block is
/// equivalent to returning an empty sequence.
///
/// Returns a new sequence which represents the combined sequences resulting
/// from mapping `block`.
- (RACSequence *)flattenMap:(__kindof RACSequence * _Nullable (^)(ValueType _Nullable value))block;
/// Flattens a sequence of sequences.
///
/// This corresponds to the `Merge` method in Rx.
///
/// Returns a sequence consisting of the combined sequences obtained from the
/// receiver.
- (RACSequence *)flatten;
/// Maps `block` across the values in the receiver.
///
/// This corresponds to the `Select` method in Rx.
///
/// Returns a new sequence with the mapped values.
- (RACSequence *)map:(id _Nullable (^)(ValueType _Nullable value))block;
/// Replaces each value in the receiver with the given object.
///
/// Returns a new sequence which includes the given object once for each value in
/// the receiver.
- (RACSequence *)mapReplace:(nullable id)object;
/// Filters out values in the receiver that don't pass the given test.
///
/// This corresponds to the `Where` method in Rx.
///
/// Returns a new sequence with only those values that passed.
- (RACSequence<ValueType> *)filter:(BOOL (^)(id _Nullable value))block;
/// Filters out values in the receiver that equal (via -isEqual:) the provided
/// value.
///
/// value - The value can be `nil`, in which case it ignores `nil` values.
///
/// Returns a new sequence containing only the values which did not compare
/// equal to `value`.
- (RACSequence *)ignore:(nullable ValueType)value;
/// Unpacks each RACTuple in the receiver and maps the values to a new value.
///
/// reduceBlock - The block which reduces each RACTuple's values into one value.
/// It must take as many arguments as the number of tuple elements
/// to process. Each argument will be an object argument. The
/// return value must be an object. This argument cannot be nil.
///
/// Returns a new sequence of reduced tuple values.
- (RACSequence *)reduceEach:(RACReduceBlock)reduceBlock;
/// Returns a sequence consisting of `value`, followed by the values in the
/// receiver.
- (RACSequence<ValueType> *)startWith:(nullable ValueType)value;
/// Skips the first `skipCount` values in the receiver.
///
/// Returns the receiver after skipping the first `skipCount` values. If
/// `skipCount` is greater than the number of values in the sequence, an empty
/// sequence is returned.
- (RACSequence<ValueType> *)skip:(NSUInteger)skipCount;
/// Returns a sequence of the first `count` values in the receiver. If `count` is
/// greater than or equal to the number of values in the sequence, a sequence
/// equivalent to the receiver is returned.
- (RACSequence<ValueType> *)take:(NSUInteger)count;
/// Zips the values in the given sequences to create RACTuples.
///
/// The first value of each sequence will be combined, then the second value,
/// and so forth, until at least one of the sequences is exhausted.
///
/// sequences - The sequence to combine. If this collection is empty, the
/// returned sequence will be empty.
///
/// Returns a new sequence containing RACTuples of the zipped values from the
/// sequences.
+ (RACSequence<RACTuple *> *)zip:(id<NSFastEnumeration>)sequence;
/// Zips sequences using +zip:, then reduces the resulting tuples into a single
/// value using -reduceEach:
///
/// sequences - The sequences to combine. If this collection is empty, the
/// returned sequence will be empty.
/// reduceBlock - The block which reduces the values from all the sequences
/// into one value. It must take as many arguments as the
/// number of sequences given. Each argument will be an object
/// argument. The return value must be an object. This argument
/// must not be nil.
///
/// Example:
///
/// [RACSequence zip:@[ stringSequence, intSequence ]
/// reduce:^(NSString *string, NSNumber *number) {
/// return [NSString stringWithFormat:@"%@: %@", string, number];
/// }];
///
/// Returns a new sequence containing the results from each invocation of
/// `reduceBlock`.
+ (RACSequence<ValueType> *)zip:(id<NSFastEnumeration>)sequences reduce:(RACReduceBlock)reduceBlock;
/// Returns a sequence obtained by concatenating `sequences` in order.
+ (RACSequence<ValueType> *)concat:(id<NSFastEnumeration>)sequences;
/// Combines values in the receiver from left to right using the given block.
///
/// The algorithm proceeds as follows:
///
/// 1. `startingValue` is passed into the block as the `running` value, and the
/// first element of the receiver is passed into the block as the `next` value.
/// 2. The result of the invocation is added to the returned sequence.
/// 3. The result of the invocation (`running`) and the next element of the
/// receiver (`next`) is passed into `block`.
/// 4. Steps 2 and 3 are repeated until all values have been processed.
///
/// startingValue - The value to be combined with the first element of the
/// receiver. This value may be `nil`.
/// reduceBlock - The block that describes how to combine values of the
/// receiver. If the receiver is empty, this block will never be
/// invoked. Cannot be nil.
///
/// Examples
///
/// RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
///
/// // Contains 1, 3, 6, 10
/// RACSequence *sums = [numbers scanWithStart:@0 reduce:^(NSNumber *sum, NSNumber *next) {
/// return @(sum.integerValue + next.integerValue);
/// }];
///
/// Returns a new sequence that consists of each application of `reduceBlock`. If
/// the receiver is empty, an empty sequence is returned.
- (RACSequence *)scanWithStart:(nullable id)startingValue reduce:(id _Nullable (^)(id _Nullable running, ValueType _Nullable next))reduceBlock;
/// Combines values in the receiver from left to right using the given block
/// which also takes zero-based index of the values.
///
/// startingValue - The value to be combined with the first element of the
/// receiver. This value may be `nil`.
/// reduceBlock - The block that describes how to combine values of the
/// receiver. This block takes zero-based index value as the last
/// parameter. If the receiver is empty, this block will never
/// be invoked. Cannot be nil.
///
/// Returns a new sequence that consists of each application of `reduceBlock`.
/// If the receiver is empty, an empty sequence is returned.
- (RACSequence *)scanWithStart:(nullable id)startingValue reduceWithIndex:(id _Nullable (^)(id _Nullable running, ValueType _Nullable next, NSUInteger index))reduceBlock;
/// Combines each previous and current value into one object.
///
/// This method is similar to -scanWithStart:reduce:, but only ever operates on
/// the previous and current values (instead of the whole sequence), and does
/// not pass the return value of `reduceBlock` into the next invocation of it.
///
/// start - The value passed into `reduceBlock` as `previous` for the
/// first value.
/// reduceBlock - The block that combines the previous value and the current
/// value to create the reduced value. Cannot be nil.
///
/// Examples
///
/// RACSequence *numbers = [@[ @1, @2, @3, @4 ].rac_sequence;
///
/// // Contains 1, 3, 5, 7
/// RACSequence *sums = [numbers combinePreviousWithStart:@0 reduce:^(NSNumber *previous, NSNumber *next) {
/// return @(previous.integerValue + next.integerValue);
/// }];
///
/// Returns a new sequence consisting of the return values from each application of
/// `reduceBlock`.
- (RACSequence *)combinePreviousWithStart:(nullable ValueType)start reduce:(id _Nullable (^)(ValueType _Nullable previous, ValueType _Nullable current))reduceBlock;
/// Takes values until the given block returns `YES`.
///
/// Returns a RACSequence of the initial values in the receiver that fail
/// `predicate`. If `predicate` never returns `YES`, a sequence equivalent to
/// the receiver is returned.
- (RACSequence<ValueType> *)takeUntilBlock:(BOOL (^)(ValueType _Nullable x))predicate;
/// Takes values until the given block returns `NO`.
///
/// Returns a sequence of the initial values in the receiver that pass
/// `predicate`. If `predicate` never returns `NO`, a sequence equivalent to the
/// receiver is returned.
- (RACSequence<ValueType> *)takeWhileBlock:(BOOL (^)(ValueType _Nullable x))predicate;
/// Skips values until the given block returns `YES`.
///
/// Returns a sequence containing the values of the receiver that follow any
/// initial values failing `predicate`. If `predicate` never returns `YES`,
/// an empty sequence is returned.
- (RACSequence<ValueType> *)skipUntilBlock:(BOOL (^)(ValueType _Nullable x))predicate;
/// Skips values until the given block returns `NO`.
///
/// Returns a sequence containing the values of the receiver that follow any
/// initial values passing `predicate`. If `predicate` never returns `NO`, an
/// empty sequence is returned.
- (RACSequence<ValueType> *)skipWhileBlock:(BOOL (^)(ValueType _Nullable x))predicate;
/// Returns a sequence of values for which -isEqual: returns NO when compared to
/// the previous value.
- (RACSequence<ValueType> *)distinctUntilChanged;
@end
NS_ASSUME_NONNULL_END