1/* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * 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 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * 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. 16 * 17 */ 18 19#import "GRXForwardingWriter.h" 20 21@interface GRXForwardingWriter () <GRXWriteable> 22@end 23 24@implementation GRXForwardingWriter { 25 GRXWriter *_writer; 26 id<GRXWriteable> _writeable; 27} 28 29- (instancetype)init { 30 return [self initWithWriter:nil]; 31} 32 33// Designated initializer 34- (instancetype)initWithWriter:(GRXWriter *)writer { 35 if (!writer) { 36 return nil; 37 } 38 if (writer.state != GRXWriterStateNotStarted) { 39 [NSException raise:NSInvalidArgumentException 40 format:@"The writer argument must not have already started."]; 41 } 42 if ((self = [super init])) { 43 _writer = writer; 44 } 45 return self; 46} 47 48// This is used to send a completion or an error to the writeable. It nillifies 49// our reference to it in order to guarantee no more messages are sent to it, 50// and to release it. 51- (void)finishOutputWithError:(NSError *)errorOrNil { 52 id<GRXWriteable> writeable = _writeable; 53 _writeable = nil; 54 [writeable writesFinishedWithError:errorOrNil]; 55} 56 57#pragma mark GRXWriteable implementation 58 59- (void)writeValue:(id)value { 60 @synchronized(self) { 61 [_writeable writeValue:value]; 62 } 63} 64 65- (void)writesFinishedWithError:(NSError *)errorOrNil { 66 @synchronized(self) { 67 _writer = nil; 68 [self finishOutputWithError:errorOrNil]; 69 } 70} 71 72#pragma mark GRXWriter implementation 73 74- (GRXWriterState)state { 75 GRXWriter *copiedWriter; 76 @synchronized(self) { 77 copiedWriter = _writer; 78 } 79 return copiedWriter ? copiedWriter.state : GRXWriterStateFinished; 80} 81 82- (void)setState:(GRXWriterState)state { 83 GRXWriter *copiedWriter = nil; 84 if (state == GRXWriterStateFinished) { 85 @synchronized(self) { 86 _writeable = nil; 87 copiedWriter = _writer; 88 _writer = nil; 89 } 90 copiedWriter.state = GRXWriterStateFinished; 91 } else { 92 @synchronized(self) { 93 copiedWriter = _writer; 94 } 95 copiedWriter.state = state; 96 } 97} 98 99- (void)startWithWriteable:(id<GRXWriteable>)writeable { 100 GRXWriter *copiedWriter = nil; 101 @synchronized(self) { 102 _writeable = writeable; 103 copiedWriter = _writer; 104 } 105 [copiedWriter startWithWriteable:self]; 106} 107 108- (void)finishWithError:(NSError *)errorOrNil { 109 GRXWriter *copiedWriter = nil; 110 @synchronized(self) { 111 [self finishOutputWithError:errorOrNil]; 112 copiedWriter = _writer; 113 _writer = nil; 114 } 115 copiedWriter.state = GRXWriterStateFinished; 116} 117 118@end 119