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