1*cc02d7e2SAndroid Build Coastguard Worker/* 2*cc02d7e2SAndroid Build Coastguard Worker * 3*cc02d7e2SAndroid Build Coastguard Worker * Copyright 2015 gRPC authors. 4*cc02d7e2SAndroid Build Coastguard Worker * 5*cc02d7e2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 6*cc02d7e2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 7*cc02d7e2SAndroid Build Coastguard Worker * You may obtain a copy of the License at 8*cc02d7e2SAndroid Build Coastguard Worker * 9*cc02d7e2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 10*cc02d7e2SAndroid Build Coastguard Worker * 11*cc02d7e2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 12*cc02d7e2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 13*cc02d7e2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*cc02d7e2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 15*cc02d7e2SAndroid Build Coastguard Worker * limitations under the License. 16*cc02d7e2SAndroid Build Coastguard Worker * 17*cc02d7e2SAndroid Build Coastguard Worker */ 18*cc02d7e2SAndroid Build Coastguard Worker 19*cc02d7e2SAndroid Build Coastguard Worker#import "GRXImmediateWriter.h" 20*cc02d7e2SAndroid Build Coastguard Worker 21*cc02d7e2SAndroid Build Coastguard Worker#import "NSEnumerator+GRXUtil.h" 22*cc02d7e2SAndroid Build Coastguard Worker 23*cc02d7e2SAndroid Build Coastguard Worker@implementation GRXImmediateWriter { 24*cc02d7e2SAndroid Build Coastguard Worker NSEnumerator *_enumerator; 25*cc02d7e2SAndroid Build Coastguard Worker NSError *_errorOrNil; 26*cc02d7e2SAndroid Build Coastguard Worker id<GRXWriteable> _writeable; 27*cc02d7e2SAndroid Build Coastguard Worker} 28*cc02d7e2SAndroid Build Coastguard Worker 29*cc02d7e2SAndroid Build Coastguard Worker@synthesize state = _state; 30*cc02d7e2SAndroid Build Coastguard Worker 31*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)init { 32*cc02d7e2SAndroid Build Coastguard Worker return [self initWithEnumerator:nil error:nil]; // results in an empty writer. 33*cc02d7e2SAndroid Build Coastguard Worker} 34*cc02d7e2SAndroid Build Coastguard Worker 35*cc02d7e2SAndroid Build Coastguard Worker// Designated initializer 36*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)initWithEnumerator:(NSEnumerator *)enumerator error:(NSError *)errorOrNil { 37*cc02d7e2SAndroid Build Coastguard Worker if (((self = [super init]))) { 38*cc02d7e2SAndroid Build Coastguard Worker _enumerator = enumerator; 39*cc02d7e2SAndroid Build Coastguard Worker _errorOrNil = errorOrNil; 40*cc02d7e2SAndroid Build Coastguard Worker _state = GRXWriterStateNotStarted; 41*cc02d7e2SAndroid Build Coastguard Worker } 42*cc02d7e2SAndroid Build Coastguard Worker return self; 43*cc02d7e2SAndroid Build Coastguard Worker} 44*cc02d7e2SAndroid Build Coastguard Worker 45*cc02d7e2SAndroid Build Coastguard Worker#pragma mark Convenience constructors 46*cc02d7e2SAndroid Build Coastguard Worker 47*cc02d7e2SAndroid Build Coastguard Worker+ (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator error:(NSError *)errorOrNil { 48*cc02d7e2SAndroid Build Coastguard Worker return [[self alloc] initWithEnumerator:enumerator error:errorOrNil]; 49*cc02d7e2SAndroid Build Coastguard Worker} 50*cc02d7e2SAndroid Build Coastguard Worker 51*cc02d7e2SAndroid Build Coastguard Worker+ (GRXWriter *)writerWithEnumerator:(NSEnumerator *)enumerator { 52*cc02d7e2SAndroid Build Coastguard Worker return [self writerWithEnumerator:enumerator error:nil]; 53*cc02d7e2SAndroid Build Coastguard Worker} 54*cc02d7e2SAndroid Build Coastguard Worker 55*cc02d7e2SAndroid Build Coastguard Worker+ (GRXWriter *)writerWithValueSupplier:(id (^)(void))block { 56*cc02d7e2SAndroid Build Coastguard Worker return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithValueSupplier:block]]; 57*cc02d7e2SAndroid Build Coastguard Worker} 58*cc02d7e2SAndroid Build Coastguard Worker 59*cc02d7e2SAndroid Build Coastguard Worker+ (GRXWriter *)writerWithContainer:(id<NSFastEnumeration>)container { 60*cc02d7e2SAndroid Build Coastguard Worker return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithContainer:container]]; 61*cc02d7e2SAndroid Build Coastguard Worker ; 62*cc02d7e2SAndroid Build Coastguard Worker} 63*cc02d7e2SAndroid Build Coastguard Worker 64*cc02d7e2SAndroid Build Coastguard Worker+ (GRXWriter *)writerWithValue:(id)value { 65*cc02d7e2SAndroid Build Coastguard Worker return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithSingleValue:value]]; 66*cc02d7e2SAndroid Build Coastguard Worker} 67*cc02d7e2SAndroid Build Coastguard Worker 68*cc02d7e2SAndroid Build Coastguard Worker+ (GRXWriter *)writerWithError:(NSError *)error { 69*cc02d7e2SAndroid Build Coastguard Worker return [self writerWithEnumerator:nil error:error]; 70*cc02d7e2SAndroid Build Coastguard Worker} 71*cc02d7e2SAndroid Build Coastguard Worker 72*cc02d7e2SAndroid Build Coastguard Worker+ (GRXWriter *)emptyWriter { 73*cc02d7e2SAndroid Build Coastguard Worker return [self writerWithEnumerator:nil error:nil]; 74*cc02d7e2SAndroid Build Coastguard Worker} 75*cc02d7e2SAndroid Build Coastguard Worker 76*cc02d7e2SAndroid Build Coastguard Worker#pragma mark Conformance with GRXWriter 77*cc02d7e2SAndroid Build Coastguard Worker 78*cc02d7e2SAndroid Build Coastguard Worker// Most of the complexity in this implementation is the result of supporting pause and resumption of 79*cc02d7e2SAndroid Build Coastguard Worker// the GRXWriter. It's an important feature for instances of GRXWriter that are backed by a 80*cc02d7e2SAndroid Build Coastguard Worker// container (which may be huge), or by a NSEnumerator (which may even be infinite). 81*cc02d7e2SAndroid Build Coastguard Worker 82*cc02d7e2SAndroid Build Coastguard Worker- (void)writeUntilPausedOrStopped { 83*cc02d7e2SAndroid Build Coastguard Worker id value; 84*cc02d7e2SAndroid Build Coastguard Worker while (value = [_enumerator nextObject]) { 85*cc02d7e2SAndroid Build Coastguard Worker [_writeable writeValue:value]; 86*cc02d7e2SAndroid Build Coastguard Worker // If the writeable has a reference to us, it might change our state to paused or finished. 87*cc02d7e2SAndroid Build Coastguard Worker if (_state == GRXWriterStatePaused || _state == GRXWriterStateFinished) { 88*cc02d7e2SAndroid Build Coastguard Worker return; 89*cc02d7e2SAndroid Build Coastguard Worker } 90*cc02d7e2SAndroid Build Coastguard Worker } 91*cc02d7e2SAndroid Build Coastguard Worker [self finishWithError:_errorOrNil]; 92*cc02d7e2SAndroid Build Coastguard Worker} 93*cc02d7e2SAndroid Build Coastguard Worker 94*cc02d7e2SAndroid Build Coastguard Worker- (void)startWithWriteable:(id<GRXWriteable>)writeable { 95*cc02d7e2SAndroid Build Coastguard Worker _state = GRXWriterStateStarted; 96*cc02d7e2SAndroid Build Coastguard Worker _writeable = writeable; 97*cc02d7e2SAndroid Build Coastguard Worker [self writeUntilPausedOrStopped]; 98*cc02d7e2SAndroid Build Coastguard Worker} 99*cc02d7e2SAndroid Build Coastguard Worker 100*cc02d7e2SAndroid Build Coastguard Worker- (void)finishWithError:(NSError *)errorOrNil { 101*cc02d7e2SAndroid Build Coastguard Worker _state = GRXWriterStateFinished; 102*cc02d7e2SAndroid Build Coastguard Worker _enumerator = nil; 103*cc02d7e2SAndroid Build Coastguard Worker _errorOrNil = nil; 104*cc02d7e2SAndroid Build Coastguard Worker id<GRXWriteable> writeable = _writeable; 105*cc02d7e2SAndroid Build Coastguard Worker _writeable = nil; 106*cc02d7e2SAndroid Build Coastguard Worker [writeable writesFinishedWithError:errorOrNil]; 107*cc02d7e2SAndroid Build Coastguard Worker} 108*cc02d7e2SAndroid Build Coastguard Worker 109*cc02d7e2SAndroid Build Coastguard Worker- (void)setState:(GRXWriterState)newState { 110*cc02d7e2SAndroid Build Coastguard Worker // Manual transitions are only allowed from the started or paused states. 111*cc02d7e2SAndroid Build Coastguard Worker if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) { 112*cc02d7e2SAndroid Build Coastguard Worker return; 113*cc02d7e2SAndroid Build Coastguard Worker } 114*cc02d7e2SAndroid Build Coastguard Worker 115*cc02d7e2SAndroid Build Coastguard Worker switch (newState) { 116*cc02d7e2SAndroid Build Coastguard Worker case GRXWriterStateFinished: 117*cc02d7e2SAndroid Build Coastguard Worker _state = newState; 118*cc02d7e2SAndroid Build Coastguard Worker _enumerator = nil; 119*cc02d7e2SAndroid Build Coastguard Worker _errorOrNil = nil; 120*cc02d7e2SAndroid Build Coastguard Worker // Per GRXWriter's contract, setting the state to Finished manually 121*cc02d7e2SAndroid Build Coastguard Worker // means one doesn't wish the writeable to be messaged anymore. 122*cc02d7e2SAndroid Build Coastguard Worker _writeable = nil; 123*cc02d7e2SAndroid Build Coastguard Worker return; 124*cc02d7e2SAndroid Build Coastguard Worker case GRXWriterStatePaused: 125*cc02d7e2SAndroid Build Coastguard Worker _state = newState; 126*cc02d7e2SAndroid Build Coastguard Worker return; 127*cc02d7e2SAndroid Build Coastguard Worker case GRXWriterStateStarted: 128*cc02d7e2SAndroid Build Coastguard Worker if (_state == GRXWriterStatePaused) { 129*cc02d7e2SAndroid Build Coastguard Worker _state = newState; 130*cc02d7e2SAndroid Build Coastguard Worker [self writeUntilPausedOrStopped]; 131*cc02d7e2SAndroid Build Coastguard Worker } 132*cc02d7e2SAndroid Build Coastguard Worker return; 133*cc02d7e2SAndroid Build Coastguard Worker case GRXWriterStateNotStarted: 134*cc02d7e2SAndroid Build Coastguard Worker return; 135*cc02d7e2SAndroid Build Coastguard Worker } 136*cc02d7e2SAndroid Build Coastguard Worker} 137*cc02d7e2SAndroid Build Coastguard Worker 138*cc02d7e2SAndroid Build Coastguard Worker@end 139