blob: c5d6d1310ae5f91d132d09d60de5316d06f473dc [file] [log] [blame]
Jorge Canizalese8304d52015-02-17 19:50:51 -08001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Jorge Canizalese8304d52015-02-17 19:50:51 -08004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Jorge Canizalese8304d52015-02-17 19:50:51 -08008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Jorge Canizalese8304d52015-02-17 19:50:51 -080010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Jorge Canizalese8304d52015-02-17 19:50:51 -080016 *
17 */
18
Jorge Canizales30697c92015-02-17 17:09:14 -080019#import "GRXImmediateWriter.h"
20
21#import "NSEnumerator+GRXUtil.h"
22
23@implementation GRXImmediateWriter {
24 NSEnumerator *_enumerator;
25 NSError *_errorOrNil;
26 id<GRXWriteable> _writeable;
27}
28
29@synthesize state = _state;
30
31- (instancetype) init {
32 return [self initWithEnumerator:nil error:nil]; // results in an empty writer.
33}
34
35// Designated initializer
36- (instancetype)initWithEnumerator:(NSEnumerator *)enumerator error:(NSError *)errorOrNil {
37 if (((self = [super init]))) {
38 _enumerator = enumerator;
39 _errorOrNil = errorOrNil;
40 _state = GRXWriterStateNotStarted;
41 }
42 return self;
43}
44
45#pragma mark Convenience constructors
46
47+ (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator error:(NSError *)errorOrNil {
48 return [[self alloc] initWithEnumerator:enumerator error:errorOrNil];
49}
50
Jorge Canizales56047122015-07-17 12:18:08 -070051+ (GRXWriter *)writerWithEnumerator:(NSEnumerator *)enumerator {
Jorge Canizales30697c92015-02-17 17:09:14 -080052 return [self writerWithEnumerator:enumerator error:nil];
53}
54
Muxi Yan0c0ebc52017-10-19 18:41:01 -070055+ (GRXWriter *)writerWithValueSupplier:(id (^)(void))block {
Jorge Canizales30697c92015-02-17 17:09:14 -080056 return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithValueSupplier:block]];
57}
58
Jorge Canizales56047122015-07-17 12:18:08 -070059+ (GRXWriter *)writerWithContainer:(id<NSFastEnumeration>)container {
Jorge Canizales30697c92015-02-17 17:09:14 -080060 return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithContainer:container]];;
61}
62
Jorge Canizales56047122015-07-17 12:18:08 -070063+ (GRXWriter *)writerWithValue:(id)value {
Jorge Canizalesbc970ae2015-07-19 12:27:20 -070064 return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithSingleValue:value]];
Jorge Canizales30697c92015-02-17 17:09:14 -080065}
66
Jorge Canizales56047122015-07-17 12:18:08 -070067+ (GRXWriter *)writerWithError:(NSError *)error {
Jorge Canizalesbc970ae2015-07-19 12:27:20 -070068 return [self writerWithEnumerator:nil error:error];
Jorge Canizales30697c92015-02-17 17:09:14 -080069}
70
Jorge Canizales56047122015-07-17 12:18:08 -070071+ (GRXWriter *)emptyWriter {
Jorge Canizalesbc970ae2015-07-19 12:27:20 -070072 return [self writerWithEnumerator:nil error:nil];
Jorge Canizales30697c92015-02-17 17:09:14 -080073}
74
75#pragma mark Conformance with GRXWriter
76
77// Most of the complexity in this implementation is the result of supporting pause and resumption of
78// the GRXWriter. It's an important feature for instances of GRXWriter that are backed by a
79// container (which may be huge), or by a NSEnumerator (which may even be infinite).
80
81- (void)writeUntilPausedOrStopped {
82 id value;
83 while (value = [_enumerator nextObject]) {
Jorge Canizalesa90a9c32015-05-18 17:12:41 -070084 [_writeable writeValue:value];
Jorge Canizales30697c92015-02-17 17:09:14 -080085 // If the writeable has a reference to us, it might change our state to paused or finished.
86 if (_state == GRXWriterStatePaused || _state == GRXWriterStateFinished) {
87 return;
88 }
89 }
90 [self finishWithError:_errorOrNil];
91}
92
93- (void)startWithWriteable:(id<GRXWriteable>)writeable {
94 _state = GRXWriterStateStarted;
95 _writeable = writeable;
96 [self writeUntilPausedOrStopped];
97}
98
99- (void)finishWithError:(NSError *)errorOrNil {
100 _state = GRXWriterStateFinished;
101 _enumerator = nil;
102 _errorOrNil = nil;
103 id<GRXWriteable> writeable = _writeable;
104 _writeable = nil;
Jorge Canizalesb2c300c2015-05-18 17:19:16 -0700105 [writeable writesFinishedWithError:errorOrNil];
Jorge Canizales30697c92015-02-17 17:09:14 -0800106}
107
108- (void)setState:(GRXWriterState)newState {
109 // Manual transitions are only allowed from the started or paused states.
110 if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) {
111 return;
112 }
113
114 switch (newState) {
115 case GRXWriterStateFinished:
116 _state = newState;
117 _enumerator = nil;
118 _errorOrNil = nil;
119 // Per GRXWriter's contract, setting the state to Finished manually
120 // means one doesn't wish the writeable to be messaged anymore.
121 _writeable = nil;
122 return;
123 case GRXWriterStatePaused:
124 _state = newState;
125 return;
126 case GRXWriterStateStarted:
127 if (_state == GRXWriterStatePaused) {
128 _state = newState;
129 [self writeUntilPausedOrStopped];
130 }
131 return;
132 case GRXWriterStateNotStarted:
133 return;
134 }
135}
136
137@end