Added UUID support in Ruby library
diff --git a/lib/rb/Rakefile b/lib/rb/Rakefile
index c6b650e..53d6096 100644
--- a/lib/rb/Rakefile
+++ b/lib/rb/Rakefile
@@ -62,10 +62,10 @@
     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
 
diff --git a/lib/rb/ext/binary_protocol_accelerated.c b/lib/rb/ext/binary_protocol_accelerated.c
index 3240fdf..791dfa7 100644
--- a/lib/rb/ext/binary_protocol_accelerated.c
+++ b/lib/rb/ext/binary_protocol_accelerated.c
@@ -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;
@@ -34,7 +36,6 @@
 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) {
@@ -228,6 +229,46 @@
   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
 //---------------------------------------
@@ -272,13 +313,6 @@
   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;
 }
@@ -316,14 +350,14 @@
 
   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);
@@ -400,6 +434,27 @@
   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"));
 
@@ -425,6 +480,7 @@
   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);
@@ -447,6 +503,7 @@
   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);
diff --git a/lib/rb/ext/compact_protocol.c b/lib/rb/ext/compact_protocol.c
index 62c17e1..8c864e8 100644
--- a/lib/rb/ext/compact_protocol.c
+++ b/lib/rb/ext/compact_protocol.c
@@ -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)
@@ -58,6 +60,7 @@
 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);
 
@@ -86,6 +89,8 @@
     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);
@@ -169,6 +174,7 @@
 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;
@@ -320,6 +326,46 @@
   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
 //---------------------------------------
@@ -331,6 +377,7 @@
 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) {
@@ -357,6 +404,8 @@
     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);
@@ -396,13 +445,6 @@
   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;
 }
@@ -565,6 +607,27 @@
   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);
@@ -599,6 +662,7 @@
   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);
@@ -622,6 +686,7 @@
   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);
diff --git a/lib/rb/ext/constants.h b/lib/rb/ext/constants.h
index e7aec44..01a0d8d 100644
--- a/lib/rb/ext/constants.h
+++ b/lib/rb/ext/constants.h
@@ -29,6 +29,7 @@
 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;
@@ -49,6 +50,7 @@
 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;
@@ -63,6 +65,7 @@
 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;
@@ -97,3 +100,12 @@
 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;
diff --git a/lib/rb/ext/protocol.c b/lib/rb/ext/protocol.c
index e69de29..d0fc721 100644
--- a/lib/rb/ext/protocol.c
+++ b/lib/rb/ext/protocol.c
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <ruby.h>
+#include <constants.h>
+#include <protocol.h>
+
+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);
+}
diff --git a/lib/rb/ext/protocol.h b/lib/rb/ext/protocol.h
index e69de29..174a346 100644
--- a/lib/rb/ext/protocol.h
+++ b/lib/rb/ext/protocol.h
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <ruby.h>
+
+VALUE get_protocol_exception(VALUE code, VALUE message);
+
+// Efficient hex character to integer conversion
+static inline int hex_char_to_int(char c) {
+  if (c >= '0' && c <= '9') return c - '0';
+  if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+  if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+  return -1;  // invalid hex character
+}
+
+// Efficient integer to hex character conversion
+static inline char int_to_hex_char(int val) {
+  return val < 10 ? ('0' + val) : ('a' + val - 10);
+}
diff --git a/lib/rb/ext/struct.c b/lib/rb/ext/struct.c
index ad33a81..c36c161 100644
--- a/lib/rb/ext/struct.c
+++ b/lib/rb/ext/struct.c
@@ -75,6 +75,11 @@
   return Qnil;
 }
 
+VALUE default_write_uuid(VALUE protocol, VALUE value) {
+  rb_funcall(protocol, write_uuid_method_id, 1, value);
+  return Qnil;
+}
+
 VALUE default_write_binary(VALUE protocol, VALUE value) {
   rb_funcall(protocol, write_binary_method_id, 1, value);
   return Qnil;
@@ -195,6 +200,10 @@
   return rb_funcall(protocol, read_string_method_id, 0);
 }
 
+VALUE default_read_uuid(VALUE protocol) {
+  return rb_funcall(protocol, read_uuid_method_id, 0);
+}
+
 VALUE default_read_binary(VALUE protocol) {
   return rb_funcall(protocol, read_binary_method_id, 0);
 }
@@ -342,6 +351,8 @@
     } else {
       default_write_binary(protocol, value);
     }
+  } else if (ttype == TTYPE_UUID) {
+    default_write_uuid(protocol, value);
   } else if (IS_CONTAINER(ttype)) {
     write_container(ttype, field_info, value, protocol);
   } else if (ttype == TTYPE_STRUCT) {
@@ -452,6 +463,8 @@
     }
   } else if (ttype == TTYPE_DOUBLE) {
     result = default_read_double(protocol);
+  } else if (ttype == TTYPE_UUID) {
+    result = default_read_uuid(protocol);
   } else if (ttype == TTYPE_STRUCT) {
     VALUE klass = rb_hash_aref(field_info, class_sym);
     result = rb_class_new_instance(0, NULL, klass);
diff --git a/lib/rb/ext/thrift_native.c b/lib/rb/ext/thrift_native.c
index 7c99f5e..cd4faa9 100644
--- a/lib/rb/ext/thrift_native.c
+++ b/lib/rb/ext/thrift_native.c
@@ -43,6 +43,7 @@
 int TTYPE_SET;
 int TTYPE_LIST;
 int TTYPE_STRUCT;
+int TTYPE_UUID;
 
 // method ids
 ID validate_method_id;
@@ -57,6 +58,7 @@
 ID write_i64_method_id;
 ID write_double_method_id;
 ID write_string_method_id;
+ID write_uuid_method_id;
 ID write_binary_method_id;
 ID write_map_begin_method_id;
 ID write_map_end_method_id;
@@ -70,6 +72,7 @@
 ID read_i32_method_id;
 ID read_i64_method_id;
 ID read_string_method_id;
+ID read_uuid_method_id;
 ID read_binary_method_id;
 ID read_double_method_id;
 ID read_map_begin_method_id;
@@ -109,6 +112,15 @@
 VALUE binary_sym;
 VALUE protocol_exception_class;
 
+// protocol errors
+int PROTOERR_UNKNOWN;
+int PROTOERR_INVALID_DATA;
+int PROTOERR_NEGATIVE_SIZE;
+int PROTOERR_SIZE_LIMIT;
+int PROTOERR_BAD_VERSION;
+int PROTOERR_NOT_IMPLEMENTED;
+int PROTOERR_DEPTH_LIMIT;
+
 RUBY_FUNC_EXPORTED void Init_thrift_native(void) {
   // cached classes
   thrift_module = rb_const_get(rb_cObject, rb_intern("Thrift"));
@@ -138,6 +150,7 @@
   TTYPE_SET = FIX2INT(rb_const_get(thrift_types_module, rb_intern("SET")));
   TTYPE_LIST = FIX2INT(rb_const_get(thrift_types_module, rb_intern("LIST")));
   TTYPE_STRUCT = FIX2INT(rb_const_get(thrift_types_module, rb_intern("STRUCT")));
+  TTYPE_UUID = FIX2INT(rb_const_get(thrift_types_module, rb_intern("UUID")));
 
   // method ids
   validate_method_id = rb_intern("validate");
@@ -152,6 +165,7 @@
   write_i64_method_id = rb_intern("write_i64");
   write_double_method_id = rb_intern("write_double");
   write_string_method_id = rb_intern("write_string");
+  write_uuid_method_id = rb_intern("write_uuid");
   write_binary_method_id = rb_intern("write_binary");
   write_map_begin_method_id = rb_intern("write_map_begin");
   write_map_end_method_id = rb_intern("write_map_end");
@@ -165,6 +179,7 @@
   read_i32_method_id = rb_intern("read_i32");
   read_i64_method_id = rb_intern("read_i64");
   read_string_method_id = rb_intern("read_string");
+  read_uuid_method_id = rb_intern("read_uuid");
   read_binary_method_id = rb_intern("read_binary");
   read_double_method_id = rb_intern("read_double");
   read_map_begin_method_id = rb_intern("read_map_begin");
@@ -203,6 +218,15 @@
   class_sym = ID2SYM(rb_intern("class"));
   binary_sym = ID2SYM(rb_intern("binary"));
 
+  // protocol errors
+  PROTOERR_UNKNOWN = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("UNKNOWN")));
+  PROTOERR_INVALID_DATA = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("INVALID_DATA")));
+  PROTOERR_NEGATIVE_SIZE = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("NEGATIVE_SIZE")));
+  PROTOERR_SIZE_LIMIT = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("SIZE_LIMIT")));
+  PROTOERR_BAD_VERSION = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("BAD_VERSION")));
+  PROTOERR_NOT_IMPLEMENTED = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("NOT_IMPLEMENTED")));
+  PROTOERR_DEPTH_LIMIT = FIX2INT(rb_const_get(protocol_exception_class, rb_intern("DEPTH_LIMIT")));
+
   rb_global_variable(&type_sym);
   rb_global_variable(&name_sym);
   rb_global_variable(&key_sym);
diff --git a/lib/rb/lib/thrift.rb b/lib/rb/lib/thrift.rb
index 5d83695..8b9a8a5 100644
--- a/lib/rb/lib/thrift.rb
+++ b/lib/rb/lib/thrift.rb
@@ -31,6 +31,7 @@
 require 'thrift/struct'
 require 'thrift/union'
 require 'thrift/struct_union'
+require 'thrift/uuid'
 
 # serializer
 require 'thrift/serializer/serializer'
diff --git a/lib/rb/lib/thrift/protocol/base_protocol.rb b/lib/rb/lib/thrift/protocol/base_protocol.rb
index e9ea7c2..dfce44a 100644
--- a/lib/rb/lib/thrift/protocol/base_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/base_protocol.rb
@@ -137,6 +137,15 @@
       raise NotImplementedError
     end
 
+    # Writes a UUID as 16 bytes.
+    #
+    # uuid - The UUID string to write (e.g. "550e8400-e29b-41d4-a716-446655440000").
+    #
+    # Returns nothing.
+    def write_uuid(uuid)
+      raise NotImplementedError
+    end
+
     def read_message_begin
       raise NotImplementedError
     end
@@ -212,6 +221,13 @@
       raise NotImplementedError
     end
 
+    # Reads a UUID as 16 bytes and returns it as a string.
+    #
+    # Returns a String (e.g. "550e8400-e29b-41d4-a716-446655440000").
+    def read_uuid
+      raise NotImplementedError
+    end
+
     # Writes a field based on the field information, field ID and value.
     #
     # field_info - A Hash containing the definition of the field:
@@ -276,6 +292,8 @@
         else
           write_string(value)
         end
+      when Types::UUID
+        write_uuid(value)
       when Types::STRUCT
         value.write(self)
       else
@@ -316,6 +334,8 @@
         else
           read_string
         end
+      when Types::UUID
+        read_uuid
       else
         raise NotImplementedError
       end
@@ -337,6 +357,8 @@
         read_double
       when Types::STRING
         read_string
+      when Types::UUID
+        read_uuid
       when Types::STRUCT
         read_struct_begin
         while true
diff --git a/lib/rb/lib/thrift/protocol/binary_protocol.rb b/lib/rb/lib/thrift/protocol/binary_protocol.rb
index ce5d0d7..39b72ff 100644
--- a/lib/rb/lib/thrift/protocol/binary_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/binary_protocol.rb
@@ -123,6 +123,11 @@
       trans.write(buf)
     end
 
+    def write_uuid(uuid)
+      UUID.validate_uuid!(uuid)
+      trans.write(UUID.uuid_bytes(uuid))
+    end
+
     def read_message_begin
       version = read_i32
       if version < 0
@@ -233,7 +238,11 @@
       size = read_i32
       trans.read_all(size)
     end
-    
+
+    def read_uuid
+      UUID.uuid_from_bytes(trans.read_all(16))
+    end
+
     def to_s
       "binary(#{super.to_s})"
     end
diff --git a/lib/rb/lib/thrift/protocol/compact_protocol.rb b/lib/rb/lib/thrift/protocol/compact_protocol.rb
index 1ab9d3d..bc342e1 100644
--- a/lib/rb/lib/thrift/protocol/compact_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/compact_protocol.rb
@@ -45,7 +45,8 @@
       SET            = 0x0A
       MAP            = 0x0B
       STRUCT         = 0x0C
-      
+      UUID           = 0x0D
+
       def self.is_bool_type?(b)
         (b & 0x0f) == BOOLEAN_TRUE || (b & 0x0f) == BOOLEAN_FALSE
       end
@@ -63,7 +64,8 @@
         LIST          => Types::LIST,
         SET           => Types::SET,
         MAP           => Types::MAP,
-        STRUCT        => Types::STRUCT
+        STRUCT        => Types::STRUCT,
+        UUID          => Types::UUID
       }
 
       TTYPE_TO_COMPACT = {
@@ -78,7 +80,8 @@
         Types::LIST           => LIST,
         Types::SET            => SET,
         Types::MAP            => MAP,
-        Types::STRUCT         => STRUCT
+        Types::STRUCT         => STRUCT,
+        Types::UUID           => UUID
       }
       
       def self.get_ttype(compact_type)
@@ -220,18 +223,23 @@
       @trans.write(buf)
     end
 
+    def write_uuid(uuid)
+      UUID.validate_uuid!(uuid)
+      trans.write(UUID.uuid_bytes(uuid))
+    end
+
     def read_message_begin
       protocol_id = read_byte()
       if protocol_id != PROTOCOL_ID
         raise ProtocolException.new("Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}")
       end
-      
+
       version_and_type = read_byte()
       version = version_and_type & VERSION_MASK
       if (version != VERSION)
         raise ProtocolException.new("Expected version #{VERSION} but got #{version}");
       end
-      
+
       type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS
       seqid = read_varint32()
       messageName = read_string()
@@ -345,17 +353,21 @@
       size = read_varint32()
       trans.read_all(size)
     end
-    
+
+    def read_uuid
+      UUID.uuid_from_bytes(trans.read_all(16))
+    end
+
     def to_s
       "compact(#{super.to_s})"
     end
 
     private
-    
-    # 
-    # Abstract method for writing the start of lists and sets. List and sets on 
+
+    #
+    # Abstract method for writing the start of lists and sets. List and sets on
     # the wire differ only by the type indicator.
-    # 
+    #
     def write_collection_begin(elem_type, size)
       if size <= 14
         write_byte(size << 4 | CompactTypes.get_compact_type(elem_type))
diff --git a/lib/rb/lib/thrift/protocol/json_protocol.rb b/lib/rb/lib/thrift/protocol/json_protocol.rb
index d03357e..09e3166 100644
--- a/lib/rb/lib/thrift/protocol/json_protocol.rb
+++ b/lib/rb/lib/thrift/protocol/json_protocol.rb
@@ -179,6 +179,8 @@
         "set"
       when Types::LIST
         "lst"
+      when Types::UUID
+        "uid"
       else
         raise NotImplementedError
       end
@@ -207,6 +209,8 @@
         result = Types::SET
       elsif (name == "lst")
         result = Types::LIST
+      elsif (name == "uid")
+        result = Types::UUID
       else
         result = Types::STOP
       end
@@ -475,6 +479,11 @@
       write_json_base64(str)
     end
 
+    def write_uuid(uuid)
+      UUID.validate_uuid!(uuid)
+      write_json_string(uuid.downcase)
+    end
+
     ##
     # Reading functions
     ##
@@ -767,6 +776,13 @@
       read_json_base64
     end
 
+    def read_uuid
+      uuid = read_json_string
+      raise EOFError.new if uuid.length < 36
+      UUID.validate_uuid!(uuid)
+      uuid.tap(&:downcase!)
+    end
+
     def to_s
       "json(#{super.to_s})"
     end
diff --git a/lib/rb/lib/thrift/protocol/protocol_decorator.rb b/lib/rb/lib/thrift/protocol/protocol_decorator.rb
index b1e3c15..73571f7 100644
--- a/lib/rb/lib/thrift/protocol/protocol_decorator.rb
+++ b/lib/rb/lib/thrift/protocol/protocol_decorator.rb
@@ -111,6 +111,10 @@
       @protocol.write_binary(buf)
     end
 
+    def write_uuid(uuid)
+      @protocol.write_uuid(uuid)
+    end
+
     def read_message_begin
       @protocol.read_message_begin
     end
@@ -190,5 +194,9 @@
     def read_binary
       @protocol.read_binary
     end
+
+    def read_uuid
+      @protocol.read_uuid
+    end
   end
-end
\ No newline at end of file
+end
diff --git a/lib/rb/lib/thrift/types.rb b/lib/rb/lib/thrift/types.rb
index cac5269..0f6ab42 100644
--- a/lib/rb/lib/thrift/types.rb
+++ b/lib/rb/lib/thrift/types.rb
@@ -34,6 +34,7 @@
     MAP = 13
     SET = 14
     LIST = 15
+    UUID = 16
   end
 
   class << self
@@ -56,6 +57,8 @@
                 Float
               when Types::STRING
                 String
+              when Types::UUID
+                String
               when Types::STRUCT
                 [Struct, Union]
               when Types::MAP
diff --git a/lib/rb/lib/thrift/uuid.rb b/lib/rb/lib/thrift/uuid.rb
new file mode 100644
index 0000000..f704cfc
--- /dev/null
+++ b/lib/rb/lib/thrift/uuid.rb
@@ -0,0 +1,49 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'thrift/protocol/base_protocol'
+
+module Thrift
+  module UUID
+    UUID_REGEX = /\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z/.freeze
+
+    def self.validate_uuid!(uuid)
+      unless uuid.is_a?(String)
+        raise ProtocolException.new(ProtocolException::INVALID_DATA, 'UUID must be a string')
+      end
+
+      unless uuid =~ UUID_REGEX
+        raise ProtocolException.new(ProtocolException::INVALID_DATA, 'Invalid UUID format')
+      end
+    end
+
+    def self.uuid_bytes(uuid)
+      [uuid.delete('-')].pack('H*')
+    end
+
+    def self.uuid_from_bytes(bytes)
+      unless bytes.bytesize == 16
+        raise ProtocolException.new(ProtocolException::INVALID_DATA, 'Invalid UUID data length')
+      end
+
+      hex = bytes.unpack('H*').first
+      "#{hex[0, 8]}-#{hex[8, 4]}-#{hex[12, 4]}-#{hex[16, 4]}-#{hex[20, 12]}"
+    end
+  end
+end
diff --git a/lib/rb/spec/ThriftSpec.thrift b/lib/rb/spec/ThriftSpec.thrift
index b42481b..3c2f3e0 100644
--- a/lib/rb/spec/ThriftSpec.thrift
+++ b/lib/rb/spec/ThriftSpec.thrift
@@ -60,6 +60,7 @@
   3: i32 other_i32_field;
   4: SomeEnum enum_field;
   5: binary binary_field;
+  6: uuid uuid_field;
 }
 
 struct Foo {
@@ -71,6 +72,7 @@
   6: set<i16> shorts = [5, 17, 239],
   7: optional string opt_string
   8: bool my_bool
+  9: optional uuid opt_uuid
 }
 
 struct Foo2 {
@@ -92,7 +94,8 @@
   8: list<map<i16, i16>> maps,
   9: list<list<i16>> lists,
   10: list<set<i16>> sets,
-  11: list<Hello> hellos
+  11: list<Hello> hellos,
+  12: list<uuid> uuids
 }
 
 exception Xception {
@@ -119,6 +122,7 @@
   8: i32 other_i32
   9: SomeEnum some_enum;
   10: map<SomeEnum, list<SomeEnum>> my_map;
+  11: uuid unique_id;
 }
 
 struct Struct_with_union {
diff --git a/lib/rb/spec/binary_protocol_spec_shared.rb b/lib/rb/spec/binary_protocol_spec_shared.rb
index 4baedd7..c83f5ae 100644
--- a/lib/rb/spec/binary_protocol_spec_shared.rb
+++ b/lib/rb/spec/binary_protocol_spec_shared.rb
@@ -254,27 +254,43 @@
     expect { @prot.write_binary(nil) }.to raise_error(StandardError, 'nil argument not allowed!')
   end
 
+  it "should write a uuid" do
+    @prot.write_uuid("00112233-4455-6677-8899-aabbccddeeff")
+    a = @trans.read(@trans.available)
+    expect(a.unpack('C*')).to eq([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
+  end
+
+  it "should read a uuid" do
+    @trans.write([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff].pack('C*'))
+    uuid = @prot.read_uuid
+    expect(uuid).to eq("00112233-4455-6677-8899-aabbccddeeff")
+  end
+
+  it "should error gracefully when trying to write an invalid uuid" do
+    expect { @prot.write_uuid("invalid") }.to raise_error(Thrift::ProtocolException)
+  end
+
   it "should write the message header without version when writes are not strict" do
     @prot = protocol_class.new(@trans, true, false) # no strict write
     @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
     expect(@trans.read(@trans.available)).to eq("\000\000\000\vtestMessage\001\000\000\000\021")
   end
-    
+
   it "should write the message header with a version when writes are strict" do
     @prot = protocol_class.new(@trans) # strict write
     @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
     expect(@trans.read(@trans.available)).to eq("\200\001\000\001\000\000\000\vtestMessage\000\000\000\021")
   end
-  
+
   # message footer is a noop
-  
+
   it "should read a field header" do
     @trans.write([Thrift::Types::STRING, 3].pack("cn"))
     expect(@prot.read_field_begin).to eq([nil, Thrift::Types::STRING, 3])
   end
-  
+
   # field footer is a noop
-  
+
   it "should read a stop field" do
     @trans.write([Thrift::Types::STOP].pack("c"));
     expect(@prot.read_field_begin).to eq([nil, Thrift::Types::STOP, 0])
diff --git a/lib/rb/spec/compact_protocol_spec.rb b/lib/rb/spec/compact_protocol_spec.rb
index 513dd69..7519810 100644
--- a/lib/rb/spec/compact_protocol_spec.rb
+++ b/lib/rb/spec/compact_protocol_spec.rb
@@ -71,6 +71,30 @@
     end
   end
 
+  it "should write a uuid" do
+    trans = Thrift::MemoryBufferTransport.new
+    proto = Thrift::CompactProtocol.new(trans)
+
+    proto.write_uuid("00112233-4455-6677-8899-aabbccddeeff")
+    a = trans.read(trans.available)
+    expect(a.unpack('C*')).to eq([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
+  end
+
+  it "should read a uuid" do
+    trans = Thrift::MemoryBufferTransport.new
+    proto = Thrift::CompactProtocol.new(trans)
+
+    trans.write([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff].pack('C*'))
+    uuid = proto.read_uuid
+    expect(uuid).to eq("00112233-4455-6677-8899-aabbccddeeff")
+  end
+
+  it "should error gracefully when trying to write an invalid uuid" do
+    trans = Thrift::MemoryBufferTransport.new
+    proto = Thrift::CompactProtocol.new(trans)
+    expect { proto.write_uuid("invalid") }.to raise_error(Thrift::ProtocolException)
+  end
+
   it "should encode and decode a monster struct correctly" do
     trans = Thrift::MemoryBufferTransport.new
     proto = Thrift::CompactProtocol.new(trans)
diff --git a/lib/rb/spec/json_protocol_spec.rb b/lib/rb/spec/json_protocol_spec.rb
index fe1af7b..9acaf86 100644
--- a/lib/rb/spec/json_protocol_spec.rb
+++ b/lib/rb/spec/json_protocol_spec.rb
@@ -252,6 +252,11 @@
       expect(@trans.read(@trans.available)).to eq("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"")
     end
 
+    it "should write a uuid" do
+      @prot.write_uuid("00112233-4455-6677-8899-aabbccddeeff")
+      expect(@trans.read(@trans.available)).to eq("\"00112233-4455-6677-8899-aabbccddeeff\"")
+    end
+
     it "should get type name for type id" do
       expect {@prot.get_type_name_for_type_id(Thrift::Types::STOP)}.to raise_error(NotImplementedError)
       expect {@prot.get_type_name_for_type_id(Thrift::Types::VOID)}.to raise_error(NotImplementedError)
@@ -534,7 +539,17 @@
       @trans.write("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"")
       expect(@prot.read_binary.bytes.to_a).to eq((0...256).to_a)
     end
-  
+
+    it "should read a uuid" do
+      @trans.write("\"00112233-4455-6677-8899-aabbccddeeff\"")
+      expect(@prot.read_uuid).to eq("00112233-4455-6677-8899-aabbccddeeff")
+    end
+
+    it "should normalize uppercase uuid on read" do
+      @trans.write("\"00112233-4455-6677-8899-AABBCCDDEEFF\"")
+      expect(@prot.read_uuid).to eq("00112233-4455-6677-8899-aabbccddeeff")
+    end
+
     it "should provide a reasonable to_s" do
       expect(@prot.to_s).to eq("json(memory)")
     end
diff --git a/lib/rb/spec/struct_spec.rb b/lib/rb/spec/struct_spec.rb
index 9a4baa8..9349686 100644
--- a/lib/rb/spec/struct_spec.rb
+++ b/lib/rb/spec/struct_spec.rb
@@ -289,5 +289,82 @@
         e.write(prot)
       end
     end
+
+    it "should handle UUID fields in structs" do
+      struct = SpecNamespace::Foo.new(
+        simple: 42,
+        words: 'test',
+        opt_uuid: '550e8400-e29b-41d4-a716-446655440000'
+      )
+
+      trans = Thrift::MemoryBufferTransport.new
+      prot = Thrift::BinaryProtocol.new(trans)
+
+      struct.write(prot)
+
+      result = SpecNamespace::Foo.new
+      result.read(prot)
+
+      expect(result.simple).to eq(42)
+      expect(result.words).to eq('test')
+      expect(result.opt_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
+    end
+
+    it "should handle optional UUID fields when unset" do
+      struct = SpecNamespace::Foo.new(simple: 42, words: 'test')
+      expect(struct.opt_uuid).to be_nil
+      expect(struct.opt_uuid?).to be_falsey
+    end
+
+    it "should handle list of UUIDs in SimpleList" do
+      uuids = ['550e8400-e29b-41d4-a716-446655440000', '6ba7b810-9dad-11d1-80b4-00c04fd430c8']
+      struct = SpecNamespace::SimpleList.new(uuids: uuids)
+
+      trans = Thrift::MemoryBufferTransport.new
+      prot = Thrift::CompactProtocol.new(trans)
+
+      struct.write(prot)
+
+      result = SpecNamespace::SimpleList.new
+      result.read(prot)
+
+      expect(result.uuids).to eq(uuids)
+    end
+
+    it "should normalize UUID case to lowercase" do
+      struct = SpecNamespace::Foo.new(opt_uuid: '550E8400-E29B-41D4-A716-446655440000')
+
+      trans = Thrift::MemoryBufferTransport.new
+      prot = Thrift::BinaryProtocol.new(trans)
+
+      struct.write(prot)
+
+      result = SpecNamespace::Foo.new
+      result.read(prot)
+
+      expect(result.opt_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
+    end
+
+    it "should handle UUID alongside other types in SimpleList" do
+      struct = SpecNamespace::SimpleList.new(
+        bools: [true, false],
+        i32s: [1, 2, 3],
+        strings: ['hello', 'world'],
+        uuids: ['550e8400-e29b-41d4-a716-446655440000', '00000000-0000-0000-0000-000000000000']
+      )
+
+      trans = Thrift::MemoryBufferTransport.new
+      prot = Thrift::BinaryProtocol.new(trans)
+
+      struct.write(prot)
+
+      result = SpecNamespace::SimpleList.new
+      result.read(prot)
+
+      expect(result.bools).to eq([true, false])
+      expect(result.i32s).to eq([1, 2, 3])
+      expect(result.strings).to eq(['hello', 'world'])
+      expect(result.uuids).to eq(['550e8400-e29b-41d4-a716-446655440000', '00000000-0000-0000-0000-000000000000'])
+    end
   end
 end
diff --git a/lib/rb/spec/union_spec.rb b/lib/rb/spec/union_spec.rb
index efb3853..7bf4ca0 100644
--- a/lib/rb/spec/union_spec.rb
+++ b/lib/rb/spec/union_spec.rb
@@ -91,6 +91,24 @@
       expect(union).not_to eq(other_union)
     end
 
+    it "should equate two unions with the same UUID value" do
+      union = SpecNamespace::My_union.new(:unique_id, '550e8400-e29b-41d4-a716-446655440000')
+      other_union = SpecNamespace::My_union.new(:unique_id, '550e8400-e29b-41d4-a716-446655440000')
+      expect(union).to eq(other_union)
+    end
+
+    it "should not equate two unions with different UUID values" do
+      union = SpecNamespace::My_union.new(:unique_id, '550e8400-e29b-41d4-a716-446655440000')
+      other_union = SpecNamespace::My_union.new(:unique_id, '6ba7b810-9dad-11d1-80b4-00c04fd430c8')
+      expect(union).not_to eq(other_union)
+    end
+
+    it "should not equate UUID union with different field type" do
+      union = SpecNamespace::My_union.new(:unique_id, '550e8400-e29b-41d4-a716-446655440000')
+      other_union = SpecNamespace::My_union.new(:some_characters, '550e8400-e29b-41d4-a716-446655440000')
+      expect(union).not_to eq(other_union)
+    end
+
     it "should inspect properly" do
       union = SpecNamespace::My_union.new(:integer32, 25)
       expect(union.inspect).to eq("<SpecNamespace::My_union integer32: 25>")
@@ -192,23 +210,58 @@
 
     it "should be comparable" do
       relationships = [
-        [0,   -1, -1, -1],
-        [1,   0,  -1, -1],
-        [1,   1,  0,  -1],
-        [1,   1,  1,  0]]
+        [0,   -1, -1, -1, -1, -1],
+        [1,   0,  -1, -1, -1, -1],
+        [1,   1,  0,  -1, -1, -1],
+        [1,   1,  1,  0,  -1, -1],
+        [1,   1,  1,  1,  0,  -1],
+        [1,   1,  1,  1,  1,  0]]
 
       objs = [
         SpecNamespace::TestUnion.new(:string_field, "blah"),
         SpecNamespace::TestUnion.new(:string_field, "blahblah"),
         SpecNamespace::TestUnion.new(:i32_field, 1),
+        SpecNamespace::TestUnion.new(:uuid_field, '550e8400-e29b-41d4-a716-446655440000'),
+        SpecNamespace::TestUnion.new(:uuid_field, '6ba7b810-9dad-11d1-80b4-00c04fd430c8'),
         SpecNamespace::TestUnion.new()]
 
-      for y in 0..3
-        for x in 0..3
+      objs.size.times do |y|
+        objs.size.times do |x|
           # puts "#{objs[y].inspect} <=> #{objs[x].inspect} should == #{relationships[y][x]}"
           expect(objs[y] <=> objs[x]).to eq(relationships[y][x])
         end
       end
     end
+
+    it "should handle UUID as union value" do
+      union = SpecNamespace::My_union.new
+      union.unique_id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
+
+      trans = Thrift::MemoryBufferTransport.new
+      prot = Thrift::CompactProtocol.new(trans)
+
+      union.write(prot)
+
+      result = SpecNamespace::My_union.new
+      result.read(prot)
+
+      expect(result.unique_id).to eq('ffffffff-ffff-ffff-ffff-ffffffffffff')
+      expect(result.get_set_field).to eq(:unique_id)
+    end
+
+    it "should normalize UUID case in union" do
+      union = SpecNamespace::My_union.new
+      union.unique_id = '550E8400-E29B-41D4-A716-446655440000'
+
+      trans = Thrift::MemoryBufferTransport.new
+      prot = Thrift::BinaryProtocol.new(trans)
+
+      union.write(prot)
+
+      result = SpecNamespace::My_union.new
+      result.read(prot)
+
+      expect(result.unique_id).to eq('550e8400-e29b-41d4-a716-446655440000')
+    end
   end
 end
diff --git a/lib/rb/spec/uuid_validation_spec.rb b/lib/rb/spec/uuid_validation_spec.rb
new file mode 100644
index 0000000..c95d408
--- /dev/null
+++ b/lib/rb/spec/uuid_validation_spec.rb
@@ -0,0 +1,238 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+require 'spec_helper'
+
+describe 'UUID Validation' do
+  protocols = [
+    ['BinaryProtocol', Thrift::BinaryProtocol],
+  ]
+
+  if defined?(Thrift::BinaryProtocolAccelerated)
+    protocols << ['BinaryProtocolAccelerated', Thrift::BinaryProtocolAccelerated]
+  end
+
+  protocols << ['CompactProtocol', Thrift::CompactProtocol]
+  protocols << ['JsonProtocol', Thrift::JsonProtocol]
+
+  protocols.each do |protocol_name, protocol_class|
+    describe protocol_name do
+      before(:each) do
+        @trans = Thrift::MemoryBufferTransport.new
+        @prot = protocol_class.new(@trans)
+      end
+
+      context 'valid UUIDs' do
+        it 'should accept lowercase UUIDs' do
+          uuid = '550e8400-e29b-41d4-a716-446655440000'
+          expect { @prot.write_uuid(uuid) }.not_to raise_error
+          result = @prot.read_uuid
+          expect(result).to eq(uuid)
+        end
+
+        it 'should accept uppercase UUIDs' do
+          uuid = '550E8400-E29B-41D4-A716-446655440000'
+          expect { @prot.write_uuid(uuid) }.not_to raise_error
+          result = @prot.read_uuid
+          # Result should be lowercase
+          expect(result).to eq('550e8400-e29b-41d4-a716-446655440000')
+        end
+
+        it 'should accept mixed case UUIDs' do
+          uuid = '550e8400-E29B-41d4-A716-446655440000'
+          expect { @prot.write_uuid(uuid) }.not_to raise_error
+          result = @prot.read_uuid
+          expect(result).to eq('550e8400-e29b-41d4-a716-446655440000')
+        end
+
+        it 'should accept all zeros' do
+          uuid = '00000000-0000-0000-0000-000000000000'
+          expect { @prot.write_uuid(uuid) }.not_to raise_error
+          result = @prot.read_uuid
+          expect(result).to eq(uuid)
+        end
+
+        it 'should accept all fs' do
+          uuid = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
+          expect { @prot.write_uuid(uuid) }.not_to raise_error
+          result = @prot.read_uuid
+          expect(result).to eq(uuid)
+        end
+      end
+
+      context 'invalid UUIDs' do
+        def expect_invalid_uuid(value, message)
+          expect { @prot.write_uuid(value) }.to raise_error(Thrift::ProtocolException) do |error|
+            expect(error.type).to eq(Thrift::ProtocolException::INVALID_DATA)
+            expect(error.message).to eq(message)
+          end
+        end
+
+        it 'should reject nil' do
+          expect_invalid_uuid(nil, 'UUID must be a string')
+        end
+
+        it 'should reject non-string' do
+          expect_invalid_uuid(12345, 'UUID must be a string')
+        end
+
+        it 'should reject wrong length' do
+          expect_invalid_uuid('550e8400-e29b-41d4-a716', 'Invalid UUID format')
+        end
+
+        it 'should reject missing hyphens' do
+          expect_invalid_uuid('550e8400e29b41d4a716446655440000', 'Invalid UUID format')
+        end
+
+        it 'should reject hyphens in wrong positions' do
+          expect_invalid_uuid('550e840-0e29b-41d4-a716-446655440000', 'Invalid UUID format')
+        end
+
+        it 'should reject invalid hex characters (g)' do
+          expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000g', 'Invalid UUID format')
+        end
+
+        it 'should reject invalid hex characters (z)' do
+          expect_invalid_uuid('z50e8400-e29b-41d4-a716-446655440000', 'Invalid UUID format')
+        end
+
+        it 'should reject invalid hex characters (space)' do
+          expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000 ', 'Invalid UUID format')
+        end
+
+        it 'should reject empty string' do
+          expect_invalid_uuid('', 'Invalid UUID format')
+        end
+
+        it 'should reject UUID with extra characters' do
+          expect_invalid_uuid('550e8400-e29b-41d4-a716-446655440000x', 'Invalid UUID format')
+        end
+
+        it 'should reject trailing hyphen' do
+          expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000-', 'Invalid UUID format')
+        end
+
+        it 'should reject hyphen inside hex pair' do
+          expect_invalid_uuid('550e8400-e29b-41d4-a716-4466-5544000', 'Invalid UUID format')
+        end
+      end
+
+      context 'malformed binary data on read' do
+        it 'should raise error on truncated data' do
+          @trans = Thrift::MemoryBufferTransport.new
+          @prot = protocol_class.new(@trans)
+
+          # Write only 10 bytes instead of 16
+          if protocol_class == Thrift::JsonProtocol
+            @trans.write('"00000000-0000-0000-0000"')
+          else
+            @trans.write("\x00" * 10)
+          end
+
+          expect { @prot.read_uuid }.to raise_error(EOFError)
+        end
+
+        it 'should raise error on 15 bytes (one byte short)' do
+          @trans = Thrift::MemoryBufferTransport.new
+          @prot = protocol_class.new(@trans)
+
+          if protocol_class == Thrift::JsonProtocol
+            @trans.write('"00000000-0000-0000-0000-000000000"')
+          else
+            @trans.write("\x00" * 15)
+          end
+
+          expect { @prot.read_uuid }.to raise_error(EOFError)
+        end
+
+        it 'should raise error on empty buffer' do
+          @trans = Thrift::MemoryBufferTransport.new
+          @prot = protocol_class.new(@trans)
+
+          expect { @prot.read_uuid }.to raise_error(EOFError)
+        end
+      end
+
+      context 'multiple UUIDs in sequence' do
+        it 'should handle 10 UUIDs in sequence' do
+          uuids = 10.times.map { |i| sprintf('%08x-0000-0000-0000-000000000000', i) }
+
+          @trans = Thrift::MemoryBufferTransport.new
+          @prot = protocol_class.new(@trans)
+
+          uuids.each { |uuid| @prot.write_uuid(uuid) }
+
+          results = 10.times.map { @prot.read_uuid }
+          expect(results).to eq(uuids)
+        end
+
+        it 'should handle UUIDs interleaved with other types' do
+          @trans = Thrift::MemoryBufferTransport.new
+          @prot = protocol_class.new(@trans)
+
+          @prot.write_message_begin('testMessage',  Thrift::MessageTypes::CALL, 0)
+          @prot.write_i32(42)
+          @prot.write_uuid('550e8400-e29b-41d4-a716-446655440000')
+          @prot.write_string('test')
+          @prot.write_uuid('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
+          @prot.write_i64(123456789)
+          @prot.write_message_end
+
+          @prot.read_message_begin
+          expect(@prot.read_i32).to eq(42)
+          expect(@prot.read_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
+          expect(@prot.read_string).to eq('test')
+          expect(@prot.read_uuid).to eq('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
+          expect(@prot.read_i64).to eq(123456789)
+          @prot.read_message_end
+        end
+
+        it 'should handle UUIDs in struct fields context' do
+          @trans = Thrift::MemoryBufferTransport.new
+          @prot = protocol_class.new(@trans)
+
+          # Simulate struct field headers
+          @prot.write_struct_begin('test')
+          @prot.write_field_begin('uuid1', Thrift::Types::UUID, 1)
+          @prot.write_uuid('550e8400-e29b-41d4-a716-446655440000')
+          @prot.write_field_end
+          @prot.write_field_begin('uuid2', Thrift::Types::UUID, 2)
+          @prot.write_uuid('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
+          @prot.write_field_end
+          @prot.write_field_stop
+          @prot.write_struct_end
+
+          @prot.read_struct_begin
+          name, type, id = @prot.read_field_begin
+          expect(type).to eq(Thrift::Types::UUID)
+          expect(@prot.read_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
+          @prot.read_field_end
+
+          name, type, id = @prot.read_field_begin
+          expect(type).to eq(Thrift::Types::UUID)
+          expect(@prot.read_uuid).to eq('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
+          @prot.read_field_end
+
+          name, type, id = @prot.read_field_begin
+          expect(type).to eq(Thrift::Types::STOP)
+        end
+      end
+    end
+  end
+end