2020#include <ruby.h>
2121#include <stdbool.h>
2222#include <stdint.h>
23+ #include <string.h>
2324#include <constants.h>
2425#include <struct.h>
2526#include <macros.h>
@@ -86,6 +87,19 @@ static void write_string_direct(VALUE trans, VALUE str) {
8687 rb_funcall (trans , write_method_id , 1 , str );
8788}
8889
90+ // Efficient hex character to integer conversion
91+ static inline int hex_char_to_int (char c ) {
92+ if (c >= '0' && c <= '9' ) return c - '0' ;
93+ if (c >= 'a' && c <= 'f' ) return c - 'a' + 10 ;
94+ if (c >= 'A' && c <= 'F' ) return c - 'A' + 10 ;
95+ return -1 ; // invalid hex character
96+ }
97+
98+ // Efficient integer to hex character conversion
99+ static inline char int_to_hex_char (int val ) {
100+ return val < 10 ? ('0' + val ) : ('a' + val - 10 );
101+ }
102+
89103//--------------------------------
90104// interface writing methods
91105//--------------------------------
@@ -228,6 +242,58 @@ VALUE rb_thrift_binary_proto_write_binary(VALUE self, VALUE buf) {
228242 return Qnil ;
229243}
230244
245+ VALUE rb_thrift_binary_proto_write_uuid (VALUE self , VALUE uuid ) {
246+ CHECK_NIL (uuid );
247+
248+ if (TYPE (uuid ) != T_STRING ) {
249+ rb_raise (rb_eStandardError , "UUID must be a string" );
250+ }
251+
252+ VALUE trans = GET_TRANSPORT (self );
253+ char bytes [16 ];
254+ const char * str = RSTRING_PTR (uuid );
255+ long len = RSTRING_LEN (uuid );
256+
257+ // Parse UUID string (format: "550e8400-e29b-41d4-a716-446655440000")
258+ // Expected length: 36 characters (32 hex + 4 hyphens)
259+ if (len != 36 || str [8 ] != '-' || str [13 ] != '-' || str [18 ] != '-' || str [23 ] != '-' ) {
260+ VALUE exception_class = rb_const_get (thrift_module , rb_intern ("ProtocolException" ));
261+ VALUE invalid_data = rb_const_get (exception_class , rb_intern ("INVALID_DATA" ));
262+ VALUE args [2 ];
263+ args [0 ] = invalid_data ;
264+ args [1 ] = rb_str_new2 ("Invalid UUID format" );
265+ rb_exc_raise (rb_class_new_instance (2 , args , exception_class ));
266+ }
267+
268+ // Parse hex string to bytes using direct conversion, skipping hyphens
269+ int byte_idx = 0 ;
270+ for (int i = 0 ; i < len && byte_idx < 16 ; i ++ ) {
271+ if (str [i ] == '-' ) continue ;
272+
273+ // Convert two hex characters to one byte
274+ int high = hex_char_to_int (str [i ]);
275+ int low = hex_char_to_int (str [i + 1 ]);
276+
277+ if (high < 0 || low < 0 ) {
278+ VALUE exception_class = rb_const_get (thrift_module , rb_intern ("ProtocolException" ));
279+ VALUE invalid_data = rb_const_get (exception_class , rb_intern ("INVALID_DATA" ));
280+ VALUE args [2 ];
281+ args [0 ] = invalid_data ;
282+ args [1 ] = rb_str_new2 ("Invalid hex character in UUID" );
283+ rb_exc_raise (rb_class_new_instance (2 , args , exception_class ));
284+ }
285+
286+ bytes [byte_idx ++ ] = (unsigned char )((high << 4 ) | low );
287+ i ++ ; // skip next char since we processed two
288+ }
289+
290+ // Write LSB first (bytes 8-15), then MSB (bytes 0-7)
291+ WRITE (trans , (char * )& bytes [8 ], 8 );
292+ WRITE (trans , (char * )& bytes [0 ], 8 );
293+
294+ return Qnil ;
295+ }
296+
231297//---------------------------------------
232298// interface reading methods
233299//---------------------------------------
@@ -400,6 +466,40 @@ VALUE rb_thrift_binary_proto_read_binary(VALUE self) {
400466 return READ (self , size );
401467}
402468
469+ VALUE rb_thrift_binary_proto_read_uuid (VALUE self ) {
470+ // Read 16 bytes directly into a single buffer: LSB (8 bytes) then MSB (8 bytes)
471+ unsigned char bytes [16 ];
472+ VALUE data = READ (self , 16 );
473+ memcpy (bytes , RSTRING_PTR (data ), 16 );
474+
475+ // Format as UUID string: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
476+ // MSB first (bytes 8-15), then LSB (bytes 0-7)
477+ char uuid_str [37 ];
478+ char * p = uuid_str ;
479+
480+ // Format MSB (bytes 8-15)
481+ for (int i = 8 ; i < 16 ; i ++ ) {
482+ * p ++ = int_to_hex_char ((bytes [i ] >> 4 ) & 0x0F );
483+ * p ++ = int_to_hex_char (bytes [i ] & 0x0F );
484+ if (i == 11 || i == 13 || i == 15 ) {
485+ * p ++ = '-' ;
486+ }
487+ }
488+
489+ // Format LSB (bytes 0-7)
490+ for (int i = 0 ; i < 8 ; i ++ ) {
491+ * p ++ = int_to_hex_char ((bytes [i ] >> 4 ) & 0x0F );
492+ * p ++ = int_to_hex_char (bytes [i ] & 0x0F );
493+ if (i == 1 ) {
494+ * p ++ = '-' ;
495+ }
496+ }
497+
498+ * p = '\0' ;
499+
500+ return rb_str_new (uuid_str , 36 );
501+ }
502+
403503void Init_binary_protocol_accelerated () {
404504 VALUE thrift_binary_protocol_class = rb_const_get (thrift_module , rb_intern ("BinaryProtocol" ));
405505
@@ -425,6 +525,7 @@ void Init_binary_protocol_accelerated() {
425525 rb_define_method (bpa_class , "write_double" , rb_thrift_binary_proto_write_double , 1 );
426526 rb_define_method (bpa_class , "write_string" , rb_thrift_binary_proto_write_string , 1 );
427527 rb_define_method (bpa_class , "write_binary" , rb_thrift_binary_proto_write_binary , 1 );
528+ rb_define_method (bpa_class , "write_uuid" , rb_thrift_binary_proto_write_uuid , 1 );
428529 // unused methods
429530 rb_define_method (bpa_class , "write_message_end" , rb_thrift_binary_proto_write_message_end , 0 );
430531 rb_define_method (bpa_class , "write_struct_begin" , rb_thrift_binary_proto_write_struct_begin , 1 );
@@ -447,6 +548,7 @@ void Init_binary_protocol_accelerated() {
447548 rb_define_method (bpa_class , "read_double" , rb_thrift_binary_proto_read_double , 0 );
448549 rb_define_method (bpa_class , "read_string" , rb_thrift_binary_proto_read_string , 0 );
449550 rb_define_method (bpa_class , "read_binary" , rb_thrift_binary_proto_read_binary , 0 );
551+ rb_define_method (bpa_class , "read_uuid" , rb_thrift_binary_proto_read_uuid , 0 );
450552 // unused methods
451553 rb_define_method (bpa_class , "read_message_end" , rb_thrift_binary_proto_read_message_end , 0 );
452554 rb_define_method (bpa_class , "read_struct_begin" , rb_thrift_binary_proto_read_struct_begin , 0 );
0 commit comments