Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LANGUAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ Thrift's core protocol is TBinary, supported by all languages except for JavaScr
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>2.7.8</td><td>4.0.0</td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
Expand Down
5 changes: 5 additions & 0 deletions compiler/cpp/src/thrift/generate/t_rb_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,9 @@ t_rb_ofstream& t_rb_generator::render_const_value(t_rb_ofstream& out,
case t_base_type::TYPE_STRING:
out << "%q\"" << get_escaped_string(value) << '"';
break;
case t_base_type::TYPE_UUID:
out << "%q\"" << get_escaped_string(value) << '"';
break;
case t_base_type::TYPE_BOOL:
out << (value->get_integer() > 0 ? "true" : "false");
break;
Expand Down Expand Up @@ -1175,6 +1178,8 @@ string t_rb_generator::type_to_enum(t_type* type) {
return "::Thrift::Types::I64";
case t_base_type::TYPE_DOUBLE:
return "::Thrift::Types::DOUBLE";
case t_base_type::TYPE_UUID:
return "::Thrift::Types::UUID";
default:
throw "compiler error: unhandled type";
}
Expand Down
4 changes: 2 additions & 2 deletions lib/rb/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ namespace :'gen-rb' do
dir = File.dirname(__FILE__) + '/benchmark'
sh THRIFT, '--gen', 'rb', '-o', dir, "#{dir}/Benchmark.thrift"
end

task :'debug_proto' do
sh "mkdir", "-p", "test/debug_proto"
sh THRIFT, '--gen', 'rb', "-o", "test/debug_proto", "../../test/v0.16/DebugProtoTest.thrift"
sh THRIFT, '--gen', 'rb', "-o", "test/debug_proto", "../../test/DebugProtoTest.thrift"
end
end

Expand Down
77 changes: 67 additions & 10 deletions lib/rb/ext/binary_protocol_accelerated.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
#include <ruby.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <constants.h>
#include <struct.h>
#include <macros.h>
#include <bytes.h>
#include <protocol.h>

VALUE rb_thrift_binary_proto_native_qmark(VALUE self) {
return Qtrue;
Expand All @@ -34,7 +36,6 @@ VALUE rb_thrift_binary_proto_native_qmark(VALUE self) {
static int VERSION_1;
static int VERSION_MASK;
static int TYPE_MASK;
static int BAD_VERSION;
static ID rbuf_ivar_id;

static void write_byte_direct(VALUE trans, int8_t b) {
Expand Down Expand Up @@ -228,6 +229,46 @@ VALUE rb_thrift_binary_proto_write_binary(VALUE self, VALUE buf) {
return Qnil;
}

VALUE rb_thrift_binary_proto_write_uuid(VALUE self, VALUE uuid) {
if (NIL_P(uuid) || TYPE(uuid) != T_STRING) {
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("UUID must be a string")));
}

VALUE trans = GET_TRANSPORT(self);
char bytes[16];
const char* str = RSTRING_PTR(uuid);
long len = RSTRING_LEN(uuid);

// Parse UUID string (format: "550e8400-e29b-41d4-a716-446655440000")
// Expected length: 36 characters (32 hex + 4 hyphens)
if (len != 36 || str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-') {
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("Invalid UUID format")));
}

// Parse hex string to bytes using direct conversion, skipping hyphens
int byte_idx = 0;
for (int i = 0; i < len && byte_idx < 16; i++) {
if (str[i] == '-') continue;
if (i + 1 >= len || str[i + 1] == '-') break;

// Convert two hex characters to one byte
int high = hex_char_to_int(str[i]);
int low = hex_char_to_int(str[i + 1]);

if (high < 0 || low < 0) break;

bytes[byte_idx++] = (unsigned char)((high << 4) | low);
i++; // skip next char since we processed two
}

if (byte_idx != 16) {
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("Invalid UUID format")));
}

WRITE(trans, bytes, 16);
return Qnil;
}

//---------------------------------------
// interface reading methods
//---------------------------------------
Expand Down Expand Up @@ -272,13 +313,6 @@ static int64_t read_i64_direct(VALUE self) {
return (hi << 32) | lo;
}

static VALUE get_protocol_exception(VALUE code, VALUE message) {
VALUE args[2];
args[0] = code;
args[1] = message;
return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class);
}

VALUE rb_thrift_binary_proto_read_message_end(VALUE self) {
return Qnil;
}
Expand Down Expand Up @@ -316,14 +350,14 @@ VALUE rb_thrift_binary_proto_read_message_begin(VALUE self) {

if (version < 0) {
if ((version & VERSION_MASK) != VERSION_1) {
rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("Missing version identifier")));
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_BAD_VERSION), rb_str_new2("Missing version identifier")));
}
type = version & TYPE_MASK;
name = rb_thrift_binary_proto_read_string(self);
seqid = rb_thrift_binary_proto_read_i32(self);
} else {
if (strict_read == Qtrue) {
rb_exc_raise(get_protocol_exception(INT2FIX(BAD_VERSION), rb_str_new2("No version identifier, old protocol client?")));
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_BAD_VERSION), rb_str_new2("No version identifier, old protocol client?")));
}
name = READ(self, version);
type = read_byte_direct(self);
Expand Down Expand Up @@ -400,6 +434,27 @@ VALUE rb_thrift_binary_proto_read_binary(VALUE self) {
return READ(self, size);
}

VALUE rb_thrift_binary_proto_read_uuid(VALUE self) {
VALUE data = READ(self, 16);
const unsigned char* bytes = (const unsigned char*)RSTRING_PTR(data);

// Format as UUID string: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
char uuid_str[37];
char* p = uuid_str;

for (int i = 0; i < 16; i++) {
*p++ = int_to_hex_char((bytes[i] >> 4) & 0x0F);
*p++ = int_to_hex_char(bytes[i] & 0x0F);
if (i == 3 || i == 5 || i == 7 || i == 9) {
*p++ = '-';
}
}

*p = '\0';

return rb_str_new(uuid_str, 36);
}

void Init_binary_protocol_accelerated(void) {
VALUE thrift_binary_protocol_class = rb_const_get(thrift_module, rb_intern("BinaryProtocol"));

Expand All @@ -425,6 +480,7 @@ void Init_binary_protocol_accelerated(void) {
rb_define_method(bpa_class, "write_double", rb_thrift_binary_proto_write_double, 1);
rb_define_method(bpa_class, "write_string", rb_thrift_binary_proto_write_string, 1);
rb_define_method(bpa_class, "write_binary", rb_thrift_binary_proto_write_binary, 1);
rb_define_method(bpa_class, "write_uuid", rb_thrift_binary_proto_write_uuid, 1);
// unused methods
rb_define_method(bpa_class, "write_message_end", rb_thrift_binary_proto_write_message_end, 0);
rb_define_method(bpa_class, "write_struct_begin", rb_thrift_binary_proto_write_struct_begin, 1);
Expand All @@ -447,6 +503,7 @@ void Init_binary_protocol_accelerated(void) {
rb_define_method(bpa_class, "read_double", rb_thrift_binary_proto_read_double, 0);
rb_define_method(bpa_class, "read_string", rb_thrift_binary_proto_read_string, 0);
rb_define_method(bpa_class, "read_binary", rb_thrift_binary_proto_read_binary, 0);
rb_define_method(bpa_class, "read_uuid", rb_thrift_binary_proto_read_uuid, 0);
// unused methods
rb_define_method(bpa_class, "read_message_end", rb_thrift_binary_proto_read_message_end, 0);
rb_define_method(bpa_class, "read_struct_begin", rb_thrift_binary_proto_read_struct_begin, 0);
Expand Down
79 changes: 72 additions & 7 deletions lib/rb/ext/compact_protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
#include <ruby.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <constants.h>
#include <struct.h>
#include <macros.h>
#include <bytes.h>
#include <protocol.h>

#define LAST_ID(obj) FIX2INT(rb_ary_pop(rb_ivar_get(obj, last_field_id)))
#define SET_LAST_ID(obj, val) rb_ary_push(rb_ivar_get(obj, last_field_id), val)
Expand Down Expand Up @@ -58,6 +60,7 @@ static int CTYPE_LIST = 0x09;
static int CTYPE_SET = 0x0A;
static int CTYPE_MAP = 0x0B;
static int CTYPE_STRUCT = 0x0C;
static int CTYPE_UUID = 0x0D;

VALUE rb_thrift_compact_proto_write_i16(VALUE self, VALUE i16);

Expand Down Expand Up @@ -86,6 +89,8 @@ static int get_compact_type(VALUE type_value) {
return CTYPE_MAP;
} else if (type == TTYPE_STRUCT) {
return CTYPE_STRUCT;
} else if (type == TTYPE_UUID) {
return CTYPE_UUID;
} else {
char str[50];
sprintf(str, "don't know what type: %d", type);
Expand Down Expand Up @@ -169,6 +174,7 @@ static void write_collection_begin(VALUE transport, VALUE elem_type, VALUE size_
VALUE rb_thrift_compact_proto_write_i32(VALUE self, VALUE i32);
VALUE rb_thrift_compact_proto_write_string(VALUE self, VALUE str);
VALUE rb_thrift_compact_proto_write_binary(VALUE self, VALUE buf);
VALUE rb_thrift_compact_proto_write_uuid(VALUE self, VALUE uuid);

VALUE rb_thrift_compact_proto_write_message_end(VALUE self) {
return Qnil;
Expand Down Expand Up @@ -320,6 +326,46 @@ VALUE rb_thrift_compact_proto_write_binary(VALUE self, VALUE buf) {
return Qnil;
}

VALUE rb_thrift_compact_proto_write_uuid(VALUE self, VALUE uuid) {
if (NIL_P(uuid) || TYPE(uuid) != T_STRING) {
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("UUID must be a string")));
}

VALUE transport = GET_TRANSPORT(self);
char bytes[16];
const char* str = RSTRING_PTR(uuid);
long len = RSTRING_LEN(uuid);

// Parse UUID string (format: "550e8400-e29b-41d4-a716-446655440000")
// Expected length: 36 characters (32 hex + 4 hyphens)
if (len != 36 || str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-') {
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("Invalid UUID format")));
}

// Parse hex string to bytes using direct conversion, skipping hyphens
int byte_idx = 0;
for (int i = 0; i < len && byte_idx < 16; i++) {
if (str[i] == '-') continue;
if (i + 1 >= len || str[i + 1] == '-') break;

// Convert two hex characters to one byte
int high = hex_char_to_int(str[i]);
int low = hex_char_to_int(str[i + 1]);

if (high < 0 || low < 0) break;

bytes[byte_idx++] = (unsigned char)((high << 4) | low);
i++; // skip next char since we processed two
}

if (byte_idx != 16) {
rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_INVALID_DATA), rb_str_new2("Invalid UUID format")));
}

WRITE(transport, bytes, 16);
return Qnil;
}

//---------------------------------------
// interface reading methods
//---------------------------------------
Expand All @@ -331,6 +377,7 @@ VALUE rb_thrift_compact_proto_read_binary(VALUE self);
VALUE rb_thrift_compact_proto_read_byte(VALUE self);
VALUE rb_thrift_compact_proto_read_i32(VALUE self);
VALUE rb_thrift_compact_proto_read_i16(VALUE self);
VALUE rb_thrift_compact_proto_read_uuid(VALUE self);

static int8_t get_ttype(int8_t ctype) {
if (ctype == TTYPE_STOP) {
Expand All @@ -357,6 +404,8 @@ static int8_t get_ttype(int8_t ctype) {
return TTYPE_MAP;
} else if (ctype == CTYPE_STRUCT) {
return TTYPE_STRUCT;
} else if (ctype == CTYPE_UUID) {
return TTYPE_UUID;
} else {
char str[50];
sprintf(str, "don't know what type: %d", ctype);
Expand Down Expand Up @@ -396,13 +445,6 @@ static int16_t read_i16(VALUE self) {
return zig_zag_to_int((int32_t)read_varint64(self));
}

static VALUE get_protocol_exception(VALUE code, VALUE message) {
VALUE args[2];
args[0] = code;
args[1] = message;
return rb_class_new_instance(2, (VALUE*)&args, protocol_exception_class);
}

VALUE rb_thrift_compact_proto_read_message_end(VALUE self) {
return Qnil;
}
Expand Down Expand Up @@ -565,6 +607,27 @@ VALUE rb_thrift_compact_proto_read_binary(VALUE self) {
return READ(self, size);
}

VALUE rb_thrift_compact_proto_read_uuid(VALUE self) {
VALUE data = READ(self, 16);
const unsigned char* bytes = (const unsigned char*)RSTRING_PTR(data);

// Format as UUID string: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
char uuid_str[37];
char* p = uuid_str;

for (int i = 0; i < 16; i++) {
*p++ = int_to_hex_char((bytes[i] >> 4) & 0x0F);
*p++ = int_to_hex_char(bytes[i] & 0x0F);
if (i == 3 || i == 5 || i == 7 || i == 9) {
*p++ = '-';
}
}

*p = '\0';

return rb_str_new(uuid_str, 36);
}

static void Init_constants(void) {
thrift_compact_protocol_class = rb_const_get(thrift_module, rb_intern("CompactProtocol"));
rb_global_variable(&thrift_compact_protocol_class);
Expand Down Expand Up @@ -599,6 +662,7 @@ static void Init_rb_methods(void) {
rb_define_method(thrift_compact_protocol_class, "write_double", rb_thrift_compact_proto_write_double, 1);
rb_define_method(thrift_compact_protocol_class, "write_string", rb_thrift_compact_proto_write_string, 1);
rb_define_method(thrift_compact_protocol_class, "write_binary", rb_thrift_compact_proto_write_binary, 1);
rb_define_method(thrift_compact_protocol_class, "write_uuid", rb_thrift_compact_proto_write_uuid, 1);

rb_define_method(thrift_compact_protocol_class, "write_message_end", rb_thrift_compact_proto_write_message_end, 0);
rb_define_method(thrift_compact_protocol_class, "write_struct_begin", rb_thrift_compact_proto_write_struct_begin, 1);
Expand All @@ -622,6 +686,7 @@ static void Init_rb_methods(void) {
rb_define_method(thrift_compact_protocol_class, "read_double", rb_thrift_compact_proto_read_double, 0);
rb_define_method(thrift_compact_protocol_class, "read_string", rb_thrift_compact_proto_read_string, 0);
rb_define_method(thrift_compact_protocol_class, "read_binary", rb_thrift_compact_proto_read_binary, 0);
rb_define_method(thrift_compact_protocol_class, "read_uuid", rb_thrift_compact_proto_read_uuid, 0);

rb_define_method(thrift_compact_protocol_class, "read_message_end", rb_thrift_compact_proto_read_message_end, 0);
rb_define_method(thrift_compact_protocol_class, "read_struct_begin", rb_thrift_compact_proto_read_struct_begin, 0);
Expand Down
12 changes: 12 additions & 0 deletions lib/rb/ext/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ extern int TTYPE_MAP;
extern int TTYPE_SET;
extern int TTYPE_LIST;
extern int TTYPE_STRUCT;
extern int TTYPE_UUID;

extern ID validate_method_id;
extern ID write_struct_begin_method_id;
Expand All @@ -49,6 +50,7 @@ extern ID write_list_begin_method_id;
extern ID write_list_end_method_id;
extern ID write_set_begin_method_id;
extern ID write_set_end_method_id;
extern ID write_uuid_method_id;
extern ID read_bool_method_id;
extern ID read_byte_method_id;
extern ID read_i16_method_id;
Expand All @@ -63,6 +65,7 @@ extern ID read_list_begin_method_id;
extern ID read_list_end_method_id;
extern ID read_set_begin_method_id;
extern ID read_set_end_method_id;
extern ID read_uuid_method_id;
extern ID read_struct_begin_method_id;
extern ID read_struct_end_method_id;
extern ID read_field_begin_method_id;
Expand Down Expand Up @@ -97,3 +100,12 @@ extern VALUE thrift_types_module;
extern VALUE thrift_bytes_module;
extern VALUE class_thrift_protocol;
extern VALUE protocol_exception_class;

// protocol errors
extern int PROTOERR_UNKNOWN;
extern int PROTOERR_INVALID_DATA;
extern int PROTOERR_NEGATIVE_SIZE;
extern int PROTOERR_SIZE_LIMIT;
extern int PROTOERR_BAD_VERSION;
extern int PROTOERR_NOT_IMPLEMENTED;
extern int PROTOERR_DEPTH_LIMIT;
Loading
Loading