static VALUE des0_read_hash(VALUE self) {
    AMF_DESERIALIZER *des;
    Data_Get_Struct(self, AMF_DESERIALIZER, des);
    des_read_uint32(des); // Hash size, but there's no optimization I can perform with this
    VALUE obj = rb_hash_new();
    rb_ary_push(des->obj_cache, obj);
    des0_read_props(self, obj, des_read_string);
    return obj;
}
static VALUE des0_read_object(VALUE self) {
    AMF_DESERIALIZER *des;
    Data_Get_Struct(self, AMF_DESERIALIZER, des);

    VALUE obj = rb_hash_new();
    rb_ary_push(des->obj_cache, obj);
    des0_read_props(self, obj, des_read_sym, 0);
    return obj;
}
static VALUE des0_read_object(VALUE self) {
    AMF_DESERIALIZER *des;
    Data_Get_Struct(self, AMF_DESERIALIZER, des);

    // Create object and add to cache
    VALUE obj = rb_funcall(des->class_mapper, id_get_ruby_obj, 1, rb_str_new(NULL, 0));
    rb_ary_push(des->obj_cache, obj);

    // Populate object
    VALUE props = rb_hash_new();
    des0_read_props(self, props, des_read_sym);
    rb_funcall(des->class_mapper, id_populate_ruby_obj, 2, obj, props);

    return obj;
}
static VALUE des0_read_hash(VALUE self) {
    AMF_DESERIALIZER *des;
    Data_Get_Struct(self, AMF_DESERIALIZER, des);

    static VALUE class_mapper = 0;
    if(class_mapper == 0) class_mapper = rb_const_get(mRocketAMF, rb_intern("ClassMapper"));

    VALUE obj = rb_funcall(class_mapper, id_get_ruby_obj, 1, rb_str_new2("Hash"));
    int translate_case = 0;
    if (obj != Qnil) {
      translate_case = rb_funcall(class_mapper, id_get_ruby_option, 2, obj, rb_str_new2("translate_case")) == Qtrue;
    } else {
      obj = rb_hash_new();
    }

    des_read_uint32(des); // Hash size, but there's no optimization I can perform with this
    rb_ary_push(des->obj_cache, obj);
    des0_read_props(self, obj, des_read_string, translate_case);
    return obj;
}
static VALUE des0_read_typed_object(VALUE self) {
    static VALUE class_mapper = 0;
    if(class_mapper == 0) class_mapper = rb_const_get(mRocketAMF, rb_intern("ClassMapper"));
    AMF_DESERIALIZER *des;
    Data_Get_Struct(self, AMF_DESERIALIZER, des);

    // Create object and add to cache
    VALUE class_name = des_read_string(des, des_read_uint16(des));
    VALUE obj = rb_funcall(class_mapper, id_get_ruby_obj, 1, class_name);
    rb_ary_push(des->obj_cache, obj);

    int translate_case = rb_funcall(class_mapper, id_get_ruby_option, 2, obj, rb_str_new2("translate_case")) == Qtrue;

    // Populate object
    VALUE props = rb_hash_new();
    des0_read_props(self, props, des_read_sym, translate_case);
    rb_funcall(class_mapper, id_populate_ruby_obj, 2, obj, props);

    return obj;
}