Skip to content

Commit 7b23858

Browse files
authored
Merge pull request #511 from ReactiveCocoa/anders/migrate-operators
Migrate operators Vol III.
2 parents 3e2b194 + 27f4990 commit 7b23858

File tree

3 files changed

+291
-223
lines changed

3 files changed

+291
-223
lines changed

Sources/Event.swift

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,51 @@ extension Signal.Event {
280280
}
281281
}
282282

283+
internal static func attemptMap<U>(_ transform: @escaping (Value) -> Result<U, Error>) -> Transformation<U, Error> {
284+
return { action in
285+
return { event in
286+
switch event {
287+
case let .value(value):
288+
switch transform(value) {
289+
case let .success(value):
290+
action(.value(value))
291+
case let .failure(error):
292+
action(.failed(error))
293+
}
294+
case let .failed(error):
295+
action(.failed(error))
296+
case .completed:
297+
action(.completed)
298+
case .interrupted:
299+
action(.interrupted)
300+
}
301+
}
302+
}
303+
}
304+
305+
internal static func attempt(_ action: @escaping (Value) -> Result<(), Error>) -> Transformation<Value, Error> {
306+
return attemptMap { value -> Result<Value, Error> in
307+
return action(value).map { _ in value }
308+
}
309+
}
310+
}
311+
312+
extension Signal.Event where Error == AnyError {
313+
internal static func attempt(_ action: @escaping (Value) throws -> Void) -> Transformation<Value, AnyError> {
314+
return attemptMap { value in
315+
try action(value)
316+
return value
317+
}
318+
}
319+
320+
internal static func attemptMap<U>(_ transform: @escaping (Value) throws -> U) -> Transformation<U, AnyError> {
321+
return attemptMap { value in
322+
ReactiveSwift.materialize { try transform(value) }
323+
}
324+
}
325+
}
326+
327+
extension Signal.Event {
283328
internal static func take(first count: Int) -> Transformation<Value, Error> {
284329
assert(count >= 1)
285330

@@ -304,6 +349,46 @@ extension Signal.Event {
304349
}
305350
}
306351

352+
internal static func take(last count: Int) -> Transformation<Value, Error> {
353+
return { action in
354+
var buffer: [Value] = []
355+
buffer.reserveCapacity(count)
356+
357+
return { event in
358+
switch event {
359+
case let .value(value):
360+
// To avoid exceeding the reserved capacity of the buffer,
361+
// we remove then add. Remove elements until we have room to
362+
// add one more.
363+
while (buffer.count + 1) > count {
364+
buffer.remove(at: 0)
365+
}
366+
367+
buffer.append(value)
368+
case let .failed(error):
369+
action(.failed(error))
370+
case .completed:
371+
buffer.forEach { action(.value($0)) }
372+
action(.completed)
373+
case .interrupted:
374+
action(.interrupted)
375+
}
376+
}
377+
}
378+
}
379+
380+
internal static func take(while shouldContinue: @escaping (Value) -> Bool) -> Transformation<Value, Error> {
381+
return { action in
382+
return { event in
383+
if let value = event.value, !shouldContinue(value) {
384+
action(.completed)
385+
} else {
386+
action(event)
387+
}
388+
}
389+
}
390+
}
391+
307392
internal static func skip(first count: Int) -> Transformation<Value, Error> {
308393
precondition(count > 0)
309394

@@ -319,6 +404,25 @@ extension Signal.Event {
319404
}
320405
}
321406
}
407+
408+
internal static func skip(while shouldContinue: @escaping (Value) -> Bool) -> Transformation<Value, Error> {
409+
return { action in
410+
var isSkipping = true
411+
412+
return { event in
413+
switch event {
414+
case let .value(value):
415+
isSkipping = isSkipping && shouldContinue(value)
416+
if !isSkipping {
417+
fallthrough
418+
}
419+
420+
case .failed, .completed, .interrupted:
421+
action(event)
422+
}
423+
}
424+
}
425+
}
322426
}
323427

324428
extension Signal.Event where Value: EventProtocol {
@@ -443,6 +547,112 @@ extension Signal.Event {
443547
}
444548
}
445549

550+
/// Implementation detail of `combinePrevious`. A default argument of a `nil` initial
551+
/// is deliberately avoided, since in the case of `Value` being an optional, the
552+
/// `nil` literal would be materialized as `Optional<Value>.none` instead of `Value`,
553+
/// thus changing the semantic.
554+
internal static func combinePrevious(initial: Value?) -> Transformation<(Value, Value), Error> {
555+
return { action in
556+
var previous = initial
557+
558+
return { event in
559+
switch event {
560+
case let .value(value):
561+
if let previous = previous {
562+
action(.value((previous, value)))
563+
}
564+
previous = value
565+
case .completed:
566+
action(.completed)
567+
case let .failed(error):
568+
action(.failed(error))
569+
case .interrupted:
570+
action(.interrupted)
571+
}
572+
}
573+
}
574+
}
575+
576+
internal static func skipRepeats(_ isEquivalent: @escaping (Value, Value) -> Bool) -> Transformation<Value, Error> {
577+
return { action in
578+
var previous: Value?
579+
580+
return { event in
581+
switch event {
582+
case let .value(value):
583+
if let previous = previous, isEquivalent(previous, value) {
584+
return
585+
}
586+
previous = value
587+
fallthrough
588+
case .completed, .interrupted, .failed:
589+
action(event)
590+
}
591+
}
592+
}
593+
}
594+
595+
internal static func uniqueValues<Identity: Hashable>(_ transform: @escaping (Value) -> Identity) -> Transformation<Value, Error> {
596+
return { action in
597+
var seenValues: Set<Identity> = []
598+
599+
return { event in
600+
switch event {
601+
case let .value(value):
602+
let identity = transform(value)
603+
let (inserted, _) = seenValues.insert(identity)
604+
if inserted {
605+
fallthrough
606+
}
607+
608+
case .failed, .completed, .interrupted:
609+
action(event)
610+
}
611+
}
612+
}
613+
}
614+
615+
internal static func scan<U>(into initialResult: U, _ nextPartialResult: @escaping (inout U, Value) -> Void) -> Transformation<U, Error> {
616+
return { action in
617+
var accumulator = initialResult
618+
619+
return { event in
620+
action(event.map { value in
621+
nextPartialResult(&accumulator, value)
622+
return accumulator
623+
})
624+
}
625+
}
626+
}
627+
628+
internal static func scan<U>(_ initialResult: U, _ nextPartialResult: @escaping (U, Value) -> U) -> Transformation<U, Error> {
629+
return scan(into: initialResult) { $0 = nextPartialResult($0, $1) }
630+
}
631+
632+
internal static func reduce<U>(into initialResult: U, _ nextPartialResult: @escaping (inout U, Value) -> Void) -> Transformation<U, Error> {
633+
return { action in
634+
var accumulator = initialResult
635+
636+
return { event in
637+
switch event {
638+
case let .value(value):
639+
nextPartialResult(&accumulator, value)
640+
case .completed:
641+
action(.value(accumulator))
642+
action(.completed)
643+
case .interrupted:
644+
action(.interrupted)
645+
case let .failed(error):
646+
action(.failed(error))
647+
}
648+
}
649+
}
650+
}
651+
652+
internal static func reduce<U>(_ initialResult: U, _ nextPartialResult: @escaping (U, Value) -> U) -> Transformation<U, Error> {
653+
return reduce(into: initialResult) { $0 = nextPartialResult($0, $1) }
654+
}
655+
446656
internal static func observe(on scheduler: Scheduler) -> Transformation<Value, Error> {
447657
return { action in
448658
return { event in
@@ -474,3 +684,41 @@ extension Signal.Event {
474684
}
475685
}
476686
}
687+
688+
extension Signal.Event where Error == NoError {
689+
internal static func promoteError<F>(_: F.Type) -> Transformation<Value, F> {
690+
return { action in
691+
return { event in
692+
switch event {
693+
case let .value(value):
694+
action(.value(value))
695+
case .failed:
696+
fatalError("NoError is impossible to construct")
697+
case .completed:
698+
action(.completed)
699+
case .interrupted:
700+
action(.interrupted)
701+
}
702+
}
703+
}
704+
}
705+
}
706+
707+
extension Signal.Event where Value == Never {
708+
internal static func promoteValue<U>(_: U.Type) -> Transformation<U, Error> {
709+
return { action in
710+
return { event in
711+
switch event {
712+
case .value:
713+
fatalError("Never is impossible to construct")
714+
case let .failed(error):
715+
action(.failed(error))
716+
case .completed:
717+
action(.completed)
718+
case .interrupted:
719+
action(.interrupted)
720+
}
721+
}
722+
}
723+
}
724+
}

0 commit comments

Comments
 (0)