From 67e6e8a9bf4fb43a76e82eb5ad56ac0546d19bc2 Mon Sep 17 00:00:00 2001 From: Jos van den Oever Date: Sat, 12 May 2018 13:58:43 +0200 Subject: [PATCH] Convert test_functions --- src/cpp.cpp | 56 ++++++++---- src/rust.cpp | 119 +++++++++++++++++++------- tests/rust_functions/src/interface.rs | 84 ++++++++---------- tests/test_functions.cpp | 1 + tests/test_functions_rust.cpp | 27 ++---- 5 files changed, 168 insertions(+), 119 deletions(-) diff --git a/src/cpp.cpp b/src/cpp.cpp index 6370ff9..352e3de 100644 --- a/src/cpp.cpp +++ b/src/cpp.cpp @@ -676,6 +676,38 @@ void constructorArgs(QTextStream& cpp, const QString& prefix, const Object& o, c } } +void writeFunctionCDecl(QTextStream& cpp, const Function& f, const QString& lcname, const Object& o) { + const QString lc(snakeCase(f.name)); + cpp << " "; + if (f.type.isComplex()) { + cpp << "void"; + } else { + cpp << f.type.name; + } + const QString name = QString("%1_%2").arg(lcname, lc); + cpp << QString(" %1(%3%2::Private*").arg(name, o.name, f.mut ? "" : "const "); + // write all the input arguments, for QString and QByteArray, write + // pointers to their content and the length + for (auto a = f.args.begin(); a < f.args.end(); a++) { + if (a->type.name == "QString") { + cpp << ", const ushort*, int"; + } else if (a->type.name == "QByteArray") { + cpp << ", const char*, int"; + } else { + cpp << ", " << a->type.rustType; + } + } + // If the return type is QString or QByteArray, append a pointer to the + // variable that will be set to the argument list. Also add a setter + // function. + if (f.type.name == "QString") { + cpp << ", QString*, qstring_set"; + } else if (f.type.name == "QByteArray") { + cpp << ", QByteArray*, qbytearray_set"; + } + cpp << ");\n"; +} + void writeObjectCDecl(QTextStream& cpp, const Object& o, const Configuration& conf) { const QString lcname(snakeCase(o.name)); cpp << QString(" %1::Private* %2_new(").arg(o.name, lcname); @@ -712,20 +744,7 @@ void writeObjectCDecl(QTextStream& cpp, const Object& o, const Configuration& co } for (const Function& f: o.functions) { - const QString lc(snakeCase(f.name)); - const QString name = QString("%1_%2").arg(lcname, lc); - cpp << QString(" %1 %2(%4%3::Private*") - .arg(f.type.cSetType, name, o.name, f.mut ? "" : "const "); - if (f.args.size() > 0) { - cpp << ", "; - for (auto a = f.args.begin(); a < f.args.end(); a++) { - cpp << QString("%2%3").arg(a->type.cSetType, a + 1 < f.args.end() ? ", " : ""); - } - } - if (f.type.name == "QString") { - cpp << ", QString*, qstring_set"; - } - cpp << ");" << endl; + writeFunctionCDecl(cpp, f, lcname, o); } } @@ -883,10 +902,11 @@ void writeCppObject(QTextStream& cpp, const Object& o, const Configuration& conf cpp << QString(")%1\n{\n") .arg(f.mut ? "" : " const"); QString argList; - if (f.args.size() > 0) { - argList.append(", "); - for (auto a = f.args.begin(); a < f.args.end(); a++) { - argList.append(QString("%2%3").arg(a->name, a + 1 < f.args.end() ? ", " : "")); + for (auto a = f.args.begin(); a < f.args.end(); a++) { + if (a->type.name == "QString") { + argList.append(QString(", %2%3.utf16(), %2%3.size()").arg(a->name, a + 1 < f.args.end() ? ", " : "")); + } else { + argList.append(QString(", %2%3").arg(a->name, a + 1 < f.args.end() ? ", " : "")); } } if (f.type.name == "QString") { diff --git a/src/rust.cpp b/src/rust.cpp index 61ed2c5..e926ec7 100644 --- a/src/rust.cpp +++ b/src/rust.cpp @@ -146,6 +146,91 @@ void rConstructorArgs(QTextStream& r, const QString& name, const Object& o, cons r << ");\n"; } +void writeFunction(QTextStream& r, const Function& f, const QString& lcname, const Object& o) { + const QString lc(snakeCase(f.name)); + r << QString(R"( +#[no_mangle] +pub extern "C" fn %1_%2(ptr: *%3 %4)").arg(lcname, lc, f.mut ? "mut" : "const", o.name); + // write all the input arguments, for QString and QByteArray, write + // pointers to their content and the length which is int in Qt + for (auto a = f.args.begin(); a < f.args.end(); a++) { + r << ", "; + if (a->type.name == "QString") { + r << QString("%1_str: *const c_ushort, %1_len: c_int").arg(a->name); + } else { + r << a->name << ": " << a->type.rustType; + } + } + // If the return type is QString or QByteArray, append a pointer to the + // variable that will be set to the argument list. Also add a setter + // function. + if (f.type.name == "QString") { + r << ", d: *mut QString, set: fn(*mut QString, str: *const c_char, len: c_int)) {\n"; + } else if (f.type.name == "QByteArray") { + r << ", d: *mut QByteArray, set: fn(*mut QString, str: *const c_char, len: c_int)) {\n"; + } else { + r << ") -> " << f.type.rustType << " {\n"; + } + for (auto a = f.args.begin(); a < f.args.end(); a++) { + if (a->type.name == "QString") { + r << " let mut " << a->name << " = String::new();\n"; + r << QString(" set_string_from_utf16(&mut %1, %1_str, %1_len);\n").arg(a->name); + } else if (a->type.name == "QByteArray") { + } + } + if (f.mut) { + r << " let o = unsafe { &mut *ptr };\n"; + } else { + r << " let o = unsafe { &*ptr };\n"; + } + r << " let r = o." << lc << "("; + for (auto a = f.args.begin(); a < f.args.end(); a++) { + if (a != f.args.begin()) { + r << ", "; + } + r << a->name; + } + r << ");\n"; + if (f.type.isComplex()) { + r << " let s: *const c_char = r.as_ptr() as (*const c_char);\n"; + r << " set(d, s, r.len() as i32);\n"; + } else if (f.type.rustType != "()") { + r << " r\n"; + } + r << "}\n"; + /* + const QString type = a->type.name == "QString" ? "*const c_ushort, len: c_int" : a->type.rustType; + const QString passAlong = a->type.name == "QString" ? QString("%1.convert()").arg(a->name) : a->name; + argList.append(QString("%1: %2%3").arg(a->name, type, a + 1 < f.args.end() ? ", " : "")); + noTypeArgs.append(QString("%1%3").arg(passAlong, a + 1 < f.args.end() ? ", " : "")); + } + QString argList; + QString noTypeArgs; + if (f.args.size() > 0) { + argList.append(", "); + } + if (f.type.name == "QString") { + r << QString(R"( +#[no_mangle] +pub extern "C" fn %1_%2(ptr: *%3 %4%6, d: *mut QString, set: fn(*mut QString, str: *const c_char, len: c_int)) { +let o = unsafe { &%5*ptr }; +let data = o.%2(%7); +let s: *const c_char = data.as_ptr() as (*const c_char); +set(d, s, data.len() as c_int); +} +)").arg(lcname, lc, f.mut ? "mut" : "const", o.name, f.mut ? "mut " : "", argList, noTypeArgs); + + } else { + r << QString(R"( +#[no_mangle] +pub unsafe extern "C" fn %1_%2(ptr: *%3 %4%7) -> %5 { +(&%6*ptr).%2(%8) +} +)").arg(lcname, lc, f.mut ? "mut" : "const", o.name, f.type.rustType, f.mut ? "mut " : "", argList, noTypeArgs); + } + */ +} + void writeRustInterfaceObject(QTextStream& r, const Object& o, const Configuration& conf) { const QString lcname(snakeCase(o.name)); r << QString(R"( @@ -455,35 +540,7 @@ pub unsafe extern "C" fn %2_set(ptr: *mut %1, v: %4) { } } for (const Function& f: o.functions) { - const QString lc(snakeCase(f.name)); - QString argList; - QString noTypeArgs; - if (f.args.size() > 0) { - argList.append(", "); - for (auto a = f.args.begin(); a < f.args.end(); a++) { - const QString type = a->type.name == "QString" ? "QStringIn" : a->type.rustType; - const QString passAlong = a->type.name == "QString" ? QString("%1.convert()").arg(a->name) : a->name; - argList.append(QString("%1: %2%3").arg(a->name, type, a + 1 < f.args.end() ? ", " : "")); - noTypeArgs.append(QString("%1%3").arg(passAlong, a + 1 < f.args.end() ? ", " : "")); - } - } - if (f.type.isComplex()) { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %1_%2(ptr: *%3 %4%7, d: *mut c_void, set: fn(*mut c_void, %5)) { - let data = (&%6*ptr).%2(%8); - set(d, (&data).into()); -} -)").arg(lcname, lc, f.mut ? "mut" : "const", o.name, f.type.name, f.mut ? "mut " : "", argList, noTypeArgs); - - } else { - r << QString(R"( -#[no_mangle] -pub unsafe extern "C" fn %1_%2(ptr: *%3 %4%7) -> %5 { - (&%6*ptr).%2(%8) -} -)").arg(lcname, lc, f.mut ? "mut" : "const", o.name, f.type.rustType, f.mut ? "mut " : "", argList, noTypeArgs); - } + writeFunction(r, f, lcname, o); } if (o.type == ObjectType::List) { r << QString(R"( @@ -867,10 +924,6 @@ void writeRustImplementationObject(QTextStream& r, const Object& o) { r << QString(" %1: %2,\n").arg(lc, rustTypeInit(p)); } } - if (o.type != ObjectType::Object) { - r << QString(" list: vec![%1Item::default(); 10],\n") - .arg(o.name); - } r << QString(R"( } } fn emit(&self) -> &%1Emitter { diff --git a/tests/rust_functions/src/interface.rs b/tests/rust_functions/src/interface.rs index 1a07de5..94861e4 100644 --- a/tests/rust_functions/src/interface.rs +++ b/tests/rust_functions/src/interface.rs @@ -1,8 +1,9 @@ /* generated by rust_qt_binding_generator */ #![allow(unknown_lints)] #![allow(mutex_atomic, needless_pass_by_value)] -use libc::{c_int, c_void, uint8_t, uint16_t}; +use libc::{c_char, c_ushort, c_int, c_void, uint8_t, uint16_t}; use std::slice; +use std::char::decode_utf16; use std::sync::{Arc, Mutex}; use std::ptr::null; @@ -10,42 +11,17 @@ use std::ptr::null; use implementation::*; -#[repr(C)] -pub struct QString { - data: *const uint8_t, - len: c_int, +pub enum QString {} + +fn set_string_from_utf16(s: &mut String, str: *const c_ushort, len: c_int) { + let utf16 = unsafe { slice::from_raw_parts(str, len as usize) }; + let characters = decode_utf16(utf16.iter().cloned()) + .into_iter() + .map(|r| r.unwrap()); + s.clear(); + s.extend(characters); } -#[repr(C)] -pub struct QStringIn { - data: *const uint16_t, - len: c_int, -} - -impl QStringIn { - fn convert(&self) -> String { - let data = unsafe { slice::from_raw_parts(self.data, self.len as usize) }; - String::from_utf16_lossy(data) - } -} - -impl<'a> From<&'a str> for QString { - fn from(string: &'a str) -> QString { - QString { - len: string.len() as c_int, - data: string.as_ptr(), - } - } -} - -impl<'a> From<&'a String> for QString { - fn from(string: &'a String) -> QString { - QString { - len: string.len() as c_int, - data: string.as_ptr(), - } - } -} pub struct PersonQObject {} @@ -98,32 +74,44 @@ pub unsafe extern "C" fn person_free(ptr: *mut Person) { } #[no_mangle] -pub unsafe extern "C" fn person_user_name_get( +pub extern "C" fn person_user_name_get( ptr: *const Person, p: *mut c_void, - set: fn(*mut c_void, QString), + set: fn(*mut c_void, *const c_char, c_int), ) { - let data = (&*ptr).user_name(); - set(p, data.into()); + let o = unsafe { &*ptr }; + let v = o.user_name(); + let s: *const c_char = v.as_ptr() as (*const c_char); + set(p, s, v.len() as c_int); } #[no_mangle] -pub unsafe extern "C" fn person_user_name_set(ptr: *mut Person, v: QStringIn) { - (&mut *ptr).set_user_name(v.convert()); +pub extern "C" fn person_user_name_set(ptr: *mut Person, v: *const c_ushort, len: c_int) { + let o = unsafe { &mut *ptr }; + let mut s = String::new(); + set_string_from_utf16(&mut s, v, len); + o.set_user_name(s); } #[no_mangle] -pub unsafe extern "C" fn person_double_name(ptr: *mut Person) -> () { - (&mut *ptr).double_name() +pub extern "C" fn person_double_name(ptr: *mut Person) -> () { + let o = unsafe { &mut *ptr }; + let r = o.double_name(); } #[no_mangle] -pub unsafe extern "C" fn person_greet(ptr: *const Person, Name: QStringIn, d: *mut c_void, set: fn(*mut c_void, QString)) { - let data = (&*ptr).greet(Name.convert()); - set(d, (&data).into()); +pub extern "C" fn person_greet(ptr: *const Person, Name_str: *const c_ushort, Name_len: c_int, d: *mut QString, set: fn(*mut QString, str: *const c_char, len: c_int)) { + let mut Name = String::new(); + set_string_from_utf16(&mut Name, Name_str, Name_len); + let o = unsafe { &*ptr }; + let r = o.greet(Name); + let s: *const c_char = r.as_ptr() as (*const c_char); + set(d, s, r.len() as i32); } #[no_mangle] -pub unsafe extern "C" fn person_vowels_in_name(ptr: *const Person) -> u8 { - (&*ptr).vowels_in_name() +pub extern "C" fn person_vowels_in_name(ptr: *const Person) -> u8 { + let o = unsafe { &*ptr }; + let r = o.vowels_in_name(); + r } diff --git a/tests/test_functions.cpp b/tests/test_functions.cpp index b5e2bc8..d4a8bab 100644 --- a/tests/test_functions.cpp +++ b/tests/test_functions.cpp @@ -44,6 +44,7 @@ void TestRustObject::testSimpleFunction() person.setUserName("Konqi"); // THEN + QCOMPARE(person.userName(), QString("Konqi")); QCOMPARE((int)person.vowelsInName(), 2); } diff --git a/tests/test_functions_rust.cpp b/tests/test_functions_rust.cpp index 76075aa..182da35 100644 --- a/tests/test_functions_rust.cpp +++ b/tests/test_functions_rust.cpp @@ -3,22 +3,9 @@ namespace { - struct qstring_t { - private: - const void* data; - int len; - public: - qstring_t(const QString& v): - data(static_cast(v.utf16())), - len(v.size()) { - } - operator QString() const { - return QString::fromUtf8(static_cast(data), len); - } - }; - typedef void (*qstring_set)(QString*, qstring_t*); - void set_qstring(QString* v, qstring_t* val) { - *v = *val; + typedef void (*qstring_set)(QString* val, const char* utf8, int nbytes); + void set_qstring(QString* val, const char* utf8, int nbytes) { + *val = QString::fromUtf8(utf8, nbytes); } inline void personUserNameChanged(Person* o) { @@ -29,9 +16,9 @@ extern "C" { Person::Private* person_new(Person*, void (*)(Person*)); void person_free(Person::Private*); void person_user_name_get(const Person::Private*, QString*, qstring_set); - void person_user_name_set(Person::Private*, qstring_t); + void person_user_name_set(Person::Private*, const ushort *str, int len); void person_double_name(Person::Private*); - qstring_t person_greet(const Person::Private*, qstring_t, QString*, qstring_set); + void person_greet(const Person::Private*, const ushort*, int, QString*, qstring_set); quint8 person_vowels_in_name(const Person::Private*); }; @@ -62,7 +49,7 @@ QString Person::userName() const return v; } void Person::setUserName(const QString& v) { - person_user_name_set(m_d, v); + person_user_name_set(m_d, reinterpret_cast(v.data()), v.size()); } void Person::doubleName() { @@ -71,7 +58,7 @@ void Person::doubleName() QString Person::greet(const QString& Name) const { QString s; - person_greet(m_d, Name, &s, set_qstring); + person_greet(m_d, Name.utf16(), Name.size(), &s, set_qstring); return s; } quint8 Person::vowelsInName() const