module Tarantool::UnpackTuples
Public Instance Methods
_unpack_tuples(p1, p2, p3, p4)
click to toggle source
static VALUE unpack_tuples(VALUE self, VALUE data, VALUE fields, VALUE _tail, VALUE tuples_affected) { uint32_t fieldsn = RARRAY_LEN(fields); uint32_t tuplesn = NUM2UINT(tuples_affected); uint32_t tail = NUM2UINT(_tail); const char *str = StringValuePtr(data); size_t len = RSTRING_LEN(data); rb_encoding *utf8 = rb_utf8_encoding(), *binary = rb_ascii8bit_encoding(); VALUE tuples = rb_ary_new2(tuplesn); VALUE serializers = rb_ary_new2(fieldsn); for (;tuplesn > 0; tuplesn--) { uint32_t tuplen, i, realfield; const char *end; VALUE tuple; if (len < 8) { rb_raise(rb_eValueError, "Response too short"); } end = str + 8 + *(uint32_t*)str; tuplen = *(uint32_t*)(str+4); tuple = rb_ary_new2(fieldsn); str += 8; len -= 8; for(i = 0; i < tuplen; i++) { size_t fieldsize = slice_ber((const uint8_t**)&str, &len); VALUE field, value; if (fieldsize == 0) { rb_ary_push(tuple, Qnil); continue; } if (fieldsize > len) { rb_raise(rb_eValueError, "Response mailformed at field #%u fieldsize: %zu tail len: %zu", i, fieldsize, len); } realfield = i; if (i >= fieldsn) { if (tail == 1) { realfield = fieldsn - 1; } else { realfield = fieldsn + (i - fieldsn) % tail - tail; } } field = RARRAY_CONST_PTR(fields)[realfield]; if (field == sym_int || field == sym_integer) { if (fieldsize != 4) { rb_raise(rb_eValueError, "Bad field size %zd for integer field #%u", fieldsize, i); } value = UINT2NUM(get_uint32(str)); } else if (field == sym_str || field == sym_string) { if (*str == 0 && fieldsize > 0) { str++; len--; fieldsize--; } value = rb_enc_str_new(str, fieldsize, utf8); } else if (field == sym_int64) { if (fieldsize != 8) { rb_raise(rb_eValueError, "Bad field size %zd for 64bit integer field #%u", fieldsize, i); } #if SIZEOF_LONG == 8 value = ULONG2NUM(get_uint64(str)); #elif HAVE_LONG_LONG value = ULL2NUM(get_uint64(str)); #else #error "Should have long long or sizeof(long) == 8" #endif } else if (field == sym_bytes) { if (*str == 0 && fieldsize > 0) { str++; len--; fieldsize--; } value = rb_enc_str_new(str, fieldsize, binary); } else if (field == sym_int16) { if (fieldsize != 2) { rb_raise(rb_eValueError, "Bad field size %zd for 16bit integer field #%u", fieldsize, i); } value = UINT2NUM(get_uint16(str)); } else if (field == sym_int8) { if (fieldsize != 1) { rb_raise(rb_eValueError, "Bad field size %zd for 8bit integer field #%u", fieldsize, i); } value = UINT2NUM(*(uint8_t*)str); } else if (field == sym_sint) { if (fieldsize != 4) { rb_raise(rb_eValueError, "Bad field size %zd for integer field #%u", fieldsize, i); } value = INT2NUM((int32_t)get_uint32(str)); } else if (field == sym_sint64) { if (fieldsize != 8) { rb_raise(rb_eValueError, "Bad field size %zd for 64bit integer field #%u", fieldsize, i); } #if SIZEOF_LONG == 8 value = LONG2NUM((int64_t)get_uint64(str)); #elif HAVE_LONG_LONG value = LL2NUM((int64_t)get_uint64(str)); #endif } else if (field == sym_sint16) { if (fieldsize != 2) { rb_raise(rb_eValueError, "Bad field size %zd for 16bit integer field #%u", fieldsize, i); } value = INT2NUM((int16_t)get_uint16(str)); } else if (field == sym_sint8) { if (fieldsize != 1) { rb_raise(rb_eValueError, "Bad field size %zd for 8bit integer field #%u", fieldsize, i); } value = INT2NUM(*(int8_t*)str); } else if (field == sym_varint) { if (fieldsize == 4) { value = UINT2NUM(get_uint32(str)); } else if (fieldsize == 8) { #if SIZEOF_LONG == 8 value = ULONG2NUM(get_uint64(str)); #elif HAVE_LONG_LONG value = ULL2NUM(get_uint64(str)); #endif } else if (fieldsize == 2) { value = UINT2NUM(get_uint16(str)); } else { rb_raise(rb_eValueError, "Bad field size %zd for integer field %d", fieldsize, i); } } else if (field == sym_auto) { value = rb_enc_str_new(str, fieldsize, utf8); if (fieldsize == 2 || fieldsize == 4 || fieldsize == 8) { value = rb_class_new_instance(1, &value, rb_cAutoType); } } else { VALUE serializer = rb_ary_entry(serializers, realfield); VALUE substr = rb_enc_str_new(str, fieldsize, binary); if (!RTEST(serializer)) { serializer = rb_funcall2(self, id_get_serializer, 1, &field); rb_ary_store(serializers, realfield, serializer); } value = rb_funcall2(serializer, id_decode, 1, &substr); } str += fieldsize; len -= fieldsize; rb_ary_push(tuple, value); } if (end != str) { rb_raise(rb_eValueError, "Response mailformed"); } rb_ary_push(tuples, tuple); } RB_GC_GUARD(data); return tuples; }