Merge pull request #3969 from grpc/release-0_11

Release 0 11 -> master
pull/3253/head^2
Nicolas Noble 9 years ago
commit dcd35b8ad6
  1. 10
      examples/objective-c/auth_sample/AuthTestService.podspec
  2. 9
      examples/objective-c/auth_sample/MakeRPCViewController.m
  3. 3
      examples/objective-c/auth_sample/Podfile
  4. 2
      examples/objective-c/route_guide/Podfile
  5. 10
      examples/objective-c/route_guide/RouteGuide.podspec
  6. 4
      include/grpc++/support/sync_stream.h
  7. 16
      src/objective-c/GRPCClient/GRPCCall+OAuth2.h
  8. 28
      src/objective-c/GRPCClient/GRPCCall+Tests.h
  9. 236
      src/objective-c/GRPCClient/GRPCCall.h
  10. 12
      src/objective-c/GRPCClient/private/GRPCChannel.h
  11. 20
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.h
  12. 6
      src/objective-c/GRPCClient/private/GRPCHost.h
  13. 8
      src/objective-c/GRPCClient/private/GRPCSecureChannel.h
  14. 2
      src/objective-c/GRPCClient/private/GRPCWrappedCall.h
  15. 6
      src/objective-c/GRPCClient/private/NSError+GRPC.h
  16. 6
      src/objective-c/ProtoRPC/ProtoMethod.h
  17. 36
      src/objective-c/RxLibrary/GRXBufferedPipe.h
  18. 54
      src/objective-c/RxLibrary/GRXConcurrentWriteable.h
  19. 24
      src/objective-c/RxLibrary/GRXForwardingWriter.h
  20. 70
      src/objective-c/RxLibrary/GRXImmediateWriter.h
  21. 22
      src/objective-c/RxLibrary/GRXWriteable.h
  22. 44
      src/objective-c/RxLibrary/GRXWriter+Immediate.h
  23. 6
      src/objective-c/RxLibrary/GRXWriter+Transformations.h
  24. 116
      src/objective-c/RxLibrary/GRXWriter.h
  25. 22
      src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h
  26. 12
      src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h
  27. 14
      src/objective-c/RxLibrary/private/GRXNSFastEnumerator.h
  28. 8
      src/objective-c/RxLibrary/private/GRXNSScalarEnumerator.h
  29. 2
      src/objective-c/RxLibrary/transformations/GRXMappingWriter.h
  30. 128
      src/objective-c/change-comments.py
  31. 31
      src/objective-c/format-all-comments.sh

@ -3,13 +3,13 @@ Pod::Spec.new do |s|
s.version = "0.0.1" s.version = "0.0.1"
s.license = "New BSD" s.license = "New BSD"
s.ios.deployment_target = "6.0" s.ios.deployment_target = "7.1"
s.osx.deployment_target = "10.8" s.osx.deployment_target = "10.9"
# Base directory where the .proto files are. # Base directory where the .proto files are.
src = "../../protos" src = "../../protos"
# Directory where the generated files will be place. # Directory where the generated files will be placed.
dir = "Pods/" + s.name dir = "Pods/" + s.name
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
@ -22,14 +22,14 @@ Pod::Spec.new do |s|
ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}" ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
ms.header_mappings_dir = dir ms.header_mappings_dir = dir
ms.requires_arc = false ms.requires_arc = false
ms.dependency "Protobuf", "~> 3.0.0-alpha-3" ms.dependency "Protobuf", "~> 3.0.0-alpha-4"
end end
s.subspec "Services" do |ss| s.subspec "Services" do |ss|
ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}" ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
ss.header_mappings_dir = dir ss.header_mappings_dir = dir
ss.requires_arc = true ss.requires_arc = true
ss.dependency "gRPC", "~> 0.6" ss.dependency "gRPC", "~> 0.11"
ss.dependency "#{s.name}/Messages" ss.dependency "#{s.name}/Messages"
end end
end end

@ -35,7 +35,6 @@
#import <AuthTestService/AuthSample.pbrpc.h> #import <AuthTestService/AuthSample.pbrpc.h>
#import <Google/SignIn.h> #import <Google/SignIn.h>
#include <grpc/status.h>
#import <ProtoRPC/ProtoRPC.h> #import <ProtoRPC/ProtoRPC.h>
NSString * const kTestScope = @"https://www.googleapis.com/auth/xapi.zoo"; NSString * const kTestScope = @"https://www.googleapis.com/auth/xapi.zoo";
@ -49,10 +48,10 @@ static NSString * const kTestHostAddress = @"grpc-test.sandbox.google.com";
@implementation NSError (AuthSample) @implementation NSError (AuthSample)
- (NSString *)UIDescription { - (NSString *)UIDescription {
if (self.code == GRPC_STATUS_UNAUTHENTICATED) { if (self.code == GRPCErrorCodeUnauthenticated) {
// Authentication error. OAuth2 specifies we'll receive a challenge header. // Authentication error. OAuth2 specifies we'll receive a challenge header.
// |userInfo[kGRPCStatusMetadataKey]| is the dictionary of response metadata. // |userInfo[kGRPCHeadersKey]| is the dictionary of response headers.
NSString *challengeHeader = self.userInfo[kGRPCStatusMetadataKey][@"www-authenticate"] ?: @""; NSString *challengeHeader = self.userInfo[kGRPCHeadersKey][@"www-authenticate"] ?: @"";
return [@"Invalid credentials. Server challenge:\n" stringByAppendingString:challengeHeader]; return [@"Invalid credentials. Server challenge:\n" stringByAppendingString:challengeHeader];
} else { } else {
// Any other error. // Any other error.
@ -89,7 +88,7 @@ static NSString * const kTestHostAddress = @"grpc-test.sandbox.google.com";
// Set the access token to be used. // Set the access token to be used.
NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken; NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken;
call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]; call.requestHeaders[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken];
// Start the RPC. // Start the RPC.
[call start]; [call start];

@ -1,6 +1,9 @@
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' platform :ios, '8.0'
pod 'Protobuf', :path => "../../../third_party/protobuf"
pod 'gRPC', :path => "../../.."
target 'AuthSample' do target 'AuthSample' do
# Depend on the generated AuthTestService library. # Depend on the generated AuthTestService library.
pod 'AuthTestService', :path => '.' pod 'AuthTestService', :path => '.'

@ -2,6 +2,8 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' platform :ios, '8.0'
target 'RouteGuideClient' do target 'RouteGuideClient' do
pod 'Protobuf', :path => "../../../third_party/protobuf"
pod 'gRPC', :path => "../../.."
# Depend on the generated RouteGuide library. # Depend on the generated RouteGuide library.
pod 'RouteGuide', :path => '.' pod 'RouteGuide', :path => '.'
end end

@ -3,13 +3,13 @@ Pod::Spec.new do |s|
s.version = "0.0.1" s.version = "0.0.1"
s.license = "New BSD" s.license = "New BSD"
s.ios.deployment_target = "6.0" s.ios.deployment_target = "7.1"
s.osx.deployment_target = "10.8" s.osx.deployment_target = "10.9"
# Base directory where the .proto files are. # Base directory where the .proto files are.
src = "../../protos" src = "../../protos"
# Directory where the generated files will be place. # Directory where the generated files will be placed.
dir = "Pods/" + s.name dir = "Pods/" + s.name
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
@ -22,14 +22,14 @@ Pod::Spec.new do |s|
ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}" ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}"
ms.header_mappings_dir = dir ms.header_mappings_dir = dir
ms.requires_arc = false ms.requires_arc = false
ms.dependency "Protobuf", "~> 3.0.0-alpha-3" ms.dependency "Protobuf", "~> 3.0.0-alpha-4"
end end
s.subspec "Services" do |ss| s.subspec "Services" do |ss|
ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}" ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}"
ss.header_mappings_dir = dir ss.header_mappings_dir = dir
ss.requires_arc = true ss.requires_arc = true
ss.dependency "gRPC", "~> 0.6" ss.dependency "gRPC", "~> 0.11"
ss.dependency "#{s.name}/Messages" ss.dependency "#{s.name}/Messages"
end end
end end

@ -131,7 +131,7 @@ class ClientReader GRPC_FINAL : public ClientReaderInterface<R> {
cq_.Pluck(&ops); cq_.Pluck(&ops);
} }
void WaitForInitialMetadata() { void WaitForInitialMetadata() GRPC_OVERRIDE {
GPR_ASSERT(!context_->initial_metadata_received_); GPR_ASSERT(!context_->initial_metadata_received_);
CallOpSet<CallOpRecvInitialMetadata> ops; CallOpSet<CallOpRecvInitialMetadata> ops;
@ -257,7 +257,7 @@ class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> {
cq_.Pluck(&ops); cq_.Pluck(&ops);
} }
void WaitForInitialMetadata() { void WaitForInitialMetadata() GRPC_OVERRIDE {
GPR_ASSERT(!context_->initial_metadata_received_); GPR_ASSERT(!context_->initial_metadata_received_);
CallOpSet<CallOpRecvInitialMetadata> ops; CallOpSet<CallOpRecvInitialMetadata> ops;

@ -33,17 +33,19 @@
#import "GRPCCall.h" #import "GRPCCall.h"
// Helpers for setting and reading headers compatible with OAuth2. /** Helpers for setting and reading headers compatible with OAuth2. */
@interface GRPCCall (OAuth2) @interface GRPCCall (OAuth2)
// Setting this property is equivalent to setting "Bearer <passed token>" as the value of the /**
// request header with key "authorization" (the authorization header). Setting it to nil removes the * Setting this property is equivalent to setting "Bearer <passed token>" as the value of the
// authorization header from the request. * request header with key "authorization" (the authorization header). Setting it to nil removes the
// The value obtained by getting the property is the OAuth2 bearer token if the authorization header * authorization header from the request.
// of the request has the form "Bearer <token>", or nil otherwise. * The value obtained by getting the property is the OAuth2 bearer token if the authorization header
* of the request has the form "Bearer <token>", or nil otherwise.
*/
@property(atomic, copy) NSString *oauth2AccessToken; @property(atomic, copy) NSString *oauth2AccessToken;
// Returns the value (if any) of the "www-authenticate" response header (the challenge header). /** Returns the value (if any) of the "www-authenticate" response header (the challenge header). */
@property(atomic, readonly) NSString *oauth2ChallengeHeader; @property(atomic, readonly) NSString *oauth2ChallengeHeader;
@end @end

@ -33,22 +33,28 @@
#import "GRPCCall.h" #import "GRPCCall.h"
// Methods to let tune down the security of gRPC connections for specific hosts. These shouldn't be /**
// used in releases, but are sometimes needed for testing. * Methods to let tune down the security of gRPC connections for specific hosts. These shouldn't be
* used in releases, but are sometimes needed for testing.
*/
@interface GRPCCall (Tests) @interface GRPCCall (Tests)
// Establish all SSL connections to the provided host using the passed SSL target name and the root /**
// certificates found in the file at |certsPath|. * Establish all SSL connections to the provided host using the passed SSL target name and the root
// * certificates found in the file at |certsPath|.
// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to *
// more than one invocation of the methods of this category. * Must be called before any gRPC call to that host is made. It's illegal to pass the same host to
* more than one invocation of the methods of this category.
*/
+ (void)useTestCertsPath:(NSString *)certsPath + (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName testName:(NSString *)testName
forHost:(NSString *)host; forHost:(NSString *)host;
// Establish all connections to the provided host using cleartext instead of SSL. /**
// * Establish all connections to the provided host using cleartext instead of SSL.
// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to *
// more than one invocation of the methods of this category. * Must be called before any gRPC call to that host is made. It's illegal to pass the same host to
* more than one invocation of the methods of this category.
*/
+ (void)useInsecureConnectionsForHost:(NSString *)host; + (void)useInsecureConnectionsForHost:(NSString *)host;
@end @end

@ -31,117 +31,145 @@
* *
*/ */
// The gRPC protocol is an RPC protocol on top of HTTP2. /**
// * The gRPC protocol is an RPC protocol on top of HTTP2.
// While the most common type of RPC receives only one request message and returns only one response *
// message, the protocol also supports RPCs that return multiple individual messages in a streaming * While the most common type of RPC receives only one request message and returns only one response
// fashion, RPCs that accept a stream of request messages, or RPCs with both streaming requests and * message, the protocol also supports RPCs that return multiple individual messages in a streaming
// responses. * fashion, RPCs that accept a stream of request messages, or RPCs with both streaming requests and
// * responses.
// Conceptually, each gRPC call consists of a bidirectional stream of binary messages, with RPCs of *
// the "non-streaming type" sending only one message in the corresponding direction (the protocol * Conceptually, each gRPC call consists of a bidirectional stream of binary messages, with RPCs of
// doesn't make any distinction). * the "non-streaming type" sending only one message in the corresponding direction (the protocol
// * doesn't make any distinction).
// Each RPC uses a different HTTP2 stream, and thus multiple simultaneous RPCs can be multiplexed *
// transparently on the same TCP connection. * Each RPC uses a different HTTP2 stream, and thus multiple simultaneous RPCs can be multiplexed
* transparently on the same TCP connection.
*/
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <RxLibrary/GRXWriter.h> #import <RxLibrary/GRXWriter.h>
#pragma mark gRPC errors #pragma mark gRPC errors
// Domain of NSError objects produced by gRPC. /** Domain of NSError objects produced by gRPC. */
extern NSString *const kGRPCErrorDomain; extern NSString *const kGRPCErrorDomain;
// gRPC error codes. /**
// Note that a few of these are never produced by the gRPC libraries, but are of general utility for * gRPC error codes.
// server applications to produce. * Note that a few of these are never produced by the gRPC libraries, but are of general utility for
* server applications to produce.
*/
typedef NS_ENUM(NSUInteger, GRPCErrorCode) { typedef NS_ENUM(NSUInteger, GRPCErrorCode) {
// The operation was cancelled (typically by the caller). /** The operation was cancelled (typically by the caller). */
GRPCErrorCodeCancelled = 1, GRPCErrorCodeCancelled = 1,
// Unknown error. Errors raised by APIs that do not return enough error information may be /**
// converted to this error. * Unknown error. Errors raised by APIs that do not return enough error information may be
* converted to this error.
*/
GRPCErrorCodeUnknown = 2, GRPCErrorCodeUnknown = 2,
// The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. /**
// INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the * The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION.
// server (e.g., a malformed file name). * INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the
* server (e.g., a malformed file name).
*/
GRPCErrorCodeInvalidArgument = 3, GRPCErrorCodeInvalidArgument = 3,
// Deadline expired before operation could complete. For operations that change the state of the /**
// server, this error may be returned even if the operation has completed successfully. For * Deadline expired before operation could complete. For operations that change the state of the
// example, a successful response from the server could have been delayed long enough for the * server, this error may be returned even if the operation has completed successfully. For
// deadline to expire. * example, a successful response from the server could have been delayed long enough for the
* deadline to expire.
*/
GRPCErrorCodeDeadlineExceeded = 4, GRPCErrorCodeDeadlineExceeded = 4,
// Some requested entity (e.g., file or directory) was not found. /** Some requested entity (e.g., file or directory) was not found. */
GRPCErrorCodeNotFound = 5, GRPCErrorCodeNotFound = 5,
// Some entity that we attempted to create (e.g., file or directory) already exists. /** Some entity that we attempted to create (e.g., file or directory) already exists. */
GRPCErrorCodeAlreadyExists = 6, GRPCErrorCodeAlreadyExists = 6,
// The caller does not have permission to execute the specified operation. PERMISSION_DENIED isn't /**
// used for rejections caused by exhausting some resource (RESOURCE_EXHAUSTED is used instead for * The caller does not have permission to execute the specified operation. PERMISSION_DENIED isn't
// those errors). PERMISSION_DENIED doesn't indicate a failure to identify the caller * used for rejections caused by exhausting some resource (RESOURCE_EXHAUSTED is used instead for
// (UNAUTHENTICATED is used instead for those errors). * those errors). PERMISSION_DENIED doesn't indicate a failure to identify the caller
* (UNAUTHENTICATED is used instead for those errors).
*/
GRPCErrorCodePermissionDenied = 7, GRPCErrorCodePermissionDenied = 7,
// The request does not have valid authentication credentials for the operation (e.g. the caller's /**
// identity can't be verified). * The request does not have valid authentication credentials for the operation (e.g. the caller's
* identity can't be verified).
*/
GRPCErrorCodeUnauthenticated = 16, GRPCErrorCodeUnauthenticated = 16,
// Some resource has been exhausted, perhaps a per-user quota. /** Some resource has been exhausted, perhaps a per-user quota. */
GRPCErrorCodeResourceExhausted = 8, GRPCErrorCodeResourceExhausted = 8,
// The RPC was rejected because the server is not in a state required for the procedure's /**
// execution. For example, a directory to be deleted may be non-empty, etc. * The RPC was rejected because the server is not in a state required for the procedure's
// The client should not retry until the server state has been explicitly fixed (e.g. by * execution. For example, a directory to be deleted may be non-empty, etc.
// performing another RPC). The details depend on the service being called, and should be found in * The client should not retry until the server state has been explicitly fixed (e.g. by
// the NSError's userInfo. * performing another RPC). The details depend on the service being called, and should be found in
* the NSError's userInfo.
*/
GRPCErrorCodeFailedPrecondition = 9, GRPCErrorCodeFailedPrecondition = 9,
// The RPC was aborted, typically due to a concurrency issue like sequencer check failures, /**
// transaction aborts, etc. The client should retry at a higher-level (e.g., restarting a read- * The RPC was aborted, typically due to a concurrency issue like sequencer check failures,
// modify-write sequence). * transaction aborts, etc. The client should retry at a higher-level (e.g., restarting a read-
* modify-write sequence).
*/
GRPCErrorCodeAborted = 10, GRPCErrorCodeAborted = 10,
// The RPC was attempted past the valid range. E.g., enumerating past the end of a list. /**
// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state * The RPC was attempted past the valid range. E.g., enumerating past the end of a list.
// changes. For example, an RPC to get elements of a list will generate INVALID_ARGUMENT if asked * Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state
// to return the element at a negative index, but it will generate OUT_OF_RANGE if asked to return * changes. For example, an RPC to get elements of a list will generate INVALID_ARGUMENT if asked
// the element at an index past the current size of the list. * to return the element at a negative index, but it will generate OUT_OF_RANGE if asked to return
* the element at an index past the current size of the list.
*/
GRPCErrorCodeOutOfRange = 11, GRPCErrorCodeOutOfRange = 11,
// The procedure is not implemented or not supported/enabled in this server. /** The procedure is not implemented or not supported/enabled in this server. */
GRPCErrorCodeUnimplemented = 12, GRPCErrorCodeUnimplemented = 12,
// Internal error. Means some invariant expected by the server application or the gRPC library has /**
// been broken. * Internal error. Means some invariant expected by the server application or the gRPC library has
* been broken.
*/
GRPCErrorCodeInternal = 13, GRPCErrorCodeInternal = 13,
// The server is currently unavailable. This is most likely a transient condition and may be /**
// corrected by retrying with a backoff. * The server is currently unavailable. This is most likely a transient condition and may be
* corrected by retrying with a backoff.
*/
GRPCErrorCodeUnavailable = 14, GRPCErrorCodeUnavailable = 14,
// Unrecoverable data loss or corruption. /** Unrecoverable data loss or corruption. */
GRPCErrorCodeDataLoss = 15, GRPCErrorCodeDataLoss = 15,
}; };
// Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by /**
// the server. * Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by
* the server.
*/
extern id const kGRPCHeadersKey; extern id const kGRPCHeadersKey;
extern id const kGRPCTrailersKey; extern id const kGRPCTrailersKey;
#pragma mark GRPCCall #pragma mark GRPCCall
// The container of the request headers of an RPC conforms to this protocol, which is a subset of /**
// NSMutableDictionary's interface. It will become a NSMutableDictionary later on. * The container of the request headers of an RPC conforms to this protocol, which is a subset of
// The keys of this container are the header names, which per the HTTP standard are case- * NSMutableDictionary's interface. It will become a NSMutableDictionary later on.
// insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and * The keys of this container are the header names, which per the HTTP standard are case-
// can only consist of ASCII characters. * insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and
// A header value is a NSString object (with only ASCII characters), unless the header name has the * can only consist of ASCII characters.
// suffix "-bin", in which case the value has to be a NSData object. * A header value is a NSString object (with only ASCII characters), unless the header name has the
* suffix "-bin", in which case the value has to be a NSData object.
*/
@protocol GRPCRequestHeaders <NSObject> @protocol GRPCRequestHeaders <NSObject>
@property(nonatomic, readonly) NSUInteger count; @property(nonatomic, readonly) NSUInteger count;
@ -154,53 +182,63 @@ extern id const kGRPCTrailersKey;
@end @end
// Represents a single gRPC remote call. /** Represents a single gRPC remote call. */
@interface GRPCCall : GRXWriter @interface GRPCCall : GRXWriter
// These HTTP headers will be passed to the server as part of this call. Each HTTP header is a /**
// name-value pair with string names and either string or binary values. * These HTTP headers will be passed to the server as part of this call. Each HTTP header is a
// * name-value pair with string names and either string or binary values.
// The passed dictionary has to use NSString keys, corresponding to the header names. The value *
// associated to each can be a NSString object or a NSData object. E.g.: * The passed dictionary has to use NSString keys, corresponding to the header names. The value
// * associated to each can be a NSString object or a NSData object. E.g.:
// call.requestHeaders = @{@"authorization": @"Bearer ..."}; *
// * call.requestHeaders = @{@"authorization": @"Bearer ..."};
// call.requestHeaders[@"my-header-bin"] = someData; *
// * call.requestHeaders[@"my-header-bin"] = someData;
// After the call is started, trying to modify this property is an error. *
// * After the call is started, trying to modify this property is an error.
// The property is initialized to an empty NSMutableDictionary. *
* The property is initialized to an empty NSMutableDictionary.
*/
@property(atomic, readonly) id<GRPCRequestHeaders> requestHeaders; @property(atomic, readonly) id<GRPCRequestHeaders> requestHeaders;
// This dictionary is populated with the HTTP headers received from the server. This happens before /**
// any response message is received from the server. It has the same structure as the request * This dictionary is populated with the HTTP headers received from the server. This happens before
// headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a * any response message is received from the server. It has the same structure as the request
// NSData value; the others have a NSString value. * headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a
// * NSData value; the others have a NSString value.
// The value of this property is nil until all response headers are received, and will change before *
// any of -writeValue: or -writesFinishedWithError: are sent to the writeable. * The value of this property is nil until all response headers are received, and will change before
* any of -writeValue: or -writesFinishedWithError: are sent to the writeable.
*/
@property(atomic, readonly) NSDictionary *responseHeaders; @property(atomic, readonly) NSDictionary *responseHeaders;
// Same as responseHeaders, but populated with the HTTP trailers received from the server before the /**
// call finishes. * Same as responseHeaders, but populated with the HTTP trailers received from the server before the
// * call finishes.
// The value of this property is nil until all response trailers are received, and will change *
// before -writesFinishedWithError: is sent to the writeable. * The value of this property is nil until all response trailers are received, and will change
* before -writesFinishedWithError: is sent to the writeable.
*/
@property(atomic, readonly) NSDictionary *responseTrailers; @property(atomic, readonly) NSDictionary *responseTrailers;
// The request writer has to write NSData objects into the provided Writeable. The server will /**
// receive each of those separately and in order as distinct messages. * The request writer has to write NSData objects into the provided Writeable. The server will
// A gRPC call might not complete until the request writer finishes. On the other hand, the request * receive each of those separately and in order as distinct messages.
// finishing doesn't necessarily make the call to finish, as the server might continue sending * A gRPC call might not complete until the request writer finishes. On the other hand, the request
// messages to the response side of the call indefinitely (depending on the semantics of the * finishing doesn't necessarily make the call to finish, as the server might continue sending
// specific remote method called). * messages to the response side of the call indefinitely (depending on the semantics of the
// To finish a call right away, invoke cancel. * specific remote method called).
* To finish a call right away, invoke cancel.
*/
- (instancetype)initWithHost:(NSString *)host - (instancetype)initWithHost:(NSString *)host
path:(NSString *)path path:(NSString *)path
requestsWriter:(GRXWriter *)requestsWriter NS_DESIGNATED_INITIALIZER; requestsWriter:(GRXWriter *)requestsWriter NS_DESIGNATED_INITIALIZER;
// Finishes the request side of this call, notifies the server that the RPC should be cancelled, and /**
// finishes the response side of the call with an error of code CANCELED. * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and
* finishes the response side of the call with an error of code CANCELED.
*/
- (void)cancel; - (void)cancel;
// TODO(jcanizales): Let specify a deadline. As a category of GRXWriter? // TODO(jcanizales): Let specify a deadline. As a category of GRXWriter?

@ -35,12 +35,16 @@
struct grpc_channel; struct grpc_channel;
// Each separate instance of this class represents at least one TCP connection to the provided host. /**
// Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|. * Each separate instance of this class represents at least one TCP connection to the provided host.
* Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|.
*/
@interface GRPCChannel : NSObject @interface GRPCChannel : NSObject
@property(nonatomic, readonly) struct grpc_channel *unmanagedChannel; @property(nonatomic, readonly) struct grpc_channel *unmanagedChannel;
// This initializer takes ownership of the passed channel, and will destroy it when this object is /**
// deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects. * This initializer takes ownership of the passed channel, and will destroy it when this object is
* deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects.
*/
- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER; - (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
@end @end

@ -36,15 +36,17 @@
typedef void(^GRPCQueueCompletionHandler)(bool success); typedef void(^GRPCQueueCompletionHandler)(bool success);
// This class lets one more easily use |grpc_completion_queue|. To use it, pass the value of the /**
// |unmanagedQueue| property of an instance of this class to |grpc_channel_create_call|. Then for * This class lets one more easily use |grpc_completion_queue|. To use it, pass the value of the
// every |grpc_call_*| method that accepts a tag, you can pass a block of type * |unmanagedQueue| property of an instance of this class to |grpc_channel_create_call|. Then for
// |GRPCQueueCompletionHandler| (remembering to cast it using |__bridge_retained|). The block is * every |grpc_call_*| method that accepts a tag, you can pass a block of type
// guaranteed to eventually be called, by a concurrent queue, and then released. Each such block is * |GRPCQueueCompletionHandler| (remembering to cast it using |__bridge_retained|). The block is
// passed a |bool| that tells if the operation was successful. * guaranteed to eventually be called, by a concurrent queue, and then released. Each such block is
// * passed a |bool| that tells if the operation was successful.
// Release the GRPCCompletionQueue object only after you are not going to pass any more blocks to *
// the |grpc_call| that's using it. * Release the GRPCCompletionQueue object only after you are not going to pass any more blocks to
* the |grpc_call| that's using it.
*/
@interface GRPCCompletionQueue : NSObject @interface GRPCCompletionQueue : NSObject
@property(nonatomic, readonly) grpc_completion_queue *unmanagedQueue; @property(nonatomic, readonly) grpc_completion_queue *unmanagedQueue;

@ -40,18 +40,18 @@ struct grpc_call;
@property(nonatomic, readonly) NSString *address; @property(nonatomic, readonly) NSString *address;
// The following properties should only be modified for testing: /** The following properties should only be modified for testing: */
@property(nonatomic, getter=isSecure) BOOL secure; @property(nonatomic, getter=isSecure) BOOL secure;
@property(nonatomic, copy) NSString *pathToCertificates; @property(nonatomic, copy) NSString *pathToCertificates;
@property(nonatomic, copy) NSString *hostNameOverride; @property(nonatomic, copy) NSString *hostNameOverride;
// Host objects initialized with the same address are the same. /** Host objects initialized with the same address are the same. */
+ (instancetype)hostWithAddress:(NSString *)address; + (instancetype)hostWithAddress:(NSString *)address;
- (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER; - (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
// Create a grpc_call object to the provided path on this host. /** Create a grpc_call object to the provided path on this host. */
- (struct grpc_call *)unmanagedCallWithPath:(NSString *)path - (struct grpc_call *)unmanagedCallWithPath:(NSString *)path
completionQueue:(GRPCCompletionQueue *)queue; completionQueue:(GRPCCompletionQueue *)queue;

@ -40,13 +40,15 @@ struct grpc_credentials;
@interface GRPCSecureChannel : GRPCChannel @interface GRPCSecureChannel : GRPCChannel
- (instancetype)initWithHost:(NSString *)host; - (instancetype)initWithHost:(NSString *)host;
// Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for /**
// pathToCertificates results in using the default root certificates distributed with the library. * Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for
* pathToCertificates results in using the default root certificates distributed with the library.
*/
- (instancetype)initWithHost:(NSString *)host - (instancetype)initWithHost:(NSString *)host
pathToCertificates:(NSString *)path pathToCertificates:(NSString *)path
hostNameOverride:(NSString *)hostNameOverride; hostNameOverride:(NSString *)hostNameOverride;
// The passed arguments aren't required to be valid beyond the invocation of this initializer. /** The passed arguments aren't required to be valid beyond the invocation of this initializer. */
- (instancetype)initWithHost:(NSString *)host - (instancetype)initWithHost:(NSString *)host
credentials:(struct grpc_credentials *)credentials credentials:(struct grpc_credentials *)credentials
args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER; args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER;

@ -39,7 +39,7 @@
@interface GRPCOperation : NSObject @interface GRPCOperation : NSObject
@property(nonatomic, readonly) grpc_op op; @property(nonatomic, readonly) grpc_op op;
// Guaranteed to be called when the operation has finished. /** Guaranteed to be called when the operation has finished. */
- (void)finish; - (void)finish;
@end @end

@ -35,7 +35,9 @@
#include <grpc/grpc.h> #include <grpc/grpc.h>
@interface NSError (GRPC) @interface NSError (GRPC)
// Returns nil if the status code is OK. Otherwise, a NSError whose code is one of |GRPCErrorCode| /**
// and whose domain is |kGRPCErrorDomain|. * Returns nil if the status code is OK. Otherwise, a NSError whose code is one of |GRPCErrorCode|
* and whose domain is |kGRPCErrorDomain|.
*/
+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details; + (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details;
@end @end

@ -33,8 +33,10 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
// A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint /**
// can implement multiple services. * A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint
* can implement multiple services.
*/
@interface ProtoMethod : NSObject @interface ProtoMethod : NSObject
@property(nonatomic, readonly) NSString *package; @property(nonatomic, readonly) NSString *package;
@property(nonatomic, readonly) NSString *service; @property(nonatomic, readonly) NSString *service;

@ -36,25 +36,27 @@
#import "GRXWriteable.h" #import "GRXWriteable.h"
#import "GRXWriter.h" #import "GRXWriter.h"
// A buffered pipe is a Writer that also acts as a Writeable. /**
// Once it is started, whatever values are written into it (via -writeValue:) will be propagated * A buffered pipe is a Writer that also acts as a Writeable.
// immediately, unless flow control prevents it. * Once it is started, whatever values are written into it (via -writeValue:) will be propagated
// If it is throttled and keeps receiving values, as well as if it receives values before being * immediately, unless flow control prevents it.
// started, it will buffer them and propagate them in order as soon as its state becomes Started. * If it is throttled and keeps receiving values, as well as if it receives values before being
// If it receives an error (via -writesFinishedWithError:), it will drop any buffered values and * started, it will buffer them and propagate them in order as soon as its state becomes Started.
// propagate the error immediately. * If it receives an error (via -writesFinishedWithError:), it will drop any buffered values and
// * propagate the error immediately.
// Beware that a pipe of this type can't prevent receiving more values when it is paused (for *
// example if used to write data to a congested network connection). Because in such situations the * Beware that a pipe of this type can't prevent receiving more values when it is paused (for
// pipe will keep buffering all data written to it, your application could run out of memory and * example if used to write data to a congested network connection). Because in such situations the
// crash. If you want to react to flow control signals to prevent that, instead of using this class * pipe will keep buffering all data written to it, your application could run out of memory and
// you can implement an object that conforms to GRXWriter. * crash. If you want to react to flow control signals to prevent that, instead of using this class
// * you can implement an object that conforms to GRXWriter.
// Thread-safety: *
// The methods of an object of this class should not be called concurrently from different threads. * Thread-safety:
* The methods of an object of this class should not be called concurrently from different threads.
*/
@interface GRXBufferedPipe : GRXWriter<GRXWriteable> @interface GRXBufferedPipe : GRXWriter<GRXWriteable>
// Convenience constructor. /** Convenience constructor. */
+ (instancetype)pipe; + (instancetype)pipe;
@end @end

@ -36,36 +36,48 @@
#import "GRXWriter.h" #import "GRXWriter.h"
#import "GRXWriteable.h" #import "GRXWriteable.h"
// This is a thread-safe wrapper over a GRXWriteable instance. It lets one enqueue calls to a /**
// GRXWriteable instance for the main thread, guaranteeing that writesFinishedWithError: is the last * This is a thread-safe wrapper over a GRXWriteable instance. It lets one enqueue calls to a
// message sent to it (no matter what messages are sent to the wrapper, in what order, nor from * GRXWriteable instance for the main thread, guaranteeing that writesFinishedWithError: is the last
// which thread). It also guarantees that, if cancelWithError: is called from the main thread (e.g. * message sent to it (no matter what messages are sent to the wrapper, in what order, nor from
// by the app cancelling the writes), no further messages are sent to the writeable except * which thread). It also guarantees that, if cancelWithError: is called from the main thread (e.g.
// writesFinishedWithError:. * by the app cancelling the writes), no further messages are sent to the writeable except
// * writesFinishedWithError:.
// TODO(jcanizales): Let the user specify another queue for the writeable callbacks. *
* TODO(jcanizales): Let the user specify another queue for the writeable callbacks.
*/
@interface GRXConcurrentWriteable : NSObject @interface GRXConcurrentWriteable : NSObject
// The GRXWriteable passed is the wrapped writeable. /**
// The GRXWriteable instance is retained until writesFinishedWithError: is sent to it, and released * The GRXWriteable passed is the wrapped writeable.
// after that. * The GRXWriteable instance is retained until writesFinishedWithError: is sent to it, and released
* after that.
*/
- (instancetype)initWithWriteable:(id<GRXWriteable>)writeable NS_DESIGNATED_INITIALIZER; - (instancetype)initWithWriteable:(id<GRXWriteable>)writeable NS_DESIGNATED_INITIALIZER;
// Enqueues writeValue: to be sent to the writeable in the main thread. /**
// The passed handler is invoked from the main thread after writeValue: returns. * Enqueues writeValue: to be sent to the writeable in the main thread.
* The passed handler is invoked from the main thread after writeValue: returns.
*/
- (void)enqueueValue:(id)value completionHandler:(void (^)())handler; - (void)enqueueValue:(id)value completionHandler:(void (^)())handler;
// Enqueues writesFinishedWithError:nil to be sent to the writeable in the main thread. After that /**
// message is sent to the writeable, all other methods of this object are effectively noops. * Enqueues writesFinishedWithError:nil to be sent to the writeable in the main thread. After that
* message is sent to the writeable, all other methods of this object are effectively noops.
*/
- (void)enqueueSuccessfulCompletion; - (void)enqueueSuccessfulCompletion;
// If the writeable has not yet received a writesFinishedWithError: message, this will enqueue one /**
// to be sent to it in the main thread, and cancel all other pending messages to the writeable * If the writeable has not yet received a writesFinishedWithError: message, this will enqueue one
// enqueued by this object (both past and future). * to be sent to it in the main thread, and cancel all other pending messages to the writeable
// The error argument cannot be nil. * enqueued by this object (both past and future).
* The error argument cannot be nil.
*/
- (void)cancelWithError:(NSError *)error; - (void)cancelWithError:(NSError *)error;
// Cancels all pending messages to the writeable enqueued by this object (both past and future). /**
// Because the writeable won't receive writesFinishedWithError:, this also releases the writeable. * Cancels all pending messages to the writeable enqueued by this object (both past and future).
* Because the writeable won't receive writesFinishedWithError:, this also releases the writeable.
*/
- (void)cancelSilently; - (void)cancelSilently;
@end @end

@ -33,17 +33,19 @@
#import "GRXWriter.h" #import "GRXWriter.h"
// A "proxy" class that simply forwards values, completion, and errors from its input writer to its /**
// writeable. * A "proxy" class that simply forwards values, completion, and errors from its input writer to its
// It is useful as a superclass for pipes that act as a transformation of their * writeable.
// input writer, and for classes that represent objects with input and * It is useful as a superclass for pipes that act as a transformation of their
// output sequences of values, like an RPC. * input writer, and for classes that represent objects with input and
// * output sequences of values, like an RPC.
// Thread-safety: *
// All messages sent to this object need to be serialized. When it is started, the writer it wraps * Thread-safety:
// is started in the same thread. Manual state changes are propagated to the wrapped writer in the * All messages sent to this object need to be serialized. When it is started, the writer it wraps
// same thread too. Importantly, all messages the wrapped writer sends to its writeable need to be * is started in the same thread. Manual state changes are propagated to the wrapped writer in the
// serialized with any message sent to this object. * same thread too. Importantly, all messages the wrapped writer sends to its writeable need to be
* serialized with any message sent to this object.
*/
@interface GRXForwardingWriter : GRXWriter @interface GRXForwardingWriter : GRXWriter
- (instancetype)initWithWriter:(GRXWriter *)writer NS_DESIGNATED_INITIALIZER; - (instancetype)initWithWriter:(GRXWriter *)writer NS_DESIGNATED_INITIALIZER;
@end @end

@ -35,46 +35,60 @@
#import "GRXWriter.h" #import "GRXWriter.h"
// Utility to construct GRXWriter instances from values that are immediately available when /**
// required. * Utility to construct GRXWriter instances from values that are immediately available when
// * required.
// Thread-safety: *
// * Thread-safety:
// An object of this class shouldn't be messaged concurrently by more than one thread. It will start *
// messaging the writeable before |startWithWriteable:| returns, in the same thread. That is the * An object of this class shouldn't be messaged concurrently by more than one thread. It will start
// only place where the writer can be paused or stopped prematurely. * messaging the writeable before |startWithWriteable:| returns, in the same thread. That is the
// * only place where the writer can be paused or stopped prematurely.
// If a paused writer of this class is resumed, it will start messaging the writeable, in the same *
// thread, before |setState:| returns. Because the object can't be legally accessed concurrently, * If a paused writer of this class is resumed, it will start messaging the writeable, in the same
// that's the only place where it can be paused again (or stopped). * thread, before |setState:| returns. Because the object can't be legally accessed concurrently,
* that's the only place where it can be paused again (or stopped).
*/
@interface GRXImmediateWriter : GRXWriter @interface GRXImmediateWriter : GRXWriter
// Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to /**
// its writeable. The NSEnumerator is released when it finishes. * Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to
* its writeable. The NSEnumerator is released when it finishes.
*/
+ (GRXWriter *)writerWithEnumerator:(NSEnumerator *)enumerator; + (GRXWriter *)writerWithEnumerator:(NSEnumerator *)enumerator;
// Returns a writer that pushes to its writeable the successive values returned by the passed /**
// block. When the block first returns nil, it is released. * Returns a writer that pushes to its writeable the successive values returned by the passed
* block. When the block first returns nil, it is released.
*/
+ (GRXWriter *)writerWithValueSupplier:(id (^)())block; + (GRXWriter *)writerWithValueSupplier:(id (^)())block;
// Returns a writer that iterates over the values of the passed container and pushes them to /**
// its writeable. The container is released when the iteration is over. * Returns a writer that iterates over the values of the passed container and pushes them to
// * its writeable. The container is released when the iteration is over.
// Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to *
// call one method per element. Because GRXWriteable instances accept values one by one, that speed * Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to
// gain doesn't happen here. * call one method per element. Because GRXWriteable instances accept values one by one, that speed
* gain doesn't happen here.
*/
+ (GRXWriter *)writerWithContainer:(id<NSFastEnumeration>)container; + (GRXWriter *)writerWithContainer:(id<NSFastEnumeration>)container;
// Returns a writer that sends the passed value to its writeable and then finishes (releasing the /**
// value). * Returns a writer that sends the passed value to its writeable and then finishes (releasing the
* value).
*/
+ (GRXWriter *)writerWithValue:(id)value; + (GRXWriter *)writerWithValue:(id)value;
// Returns a writer that, as part of its start method, sends the passed error to the writeable /**
// (then releasing the error). * Returns a writer that, as part of its start method, sends the passed error to the writeable
* (then releasing the error).
*/
+ (GRXWriter *)writerWithError:(NSError *)error; + (GRXWriter *)writerWithError:(NSError *)error;
// Returns a writer that, as part of its start method, finishes immediately without sending any /**
// values to its writeable. * Returns a writer that, as part of its start method, finishes immediately without sending any
* values to its writeable.
*/
+ (GRXWriter *)emptyWriter; + (GRXWriter *)emptyWriter;
@end @end

@ -33,16 +33,20 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
// A GRXWriteable is an object to which a sequence of values can be sent. The /**
// sequence finishes with an optional error. * A GRXWriteable is an object to which a sequence of values can be sent. The
* sequence finishes with an optional error.
*/
@protocol GRXWriteable <NSObject> @protocol GRXWriteable <NSObject>
// Push the next value of the sequence to the receiving object. /** Push the next value of the sequence to the receiving object. */
- (void)writeValue:(id)value; - (void)writeValue:(id)value;
// Signal that the sequence is completed, or that an error ocurred. After this /**
// message is sent to the instance, neither it nor writeValue: may be * Signal that the sequence is completed, or that an error ocurred. After this
// called again. * message is sent to the instance, neither it nor writeValue: may be
* called again.
*/
- (void)writesFinishedWithError:(NSError *)errorOrNil; - (void)writesFinishedWithError:(NSError *)errorOrNil;
@end @end
@ -51,8 +55,10 @@ typedef void (^GRXCompletionHandler)(NSError *errorOrNil);
typedef void (^GRXSingleHandler)(id value, NSError *errorOrNil); typedef void (^GRXSingleHandler)(id value, NSError *errorOrNil);
typedef void (^GRXEventHandler)(BOOL done, id value, NSError *error); typedef void (^GRXEventHandler)(BOOL done, id value, NSError *error);
// Utility to create objects that conform to the GRXWriteable protocol, from /**
// blocks that handle each of the two methods of the protocol. * Utility to create objects that conform to the GRXWriteable protocol, from
* blocks that handle each of the two methods of the protocol.
*/
@interface GRXWriteable : NSObject<GRXWriteable> @interface GRXWriteable : NSObject<GRXWriteable>
+ (instancetype)writeableWithSingleHandler:(GRXSingleHandler)handler; + (instancetype)writeableWithSingleHandler:(GRXSingleHandler)handler;

@ -35,32 +35,44 @@
@interface GRXWriter (Immediate) @interface GRXWriter (Immediate)
// Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to /**
// its writeable. The NSEnumerator is released when it finishes. * Returns a writer that pulls values from the passed NSEnumerator instance and pushes them to
* its writeable. The NSEnumerator is released when it finishes.
*/
+ (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator; + (instancetype)writerWithEnumerator:(NSEnumerator *)enumerator;
// Returns a writer that pushes to its writeable the successive values returned by the passed /**
// block. When the block first returns nil, it is released. * Returns a writer that pushes to its writeable the successive values returned by the passed
* block. When the block first returns nil, it is released.
*/
+ (instancetype)writerWithValueSupplier:(id (^)())block; + (instancetype)writerWithValueSupplier:(id (^)())block;
// Returns a writer that iterates over the values of the passed container and pushes them to /**
// its writeable. The container is released when the iteration is over. * Returns a writer that iterates over the values of the passed container and pushes them to
// * its writeable. The container is released when the iteration is over.
// Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to *
// call one method per element. Because GRXWriteable instances accept values one by one, that speed * Note that the usual speed gain of NSFastEnumeration over NSEnumerator results from not having to
// gain doesn't happen here. * call one method per element. Because GRXWriteable instances accept values one by one, that speed
* gain doesn't happen here.
*/
+ (instancetype)writerWithContainer:(id<NSFastEnumeration>)container; + (instancetype)writerWithContainer:(id<NSFastEnumeration>)container;
// Returns a writer that sends the passed value to its writeable and then finishes (releasing the /**
// value). * Returns a writer that sends the passed value to its writeable and then finishes (releasing the
* value).
*/
+ (instancetype)writerWithValue:(id)value; + (instancetype)writerWithValue:(id)value;
// Returns a writer that, as part of its start method, sends the passed error to the writeable /**
// (then releasing the error). * Returns a writer that, as part of its start method, sends the passed error to the writeable
* (then releasing the error).
*/
+ (instancetype)writerWithError:(NSError *)error; + (instancetype)writerWithError:(NSError *)error;
// Returns a writer that, as part of its start method, finishes immediately without sending any /**
// values to its writeable. * Returns a writer that, as part of its start method, finishes immediately without sending any
* values to its writeable.
*/
+ (instancetype)emptyWriter; + (instancetype)emptyWriter;
@end @end

@ -35,8 +35,10 @@
@interface GRXWriter (Transformations) @interface GRXWriter (Transformations)
// Returns a writer that wraps the receiver, and has all the values the receiver would write /**
// transformed by the provided mapping function. * Returns a writer that wraps the receiver, and has all the values the receiver would write
* transformed by the provided mapping function.
*/
- (GRXWriter *)map:(id (^)(id value))map; - (GRXWriter *)map:(id (^)(id value))map;
@end @end

@ -35,73 +35,87 @@
#import "GRXWriteable.h" #import "GRXWriteable.h"
// States of a writer. /** States of a writer. */
typedef NS_ENUM(NSInteger, GRXWriterState) { typedef NS_ENUM(NSInteger, GRXWriterState) {
// The writer has not yet been given a writeable to which it can push its values. To have a writer /**
// transition to the Started state, send it a startWithWriteable: message. * The writer has not yet been given a writeable to which it can push its values. To have a writer
// * transition to the Started state, send it a startWithWriteable: message.
// A writer's state cannot be manually set to this value. *
* A writer's state cannot be manually set to this value.
*/
GRXWriterStateNotStarted, GRXWriterStateNotStarted,
// The writer might push values to the writeable at any moment. /** The writer might push values to the writeable at any moment. */
GRXWriterStateStarted, GRXWriterStateStarted,
// The writer is temporarily paused, and won't send any more values to the writeable unless its /**
// state is set back to Started. The writer might still transition to the Finished state at any * The writer is temporarily paused, and won't send any more values to the writeable unless its
// moment, and is allowed to send writesFinishedWithError: to its writeable. * state is set back to Started. The writer might still transition to the Finished state at any
* moment, and is allowed to send writesFinishedWithError: to its writeable.
*/
GRXWriterStatePaused, GRXWriterStatePaused,
// The writer has released its writeable and won't interact with it anymore. /**
// * The writer has released its writeable and won't interact with it anymore.
// One seldomly wants to set a writer's state to this value, as its writeable isn't notified with *
// a writesFinishedWithError: message. Instead, sending finishWithError: to the writer will make * One seldomly wants to set a writer's state to this value, as its writeable isn't notified with
// it notify the writeable and then transition to this state. * a writesFinishedWithError: message. Instead, sending finishWithError: to the writer will make
* it notify the writeable and then transition to this state.
*/
GRXWriterStateFinished GRXWriterStateFinished
}; };
// An GRXWriter object can produce, on demand, a sequence of values. The sequence may be produced /**
// asynchronously, and it may consist of any number of elements, including none or an infinite * An GRXWriter object can produce, on demand, a sequence of values. The sequence may be produced
// number. * asynchronously, and it may consist of any number of elements, including none or an infinite
// * number.
// GRXWriter is the active dual of NSEnumerator. The difference between them is thus whether the *
// object plays an active or passive role during usage: A user of NSEnumerator pulls values off it, * GRXWriter is the active dual of NSEnumerator. The difference between them is thus whether the
// and passes the values to a writeable. A user of GRXWriter, though, just gives it a writeable, and * object plays an active or passive role during usage: A user of NSEnumerator pulls values off it,
// the GRXWriter instance pushes values to the writeable. This makes this protocol suitable to * and passes the values to a writeable. A user of GRXWriter, though, just gives it a writeable, and
// represent a sequence of future values, as well as collections with internal iteration. * the GRXWriter instance pushes values to the writeable. This makes this protocol suitable to
// * represent a sequence of future values, as well as collections with internal iteration.
// An instance of GRXWriter can start producing values after a writeable is passed to it. It can *
// also be commanded to finish the sequence immediately (with an optional error). Finally, it can be * An instance of GRXWriter can start producing values after a writeable is passed to it. It can
// asked to pause, and resumed later. All GRXWriter objects support pausing and early termination. * also be commanded to finish the sequence immediately (with an optional error). Finally, it can be
// * asked to pause, and resumed later. All GRXWriter objects support pausing and early termination.
// Thread-safety: *
// * Thread-safety:
// State transitions take immediate effect if the object is used from a single thread. Subclasses *
// might offer stronger guarantees. * State transitions take immediate effect if the object is used from a single thread. Subclasses
// * might offer stronger guarantees.
// Unless otherwise indicated by a conforming subclass, no messages should be sent concurrently to a *
// GRXWriter. I.e., conforming classes aren't required to be thread-safe. * Unless otherwise indicated by a conforming subclass, no messages should be sent concurrently to a
* GRXWriter. I.e., conforming classes aren't required to be thread-safe.
*/
@interface GRXWriter : NSObject @interface GRXWriter : NSObject
// This property can be used to query the current state of the writer, which determines how it might /**
// currently use its writeable. Some state transitions can be triggered by setting this property to * This property can be used to query the current state of the writer, which determines how it might
// the corresponding value, and that's useful for advanced use cases like pausing an writer. For * currently use its writeable. Some state transitions can be triggered by setting this property to
// more details, see the documentation of the enum further down. * the corresponding value, and that's useful for advanced use cases like pausing an writer. For
* more details, see the documentation of the enum further down.
*/
@property(nonatomic) GRXWriterState state; @property(nonatomic) GRXWriterState state;
// Transition to the Started state, and start sending messages to the writeable (a reference to it /**
// is retained). Messages to the writeable may be sent before the method returns, or they may be * Transition to the Started state, and start sending messages to the writeable (a reference to it
// sent later in the future. See GRXWriteable.h for the different messages a writeable can receive. * is retained). Messages to the writeable may be sent before the method returns, or they may be
// * sent later in the future. See GRXWriteable.h for the different messages a writeable can receive.
// If this writer draws its values from an external source (e.g. from the filesystem or from a *
// server), calling this method will commonly trigger side effects (like network connections). * If this writer draws its values from an external source (e.g. from the filesystem or from a
// * server), calling this method will commonly trigger side effects (like network connections).
// This method might only be called on writers in the NotStarted state. *
* This method might only be called on writers in the NotStarted state.
*/
- (void)startWithWriteable:(id<GRXWriteable>)writeable; - (void)startWithWriteable:(id<GRXWriteable>)writeable;
// Send writesFinishedWithError:errorOrNil to the writeable. Then release the reference to it and /**
// transition to the Finished state. * Send writesFinishedWithError:errorOrNil to the writeable. Then release the reference to it and
// * transition to the Finished state.
// This method might only be called on writers in the Started or Paused state. *
* This method might only be called on writers in the Started or Paused state.
*/
- (void)finishWithError:(NSError *)errorOrNil; - (void)finishWithError:(NSError *)errorOrNil;
@end @end

@ -35,17 +35,23 @@
@interface NSEnumerator (GRXUtil) @interface NSEnumerator (GRXUtil)
// Returns a NSEnumerator instance that iterates through the elements of the passed container that /**
// supports fast enumeration. Note that this negates the speed benefits of fast enumeration over * Returns a NSEnumerator instance that iterates through the elements of the passed container that
// NSEnumerator. It's only intended for the rare cases when one needs the latter and only has the * supports fast enumeration. Note that this negates the speed benefits of fast enumeration over
// former, e.g. for iteration that needs to be paused and resumed later. * NSEnumerator. It's only intended for the rare cases when one needs the latter and only has the
* former, e.g. for iteration that needs to be paused and resumed later.
*/
+ (NSEnumerator *)grx_enumeratorWithContainer:(id<NSFastEnumeration>)container; + (NSEnumerator *)grx_enumeratorWithContainer:(id<NSFastEnumeration>)container;
// Returns a NSEnumerator instance that provides a single object before finishing. The value is then /**
// released. * Returns a NSEnumerator instance that provides a single object before finishing. The value is then
* released.
*/
+ (NSEnumerator *)grx_enumeratorWithSingleValue:(id)value; + (NSEnumerator *)grx_enumeratorWithSingleValue:(id)value;
// Returns a NSEnumerator instance that delegates the invocations of nextObject to the passed block. /**
// When the block first returns nil, it is released. * Returns a NSEnumerator instance that delegates the invocations of nextObject to the passed block.
* When the block first returns nil, it is released.
*/
+ (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)())block; + (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)())block;
@end @end

@ -33,10 +33,14 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
// Concrete subclass of NSEnumerator that delegates the invocations of nextObject to a block passed /**
// on initialization. * Concrete subclass of NSEnumerator that delegates the invocations of nextObject to a block passed
* on initialization.
*/
@interface GRXNSBlockEnumerator : NSEnumerator @interface GRXNSBlockEnumerator : NSEnumerator
// The first time the passed block returns nil, the enumeration will end and the block will be /**
// released. * The first time the passed block returns nil, the enumeration will end and the block will be
* released.
*/
- (instancetype)initWithValueSupplier:(id (^)())block; - (instancetype)initWithValueSupplier:(id (^)())block;
@end @end

@ -33,11 +33,15 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
// This is a bridge to interact through NSEnumerator's interface with objects that only conform to /**
// NSFastEnumeration. (There's nothing specifically fast about it - you certainly don't win any * This is a bridge to interact through NSEnumerator's interface with objects that only conform to
// speed by using this instead of a NSEnumerator provided by your container). * NSFastEnumeration. (There's nothing specifically fast about it - you certainly don't win any
* speed by using this instead of a NSEnumerator provided by your container).
*/
@interface GRXNSFastEnumerator : NSEnumerator @interface GRXNSFastEnumerator : NSEnumerator
// After the iteration of the container (via the NSFastEnumeration protocol) is over, the container /**
// is released. If the container is modified during enumeration, an exception is thrown. * After the iteration of the container (via the NSFastEnumeration protocol) is over, the container
* is released. If the container is modified during enumeration, an exception is thrown.
*/
- (instancetype)initWithContainer:(id<NSFastEnumeration>)container; - (instancetype)initWithContainer:(id<NSFastEnumeration>)container;
@end @end

@ -33,9 +33,11 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
// Concrete subclass of NSEnumerator whose instances return a single object before finishing. /** Concrete subclass of NSEnumerator whose instances return a single object before finishing. */
@interface GRXNSScalarEnumerator : NSEnumerator @interface GRXNSScalarEnumerator : NSEnumerator
// Param value: the single object this instance will produce. After the first invocation of /**
// nextObject, the value is released. * Param value: the single object this instance will produce. After the first invocation of
* nextObject, the value is released.
*/
- (instancetype)initWithValue:(id)value; - (instancetype)initWithValue:(id)value;
@end @end

@ -33,7 +33,7 @@
#import "RxLibrary/GRXForwardingWriter.h" #import "RxLibrary/GRXForwardingWriter.h"
// A "proxy" writer that transforms all the values of its input writer by using a mapping function. /** A "proxy" writer that transforms all the values of its input writer by using a mapping function. */
@interface GRXMappingWriter : GRXForwardingWriter @interface GRXMappingWriter : GRXForwardingWriter
- (instancetype)initWithWriter:(GRXWriter *)writer map:(id (^)(id value))map - (instancetype)initWithWriter:(GRXWriter *)writer map:(id (^)(id value))map
NS_DESIGNATED_INITIALIZER; NS_DESIGNATED_INITIALIZER;

@ -0,0 +1,128 @@
#!/usr/bin/env python2.7
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Change comments style of source files from // to /** */"""
import re
import sys
if len(sys.argv) < 2:
print("Please provide at least one source file name as argument.")
sys.exit()
for file_name in sys.argv[1:]:
print("Modifying format of {file} comments in place...".format(
file=file_name,
))
# Input
with open(file_name, "r") as input_file:
lines = input_file.readlines()
def peek():
return lines[0]
def read_line():
return lines.pop(0)
def more_input_available():
return lines
# Output
output_lines = []
def write(line):
output_lines.append(line)
def flush_output():
with open(file_name, "w") as output_file:
for line in output_lines:
output_file.write(line)
# Pattern matching
comment_regex = r'^(\s*)//\s(.*)$'
def is_comment(line):
return re.search(comment_regex, line)
def isnt_comment(line):
return not is_comment(line)
def next_line(predicate):
return more_input_available() and predicate(peek())
# Transformation
def indentation_of(line):
match = re.search(comment_regex, line)
return match.group(1)
def content(line):
match = re.search(comment_regex, line)
return match.group(2)
def format_as_block(comment_block):
if len(comment_block) == 0:
return []
indent = indentation_of(comment_block[0])
if len(comment_block) == 1:
return [indent + "/** " + content(comment_block[0]) + " */\n"]
block = ["/**"] + [" * " + content(line) for line in comment_block] + [" */"]
return [indent + line.rstrip() + "\n" for line in block]
# Main algorithm
while more_input_available():
while next_line(isnt_comment):
write(read_line())
comment_block = []
# Get all lines in the same comment block. We could restrict the indentation
# to be the same as the first line of the block, but it's probably ok.
while (next_line(is_comment)):
comment_block.append(read_line())
for line in format_as_block(comment_block):
write(line)
flush_output()

@ -0,0 +1,31 @@
#!/bin/bash
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
find . -type f -name "*.h" ! -path "*/Pods/*" ! -path "./generated_libraries/*" ! -path "./examples/*" ! -path "./tests/*" | xargs ./change-comments.py
Loading…
Cancel
Save