[Kde-bindings] QtRuby: Qt::Variant#value fails for ushort and QChar variants

Yaohan Chen yaohan.chen at gmail.com
Wed Apr 11 07:11:33 UTC 2012


Hello,

I'm getting a segfault when calling Qt::Variant#value for QVariant<ushort>, and NoMethodError
for QVariant<QChar>. I've included test cases that show the failures as well as workaround using
String#unpack below. They require RSpec, RubyInline and of course QtRuby to run. Could anyone
confirm if you have the same problem?

Thanks,

Yaohan Chen


#!/usr/bin/env rspec

require 'Qt'
require 'inline'

# These tests demonstrate that when you get a Qt::Variant by unserializing a serialized
# QVariant via QDataStream, the value method fails if the variant's type is QChar or ushort.
describe 'Qt::Variant#value' do
  it 'returns the value of an int variant' do
    variant = unserialize_variant SerializedVariant.of_int(15)
    # This one works for me
    variant.value.should == 15
  end

  it 'returns the value of a QChar variant' do
    variant = unserialize_variant SerializedVariant.of_QChar(10)
    # This fails for me saying the QVariant does not have method toChar defined
    variant.value.should == 10
  end

  it 'returns the value of a ushort variant' do
    variant = unserialize_variant SerializedVariant.of_ushort(5)

    # pending 'causes segfault'
    
    # This causes Ruby to segfault for me. If it happens for you too, uncomment the pending
    # line above so RSpec can report the results of other examples.
    variant.value.should == 5
  end
end

# These extract Ruby values directly from serialized variants without Qt, to show that the
# correct data is passed from C++ to Ruby. They use String#unpack and skip the first
# 5 bytes ('@5') which are QVariant's type information and "null flag". See
# https://qt-project.org/doc/qt-4.8/datastreamformat.html
describe 'Workaround using String#unpack' do
  it 'returns the value of an int variant' do
    string = SerializedVariant.of_int(15);
    # l> for big-endian 32bit signed integer
    string.unpack('@5l>').first.should == 15
  end

  it 'returns the value of a QChar variant' do
    string = SerializedVariant.of_QChar(10);
    # s> for big-endian 16bit signed integer (QChar stores a UTF-16 character)
    string.unpack('@5s>').first.should == 10
  end

  it 'returns the value of a ushort variant' do
    string = SerializedVariant.of_ushort(5);
    # S> for big-endian 16bit unsigned integer
    string.unpack('@5S>').first.should == 5
  end
end

# Given string containing serialization of a variant, return the variant
def unserialize_variant(string)
  byte_array = Qt::ByteArray.new string
  data_stream = Qt::DataStream.new byte_array
  variant = Qt::Variant.new
  data_stream >> variant
  variant
end

# This module contains functions that return serialization of several variant types
module SerializedVariant
  inline :C do |builder|
    builder.add_compile_flags %w[-x c++]
    builder.include '<QtCore/QByteArray>'
    builder.include '<QtCore/QDataStream>'
    builder.include '<QtCore/QVariant>'
    builder.add_link_flags %w[-lQtCore]

    builder.prefix <<-CODE
      // Return serialization of the given QVariant
      VALUE serialize(QVariant variant) {
        QByteArray byte_array;
        QDataStream data_stream(&byte_array, QIODevice::WriteOnly);
        data_stream << variant;
        return rb_str_new(byte_array.data(), byte_array.size());
      }
    CODE

    # :expand_types => true makes RubyInline insert VALUE self and figure arity automatically
    builder.c_raw_singleton <<-CODE, :expand_types => true
      // Return serialization of a QVariant containing the given int
      VALUE of_int(VALUE v) {
        QVariant variant = QVariant::fromValue<int>(FIX2INT(v));
        return serialize(variant);
      }
    CODE

    builder.c_raw_singleton <<-CODE, :expand_types => true
      // Return serialization of a QVariant containing the given QChar
      VALUE of_QChar(VALUE v) {
        QVariant variant = QVariant::fromValue<QChar>(FIX2INT(v));
        return serialize(variant);
      }
    CODE

    builder.c_raw_singleton <<-CODE, :expand_types => true
      // Return serialization of a QVariant containing the given ushort
      VALUE of_ushort(VALUE v) {
        QVariant variant = QVariant::fromValue<ushort>(FIX2INT(v));
        return serialize(variant);
      }
    CODE
  end
end




More information about the Kde-bindings mailing list