blob: c15ccb17fb9d8900357dc560400ed56badeca912 [file] [log] [blame]
Jorge Canizalese8304d52015-02-17 19:50:51 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Jorge Canizalese8304d52015-02-17 19:50:51 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Jorge Canizales30697c92015-02-17 17:09:14 -080034#import "GRXWriteable.h"
35
36@implementation GRXWriteable {
37 GRXValueHandler _valueHandler;
38 GRXCompletionHandler _completionHandler;
39}
40
Jorge Canizalesf95ddba2015-08-12 10:51:56 -070041+ (instancetype)writeableWithSingleHandler:(GRXSingleHandler)handler {
Jorge Canizales2779ccb2015-04-20 23:42:46 -070042 if (!handler) {
43 return [[self alloc] init];
44 }
Jorge Canizales5e672322016-03-09 13:34:28 -080045 // We nilify this variable when the block is invoked, so that handler is only invoked once even if
46 // the writer tries to write multiple values.
47 __block GRXEventHandler eventHandler = ^(BOOL done, id value, NSError *error) {
48 // Nillify eventHandler before invoking handler, in case the latter causes the former to be
49 // executed recursively. Because blocks can be deallocated even during execution, we have to
50 // first retain handler locally to guarantee it's valid.
51 // TODO(jcanizales): Just turn this craziness into a simple subclass of GRXWriteable.
52 GRXSingleHandler singleHandler = handler;
53 eventHandler = nil;
54
55 if (value) {
56 singleHandler(value, nil);
57 } else if (error) {
58 singleHandler(nil, error);
59 } else {
60 NSDictionary *userInfo = @{
61 NSLocalizedDescriptionKey: @"The writer finished without producing any value."
62 };
63 // Even though RxLibrary is independent of gRPC, the domain and code here are, for the moment,
64 // set to the values of kGRPCErrorDomain and GRPCErrorCodeInternal. This way, the error formed
65 // is the one user of gRPC would expect if the server failed to produce a response.
66 //
67 // TODO(jcanizales): Figure out a way to keep errors of RxLibrary generic without making users
68 // of gRPC take care of two different error domains and error code enums. A possibility is to
69 // add error handling to GRXWriters or GRXWriteables, and use them to translate errors between
70 // the two domains.
Jorge Canizales5a8ec752016-03-11 18:41:54 -080071 static NSString *kGRPCErrorDomain = @"io.grpc";
72 static NSUInteger kGRPCErrorCodeInternal = 13;
73 singleHandler(nil, [NSError errorWithDomain:kGRPCErrorDomain
74 code:kGRPCErrorCodeInternal
75 userInfo:userInfo]);
Jorge Canizales5e672322016-03-09 13:34:28 -080076 }
77 };
78 return [self writeableWithEventHandler:^(BOOL done, id value, NSError *error) {
79 if (eventHandler) {
80 eventHandler(done, value, error);
Jorge Canizales2779ccb2015-04-20 23:42:46 -070081 }
82 }];
83}
84
Jorge Canizalesf95ddba2015-08-12 10:51:56 -070085+ (instancetype)writeableWithEventHandler:(GRXEventHandler)handler {
Jorge Canizales2779ccb2015-04-20 23:42:46 -070086 if (!handler) {
87 return [[self alloc] init];
88 }
89 return [[self alloc] initWithValueHandler:^(id value) {
90 handler(NO, value, nil);
91 } completionHandler:^(NSError *errorOrNil) {
92 handler(YES, nil, errorOrNil);
93 }];
94}
95
Jorge Canizales30697c92015-02-17 17:09:14 -080096- (instancetype)init {
97 return [self initWithValueHandler:nil completionHandler:nil];
98}
99
100// Designated initializer
101- (instancetype)initWithValueHandler:(GRXValueHandler)valueHandler
102 completionHandler:(GRXCompletionHandler)completionHandler {
103 if ((self = [super init])) {
104 _valueHandler = valueHandler;
105 _completionHandler = completionHandler;
106 }
107 return self;
108}
109
Jorge Canizalesa90a9c32015-05-18 17:12:41 -0700110- (void)writeValue:(id)value {
Jorge Canizales30697c92015-02-17 17:09:14 -0800111 if (_valueHandler) {
112 _valueHandler(value);
113 }
114}
115
Jorge Canizalesb2c300c2015-05-18 17:19:16 -0700116- (void)writesFinishedWithError:(NSError *)errorOrNil {
Jorge Canizales30697c92015-02-17 17:09:14 -0800117 if (_completionHandler) {
118 _completionHandler(errorOrNil);
119 }
120}
121@end