Cleanup: remove redundant extension code

pull/1188/head
Tim Emiola 10 years ago
parent 495e9a8c75
commit c8b55a3a31
  1. 201
      src/ruby/ext/grpc/rb_byte_buffer.c
  2. 14
      src/ruby/ext/grpc/rb_byte_buffer.h
  3. 296
      src/ruby/ext/grpc/rb_call.c
  4. 1
      src/ruby/ext/grpc/rb_completion_queue.c
  5. 361
      src/ruby/ext/grpc/rb_event.c
  6. 53
      src/ruby/ext/grpc/rb_event.h
  7. 6
      src/ruby/ext/grpc/rb_grpc.c
  8. 215
      src/ruby/ext/grpc/rb_metadata.c
  9. 53
      src/ruby/ext/grpc/rb_metadata.h

@ -65,204 +65,3 @@ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
}
return rb_str_new(string, length);
}
/* grpc_rb_byte_buffer wraps a grpc_byte_buffer. It provides a peer ruby
* object, 'mark' to minimize copying when a byte_buffer is created from
* ruby. */
typedef struct grpc_rb_byte_buffer {
/* Holder of ruby objects involved in constructing the status */
VALUE mark;
/* The actual status */
grpc_byte_buffer *wrapped;
} grpc_rb_byte_buffer;
/* Destroys ByteBuffer instances. */
static void grpc_rb_byte_buffer_free(void *p) {
grpc_rb_byte_buffer *bb = NULL;
if (p == NULL) {
return;
};
bb = (grpc_rb_byte_buffer *)p;
/* Deletes the wrapped object if the mark object is Qnil, which indicates
* that no other object is the actual owner. */
if (bb->wrapped != NULL && bb->mark == Qnil) {
grpc_byte_buffer_destroy(bb->wrapped);
}
xfree(p);
}
/* Protects the mark object from GC */
static void grpc_rb_byte_buffer_mark(void *p) {
grpc_rb_byte_buffer *bb = NULL;
if (p == NULL) {
return;
}
bb = (grpc_rb_byte_buffer *)p;
/* If it's not already cleaned up, mark the mark object */
if (bb->mark != Qnil && BUILTIN_TYPE(bb->mark) != T_NONE) {
rb_gc_mark(bb->mark);
}
}
/* id_source is the name of the hidden ivar the preserves the original
* byte_buffer source string */
static ID id_source;
/* Allocates ByteBuffer instances.
Provides safe default values for the byte_buffer fields. */
static VALUE grpc_rb_byte_buffer_alloc(VALUE cls) {
grpc_rb_byte_buffer *wrapper = ALLOC(grpc_rb_byte_buffer);
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
return Data_Wrap_Struct(cls, grpc_rb_byte_buffer_mark,
grpc_rb_byte_buffer_free, wrapper);
}
/* Clones ByteBuffer instances.
Gives ByteBuffer a consistent implementation of Ruby's object copy/dup
protocol. */
static VALUE grpc_rb_byte_buffer_init_copy(VALUE copy, VALUE orig) {
grpc_rb_byte_buffer *orig_bb = NULL;
grpc_rb_byte_buffer *copy_bb = NULL;
if (copy == orig) {
return copy;
}
/* Raise an error if orig is not a metadata object or a subclass. */
if (TYPE(orig) != T_DATA ||
RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_byte_buffer_free) {
rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cByteBuffer));
}
Data_Get_Struct(orig, grpc_rb_byte_buffer, orig_bb);
Data_Get_Struct(copy, grpc_rb_byte_buffer, copy_bb);
/* use ruby's MEMCPY to make a byte-for-byte copy of the metadata wrapper
* object. */
MEMCPY(copy_bb, orig_bb, grpc_rb_byte_buffer, 1);
return copy;
}
/* id_empty is used to return the empty string from to_s when necessary. */
static ID id_empty;
static VALUE grpc_rb_byte_buffer_to_s_obj(VALUE self) {
grpc_rb_byte_buffer *wrapper = NULL;
grpc_byte_buffer *bb = NULL;
grpc_byte_buffer_reader *reader = NULL;
char *output = NULL;
size_t length = 0;
size_t offset = 0;
VALUE output_obj = Qnil;
gpr_slice next;
Data_Get_Struct(self, grpc_rb_byte_buffer, wrapper);
output_obj = rb_ivar_get(wrapper->mark, id_source);
if (output_obj != Qnil) {
/* From ruby, ByteBuffers are immutable so if a source is set, return that
* as the to_s value */
return output_obj;
}
/* Read the bytes. */
bb = wrapper->wrapped;
if (bb == NULL) {
return rb_id2str(id_empty);
}
length = grpc_byte_buffer_length(bb);
if (length == 0) {
return rb_id2str(id_empty);
}
reader = grpc_byte_buffer_reader_create(bb);
output = xmalloc(length);
while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
memcpy(output + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
}
output_obj = rb_str_new(output, length);
/* Save a references to the computed string in the mark object so that the
* calling to_s does not do any allocations. */
wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
rb_ivar_set(wrapper->mark, id_source, output_obj);
return output_obj;
}
/* Initializes ByteBuffer instances. */
static VALUE grpc_rb_byte_buffer_init(VALUE self, VALUE src) {
gpr_slice a_slice;
grpc_rb_byte_buffer *wrapper = NULL;
grpc_byte_buffer *byte_buffer = NULL;
if (TYPE(src) != T_STRING) {
rb_raise(rb_eTypeError, "bad byte_buffer arg: got <%s>, want <String>",
rb_obj_classname(src));
return Qnil;
}
Data_Get_Struct(self, grpc_rb_byte_buffer, wrapper);
a_slice = gpr_slice_malloc(RSTRING_LEN(src));
memcpy(GPR_SLICE_START_PTR(a_slice), RSTRING_PTR(src), RSTRING_LEN(src));
byte_buffer = grpc_byte_buffer_create(&a_slice, 1);
gpr_slice_unref(a_slice);
if (byte_buffer == NULL) {
rb_raise(rb_eArgError, "could not create a byte_buffer, not sure why");
return Qnil;
}
wrapper->wrapped = byte_buffer;
/* Save a references to the original string in the mark object so that the
* pointers used there is valid for the lifetime of the object. */
wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
rb_ivar_set(wrapper->mark, id_source, src);
return self;
}
/* rb_cByteBuffer is the ruby class that proxies grpc_byte_buffer. */
VALUE rb_cByteBuffer = Qnil;
void Init_grpc_byte_buffer() {
rb_cByteBuffer =
rb_define_class_under(rb_mGrpcCore, "ByteBuffer", rb_cObject);
/* Allocates an object managed by the ruby runtime */
rb_define_alloc_func(rb_cByteBuffer, grpc_rb_byte_buffer_alloc);
/* Provides a ruby constructor and support for dup/clone. */
rb_define_method(rb_cByteBuffer, "initialize", grpc_rb_byte_buffer_init, 1);
rb_define_method(rb_cByteBuffer, "initialize_copy",
grpc_rb_byte_buffer_init_copy, 1);
/* Provides a to_s method that returns the buffer value */
rb_define_method(rb_cByteBuffer, "to_s", grpc_rb_byte_buffer_to_s_obj, 0);
id_source = rb_intern("__source");
id_empty = rb_intern("");
}
VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer *bb) {
grpc_rb_byte_buffer *byte_buffer = NULL;
if (bb == NULL) {
return Qnil;
}
byte_buffer = ALLOC(grpc_rb_byte_buffer);
byte_buffer->wrapped = bb;
byte_buffer->mark = mark;
return Data_Wrap_Struct(rb_cByteBuffer, grpc_rb_byte_buffer_mark,
grpc_rb_byte_buffer_free, byte_buffer);
}
/* Gets the wrapped byte_buffer from the ruby wrapper */
grpc_byte_buffer *grpc_rb_get_wrapped_byte_buffer(VALUE v) {
grpc_rb_byte_buffer *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_byte_buffer, wrapper);
return wrapper->wrapped;
}

@ -37,20 +37,6 @@
#include <grpc/grpc.h>
#include <ruby.h>
/* rb_cByteBuffer is the ByteBuffer class whose instances proxy
grpc_byte_buffer. */
extern VALUE rb_cByteBuffer;
/* Initializes the ByteBuffer class. */
void Init_grpc_byte_buffer();
/* grpc_rb_byte_buffer_create_with_mark creates a grpc_rb_byte_buffer with a
* ruby mark object that will be kept alive while the byte_buffer is alive. */
VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer* bb);
/* Gets the wrapped byte_buffer from its ruby object. */
grpc_byte_buffer* grpc_rb_get_wrapped_byte_buffer(VALUE v);
/* Converts a char* with a length to a grpc_byte_buffer */
grpc_byte_buffer *grpc_rb_s_to_byte_buffer(char *string, size_t length);

@ -40,7 +40,6 @@
#include "rb_byte_buffer.h"
#include "rb_completion_queue.h"
#include "rb_metadata.h"
#include "rb_grpc.h"
/* rb_sBatchResult is struct class used to hold the results of a batch call */
@ -119,87 +118,6 @@ const char *grpc_call_error_detail_of(grpc_call_error err) {
return detail;
}
/* grpc_rb_call_add_metadata_hash_cb is the hash iteration callback used by
grpc_rb_call_add_metadata.
*/
int grpc_rb_call_add_metadata_hash_cb(VALUE key, VALUE val, VALUE call_obj) {
grpc_call *call = NULL;
grpc_metadata *md = NULL;
VALUE md_obj = Qnil;
VALUE md_obj_args[2];
VALUE flags = rb_ivar_get(call_obj, id_flags);
grpc_call_error err;
int array_length;
int i;
/* Construct a metadata object from key and value and add it */
Data_Get_Struct(call_obj, grpc_call, call);
md_obj_args[0] = key;
if (TYPE(val) == T_ARRAY) {
/* If the value is an array, add each value in the array separately */
array_length = RARRAY_LEN(val);
for (i = 0; i < array_length; i++) {
md_obj_args[1] = rb_ary_entry(val, i);
md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
md = grpc_rb_get_wrapped_metadata(md_obj);
err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
return ST_STOP;
}
}
} else {
md_obj_args[1] = val;
md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
md = grpc_rb_get_wrapped_metadata(md_obj);
err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
return ST_STOP;
}
}
return ST_CONTINUE;
}
/*
call-seq:
call.add_metadata(completion_queue, hash_elements, flags=nil)
Add metadata elements to the call from a ruby hash, to be sent upon
invocation. flags is a bit-field combination of the write flags defined
above.
REQUIRES: grpc_call_invoke/grpc_call_accept have not been
called on this call. Produces no events. */
static VALUE grpc_rb_call_add_metadata(int argc, VALUE *argv, VALUE self) {
VALUE metadata;
VALUE flags = Qnil;
ID id_size = rb_intern("size");
/* "11" == 1 mandatory args, 1 (flags) is optional */
rb_scan_args(argc, argv, "11", &metadata, &flags);
if (NIL_P(flags)) {
flags = UINT2NUM(0); /* Default to no flags */
}
if (TYPE(metadata) != T_HASH) {
rb_raise(rb_eTypeError, "add metadata failed: metadata should be a hash");
return Qnil;
}
if (NUM2UINT(rb_funcall(metadata, id_size, 0)) == 0) {
return Qnil;
}
rb_ivar_set(self, id_flags, flags);
rb_ivar_set(self, id_input_md, metadata);
rb_hash_foreach(metadata, grpc_rb_call_add_metadata_hash_cb, self);
return Qnil;
}
/* Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread. */
static VALUE grpc_rb_call_cancel(VALUE self) {
@ -215,65 +133,6 @@ static VALUE grpc_rb_call_cancel(VALUE self) {
return Qnil;
}
/*
call-seq:
call.invoke(completion_queue, tag, flags=nil)
Invoke the RPC. Starts sending metadata and request headers on the wire.
flags is a bit-field combination of the write flags defined above.
REQUIRES: Can be called at most once per call.
Can only be called on the client.
Produces a GRPC_INVOKE_ACCEPTED event on completion. */
static VALUE grpc_rb_call_invoke(int argc, VALUE *argv, VALUE self) {
VALUE cqueue = Qnil;
VALUE metadata_read_tag = Qnil;
VALUE finished_tag = Qnil;
VALUE flags = Qnil;
grpc_call *call = NULL;
grpc_completion_queue *cq = NULL;
grpc_call_error err;
/* "31" == 3 mandatory args, 1 (flags) is optional */
rb_scan_args(argc, argv, "31", &cqueue, &metadata_read_tag, &finished_tag,
&flags);
if (NIL_P(flags)) {
flags = UINT2NUM(0); /* Default to no flags */
}
cq = grpc_rb_get_wrapped_completion_queue(cqueue);
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_invoke_old(call, cq, ROBJECT(metadata_read_tag),
ROBJECT(finished_tag), NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "invoke failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
/* Add the completion queue as an instance attribute, prevents it from being
* GCed until this call object is GCed */
rb_ivar_set(self, id_cq, cqueue);
return Qnil;
}
/* Initiate a read on a call. Output event contains a byte buffer with the
result of the read.
REQUIRES: No other reads are pending on the call.
It is only safe to start the next read after the corresponding
read event is received. */
static VALUE grpc_rb_call_start_read(VALUE self, VALUE tag) {
grpc_call *call = NULL;
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_start_read_old(call, ROBJECT(tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "start read failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
return Qnil;
}
/*
call-seq:
status = call.status
@ -322,122 +181,6 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
return rb_ivar_set(self, id_metadata, metadata);
}
/*
call-seq:
call.start_write(byte_buffer, tag, flags=nil)
Queue a byte buffer for writing.
flags is a bit-field combination of the write flags defined above.
A write with byte_buffer null is allowed, and will not send any bytes on the
wire. If this is performed without GRPC_WRITE_BUFFER_HINT flag it provides
a mechanism to flush any previously buffered writes to outgoing flow control.
REQUIRES: No other writes are pending on the call. It is only safe to
start the next write after the corresponding write_accepted event
is received.
GRPC_INVOKE_ACCEPTED must have been received by the application
prior to calling this on the client. On the server,
grpc_call_accept must have been called successfully.
Produces a GRPC_WRITE_ACCEPTED event. */
static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) {
VALUE byte_buffer = Qnil;
VALUE tag = Qnil;
VALUE flags = Qnil;
grpc_call *call = NULL;
grpc_byte_buffer *bfr = NULL;
grpc_call_error err;
/* "21" == 2 mandatory args, 1 (flags) is optional */
rb_scan_args(argc, argv, "21", &byte_buffer, &tag, &flags);
if (NIL_P(flags)) {
flags = UINT2NUM(0); /* Default to no flags */
}
bfr = grpc_rb_get_wrapped_byte_buffer(byte_buffer);
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_start_write_old(call, bfr, ROBJECT(tag), NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "start write failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
return Qnil;
}
/* Queue a status for writing.
call-seq:
tag = Object.new
call.write_status(200, "OK", tag)
REQUIRES: No other writes are pending on the call. It is only safe to
start the next write after the corresponding write_accepted event
is received.
GRPC_INVOKE_ACCEPTED must have been received by the application
prior to calling this.
Only callable on the server.
Produces a GRPC_FINISHED event when the status is sent and the
stream is fully closed */
static VALUE grpc_rb_call_start_write_status(VALUE self, VALUE code,
VALUE status, VALUE tag) {
grpc_call *call = NULL;
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_start_write_status_old(call, NUM2UINT(code),
StringValueCStr(status), ROBJECT(tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "start write status: %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
return Qnil;
}
/* No more messages to send.
REQUIRES: No other writes are pending on the call. */
static VALUE grpc_rb_call_writes_done(VALUE self, VALUE tag) {
grpc_call *call = NULL;
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_writes_done_old(call, ROBJECT(tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "writes done: %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
return Qnil;
}
/* call-seq:
call.server_end_initial_metadata(flag)
Only to be called on servers, before sending messages.
flags is a bit-field combination of the write flags defined above.
REQUIRES: Can be called at most once per call.
Can only be called on the server, must be called after
grpc_call_server_accept
Produces no events */
static VALUE grpc_rb_call_server_end_initial_metadata(int argc, VALUE *argv,
VALUE self) {
VALUE flags = Qnil;
grpc_call *call = NULL;
grpc_call_error err;
/* "01" == 1 (flags) is optional */
rb_scan_args(argc, argv, "01", &flags);
if (NIL_P(flags)) {
flags = UINT2NUM(0); /* Default to no flags */
}
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_server_end_initial_metadata_old(call, NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "end_initial_metadata failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
return Qnil;
}
/* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used
to fill grpc_metadata_array.
@ -826,35 +569,6 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag,
return result;
}
/* call-seq:
call.server_accept(completion_queue, finished_tag)
Accept an incoming RPC, binding a completion queue to it.
To be called before sending or receiving messages.
REQUIRES: Can be called at most once per call.
Can only be called on the server.
Produces a GRPC_FINISHED event with finished_tag when the call has been
completed (there may be other events for the call pending at this
time) */
static VALUE grpc_rb_call_server_accept(VALUE self, VALUE cqueue,
VALUE finished_tag) {
grpc_call *call = NULL;
grpc_completion_queue *cq = grpc_rb_get_wrapped_completion_queue(cqueue);
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_server_accept_old(call, cq, ROBJECT(finished_tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "server_accept failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
/* Add the completion queue as an instance attribute, prevents it from being
* GCed until this call object is GCed */
rb_ivar_set(self, id_cq, cqueue);
return Qnil;
}
/* rb_cCall is the ruby class that proxies grpc_call. */
VALUE rb_cCall = Qnil;
@ -948,17 +662,7 @@ void Init_grpc_call() {
/* Add ruby analogues of the Call methods. */
rb_define_method(rb_cCall, "run_batch", grpc_rb_call_run_batch, 4);
rb_define_method(rb_cCall, "server_accept", grpc_rb_call_server_accept, 2);
rb_define_method(rb_cCall, "server_end_initial_metadata",
grpc_rb_call_server_end_initial_metadata, -1);
rb_define_method(rb_cCall, "add_metadata", grpc_rb_call_add_metadata, -1);
rb_define_method(rb_cCall, "cancel", grpc_rb_call_cancel, 0);
rb_define_method(rb_cCall, "invoke", grpc_rb_call_invoke, -1);
rb_define_method(rb_cCall, "start_read", grpc_rb_call_start_read, 1);
rb_define_method(rb_cCall, "start_write", grpc_rb_call_start_write, -1);
rb_define_method(rb_cCall, "start_write_status",
grpc_rb_call_start_write_status, 3);
rb_define_method(rb_cCall, "writes_done", grpc_rb_call_writes_done, 1);
rb_define_method(rb_cCall, "status", grpc_rb_call_get_status, 0);
rb_define_method(rb_cCall, "status=", grpc_rb_call_set_status, 1);
rb_define_method(rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);

@ -38,7 +38,6 @@
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#include "rb_grpc.h"
#include "rb_event.h"
/* Used to allow grpc_completion_queue_next call to release the GIL */
typedef struct next_call_stack {

@ -1,361 +0,0 @@
/*
*
* 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.
*
*/
#include "rb_event.h"
#include <ruby.h>
#include <grpc/grpc.h>
#include "rb_grpc.h"
#include "rb_byte_buffer.h"
#include "rb_call.h"
#include "rb_metadata.h"
/* grpc_rb_event wraps a grpc_event. It provides a peer ruby object,
* 'mark' to minimize copying when an event is created from ruby. */
typedef struct grpc_rb_event {
/* Holder of ruby objects involved in constructing the channel */
VALUE mark;
/* The actual event */
grpc_event *wrapped;
} grpc_rb_event;
/* rb_mCompletionType is a ruby module that holds the completion type values */
VALUE rb_mCompletionType = Qnil;
/* Destroys Event instances. */
static void grpc_rb_event_free(void *p) {
grpc_rb_event *ev = NULL;
if (p == NULL) {
return;
};
ev = (grpc_rb_event *)p;
/* Deletes the wrapped object if the mark object is Qnil, which indicates
* that no other object is the actual owner. */
if (ev->wrapped != NULL && ev->mark == Qnil) {
grpc_event_finish(ev->wrapped);
rb_warning("event gc: destroyed the c event");
} else {
rb_warning("event gc: did not destroy the c event");
}
xfree(p);
}
/* Protects the mark object from GC */
static void grpc_rb_event_mark(void *p) {
grpc_rb_event *event = NULL;
if (p == NULL) {
return;
}
event = (grpc_rb_event *)p;
if (event->mark != Qnil) {
rb_gc_mark(event->mark);
}
}
static VALUE grpc_rb_event_result(VALUE self);
/* Obtains the type of an event. */
static VALUE grpc_rb_event_type(VALUE self) {
grpc_event *event = NULL;
grpc_rb_event *wrapper = NULL;
Data_Get_Struct(self, grpc_rb_event, wrapper);
if (wrapper->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "finished!");
return Qnil;
}
event = wrapper->wrapped;
switch (event->type) {
case GRPC_QUEUE_SHUTDOWN:
return rb_const_get(rb_mCompletionType, rb_intern("QUEUE_SHUTDOWN"));
case GRPC_READ:
return rb_const_get(rb_mCompletionType, rb_intern("READ"));
case GRPC_WRITE_ACCEPTED:
grpc_rb_event_result(self); /* validates the result */
return rb_const_get(rb_mCompletionType, rb_intern("WRITE_ACCEPTED"));
case GRPC_FINISH_ACCEPTED:
grpc_rb_event_result(self); /* validates the result */
return rb_const_get(rb_mCompletionType, rb_intern("FINISH_ACCEPTED"));
case GRPC_CLIENT_METADATA_READ:
return rb_const_get(rb_mCompletionType,
rb_intern("CLIENT_METADATA_READ"));
case GRPC_FINISHED:
return rb_const_get(rb_mCompletionType, rb_intern("FINISHED"));
case GRPC_SERVER_RPC_NEW:
return rb_const_get(rb_mCompletionType, rb_intern("SERVER_RPC_NEW"));
default:
rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
event->type);
}
return Qnil; /* should not be reached */
}
/* Obtains the tag associated with an event. */
static VALUE grpc_rb_event_tag(VALUE self) {
grpc_event *event = NULL;
grpc_rb_event *wrapper = NULL;
Data_Get_Struct(self, grpc_rb_event, wrapper);
if (wrapper->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "finished!");
return Qnil;
}
event = wrapper->wrapped;
if (event->tag == NULL) {
return Qnil;
}
return (VALUE)event->tag;
}
/* Obtains the call associated with an event. */
static VALUE grpc_rb_event_call(VALUE self) {
grpc_event *event = NULL;
grpc_rb_event *wrapper = NULL;
Data_Get_Struct(self, grpc_rb_event, wrapper);
if (wrapper->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "finished!");
return Qnil;
}
event = wrapper->wrapped;
if (event->call != NULL) {
return grpc_rb_wrap_call(event->call);
}
return Qnil;
}
/* Obtains the metadata associated with an event. */
static VALUE grpc_rb_event_metadata(VALUE self) {
grpc_event *event = NULL;
grpc_rb_event *wrapper = NULL;
grpc_metadata *metadata = NULL;
VALUE key = Qnil;
VALUE new_ary = Qnil;
VALUE result = Qnil;
VALUE value = Qnil;
size_t count = 0;
size_t i = 0;
Data_Get_Struct(self, grpc_rb_event, wrapper);
if (wrapper->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "finished!");
return Qnil;
}
/* Figure out which metadata to read. */
event = wrapper->wrapped;
switch (event->type) {
case GRPC_CLIENT_METADATA_READ:
count = event->data.client_metadata_read.count;
metadata = event->data.client_metadata_read.elements;
break;
case GRPC_FINISHED:
count = event->data.finished.metadata_count;
metadata = event->data.finished.metadata_elements;
break;
case GRPC_SERVER_RPC_NEW:
count = event->data.server_rpc_new.metadata_count;
metadata = event->data.server_rpc_new.metadata_elements;
break;
default:
rb_raise(rb_eRuntimeError,
"bug: bad event type metadata. got %d; want %d|%d:%d",
event->type, GRPC_CLIENT_METADATA_READ, GRPC_FINISHED,
GRPC_SERVER_RPC_NEW);
return Qnil;
}
result = rb_hash_new();
for (i = 0; i < count; i++) {
key = rb_str_new2(metadata[i].key);
value = rb_hash_aref(result, key);
if (value == Qnil) {
value = rb_str_new(metadata[i].value, metadata[i].value_length);
rb_hash_aset(result, key, value);
} else if (TYPE(value) == T_ARRAY) {
/* Add the string to the returned array */
rb_ary_push(value,
rb_str_new(metadata[i].value, metadata[i].value_length));
} else {
/* Add the current value with this key and the new one to an array */
new_ary = rb_ary_new();
rb_ary_push(new_ary, value);
rb_ary_push(new_ary,
rb_str_new(metadata[i].value, metadata[i].value_length));
rb_hash_aset(result, key, new_ary);
}
}
return result;
}
/* Obtains the data associated with an event. */
static VALUE grpc_rb_event_result(VALUE self) {
grpc_event *event = NULL;
grpc_rb_event *wrapper = NULL;
Data_Get_Struct(self, grpc_rb_event, wrapper);
if (wrapper->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "finished!");
return Qnil;
}
event = wrapper->wrapped;
switch (event->type) {
case GRPC_QUEUE_SHUTDOWN:
return Qnil;
case GRPC_READ:
return grpc_rb_byte_buffer_create_with_mark(self, event->data.read);
case GRPC_FINISH_ACCEPTED:
if (event->data.finish_accepted == GRPC_OP_OK) {
return Qnil;
}
rb_raise(rb_eEventError, "finish failed, not sure why (code=%d)",
event->data.finish_accepted);
break;
case GRPC_WRITE_ACCEPTED:
if (event->data.write_accepted == GRPC_OP_OK) {
return Qnil;
}
rb_raise(rb_eEventError, "write failed, not sure why (code=%d)",
event->data.write_accepted);
break;
case GRPC_CLIENT_METADATA_READ:
return grpc_rb_event_metadata(self);
case GRPC_FINISHED:
return rb_struct_new(rb_sStatus, UINT2NUM(event->data.finished.status),
(event->data.finished.details == NULL
? Qnil
: rb_str_new2(event->data.finished.details)),
grpc_rb_event_metadata(self), NULL);
break;
case GRPC_SERVER_RPC_NEW:
return rb_struct_new(
rb_sNewServerRpc, rb_str_new2(event->data.server_rpc_new.method),
rb_str_new2(event->data.server_rpc_new.host),
Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
(void *)&event->data.server_rpc_new.deadline),
grpc_rb_event_metadata(self), NULL);
default:
rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
event->type);
}
return Qfalse;
}
static VALUE grpc_rb_event_finish(VALUE self) {
grpc_event *event = NULL;
grpc_rb_event *wrapper = NULL;
Data_Get_Struct(self, grpc_rb_event, wrapper);
if (wrapper->wrapped == NULL) { /* already closed */
return Qnil;
}
event = wrapper->wrapped;
grpc_event_finish(event);
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
return Qnil;
}
/* rb_cEvent is the Event class whose instances proxy grpc_event */
VALUE rb_cEvent = Qnil;
/* rb_eEventError is the ruby class of the exception thrown on failures during
rpc event processing. */
VALUE rb_eEventError = Qnil;
void Init_grpc_event() {
rb_eEventError =
rb_define_class_under(rb_mGrpcCore, "EventError", rb_eStandardError);
rb_cEvent = rb_define_class_under(rb_mGrpcCore, "Event", rb_cObject);
/* Prevent allocation or inialization from ruby. */
rb_define_alloc_func(rb_cEvent, grpc_rb_cannot_alloc);
rb_define_method(rb_cEvent, "initialize", grpc_rb_cannot_init, 0);
rb_define_method(rb_cEvent, "initialize_copy", grpc_rb_cannot_init_copy, 1);
/* Accessors for the data available in an event. */
rb_define_method(rb_cEvent, "call", grpc_rb_event_call, 0);
rb_define_method(rb_cEvent, "result", grpc_rb_event_result, 0);
rb_define_method(rb_cEvent, "tag", grpc_rb_event_tag, 0);
rb_define_method(rb_cEvent, "type", grpc_rb_event_type, 0);
rb_define_method(rb_cEvent, "finish", grpc_rb_event_finish, 0);
rb_define_alias(rb_cEvent, "close", "finish");
/* Constants representing the completion types */
rb_mCompletionType =
rb_define_module_under(rb_mGrpcCore, "CompletionType");
rb_define_const(rb_mCompletionType, "QUEUE_SHUTDOWN",
INT2NUM(GRPC_QUEUE_SHUTDOWN));
rb_define_const(rb_mCompletionType, "OP_COMPLETE", INT2NUM(GRPC_OP_COMPLETE));
rb_define_const(rb_mCompletionType, "READ", INT2NUM(GRPC_READ));
rb_define_const(rb_mCompletionType, "WRITE_ACCEPTED",
INT2NUM(GRPC_WRITE_ACCEPTED));
rb_define_const(rb_mCompletionType, "FINISH_ACCEPTED",
INT2NUM(GRPC_FINISH_ACCEPTED));
rb_define_const(rb_mCompletionType, "CLIENT_METADATA_READ",
INT2NUM(GRPC_CLIENT_METADATA_READ));
rb_define_const(rb_mCompletionType, "FINISHED", INT2NUM(GRPC_FINISHED));
rb_define_const(rb_mCompletionType, "SERVER_RPC_NEW",
INT2NUM(GRPC_SERVER_RPC_NEW));
rb_define_const(rb_mCompletionType, "SERVER_SHUTDOWN",
INT2NUM(GRPC_SERVER_SHUTDOWN));
rb_define_const(rb_mCompletionType, "RESERVED",
INT2NUM(GRPC_COMPLETION_DO_NOT_USE));
}
VALUE grpc_rb_new_event(grpc_event *ev) {
grpc_rb_event *wrapper = ALLOC(grpc_rb_event);
wrapper->wrapped = ev;
wrapper->mark = Qnil;
return Data_Wrap_Struct(rb_cEvent, grpc_rb_event_mark, grpc_rb_event_free,
wrapper);
}

@ -1,53 +0,0 @@
/*
*
* 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.
*
*/
#ifndef GRPC_RB_EVENT_H_
#define GRPC_RB_EVENT_H_
#include <ruby.h>
#include <grpc/grpc.h>
/* rb_cEvent is the Event class whose instances proxy grpc_event. */
extern VALUE rb_cEvent;
/* rb_cEventError is the ruby class that acts the exception thrown during rpc
event processing. */
extern VALUE rb_eEventError;
/* Used to create new ruby event objects */
VALUE grpc_rb_new_event(grpc_event *ev);
/* Initializes the Event and EventError classes. */
void Init_grpc_event();
#endif /* GRPC_RB_EVENT_H_ */

@ -39,12 +39,9 @@
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#include "rb_byte_buffer.h"
#include "rb_call.h"
#include "rb_channel.h"
#include "rb_completion_queue.h"
#include "rb_event.h"
#include "rb_metadata.h"
#include "rb_server.h"
#include "rb_credentials.h"
#include "rb_server_credentials.h"
@ -263,13 +260,10 @@ void Init_grpc() {
sym_details = ID2SYM(rb_intern("details"));
sym_metadata = ID2SYM(rb_intern("metadata"));
Init_grpc_byte_buffer();
Init_grpc_event();
Init_grpc_channel();
Init_grpc_completion_queue();
Init_grpc_call();
Init_grpc_credentials();
Init_grpc_metadata();
Init_grpc_server();
Init_grpc_server_credentials();
Init_grpc_status_codes();

@ -1,215 +0,0 @@
/*
*
* 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.
*
*/
#include "rb_metadata.h"
#include <ruby.h>
#include <string.h>
#include <grpc/grpc.h>
#include "rb_grpc.h"
/* grpc_rb_metadata wraps a grpc_metadata. It provides a peer ruby object,
* 'mark' to minimize copying when a metadata is created from ruby. */
typedef struct grpc_rb_metadata {
/* Holder of ruby objects involved in constructing the metadata */
VALUE mark;
/* The actual metadata */
grpc_metadata *wrapped;
} grpc_rb_metadata;
/* Destroys Metadata instances. */
static void grpc_rb_metadata_free(void *p) {
if (p == NULL) {
return;
};
/* Because metadata is only created during a call to grpc_call_add_metadata,
* and the call takes ownership of the metadata, this does not free the
* wrapped struct, only the wrapper */
xfree(p);
}
/* Protects the mark object from GC */
static void grpc_rb_metadata_mark(void *p) {
grpc_rb_metadata *md = NULL;
if (p == NULL) {
return;
}
md = (grpc_rb_metadata *)p;
/* If it's not already cleaned up, mark the mark object */
if (md->mark != Qnil && BUILTIN_TYPE(md->mark) != T_NONE) {
rb_gc_mark(md->mark);
}
}
/* Allocates Metadata instances.
Provides safe default values for the Metadata fields. */
static VALUE grpc_rb_metadata_alloc(VALUE cls) {
grpc_rb_metadata *wrapper = ALLOC(grpc_rb_metadata);
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
return Data_Wrap_Struct(cls, grpc_rb_metadata_mark, grpc_rb_metadata_free,
wrapper);
}
/* id_key and id_value are the names of the hidden ivars that preserve the
* original byte_buffer source string */
static ID id_key;
static ID id_value;
/* Initializes Metadata instances. */
static VALUE grpc_rb_metadata_init(VALUE self, VALUE key, VALUE value) {
grpc_rb_metadata *wrapper = NULL;
grpc_metadata *md = ALLOC(grpc_metadata);
/* Use direct pointers to the strings wrapped by the ruby object to avoid
* copying */
Data_Get_Struct(self, grpc_rb_metadata, wrapper);
wrapper->wrapped = md;
if (TYPE(key) == T_SYMBOL) {
md->key = (char *)rb_id2name(SYM2ID(key));
} else { /* StringValueCStr does all other type exclusions for us */
md->key = StringValueCStr(key);
}
md->value = RSTRING_PTR(value);
md->value_length = RSTRING_LEN(value);
/* Save references to the original values on the mark object so that the
* pointers used there are valid for the lifetime of the object. */
wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
rb_ivar_set(wrapper->mark, id_key, key);
rb_ivar_set(wrapper->mark, id_value, value);
return self;
}
/* Clones Metadata instances.
Gives Metadata a consistent implementation of Ruby's object copy/dup
protocol. */
static VALUE grpc_rb_metadata_init_copy(VALUE copy, VALUE orig) {
grpc_rb_metadata *orig_md = NULL;
grpc_rb_metadata *copy_md = NULL;
if (copy == orig) {
return copy;
}
/* Raise an error if orig is not a metadata object or a subclass. */
if (TYPE(orig) != T_DATA ||
RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_metadata_free) {
rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cMetadata));
}
Data_Get_Struct(orig, grpc_rb_metadata, orig_md);
Data_Get_Struct(copy, grpc_rb_metadata, copy_md);
/* use ruby's MEMCPY to make a byte-for-byte copy of the metadata wrapper
* object. */
MEMCPY(copy_md, orig_md, grpc_rb_metadata, 1);
return copy;
}
/* Gets the key from a metadata instance. */
static VALUE grpc_rb_metadata_key(VALUE self) {
VALUE key = Qnil;
grpc_rb_metadata *wrapper = NULL;
grpc_metadata *md = NULL;
Data_Get_Struct(self, grpc_rb_metadata, wrapper);
if (wrapper->mark != Qnil) {
key = rb_ivar_get(wrapper->mark, id_key);
if (key != Qnil) {
return key;
}
}
md = wrapper->wrapped;
if (md == NULL || md->key == NULL) {
return Qnil;
}
return rb_str_new2(md->key);
}
/* Gets the value from a metadata instance. */
static VALUE grpc_rb_metadata_value(VALUE self) {
VALUE val = Qnil;
grpc_rb_metadata *wrapper = NULL;
grpc_metadata *md = NULL;
Data_Get_Struct(self, grpc_rb_metadata, wrapper);
if (wrapper->mark != Qnil) {
val = rb_ivar_get(wrapper->mark, id_value);
if (val != Qnil) {
return val;
}
}
md = wrapper->wrapped;
if (md == NULL || md->value == NULL) {
return Qnil;
}
return rb_str_new2(md->value);
}
/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */
VALUE rb_cMetadata = Qnil;
void Init_grpc_metadata() {
rb_cMetadata =
rb_define_class_under(rb_mGrpcCore, "Metadata", rb_cObject);
/* Allocates an object managed by the ruby runtime */
rb_define_alloc_func(rb_cMetadata, grpc_rb_metadata_alloc);
/* Provides a ruby constructor and support for dup/clone. */
rb_define_method(rb_cMetadata, "initialize", grpc_rb_metadata_init, 2);
rb_define_method(rb_cMetadata, "initialize_copy", grpc_rb_metadata_init_copy,
1);
/* Provides accessors for the code and details. */
rb_define_method(rb_cMetadata, "key", grpc_rb_metadata_key, 0);
rb_define_method(rb_cMetadata, "value", grpc_rb_metadata_value, 0);
id_key = rb_intern("__key");
id_value = rb_intern("__value");
}
/* Gets the wrapped metadata from the ruby wrapper */
grpc_metadata *grpc_rb_get_wrapped_metadata(VALUE v) {
grpc_rb_metadata *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_metadata, wrapper);
return wrapper->wrapped;
}

@ -1,53 +0,0 @@
/*
*
* 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.
*
*/
#ifndef GRPC_RB_METADATA_H_
#define GRPC_RB_METADATA_H_
#include <grpc/grpc.h>
#include <ruby.h>
/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */
extern VALUE rb_cMetadata;
/* grpc_rb_metadata_create_with_mark creates a grpc_rb_metadata with a ruby mark
* object that will be kept alive while the metadata is alive. */
extern VALUE grpc_rb_metadata_create_with_mark(VALUE mark, grpc_metadata* md);
/* Gets the wrapped metadata from the ruby wrapper */
grpc_metadata* grpc_rb_get_wrapped_metadata(VALUE v);
/* Initializes the Metadata class. */
void Init_grpc_metadata();
#endif /* GRPC_RB_METADATA_H_ */
Loading…
Cancel
Save