diff --git a/src/gsi/gsi/gsiSerialisation.h b/src/gsi/gsi/gsiSerialisation.h index 30049b11c..e43af8541 100644 --- a/src/gsi/gsi/gsiSerialisation.h +++ b/src/gsi/gsi/gsiSerialisation.h @@ -698,76 +698,6 @@ class GSI_PUBLIC_TEMPLATE StringAdaptorImpl #if defined(HAVE_QT) -/** - * @brief Specialization for QByteArray - */ -template <> -class GSI_PUBLIC StringAdaptorImpl - : public StringAdaptor -{ -public: - StringAdaptorImpl (QByteArray *s) - : mp_s (s), m_is_const (false) - { - // .. nothing yet .. - } - - StringAdaptorImpl (const QByteArray *s) - : mp_s (const_cast (s)), m_is_const (true) - { - // .. nothing yet .. - } - - StringAdaptorImpl (const QByteArray &s) - : m_is_const (false), m_s (s) - { - mp_s = &m_s; - } - - StringAdaptorImpl () - : m_is_const (false) - { - mp_s = &m_s; - } - - virtual ~StringAdaptorImpl () - { - // .. nothing yet .. - } - - virtual size_t size () const - { - return mp_s->size (); - } - - virtual const char *c_str () const - { - return mp_s->constData (); - } - - virtual void set (const char *c_str, size_t s, tl::Heap &) - { - if (! m_is_const) { - *mp_s = QByteArray (c_str, int (s)); - } - } - - virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const - { - StringAdaptorImpl *s = dynamic_cast *>(target); - if (s) { - *s->mp_s = *mp_s; - } else { - StringAdaptor::copy_to (target, heap); - } - } - -private: - QByteArray *mp_s; - bool m_is_const; - QByteArray m_s; -}; - /** * @brief Specialization for QString */ @@ -1102,6 +1032,206 @@ public: StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP (s) { } }; +// ------------------------------------------------------------ +// ByteArray adaptor framework + +/** + * @brief A generic adaptor for strings + * This is the base class for implementing generic access to strings + */ +class GSI_PUBLIC ByteArrayAdaptor + : public AdaptorBase +{ +public: + /** + * @brief Default constructor + */ + ByteArrayAdaptor () { } + + /** + * @brief Destructor + */ + virtual ~ByteArrayAdaptor () { } + + /** + * @brief Returns the size of the string + */ + virtual size_t size () const = 0; + + /** + * @brief Returns a pointer to a UTF8 encoded character array with size size() + */ + virtual const char *c_str () const = 0; + + /** + * @brief Sets the string to the given UTF8 string with length s + */ + virtual void set (const char *c_str, size_t s, tl::Heap &heap) = 0; + + /** + * @brief copy_to implementation + */ + virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const + { + ByteArrayAdaptor *s = dynamic_cast(target); + tl_assert (s); + s->set (c_str (), size (), heap); + } +}; + +/** + * @brief Generic string adaptor implementation + */ +template +class GSI_PUBLIC_TEMPLATE ByteArrayAdaptorImpl + : public ByteArrayAdaptor +{ +}; + +#if defined(HAVE_QT) + +/** + * @brief Specialization for QByteArray + */ +template <> +class GSI_PUBLIC ByteArrayAdaptorImpl + : public ByteArrayAdaptor +{ +public: + ByteArrayAdaptorImpl (QByteArray *s) + : mp_s (s), m_is_const (false) + { + // .. nothing yet .. + } + + ByteArrayAdaptorImpl (const QByteArray *s) + : mp_s (const_cast (s)), m_is_const (true) + { + // .. nothing yet .. + } + + ByteArrayAdaptorImpl (const QByteArray &s) + : m_is_const (false), m_s (s) + { + mp_s = &m_s; + } + + ByteArrayAdaptorImpl () + : m_is_const (false) + { + mp_s = &m_s; + } + + virtual ~ByteArrayAdaptorImpl () + { + // .. nothing yet .. + } + + virtual size_t size () const + { + return mp_s->size (); + } + + virtual const char *c_str () const + { + return mp_s->constData (); + } + + virtual void set (const char *c_str, size_t s, tl::Heap &) + { + if (! m_is_const) { + *mp_s = QByteArray (c_str, int (s)); + } + } + + virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const + { + ByteArrayAdaptorImpl *s = dynamic_cast *>(target); + if (s) { + *s->mp_s = *mp_s; + } else { + ByteArrayAdaptor::copy_to (target, heap); + } + } + +private: + QByteArray *mp_s; + bool m_is_const; + QByteArray m_s; +}; + +#endif + +/** + * @brief Specialization for std::string + */ +template <> +class GSI_PUBLIC ByteArrayAdaptorImpl > + : public ByteArrayAdaptor +{ +public: + ByteArrayAdaptorImpl (std::vector *s) + : mp_s (s), m_is_const (false) + { + // .. nothing yet .. + } + + ByteArrayAdaptorImpl (const std::vector *s) + : mp_s (const_cast *> (s)), m_is_const (true) + { + // .. nothing yet .. + } + + ByteArrayAdaptorImpl (const std::vector &s) + : m_is_const (false), m_s (s) + { + mp_s = &m_s; + } + + ByteArrayAdaptorImpl () + : m_is_const (false) + { + mp_s = &m_s; + } + + virtual ~ByteArrayAdaptorImpl () + { + // .. nothing yet .. + } + + virtual size_t size () const + { + return mp_s->size (); + } + + virtual const char *c_str () const + { + return &mp_s->front (); + } + + virtual void set (const char *c_str, size_t s, tl::Heap &) + { + if (! m_is_const) { + *mp_s = std::vector (c_str, c_str + s); + } + } + + virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const + { + ByteArrayAdaptorImpl > *s = dynamic_cast > *>(target); + if (s) { + *s->mp_s = *mp_s; + } else { + ByteArrayAdaptor::copy_to (target, heap); + } + } + +private: + std::vector *mp_s; + bool m_is_const; + std::vector m_s; +}; + // ------------------------------------------------------------ // Variant adaptor framework @@ -1909,6 +2039,12 @@ inline AdaptorBase *create_adaptor_by_category(const string_adaptor_tag & /*tag* return new StringAdaptorImpl (v); } +template +inline AdaptorBase *create_adaptor_by_category(const byte_array_adaptor_tag & /*tag*/, V v) +{ + return new ByteArrayAdaptorImpl (v); +} + template inline AdaptorBase *create_adaptor_by_category(const variant_adaptor_tag & /*tag*/, const V &v) { diff --git a/src/gsi/gsi/gsiTypes.cc b/src/gsi/gsi/gsiTypes.cc index 7d5b30cc2..b433e1e42 100644 --- a/src/gsi/gsi/gsiTypes.cc +++ b/src/gsi/gsi/gsiTypes.cc @@ -76,6 +76,8 @@ ArgType::to_string () const s += "float"; break; case T_string: s += "string"; break; + case T_byte_array: + s += "byte array"; break; case T_var: s += "variant"; break; case T_object: diff --git a/src/gsi/gsi/gsiTypes.h b/src/gsi/gsi/gsiTypes.h index a40ee8666..66e9da8bb 100644 --- a/src/gsi/gsi/gsiTypes.h +++ b/src/gsi/gsi/gsiTypes.h @@ -26,6 +26,7 @@ #include "tlInternational.h" #include "tlException.h" +#include "tlTypeTraits.h" #include "gsiCommon.h" #include @@ -37,6 +38,7 @@ #if defined(HAVE_QT) #include #include +#include #include #include #include @@ -61,6 +63,7 @@ class GSI_PUBLIC SerialArgs; class GSI_PUBLIC VectorAdaptor; class GSI_PUBLIC MapAdaptor; class GSI_PUBLIC StringAdaptor; +class GSI_PUBLIC ByteArrayAdaptor; class GSI_PUBLIC VariantAdaptor; class GSI_PUBLIC ClassBase; struct NoAdaptorTag; @@ -112,6 +115,7 @@ enum BasicType T_float = 14, T_var = 15, T_string = 16, + T_byte_array = 17, T_void_ptr = 19, T_object = 20, T_vector = 21, @@ -175,6 +179,7 @@ struct adaptor_category_tag { }; struct vector_adaptor_tag : public adaptor_category_tag { }; struct map_adaptor_tag : public adaptor_category_tag { }; struct string_adaptor_tag : public adaptor_category_tag { }; +struct byte_array_adaptor_tag : public adaptor_category_tag { }; struct variant_adaptor_tag : public adaptor_category_tag { }; struct basic_type_tag : public type_tag_base { }; @@ -224,6 +229,7 @@ struct adaptor_ptr_tag : public npod_ptr_tag { }; struct vector_tag : public adaptor_direct_tag, public vector_adaptor_tag { }; struct map_tag : public adaptor_direct_tag, public map_adaptor_tag { }; struct string_tag : public adaptor_direct_tag, public string_adaptor_tag { }; +struct byte_array_tag : public adaptor_direct_tag, public byte_array_adaptor_tag { }; struct var_tag : public adaptor_direct_tag, public variant_adaptor_tag { }; struct bool_cref_tag : public pod_cref_tag { }; @@ -247,6 +253,7 @@ struct float_cref_tag : public pod_cref_tag { }; struct vector_cref_tag : public adaptor_cref_tag, public vector_adaptor_tag { }; struct map_cref_tag : public adaptor_cref_tag, public map_adaptor_tag { }; struct string_cref_tag : public adaptor_cref_tag, public string_adaptor_tag { }; +struct byte_array_cref_tag : public adaptor_cref_tag, public byte_array_adaptor_tag { }; struct var_cref_tag : public adaptor_cref_tag, public variant_adaptor_tag { }; struct bool_ref_tag : public pod_ref_tag { }; @@ -270,6 +277,7 @@ struct float_ref_tag : public pod_ref_tag { }; struct vector_ref_tag : public adaptor_ref_tag, public vector_adaptor_tag { }; struct map_ref_tag : public adaptor_ref_tag, public map_adaptor_tag { }; struct string_ref_tag : public adaptor_ref_tag, public string_adaptor_tag { }; +struct byte_array_ref_tag : public adaptor_ref_tag, public byte_array_adaptor_tag { }; struct var_ref_tag : public adaptor_ref_tag, public variant_adaptor_tag { }; struct bool_cptr_tag : public pod_cptr_tag { }; @@ -293,6 +301,7 @@ struct float_cptr_tag : public pod_cptr_tag { }; struct vector_cptr_tag : public adaptor_cptr_tag, public vector_adaptor_tag { }; struct map_cptr_tag : public adaptor_cptr_tag, public map_adaptor_tag { }; struct string_cptr_tag : public adaptor_cptr_tag, public string_adaptor_tag { }; +struct byte_array_cptr_tag : public adaptor_cptr_tag, public byte_array_adaptor_tag { }; struct var_cptr_tag : public adaptor_cptr_tag, public variant_adaptor_tag { }; struct bool_ptr_tag : public pod_ptr_tag { }; @@ -316,6 +325,7 @@ struct float_ptr_tag : public pod_ptr_tag { }; struct vector_ptr_tag : public adaptor_ptr_tag, public vector_adaptor_tag { }; struct map_ptr_tag : public adaptor_ptr_tag, public map_adaptor_tag { }; struct string_ptr_tag : public adaptor_ptr_tag, public string_adaptor_tag { }; +struct byte_array_ptr_tag : public adaptor_ptr_tag, public byte_array_adaptor_tag { }; struct var_ptr_tag : public adaptor_ptr_tag, public variant_adaptor_tag { }; // all other objects @@ -427,7 +437,8 @@ template <> struct type_traits : generic_type_trait #if defined(HAVE_QT) template <> struct type_traits : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; -template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits > : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; #endif template <> struct type_traits : generic_type_traits { }; @@ -459,7 +470,8 @@ template <> struct type_traits : generic_type_trait #if defined(HAVE_QT) template <> struct type_traits : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; -template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits &> : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; #endif template <> struct type_traits : generic_type_traits { }; @@ -488,7 +500,8 @@ template <> struct type_traits : generic_type_trait #if defined(HAVE_QT) template <> struct type_traits : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; -template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits &> : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; #endif template <> struct type_traits : generic_type_traits { }; @@ -518,7 +531,8 @@ template <> struct type_traits : generic_type_trait #if defined(HAVE_QT) template <> struct type_traits : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; -template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits *> : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; #endif template <> struct type_traits : generic_type_traits { }; @@ -548,7 +562,8 @@ template <> struct type_traits : generic_type_trait #if defined(HAVE_QT) template <> struct type_traits : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; -template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits : generic_type_traits { }; +template <> struct type_traits *> : generic_type_traits { }; template <> struct type_traits : generic_type_traits { }; #endif template <> struct type_traits : generic_type_traits { }; @@ -1976,6 +1991,11 @@ struct ObjectType { }; */ struct StringType { }; +/** + * @brief Represents "T_byte_array" as a C++ type + */ +struct ByteArrayType { }; + /** * @brief Represents "T_var" as a C++ type */ @@ -2053,7 +2073,10 @@ void do_on_type_impl (gsi::BasicType type, const A1 *arg1, const A2 *arg2, const case gsi::T_string: call_variadic_function, A1, A2, A3, A4, A5> () (arg1, arg2, arg3, arg4, arg5); break; - case gsi::T_var: + case gsi::T_byte_array: + call_variadic_function, A1, A2, A3, A4, A5> () (arg1, arg2, arg3, arg4, arg5); + break; + case gsi::T_var: call_variadic_function, A1, A2, A3, A4, A5> () (arg1, arg2, arg3, arg4, arg5); break; case gsi::T_object: diff --git a/src/gsi/gsi_test/gsiTest.cc b/src/gsi/gsi_test/gsiTest.cc index 8b64d6f4b..e1e784df2 100644 --- a/src/gsi/gsi_test/gsiTest.cc +++ b/src/gsi/gsi_test/gsiTest.cc @@ -107,6 +107,48 @@ const char *A::a_static () return "static_a"; } +std::vector +A::qba_cref_to_ia (const QByteArray &ba) +{ + const char *cp = ba.constData (); + size_t n = ba.size (); + std::vector ia; + for (size_t i = 0; i < n; ++i) { + ia.push_back (int (*cp++)); + } + return ia; +} + +QByteArray +A::ia_cref_to_qba (const std::vector &ia) +{ + QByteArray ba; + for (std::vector::const_iterator i = ia.begin (); i != ia.end (); ++i) { + ba.push_back (char (*i)); + } + return ba; +} + +std::vector +A::ba_cref_to_ia (const std::vector &ba) +{ + std::vector ia; + for (std::vector::const_iterator i = ba.begin (); i != ba.end (); ++i) { + ia.push_back (int (*i)); + } + return ia; +} + +std::vector +A::ia_cref_to_ba (const std::vector &ia) +{ + std::vector ba; + for (std::vector::const_iterator i = ia.begin (); i != ia.end (); ++i) { + ba.push_back (char (*i)); + } + return ba; +} + static A *a_ctor (int i) { return new A (i); @@ -781,6 +823,22 @@ static gsi::QFlagsClass decl_qflags_enum ("", "Enums"); static gsi::Class decl_a ("", "A", gsi::constructor ("new_a|new", &a_ctor) + gsi::method ("instance_count", &A::instance_count) + + +#if defined(HAVE_QT) + gsi::method ("qba_cref_to_ia", &A::qba_cref_to_ia) + + gsi::method ("qba_ref_to_ia", &A::qba_ref_to_ia) + + gsi::method ("qba_cptr_to_ia", &A::qba_cptr_to_ia) + + gsi::method ("qba_ptr_to_ia", &A::qba_ptr_to_ia) + + gsi::method ("qba_to_ia", &A::qba_to_ia) + + gsi::method ("ia_cref_to_qba", &A::ia_cref_to_qba) + +#endif + gsi::method ("ba_cref_to_ia", &A::ba_cref_to_ia) + + gsi::method ("ba_ref_to_ia", &A::ba_ref_to_ia) + + gsi::method ("ba_cptr_to_ia", &A::ba_cptr_to_ia) + + gsi::method ("ba_ptr_to_ia", &A::ba_ptr_to_ia) + + gsi::method ("ba_to_ia", &A::ba_to_ia) + + gsi::method ("ia_cref_to_ba", &A::ia_cref_to_ba) + + gsi::method ("br", &A::br) + gsi::method ("get_e", &A::get_e) + gsi::method ("get_eptr", &A::get_eptr) + diff --git a/src/gsi/gsi_test/gsiTest.h b/src/gsi/gsi_test/gsiTest.h index 441a50c4a..c367a17af 100644 --- a/src/gsi/gsi_test/gsiTest.h +++ b/src/gsi/gsi_test/gsiTest.h @@ -93,6 +93,36 @@ struct A */ static const char *a_static (); +#if defined(HAVE_QT) + /** + * @brief Byte sequences: tests access to QByteArray + */ + static std::vector qba_cref_to_ia (const QByteArray &ba); + static std::vector qba_ref_to_ia (QByteArray &ba) { return qba_cref_to_ia (ba); } + static std::vector qba_cptr_to_ia (const QByteArray *ba) { return qba_cref_to_ia (*ba); } + static std::vector qba_ptr_to_ia (QByteArray *ba) { return qba_cref_to_ia (*ba); } + static std::vector qba_to_ia (QByteArray ba) { return qba_cref_to_ia (ba); } + + /** + * @brief Byte sequences: tests return of QByteArray + */ + static QByteArray ia_cref_to_qba (const std::vector &ia); +#endif + + /** + * @brief Byte sequences: tests access to std::vector (another byte array) + */ + static std::vector ba_cref_to_ia (const std::vector &ba); + static std::vector ba_ref_to_ia (std::vector &ba) { return ba_cref_to_ia (ba); } + static std::vector ba_cptr_to_ia (const std::vector *ba) { return ba_cref_to_ia (*ba); } + static std::vector ba_ptr_to_ia (std::vector *ba) { return ba_cref_to_ia (*ba); } + static std::vector ba_to_ia (std::vector ba) { return ba_cref_to_ia (ba); } + + /** + * @brief Byte sequences: tests return of std::vector + */ + static std::vector ia_cref_to_ba (const std::vector &ia); + /* * @brief A dummy method providing a chance to set a breakpoint in the script */ @@ -115,6 +145,9 @@ struct A int a3 (const std::string &x) { return int (x.size ()); } + int a3_ba (const std::vector &x) { + return x.size (); + } #if defined(HAVE_QT) int a3_qstr (const QString &x) { return x.size (); @@ -126,7 +159,7 @@ struct A return x.size (); } #endif - double a4 (const std::vector &d) { + double a4 (const std::vector &d) { m_d = d; return d.back (); } @@ -165,6 +198,7 @@ struct A unsigned long long a11_ull (double f) { return (unsigned long long)(f); } std::string a10_d (double f) { return tl::to_string (f); } + std::vector a10_d_ba (double f) { std::string s = tl::to_string (f); return std::vector (s.begin (), s.end ()); } #if defined(HAVE_QT) QByteArray a10_d_qba (double f) { return tl::to_qstring (tl::to_string (f)).toUtf8 (); } QString a10_d_qstr (double f) { return tl::to_qstring (tl::to_string (f)); } diff --git a/src/pya/pya/pyaConvert.cc b/src/pya/pya/pyaConvert.cc index d2988eed0..b63f1aa69 100644 --- a/src/pya/pya/pyaConvert.cc +++ b/src/pya/pya/pyaConvert.cc @@ -192,6 +192,42 @@ std::string python2c_func::operator() (PyObject *rval) } } +template <> +std::vector python2c_func >::operator() (PyObject *rval) +{ +#if PY_MAJOR_VERSION < 3 + if (PyString_Check (rval)) { + const char *cp = PyString_AsString (rval); + return std::vector (cp, cp + PyString_Size (rval)); + } else +#else + if (PyBytes_Check (rval)) { + char *cp = 0; + ssize_t sz = 0; + PyBytes_AsStringAndSize (rval, &cp, &sz); + tl_assert (cp != 0); + return std::vector (cp, cp + sz); + } else +#endif + if (PyUnicode_Check (rval)) { + PythonRef ba (PyUnicode_AsUTF8String (rval)); + if (! ba) { + check_error (); + } + char *cp = 0; + ssize_t sz = 0; + PyBytes_AsStringAndSize (ba.get (), &cp, &sz); + tl_assert (cp != 0); + return std::vector (cp, cp + sz); + } else if (PyByteArray_Check (rval)) { + char *cp = PyByteArray_AsString (rval); + ssize_t sz = PyByteArray_Size (rval); + return std::vector (cp, cp + sz); + } else { + throw tl::Exception (tl::to_string (tr ("Argument cannot be converted to a byte array"))); + } +} + #if defined(HAVE_QT) template <> QByteArray python2c_func::operator() (PyObject *rval) @@ -515,6 +551,16 @@ PyObject *c2python_func::operator() (const std::string &c) #endif } +template <> +PyObject *c2python_func &>::operator() (const std::vector &c) +{ +#if PY_MAJOR_VERSION < 3 + return PyByteArray_FromStringAndSize (&c.front (), Py_ssize_t (c.size ())); +#else + return PyBytes_FromStringAndSize (&c.front (), Py_ssize_t (c.size ())); +#endif +} + template <> PyObject *c2python_func::operator() (const char *p) { @@ -542,9 +588,9 @@ PyObject *c2python_func::operator() (const QByteArray &qba) Py_RETURN_NONE; } else { #if PY_MAJOR_VERSION < 3 - return PyString_FromStringAndSize (qba.constData (), Py_ssize_t (qba.size ())); -#else return PyByteArray_FromStringAndSize (qba.constData (), Py_ssize_t (qba.size ())); +#else + return PyBytes_FromStringAndSize (qba.constData (), Py_ssize_t (qba.size ())); #endif } } diff --git a/src/pya/pya/pyaConvert.h b/src/pya/pya/pyaConvert.h index f650ee4f6..f134c8c3b 100644 --- a/src/pya/pya/pyaConvert.h +++ b/src/pya/pya/pyaConvert.h @@ -185,6 +185,7 @@ struct test_type_func }; template <> struct test_type_func : public test_type_func { }; +template <> struct test_type_func > : public test_type_func { }; #if defined(HAVE_QT) template <> struct test_type_func : public test_type_func { }; template <> struct test_type_func : public test_type_func { }; @@ -333,6 +334,7 @@ template <> PYA_PUBLIC double python2c_func::operator() (PyObject *rval) template <> struct python2c_func : public python2c_func_cast { }; template <> PYA_PUBLIC std::string python2c_func::operator() (PyObject *rval); +template <> PYA_PUBLIC std::vector python2c_func >::operator() (PyObject *rval); #if defined(HAVE_QT) template <> PYA_PUBLIC QByteArray python2c_func::operator() (PyObject *rval); template <> PYA_PUBLIC QString python2c_func::operator() (PyObject *rval); @@ -620,6 +622,7 @@ template <> struct c2python_func : public c2python_func PYA_PUBLIC PyObject *c2python_func::operator() (const std::string &c); template <> struct c2python_func : public c2python_func { }; +template <> struct c2python_func > : public c2python_func &> { }; template <> struct c2python_func diff --git a/src/pya/pya/pyaMarshal.cc b/src/pya/pya/pyaMarshal.cc index 029970e34..43c584708 100644 --- a/src/pya/pya/pyaMarshal.cc +++ b/src/pya/pya/pyaMarshal.cc @@ -61,6 +61,7 @@ public: virtual void set (const char * /*c_str*/, size_t /*s*/, tl::Heap & /*heap*/) { // TODO: is there a setter for a string? + // So far it's not possible to have string OUT parameter } private: @@ -68,6 +69,40 @@ private: PythonPtr m_string; }; +/** + * @brief An adaptor for a byte array from ruby objects + */ +class PythonBasedByteArrayAdaptor + : public gsi::ByteArrayAdaptor +{ +public: + PythonBasedByteArrayAdaptor (const PythonPtr &ba) + : m_bytearray (python2c > (ba.get ())), m_bytes (ba) + { + // .. nothing yet .. + } + + virtual const char *c_str () const + { + return &m_bytearray.front (); + } + + virtual size_t size () const + { + return m_bytearray.size (); + } + + virtual void set (const char * /*c_str*/, size_t /*s*/, tl::Heap & /*heap*/) + { + // TODO: is there a setter for a byte array? + // So far it's not possible to have bytes OUT parameter + } + +private: + std::vector m_bytearray; + PythonPtr m_bytes; +}; + /** * @brief An adaptor for a variant from ruby objects */ @@ -303,6 +338,55 @@ struct writer } }; +/** + * @brief Serialization for strings + */ +template <> +struct writer +{ + void operator() (gsi::SerialArgs *aa, PyObject *arg, const gsi::ArgType &atype, tl::Heap *heap) + { + // Cannot pass ownership currently + tl_assert (!atype.pass_obj ()); + + if (arg == Py_None || arg == NULL) { + + if (! (atype.is_ptr () || atype.is_cptr ())) { + // nil is treated as an empty string for references + aa->write ((void *)new gsi::ByteArrayAdaptorImpl > (std::vector ())); + } else { + aa->write ((void *)0); + } + + } else { + + if (atype.is_ref () || atype.is_ptr ()) { + + // references or pointers require a boxed object. Pointers also allow nil. + void *vc = 0; + get_boxed_value_func > () (&vc, arg, heap); + if (! vc && atype.is_ref ()) { + throw tl::Exception (tl::to_string (tr ("Arguments or return values of reference or direct type cannot be passed nil or an empty boxed value object"))); + } + + // NOTE: by convention we pass the ownership to the receiver for adaptors. + if (! vc) { + aa->write (0); + } else { + aa->write ((void *)new gsi::ByteArrayAdaptorImpl > ((std::vector *) vc)); + } + + } else { + + // NOTE: by convention we pass the ownership to the receiver for adaptors. + aa->write ((void *)new PythonBasedByteArrayAdaptor (arg)); + + } + + } + } +}; + /** * @brief Specialization for Variant */ @@ -533,6 +617,25 @@ struct reader } }; +/** + * @brief Deseralisation wrapper: specialization for byte arrays + */ +template <> +struct reader +{ + void operator() (gsi::SerialArgs *rr, PythonRef *ret, PYAObjectBase * /*self*/, const gsi::ArgType &, tl::Heap *heap) + { + std::unique_ptr a ((gsi::ByteArrayAdaptor *) rr->read(*heap)); + if (!a.get ()) { + *ret = PythonRef (Py_None, false /*borrowed*/); + } else { + const char *cp = a->c_str (); + size_t sz = a->size (); + *ret = c2python (std::vector (cp, cp + sz)); + } + } +}; + static PyObject *object_from_variant (const tl::Variant &var, PYAObjectBase *self, const gsi::ArgType &atype) { diff --git a/src/rba/rba/rbaConvert.h b/src/rba/rba/rbaConvert.h index 436c482b7..8ff5e5c35 100644 --- a/src/rba/rba/rbaConvert.h +++ b/src/rba/rba/rbaConvert.h @@ -182,6 +182,12 @@ inline bool test_type (VALUE rval, bool /*loose*/) return TYPE (rval) == T_STRING; } +template <> +inline bool test_type (VALUE rval, bool /*loose*/) +{ + return TYPE (rval) == T_STRING; +} + template <> inline bool test_type (VALUE /*rval*/, bool /*loose*/) { @@ -313,6 +319,15 @@ inline std::string ruby2c (VALUE rval) return std::string (RSTRING_PTR(str), RSTRING_LEN(str)); } +template <> +inline std::vector ruby2c > (VALUE rval) +{ + VALUE str = rba_safe_string_value (rval); + char *cp = RSTRING_PTR(str); + size_t sz = RSTRING_LEN(str); + return std::vector (cp, cp + sz); +} + #if defined(HAVE_QT) template <> inline QByteArray ruby2c (VALUE rval) @@ -450,6 +465,12 @@ inline VALUE c2ruby (const std::string &c) return rb_str_new (c.c_str (), long (c.size ())); } +template <> +inline VALUE c2ruby > (const std::vector &c) +{ + return rb_str_new (&c.front (), c.size ()); +} + #if defined(HAVE_QT) template <> inline VALUE c2ruby (const QByteArray &qba) diff --git a/src/rba/rba/rbaMarshal.cc b/src/rba/rba/rbaMarshal.cc index 45963e4ac..c0eeec81f 100644 --- a/src/rba/rba/rbaMarshal.cc +++ b/src/rba/rba/rbaMarshal.cc @@ -68,12 +68,51 @@ public: virtual void set (const char * /*c_str*/, size_t /*s*/, tl::Heap & /*heap*/) { // TODO: is there a setter for a string? + // -> so far, string OUT parameters are not supported } private: VALUE m_string; }; +/** + * @brief An adaptor for a byte array from ruby objects + */ +class RubyBasedByteArrayAdaptor + : public gsi::ByteArrayAdaptor +{ +public: + RubyBasedByteArrayAdaptor (VALUE value) + { + m_bytes = rba_safe_string_value (value); + gc_lock_object (m_bytes); + } + + ~RubyBasedByteArrayAdaptor () + { + gc_unlock_object (m_bytes); + } + + virtual const char *c_str () const + { + return RSTRING_PTR (m_bytes); + } + + virtual size_t size () const + { + return RSTRING_LEN (m_bytes); + } + + virtual void set (const char * /*c_str*/, size_t /*s*/, tl::Heap & /*heap*/) + { + // TODO: is there a setter for a string? + // -> so far, byte array OUT parameters are not supported + } + +private: + VALUE m_bytes; +}; + /** * @brief An adaptor for a variant from ruby objects */ @@ -214,6 +253,7 @@ struct get_boxed_value_func_error template <> struct get_boxed_value_func : get_boxed_value_func_error { }; template <> struct get_boxed_value_func : get_boxed_value_func_error { }; +template <> struct get_boxed_value_func : get_boxed_value_func_error { }; template <> struct get_boxed_value_func : get_boxed_value_func_error { }; template <> struct get_boxed_value_func : get_boxed_value_func_error { }; template <> struct get_boxed_value_func : get_boxed_value_func_error { }; @@ -321,6 +361,55 @@ struct writer } }; +/** + * @brief Serialization for strings + */ +template <> +struct writer +{ + void operator() (gsi::SerialArgs *aa, VALUE arg, const gsi::ArgType &atype, tl::Heap *heap) + { + // Cannot pass ownership currently + tl_assert (!atype.pass_obj ()); + + if (arg == Qnil) { + + if (! (atype.is_ptr () || atype.is_cptr ())) { + // nil is treated as an empty string for references + aa->write ((void *)new gsi::ByteArrayAdaptorImpl > (std::vector ())); + } else { + aa->write ((void *)0); + } + + } else { + + if (atype.is_ref () || atype.is_ptr ()) { + + // references or pointers require a boxed object. Pointers also allow nil. + void *vc = 0; + get_boxed_value_func > () (&vc, arg, heap); + if (! vc && atype.is_ref ()) { + throw tl::Exception (tl::to_string (tr ("Arguments or return values of reference or direct type cannot be passed nil or an empty boxed value object"))); + } + + // NOTE: by convention we pass the ownership to the receiver for adaptors. + if (! vc) { + aa->write (0); + } else { + aa->write ((void *)new gsi::ByteArrayAdaptorImpl > ((std::vector *) vc)); + } + + } else { + + // NOTE: by convention we pass the ownership to the receiver for adaptors. + aa->write ((void *)new RubyBasedByteArrayAdaptor (arg)); + + } + + } + } +}; + /** * @brief Specialization for Variant */ @@ -556,6 +645,23 @@ struct reader } }; +/** + * @brief Deseralisation wrapper: specialization for strings + */ +template <> +struct reader +{ + void operator() (gsi::SerialArgs *rr, VALUE *ret, Proxy * /*self*/, const gsi::ArgType &, tl::Heap *heap) + { + std::unique_ptr a ((gsi::ByteArrayAdaptor *) rr->read(*heap)); + if (!a.get ()) { + *ret = Qnil; + } else { + *ret = rb_str_new (a->c_str (), long (a->size ())); + } + } +}; + static VALUE object_from_variant (const tl::Variant &var, Proxy *self, const gsi::ArgType &atype) { if (var.is_user()) { diff --git a/src/tl/tl/tlVariant.cc b/src/tl/tl/tlVariant.cc index d70645fca..d45c52805 100644 --- a/src/tl/tl/tlVariant.cc +++ b/src/tl/tl/tlVariant.cc @@ -238,6 +238,12 @@ Variant::Variant () // .. nothing yet .. } +Variant::Variant (const std::vector &ba) + : m_type (t_bytearray), m_string (0) +{ + m_var.m_bytearray = new std::vector (ba); +} + #if defined(HAVE_QT) Variant::Variant (const QByteArray &qba) @@ -574,6 +580,8 @@ Variant::reset () delete m_var.m_list; } else if (m_type == t_array) { delete m_var.m_array; + } else if (m_type == t_bytearray) { + delete m_var.m_bytearray; #if defined(HAVE_QT) } else if (m_type == t_qstring) { delete m_var.m_qstring; @@ -622,6 +630,20 @@ Variant::operator= (const std::string &s) return *this; } +Variant & +Variant::operator= (const std::vector &s) +{ + if (m_type == t_bytearray && &s == m_var.m_bytearray) { + // we are assigning to ourselves + } else { + std::vector *snew = new std::vector (s); + reset (); + m_type = t_bytearray; + m_var.m_bytearray = snew; + } + return *this; +} + #if defined(HAVE_QT) Variant & @@ -837,6 +859,8 @@ Variant::operator= (const Variant &v) #endif } else if (m_type == t_id) { m_var.m_id = v.m_var.m_id; + } else if (m_type == t_bytearray) { + m_var.m_bytearray = new std::vector (*v.m_var.m_bytearray); #if defined(HAVE_QT) } else if (m_type == t_qstring) { m_var.m_qstring = new QString (*v.m_var.m_qstring); @@ -922,6 +946,8 @@ normalized_type (Variant::type type) case Variant::t_stdstring: case Variant::t_string: return Variant::t_string; + case Variant::t_bytearray: + return Variant::t_bytearray; default: #if defined(HAVE_64BIT_COORD) case Variant::t_int128: @@ -989,6 +1015,9 @@ Variant::operator== (const tl::Variant &d) const return to_double () == d.to_double (); } else if (t == t_string) { return strcmp (to_string (), d.to_string ()) == 0; + } else if (t == t_bytearray) { + // TODO: can't compare std::vector with QByteArray currently + return *m_var.m_bytearray == *d.m_var.m_bytearray; #if defined(HAVE_QT) } else if (t == t_qstring) { return *m_var.m_qstring == *d.m_var.m_qstring; @@ -1042,6 +1071,9 @@ Variant::operator< (const tl::Variant &d) const return to_double () < d.to_double (); } else if (t == t_string) { return strcmp (to_string (), d.to_string ()) < 0; + } else if (t == t_bytearray) { + // TODO: can't compare std::vector with QByteArray currently + return *m_var.m_bytearray < *d.m_var.m_bytearray; #if defined(HAVE_QT) } else if (t == t_qstring) { return *m_var.m_qstring < *d.m_var.m_qstring; @@ -1099,6 +1131,7 @@ Variant::can_convert_to_float () const case t_qstring: case t_qbytearray: #endif + case t_bytearray: case t_stdstring: case t_string: { @@ -1138,6 +1171,7 @@ Variant::can_convert_to_double () const case t_qstring: case t_qbytearray: #endif + case t_bytearray: case t_stdstring: case t_string: { @@ -1177,6 +1211,7 @@ Variant::can_convert_to_int128 () const case t_qstring: case t_qbytearray: #endif + case t_bytearray: case t_stdstring: // TODO: there is no range checking currently return true; @@ -1191,7 +1226,7 @@ Variant::can_convert_to_ulonglong () const { switch (m_type) { case t_double: - return m_var.m_double <= std::numeric_limits::max () && m_var.m_double >= std::numeric_limits::min (); + return m_var.m_double <= double (std::numeric_limits::max ()) && m_var.m_double >= double (std::numeric_limits::min ()); case t_float: return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::min ()); case t_longlong: @@ -1224,6 +1259,7 @@ Variant::can_convert_to_ulonglong () const case t_qbytearray: #endif case t_stdstring: + case t_bytearray: { tl::Extractor ex (to_string ()); try { @@ -1243,7 +1279,7 @@ Variant::can_convert_to_longlong () const { switch (m_type) { case t_double: - return m_var.m_double <= std::numeric_limits::max () && m_var.m_double >= std::numeric_limits::min (); + return m_var.m_double <= double (std::numeric_limits::max ()) && m_var.m_double >= double (std::numeric_limits::min ()); case t_float: return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::min ()); #if defined(HAVE_64BIT_COORD) @@ -1271,6 +1307,7 @@ Variant::can_convert_to_longlong () const case t_qbytearray: #endif case t_stdstring: + case t_bytearray: { tl::Extractor ex (to_string ()); try { @@ -1290,9 +1327,9 @@ Variant::can_convert_to_ulong () const { switch (m_type) { case t_double: - return m_var.m_double <= std::numeric_limits::max () && m_var.m_double >= std::numeric_limits::min (); + return m_var.m_double <= double (std::numeric_limits::max ()) && m_var.m_double >= double (std::numeric_limits::min ()); case t_float: - return m_var.m_float <= std::numeric_limits::max () && m_var.m_float >= std::numeric_limits::min (); + return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::min ()); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); @@ -1324,6 +1361,7 @@ Variant::can_convert_to_ulong () const case t_qbytearray: #endif case t_stdstring: + case t_bytearray: { tl::Extractor ex (to_string ()); try { @@ -1343,7 +1381,7 @@ Variant::can_convert_to_long () const { switch (m_type) { case t_double: - return m_var.m_double <= std::numeric_limits::max () && m_var.m_double >= std::numeric_limits::min (); + return m_var.m_double <= double (std::numeric_limits::max ()) && m_var.m_double >= double (std::numeric_limits::min ()); case t_float: return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::min ()); #if defined(HAVE_64BIT_COORD) @@ -1373,6 +1411,7 @@ Variant::can_convert_to_long () const case t_qbytearray: #endif case t_stdstring: + case t_bytearray: { tl::Extractor ex (to_string ()); try { @@ -1392,9 +1431,9 @@ Variant::can_convert_to_int () const { switch (m_type) { case t_double: - return m_var.m_double <= std::numeric_limits::max () && m_var.m_double >= std::numeric_limits::min (); + return m_var.m_double <= double (std::numeric_limits::max ()) && m_var.m_double >= double (std::numeric_limits::min ()); case t_float: - return m_var.m_float <= std::numeric_limits::max () && m_var.m_float >= std::numeric_limits::min (); + return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::min ()); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); @@ -1424,6 +1463,7 @@ Variant::can_convert_to_int () const case t_qbytearray: #endif case t_stdstring: + case t_bytearray: { tl::Extractor ex (to_string ()); try { @@ -1443,9 +1483,9 @@ Variant::can_convert_to_uint () const { switch (m_type) { case t_double: - return m_var.m_double <= std::numeric_limits::max () && m_var.m_double >= std::numeric_limits::min (); + return m_var.m_double <= double (std::numeric_limits::max ()) && m_var.m_double >= double (std::numeric_limits::min ()); case t_float: - return m_var.m_float <= std::numeric_limits::max () && m_var.m_float >= std::numeric_limits::min (); + return m_var.m_float <= float (std::numeric_limits::max ()) && m_var.m_float >= float (std::numeric_limits::min ()); #if defined(HAVE_64BIT_COORD) case t_int128: return m_var.m_int128 <= __int128 (std::numeric_limits::max ()) && m_var.m_int128 >= __int128 (std::numeric_limits::min ()); @@ -1475,6 +1515,7 @@ Variant::can_convert_to_uint () const case t_qbytearray: #endif case t_stdstring: + case t_bytearray: { tl::Extractor ex (to_string ()); try { @@ -1526,6 +1567,8 @@ Variant::to_qbytearray () const { if (m_type == t_qbytearray) { return *m_var.m_qbytearray; + } else if (m_type == t_bytearray) { + return QByteArray (&m_var.m_bytearray->front (), m_var.m_bytearray->size ()); } else if (m_type == t_qstring) { return m_var.m_qstring->toUtf8 (); } else if (m_type == t_stdstring) { @@ -1544,6 +1587,8 @@ Variant::to_qstring () const return *m_var.m_qstring; } else if (m_type == t_qbytearray) { return QString::fromUtf8 (*m_var.m_qbytearray); + } else if (m_type == t_bytearray) { + return QString::fromUtf8 (&m_var.m_bytearray->front ()); } else { return tl::to_qstring (to_string ()); } @@ -1551,11 +1596,32 @@ Variant::to_qstring () const #endif +std::vector +Variant::to_bytearray () const +{ + if (m_type == t_qbytearray) { + return std::vector (m_var.m_qbytearray->constBegin (), m_var.m_qbytearray->constEnd ()); + } else if (m_type == t_bytearray) { + return *m_var.m_bytearray; + } else if (m_type == t_qstring) { + QByteArray ba = m_var.m_qstring->toUtf8 (); + return std::vector (ba.constBegin (), ba.constEnd ()); + } else if (m_type == t_stdstring) { + return std::vector (m_var.m_stdstring->begin (), m_var.m_stdstring->end ()); + } else { + // TODO: maybe some other conversion makes sense? I.e. byte representation of int? + std::string s = to_string (); + return std::vector (s.begin (), s.end ()); + } +} + std::string Variant::to_stdstring () const { if (m_type == t_stdstring) { return *m_var.m_stdstring; + } else if (m_type == t_bytearray) { + return std::string (m_var.m_bytearray->begin (), m_var.m_bytearray->end ()); #if defined(HAVE_QT) } else if (m_type == t_qstring) { return tl::to_string (*m_var.m_qstring); @@ -1574,11 +1640,31 @@ Variant::to_string () const return m_var.m_stdstring->c_str (); + } else if (m_type == t_bytearray) { + + // need to add a terminating 0 for safety + if (! m_string) { + size_t n = m_var.m_bytearray->size (); + m_string = new char [n + 1]; + strncpy (m_string, &m_var.m_bytearray->front (), n); + m_string[n] = 0; + } + + return m_string; + #if defined(HAVE_QT) } else if (m_type == t_qbytearray) { - // TODO: content may be longer - const char * terminates at first 0 character - return m_var.m_qbytearray->constData (); + // need to add a terminating 0 for safety + if (! m_string) { + size_t n = m_var.m_qbytearray->size (); + m_string = new char [n + 1]; + strncpy (m_string, m_var.m_qbytearray->constData (), n); + m_string[n] = 0; + } + + return m_string; + #endif // conversion needed @@ -1623,8 +1709,6 @@ Variant::to_string () const #if defined(HAVE_QT) } else if (m_type == t_qstring) { r = tl::to_string (*m_var.m_qstring); - } else if (m_type == t_qbytearray) { - r = std::string (m_var.m_qbytearray->constData (), m_var.m_qbytearray->size ()); #endif } else if (m_type == t_list) { for (std::vector::const_iterator v = m_var.m_list->begin (); v != m_var.m_list->end (); ++v) { @@ -1709,8 +1793,8 @@ Variant::to_int128 () const } else if (m_type == t_bool) { return m_var.m_bool; #if defined(HAVE_QT) - } else if (m_type == t_qbytearray) { - tl::Extractor ex (m_var.m_qbytearray->constData ()); + } else if (m_type == t_qbytearray || m_type == t_bytearray) { + tl::Extractor ex (to_string ()); __int128 l = 0; ex.read (l); return l; @@ -1780,9 +1864,9 @@ Variant::to_ulonglong () const tl::from_string (*m_var.m_stdstring, l); return l; #if defined(HAVE_QT) - } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) { + } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray || m_type == t_bytearray) { #else - } else if (m_type == t_string) { + } else if (m_type == t_string || m_type == t_bytearray) { #endif unsigned long long l = 0; tl::from_string (to_string (), l); @@ -1834,9 +1918,9 @@ Variant::to_longlong () const tl::from_string (*m_var.m_stdstring, l); return l; #if defined(HAVE_QT) - } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) { + } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray || m_type == t_bytearray) { #else - } else if (m_type == t_string) { + } else if (m_type == t_string || m_type == t_bytearray) { #endif long long l = 0; tl::from_string (to_string (), l); @@ -1888,9 +1972,9 @@ Variant::to_ulong () const tl::from_string (*m_var.m_stdstring, l); return l; #if defined(HAVE_QT) - } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) { + } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray || m_type == t_bytearray) { #else - } else if (m_type == t_string) { + } else if (m_type == t_string || m_type == t_bytearray) { #endif unsigned long l = 0; tl::from_string (to_string (), l); @@ -1942,9 +2026,9 @@ Variant::to_long () const tl::from_string (*m_var.m_stdstring, l); return l; #if defined(HAVE_QT) - } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) { + } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray || m_type == t_bytearray) { #else - } else if (m_type == t_string) { + } else if (m_type == t_string || m_type == t_bytearray) { #endif long l = 0; tl::from_string (to_string (), l); @@ -2048,9 +2132,9 @@ Variant::to_double () const tl::from_string (*m_var.m_stdstring, d); return d; #if defined(HAVE_QT) - } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray) { + } else if (m_type == t_string || m_type == t_qstring || m_type == t_qbytearray || m_type == t_bytearray) { #else - } else if (m_type == t_string) { + } else if (m_type == t_string || m_type == t_bytearray) { #endif double d = 0; tl::from_string (to_string (), d); @@ -2114,6 +2198,8 @@ Variant::native_ptr () const case t_qbytearray: return m_var.m_qbytearray; #endif + case t_bytearray: + return m_var.m_bytearray; case t_stdstring: return m_var.m_stdstring; case t_array: @@ -2198,9 +2284,9 @@ Variant::to_parsable_string () const } else if (is_stdstring ()) { return tl::to_quoted_string (*m_var.m_stdstring); #if defined(HAVE_QT) - } else if (is_cstring () || is_qstring () || is_qbytearray ()) { + } else if (is_cstring () || is_qstring () || is_qbytearray () || is_bytearray ()) { #else - } else if (is_cstring ()) { + } else if (is_cstring () || is_bytearray ()) { #endif return tl::to_quoted_string (to_string ()); } else if (is_list ()) { @@ -2314,6 +2400,8 @@ QVariant Variant::to_qvariant () const case t_qbytearray: return QVariant (*m_var.m_qbytearray); #endif + case t_bytearray: + return QVariant (to_qbytearray ()); case t_list: { QList l; diff --git a/src/tl/tl/tlVariant.h b/src/tl/tl/tlVariant.h index e622fe7fd..fc90c7396 100644 --- a/src/tl/tl/tlVariant.h +++ b/src/tl/tl/tlVariant.h @@ -164,6 +164,7 @@ public: t_double, t_string, t_stdstring, + t_bytearray, #if defined(HAVE_QT) t_qstring, t_qbytearray, @@ -190,6 +191,11 @@ public: */ Variant (const tl::Variant &d); + /** + * @brief Initialize the Variant with a std::vector + */ + Variant (const std::vector &s); + #if defined(HAVE_QT) /** * @brief Initialize the Variant with a QByteArray @@ -447,6 +453,11 @@ public: */ Variant &operator= (const std::string &v); + /** + * @brief Assignment of a STL byte array + */ + Variant &operator= (const std::vector &v); + /** * @brief Assignment of a double */ @@ -625,6 +636,14 @@ public: QString to_qstring () const; #endif + /** + * @brief Conversion to a STL byte array + * + * This performs the conversion to a std::vector as far as possible. + * No conversion is provided to user types currently. + */ + std::vector to_bytearray () const; + /** * @brief Conversion to a std::string * @@ -1326,6 +1345,14 @@ public: return m_type == t_id; } + /** + * @brief Test, if it is a std::vector byte array + */ + bool is_bytearray () const + { + return m_type == t_bytearray; + } + #if defined(HAVE_QT) /** @@ -1368,12 +1395,24 @@ public: bool is_a_string () const { #if defined(HAVE_QT) - return m_type == t_string || m_type == t_stdstring || m_type == t_qstring || m_type == t_qbytearray; + return m_type == t_string || m_type == t_stdstring || m_type == t_qstring; #else return m_type == t_string || m_type == t_stdstring; #endif } + /** + * @brief Test, if it is a byte array + */ + bool is_a_bytearray () const + { +#if defined(HAVE_QT) + return m_type == t_bytearray || m_type == t_qbytearray; +#else + return m_type == t_bytearray; +#endif + } + /** * @brief Returns true if the variant is of the given type internally * @@ -1525,6 +1564,7 @@ private: QString *m_qstring; QByteArray *m_qbytearray; #endif + std::vector *m_bytearray; std::string *m_stdstring; } m_var; @@ -1553,6 +1593,7 @@ template<> inline __int128 Variant::to<__int128> () const template<> inline double Variant::to () const { return to_double (); } template<> inline float Variant::to () const { return to_float (); } template<> inline std::string Variant::to () const { return to_stdstring (); } +template<> inline std::vector Variant::to > () const { return to_bytearray (); } #if defined(HAVE_QT) template<> inline QString Variant::to () const { return to_qstring (); } template<> inline QByteArray Variant::to () const { return to_qbytearray (); } @@ -1578,6 +1619,7 @@ template<> inline bool Variant::is<__int128> () const { return m_typ template<> inline bool Variant::is () const { return m_type == t_double; } template<> inline bool Variant::is () const { return m_type == t_float; } template<> inline bool Variant::is () const { return m_type == t_stdstring; } +template<> inline bool Variant::is > () const { return m_type == t_bytearray; } #if defined(HAVE_QT) template<> inline bool Variant::is () const { return m_type == t_qstring; } template<> inline bool Variant::is () const { return m_type == t_qbytearray; } @@ -1603,6 +1645,7 @@ template<> inline bool Variant::can_convert_to<__int128> () const { template<> inline bool Variant::can_convert_to () const { return can_convert_to_double (); } template<> inline bool Variant::can_convert_to () const { return can_convert_to_float (); } template<> inline bool Variant::can_convert_to () const { return true; } +template<> inline bool Variant::can_convert_to > () const { return true; } #if defined(HAVE_QT) template<> inline bool Variant::can_convert_to () const { return true; } template<> inline bool Variant::can_convert_to () const { return true; } diff --git a/testdata/python/basic.py b/testdata/python/basic.py index 305d2e6ef..fe6600711 100644 --- a/testdata/python/basic.py +++ b/testdata/python/basic.py @@ -2809,6 +2809,30 @@ class BasicTest(unittest.TestCase): self.assertEqual(sc.got_s0a, 0) self.assertEqual(sc.got_s0b, 0) + def test_74(self): + + # binary strings + + qba = pya.A.ia_cref_to_qba([ 17, 42, 0, 8 ]) + self.assertEqual(repr(qba), "b'\\x11*\\x00\\x08'") + self.assertEqual(pya.A.qba_to_ia(qba), [ 17, 42, 0, 8 ]) + self.assertEqual(pya.A.qba_cref_to_ia(qba), [ 17, 42, 0, 8 ]) + self.assertEqual(pya.A.qba_cptr_to_ia(qba), [ 17, 42, 0, 8 ]) + self.assertEqual(pya.A.qba_ref_to_ia(qba), [ 17, 42, 0, 8 ]) + self.assertEqual(pya.A.qba_ptr_to_ia(qba), [ 17, 42, 0, 8 ]) + + self.assertEqual(pya.A.qba_to_ia(b'\x00\x01\x02'), [ 0, 1, 2 ]) + + ba = pya.A.ia_cref_to_ba([ 17, 42, 0, 8 ]) + self.assertEqual(repr(ba), "b'\\x11*\\x00\\x08'") + self.assertEqual(pya.A.ba_to_ia(ba), [ 17, 42, 0, 8 ]) + self.assertEqual(pya.A.ba_cref_to_ia(ba), [ 17, 42, 0, 8 ]) + self.assertEqual(pya.A.ba_cptr_to_ia(ba), [ 17, 42, 0, 8 ]) + self.assertEqual(pya.A.ba_ref_to_ia(ba), [ 17, 42, 0, 8 ]) + self.assertEqual(pya.A.ba_ptr_to_ia(ba), [ 17, 42, 0, 8 ]) + + self.assertEqual(pya.A.ba_to_ia(b'\x00\x01\x02'), [ 0, 1, 2 ]) + # Custom factory implemented in Python def test_80(self): gc = pya.GObject.g_inst_count() diff --git a/testdata/ruby/basic_testcore.rb b/testdata/ruby/basic_testcore.rb index 97e97e794..345cd6282 100644 --- a/testdata/ruby/basic_testcore.rb +++ b/testdata/ruby/basic_testcore.rb @@ -2731,6 +2731,32 @@ class Basic_TestClass < TestBase end + def test_74 + + # binary strings + + qba = RBA::A::ia_cref_to_qba([ 17, 42, 0, 8 ]) + assert_equal(qba.inspect, "\"\\x11*\\x00\\b\"") + assert_equal(RBA::A::qba_to_ia(qba), [ 17, 42, 0, 8 ]) + assert_equal(RBA::A::qba_cref_to_ia(qba), [ 17, 42, 0, 8 ]) + assert_equal(RBA::A::qba_cptr_to_ia(qba), [ 17, 42, 0, 8 ]) + assert_equal(RBA::A::qba_ref_to_ia(qba), [ 17, 42, 0, 8 ]) + assert_equal(RBA::A::qba_ptr_to_ia(qba), [ 17, 42, 0, 8 ]) + + assert_equal(RBA::A::qba_to_ia("\x00\x01\x02"), [ 0, 1, 2 ]) + + ba = RBA::A::ia_cref_to_ba([ 17, 42, 0, 8 ]) + assert_equal(ba.inspect, "\"\\x11*\\x00\\b\"") + assert_equal(RBA::A::ba_to_ia(ba), [ 17, 42, 0, 8 ]) + assert_equal(RBA::A::ba_cref_to_ia(ba), [ 17, 42, 0, 8 ]) + assert_equal(RBA::A::ba_cptr_to_ia(ba), [ 17, 42, 0, 8 ]) + assert_equal(RBA::A::ba_ref_to_ia(ba), [ 17, 42, 0, 8 ]) + assert_equal(RBA::A::ba_ptr_to_ia(ba), [ 17, 42, 0, 8 ]) + + assert_equal(RBA::A::ba_to_ia("\x00\x01\x02"), [ 0, 1, 2 ]) + + end + # Custom factory implemented in Ruby def test_80